feat: Support erc20 system tx from address

This commit is contained in:
sprites0
2025-03-10 23:47:59 +00:00
parent 7fe7c06507
commit 9a6a1a4cc1
5 changed files with 29 additions and 21 deletions

View File

@ -23,7 +23,7 @@ use reth_execution_types::BlockExecutionResult;
use reth_primitives::{ use reth_primitives::{
EthPrimitives, Receipt, Recovered, RecoveredBlock, SealedBlock, TransactionSigned, EthPrimitives, Receipt, Recovered, RecoveredBlock, SealedBlock, TransactionSigned,
}; };
use reth_primitives_traits::{transaction::signed::HL_SYSTEM_TX_FROM_ADDR, NodePrimitives}; use reth_primitives_traits::{transaction::signed::is_impersonated_tx, NodePrimitives};
use reth_revm::{context_interface::result::ResultAndState, db::State, DatabaseCommit}; use reth_revm::{context_interface::result::ResultAndState, db::State, DatabaseCommit};
/// Factory for [`EthExecutionStrategy`]. /// Factory for [`EthExecutionStrategy`].
@ -191,7 +191,7 @@ where
} }
let hash = tx.hash(); let hash = tx.hash();
let is_system_transaction = tx.signer() == HL_SYSTEM_TX_FROM_ADDR; let is_system_transaction = is_impersonated_tx(tx.signature(), tx.gas_price()).is_some();
// Execute transaction. // Execute transaction.
let result_and_state = let result_and_state =

View File

@ -21,7 +21,7 @@ use reth_primitives_traits::{
sync::OnceLock, sync::OnceLock,
transaction::{ transaction::{
error::TransactionConversionError, error::TransactionConversionError,
signed::{is_impersonated_tx, RecoveryError, HL_SYSTEM_TX_FROM_ADDR}, signed::{is_impersonated_tx, RecoveryError},
}, },
InMemorySize, SignedTransaction, InMemorySize, SignedTransaction,
}; };
@ -836,8 +836,8 @@ impl SignedTransaction for TransactionSigned {
fn recover_signer(&self) -> Result<Address, RecoveryError> { fn recover_signer(&self) -> Result<Address, RecoveryError> {
let signature = self.signature(); let signature = self.signature();
if is_impersonated_tx(signature, self.gas_price()) { if let Some(address) = is_impersonated_tx(signature, self.gas_price()) {
return Ok(HL_SYSTEM_TX_FROM_ADDR); return Ok(address);
} }
let signature_hash = self.signature_hash(); let signature_hash = self.signature_hash();
recover_signer(&self.signature, signature_hash) recover_signer(&self.signature, signature_hash)

View File

@ -15,7 +15,7 @@ pub mod shanghai;
use alloy_rpc_types_engine::{ExecutionData, PayloadError}; use alloy_rpc_types_engine::{ExecutionData, PayloadError};
use reth_chainspec::EthereumHardforks; use reth_chainspec::EthereumHardforks;
use reth_primitives::SealedBlock; use reth_primitives::SealedBlock;
use reth_primitives_traits::transaction::signed::HL_SYSTEM_TX_FROM_ADDR; use reth_primitives_traits::transaction::signed::is_impersonated_tx;
use reth_primitives_traits::{Block, SignedTransaction}; use reth_primitives_traits::{Block, SignedTransaction};
use std::sync::Arc; use std::sync::Arc;
@ -94,9 +94,7 @@ impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
let (normal, system) = transactions.into_iter().partition(|tx| { let (normal, system) = transactions.into_iter().partition(|tx| {
let tx = T::decode_2718(&mut tx.iter().as_slice()); let tx = T::decode_2718(&mut tx.iter().as_slice());
match tx { match tx {
Ok(tx) => { Ok(tx) => is_impersonated_tx(tx.signature(), tx.gas_price()).is_none(),
!matches!(tx.recover_signer(), Ok(address) if HL_SYSTEM_TX_FROM_ADDR == address)
}
Err(_) => true, Err(_) => true,
} }
}); });

View File

@ -1,7 +1,7 @@
//! Block body abstraction. //! Block body abstraction.
use crate::{ use crate::{
transaction::signed::{RecoveryError, HL_SYSTEM_TX_FROM_ADDR}, transaction::signed::{is_impersonated_tx, RecoveryError},
BlockHeader, FullSignedTx, InMemorySize, MaybeSerde, MaybeSerdeBincodeCompat, BlockHeader, FullSignedTx, InMemorySize, MaybeSerde, MaybeSerdeBincodeCompat,
SignedTransaction, SignedTransaction,
}; };
@ -85,7 +85,7 @@ pub trait BlockBody:
let transactions: Vec<Self::Transaction> = self let transactions: Vec<Self::Transaction> = self
.transactions() .transactions()
.into_iter() .into_iter()
.filter(|tx| !matches!(tx.recover_signer(), Ok(address) if HL_SYSTEM_TX_FROM_ADDR == address)) .filter(|&tx| is_impersonated_tx(tx.signature(), tx.gas_price()).is_none())
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
alloy_consensus::proofs::calculate_transaction_root(transactions.as_slice()) alloy_consensus::proofs::calculate_transaction_root(transactions.as_slice())

View File

@ -10,9 +10,10 @@ use alloy_consensus::{
SignableTransaction, Transaction, SignableTransaction, Transaction,
}; };
use alloy_eips::eip2718::{Decodable2718, Encodable2718}; use alloy_eips::eip2718::{Decodable2718, Encodable2718};
use alloy_primitives::{keccak256, Address, PrimitiveSignature as Signature, TxHash, B256}; use alloy_primitives::{keccak256, Address, PrimitiveSignature as Signature, TxHash, B256, U160};
use core::hash::Hash; use core::hash::Hash;
use revm_primitives::{address, U256}; use revm_primitives::{address, U256};
use std::ops::Add;
/// Helper trait that unifies all behaviour required by block to support full node operations. /// Helper trait that unifies all behaviour required by block to support full node operations.
pub trait FullSignedTx: SignedTransaction + MaybeCompact + MaybeSerdeBincodeCompat {} pub trait FullSignedTx: SignedTransaction + MaybeCompact + MaybeSerdeBincodeCompat {}
@ -23,11 +24,20 @@ pub const HL_SYSTEM_TX_FROM_ADDR: Address = address!("22222222222222222222222222
/// Check if the transaction is impersonated. /// Check if the transaction is impersonated.
/// Signature part is introduced in block_ingest, while the gas_price is trait of hyperliquid system transactions. /// Signature part is introduced in block_ingest, while the gas_price is trait of hyperliquid system transactions.
pub fn is_impersonated_tx(signature: &Signature, gas_price: Option<u128>) -> bool { pub fn is_impersonated_tx(signature: &Signature, gas_price: Option<u128>) -> Option<Address> {
signature.r() == U256::from(1) if signature.r() == U256::from(1) && signature.v() == true && gas_price == Some(0u128) {
&& signature.s() == U256::from(1) if signature.s() == U256::from(1) {
&& signature.v() == true Some(HL_SYSTEM_TX_FROM_ADDR)
&& gas_price == Some(0u128) } else {
let s = signature.s().reduce_mod(U256::from(U160::MAX).add(U256::from(1)));
let s = U160::from(s);
let s: [u8; 20] = s.to_be_bytes();
let s = Address::from_slice(&s);
Some(s)
}
} else {
None
}
} }
/// A signed transaction. /// A signed transaction.
@ -89,8 +99,8 @@ pub trait SignedTransaction:
/// Returns `None` if the transaction's signature is invalid, see also /// Returns `None` if the transaction's signature is invalid, see also
/// `reth_primitives::transaction::recover_signer_unchecked`. /// `reth_primitives::transaction::recover_signer_unchecked`.
fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> { fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
if is_impersonated_tx(self.signature(), self.gas_price()) { if let Some(address) = is_impersonated_tx(self.signature(), self.gas_price()) {
return Ok(HL_SYSTEM_TX_FROM_ADDR); return Ok(address);
} }
self.recover_signer_unchecked_with_buf(&mut Vec::new()).map_err(|_| RecoveryError) self.recover_signer_unchecked_with_buf(&mut Vec::new()).map_err(|_| RecoveryError)
} }
@ -183,8 +193,8 @@ impl SignedTransaction for PooledTransaction {
buf: &mut Vec<u8>, buf: &mut Vec<u8>,
) -> Result<Address, RecoveryError> { ) -> Result<Address, RecoveryError> {
let signature = self.signature(); let signature = self.signature();
if is_impersonated_tx(signature, self.gas_price()) { if let Some(address) = is_impersonated_tx(signature, self.gas_price()) {
return Ok(HL_SYSTEM_TX_FROM_ADDR); return Ok(address);
} }
match self { match self {
Self::Legacy(tx) => tx.tx().encode_for_signing(buf), Self::Legacy(tx) => tx.tx().encode_for_signing(buf),