Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix custom transaction error code clash, and make ethereum tests easier to write #3359

Merged
merged 7 commits into from
Jan 30, 2025
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
9 changes: 6 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions crates/sp-domains-fraud-proof/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,16 @@ domain-test-service = { version = "0.1.0", path = "../../domains/test/service" }
ethereum = "0.15.0"
fp-rpc = { version = "3.0.0-dev", git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968", features = ['default'] }
fp-self-contained = { version = "1.0.0-dev", git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968", features = ['default'] }
frame-support = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" }
frame-system = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" }
futures = "0.3.31"
libsecp256k1 = { version = "0.7.1", features = ["static-context", "hmac"] }
pallet-balances = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" }
pallet-ethereum = { git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968", features = ['default'] }
pallet-evm = { version = "6.0.0-dev", git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968", default-features = false }
rand = { version = "0.8.5", features = ["min_const_gen"] }
rlp = "0.5.2"
sp-core = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" }
sc-cli = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305", default-features = false }
sp-domains = { version = "0.1.0", default-features = false, features = ["test-ethereum"], path = "../sp-domains" }
sc-service = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305", default-features = false }
subspace-test-service = { version = "0.1.0", path = "../../test/subspace-test-service" }
subspace-runtime-primitives = { version = "0.1.0", path = "../../crates/subspace-runtime-primitives" }
Expand Down
5 changes: 3 additions & 2 deletions crates/sp-domains-fraud-proof/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ mod host_functions;
mod runtime_interface;
pub mod storage_proof;
#[cfg(test)]
pub mod test_ethereum_tx;
#[cfg(test)]
mod tests;
pub mod verification;

Expand Down Expand Up @@ -47,6 +45,9 @@ use subspace_core_primitives::U256;
use subspace_runtime_primitives::{Balance, Moment};

/// Custom invalid validity code for the extrinsics in pallet-domains.
// When updating these error codes, check for clashes between:
// <https://github.com/autonomys/subspace/blob/main/domains/primitives/runtime/src/lib.rs#L85-L88>
// <https://github.com/autonomys/subspace/blob/main/domains/pallets/messenger/src/lib.rs#L49-L53>
#[repr(u8)]
pub enum InvalidTransactionCode {
TransactionProof = 101,
Expand Down
129 changes: 14 additions & 115 deletions crates/sp-domains-fraud-proof/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
use crate::test_ethereum_tx::{
EIP1559UnsignedTransaction, EIP2930UnsignedTransaction, LegacyUnsignedTransaction,
};
use codec::Encode;
use domain_runtime_primitives::{Balance, CheckExtrinsicsValidityError};
use domain_test_service::evm_domain_test_runtime::{
Expand All @@ -11,125 +8,27 @@ use domain_test_service::Sr25519Keyring::Ferdie;
use domain_test_service::{construct_extrinsic_raw_payload, EvmDomainNode};
use ethereum::TransactionV2 as Transaction;
use fp_rpc::EthereumRuntimeRPCApi;
use frame_support::pallet_prelude::DispatchClass;
use pallet_ethereum::Call;
use pallet_evm::GasWeightMapping;
use rand::distributions::{Distribution, Uniform};
use sc_client_api::{HeaderBackend, StorageProof};
use sc_service::{BasePath, Role};
use sp_api::{ApiExt, ProvideRuntimeApi, TransactionOutcome};
use sp_core::ecdsa::Pair;
use sp_core::{keccak_256, Pair as _, H160, H256, U256};
use sp_core::{keccak_256, Pair as _, U256};
use sp_domains::core_api::DomainCoreApi;
use sp_domains::test_ethereum::{
address_build, generate_eip1559_tx, generate_eip2930_tx, generate_legacy_tx, AccountInfo,
};
use sp_runtime::traits::{Extrinsic, Zero};
use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidityError};
use sp_runtime::OpaqueExtrinsic;
use subspace_test_service::{produce_block_with, produce_blocks, MockConsensusNode};
use tempfile::TempDir;

#[derive(Clone)]
pub struct AccountInfo {
pub address: H160,
pub private_key: H256,
}

fn address_build(seed_number: u128) -> AccountInfo {
let mut seed = [0u8; 32];
seed[0..16].copy_from_slice(&seed_number.to_be_bytes());
let private_key = H256::from_slice(&seed);
let secret_key = libsecp256k1::SecretKey::parse_slice(&private_key[..]).unwrap();
let public_key = &libsecp256k1::PublicKey::from_secret_key(&secret_key).serialize()[1..65];
let address = H160::from(H256::from(keccak_256(public_key)));

let mut data = [0u8; 32];
data[0..20].copy_from_slice(&address[..]);

AccountInfo {
private_key,
address,
}
}

fn generate_legacy_tx(
account_info: AccountInfo,
nonce: U256,
action: ethereum::TransactionAction,
input: Vec<u8>,
gas_price: U256,
) -> Transaction {
let limits: frame_system::limits::BlockWeights =
<TestRuntime as frame_system::Config>::BlockWeights::get();
// `limits.get(DispatchClass::Normal).max_extrinsic` is too large to use as `gas_limit`
// thus use `base_extrinsic`
let max_extrinsic = limits.get(DispatchClass::Normal).base_extrinsic * 1000;
let max_extrinsic_gas =
<TestRuntime as pallet_evm::Config>::GasWeightMapping::weight_to_gas(max_extrinsic);

LegacyUnsignedTransaction {
nonce,
gas_price,
gas_limit: U256::from(max_extrinsic_gas),
action,
value: U256::zero(),
input,
}
.sign(&account_info.private_key)
}

fn generate_eip2930_tx(
account_info: AccountInfo,
nonce: U256,
action: ethereum::TransactionAction,
input: Vec<u8>,
gas_price: U256,
) -> Transaction {
let limits: frame_system::limits::BlockWeights =
<TestRuntime as frame_system::Config>::BlockWeights::get();
// `limits.get(DispatchClass::Normal).max_extrinsic` is too large to use as `gas_limit`
// thus use `base_extrinsic`
let max_extrinsic = limits.get(DispatchClass::Normal).base_extrinsic * 100;
let max_extrinsic_gas =
<TestRuntime as pallet_evm::Config>::GasWeightMapping::weight_to_gas(max_extrinsic);

EIP2930UnsignedTransaction {
nonce,
gas_price,
gas_limit: U256::from(max_extrinsic_gas),
action,
value: U256::one(),
input,
}
.sign(&account_info.private_key, None)
}

fn generate_eip1559_tx(
account_info: AccountInfo,
nonce: U256,
action: ethereum::TransactionAction,
input: Vec<u8>,
gas_price: U256,
) -> Transaction {
let limits: frame_system::limits::BlockWeights =
<TestRuntime as frame_system::Config>::BlockWeights::get();
// `limits.get(DispatchClass::Normal).max_extrinsic` is too large to use as `gas_limit`
// thus use `base_extrinsic`
let max_extrinsic = limits.get(DispatchClass::Normal).base_extrinsic * 1000;
let max_extrinsic_gas =
<TestRuntime as pallet_evm::Config>::GasWeightMapping::weight_to_gas(max_extrinsic);

EIP1559UnsignedTransaction {
nonce,
max_priority_fee_per_gas: U256::from(1),
max_fee_per_gas: gas_price,
gas_limit: U256::from(max_extrinsic_gas),
action,
value: U256::zero(),
input,
}
.sign(&account_info.private_key, None)
}

fn generate_evm_domain_extrinsic(tx: Transaction) -> RuntimeUncheckedExtrinsic {
/// Generate a self-contained EVM domain extrinsic.
// This function depends on the macro-constructed `TestRuntime::RuntimeCall` enum, so it can't be
// shared via `sp_domains::test_ethereum`.
pub fn generate_evm_domain_extrinsic(tx: Transaction) -> RuntimeUncheckedExtrinsic {
let call = Call::<TestRuntime>::transact { transaction: tx };
fp_self_contained::UncheckedExtrinsic::new(RuntimeCall::Ethereum(call), None).unwrap()
}
Expand Down Expand Up @@ -191,7 +90,7 @@ async fn benchmark_bundle_with_evm_tx(
);
let extrinsic = match tx_type_to_use {
0 => {
let evm_tx = generate_eip1559_tx(
let evm_tx = generate_eip1559_tx::<TestRuntime>(
account_info.clone(),
U256::zero(),
ethereum::TransactionAction::Create,
Expand All @@ -201,7 +100,7 @@ async fn benchmark_bundle_with_evm_tx(
generate_evm_domain_extrinsic(evm_tx)
}
1 => {
let evm_tx = generate_eip2930_tx(
let evm_tx = generate_eip2930_tx::<TestRuntime>(
account_info.clone(),
U256::zero(),
ethereum::TransactionAction::Create,
Expand All @@ -211,7 +110,7 @@ async fn benchmark_bundle_with_evm_tx(
generate_evm_domain_extrinsic(evm_tx)
}
2 => {
let evm_tx = generate_legacy_tx(
let evm_tx = generate_legacy_tx::<TestRuntime>(
account_info.clone(),
U256::zero(),
ethereum::TransactionAction::Create,
Expand Down Expand Up @@ -727,9 +626,9 @@ async fn test_evm_domain_block_fee() {
let tx_generators: Vec<
Box<dyn Fn(AccountInfo, U256, ethereum::TransactionAction, Vec<u8>, U256) -> Transaction>,
> = vec![
Box::new(generate_eip2930_tx),
Box::new(generate_eip1559_tx),
Box::new(generate_legacy_tx),
Box::new(generate_eip2930_tx::<TestRuntime>),
Box::new(generate_eip1559_tx::<TestRuntime>),
Box::new(generate_legacy_tx::<TestRuntime>),
];
for (i, (acc, tx_generator)) in account_infos
.iter()
Expand Down
16 changes: 16 additions & 0 deletions crates/sp-domains/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ subspace-core-primitives = { version = "0.1.0", default-features = false, path =
subspace-runtime-primitives = { version = "0.1.0", default-features = false, path = "../subspace-runtime-primitives" }
trie-db = { version = "0.29.1", default-features = false }

# test-ethereum dependencies
ethereum = { version = "0.15.0", optional = true }
fp-self-contained = { version = "1.0.0-dev", git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968", features = ['default'], optional = true }
frame-system = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305", optional = true }
libsecp256k1 = { version = "0.7.1", features = ["static-context", "hmac"], optional = true }
pallet-evm = { version = "6.0.0-dev", git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968", default-features = false, optional = true }
rlp = { version = "0.5.2", optional = true }

[dev-dependencies]
num-traits = "0.2.18"
rand = { version = "0.8.5", features = ["min_const_gen"] }
Expand Down Expand Up @@ -70,3 +78,11 @@ std = [
"trie-db/std",
]
runtime-benchmarks = []
test-ethereum = [
"ethereum",
"fp-self-contained",
"frame-system",
"libsecp256k1",
"pallet-evm",
"rlp",
]
26 changes: 15 additions & 11 deletions crates/sp-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ pub mod extrinsics;
pub mod merkle_tree;
pub mod proof_provider_and_verifier;
pub mod storage;
#[cfg(any(test, feature = "test-ethereum"))]
pub mod test_ethereum;
#[cfg(any(test, feature = "test-ethereum"))]
pub mod test_ethereum_tx;
#[cfg(test)]
mod tests;
pub mod valued_trie;
Expand Down Expand Up @@ -968,17 +972,17 @@ impl DomainsDigestItem for DigestItem {

/// EVM chain Id storage key.
///
/// This and next function should ideally use Host function to fetch the storage key
/// This function should ideally use a Host function to fetch the storage key
/// from the domain runtime. But since the Host function is not available at Genesis, we have to
/// assume the storage keys.
/// TODO: once the chain is launched in mainnet, we should use the Host function for all domain instances.
pub(crate) fn evm_chain_id_storage_key() -> StorageKey {
StorageKey(
storage_prefix(
// This is the name used for the `pallet_evm_chain_id` in the `construct_runtime` macro
// This is the name used for `pallet_evm_chain_id` in the `construct_runtime` macro
// i.e. `EVMChainId: pallet_evm_chain_id = 82,`
"EVMChainId".as_bytes(),
// This is the storage item name used inside the `pallet_evm_chain_id`
// This is the storage item name used inside `pallet_evm_chain_id`
"ChainId".as_bytes(),
)
.to_vec(),
Expand All @@ -994,9 +998,9 @@ pub(crate) fn evm_chain_id_storage_key() -> StorageKey {
pub fn domain_total_issuance_storage_key() -> StorageKey {
StorageKey(
storage_prefix(
// This is the name used for the `pallet_balances` in the `construct_runtime` macro
// This is the name used for `pallet_balances` in the `construct_runtime` macro
"Balances".as_bytes(),
// This is the storage item name used inside the `pallet_balances`
// This is the storage item name used inside `pallet_balances`
"TotalIssuance".as_bytes(),
)
.to_vec(),
Expand All @@ -1005,7 +1009,7 @@ pub fn domain_total_issuance_storage_key() -> StorageKey {

/// Account info on frame_system on Domains
///
/// This function should ideally use Host function to fetch the storage key
/// This function should ideally use a Host function to fetch the storage key
/// from the domain runtime. But since the Host function is not available at Genesis, we have to
/// assume the storage keys.
/// TODO: once the chain is launched in mainnet, we should use the Host function for all domain instances.
Expand All @@ -1021,17 +1025,17 @@ pub fn domain_account_storage_key<AccountId: Encode>(who: AccountId) -> StorageK
StorageKey(final_key)
}

/// The storage key of the `SelfDomainId` storage item in the `pallet-domain-id`
/// The storage key of the `SelfDomainId` storage item in `pallet-domain-id`
///
/// Any change to the storage item name or the `pallet-domain-id` name used in the `construct_runtime`
/// Any change to the storage item name or `pallet-domain-id` name used in the `construct_runtime`
/// macro must be reflected here.
pub fn self_domain_id_storage_key() -> StorageKey {
StorageKey(
frame_support::storage::storage_prefix(
// This is the name used for the `pallet-domain-id` in the `construct_runtime` macro
// This is the name used for `pallet-domain-id` in the `construct_runtime` macro
// i.e. `SelfDomainId: pallet_domain_id = 90`
"SelfDomainId".as_bytes(),
// This is the storage item name used inside the `pallet-domain-id`
// This is the storage item name used inside `pallet-domain-id`
"SelfDomainId".as_bytes(),
)
.to_vec(),
Expand Down Expand Up @@ -1552,7 +1556,7 @@ sp_api::decl_runtime_apis! {

/// Returns the last confirmed domain block execution receipt.
fn last_confirmed_domain_block_receipt(domain_id: DomainId) ->Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
}
}

pub trait BundleProducerElectionApi<Balance: Encode + Decode> {
fn bundle_producer_election_params(domain_id: DomainId) -> Option<BundleProducerElectionParams<Balance>>;
Expand Down
Loading
Loading