diff --git a/Cargo.toml b/Cargo.toml index c05aabc5bb4a8..77fa5463a666d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -792,6 +792,7 @@ environmental = { version = "1.1.4", default-features = false } equivocation-detector = { path = "bridges/relays/equivocation" } ethabi = { version = "2.0.0", default-features = false, package = "ethabi-decode" } ethbloom = { version = "0.14.1", default-features = false } +ethereum = { version = "0.18.2", default-features = false } ethereum-types = { version = "0.15.1", default-features = false } exit-future = { version = "0.2.0" } expander = { version = "2.0.0" } diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 7758137b12107..50f19565122de 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -21,6 +21,7 @@ alloy-core = { workspace = true, features = ["sol-types"] } codec = { features = ["derive", "max-encoded-len"], workspace = true } derive_more = { workspace = true, features = ["from", "try_into"] } environmental = { workspace = true } +# ethereum = { workspace = true, features = ["with-scale"] } ethereum-standards = { workspace = true } ethereum-types = { workspace = true, features = ["codec", "rlp", "serialize"] } hex-literal = { workspace = true } @@ -48,6 +49,7 @@ pallet-revive-fixtures = { workspace = true, optional = true } pallet-revive-proc-macro = { workspace = true } pallet-revive-uapi = { workspace = true, features = ["scale"] } pallet-transaction-payment = { workspace = true } +pallet-timestamp = { workspace = true, default-features = true } ripemd = { workspace = true } sp-api = { workspace = true } sp-arithmetic = { workspace = true } @@ -71,7 +73,6 @@ serde_json = { workspace = true } pallet-balances = { workspace = true, default-features = true } pallet-proxy = { workspace = true, default-features = true } pallet-revive-fixtures = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } pallet-utility = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } diff --git a/substrate/frame/revive/rpc/src/receipt_extractor.rs b/substrate/frame/revive/rpc/src/receipt_extractor.rs index 0e5273d4f7501..6d829d9979a49 100644 --- a/substrate/frame/revive/rpc/src/receipt_extractor.rs +++ b/substrate/frame/revive/rpc/src/receipt_extractor.rs @@ -104,8 +104,12 @@ impl ReceiptExtractor { let events = ext.events().await?; let success = events.has::().inspect_err(|err| { - log::debug!(target: LOG_TARGET, "Failed to lookup for ExtrinsicSuccess event in block {block_number}: {err:?}") - })?; + log::debug!( + target: LOG_TARGET, + "Failed to lookup for ExtrinsicSuccess event in block {block_number}: {err:?}" + ); + })?; + let tx_fees = events .find_first::()? .ok_or(ClientError::TxFeeNotFound) diff --git a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs index 549dde9dea954..8fe6b7ff14b4a 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs @@ -74,7 +74,9 @@ fn deserialize_input_or_data<'d, D: Deserializer<'d>>(d: D) -> Result; -#[derive(Debug, Clone, Serialize, Deserialize, From, TryInto, Eq, PartialEq)] +#[derive( + Debug, Clone, Serialize, Deserialize, From, TryInto, Eq, PartialEq, TypeInfo, Encode, Decode, +)] #[serde(untagged)] pub enum HashesOrTransactionInfos { /// Transaction hashes @@ -540,7 +546,9 @@ pub struct SyncingProgress { } /// EIP-1559 transaction. -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] pub struct Transaction1559Unsigned { /// accessList /// EIP-2930 access list @@ -580,7 +588,9 @@ pub struct Transaction1559Unsigned { } /// EIP-2930 transaction. -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] pub struct Transaction2930Unsigned { /// accessList /// EIP-2930 access list @@ -609,7 +619,9 @@ pub struct Transaction2930Unsigned { } /// EIP-4844 transaction. -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] pub struct Transaction4844Unsigned { /// accessList /// EIP-2930 access list @@ -651,7 +663,9 @@ pub struct Transaction4844Unsigned { } /// Legacy transaction. -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] pub struct TransactionLegacyUnsigned { /// chainId /// Chain ID that this transaction is valid on. @@ -675,7 +689,9 @@ pub struct TransactionLegacyUnsigned { pub value: U256, } -#[derive(Debug, Clone, Serialize, Deserialize, From, TryInto, Eq, PartialEq)] +#[derive( + Debug, Clone, Serialize, Deserialize, From, TryInto, Eq, PartialEq, TypeInfo, Encode, Decode, +)] #[serde(untagged)] pub enum TransactionSigned { Transaction4844Signed(Transaction4844Signed), @@ -690,7 +706,9 @@ impl Default for TransactionSigned { } /// Validator withdrawal -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] pub struct Withdrawal { /// recipient address for withdrawal value pub address: Address, @@ -729,7 +747,9 @@ impl Default for FilterTopic { } /// Signed 1559 Transaction -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] pub struct Transaction1559Signed { #[serde(flatten)] pub transaction_1559_unsigned: Transaction1559Unsigned, @@ -749,7 +769,9 @@ pub struct Transaction1559Signed { } /// Signed 2930 Transaction -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] pub struct Transaction2930Signed { #[serde(flatten)] pub transaction_2930_unsigned: Transaction2930Unsigned, @@ -769,7 +791,9 @@ pub struct Transaction2930Signed { } /// Signed 4844 Transaction -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] pub struct Transaction4844Signed { #[serde(flatten)] pub transaction_4844_unsigned: Transaction4844Unsigned, @@ -784,7 +808,9 @@ pub struct Transaction4844Signed { } /// Signed Legacy Transaction -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive( + Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, TypeInfo, Encode, Decode, +)] pub struct TransactionLegacySigned { #[serde(flatten)] pub transaction_legacy_unsigned: TransactionLegacyUnsigned, diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 48380f83899bd..bcc3fa24996c0 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -142,8 +142,15 @@ where fn check(self, lookup: &Lookup) -> Result { if !self.0.is_signed() { - if let Some(crate::Call::eth_transact { payload }) = self.0.function.is_sub_type() { - let checked = E::try_into_checked_extrinsic(payload.to_vec(), self.encoded_size())?; + if let Some(crate::Call::eth_transact { payload, raw_bytes }) = + self.0.function.is_sub_type() + { + let checked = E::try_into_checked_extrinsic( + payload.to_vec(), + raw_bytes.to_vec(), + self.encoded_size(), + )?; + return Ok(checked) }; } @@ -270,11 +277,10 @@ pub trait EthExtra { /// /// # Parameters /// - `payload`: The RLP-encoded Ethereum transaction. - /// - `gas_limit`: The gas limit for the extrinsic - /// - `storage_deposit_limit`: The storage deposit limit for the extrinsic, - /// - `encoded_len`: The encoded length of the extrinsic. + /// - `raw_bytes`: The raw bytes of the Ethereum transaction. fn try_into_checked_extrinsic( payload: Vec, + _raw_bytes: Vec, encoded_len: usize, ) -> Result< CheckedExtrinsic, CallOf, Self::Extension>, @@ -563,7 +569,10 @@ mod test { let payload = account .sign_transaction(tx.clone().try_into_unsigned().unwrap()) .signed_payload(); - let call = RuntimeCall::Contracts(crate::Call::eth_transact { payload }); + let call = RuntimeCall::Contracts(crate::Call::eth_transact { + payload, + raw_bytes: vec![], + }); let encoded_len = call.encoded_size(); let uxt: Ex = generic::UncheckedExtrinsic::new_bare(call).into(); diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index c7dc0d5ab21ac..7a6019ac68af4 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -34,6 +34,7 @@ mod storage; #[cfg(test)] mod tests; mod transient_storage; +// mod types; mod vm; pub mod evm; @@ -45,8 +46,9 @@ pub mod weights; use crate::{ evm::{ - runtime::GAS_PRICE, CallTracer, GasEncoder, GenericTransaction, PrestateTracer, Trace, - Tracer, TracerType, TYPE_EIP1559, + runtime::GAS_PRICE, Block as EthBlock, CallTracer, GasEncoder, GenericTransaction, Log, + PrestateTracer, ReceiptInfo, Trace, Tracer, TracerType, TransactionInfo, TransactionSigned, + TYPE_EIP1559, }, exec::{AccountIdOf, ExecError, Executable, Key, Stack as ExecStack}, gas::GasMeter, @@ -54,9 +56,11 @@ use crate::{ meter::Meter as StorageMeter, AccountInfo, AccountType, ContractInfo, DeletionQueueManager, }, tracing::if_tracing, + // types::BlockV3, vm::{CodeInfo, ContractBlob, RuntimeCosts}, }; -use alloc::{boxed::Box, format, vec}; + +use alloc::{boxed::Box, collections::btree_map::BTreeMap, format, vec}; use codec::{Codec, Decode, Encode}; use environmental::*; use frame_support::{ @@ -80,10 +84,6 @@ use frame_system::{ }; use pallet_transaction_payment::OnChargeTransaction; use scale_info::TypeInfo; -use sp_runtime::{ - traits::{BadOrigin, Bounded, Convert, Dispatchable, Saturating}, - AccountId32, DispatchError, -}; pub use crate::{ address::{ @@ -93,12 +93,18 @@ pub use crate::{ pallet::*, }; pub use codec; -pub use frame_support::{self, dispatch::DispatchInfo, weights::Weight}; +pub use frame_support::{self, dispatch::DispatchInfo, traits::IsSubType, weights::Weight}; pub use frame_system::{self, limits::BlockWeights}; pub use pallet_transaction_payment; pub use primitives::*; -pub use sp_core::{H160, H256, U256}; +pub use sp_core::{keccak_256, H160, H256, U256}; pub use sp_runtime; +use sp_runtime::{ + traits::{ + BadOrigin, Block as BlockT, Bounded, Convert, Dispatchable, ExtrinsicCall, Saturating, + }, + AccountId32, DispatchError, +}; pub use weights::WeightInfo; #[cfg(doc)] @@ -362,6 +368,8 @@ pub mod pallet { /// A list of topics used to index the event. /// Number of topics is capped by [`limits::NUM_EVENT_TOPICS`]. topics: Vec, + // TODO: This needs to be extended with eth tx hash. + // tx hash needs to be stored in the pallet. }, /// Contract deployed by deployer at the specified address. @@ -543,14 +551,305 @@ pub mod pallet { } } + // /// Mapping from transaction index to transaction in the current building block. + // #[pallet::storage] + // pub type Pending = + // CountedStorageMap<_, Identity, u32, (Transaction, TransactionStatus, Receipt), OptionQuery>; + + // /// The current Ethereum block. + // #[pallet::storage] + // pub type CurrentBlock = StorageValue<_, BlockV3>; + + // TODO: This should be bounded at a constant length. + #[pallet::storage] + #[pallet::unbounded] + #[pallet::getter(fn current_eth_block)] + pub type CurrentEthBlock = StorageValue<_, EthBlock>; + // /// The current Ethereum receipts. + // #[pallet::storage] + // pub type CurrentReceipts = StorageValue<_, BoundedVec>>; + + /// The current transaction statuses. + /// + /// TODO: Bounded Vec length must be a constant on the pallet itself. + // #[pallet::storage] + // pub type CurrentTransactionStatuses = + // StorageValue<_, BoundedVec>>; + + // Mapping for block number and hashes. + #[pallet::storage] + pub type BlockHash = StorageMap<_, Twox64Concat, U256, H256, ValueQuery>; + #[pallet::hooks] - impl Hooks> for Pallet { + impl Hooks> for Pallet + where + pallet::Event: From<::RuntimeEvent>, + <::Block as BlockT>::Extrinsic: + ExtrinsicCall::RuntimeCall>, + ::RuntimeCall: IsSubType>, + + ::RuntimeEvent: IsType<::RuntimeEvent>, + + ::RuntimeEvent: + From> + IsType<::RuntimeEvent>, + + // TODO: Does it hold water? + frame_system::Event: TryFrom<::RuntimeEvent>, + frame_system::Event: TryFrom<::RuntimeEvent>, + + // frame_system::Event: TryFrom<::RuntimeEvent>, + // pallet_transaction_payment::Event::TransactionFeePaid + + // type RuntimeEvent: From> + IsType<::RuntimeEvent>; ::RuntimeCall: + // IsSubType>, + + // Must be taken exactly from Pallet::Call to work + BalanceOf: Into + TryFrom, + MomentOf: Into, + T::Hash: frame_support::traits::IsType, + + // For ETH block gas limit + ::RuntimeCall: + Dispatchable, + T: pallet_transaction_payment::Config, + OnChargeTransactionBalanceOf: Into>, + { fn on_idle(_block: BlockNumberFor, limit: Weight) -> Weight { let mut meter = WeightMeter::with_limit(limit); ContractInfo::::process_deletion_queue_batch(&mut meter); meter.consumed() } + fn on_initialize(_n: BlockNumberFor) -> Weight { + // let eth_block = CurrentEthBlock::::get(); + // let parent_state_root = storage::root(sp_runtime::StateVersion::V1); + + // TODO: Return proper weight. + Weight::zero() + } + + fn on_finalize(_: BlockNumberFor) { + // Its impossible at this point to associate the event stored + // with the ETH transaction submitted, if we use read_events_for_pallet. + let extrinsic_count = frame_system::Pallet::::extrinsic_count(); + log::info!("Processing {} extrinsics in block", extrinsic_count); + + // A tuple of (index, extrinsic data, events). + // Filter extrinsics that are not ether transactions. + // Maps the index to the extrinsic data and events. + let mut extrinsics = (0..extrinsic_count) + .into_iter() + .filter_map(|index| { + let extrinsic_data = frame_system::Pallet::::extrinsic_data(index); + + // Decode the encoded extrinsic into T::Extrinsic. + let extrinsic = + match <::Block as BlockT>::Extrinsic::decode( + &mut &extrinsic_data[..], + ) { + Ok(extrinsic) => extrinsic, + Err(_) => return None, + }; + + let call = extrinsic.call(); + + // TODO: check here for timestamp if T::Time::now() is not enough. + // if let Some(call) = call.is_sub_type() { + // if let pallet_timestamp::Call::set { now } = call { + // // Handle the timestamp set call + // } + // } + + if let Some(crate::Call::eth_transact { payload, .. }) = call.is_sub_type() { + Some((index, (payload.clone(), Vec::new()))) + } else { + None + } + }) + .collect::>(); + + for event_record in >::read_events_no_consensus() { + // Event is not correlated to our extrinsics. + match event_record.phase { + frame_system::Phase::ApplyExtrinsic(index) => { + if !extrinsics.contains_key(&index) { + continue; + } + + extrinsics + .get_mut(&index) + .expect("Index exists; qed") + .1 + .push(event_record.event.clone()); + }, + _ => continue, + }; + } + + // For each transaction and call: + let block_number = frame_system::Pallet::::block_number(); + let block_hash = frame_system::Pallet::::block_hash(block_number); + + // For each transaction we need to build: + // TransactionSigned and ReceiptInfo. + let mut total_gas_used = U256::zero(); + let tx_and_receipts = extrinsics + .into_iter() + .filter_map(|(transaction_index, (extrinsic_payload, events))| { + // TODO: Move this to a function. + + // Check if the ExtrinsicSuccess event is present in the events. + let success = events.iter().any(|event| { + // TODO: Avoid cloning. + if let Ok(frame_system::Event::ExtrinsicSuccess { dispatch_info }) = + event.clone().try_into() + { + log::info!( + "Found ExtrinsicSuccess with dispatch_info: {:?}", + dispatch_info + ); + true + } else { + false + } + }); + + // TODO: Calculate the transaction fee. + // let tx_fee = events.iter().find_map(|event| { + // if let Ok(pallet_transaction_payment::Event::TransactionFeePaid { .. }) = + // event.try_into() + // { + // Some(event.clone()) + // } else { + // None + // } + // }); + + let transaction_hash = H256(keccak_256(&extrinsic_payload)); + + // TODO: Don't panic + let signed_tx = TransactionSigned::decode(&mut &extrinsic_payload[..]) + .expect("Extrinsic is valid; qed"); + let from = + signed_tx.recover_eth_address().expect("Cannot recover address; qed"); + + // TODO: Fetch gas price. + let base_gas_price = U256::from(0); + let tx_info = GenericTransaction::from_signed( + signed_tx.clone(), + base_gas_price, + Some(from), + ); + // TODO: Compute gas correctly. + let gas_price = U256::from(0); + let gas_used = U256::from(0); + + let logs = events + .iter() + .filter_map(|event| { + if let Ok(Event::ContractEmitted { contract, data, topics }) = + event.clone().try_into() + { + Some(Log { + address: contract, + topics, + // TODO: No panics. + data: Some(data.into()), + block_number: block_number.into(), + transaction_hash, + transaction_index: transaction_index.into(), + block_hash: block_hash.into(), + // This needs to be extracted from the event.index somehow. + log_index: U256::from(0), // TODO: Set correct log index. + ..Default::default() + }) + } else { + None + } + }) + .collect::>(); + + let contract_address = if tx_info.to.is_none() { + Some(create1( + &from, + tx_info + .nonce + .unwrap_or_default() + .try_into() + // TODO: Do not panic! + .expect("Nonce is a valid u32; qed"), + // .map_err(|_| ClientError::ConversionFailed)?, + )) + } else { + None + }; + + total_gas_used += gas_used; + let receipt = ReceiptInfo::new( + block_hash.into(), + block_number.into(), + contract_address, + from, + logs, + tx_info.to, + gas_price, + gas_used, + success, + transaction_hash, + transaction_index.into(), + tx_info.r#type.unwrap_or_default(), + ); + + Some((signed_tx, receipt)) + }) + .collect::>(); + + // Build EVM block. + let gas_limit = Self::evm_block_gas_limit(); + + // TODO: We can bail out sooner. + let block_author = Self::block_author().expect("Block author must be found; qed"); + let base_fee_per_gas = Self::evm_gas_price(); + + // This or block_number - 1. + let parent_hash = frame_system::Pallet::::parent_hash().into(); + + // Lets assume we are always dealing with a hydrated block. + let transactions = tx_and_receipts + .into_iter() + .map(|(signed, receipt)| TransactionInfo::new(&receipt, signed)) + .collect::>() + .into(); + + // TODO: Fetch somehow? state root and extrinsics root. + let extrinsics_root = H256::default(); + let state_root = H256::default(); + + let eth_block = EthBlock { + hash: block_hash.into(), + parent_hash, + state_root, + miner: block_author, + transactions_root: extrinsics_root, + number: block_number.into(), + // This may be different from the substrate block time, but that's ok. + // The alternative is to dig through the block transactions and get + // pallet_timestamp::Call::set { now: u64 } value. Which is quite expensive. + timestamp: T::Time::now().into(), + difficulty: Some(0u32.into()), + base_fee_per_gas: Some(base_fee_per_gas), + gas_limit, + gas_used: total_gas_used.into(), + receipts_root: extrinsics_root, + transactions, + ..Default::default() + }; + + CurrentEthBlock::::put(eth_block); + } + fn integrity_test() { use limits::code::STATIC_MEMORY_BYTES; @@ -684,9 +983,7 @@ pub mod pallet { /// # Parameters /// /// * `payload`: The encoded [`crate::evm::TransactionSigned`]. - /// * `gas_limit`: The gas limit enforced during contract execution. - /// * `storage_deposit_limit`: The maximum balance that can be charged to the caller for - /// storage usage. + /// * `raw_bytes`: The raw bytes of the transaction, which is used to recover the signer. /// /// # Note /// @@ -697,7 +994,11 @@ pub mod pallet { #[allow(unused_variables)] #[pallet::call_index(0)] #[pallet::weight(Weight::MAX)] - pub fn eth_transact(origin: OriginFor, payload: Vec) -> DispatchResultWithPostInfo { + pub fn eth_transact( + origin: OriginFor, + payload: Vec, + raw_bytes: Vec, + ) -> DispatchResultWithPostInfo { Err(frame_system::Error::CallFiltered::.into()) } @@ -1429,8 +1730,10 @@ where return Err(EthTransactError::Message("Invalid transaction".into())); }; - let eth_transact_call = - crate::Call::::eth_transact { payload: unsigned_tx.dummy_signed_payload() }; + let eth_transact_call = crate::Call::::eth_transact { + payload: unsigned_tx.dummy_signed_payload(), + raw_bytes: vec![], + }; let fee = tx_fee(eth_transact_call.into(), dispatch_call); let raw_gas = Self::evm_fee_to_gas(fee); let eth_gas = @@ -1708,7 +2011,12 @@ sp_api::decl_runtime_apis! { /// Perform an Ethereum call. /// /// See [`crate::Pallet::dry_run_eth_transact`] - fn eth_transact(tx: GenericTransaction) -> Result, EthTransactError>; + fn eth_transact(tx: GenericTransaction, raw_bytes: Vec) -> Result, EthTransactError>; + + /// Fetch the current ETH block from storage. + /// + /// This does not contain the state and transaction roots yet. + fn eth_block() -> EthBlock; /// Upload new code without instantiating a contract from it. /// @@ -1781,6 +2089,15 @@ sp_api::decl_runtime_apis! { } } +// fn decode_eth_transaction(raw_bytes: &[u8]) -> Result +// { let transaction = ethereum::TransactionV3::decode(&mut &raw_bytes[..]) +// .map_err(|_| EthTransactError::Message("Failed to decode transaction".into()))?; + +// let transaction_hash = transaction.hash(); + +// Ok(transaction) +// } + /// This macro wraps substrate's `impl_runtime_apis!` and implements `pallet_revive` runtime APIs. /// /// # Parameters @@ -1825,6 +2142,7 @@ macro_rules! impl_runtime_apis_plus_revive { fn eth_transact( tx: $crate::evm::GenericTransaction, + raw_bytes: Vec, ) -> Result<$crate::EthTransactInfo, $crate::EthTransactError> { use $crate::{ codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get, @@ -1832,6 +2150,14 @@ macro_rules! impl_runtime_apis_plus_revive { sp_runtime::traits::Block as BlockT }; + // // Decode eth raw bytes to a transaction. + // let eth_tx = ethereum::TransactionV3::decode(&mut &raw_bytes[..]) + // .map_err(|_| $crate::EthTransactError::Message("Failed to decode transaction".into()))?; + + // let transaction_hash = eth_tx.hash(); + // // let transaction_index = Pending::::count(); + + let tx_fee = |call: ::RuntimeCall, dispatch_call: ::RuntimeCall| { use $crate::frame_support::dispatch::GetDispatchInfo; @@ -1857,6 +2183,10 @@ macro_rules! impl_runtime_apis_plus_revive { $crate::Pallet::::dry_run_eth_transact(tx, blockweights.max_block, tx_fee) } + fn eth_block() -> EthBlock { + $crate::Pallet::::current_eth_block() + } + fn call( origin: AccountId, dest: $crate::H160, diff --git a/substrate/frame/revive/src/types.rs b/substrate/frame/revive/src/types.rs new file mode 100644 index 0000000000000..bf76e9a9817e5 --- /dev/null +++ b/substrate/frame/revive/src/types.rs @@ -0,0 +1,82 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use std::ops::Deref; + +/// Wrapper for BlockV3 that implements `MaxEncodedLen`. +#[derive(Debug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct BlockV3(ethereum::BlockV3); + +impl codec::MaxEncodedLen for BlockV3 { + fn max_encoded_len() -> usize { + usize::MAX + } +} + +// Passthrough implementations for Encode and Decode +impl From for BlockV3 { + fn from(block: ethereum::BlockV3) -> Self { + BlockV3(block) + } +} + +impl From for ethereum::BlockV3 { + fn from(wrapper: BlockV3) -> Self { + wrapper.0 + } +} + +impl Deref for BlockV3 { + type Target = ethereum::BlockV3; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// Wrapper for ReceiptV4 that implements `MaxEncodedLen`. +#[derive(Debug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct ReceiptV4(ethereum::ReceiptV4); + +impl codec::MaxEncodedLen for ReceiptV4 { + fn max_encoded_len() -> usize { + usize::MAX + } +} + +// Passthrough implementations for Encode and Decode +impl From for ReceiptV4 { + fn from(block: ethereum::ReceiptV4) -> Self { + ReceiptV4(block) + } +} + +impl From for ethereum::ReceiptV4 { + fn from(wrapper: ReceiptV4) -> Self { + wrapper.0 + } +} + +impl Deref for ReceiptV4 { + type Target = ethereum::ReceiptV4; + + fn deref(&self) -> &Self::Target { + &self.0 + } +}