From 193b46b2d301c8eec2cc5422a75d1c726ce58942 Mon Sep 17 00:00:00 2001 From: icodezjb Date: Thu, 20 Jan 2022 13:10:59 +0800 Subject: [PATCH] Merge moonbeam-polkadot-v0.9.13 base on 5f9cf816fcb6b17a7804200a8f0256c109389718 --- Cargo.lock | 22 ++- client/rpc-core/Cargo.toml | 2 +- client/rpc-core/src/types/call_request.rs | 3 + .../rpc-core/src/types/transaction_request.rs | 12 +- client/rpc/Cargo.toml | 4 +- client/rpc/src/eth.rs | 174 +++++++++++++++--- client/rpc/src/eth_pubsub.rs | 11 +- client/rpc/src/lib.rs | 3 +- client/rpc/src/overrides/mod.rs | 39 +++- .../rpc/src/overrides/schema_v1_override.rs | 25 ++- .../rpc/src/overrides/schema_v2_override.rs | 25 ++- .../rpc/src/overrides/schema_v3_override.rs | 151 +++++++++++++++ frame/ethereum/Cargo.toml | 5 +- frame/ethereum/src/lib.rs | 83 ++++++--- frame/evm/Cargo.toml | 2 +- frame/evm/precompile/modexp/src/lib.rs | 56 +++++- frame/evm/test-vector-support/Cargo.toml | 2 +- primitives/consensus/Cargo.toml | 2 +- primitives/evm/Cargo.toml | 2 +- primitives/rpc/Cargo.toml | 2 +- primitives/rpc/src/lib.rs | 42 ++++- primitives/self-contained/Cargo.toml | 2 +- template/node/src/rpc.rs | 7 +- template/runtime/src/lib.rs | 6 +- ts-tests/tests/test-gas.ts | 15 +- 25 files changed, 593 insertions(+), 104 deletions(-) create mode 100644 client/rpc/src/overrides/schema_v3_override.rs diff --git a/Cargo.lock b/Cargo.lock index b9b9e9309a..a53cd711e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -369,6 +369,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "auto_impl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -1397,9 +1409,9 @@ dependencies = [ [[package]] name = "ethereum" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fb916554a4dba293ea69c69ad5653e21d770a9d0c2496b5fa0a1f5a3946d87" +checksum = "34c90e0a755da706ce0970ec0fa8cc48aabcc8e8efa1245336acf718dab06ffe" dependencies = [ "bytes 1.1.0", "ethereum-types", @@ -1438,10 +1450,11 @@ checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" [[package]] name = "evm" -version = "0.33.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2068bbfe82315b76637b601c73810ec7e92d542bad02f0155182915e832c6357" +checksum = "408ffdd509e16de15ea9b51f5333748f6086601f29d445d2ba53dd7e95565574" dependencies = [ + "auto_impl", "environmental", "ethereum", "evm-core", @@ -4143,6 +4156,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" dependencies = [ + "proc-macro-crate 1.1.0", "proc-macro2", "quote", "syn", diff --git a/client/rpc-core/Cargo.toml b/client/rpc-core/Cargo.toml index b076527cf5..82dc8224ab 100644 --- a/client/rpc-core/Cargo.toml +++ b/client/rpc-core/Cargo.toml @@ -12,7 +12,7 @@ jsonrpc-core-client = "18.0" jsonrpc-derive = "18.0" jsonrpc-pubsub = "18.0" rustc-hex = "2.1.0" -ethereum = { version = "0.10.0", features = ["with-codec"] } +ethereum = { version = "0.11.1", features = ["with-codec"] } sha3 = "0.8" ethereum-types = "0.12" serde = { version = "1.0", features = ["derive"] } diff --git a/client/rpc-core/src/types/call_request.rs b/client/rpc-core/src/types/call_request.rs index 4e82157e94..87a4b49265 100644 --- a/client/rpc-core/src/types/call_request.rs +++ b/client/rpc-core/src/types/call_request.rs @@ -17,6 +17,7 @@ // along with this program. If not, see . use crate::types::Bytes; +use ethereum::AccessListItem; use ethereum_types::{H160, U256}; use serde::Deserialize; @@ -43,4 +44,6 @@ pub struct CallRequest { pub data: Option, /// Nonce pub nonce: Option, + /// AccessList + pub access_list: Option>, } diff --git a/client/rpc-core/src/types/transaction_request.rs b/client/rpc-core/src/types/transaction_request.rs index ad7cc95779..fdfddeff30 100644 --- a/client/rpc-core/src/types/transaction_request.rs +++ b/client/rpc-core/src/types/transaction_request.rs @@ -22,7 +22,7 @@ use crate::types::Bytes; use ethereum::{ AccessListItem, EIP1559TransactionMessage, EIP2930TransactionMessage, LegacyTransactionMessage, }; -use ethereum_types::{H160, H256, U256}; +use ethereum_types::{H160, U256}; use serde::{Deserialize, Serialize}; pub enum TransactionMessage { @@ -32,7 +32,7 @@ pub enum TransactionMessage { } /// Transaction request coming from RPC -#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] #[serde(rename_all = "camelCase")] pub struct TransactionRequest { @@ -57,9 +57,9 @@ pub struct TransactionRequest { pub data: Option, /// Transaction's nonce pub nonce: Option, - /// TODO! Pre-pay to warm storage access. + /// Pre-pay to warm storage access. #[serde(default)] - pub access_list: Option)>>, + pub access_list: Option>, } impl Into> for TransactionRequest { @@ -98,7 +98,7 @@ impl Into> for TransactionRequest { .access_list .unwrap() .into_iter() - .map(|(address, slots)| AccessListItem { address, slots }) + .map(|item| item) .collect(), })), // EIP1559 @@ -122,7 +122,7 @@ impl Into> for TransactionRequest { .access_list .unwrap_or(Vec::new()) .into_iter() - .map(|(address, slots)| AccessListItem { address, slots }) + .map(|item| item) .collect(), })) } diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 68deeb81ab..3107e51282 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -13,7 +13,7 @@ jsonrpc-core-client = "18.0" jsonrpc-pubsub = "18.0" log = "0.4.8" ethereum-types = "0.12" -evm = "0.33.0" +evm = "0.33.1" fc-consensus = { version = "2.0.0-dev", path = "../consensus" } fc-db = { version = "2.0.0-dev", path = "../db" } fc-rpc-core = { version = "1.1.0-dev", path = "../rpc-core" } @@ -36,7 +36,7 @@ sc-network = { git = 'https://github.com/paritytech/substrate', branch = "polkad pallet-evm = { version = "6.0.0-dev", path = "../../frame/evm" } fp-evm = { version = "3.0.0-dev", path = "../../primitives/evm" } pallet-ethereum = { version = "4.0.0-dev", path = "../../frame/ethereum" } -ethereum = { version = "0.10.0", features = ["with-codec"] } +ethereum = { version = "0.11.1", features = ["with-codec"] } codec = { package = "parity-scale-codec", version = "2.0.0" } rlp = "0.5" futures = { version = "0.3.1", features = ["compat"] } diff --git a/client/rpc/src/eth.rs b/client/rpc/src/eth.rs index d2a843b90b..e3959e2db0 100644 --- a/client/rpc/src/eth.rs +++ b/client/rpc/src/eth.rs @@ -341,7 +341,7 @@ where let max_duration = time::Duration::from_secs(10); let begin_request = time::Instant::now(); - let mut current_number = to; + let mut current_number = from; // Pre-calculate BloomInput for reuse. let topics_input = if let Some(_) = &filter.topics { @@ -371,7 +371,7 @@ where default_schema = local_cache.get(&cache_keys[0]); } - while current_number >= from { + while current_number <= to { let id = BlockId::Number(current_number); let substrate_hash = client .expect_block_hash_from_id(&id) @@ -430,10 +430,10 @@ where max_duration.as_secs() ))); } - if current_number == Zero::zero() { + if current_number == to { break; } else { - current_number = current_number.saturating_sub(One::one()); + current_number = current_number.saturating_add(One::one()); } } Ok(()) @@ -1078,6 +1078,7 @@ where value, data, nonce, + access_list, } = request; let (gas_price, max_fee_per_gas, max_priority_fee_per_gas) = { @@ -1132,6 +1133,7 @@ where match to { Some(to) => { if api_version == 1 { + // Legacy pre-london #[allow(deprecated)] let info = api.call_before_version_2( &id, @@ -1149,7 +1151,29 @@ where error_on_execution_failure(&info.exit_reason, &info.value)?; Ok(Bytes(info.value)) - } else if api_version >= 2 { + } else if api_version >= 2 && api_version < 4 { + // Post-london + #[allow(deprecated)] + let info = api.call_before_version_4( + &id, + from.unwrap_or_default(), + to, + data, + value.unwrap_or_default(), + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + false, + ) + .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? + .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?; + + error_on_execution_failure(&info.exit_reason, &info.value)?; + Ok(Bytes(info.value)) + } else if api_version == 4 { + // Post-london + access list support + let access_list = access_list.unwrap_or_default(); let info = api .call( &id, @@ -1162,6 +1186,12 @@ where max_priority_fee_per_gas, nonce, false, + Some( + access_list + .into_iter() + .map(|item| (item.address, item.slots)) + .collect(), + ), ) .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?; @@ -1176,6 +1206,7 @@ where } None => { if api_version == 1 { + // Legacy pre-london #[allow(deprecated)] let info = api.create_before_version_2( &id, @@ -1192,7 +1223,28 @@ where error_on_execution_failure(&info.exit_reason, &[])?; Ok(Bytes(info.value[..].to_vec())) - } else if api_version >= 2 { + } else if api_version >= 2 && api_version < 4 { + // Post-london + #[allow(deprecated)] + let info = api.create_before_version_4( + &id, + from.unwrap_or_default(), + data, + value.unwrap_or_default(), + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + false, + ) + .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? + .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?; + + error_on_execution_failure(&info.exit_reason, &[])?; + Ok(Bytes(info.value[..].to_vec())) + } else if api_version == 4 { + // Post-london + access list support + let access_list = access_list.unwrap_or_default(); let info = api .create( &id, @@ -1204,6 +1256,12 @@ where max_priority_fee_per_gas, nonce, false, + Some( + access_list + .into_iter() + .map(|item| (item.address, item.slots)) + .collect(), + ), ) .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?; @@ -1311,6 +1369,7 @@ where value, data, nonce, + access_list, .. } = request; @@ -1322,6 +1381,7 @@ where let (exit_reason, data, used_gas) = match to { Some(to) => { let info = if api_version == 1 { + // Legacy pre-london #[allow(deprecated)] api.call_before_version_2( &BlockId::Hash(best_hash), @@ -1336,7 +1396,26 @@ where ) .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))? + } else if api_version < 4 { + // Post-london + #[allow(deprecated)] + api.call_before_version_4( + &BlockId::Hash(best_hash), + from.unwrap_or_default(), + to, + data, + value.unwrap_or_default(), + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + true, + ) + .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? + .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))? } else { + // Post-london + access list support + let access_list = access_list.unwrap_or_default(); api.call( &BlockId::Hash(best_hash), from.unwrap_or_default(), @@ -1348,6 +1427,12 @@ where max_priority_fee_per_gas, nonce, true, + Some( + access_list + .into_iter() + .map(|item| (item.address, item.slots)) + .collect(), + ), ) .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))? @@ -1357,6 +1442,7 @@ where } None => { let info = if api_version == 1 { + // Legacy pre-london #[allow(deprecated)] api.create_before_version_2( &BlockId::Hash(best_hash), @@ -1370,7 +1456,25 @@ where ) .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))? + } else if api_version < 4 { + // Post-london + #[allow(deprecated)] + api.create_before_version_4( + &BlockId::Hash(best_hash), + from.unwrap_or_default(), + data, + value.unwrap_or_default(), + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + true, + ) + .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? + .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))? } else { + // Post-london + access list support + let access_list = access_list.unwrap_or_default(); api.create( &BlockId::Hash(best_hash), from.unwrap_or_default(), @@ -1381,6 +1485,12 @@ where max_priority_fee_per_gas, nonce, true, + Some( + access_list + .into_iter() + .map(|item| (item.address, item.slots)) + .collect(), + ), ) .map_err(|err| internal_err(format!("runtime error: {:?}", err)))? .map_err(|err| internal_err(format!("execution fatal: {:?}", err)))? @@ -1740,9 +1850,27 @@ where let block_hash = H256::from_slice(Keccak256::digest(&rlp::encode(&block.header)).as_slice()); let receipt = receipts[index].clone(); + + let (logs, logs_bloom, status_code, cumulative_gas_used) = match receipt { + ethereum::ReceiptV3::Legacy(d) + | ethereum::ReceiptV3::EIP2930(d) + | ethereum::ReceiptV3::EIP1559(d) => (d.logs, d.logs_bloom, d.status_code, d.used_gas), + }; + let status = statuses[index].clone(); let mut cumulative_receipts = receipts.clone(); cumulative_receipts.truncate((status.transaction_index + 1) as usize); + let gas_used = if index > 0 { + let previous_receipt = receipts[index - 1].clone(); + let previous_gas_used = match previous_receipt { + ethereum::ReceiptV3::Legacy(d) + | ethereum::ReceiptV3::EIP2930(d) + | ethereum::ReceiptV3::EIP1559(d) => d.used_gas, + }; + cumulative_gas_used.saturating_sub(previous_gas_used) + } else { + cumulative_gas_used + }; let transaction = block.transactions[index].clone(); let effective_gas_price = match transaction { @@ -1762,14 +1890,8 @@ where from: Some(status.from), to: status.to, block_number: Some(block.header.number), - cumulative_gas_used: { - let cumulative_gas: u32 = cumulative_receipts - .iter() - .map(|r| r.used_gas.as_u32()) - .sum(); - U256::from(cumulative_gas) - }, - gas_used: Some(receipt.used_gas), + cumulative_gas_used, + gas_used: Some(gas_used), contract_address: status.contract_address, logs: { let mut pre_receipts_log_index = None; @@ -1778,13 +1900,15 @@ where pre_receipts_log_index = Some( cumulative_receipts .iter() - .map(|r| r.logs.len() as u32) + .map(|r| match r { + ethereum::ReceiptV3::Legacy(d) + | ethereum::ReceiptV3::EIP2930(d) + | ethereum::ReceiptV3::EIP1559(d) => d.logs.len() as u32, + }) .sum::(), ); } - receipt - .logs - .iter() + logs.iter() .enumerate() .map(|(i, log)| Log { address: log.address, @@ -1802,8 +1926,8 @@ where }) .collect() }, - status_code: Some(U64::from(receipt.state_root.to_low_u64_be())), - logs_bloom: receipt.logs_bloom, + status_code: Some(U64::from(status_code)), + logs_bloom: logs_bloom, state_root: None, effective_gas_price, })); @@ -2631,12 +2755,20 @@ where result.gas_used_ratio = gas_used / (gas_target * elasticity_multiplier); + let mut previous_cumulative_gas = U256::zero(); + let used_gas = |current: U256, previous: &mut U256| -> u64 { + let r = current.saturating_sub(*previous).as_u64(); + *previous = current; + r + }; // Build a list of relevant transaction information. let mut transactions: Vec = receipts .iter() .enumerate() .map(|(i, receipt)| TransactionHelper { - gas_used: receipt.used_gas.as_u64(), + gas_used: match receipt { + ethereum::ReceiptV3::Legacy(d) | ethereum::ReceiptV3::EIP2930(d) | ethereum::ReceiptV3::EIP1559(d) => used_gas(d.used_gas, &mut previous_cumulative_gas), + }, effective_reward: match block.transactions.get(i) { Some(ðereum::TransactionV2::Legacy(ref t)) => { t.gas_price.saturating_sub(base_fee).as_u64() diff --git a/client/rpc/src/eth_pubsub.rs b/client/rpc/src/eth_pubsub.rs index 8ab5c45321..90cd91f2ce 100644 --- a/client/rpc/src/eth_pubsub.rs +++ b/client/rpc/src/eth_pubsub.rs @@ -151,7 +151,7 @@ impl SubscriptionResult { pub fn logs( &self, block: EthereumBlock, - receipts: Vec, + receipts: Vec, params: &FilteredParams, ) -> Vec { let block_hash = Some(H256::from_slice( @@ -160,13 +160,18 @@ impl SubscriptionResult { let mut logs: Vec = vec![]; let mut log_index: u32 = 0; for (receipt_index, receipt) in receipts.into_iter().enumerate() { + let receipt_logs = match receipt { + ethereum::ReceiptV3::Legacy(d) + | ethereum::ReceiptV3::EIP2930(d) + | ethereum::ReceiptV3::EIP1559(d) => d.logs, + }; let mut transaction_log_index: u32 = 0; - let transaction_hash: Option = if receipt.logs.len() > 0 { + let transaction_hash: Option = if receipt_logs.len() > 0 { Some(block.transactions[receipt_index as usize].hash()) } else { None }; - for log in receipt.logs { + for log in receipt_logs { if self.add_log(block_hash.unwrap(), &log, &block, params) { logs.push(Log { address: log.address, diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs index f45c0fe062..e9311e9ec8 100644 --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -29,7 +29,8 @@ pub use eth::{ pub use eth_pubsub::{EthPubSubApi, EthPubSubApiServer, HexEncodedIdProvider}; pub use ethereum::TransactionV2 as EthereumTransaction; pub use overrides::{ - OverrideHandle, RuntimeApiStorageOverride, SchemaV1Override, SchemaV2Override, StorageOverride, + OverrideHandle, RuntimeApiStorageOverride, SchemaV1Override, SchemaV2Override, + SchemaV3Override, StorageOverride, }; use ethereum_types::{H160, H256}; diff --git a/client/rpc/src/overrides/mod.rs b/client/rpc/src/overrides/mod.rs index 5f11d7c715..1f07f18733 100644 --- a/client/rpc/src/overrides/mod.rs +++ b/client/rpc/src/overrides/mod.rs @@ -25,11 +25,13 @@ use std::{marker::PhantomData, sync::Arc}; mod schema_v1_override; mod schema_v2_override; +mod schema_v3_override; pub use fc_rpc_core::{EthApiServer, NetApiServer}; use pallet_ethereum::EthereumStorageSchema; pub use schema_v1_override::SchemaV1Override; pub use schema_v2_override::SchemaV2Override; +pub use schema_v3_override::SchemaV3Override; pub struct OverrideHandle { pub schemas: BTreeMap + Send + Sync>>, @@ -49,7 +51,7 @@ pub trait StorageOverride { /// Return the current block. fn current_block(&self, block: &BlockId) -> Option; /// Return the current receipt. - fn current_receipts(&self, block: &BlockId) -> Option>; + fn current_receipts(&self, block: &BlockId) -> Option>; /// Return the current transaction status. fn current_transaction_statuses( &self, @@ -143,8 +145,39 @@ where } /// Return the current receipt. - fn current_receipts(&self, block: &BlockId) -> Option> { - self.client.runtime_api().current_receipts(&block).ok()? + fn current_receipts(&self, block: &BlockId) -> Option> { + let api = self.client.runtime_api(); + + let api_version = if let Ok(Some(api_version)) = + api.api_version::>(&block) + { + api_version + } else { + return None; + }; + if api_version < 4 { + #[allow(deprecated)] + let old_receipts = api.current_receipts_before_version_4(&block).ok()?; + if let Some(receipts) = old_receipts { + Some( + receipts + .into_iter() + .map(|r| { + ethereum::ReceiptV3::Legacy(ethereum::EIP658ReceiptData { + status_code: r.state_root.to_low_u64_be() as u8, + used_gas: r.used_gas, + logs_bloom: r.logs_bloom, + logs: r.logs, + }) + }) + .collect(), + ) + } else { + None + } + } else { + self.client.runtime_api().current_receipts(&block).ok()? + } } /// Return the current transaction status. diff --git a/client/rpc/src/overrides/schema_v1_override.rs b/client/rpc/src/overrides/schema_v1_override.rs index f715fe9f17..002eb1216d 100644 --- a/client/rpc/src/overrides/schema_v1_override.rs +++ b/client/rpc/src/overrides/schema_v1_override.rs @@ -53,14 +53,6 @@ where B: BlockT + Send + Sync + 'static, C: Send + Sync + 'static, { - // My attempt using result - // fn query_storage(&self, id: &BlockId, key: &StorageKey) -> Result { - // let raw_data = self.client.storage(id, key)? - // .ok_or("Storage provider returned Ok(None)")?; - // - // Decode::decode(&mut &raw_data.0[..]).map_err(|_| "Could not decode data".into()) - // } - fn query_storage(&self, id: &BlockId, key: &StorageKey) -> Option { if let Ok(Some(data)) = self.client.storage(id, key) { if let Ok(result) = Decode::decode(&mut &data.0[..]) { @@ -111,11 +103,24 @@ where } /// Return the current receipt. - fn current_receipts(&self, block: &BlockId) -> Option> { - self.query_storage::>( + fn current_receipts(&self, block: &BlockId) -> Option> { + self.query_storage::>( block, &StorageKey(storage_prefix_build(b"Ethereum", b"CurrentReceipts")), ) + .map(|receipts| { + receipts + .into_iter() + .map(|r| { + ethereum::ReceiptV3::Legacy(ethereum::EIP658ReceiptData { + status_code: r.state_root.to_low_u64_be() as u8, + used_gas: r.used_gas, + logs_bloom: r.logs_bloom, + logs: r.logs, + }) + }) + .collect() + }) } /// Return the current transaction status. diff --git a/client/rpc/src/overrides/schema_v2_override.rs b/client/rpc/src/overrides/schema_v2_override.rs index fc0d2e37db..fa8fdc303f 100644 --- a/client/rpc/src/overrides/schema_v2_override.rs +++ b/client/rpc/src/overrides/schema_v2_override.rs @@ -53,14 +53,6 @@ where B: BlockT + Send + Sync + 'static, C: Send + Sync + 'static, { - // My attempt using result - // fn query_storage(&self, id: &BlockId, key: &StorageKey) -> Result { - // let raw_data = self.client.storage(id, key)? - // .ok_or("Storage provider returned Ok(None)")?; - // - // Decode::decode(&mut &raw_data.0[..]).map_err(|_| "Could not decode data".into()) - // } - fn query_storage(&self, id: &BlockId, key: &StorageKey) -> Option { if let Ok(Some(data)) = self.client.storage(id, key) { if let Ok(result) = Decode::decode(&mut &data.0[..]) { @@ -110,11 +102,24 @@ where } /// Return the current receipt. - fn current_receipts(&self, block: &BlockId) -> Option> { - self.query_storage::>( + fn current_receipts(&self, block: &BlockId) -> Option> { + self.query_storage::>( block, &StorageKey(storage_prefix_build(b"Ethereum", b"CurrentReceipts")), ) + .map(|receipts| { + receipts + .into_iter() + .map(|r| { + ethereum::ReceiptV3::Legacy(ethereum::EIP658ReceiptData { + status_code: r.state_root.to_low_u64_be() as u8, + used_gas: r.used_gas, + logs_bloom: r.logs_bloom, + logs: r.logs, + }) + }) + .collect() + }) } /// Return the current transaction status. diff --git a/client/rpc/src/overrides/schema_v3_override.rs b/client/rpc/src/overrides/schema_v3_override.rs new file mode 100644 index 0000000000..95f5b7e2a7 --- /dev/null +++ b/client/rpc/src/overrides/schema_v3_override.rs @@ -0,0 +1,151 @@ +// Copyright 2017-2020 Parity Technologies (UK) Ltd. +// This file is part of Frontier. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +use codec::Decode; +use ethereum_types::{H160, H256, U256}; +use fp_rpc::TransactionStatus; +use sc_client_api::backend::{AuxStore, Backend, StateBackend, StorageProvider}; +use sp_api::BlockId; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use sp_runtime::{ + traits::{BlakeTwo256, Block as BlockT}, + Permill, +}; +use sp_storage::StorageKey; +use std::{marker::PhantomData, sync::Arc}; + +use super::{blake2_128_extend, storage_prefix_build, StorageOverride}; + +/// An override for runtimes that use Schema V1 +pub struct SchemaV3Override { + client: Arc, + _marker: PhantomData<(B, BE)>, +} + +impl SchemaV3Override { + pub fn new(client: Arc) -> Self { + Self { + client, + _marker: PhantomData, + } + } +} + +impl SchemaV3Override +where + C: StorageProvider + AuxStore, + C: HeaderBackend + HeaderMetadata + 'static, + BE: Backend + 'static, + BE::State: StateBackend, + B: BlockT + Send + Sync + 'static, + C: Send + Sync + 'static, +{ + fn query_storage(&self, id: &BlockId, key: &StorageKey) -> Option { + if let Ok(Some(data)) = self.client.storage(id, key) { + if let Ok(result) = Decode::decode(&mut &data.0[..]) { + return Some(result); + } + } + None + } +} + +impl StorageOverride for SchemaV3Override +where + C: StorageProvider, + C: AuxStore, + C: HeaderBackend, + C: HeaderMetadata + 'static, + BE: Backend + 'static, + BE::State: StateBackend, + Block: BlockT + Send + Sync + 'static, + C: Send + Sync + 'static, +{ + /// For a given account address, returns pallet_evm::AccountCodes. + fn account_code_at(&self, block: &BlockId, address: H160) -> Option> { + let mut key: Vec = storage_prefix_build(b"EVM", b"AccountCodes"); + key.extend(blake2_128_extend(address.as_bytes())); + self.query_storage::>(block, &StorageKey(key)) + } + + /// For a given account address and index, returns pallet_evm::AccountStorages. + fn storage_at(&self, block: &BlockId, address: H160, index: U256) -> Option { + let tmp: &mut [u8; 32] = &mut [0; 32]; + index.to_big_endian(tmp); + + let mut key: Vec = storage_prefix_build(b"EVM", b"AccountStorages"); + key.extend(blake2_128_extend(address.as_bytes())); + key.extend(blake2_128_extend(tmp)); + + self.query_storage::(block, &StorageKey(key)) + } + + /// Return the current block. + fn current_block(&self, block: &BlockId) -> Option { + self.query_storage::( + block, + &StorageKey(storage_prefix_build(b"Ethereum", b"CurrentBlock")), + ) + } + + /// Return the current receipt. + fn current_receipts(&self, block: &BlockId) -> Option> { + self.query_storage::>( + block, + &StorageKey(storage_prefix_build(b"Ethereum", b"CurrentReceipts")), + ) + } + + /// Return the current transaction status. + fn current_transaction_statuses( + &self, + block: &BlockId, + ) -> Option> { + self.query_storage::>( + block, + &StorageKey(storage_prefix_build( + b"Ethereum", + b"CurrentTransactionStatuses", + )), + ) + } + + /// Return the base fee at the given height. + fn base_fee(&self, block: &BlockId) -> Option { + self.query_storage::( + block, + &StorageKey(storage_prefix_build(b"BaseFee", b"BaseFeePerGas")), + ) + } + + /// Prior to eip-1559 there is no base fee. + fn elasticity(&self, block: &BlockId) -> Option { + let default_elasticity = Some(Permill::from_parts(125_000)); + let elasticity = self.query_storage::( + block, + &StorageKey(storage_prefix_build(b"BaseFee", b"Elasticity")), + ); + if elasticity.is_some() { + elasticity + } else { + default_elasticity + } + } + + fn is_eip1559(&self, _block: &BlockId) -> bool { + true + } +} diff --git a/frame/ethereum/Cargo.toml b/frame/ethereum/Cargo.toml index e9ce31c1db..afe0f98797 100644 --- a/frame/ethereum/Cargo.toml +++ b/frame/ethereum/Cargo.toml @@ -20,8 +20,8 @@ sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = "polkad sp-std = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } sp-io = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } fp-evm = { version = "3.0.0-dev", default-features = false, path = "../../primitives/evm" } -evm = { version = "0.33.0", features = ["with-codec"], default-features = false } -ethereum = { version = "0.10.0", default-features = false, features = ["with-codec"] } +evm = { version = "0.33.1", features = ["with-codec"], default-features = false } +ethereum = { version = "0.11.1", default-features = false, features = ["with-codec"] } ethereum-types = { version = "0.12", default-features = false } rlp = { version = "0.5", default-features = false } sha3 = { version = "0.8", default-features = false } @@ -65,4 +65,5 @@ std = [ "evm/std", "fp-self-contained/std", "scale-info/std", + "num_enum/std", ] diff --git a/frame/ethereum/src/lib.rs b/frame/ethereum/src/lib.rs index 23db9c12de..b64508e6e4 100644 --- a/frame/ethereum/src/lib.rs +++ b/frame/ethereum/src/lib.rs @@ -48,8 +48,8 @@ use sp_runtime::{ use sp_std::{marker::PhantomData, prelude::*}; pub use ethereum::{ - BlockV2 as Block, LegacyTransactionMessage, Log, Receipt, TransactionAction, - TransactionV2 as Transaction, + AccessListItem, BlockV2 as Block, LegacyTransactionMessage, Log, ReceiptV3 as Receipt, + TransactionAction, TransactionV2 as Transaction, }; pub use fp_rpc::TransactionStatus; @@ -230,7 +230,14 @@ pub mod pallet { 0 } + fn on_runtime_upgrade() -> Weight { + frame_support::storage::unhashed::put::( + &PALLET_ETHEREUM_SCHEMA, + &EthereumStorageSchema::V3, + ); + 0 + } } #[pallet::call] @@ -275,7 +282,7 @@ pub mod pallet { /// Current building block's transactions and receipts. #[pallet::storage] pub(super) type Pending = - StorageValue<_, Vec<(Transaction, TransactionStatus, ethereum::Receipt)>, ValueQuery>; + StorageValue<_, Vec<(Transaction, TransactionStatus, Receipt)>, ValueQuery>; /// The current Ethereum block. #[pallet::storage] @@ -283,7 +290,7 @@ pub mod pallet { /// The current Ethereum receipts. #[pallet::storage] - pub(super) type CurrentReceipts = StorageValue<_, Vec>; + pub(super) type CurrentReceipts = StorageValue<_, Vec>; /// The current transaction statuses. #[pallet::storage] @@ -303,7 +310,7 @@ pub mod pallet { >::store_block(false, U256::zero()); frame_support::storage::unhashed::put::( &PALLET_ETHEREUM_SCHEMA, - &EthereumStorageSchema::V2, + &EthereumStorageSchema::V3, ); } } @@ -399,11 +406,18 @@ impl Pallet { let mut statuses = Vec::new(); let mut receipts = Vec::new(); let mut logs_bloom = Bloom::default(); + let mut cumulative_gas_used = U256::zero(); for (transaction, status, receipt) in Pending::::get() { transactions.push(transaction); statuses.push(status); receipts.push(receipt.clone()); - Self::logs_bloom(receipt.logs.clone(), &mut logs_bloom); + let (logs, used_gas) = match receipt { + Receipt::Legacy(d) | Receipt::EIP2930(d) | Receipt::EIP1559(d) => { + (d.logs.clone(), d.used_gas) + } + }; + cumulative_gas_used = used_gas; + Self::logs_bloom(logs, &mut logs_bloom); } let ommers = Vec::::new(); @@ -418,10 +432,7 @@ impl Pallet { difficulty: U256::zero(), number: block_number, gas_limit: T::BlockGasLimit::get(), - gas_used: receipts - .clone() - .into_iter() - .fold(U256::zero(), |acc, r| acc + r.used_gas), + gas_used: cumulative_gas_used, timestamp: UniqueSaturatedInto::::unique_saturated_into( pallet_timestamp::Pallet::::get(), ), @@ -581,8 +592,9 @@ impl Pallet { } fn apply_validated_transaction(source: H160, transaction: Transaction) -> PostDispatchInfo { + let pending = Pending::::get(); let transaction_hash = transaction.hash(); - let transaction_index = Pending::::get().len() as u32; + let transaction_index = pending.len() as u32; let (to, _, info) = Self::execute(source, &transaction, None) .expect("transaction is already validated; error indicates that the block is invalid"); @@ -626,16 +638,42 @@ impl Pallet { ), }; - let receipt = ethereum::Receipt { - state_root: match reason { - ExitReason::Succeed(_) => H256::from_low_u64_be(1), - ExitReason::Error(_) => H256::from_low_u64_le(0), - ExitReason::Revert(_) => H256::from_low_u64_le(0), - ExitReason::Fatal(_) => H256::from_low_u64_le(0), - }, - used_gas, - logs_bloom: status.clone().logs_bloom, - logs: status.clone().logs, + let receipt = { + let status_code: u8 = match reason { + ExitReason::Succeed(_) => 1, + _ => 0, + }; + let logs_bloom = status.clone().logs_bloom; + let logs = status.clone().logs; + let cumulative_gas_used = if let Some((_, _, receipt)) = pending.last() { + match receipt { + Receipt::Legacy(d) | Receipt::EIP2930(d) | Receipt::EIP1559(d) => { + d.used_gas.saturating_add(used_gas) + } + } + } else { + used_gas + }; + match &transaction { + Transaction::Legacy(_) => Receipt::Legacy(ethereum::EIP658ReceiptData { + status_code, + used_gas: cumulative_gas_used, + logs_bloom, + logs, + }), + Transaction::EIP2930(_) => Receipt::EIP2930(ethereum::EIP2930ReceiptData { + status_code, + used_gas: cumulative_gas_used, + logs_bloom, + logs, + }), + Transaction::EIP1559(_) => Receipt::EIP1559(ethereum::EIP2930ReceiptData { + status_code, + used_gas: cumulative_gas_used, + logs_bloom, + logs, + }), + } }; Pending::::append((transaction, status, receipt)); @@ -671,7 +709,7 @@ impl Pallet { } /// Get receipts by number. - pub fn current_receipts() -> Option> { + pub fn current_receipts() -> Option> { CurrentReceipts::::get() } @@ -828,6 +866,7 @@ pub enum EthereumStorageSchema { Undefined, V1, V2, + V3, } impl Default for EthereumStorageSchema { diff --git a/frame/evm/Cargo.toml b/frame/evm/Cargo.toml index 5d41a71c15..f020b9203e 100644 --- a/frame/evm/Cargo.toml +++ b/frame/evm/Cargo.toml @@ -27,7 +27,7 @@ frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = fp-evm = { version = "3.0.0-dev", default-features = false, path = "../../primitives/evm" } primitive-types = { version = "0.10.0", default-features = false, features = ["rlp", "byteorder"] } rlp = { version = "0.5", default-features = false } -evm = { version = "0.33.0", default-features = false, features = ["with-codec"] } +evm = { version = "0.33.1", default-features = false, features = ["with-codec"] } evm-runtime = { version = "0.33.0", default-features = false } evm-gasometer = { version = "0.33.0", default-features = false } sha3 = { version = "0.8", default-features = false } diff --git a/frame/evm/precompile/modexp/src/lib.rs b/frame/evm/precompile/modexp/src/lib.rs index a7ae46e544..2aaad31bd4 100644 --- a/frame/evm/precompile/modexp/src/lib.rs +++ b/frame/evm/precompile/modexp/src/lib.rs @@ -47,7 +47,10 @@ fn calculate_gas_cost( words += 1; } - // TODO: prevent/handle overflow + // Note: can't overflow because we take words to be some u64 value / 8, which is + // necessarily less than sqrt(u64::MAX). + // Additionally, both base_length and mod_length are bounded to 1024, so this has + // an upper bound of roughly (1024 / 8) squared words * words } @@ -63,8 +66,17 @@ fn calculate_gas_cost( let bytes: [u8; 32] = [0xFF; 32]; let max_256_bit_uint = BigUint::from_bytes_be(&bytes); + // from the EIP spec: + // (8 * (exp_length - 32)) + ((exponent & (2**256 - 1)).bit_length() - 1) + // + // Notes: + // * exp_length is bounded to 1024 and is > 32 + // * exponent can be zero, so we subtract 1 after adding the other terms (whose sum + // must be > 0) + // * the addition can't overflow because the terms are both capped at roughly + // 8 * max size of exp_length (1024) iteration_count = - (8 * (exp_length - 32)) + ((exponent.bitand(max_256_bit_uint)).bits() - 1); + (8 * (exp_length - 32)) + exponent.bitand(max_256_bit_uint).bits() - 1; } max(iteration_count, 1) @@ -89,7 +101,7 @@ fn calculate_gas_cost( // 6) modulus, size as described above // // -// NOTE: input sizes are arbitrarily large (up to 256 bits), with the expectation +// NOTE: input sizes are bound to 1024 bytes, with the expectation // that gas limits would be applied before actual computation. // // maximum stack size will also prevent abuse. @@ -133,7 +145,7 @@ impl Precompile for Modexp { let mod_len_big = BigUint::from_bytes_be(&buf); if mod_len_big > max_size_big { return Err(PrecompileFailure::Error { - exit_status: ExitError::Other("unreasonably large exponent length".into()), + exit_status: ExitError::Other("unreasonably large modulus length".into()), }); } @@ -162,7 +174,6 @@ impl Precompile for Modexp { let exponent = BigUint::from_bytes_be(&input[exp_start..exp_start + exp_len]); // do our gas accounting - // TODO: we could technically avoid reading base first... let gas_cost = calculate_gas_cost(base_len as u64, exp_len as u64, mod_len as u64, &exponent); if let Some(gas_left) = target_gas { @@ -423,4 +434,39 @@ mod tests { } } } + + #[test] + fn test_zero_exp_with_33_length() { + // This is a regression test which ensures that the 'iteration_count' calculation + // in 'calculate_iteration_count' cannot underflow. + // + // In debug mode, this underflow could cause a panic. Otherwise, it causes N**0 to + // be calculated at more-than-normal expense. + // + // TODO: cite security advisory + + let input = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + ]; + + let cost: u64 = 100000; + + let context: Context = Context { + address: Default::default(), + caller: Default::default(), + apparent_value: From::from(0), + }; + + let precompile_result = Modexp::execute(&input, Some(cost), &context, false) + .expect("Modexp::execute() returned error"); + + assert_eq!(precompile_result.output.len(), 1); // should be same length as mod + let result = BigUint::from_bytes_be(&precompile_result.output[..]); + let expected = BigUint::parse_bytes(b"0", 10).unwrap(); + assert_eq!(result, expected); + } } diff --git a/frame/evm/test-vector-support/Cargo.toml b/frame/evm/test-vector-support/Cargo.toml index 4de9e2c4d1..28799aeb63 100644 --- a/frame/evm/test-vector-support/Cargo.toml +++ b/frame/evm/test-vector-support/Cargo.toml @@ -12,7 +12,7 @@ description = "Test vector support for EVM pallet." hex = { version = "0.4.0", optional = true } serde = { version = "1.0.101", optional = true, features = ["derive"] } serde_json = { version = "1.0", optional = true } -evm = { version = "0.33.0", default-features = false, features = ["with-codec"] } +evm = { version = "0.33.1", default-features = false, features = ["with-codec"] } fp-evm = { version = "3.0.0-dev", default-features = false, path = "../../../primitives/evm" } [features] diff --git a/primitives/consensus/Cargo.toml b/primitives/consensus/Cargo.toml index ce7079cf10..1ab3375465 100644 --- a/primitives/consensus/Cargo.toml +++ b/primitives/consensus/Cargo.toml @@ -13,7 +13,7 @@ sp-std = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } sp-core = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } -ethereum = { version = "0.10.0", default-features = false, features = ["with-codec"] } +ethereum = { version = "0.11.1", default-features = false, features = ["with-codec"] } rlp = { version = "0.5", default-features = false } sha3 = { version = "0.8", default-features = false } diff --git a/primitives/evm/Cargo.toml b/primitives/evm/Cargo.toml index 7ba5a4be14..9626480743 100644 --- a/primitives/evm/Cargo.toml +++ b/primitives/evm/Cargo.toml @@ -17,7 +17,7 @@ sp-core = { git = 'https://github.com/paritytech/substrate', branch = "polkadot- sp-std = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -evm = { version = "0.33.0", default-features = false, features = ["with-codec"] } +evm = { version = "0.33.1", default-features = false, features = ["with-codec"] } [features] default = ["std"] diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index c85784e3fd..3e71797521 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" sp-core = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } sp-api = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } fp-evm = { version = "3.0.0-dev", default-features = false, path = "../../primitives/evm" } -ethereum = { version = "0.10.0", default-features = false, features = ["with-codec"] } +ethereum = { version = "0.11.1", default-features = false, features = ["with-codec"] } ethereum-types = { version = "0.12", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } diff --git a/primitives/rpc/src/lib.rs b/primitives/rpc/src/lib.rs index 4c133a1e9e..99d2305132 100644 --- a/primitives/rpc/src/lib.rs +++ b/primitives/rpc/src/lib.rs @@ -51,7 +51,7 @@ impl Default for TransactionStatus { sp_api::decl_runtime_apis! { /// API necessary for Ethereum-compatibility layer. - #[api_version(3)] + #[api_version(4)] pub trait EthereumRuntimeRPCApi { /// Returns runtime defined pallet_evm::ChainId. fn chain_id() -> u64; @@ -77,6 +77,7 @@ sp_api::decl_runtime_apis! { nonce: Option, estimate: bool, ) -> Result; + #[changed_in(4)] fn call( from: H160, to: H160, @@ -88,6 +89,18 @@ sp_api::decl_runtime_apis! { nonce: Option, estimate: bool, ) -> Result; + fn call( + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result; /// Returns a frame_ethereum::create response. #[changed_in(2)] fn create( @@ -99,6 +112,17 @@ sp_api::decl_runtime_apis! { nonce: Option, estimate: bool, ) -> Result; + #[changed_in(4)] + fn create( + from: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + ) -> Result; fn create( from: H160, data: Vec, @@ -108,6 +132,7 @@ sp_api::decl_runtime_apis! { max_priority_fee_per_gas: Option, nonce: Option, estimate: bool, + access_list: Option)>>, ) -> Result; /// Return the current block. Legacy. #[changed_in(2)] @@ -115,20 +140,29 @@ sp_api::decl_runtime_apis! { /// Return the current block. fn current_block() -> Option; /// Return the current receipt. - fn current_receipts() -> Option>; + #[changed_in(4)] + fn current_receipts() -> Option>; + /// Return the current receipt. + fn current_receipts() -> Option>; /// Return the current transaction status. fn current_transaction_statuses() -> Option>; /// Return all the current data for a block in a single runtime call. Legacy. #[changed_in(2)] fn current_all() -> ( Option, - Option>, + Option>, Option> ); /// Return all the current data for a block in a single runtime call. + #[changed_in(4)] + fn current_all() -> ( + Option, + Option>, + Option> + ); fn current_all() -> ( Option, - Option>, + Option>, Option> ); /// Receives a `Vec` and filters all the ethereum transactions. Legacy. diff --git a/primitives/self-contained/Cargo.toml b/primitives/self-contained/Cargo.toml index 5de2feb22c..6cd0089cb9 100644 --- a/primitives/self-contained/Cargo.toml +++ b/primitives/self-contained/Cargo.toml @@ -12,7 +12,7 @@ documentation = "https://docs.rs/fp-ethereum" [dependencies] serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } -ethereum = { version = "0.10.0", default-features = false, features = ["with-codec"] } +ethereum = { version = "0.11.1", default-features = false, features = ["with-codec"] } sp-core = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } sp-io = { git = 'https://github.com/paritytech/substrate', branch = "polkadot-v0.9.11", default-features = false } diff --git a/template/node/src/rpc.rs b/template/node/src/rpc.rs index 5c1461b863..eba4aab6f6 100644 --- a/template/node/src/rpc.rs +++ b/template/node/src/rpc.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use fc_rpc::{ EthBlockDataCache, OverrideHandle, RuntimeApiStorageOverride, SchemaV1Override, - SchemaV2Override, StorageOverride, + SchemaV2Override, SchemaV3Override, StorageOverride, }; use fc_rpc_core::types::{FeeHistoryCache, FilterPool}; use frontier_template_runtime::{opaque::Block, AccountId, Balance, Hash, Index}; @@ -77,6 +77,11 @@ where Box::new(SchemaV2Override::new(client.clone())) as Box + Send + Sync>, ); + overrides_map.insert( + EthereumStorageSchema::V3, + Box::new(SchemaV3Override::new(client.clone())) + as Box + Send + Sync>, + ); Arc::new(OverrideHandle { schemas: overrides_map, diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index b3c2679fbf..540fc69ffd 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -598,6 +598,7 @@ impl_runtime_apis! { max_priority_fee_per_gas: Option, nonce: Option, estimate: bool, + access_list: Option)>>, ) -> Result { let config = if estimate { let mut config = ::config().clone(); @@ -616,7 +617,7 @@ impl_runtime_apis! { max_fee_per_gas, max_priority_fee_per_gas, nonce, - Vec::new(), + access_list.unwrap_or_default(), config.as_ref().unwrap_or(::config()), ).map_err(|err| err.into()) } @@ -630,6 +631,7 @@ impl_runtime_apis! { max_priority_fee_per_gas: Option, nonce: Option, estimate: bool, + access_list: Option)>>, ) -> Result { let config = if estimate { let mut config = ::config().clone(); @@ -647,7 +649,7 @@ impl_runtime_apis! { max_fee_per_gas, max_priority_fee_per_gas, nonce, - Vec::new(), + access_list.unwrap_or_default(), config.as_ref().unwrap_or(::config()), ).map_err(|err| err.into()) } diff --git a/ts-tests/tests/test-gas.ts b/ts-tests/tests/test-gas.ts index 4e1ac995cb..c0ce9958be 100644 --- a/ts-tests/tests/test-gas.ts +++ b/ts-tests/tests/test-gas.ts @@ -1,7 +1,7 @@ import { expect } from "chai"; import Test from "../build/contracts/Test.json" -import { describeWithFrontier, createAndFinalizeBlock } from "./util"; +import { describeWithFrontier, createAndFinalizeBlock,customRequest } from "./util"; import { AbiItem } from "web3-utils"; describeWithFrontier("Frontier RPC (Gas)", (context) => { @@ -58,4 +58,17 @@ describeWithFrontier("Frontier RPC (Gas)", (context) => { expect(await contract.methods.multiply(3).estimateGas()).to.equal(21204); }); + it("eth_estimateGas should handle AccessList alias", async function () { + let result = (await customRequest(context.web3, "eth_estimateGas", [{ + from: GENESIS_ACCOUNT, + data: Test.bytecode, + accessList: [{ + address: "0x0000000000000000000000000000000000000000", + storageKeys: ["0x0000000000000000000000000000000000000000000000000000000000000000"] + }] + }])).result; + // 4300 == 1900 for one key and 2400 for one storage. + expect(result).to.equal(context.web3.utils.numberToHex(196657 + 4300)); + }); + });