diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index 05eaf52c1bc9b2eaf2c1e3faa6afaf88ec956087..c2ad48ca981ab03ac85d0e8db01a71d34d7ebdef 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -582,6 +582,7 @@ where )?; if let Some(ContractInfo::Alive(info)) = ContractInfoOf::<T>::take(&self_id) { Storage::<T>::queue_trie_for_deletion(&info)?; + Contracts::<T>::deposit_event(RawEvent::Terminated(self_id, beneficiary.clone())); Ok(()) } else { panic!( @@ -671,7 +672,7 @@ where fn deposit_event(&mut self, topics: Vec<T::Hash>, data: Vec<u8>) { deposit_event::<Self::T>( topics, - RawEvent::ContractExecution(self.ctx.self_account.clone(), data) + RawEvent::ContractEmitted(self.ctx.self_account.clone(), data) ); } diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 43566bc547c409a7bfd12e35bf565e493fb6eef8..9c810faad9655cb4b38cb49bb30a88db1c26e932 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -756,39 +756,57 @@ decl_event! { <T as frame_system::Config>::AccountId, <T as frame_system::Config>::Hash { - /// Contract deployed by address at the specified address. \[owner, contract\] + /// Contract deployed by address at the specified address. \[deployer, contract\] Instantiated(AccountId, AccountId), - /// Contract has been evicted and is now in tombstone state. - /// \[contract, tombstone\] + /// Contract has been evicted and is now in tombstone state. \[contract\] + Evicted(AccountId), + + /// Contract has been terminated without leaving a tombstone. + /// \[contract, beneficiary\] /// /// # Params /// - /// - `contract`: `AccountId`: The account ID of the evicted contract. - /// - `tombstone`: `bool`: True if the evicted contract left behind a tombstone. - Evicted(AccountId, bool), + /// - `contract`: The contract that was terminated. + /// - `beneficiary`: The account that received the contracts remaining balance. + /// + /// # Note + /// + /// The only way for a contract to be removed without a tombstone and emitting + /// this event is by calling `seal_terminate`. + Terminated(AccountId, AccountId), - /// Restoration for a contract has been successful. - /// \[donor, dest, code_hash, rent_allowance\] + /// Restoration of a contract has been successful. + /// \[restorer, dest, code_hash, rent_allowance\] /// /// # Params /// - /// - `donor`: `AccountId`: Account ID of the restoring contract - /// - `dest`: `AccountId`: Account ID of the restored contract - /// - `code_hash`: `Hash`: Code hash of the restored contract - /// - `rent_allowance: `Balance`: Rent allowance of the restored contract + /// - `restorer`: Account ID of the restoring contract. + /// - `dest`: Account ID of the restored contract. + /// - `code_hash`: Code hash of the restored contract. + /// - `rent_allowance`: Rent allowance of the restored contract. Restored(AccountId, AccountId, Hash, Balance), - /// Code with the specified hash has been stored. - /// \[code_hash\] + /// Code with the specified hash has been stored. \[code_hash\] CodeStored(Hash), - /// Triggered when the current \[schedule\] is updated. + /// Triggered when the current schedule is updated. + /// \[version\] + /// + /// # Params + /// + /// - `version`: The version of the newly set schedule. ScheduleUpdated(u32), - /// An event deposited upon execution of a contract from the account. - /// \[account, data\] - ContractExecution(AccountId, Vec<u8>), + /// A custom event emitted by the contract. + /// \[contract, data\] + /// + /// # Params + /// + /// - `contract`: The contract that emitted the event. + /// - `data`: Data supplied by the contract. Metadata generated during contract + /// compilation is needed to decode it. + ContractEmitted(AccountId, Vec<u8>), } } diff --git a/substrate/frame/contracts/src/rent.rs b/substrate/frame/contracts/src/rent.rs index 0bf229d49469650f62921e07503e97349f8c373d..2075f6f757de2ef3d3e87fadcc884b288adabd00 100644 --- a/substrate/frame/contracts/src/rent.rs +++ b/substrate/frame/contracts/src/rent.rs @@ -261,7 +261,7 @@ where ); let tombstone_info = ContractInfo::Tombstone(tombstone); <ContractInfoOf<T>>::insert(account, &tombstone_info); - <Module<T>>::deposit_event(RawEvent::Evicted(account.clone(), true)); + <Module<T>>::deposit_event(RawEvent::Evicted(account.clone())); Ok(Some(tombstone_info)) } Verdict::Charge { amount } => { diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index a2916ff833b4ee0d5618f61dba55c64d4c5f0922..a8bf80213a176f95bae0ec75f84708c307d1f217 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -512,7 +512,7 @@ fn instantiate_and_call_and_deposit_event() { EventRecord { phase: Phase::Initialization, event: MetaEvent::contracts( - RawEvent::ContractExecution(addr.clone(), vec![1, 2, 3, 4]) + RawEvent::ContractEmitted(addr.clone(), vec![1, 2, 3, 4]) ), topics: vec![], }, @@ -1300,7 +1300,7 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: EventRecord { phase: Phase::Initialization, event: MetaEvent::contracts( - RawEvent::Evicted(addr_bob.clone(), true) + RawEvent::Evicted(addr_bob.clone()) ), topics: vec![], }, @@ -1385,7 +1385,7 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: pretty_assertions::assert_eq!(System::events(), vec![ EventRecord { phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Evicted(addr_bob, true)), + event: MetaEvent::contracts(RawEvent::Evicted(addr_bob)), topics: vec![], }, EventRecord { @@ -1633,6 +1633,7 @@ fn self_destruct_works() { .build() .execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let _ = Balances::deposit_creating(&DJANGO, 1_000_000); assert_ok!(Contracts::put_code(Origin::signed(ALICE), wasm)); // Instantiate the BOB contract. @@ -1652,6 +1653,9 @@ fn self_destruct_works() { Some(ContractInfo::Alive(_)) ); + // Drop all previous events + initialize_block(2); + // Call BOB without input data which triggers termination. assert_matches!( Contracts::call( @@ -1664,11 +1668,35 @@ fn self_destruct_works() { Ok(_) ); + pretty_assertions::assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system( + frame_system::Event::KilledAccount(addr.clone()) + ), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances( + pallet_balances::RawEvent::Transfer(addr.clone(), DJANGO, 100_000) + ), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts( + RawEvent::Terminated(addr.clone(), DJANGO) + ), + topics: vec![], + }, + ]); + // Check that account is gone assert!(ContractInfoOf::<Test>::get(&addr).is_none()); // check that the beneficiary (django) got remaining balance - assert_eq!(Balances::free_balance(DJANGO), 100_000); + assert_eq!(Balances::free_balance(DJANGO), 1_100_000); }); }