Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2,912 changes: 1,387 additions & 1,525 deletions Cargo.lock

Large diffs are not rendered by default.

161 changes: 81 additions & 80 deletions Cargo.toml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fp-storage = { workspace = true, features = ["default"] }
[dev-dependencies]
futures = { workspace = true }
scale-codec = { workspace = true }
tempfile = "3.3.0"
tempfile = "3.20"
# Substrate
sc-block-builder = { workspace = true }
sc-client-db = { workspace = true, features = ["rocksdb"] }
Expand Down
2 changes: 1 addition & 1 deletion client/db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fp-storage = { workspace = true, features = ["default"] }
[dev-dependencies]
futures = { workspace = true }
maplit = "1.0.2"
tempfile = "3.17.1"
tempfile = "3.20"
# Substrate
sc-block-builder = { workspace = true }
sp-consensus = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion client/mapping-sync/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ ethereum = { workspace = true }
ethereum-types = { workspace = true }
scale-codec = { workspace = true }
sqlx = { workspace = true, features = ["runtime-tokio-native-tls", "sqlite"] }
tempfile = "3.17.1"
tempfile = "3.20"
tokio = { workspace = true, features = ["sync"] }
# Substrate
sc-block-builder = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion client/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fp-storage = { workspace = true, features = ["default"] }
pallet-evm = { workspace = true, features = ["default"] }

[dev-dependencies]
tempfile = "3.14.0"
tempfile = "3.20"
# Substrate
sc-block-builder = { workspace = true }
sc-client-db = { workspace = true, features = ["rocksdb"] }
Expand Down
4 changes: 2 additions & 2 deletions frame/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub use ethereum::{
};
use ethereum_types::{Bloom, BloomInput, H160, H256, H64, U256};
use evm::ExitReason;
use scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
// Substrate
use frame_support::{
Expand Down Expand Up @@ -72,7 +72,7 @@ use fp_storage::{EthereumStorageSchema, PALLET_ETHEREUM_SCHEMA};
use pallet_evm::{BlockHashMapping, FeeCalculator, GasWeightMapping, Runner};

#[derive(Clone, Eq, PartialEq, RuntimeDebug)]
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)]
#[derive(Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, TypeInfo)]
pub enum RawOrigin {
EthereumTransaction(H160),
}
Expand Down
27 changes: 20 additions & 7 deletions frame/ethereum/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

//! Test utilities

use core::str::FromStr;
use ethereum::{TransactionAction, TransactionSignature};
use rlp::RlpStream;
// Substrate
Expand All @@ -28,7 +29,8 @@ use sp_runtime::{
};
// Frontier
use pallet_evm::{
config_preludes::ChainId, AddressMapping, BalanceConverter, EvmBalance, SubstrateBalance,
config_preludes::ChainId, AddressMapping, BalanceConverter, EnsureAllowedCreateAddress,
EvmBalance, SubstrateBalance,
};

use super::*;
Expand Down Expand Up @@ -88,6 +90,9 @@ impl FindAuthor<H160> for FindAuthorTruncated {
parameter_types! {
pub const TransactionByteFee: u64 = 1;
pub const GasLimitStorageGrowthRatio: u64 = 0;
// Alice is allowed to create contracts via CREATE and CALL(CREATE)
pub AllowedAddressesCreate: Vec<H160> = vec![H160::from_str("0x1a642f0e3c3af545e7acbd38b07251b3990914f1").expect("alice address")];
pub AllowedAddressesCreateInner: Vec<H160> = vec![H160::from_str("0x1a642f0e3c3af545e7acbd38b07251b3990914f1").expect("alice address")];
}

const EVM_DECIMALS_FACTOR: u64 = 1_000_000_000_u64;
Expand Down Expand Up @@ -131,6 +136,8 @@ impl pallet_evm::Config for Test {
type BalanceConverter = SubtensorEvmBalanceConverter;
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type BlockHashMapping = crate::EthereumBlockHashMapping<Self>;
type CreateOriginFilter = EnsureAllowedCreateAddress<AllowedAddressesCreate>;
type CreateInnerOriginFilter = EnsureAllowedCreateAddress<AllowedAddressesCreateInner>;
type Currency = Balances;
type PrecompilesType = ();
type PrecompilesValue = ();
Expand Down Expand Up @@ -234,9 +241,12 @@ pub fn new_test_ext(accounts_len: usize) -> (Vec<AccountInfo>, sp_io::TestExtern
.map(|i| (pairs[i].account_id.clone(), 10_000_000))
.collect();

pallet_balances::GenesisConfig::<Test> { balances }
.assimilate_storage(&mut ext)
.unwrap();
pallet_balances::GenesisConfig::<Test> {
balances,
dev_accounts: None,
}
.assimilate_storage(&mut ext)
.unwrap();

(pairs, ext.into())
}
Expand All @@ -259,9 +269,12 @@ pub fn new_test_ext_with_initial_balance(
.map(|i| (pairs[i].account_id.clone(), initial_balance))
.collect();

pallet_balances::GenesisConfig::<Test> { balances }
.assimilate_storage(&mut ext)
.unwrap();
pallet_balances::GenesisConfig::<Test> {
balances,
dev_accounts: None,
}
.assimilate_storage(&mut ext)
.unwrap();

(pairs, ext.into())
}
Expand Down
150 changes: 149 additions & 1 deletion frame/ethereum/src/tests/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ use super::*;
use evm::{ExitReason, ExitRevert, ExitSucceed};
use fp_ethereum::{TransactionData, ValidatedTransaction};
use frame_support::{
dispatch::{DispatchClass, GetDispatchInfo},
dispatch::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo},
weights::Weight,
};
use pallet_evm::AddressMapping;
use sp_runtime::{DispatchError, DispatchErrorWithPostInfo, ModuleError};

fn legacy_erc20_creation_unsigned_transaction() -> LegacyUnsignedTransaction {
LegacyUnsignedTransaction {
Expand All @@ -41,6 +42,21 @@ fn legacy_erc20_creation_transaction(account: &AccountInfo) -> Transaction {
legacy_erc20_creation_unsigned_transaction().sign(&account.private_key)
}

fn legacy_foo_bar_contract_creation_unsigned_transaction() -> LegacyUnsignedTransaction {
LegacyUnsignedTransaction {
nonce: U256::zero(),
gas_price: U256::from(1),
gas_limit: U256::from(0x100000),
action: ethereum::TransactionAction::Create,
value: U256::zero(),
input: hex::decode(FOO_BAR_CONTRACT_CREATOR_BYTECODE.trim_end()).unwrap(),
}
}

fn legacy_foo_bar_contract_creation_transaction(account: &AccountInfo) -> Transaction {
legacy_foo_bar_contract_creation_unsigned_transaction().sign(&account.private_key)
}

#[test]
fn transaction_should_increment_nonce() {
let (pairs, mut ext) = new_test_ext(1);
Expand Down Expand Up @@ -273,6 +289,138 @@ fn transaction_should_generate_correct_gas_used() {
});
}

#[test]
fn contract_creation_succeeds_with_allowed_address() {
let (pairs, mut ext) = new_test_ext(1);
let alice = &pairs[0];

ext.execute_with(|| {
// Alice can deploy contracts
let t = LegacyUnsignedTransaction {
nonce: U256::zero(),
gas_price: U256::from(1),
gas_limit: U256::from(0x100000),
action: ethereum::TransactionAction::Create,
value: U256::zero(),
input: hex::decode(TEST_CONTRACT_CODE).unwrap(),
}
.sign(&alice.private_key);
assert_ok!(Ethereum::execute(alice.address, &t, None,));
});
}

#[test]
fn contract_creation_fails_with_not_allowed_address() {
let (pairs, mut ext) = new_test_ext(2);
let bob = &pairs[1];

ext.execute_with(|| {
// Bob can't deploy contracts
let t = LegacyUnsignedTransaction {
nonce: U256::zero(),
gas_price: U256::from(1),
gas_limit: U256::from(0x100000),
action: ethereum::TransactionAction::Create,
value: U256::zero(),
input: hex::decode(TEST_CONTRACT_CODE).unwrap(),
}
.sign(&bob.private_key);

let result = Ethereum::execute(bob.address, &t, None);
assert!(result.is_err());

// Note: assert_err! macro doesn't work here because we receive 'None' as
// 'actual_weight' using assert_err instead of Some(Weight::default()),
// but the error is the same "CreateOriginNotAllowed".
assert_eq!(
result,
Err(DispatchErrorWithPostInfo {
post_info: PostDispatchInfo {
actual_weight: Some(Weight::default()),
pays_fee: Pays::Yes
},
error: DispatchError::Module(ModuleError {
index: 3,
error: [14, 0, 0, 0],
message: Some("CreateOriginNotAllowed")
})
})
);
});
}

#[test]
fn inner_contract_creation_succeeds_with_allowed_address() {
let (pairs, mut ext) = new_test_ext(1);
let alice = &pairs[0];

ext.execute_with(|| {
let t = legacy_foo_bar_contract_creation_transaction(alice);
assert_ok!(Ethereum::execute(alice.address, &t, None,));

let contract_address = hex::decode("32dcab0ef3fb2de2fce1d2e0799d36239671f04a").unwrap();
let new_bar = hex::decode("2fc11060").unwrap();

// Alice is allowed to deploy contracts via inner calls.
let new_bar_inner_creation_tx = LegacyUnsignedTransaction {
nonce: U256::from(1),
gas_price: U256::from(1),
gas_limit: U256::from(0x100000),
action: TransactionAction::Call(H160::from_slice(&contract_address)),
value: U256::zero(),
input: new_bar,
}
.sign(&alice.private_key);

let (_, _, info) =
Ethereum::execute(alice.address, &new_bar_inner_creation_tx, None).unwrap();

assert!(Ethereum::execute(alice.address, &new_bar_inner_creation_tx, None).is_ok());
match info {
CallOrCreateInfo::Call(info) => {
assert_eq!(info.exit_reason, ExitReason::Succeed(ExitSucceed::Returned));
}
CallOrCreateInfo::Create(_) => panic!("expected call info"),
}
});
}

#[test]
fn inner_contract_creation_reverts_with_not_allowed_address() {
let (pairs, mut ext) = new_test_ext(2);
let alice = &pairs[0];
let bob = &pairs[1];

ext.execute_with(|| {
let t = legacy_foo_bar_contract_creation_transaction(alice);
assert_ok!(Ethereum::execute(alice.address, &t, None,));

let contract_address = hex::decode("32dcab0ef3fb2de2fce1d2e0799d36239671f04a").unwrap();
let new_bar = hex::decode("2fc11060").unwrap();

// Bob is not allowed to deploy contracts via inner calls.
let new_bar_inner_creation_tx = LegacyUnsignedTransaction {
nonce: U256::from(1),
gas_price: U256::from(1),
gas_limit: U256::from(0x100000),
action: TransactionAction::Call(H160::from_slice(&contract_address)),
value: U256::zero(),
input: new_bar,
}
.sign(&bob.private_key);

let (_, _, info) =
Ethereum::execute(bob.address, &new_bar_inner_creation_tx, None).unwrap();

match info {
CallOrCreateInfo::Call(info) => {
assert_eq!(info.exit_reason, ExitReason::Revert(ExitRevert::Reverted));
}
CallOrCreateInfo::Create(_) => panic!("expected call info"),
}
});
}

#[test]
fn call_should_handle_errors() {
let (pairs, mut ext) = new_test_ext(1);
Expand Down
23 changes: 23 additions & 0 deletions frame/ethereum/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,26 @@ pub const ERC20_CONTRACT_BYTECODE: &str = include_str!("./res/erc20_contract_byt
// }
// }
pub const TEST_CONTRACT_CODE: &str = "608060405234801561001057600080fd5b50610129806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c8063c2985578146037578063febb0f7e146055575b600080fd5b603d605d565b60405180821515815260200191505060405180910390f35b605b6066565b005b60006001905090565b600060bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260358152602001806100bf6035913960400191505060405180910390fd5b56fe766572795f6c6f6e675f6572726f725f6d73675f746861745f77655f6578706563745f746f5f62655f7472696d6d65645f61776179a26469706673582212207af96dd688d3a3adc999c619e6073d5b6056c72c79ace04a90ea4835a77d179364736f6c634300060c0033";

// pragma solidity ^0.8.2;
// contract Foo {
// function newBar() // 2fc11060
// public
// returns(Bar newContract)
// {
// Bar b = new Bar();
// return b;
// }
//}

// contract Bar {
// function getNumber()
// public
// pure
// returns (uint32 number)
// {
// return 10;
// }
//}
pub const FOO_BAR_CONTRACT_CREATOR_BYTECODE: &str =
include_str!("./res/foo_bar_contract_creator.txt");
1 change: 1 addition & 0 deletions frame/ethereum/src/tests/res/foo_bar_contract_creator.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6080604052348015600e575f80fd5b506102208061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80632fc110601461002d575b5f80fd5b61003561004b565b6040516100429190610102565b60405180910390f35b5f806040516100599061007c565b604051809103905ff080158015610072573d5f803e3d5ffd5b5090508091505090565b60cf8061011c83390190565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f819050919050565b5f6100ca6100c56100c084610088565b6100a7565b610088565b9050919050565b5f6100db826100b0565b9050919050565b5f6100ec826100d1565b9050919050565b6100fc816100e2565b82525050565b5f6020820190506101155f8301846100f3565b9291505056fe6080604052348015600e575f80fd5b5060b580601a5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063f2c9ecd814602a575b5f80fd5b60306044565b604051603b91906068565b60405180910390f35b5f600a905090565b5f63ffffffff82169050919050565b606281604c565b82525050565b5f60208201905060795f830184605b565b9291505056fea2646970667358221220d061ca6930ff12673467107984883595e5f7ee04e63392aed46124a4bd3c4b4f64736f6c63430008190033a2646970667358221220f849f845d87941120b198faa30df2975ad373cbacfb60c64a7f2c0a2a36b502564736f6c63430008190033
10 changes: 10 additions & 0 deletions frame/evm/precompile/dispatch/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ impl pallet_evm::Config for Test {
type GasLimitPovSizeRatio = ();
type GasLimitStorageGrowthRatio = ();
type Timestamp = Timestamp;
type CreateInnerOriginFilter = ();
type CreateOriginFilter = ();
type WeightInfo = ();
}

Expand Down Expand Up @@ -253,11 +255,19 @@ impl PrecompileHandle for MockHandle {
&self.context
}

fn origin(&self) -> H160 {
unimplemented!()
}

fn is_static(&self) -> bool {
unimplemented!()
}

fn gas_limit(&self) -> Option<u64> {
None
}

fn is_contract_being_constructed(&self, _address: H160) -> bool {
unimplemented!()
}
}
Loading
Loading