diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index c4fdc0f13d..012d5e796d 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -561,6 +561,9 @@ pub mod pallet { #[pallet::storage] pub type AccountStorages = StorageDoubleMap<_, Blake2_128Concat, H160, Blake2_128Concat, H256, H256, ValueQuery>; + + #[pallet::storage] + pub type Suicided = StorageMap<_, Blake2_128Concat, H160, (), OptionQuery>; } /// Type alias for currency balance. @@ -793,18 +796,29 @@ impl Pallet { /// Remove an account. pub fn remove_account(address: &H160) { if >::contains_key(address) { + // Remember to call `dec_sufficients` when clearing Suicided. + >::insert(address, ()); + + // In theory, we can always have pre-EIP161 contracts, so we + // make sure the account nonce is at least one. let account_id = T::AddressMapping::into_account_id(*address); - let _ = frame_system::Pallet::::dec_sufficients(&account_id); + frame_system::Pallet::::inc_account_nonce(&account_id); } >::remove(address); >::remove(address); - #[allow(deprecated)] - let _ = >::remove_prefix(address, None); } /// Create an account. pub fn create_account(address: H160, code: Vec) { + if >::contains_key(address) { + // This branch should never trigger, because when Suicided + // contains an address, then its nonce will be at least one, + // which causes CreateCollision error in EVM, but we add it + // here for safeguard. + return; + } + if code.is_empty() { return; } diff --git a/frame/evm/src/tests.rs b/frame/evm/src/tests.rs index ffa7bdbe02..6c4c294b90 100644 --- a/frame/evm/src/tests.rs +++ b/frame/evm/src/tests.rs @@ -1037,8 +1037,7 @@ fn handle_sufficient_reference() { assert_eq!(account_2.sufficients, 1); EVM::remove_account(&addr_2); let account_2 = frame_system::Account::::get(substrate_addr_2); - // We decreased the sufficient reference by 1 on removing the account. - assert_eq!(account_2.sufficients, 0); + assert_eq!(account_2.sufficients, 1); }); }