git.delta.rocks / unique-network / refs/commits / b230e7e5f037

difftreelog

feat fake event injection

Yaroslav Bolyukin2022-11-23parent: #1d4e56c.patch.diff
in: master

8 files changed

modifiedCargo.lockdiffbeforeafterboth
6038name = "pallet-evm-migration"6038name = "pallet-evm-migration"
6039version = "0.1.1"6039version = "0.1.1"
6040dependencies = [6040dependencies = [
6041 "ethereum",
6041 "fp-evm",6042 "fp-evm",
6042 "frame-benchmarking",6043 "frame-benchmarking",
6043 "frame-support",6044 "frame-support",
modifiedpallets/evm-migration/Cargo.tomldiffbeforeafterboth
8scale-info = { version = "2.0.1", default-features = false, features = [8scale-info = { version = "2.0.1", default-features = false, features = [
9 "derive",9 "derive",
10] }10] }
11ethereum = { version = "0.12.0", default-features = false }
11frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }12frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
12frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }13frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
13frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }14frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
modifiedpallets/evm-migration/src/benchmarking.rsdiffbeforeafterboth
20use frame_benchmarking::benchmarks;20use frame_benchmarking::benchmarks;
21use frame_system::RawOrigin;21use frame_system::RawOrigin;
22use sp_core::{H160, H256};22use sp_core::{H160, H256};
23use sp_std::vec::Vec;23use sp_std::{vec::Vec, vec};
2424
25benchmarks! {25benchmarks! {
26 where_clause { where <T as Config>::RuntimeEvent: codec::Encode }
27
26 begin {28 begin {
27 }: _(RawOrigin::Root, H160::default())29 }: _(RawOrigin::Root, H160::default())
46 <Pallet<T>>::begin(RawOrigin::Root.into(), address)?;48 <Pallet<T>>::begin(RawOrigin::Root.into(), address)?;
47 }: _(RawOrigin::Root, address, data)49 }: _(RawOrigin::Root, address, data)
50
51 insert_eth_logs {
52 let b in 0..200;
53 let logs = (0..b).map(|_| ethereum::Log {
54 address: H160([b as u8; 20]),
55 data: vec![b as u8; 128],
56 topics: vec![H256([b as u8; 32]); 6],
57 }).collect::<Vec<_>>();
58 }: _(RawOrigin::Root, logs)
59
60 insert_events {
61 let b in 0..200;
62 use codec::Encode;
63 let logs = (0..b).map(|_| <T as Config>::RuntimeEvent::from(crate::Event::<T>::TestEvent).encode()).collect::<Vec<_>>();
64 }: _(RawOrigin::Root, logs)
48}65}
4966
modifiedpallets/evm-migration/src/lib.rsdiffbeforeafterboth
2525
26#[frame_support::pallet]26#[frame_support::pallet]
27pub mod pallet {27pub mod pallet {
28 use frame_support::pallet_prelude::*;28 use frame_support::{
29 pallet_prelude::{*, DispatchResult},
30 traits::IsType,
31 };
29 use frame_system::pallet_prelude::*;32 use frame_system::pallet_prelude::{*, OriginFor};
30 use sp_core::{H160, H256};33 use sp_core::{H160, H256};
31 use sp_std::vec::Vec;34 use sp_std::vec::Vec;
32 use super::weights::WeightInfo;35 use super::weights::WeightInfo;
36 pub trait Config: frame_system::Config + pallet_evm::Config {39 pub trait Config: frame_system::Config + pallet_evm::Config {
37 /// Weights40 /// Weights
38 type WeightInfo: WeightInfo;41 type WeightInfo: WeightInfo;
42 /// The overarching event type.
43 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
39 }44 }
4045
41 type SelfWeightOf<T> = <T as Config>::WeightInfo;46 type SelfWeightOf<T> = <T as Config>::WeightInfo;
44 #[pallet::generate_store(pub(super) trait Store)]49 #[pallet::generate_store(pub(super) trait Store)]
45 pub struct Pallet<T>(_);50 pub struct Pallet<T>(_);
51
52 #[pallet::event]
53 pub enum Event<T: Config> {
54 /// This event is used in benchmarking and can be used for tests
55 TestEvent,
56 }
4657
47 #[pallet::error]58 #[pallet::error]
48 pub enum Error<T> {59 pub enum Error<T> {
49 /// Can only migrate to empty address.60 /// Can only migrate to empty address.
50 AccountNotEmpty,61 AccountNotEmpty,
51 /// Migration of this account is not yet started, or already finished.62 /// Migration of this account is not yet started, or already finished.
52 AccountIsNotMigrating,63 AccountIsNotMigrating,
64 /// Failed to decode event bytes
65 BadEvent,
53 }66 }
5467
55 #[pallet::storage]68 #[pallet::storage]
108 Ok(())121 Ok(())
109 }122 }
123
124 /// Create ethereum events attached to the fake transaction
125 #[pallet::weight(<SelfWeightOf<T>>::insert_eth_logs(logs.len() as u32))]
126 pub fn insert_eth_logs(origin: OriginFor<T>, logs: Vec<ethereum::Log>) -> DispatchResult {
127 ensure_root(origin)?;
128 for log in logs {
129 <pallet_evm::Pallet<T>>::deposit_log(log);
130 }
131 // Transactions is created by FakeTransactionFinalizer
132 Ok(())
133 }
134
135 /// Create substrate events
136 #[pallet::weight(<SelfWeightOf<T>>::insert_events(events.len() as u32))]
137 pub fn insert_events(origin: OriginFor<T>, events: Vec<Vec<u8>>) -> DispatchResult {
138 ensure_root(origin)?;
139 for event in events {
140 <frame_system::Pallet<T>>::deposit_event(
141 <T as frame_system::Config>::RuntimeEvent::decode(&mut event.as_slice())
142 .map_err(|_| <Error<T>>::BadEvent)?,
143 );
144 }
145 Ok(())
146 }
110 }147 }
111148
112 /// Implements [`pallet_evm::OnMethodCall`], which reserves accounts with pending migration149 /// Implements [`pallet_evm::OnMethodCall`], which reserves accounts with pending migration
modifiedpallets/evm-migration/src/weights.rsdiffbeforeafterboth
3//! Autogenerated weights for pallet_evm_migration3//! Autogenerated weights for pallet_evm_migration
4//!4//!
5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
6//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`6//! DATE: 2022-11-23, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
7//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 10247//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
88
9// Executed Command:9// Executed Command:
37 fn begin() -> Weight;37 fn begin() -> Weight;
38 fn set_data(b: u32, ) -> Weight;38 fn set_data(b: u32, ) -> Weight;
39 fn finish(b: u32, ) -> Weight;39 fn finish(b: u32, ) -> Weight;
40 fn insert_eth_logs(b: u32, ) -> Weight;
41 fn insert_events(b: u32, ) -> Weight;
40}42}
4143
42/// Weights for pallet_evm_migration using the Substrate node and recommended hardware.44/// Weights for pallet_evm_migration using the Substrate node and recommended hardware.
46 // Storage: System Account (r:1 w:0)48 // Storage: System Account (r:1 w:0)
47 // Storage: EVM AccountCodes (r:1 w:0)49 // Storage: EVM AccountCodes (r:1 w:0)
48 fn begin() -> Weight {50 fn begin() -> Weight {
49 Weight::from_ref_time(8_035_000)51 Weight::from_ref_time(16_080_000 as u64)
50 .saturating_add(T::DbWeight::get().reads(3 as u64))52 .saturating_add(T::DbWeight::get().reads(3 as u64))
51 .saturating_add(T::DbWeight::get().writes(1 as u64))53 .saturating_add(T::DbWeight::get().writes(1 as u64))
52 }54 }
53 // Storage: EvmMigration MigrationPending (r:1 w:0)55 // Storage: EvmMigration MigrationPending (r:1 w:0)
54 // Storage: EVM AccountStorages (r:0 w:1)56 // Storage: EVM AccountStorages (r:0 w:1)
55 fn set_data(b: u32, ) -> Weight {57 fn set_data(b: u32, ) -> Weight {
56 Weight::from_ref_time(3_076_000)58 Weight::from_ref_time(7_945_000 as u64)
57 // Standard Error: 059 // Standard Error: 1_272
58 .saturating_add(Weight::from_ref_time(828_000).saturating_mul(b as u64))60 .saturating_add(Weight::from_ref_time(1_056_832 as u64).saturating_mul(b as u64))
59 .saturating_add(T::DbWeight::get().reads(1 as u64))61 .saturating_add(T::DbWeight::get().reads(1 as u64))
60 .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(b as u64)))62 .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(b as u64)))
61 }63 }
62 // Storage: EvmMigration MigrationPending (r:1 w:1)64 // Storage: EvmMigration MigrationPending (r:1 w:1)
63 // Storage: EVM AccountCodes (r:0 w:1)65 // Storage: EVM AccountCodes (r:0 w:1)
64 fn finish(_b: u32, ) -> Weight {66 fn finish(b: u32, ) -> Weight {
65 Weight::from_ref_time(6_591_000)67 Weight::from_ref_time(8_336_000 as u64)
68 // Standard Error: 89
69 .saturating_add(Weight::from_ref_time(6_411 as u64).saturating_mul(b as u64))
66 .saturating_add(T::DbWeight::get().reads(1 as u64))70 .saturating_add(T::DbWeight::get().reads(1 as u64))
67 .saturating_add(T::DbWeight::get().writes(2 as u64))71 .saturating_add(T::DbWeight::get().writes(2 as u64))
68 }72 }
73 fn insert_eth_logs(b: u32, ) -> Weight {
74 Weight::from_ref_time(3_447_000 as u64)
75 // Standard Error: 843
76 .saturating_add(Weight::from_ref_time(901_039 as u64).saturating_mul(b as u64))
77 }
78 fn insert_events(b: u32, ) -> Weight {
79 Weight::from_ref_time(3_457_000 as u64)
80 // Standard Error: 1_460
81 .saturating_add(Weight::from_ref_time(1_491_611 as u64).saturating_mul(b as u64))
82 }
69}83}
7084
71// For backwards compatibility and tests85// For backwards compatibility and tests
74 // Storage: System Account (r:1 w:0)88 // Storage: System Account (r:1 w:0)
75 // Storage: EVM AccountCodes (r:1 w:0)89 // Storage: EVM AccountCodes (r:1 w:0)
76 fn begin() -> Weight {90 fn begin() -> Weight {
77 Weight::from_ref_time(8_035_000)91 Weight::from_ref_time(16_080_000 as u64)
78 .saturating_add(RocksDbWeight::get().reads(3 as u64))92 .saturating_add(RocksDbWeight::get().reads(3 as u64))
79 .saturating_add(RocksDbWeight::get().writes(1 as u64))93 .saturating_add(RocksDbWeight::get().writes(1 as u64))
80 }94 }
81 // Storage: EvmMigration MigrationPending (r:1 w:0)95 // Storage: EvmMigration MigrationPending (r:1 w:0)
82 // Storage: EVM AccountStorages (r:0 w:1)96 // Storage: EVM AccountStorages (r:0 w:1)
83 fn set_data(b: u32, ) -> Weight {97 fn set_data(b: u32, ) -> Weight {
84 Weight::from_ref_time(3_076_000)98 Weight::from_ref_time(7_945_000 as u64)
85 // Standard Error: 099 // Standard Error: 1_272
86 .saturating_add(Weight::from_ref_time(828_000).saturating_mul(b as u64))100 .saturating_add(Weight::from_ref_time(1_056_832 as u64).saturating_mul(b as u64))
87 .saturating_add(RocksDbWeight::get().reads(1 as u64))101 .saturating_add(RocksDbWeight::get().reads(1 as u64))
88 .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(b as u64)))102 .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(b as u64)))
89 }103 }
90 // Storage: EvmMigration MigrationPending (r:1 w:1)104 // Storage: EvmMigration MigrationPending (r:1 w:1)
91 // Storage: EVM AccountCodes (r:0 w:1)105 // Storage: EVM AccountCodes (r:0 w:1)
92 fn finish(_b: u32, ) -> Weight {106 fn finish(b: u32, ) -> Weight {
93 Weight::from_ref_time(6_591_000)107 Weight::from_ref_time(8_336_000 as u64)
108 // Standard Error: 89
109 .saturating_add(Weight::from_ref_time(6_411 as u64).saturating_mul(b as u64))
94 .saturating_add(RocksDbWeight::get().reads(1 as u64))110 .saturating_add(RocksDbWeight::get().reads(1 as u64))
95 .saturating_add(RocksDbWeight::get().writes(2 as u64))111 .saturating_add(RocksDbWeight::get().writes(2 as u64))
96 }112 }
113 fn insert_eth_logs(b: u32, ) -> Weight {
114 Weight::from_ref_time(3_447_000 as u64)
115 // Standard Error: 843
116 .saturating_add(Weight::from_ref_time(901_039 as u64).saturating_mul(b as u64))
117 }
118 fn insert_events(b: u32, ) -> Weight {
119 Weight::from_ref_time(3_457_000 as u64)
120 // Standard Error: 1_460
121 .saturating_add(Weight::from_ref_time(1_491_611 as u64).saturating_mul(b as u64))
122 }
97}123}
98124
modifiedruntime/common/config/ethereum.rsdiffbeforeafterboth
91}91}
9292
93impl pallet_evm_migration::Config for Runtime {93impl pallet_evm_migration::Config for Runtime {
94 type RuntimeEvent = RuntimeEvent;
94 type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;95 type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;
95}96}
9697
modifiedruntime/common/construct_runtime/mod.rsdiffbeforeafterboth
92 EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,92 EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
93 EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage, Event<T>} = 151,93 EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage, Event<T>} = 151,
94 EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,94 EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
95 EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,95 EvmMigration: pallet_evm_migration::{Pallet, Call, Storage, Event<T>} = 153,
9696
97 Maintenance: pallet_maintenance::{Pallet, Call, Storage, Event<T>} = 154,97 Maintenance: pallet_maintenance::{Pallet, Call, Storage, Event<T>} = 154,
9898
modifiedtests/src/eth/migration.seqtest.tsdiffbeforeafterboth
1616
17import {expect, itEth, usingEthPlaygrounds} from './util';17import {expect, itEth, usingEthPlaygrounds} from './util';
18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';
19import {Struct} from '@polkadot/types';
20
21import {IEvent} from '../util/playgrounds/types';
22import {ApiPromise} from '@polkadot/api';
23
24const encodeEvent = (api: ApiPromise, pallet: string, palletEvents: string, event: string, fields: any) => {
25 const palletIndex = api.runtimeMetadata.asV14.pallets.find(p => p.name.toString() == pallet)!.index.toNumber();
26 const eventMeta = api.events[palletEvents][event].meta;
27 const eventIndex = eventMeta.index.toNumber();
28 const data = [
29 palletIndex, eventIndex,
30 ];
31 const metaEvent = api.registry.findMetaEvent(new Uint8Array(data));
32 data.push(...new Struct(api.registry, {data: metaEvent}, {data: fields}).toU8a());
33
34 const typeName = api.registry.lookup.names.find(n => n.endsWith('RuntimeEvent'))!;
35 return api.registry.createType(typeName, new Uint8Array(data)).toHex();
36};
1937
20describe('EVM Migrations', () => {38describe('EVM Migrations', () => {
21 let superuser: IKeyringPair;39 let superuser: IKeyringPair;
40 let charlie: IKeyringPair;
2241
23 before(async function() {42 before(async function() {
24 await usingEthPlaygrounds(async (_helper, privateKey) => {43 await usingEthPlaygrounds(async (_helper, privateKey) => {
25 superuser = await privateKey('//Alice');44 superuser = await privateKey('//Alice');
45 charlie = await privateKey('//Charlie');
26 });46 });
27 });47 });
28 48
105 expect(await contract.methods.get(i).call()).to.be.equal(i.toString());125 expect(await contract.methods.get(i).call()).to.be.equal(i.toString());
106 }126 }
107 });127 });
128 itEth('Fake collection creation on substrate side', async ({helper}) => {
129 const txInsertEvents = helper.constructApiCall('api.tx.evmMigration.insertEvents', [[
130 encodeEvent(helper.api!, 'Common', 'common', 'CollectionCreated', [
131 // Collection Id
132 9999,
133 // Collection mode: NFT
134 1,
135 // Owner
136 charlie.address,
137 ]),
138 ]]);
139 await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txInsertEvents]);
140 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
141 const eventStrings = event.map(e => `${e.section}.${e.method}`);
142
143 expect(eventStrings).to.contain('common.CollectionCreated');
144 });
145 itEth('Fake token creation on substrate side', async ({helper}) => {
146 const txInsertEvents = helper.constructApiCall('api.tx.evmMigration.insertEvents', [[
147 encodeEvent(helper.api!, 'Common', 'common', 'ItemCreated', [
148 // Collection Id
149 9999,
150 // TokenId
151 9999,
152 // Owner
153 {Substrate: charlie.address},
154 // Amount
155 1,
156 ]),
157 ]]);
158 await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txInsertEvents]);
159 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
160 const eventStrings = event.map(e => `${e.section}.${e.method}`);
161
162 expect(eventStrings).to.contain('common.ItemCreated');
163 });
164 itEth('Fake token creation on ethereum side', async ({helper}) => {
165 const collection = await helper.nft.mintCollection(superuser);
166 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
167 const caller = await helper.eth.createAccountWithBalance(superuser);
168 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller);
169
170 const events: any = [];
171 contract.events.allEvents((_: any, event: any) => {
172 events.push(event);
173 });
174
175 {
176 const txInsertEthLogs = helper.constructApiCall('api.tx.evmMigration.insertEthLogs', [[
177 {
178 // Contract, which has emitted this log
179 address: collectionAddress,
180
181 topics: [
182 // First topic - event signature
183 helper.getWeb3().eth.abi.encodeEventSignature('Transfer(address,address,uint256)'),
184 // Rest of topics - indexed event fields in definition order
185 helper.getWeb3().eth.abi.encodeParameter('address', '0x' + '00'.repeat(20)),
186 helper.getWeb3().eth.abi.encodeParameter('address', caller),
187 helper.getWeb3().eth.abi.encodeParameter('uint256', 9999),
188 ],
189
190 // Every field coming from event, which is not marked as indexed, should be encoded here
191 // NFT transfer has no such fields, but here is an example for some other possible event:
192 // data: helper.getWeb3().eth.abi.encodeParameters(['uint256', 'address'], [22, collectionAddress])
193 data: [],
194 },
195 ]]);
196 await helper.executeExtrinsic(superuser, 'api.tx.sudo.sudo', [txInsertEthLogs]);
197 }
198
199 if (events.length == 0) await helper.wait.newBlocks(1);
200 const event = events[0];
201
202 expect(event.address).to.be.equal(collectionAddress);
203 expect(event.returnValues.from).to.be.equal('0x' + '00'.repeat(20));
204 expect(event.returnValues.to).to.be.equal(caller);
205 expect(event.returnValues.tokenId).to.be.equal('9999');
206 });
108});207});
109208