Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions modules/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ pub mod module {
#[pallet::compact] value: BalanceOf<T>,
#[pallet::compact] gas_limit: u64,
#[pallet::compact] storage_limit: u32,
#[pallet::compact] _nonce: T::Index, // checked by tx validation logic
#[pallet::compact] _valid_until: T::BlockNumber, // checked by tx validation logic
) -> DispatchResultWithPostInfo {
match action {
Expand Down
22 changes: 11 additions & 11 deletions primitives/src/unchecked_extrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl<Call, Extra, ConvertTx, StorageDepositPerByte, TxFeePerGas, Lookup> Checkab
where
Call: Encode + Member,
Extra: SignedExtension<AccountId = AccountId32>,
ConvertTx: Convert<(Call, Extra), Result<EthereumTransactionMessage, InvalidTransaction>>,
ConvertTx: Convert<(AccountId32, Call, Extra), Result<EthereumTransactionMessage, InvalidTransaction>>,
StorageDepositPerByte: Get<Balance>,
TxFeePerGas: Get<Balance>,
Lookup: traits::Lookup<Source = Address, Target = AccountId32>,
Expand All @@ -113,7 +113,8 @@ where
match self.0.signature {
Some((addr, AcalaMultiSignature::Ethereum(sig), extra)) => {
let function = self.0.function;
let eth_msg = ConvertTx::convert((function.clone(), extra.clone()))?;
let expected_account_id = lookup.lookup(addr)?;
let eth_msg = ConvertTx::convert((expected_account_id.clone(), function.clone(), extra.clone()))?;

if eth_msg.tip != 0 {
// Not yet supported, require zero tip
Expand Down Expand Up @@ -161,33 +162,32 @@ where

let signer = recover_signer(&sig, msg_hash.as_fixed_bytes()).ok_or(InvalidTransaction::BadProof)?;

let acc = lookup.lookup(Address::Address20(signer.into()))?;
let expected = lookup.lookup(addr)?;
let account_id = lookup.lookup(Address::Address20(signer.into()))?;

if acc != expected {
if account_id != expected_account_id {
return Err(InvalidTransaction::BadProof.into());
}

Ok(CheckedExtrinsic {
signed: Some((acc, extra)),
signed: Some((account_id, extra)),
function,
})
}
Some((addr, AcalaMultiSignature::AcalaEip712(sig), extra)) => {
let function = self.0.function;
let eth_msg = ConvertTx::convert((function.clone(), extra.clone()))?;
let expected_account_id = lookup.lookup(addr)?;
let eth_msg = ConvertTx::convert((expected_account_id.clone(), function.clone(), extra.clone()))?;

let signer = verify_eip712_signature(eth_msg, sig).ok_or(InvalidTransaction::BadProof)?;

let acc = lookup.lookup(Address::Address20(signer.into()))?;
let expected = lookup.lookup(addr)?;
let account_id = lookup.lookup(Address::Address20(signer.into()))?;

if acc != expected {
if account_id != expected_account_id {
return Err(InvalidTransaction::BadProof.into());
}

Ok(CheckedExtrinsic {
signed: Some((acc, extra)),
signed: Some((account_id, extra)),
function,
})
}
Expand Down
106 changes: 103 additions & 3 deletions runtime/mandala/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use module_currencies::{BasicCurrencyAdapter, Currency};
use module_evm::{CallInfo, CreateInfo, EvmTask, Runner};
use module_evm_accounts::EvmAddressMapping;
use module_relaychain::RelayChainCallBuilder;
use module_support::{DispatchableTask, ExchangeRateProvider, ForeignAssetIdMapping};
use module_support::{AddressMapping, DispatchableTask, ExchangeRateProvider, ForeignAssetIdMapping};
use module_transaction_payment::{Multiplier, TargetedFeeAdjustment};
use scale_info::TypeInfo;

Expand Down Expand Up @@ -1959,21 +1959,37 @@ impl cumulus_pallet_aura_ext::Config for Runtime {}
#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)]
pub struct ConvertEthereumTx;

impl Convert<(Call, SignedExtra), Result<EthereumTransactionMessage, InvalidTransaction>> for ConvertEthereumTx {
fn convert((call, extra): (Call, SignedExtra)) -> Result<EthereumTransactionMessage, InvalidTransaction> {
impl Convert<(AccountId, Call, SignedExtra), Result<EthereumTransactionMessage, InvalidTransaction>>
for ConvertEthereumTx
{
fn convert(
(who, call, extra): (AccountId, Call, SignedExtra),
) -> Result<EthereumTransactionMessage, InvalidTransaction> {
match call {
Call::EVM(module_evm::Call::eth_call {
action,
input,
value,
gas_limit,
storage_limit,
nonce,
Comment thread
xlc marked this conversation as resolved.
Outdated
valid_until,
}) => {
if System::block_number() > valid_until {
return Err(InvalidTransaction::Stale);
}

let address = EvmAddressMapping::<Runtime>::get_default_evm_address(&who);
Comment thread
xlc marked this conversation as resolved.
Outdated
let evm_nonce = EVM::accounts(&address).map(|x| x.nonce).unwrap_or_default();

if nonce != evm_nonce {
return if evm_nonce > nonce {
Err(InvalidTransaction::Stale)
} else {
Err(InvalidTransaction::Future)
};
}

let era: frame_system::CheckEra<Runtime> = extra.3;
if era != frame_system::CheckEra::from(sp_runtime::generic::Era::Immortal) {
// require immortal
Expand Down Expand Up @@ -2556,6 +2572,7 @@ cumulus_pallet_parachain_system::register_validate_block!(
#[cfg(test)]
mod tests {
use super::*;
use frame_support::assert_noop;
use frame_system::offchain::CreateSignedTransaction;

#[test]
Expand Down Expand Up @@ -2602,4 +2619,87 @@ mod tests {
If the limit is too strong, maybe consider increasing the limit",
);
}

#[test]
fn convert_tx_check_evm_nonce() {
sp_io::TestExternalities::new_empty().execute_with(|| {
let alice: AccountId = sp_runtime::AccountId32::from([1; 32]);
let address = EvmAddressMapping::<Runtime>::get_default_evm_address(&alice);

// set evm nonce to 1
module_evm::Accounts::<Runtime>::insert(
&address,
module_evm::AccountInfo {
nonce: 1,
contract_info: None,
},
);

let stale_call = Call::EVM(module_evm::Call::eth_call {
action: module_evm::TransactionAction::Create,
input: vec![0x01],
value: 0,
gas_limit: 21_000,
storage_limit: 1_000,
nonce: 0, // evm::accounts.nonce - 1
valid_until: 30,
});

let valid_call = Call::EVM(module_evm::Call::eth_call {
action: module_evm::TransactionAction::Create,
input: vec![0x01],
value: 0,
gas_limit: 21_000,
storage_limit: 1_000,
nonce: 1, // evm::accounts.nonce
valid_until: 30,
});

let future_call = Call::EVM(module_evm::Call::eth_call {
action: module_evm::TransactionAction::Create,
input: vec![0x01],
value: 0,
gas_limit: 21_000,
storage_limit: 1_000,
nonce: 2, // evm::accounts.nonce + 1
valid_until: 30,
});

let extra: SignedExtra = (
frame_system::CheckSpecVersion::<Runtime>::new(),
frame_system::CheckTxVersion::<Runtime>::new(),
frame_system::CheckGenesis::<Runtime>::new(),
frame_system::CheckEra::<Runtime>::from(generic::Era::Immortal),
frame_system::CheckNonce::<Runtime>::from(3), // system::account.nonce
frame_system::CheckWeight::<Runtime>::new(),
module_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0),
module_evm::SetEvmOrigin::<Runtime>::new(),
);

assert_eq!(
ConvertEthereumTx::convert((alice.clone(), valid_call, extra.clone())).unwrap(),
EthereumTransactionMessage {
nonce: 3, // system::account.nonce
tip: 0,
gas_limit: 21_000,
storage_limit: 1_000,
action: module_evm::TransactionAction::Create,
value: 0,
input: vec![0x01],
chain_id: 595,
genesis: sp_core::H256::default(),
valid_until: 30
}
);

assert_noop!(
ConvertEthereumTx::convert((alice.clone(), stale_call, extra.clone())),
InvalidTransaction::Stale
);
assert_noop!(
ConvertEthereumTx::convert((alice.clone(), future_call, extra.clone())),
InvalidTransaction::Future
);
});
}
}