Skip to content
This repository has been archived by the owner on Mar 13, 2023. It is now read-only.

Integrate Ethereum::message_transact call from dispatch module #1267

Merged
merged 48 commits into from
Jun 20, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
741f8f2
A copy-paste version
boundless-forest Jun 8, 2022
f47095b
Adapt for other two places
boundless-forest Jun 9, 2022
854fccc
Simplify the implementation
boundless-forest Jun 9, 2022
eb9b24f
Add evm support
boundless-forest Jun 9, 2022
e874faa
Fix
boundless-forest Jun 9, 2022
3852856
Test updated trait
boundless-forest Jun 9, 2022
bffa1b7
Get the matched value, Thanks Xavier
boundless-forest Jun 9, 2022
5c67cff
Merge branch 'main' into bear-move-FromBridgedChainMessageDispatch
boundless-forest Jun 10, 2022
d3597b0
Fix compile
boundless-forest Jun 10, 2022
7435077
Impl call filter and into dispatch origin for pangoro
boundless-forest Jun 10, 2022
482a61a
That's a hard one to write
boundless-forest Jun 10, 2022
1c5a8bc
Merge branch 'main' into bear-move-FromBridgedChainMessageDispatch
boundless-forest Jun 13, 2022
fe4b2d0
Code clean for pangoro mess
boundless-forest Jun 13, 2022
06c5bc6
Merge branch 'main' into bear-move-FromBridgedChainMessageDispatch
boundless-forest Jun 13, 2022
3449c91
Adapt for pangolin runtime, compile is ok
boundless-forest Jun 13, 2022
b45c2f4
Fix tx validation check
boundless-forest Jun 13, 2022
3ae8454
Fix tx
boundless-forest Jun 13, 2022
2be2623
Fix tx
boundless-forest Jun 13, 2022
885653d
Use patch to dev
boundless-forest Jun 14, 2022
5c48a90
Revert changes
boundless-forest Jun 14, 2022
0d82220
A new version
boundless-forest Jun 14, 2022
1104a1c
Fix compile
boundless-forest Jun 14, 2022
9d3b3c3
Fix tests
boundless-forest Jun 14, 2022
1e39805
Remove useless imports
boundless-forest Jun 14, 2022
7bd2478
Optimal pre_dispatch
boundless-forest Jun 14, 2022
dff1ac9
Add weight check test
boundless-forest Jun 14, 2022
e1dddbc
Rename
boundless-forest Jun 14, 2022
c8618cb
Merge branch 'main' into bear-move-FromBridgedChainMessageDispatch
boundless-forest Jun 16, 2022
dbf382c
Adapt for changes
boundless-forest Jun 16, 2022
07a8452
Code clean
boundless-forest Jun 16, 2022
8784a2c
Add more test
boundless-forest Jun 16, 2022
1f8e5e0
Merge branch 'main' into bear-move-FromBridgedChainMessageDispatch
hackfisher Jun 16, 2022
a631b79
Merge branch 'main' into bear-eth-transact
boundless-forest Jun 16, 2022
f2d684d
Forbid payable call
boundless-forest Jun 16, 2022
62ad6e2
Merge branch 'main' into bear-move-FromBridgedChainMessageDispatch
hackfisher Jun 16, 2022
45c5343
Merge branch 'main' into bear-move-FromBridgedChainMessageDispatch
hackfisher Jun 17, 2022
3315f11
Adapt new trait
boundless-forest Jun 17, 2022
313f6e3
Add todo
boundless-forest Jun 17, 2022
f738983
Add message transact dispatch all, only used by message layer (#1296)
hackfisher Jun 17, 2022
6a59c89
Fix gas limit, and change call from transact to message_transact
hackfisher Jun 17, 2022
ba7b13c
add missing changes
hackfisher Jun 17, 2022
65f210f
check_receiving_before_dispatch and update todos
hackfisher Jun 17, 2022
05ef8d5
Fix dispatch in pangoro runtime
boundless-forest Jun 19, 2022
f7d1e5d
Fix dispatch in pangolin runtime
boundless-forest Jun 19, 2022
af82891
Fix tests
boundless-forest Jun 19, 2022
1f4fad1
Add comments
boundless-forest Jun 19, 2022
e4349b4
Update lock file
boundless-forest Jun 19, 2022
57344c1
fix check (#1297)
hackfisher Jun 20, 2022
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
160 changes: 105 additions & 55 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion frame/dvm/ethereum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ pallet-evm = { default-features = false, git = "https://github.com/darwin
array-bytes = { version = "1.5" }
libsecp256k1 = { version = "0.5", features = ["static-context", "hmac"] }
# darwinia-network
darwinia-balances = { path = "../../balances" }
bp-message-dispatch = { git = "https://github.com/darwinia-network/darwinia-bridges-substrate", branch = "darwinia-v0.12.3" }
bp-runtime = { git = "https://github.com/darwinia-network/darwinia-bridges-substrate", branch = "darwinia-v0.12.3" }
darwinia-balances = { path = "../../balances" }
pallet-bridge-dispatch = { git = "https://github.com/darwinia-network/darwinia-bridges-substrate", branch = "darwinia-v0.12.3" }
# frontier
pallet-evm-precompile-simple = { git = "https://github.com/darwinia-network/frontier", branch = "darwinia-v0.12.3" }

Expand Down
102 changes: 99 additions & 3 deletions frame/dvm/ethereum/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use sha3::{Digest, Keccak256};
// --- paritytech ---
use fp_evm::{Context, Precompile, PrecompileResult, PrecompileSet};
use frame_support::{
traits::{Everything, FindAuthor, GenesisBuild},
traits::{Everything, FindAuthor, GenesisBuild, OriginTrait},
weights::GetDispatchInfo,
ConsensusEngineId, PalletId,
};
Expand All @@ -37,20 +37,21 @@ use pallet_evm_precompile_simple::{ECRecover, Identity, Ripemd160, Sha256};
use sp_core::{H160, H256, U256};
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify},
AccountId32, Perbill, RuntimeDebug,
};
use sp_std::prelude::*;
// --- darwinia-network ---
use crate::{self as darwinia_ethereum, account_basic::*, *};
use bp_message_dispatch::{CallFilter as CallFilterT, IntoDispatchOrigin as IntoDispatchOriginT};
use darwinia_evm::{runner::stack::Runner, EVMCurrencyAdapter, EnsureAddressTruncated};
use darwinia_support::evm::DeriveSubstrateAddress;

type Block = MockBlock<Test>;
pub type SignedExtra = (frame_system::CheckSpecVersion<Test>,);
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test, (), SignedExtra>;
type Balance = u64;

pub type SignedExtra = (frame_system::CheckSpecVersion<Test>,);
pub type EthereumTransactCall = darwinia_ethereum::Call<Test>;
pub type TestRuntimeCall = <Test as frame_system::Config>::Call;

Expand Down Expand Up @@ -239,6 +240,100 @@ impl darwinia_ethereum::Config for Test {
type StateRoot = IntermediateStateRoot;
}

// --- pallet-bridge-dispatch config start ---

pub type BridgeMessageId = [u8; 4];
pub type SubChainId = [u8; 4];
pub const SOURCE_CHAIN_ID: SubChainId = *b"srce";
pub const TARGET_CHAIN_ID: SubChainId = *b"trgt";

pub struct AccountIdConverter;

impl sp_runtime::traits::Convert<H256, AccountId32> for AccountIdConverter {
fn convert(hash: H256) -> AccountId32 {
AccountId32::new(hash.0)
}
}

#[derive(Decode, Encode)]
pub struct EncodedCall(pub Vec<u8>);

impl From<EncodedCall> for Result<Call, ()> {
fn from(call: EncodedCall) -> Result<Call, ()> {
Call::decode(&mut &call.0[..]).map_err(drop)
}
}

pub struct CallFilter;
boundless-forest marked this conversation as resolved.
Show resolved Hide resolved
impl CallFilterT<Origin, Call> for CallFilter {
boundless-forest marked this conversation as resolved.
Show resolved Hide resolved
fn contains(origin: &Origin, call: &Call) -> bool {
boundless-forest marked this conversation as resolved.
Show resolved Hide resolved
match call {
// Note: Only supprt Ethereum::transact(LegacyTransaction)
Call::Ethereum(darwinia_ethereum::Call::transact { transaction: tx }) => {
match origin.caller() {
OriginCaller::Ethereum(RawOrigin::EthereumTransaction(id)) => match tx {
Transaction::Legacy(_) =>
Ethereum::validate_transaction_in_block(*id, tx).is_ok(),
_ => false,
},
_ => false,
}
},
_ => true,
}
}
}

pub struct IntoDispatchOrigin;
impl IntoDispatchOriginT<AccountId32, Call, Origin> for IntoDispatchOrigin {
fn into_dispatch_origin(id: &AccountId32, call: &Call) -> Origin {
match call {
Call::Ethereum(darwinia_ethereum::Call::transact { .. }) => {
let derive_eth_address = id.derive_ethereum_address();
darwinia_ethereum::RawOrigin::EthereumTransaction(derive_eth_address).into()
},
_ => frame_system::RawOrigin::Signed(id.clone()).into(),
}
}
}

#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
pub struct TestAccountPublic(AccountId32);

impl IdentifyAccount for TestAccountPublic {
type AccountId = AccountId32;

fn into_account(self) -> AccountId32 {
self.0
}
}

#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
pub struct TestSignature(AccountId32);

impl Verify for TestSignature {
type Signer = TestAccountPublic;

fn verify<L: sp_runtime::traits::Lazy<[u8]>>(&self, _msg: L, signer: &AccountId32) -> bool {
self.0 == *signer
}
}

impl pallet_bridge_dispatch::Config for Test {
type AccountIdConverter = AccountIdConverter;
type BridgeMessageId = BridgeMessageId;
type Call = Call;
type CallFilter = CallFilter;
type EncodedCall = EncodedCall;
type Event = Event;
type IntoDispatchOrigin = IntoDispatchOrigin;
type SourceChainAccountId = AccountId32;
type TargetChainAccountPublic = TestAccountPublic;
type TargetChainSignature = TestSignature;
}

// --- pallet-bridge-dispatch config end ---

frame_support::construct_runtime! {
pub enum Test where
Block = Block,
Expand All @@ -251,6 +346,7 @@ frame_support::construct_runtime! {
Kton: darwinia_balances::<Instance2>::{Pallet, Call, Storage, Config<T>, Event<T>},
EVM: darwinia_evm::{Pallet, Call, Storage, Config, Event<T>},
Ethereum: darwinia_ethereum::{Pallet, Call, Storage, Config, Event<T>, Origin},
Dispatch: pallet_bridge_dispatch::{Pallet, Call, Event<T>},
}
}

Expand Down
160 changes: 160 additions & 0 deletions frame/dvm/ethereum/src/tests/dispatch_transact.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// This file is part of Darwinia.
//
// Copyright (C) 2018-2022 Darwinia Network
// SPDX-License-Identifier: GPL-3.0
//
// Darwinia is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Darwinia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Darwinia. If not, see <https://www.gnu.org/licenses/>.

// --- crates.io ---
use codec::Encode;
// --- darwinia-network ---
use super::*;
use crate::{tests::legacy::*, Weight};
use bp_message_dispatch::{CallOrigin, MessageDispatch, MessagePayload, SpecVersion};
use bp_runtime::messages::DispatchFeePayment;
use darwinia_evm::AccountBasic;
use darwinia_support::evm::decimal_convert;
// --- paritytech ---
use sp_runtime::AccountId32;

const TEST_SPEC_VERSION: SpecVersion = 0;
const TEST_WEIGHT: Weight = 1_000_000_000_000;

fn prepare_message(
origin: CallOrigin<AccountId32, TestAccountPublic, TestSignature>,
call: Call,
) -> <pallet_bridge_dispatch::Pallet<Test> as MessageDispatch<
<Test as frame_system::Config>::Origin,
<Test as pallet_bridge_dispatch::Config>::BridgeMessageId,
<Test as pallet_bridge_dispatch::Config>::Call,
>>::Message {
MessagePayload {
spec_version: TEST_SPEC_VERSION,
weight: TEST_WEIGHT,
origin,
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
call: EncodedCall(call.encode()),
}
}

fn prepare_source_message(
call: Call,
) -> <pallet_bridge_dispatch::Pallet<Test> as MessageDispatch<
<Test as frame_system::Config>::Origin,
<Test as pallet_bridge_dispatch::Config>::BridgeMessageId,
<Test as pallet_bridge_dispatch::Config>::Call,
>>::Message {
let origin = CallOrigin::SourceAccount(AccountId32::new([1; 32]));
prepare_message(origin, call)
}

#[test]
fn test_dispatch_basic_system_call_works() {
let (_, mut ext) = new_test_ext(1);

ext.execute_with(|| {
let id = [0; 4];
let call = Call::System(frame_system::Call::remark { remark: vec![] });
let mut message = prepare_source_message(call);
message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;

System::set_block_number(1);
let result =
Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| Ok(()));
assert!(result.dispatch_fee_paid_during_dispatch);
assert!(result.dispatch_result);

System::assert_has_event(Event::Dispatch(
pallet_bridge_dispatch::Event::MessageDispatched(SOURCE_CHAIN_ID, id, Ok(())),
));
});
}

#[test]
fn test_dispatch_ethereum_transact_works() {
let (pairs, mut ext) = new_test_ext(1);
let alice = &pairs[0];
ext.execute_with(|| {
let id = [0; 4];
let t = legacy_erc20_creation_transaction(alice);
let call = TestRuntimeCall::Ethereum(EthereumTransactCall::transact { transaction: t });

let mut message = prepare_source_message(call);
message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;
// Ensure the derive ethereum address has enough balance to cover fee.
let origin = H160::from_str("0x308f55f1caf780c5f7a73e2b2b88cb61ee5bec9b").unwrap();
RingAccount::mutate_account_basic_balance(&origin, decimal_convert(1000, None));

System::set_block_number(1);
let result =
Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| Ok(()));
assert!(result.dispatch_result);
// System::assert_has_event(Event::Dispatch(
// pallet_bridge_dispatch::Event::MessageDispatched(SOURCE_CHAIN_ID, id, Ok(())),
// ));
// assert_ne!(RingAccount::account_basic(&origin).balance, decimal_convert(1000, None));
});
}

#[test]
fn test_dispatch_ethereum_transact_invalid_payment() {
let (pairs, mut ext) = new_test_ext(1);
let alice = &pairs[0];
ext.execute_with(|| {
let id = [0; 4];
let t = legacy_erc20_creation_transaction(alice);
let call = TestRuntimeCall::Ethereum(EthereumTransactCall::transact { transaction: t });

let mut message = prepare_source_message(call);
message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;

System::set_block_number(1);
let result =
Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| Ok(()));

assert!(!result.dispatch_result);
System::assert_has_event(Event::Dispatch(
pallet_bridge_dispatch::Event::MessageCallRejected(SOURCE_CHAIN_ID, id),
));
});
}

#[test]
fn test_dispatch_ethereum_transact_invalid_nonce() {
let (pairs, mut ext) = new_test_ext(1);
let alice = &pairs[0];
ext.execute_with(|| {
let id = [0; 4];
let mut unsigned_tx = legacy_erc20_creation_unsigned_transaction();
unsigned_tx.nonce = U256::from(3);
let t = unsigned_tx.sign(&alice.private_key);

let call = TestRuntimeCall::Ethereum(EthereumTransactCall::transact { transaction: t });

let mut message = prepare_source_message(call);
message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;
// Ensure the derive ethereum address has enough balance to cover fee.
let origin = H160::from_str("0x308f55f1caf780c5f7a73e2b2b88cb61ee5bec9b").unwrap();
RingAccount::mutate_account_basic_balance(&origin, decimal_convert(1000, None));

System::set_block_number(1);
let result =
Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| Ok(()));

assert!(!result.dispatch_result);
System::assert_has_event(Event::Dispatch(
pallet_bridge_dispatch::Event::MessageCallRejected(SOURCE_CHAIN_ID, id),
));
});
}
2 changes: 1 addition & 1 deletion frame/dvm/ethereum/src/tests/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn legacy_erc20_creation_unsigned_transaction() -> LegacyUnsignedTransaction
}
}

fn legacy_erc20_creation_transaction(account: &AccountInfo) -> Transaction {
pub fn legacy_erc20_creation_transaction(account: &AccountInfo) -> Transaction {
legacy_erc20_creation_unsigned_transaction().sign(&account.private_key)
}

Expand Down
1 change: 1 addition & 0 deletions frame/dvm/ethereum/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::{
};

mod account_basic;
mod dispatch_transact;
mod eip1559;
mod eip2930;
mod internal;
Expand Down
Loading