From 4f4efccab90638b63d2337290dba1d7d62007afd Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 30 Sep 2024 16:48:12 +0200 Subject: [PATCH 001/174] Add RPC integration --- Cargo.lock | 73 +- substrate/bin/node/runtime/src/lib.rs | 28 +- substrate/frame/revive/Cargo.toml | 24 +- substrate/frame/revive/src/address.rs | 4 +- substrate/frame/revive/src/evm.rs | 6 + substrate/frame/revive/src/evm/api.rs | 21 + substrate/frame/revive/src/evm/api/byte.rs | 132 ++++ .../frame/revive/src/evm/api/rlp_codec.rs | 205 ++++++ .../revive/src/evm/api/rpc_methods_gen.rs | 136 ++++ .../frame/revive/src/evm/api/rpc_types.rs | 16 + .../frame/revive/src/evm/api/rpc_types_gen.rs | 634 ++++++++++++++++++ .../frame/revive/src/evm/api/signature.rs | 67 ++ substrate/frame/revive/src/evm/api/type_id.rs | 70 ++ substrate/frame/revive/src/evm/runtime.rs | 269 ++++++++ substrate/frame/revive/src/exec.rs | 33 +- substrate/frame/revive/src/lib.rs | 139 +++- substrate/frame/revive/src/primitives.rs | 54 +- .../frame/revive/src/test_utils/builder.rs | 9 +- substrate/frame/revive/src/wasm/mod.rs | 5 +- umbrella/Cargo.toml | 1 - 20 files changed, 1884 insertions(+), 42 deletions(-) create mode 100644 substrate/frame/revive/src/evm.rs create mode 100644 substrate/frame/revive/src/evm/api.rs create mode 100644 substrate/frame/revive/src/evm/api/byte.rs create mode 100644 substrate/frame/revive/src/evm/api/rlp_codec.rs create mode 100644 substrate/frame/revive/src/evm/api/rpc_methods_gen.rs create mode 100644 substrate/frame/revive/src/evm/api/rpc_types.rs create mode 100644 substrate/frame/revive/src/evm/api/rpc_types_gen.rs create mode 100644 substrate/frame/revive/src/evm/api/signature.rs create mode 100644 substrate/frame/revive/src/evm/api/type_id.rs create mode 100644 substrate/frame/revive/src/evm/runtime.rs diff --git a/Cargo.lock b/Cargo.lock index 97bdc9351357..c9263036d5a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6789,6 +6789,10 @@ name = "futures-timer" version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] [[package]] name = "futures-util" @@ -6924,6 +6928,27 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" +[[package]] +name = "gloo-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http 1.1.0", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "gloo-timers" version = "0.2.6" @@ -6936,6 +6961,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "glutton-westend-runtime" version = "3.0.0" @@ -8014,11 +8052,13 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ec465b607a36dc5dd45d48b7689bc83f679f66a3ac6b6b21cc787a11e0f8685" dependencies = [ + "jsonrpsee-client-transport 0.24.3", "jsonrpsee-core 0.24.3", "jsonrpsee-http-client 0.24.3", "jsonrpsee-proc-macros", "jsonrpsee-server", "jsonrpsee-types 0.24.3", + "jsonrpsee-wasm-client", "jsonrpsee-ws-client 0.24.3", "tokio", "tracing", @@ -8075,7 +8115,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90f0977f9c15694371b8024c35ab58ca043dbbf4b51ccb03db8858a021241df1" dependencies = [ "base64 0.22.1", + "futures-channel", "futures-util", + "gloo-net", "http 1.1.0", "jsonrpsee-core 0.24.3", "pin-project", @@ -8160,6 +8202,7 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "wasm-bindgen-futures", ] [[package]] @@ -8285,6 +8328,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "jsonrpsee-wasm-client" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0470d0ae043ffcb0cd323797a631e637fb4b55fe3eaa6002934819458bba62a7" +dependencies = [ + "jsonrpsee-client-transport 0.24.3", + "jsonrpsee-core 0.24.3", + "jsonrpsee-types 0.24.3", +] + [[package]] name = "jsonrpsee-ws-client" version = "0.23.2" @@ -9013,7 +9067,7 @@ dependencies = [ "futures", "js-sys", "libp2p-core", - "send_wrapper", + "send_wrapper 0.6.0", "wasm-bindgen", "wasm-bindgen-futures", ] @@ -12321,11 +12375,16 @@ dependencies = [ "array-bytes", "assert_matches", "bitflags 1.3.2", + "derive_more", "environmental", + "ethereum-types", "frame-benchmarking", "frame-support", "frame-system", + "hex", + "hex-literal", "impl-trait-for-tuples", + "jsonrpsee 0.24.3", "log", "pallet-assets", "pallet-balances", @@ -12335,6 +12394,7 @@ dependencies = [ "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-timestamp", + "pallet-transaction-payment", "pallet-utility", "parity-scale-codec", "paste", @@ -12342,17 +12402,20 @@ dependencies = [ "pretty_assertions", "rlp", "scale-info", + "secp256k1", "serde", + "serde_json", "sp-api 26.0.0", + "sp-arithmetic 23.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-tracing 16.0.0", + "sp-weights 27.0.0", "staging-xcm", "staging-xcm-builder", - "wat", ] [[package]] @@ -20317,6 +20380,12 @@ dependencies = [ "pest", ] +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + [[package]] name = "send_wrapper" version = "0.6.0" diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 784d74973c32..c59316e3b8db 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -3005,6 +3005,30 @@ impl_runtime_apis! { impl pallet_revive::ReviveApi for Runtime { + fn eth_transact( + from: H160, + dest: Option, + value: Balance, + input: Vec, + gas_limit: Option, + storage_deposit_limit: Option, + ) -> pallet_revive::ContractResult + { + use pallet_revive::AddressMapper; + let blockweights: BlockWeights = ::BlockWeights::get(); + let origin = ::AddressMapper::to_account_id_contract(&from); + Revive::bare_eth_transact( + RuntimeOrigin::signed(origin), + dest, + value, + input, + gas_limit.unwrap_or(blockweights.max_block), + storage_deposit_limit.unwrap_or(u128::MAX), + pallet_revive::DebugInfo::UnsafeDebug, + pallet_revive::CollectEvents::UnsafeCollect, + ) + } + fn call( origin: AccountId, dest: H160, @@ -3012,7 +3036,7 @@ impl_runtime_apis! { gas_limit: Option, storage_deposit_limit: Option, input_data: Vec, - ) -> pallet_revive::ContractExecResult { + ) -> pallet_revive::ContractResult { Revive::bare_call( RuntimeOrigin::signed(origin), dest, @@ -3033,7 +3057,7 @@ impl_runtime_apis! { code: pallet_revive::Code, data: Vec, salt: Option<[u8; 32]>, - ) -> pallet_revive::ContractInstantiateResult + ) -> pallet_revive::ContractResult { Revive::bare_instantiate( RuntimeOrigin::signed(origin), diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 177b3c3e9eec..4a83ef3eceaa 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -27,9 +27,13 @@ codec = { features = [ ], workspace = true } scale-info = { features = ["derive"], workspace = true } log = { workspace = true } -serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +serde = { features = ["alloc", "derive"], workspace = true, default-features = false } impl-trait-for-tuples = { workspace = true } rlp = { workspace = true } +derive_more.workspace = true +hex = { workspace = true } +jsonrpsee = { workspace = true, features = ["full"], optional = true } +ethereum-types = { workspace = true, features = ["codec", "rlp", "serialize"] } # Polkadot SDK Dependencies frame-benchmarking = { optional = true, workspace = true } @@ -39,11 +43,14 @@ pallet-balances = { optional = true, workspace = true } pallet-revive-fixtures = { workspace = true, default-features = false } pallet-revive-uapi = { workspace = true, default-features = true } pallet-revive-proc-macro = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true } sp-api = { workspace = true } +sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +sp-weights = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } @@ -51,7 +58,6 @@ xcm-builder = { workspace = true } array-bytes = { workspace = true, default-features = true } assert_matches = { workspace = true } pretty_assertions = { workspace = true } -wat = { workspace = true } pallet-revive-fixtures = { workspace = true, default-features = true } # Polkadot SDK Dependencies @@ -64,6 +70,9 @@ pallet-proxy = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } xcm-builder = { workspace = true, default-features = true } +secp256k1 = { workspace = true, features = ["recovery"] } +serde_json.workspace = true +hex-literal.workspace = true [features] default = ["std"] @@ -77,6 +86,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "jsonrpsee", "log/std", "pallet-balances?/std", "pallet-proxy/std", @@ -86,13 +96,20 @@ std = [ "polkavm/std", "rlp/std", "scale-info/std", - "serde", + "ethereum-types/std", + "hex/std", + "pallet-transaction-payment/std", + "secp256k1/std", + "serde/std", + "serde_json/std", "sp-api/std", + "sp-arithmetic/std", "sp-core/std", "sp-io/std", "sp-keystore/std", "sp-runtime/std", "sp-std/std", + "sp-weights/std", "xcm-builder/std", "xcm/std", ] @@ -117,6 +134,7 @@ try-runtime = [ "pallet-message-queue/try-runtime", "pallet-proxy/try-runtime", "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", "sp-runtime/try-runtime", ] diff --git a/substrate/frame/revive/src/address.rs b/substrate/frame/revive/src/address.rs index c51940ba771e..3418e49e6f20 100644 --- a/substrate/frame/revive/src/address.rs +++ b/substrate/frame/revive/src/address.rs @@ -17,6 +17,7 @@ //! Functions that deal contract addresses. +use crate::LOG_TARGET; use alloc::vec::Vec; use sp_core::H160; use sp_io::hashing::keccak_256; @@ -34,7 +35,7 @@ use sp_runtime::AccountId32; /// case for all existing runtimes as of right now. Reasing is that this will allow /// us to reverse an address -> account_id mapping by just stripping the prefix. pub trait AddressMapper: private::Sealed { - /// Convert an account id to an ethereum adress. + /// Convert an account id to an ethereum address. /// /// This mapping is **not** required to be reversible. fn to_address(account_id: &T) -> H160; @@ -77,6 +78,7 @@ impl AddressMapper for DefaultAddressMapper { /// Determine the address of a contract using CREATE semantics. pub fn create1(deployer: &H160, nonce: u64) -> H160 { + log::debug!(target: LOG_TARGET, "create1: deployer={deployer:?}, nonce={nonce}"); let mut list = rlp::RlpStream::new_list(2); list.append(&deployer.as_bytes()); list.append(&nonce); diff --git a/substrate/frame/revive/src/evm.rs b/substrate/frame/revive/src/evm.rs new file mode 100644 index 000000000000..018c652aec75 --- /dev/null +++ b/substrate/frame/revive/src/evm.rs @@ -0,0 +1,6 @@ +//!Types, and traits to integrate pallet-revive with EVM. +#![warn(missing_docs)] + +mod api; +pub use api::*; +pub mod runtime; diff --git a/substrate/frame/revive/src/evm/api.rs b/substrate/frame/revive/src/evm/api.rs new file mode 100644 index 000000000000..3fb620df2423 --- /dev/null +++ b/substrate/frame/revive/src/evm/api.rs @@ -0,0 +1,21 @@ +//! JSON-RPC methods and types, for Ethereum. + +mod byte; +pub use byte::*; + +mod rlp_codec; +pub use rlp; + +mod type_id; +pub use type_id::*; + +mod rpc_types; +mod rpc_types_gen; +pub use rpc_types_gen::*; + +#[cfg(feature = "std")] +pub mod rpc_methods_gen; +#[cfg(feature = "std")] +pub use rpc_methods_gen::*; + +mod signature; diff --git a/substrate/frame/revive/src/evm/api/byte.rs b/substrate/frame/revive/src/evm/api/byte.rs new file mode 100644 index 000000000000..164182d5e5a4 --- /dev/null +++ b/substrate/frame/revive/src/evm/api/byte.rs @@ -0,0 +1,132 @@ +//! Define Byte wrapper types for encoding and decoding hex strings +use codec::{Decode, Encode}; +use core::{ + fmt::{Debug, Display, Formatter, Result as FmtResult}, + str::FromStr, +}; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; + +#[cfg(not(feature = "std"))] +use alloc::vec; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +use hex_serde::HexCodec; + +mod hex_serde { + #[cfg(not(feature = "std"))] + use alloc::{format, string::String, vec::Vec}; + use serde::{Deserialize, Deserializer, Serializer}; + + pub trait HexCodec: Sized { + type Error; + fn to_hex(&self) -> String; + fn from_hex(s: String) -> Result; + } + + impl HexCodec for u8 { + type Error = core::num::ParseIntError; + fn to_hex(&self) -> String { + format!("0x{:x}", self) + } + fn from_hex(s: String) -> Result { + u8::from_str_radix(s.trim_start_matches("0x"), 16) + } + } + + impl HexCodec for [u8; T] { + type Error = hex::FromHexError; + fn to_hex(&self) -> String { + format!("0x{}", hex::encode(self)) + } + fn from_hex(s: String) -> Result { + let data = hex::decode(s.trim_start_matches("0x"))?; + data.try_into().map_err(|_| hex::FromHexError::InvalidStringLength) + } + } + + impl HexCodec for Vec { + type Error = hex::FromHexError; + fn to_hex(&self) -> String { + format!("0x{}", hex::encode(self)) + } + fn from_hex(s: String) -> Result { + hex::decode(s.trim_start_matches("0x")) + } + } + + pub fn serialize(value: &T, serializer: S) -> Result + where + S: Serializer, + T: HexCodec, + { + let s = value.to_hex(); + serializer.serialize_str(&s) + } + + pub fn deserialize<'de, D, T>(deserializer: D) -> Result + where + D: Deserializer<'de>, + T: HexCodec, + ::Error: core::fmt::Debug, + { + let s = String::deserialize(deserializer)?; + let value = T::from_hex(s).map_err(|e| serde::de::Error::custom(format!("{:?}", e)))?; + Ok(value) + } +} + +impl FromStr for Bytes { + type Err = hex::FromHexError; + fn from_str(s: &str) -> Result { + let data = hex::decode(s.trim_start_matches("0x"))?; + Ok(Bytes(data)) + } +} + +macro_rules! impl_hex { + ($type:ident, $inner:ty, $default:expr) => { + #[derive(Encode, Decode, Eq, PartialEq, TypeInfo, Clone, Serialize, Deserialize)] + #[doc = concat!("`", stringify!($inner), "`", " wrapper type for encoding and decoding hex strings")] + pub struct $type(#[serde(with = "hex_serde")] pub $inner); + + impl Default for $type { + fn default() -> Self { + $type($default) + } + } + + impl From<$inner> for $type { + fn from(inner: $inner) -> Self { + $type(inner) + } + } + + impl Debug for $type { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, concat!(stringify!($type), "({})"), self.0.to_hex()) + } + } + + impl Display for $type { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, "{}", self.0.to_hex()) + } + } + }; +} + +impl_hex!(Byte, u8, 0u8); +impl_hex!(Bytes, Vec, vec![]); +impl_hex!(Bytes256, [u8; 256], [0u8; 256]); + +#[test] +fn serialize_byte() { + let a = Byte(42); + let s = serde_json::to_string(&a).unwrap(); + assert_eq!(s, "\"0x2a\""); + let b = serde_json::from_str::(&s).unwrap(); + assert_eq!(a, b); +} diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs new file mode 100644 index 000000000000..1d4340eaf5d0 --- /dev/null +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -0,0 +1,205 @@ +//! RLP encoding and decoding for Ethereum transactions. +//! See for more information about RLP encoding. + +use super::*; +use rlp::{Decodable, Encodable}; + +/// See +impl Encodable for TransactionLegacyUnsigned { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + if let Some(chain_id) = self.chain_id { + s.begin_list(9); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + match self.to { + Some(ref to) => s.append(to), + None => s.append_empty_data(), + }; + s.append(&self.value); + s.append(&self.input.0); + s.append(&chain_id); + s.append(&0_u8); + s.append(&0_u8); + } else { + s.begin_list(6); + s.append(&self.nonce); + s.append(&self.gas_price); + s.append(&self.gas); + match self.to { + Some(ref to) => s.append(to), + None => s.append_empty_data(), + }; + s.append(&self.value); + s.append(&self.input.0); + } + } +} + +/// See +impl Decodable for TransactionLegacyUnsigned { + fn decode(rlp: &rlp::Rlp) -> Result { + Ok(TransactionLegacyUnsigned { + nonce: rlp.val_at(0)?, + gas_price: rlp.val_at(1)?, + gas: rlp.val_at(2)?, + to: { + let to = rlp.at(3)?; + if to.is_empty() { + None + } else { + Some(to.as_val()?) + } + }, + value: rlp.val_at(4)?, + input: Bytes(rlp.val_at(5)?), + chain_id: { + if let Ok(chain_id) = rlp.val_at(6) { + Some(chain_id) + } else { + None + } + }, + ..Default::default() + }) + } +} + +impl Encodable for TransactionLegacySigned { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + s.begin_list(9); + s.append(&self.transaction_legacy_unsigned.nonce); + s.append(&self.transaction_legacy_unsigned.gas_price); + s.append(&self.transaction_legacy_unsigned.gas); + match self.transaction_legacy_unsigned.to { + Some(ref to) => s.append(to), + None => s.append_empty_data(), + }; + s.append(&self.transaction_legacy_unsigned.value); + s.append(&self.transaction_legacy_unsigned.input.0); + + s.append(&self.v); + s.append(&self.r); + s.append(&self.s); + } +} + +/// See +impl Decodable for TransactionLegacySigned { + fn decode(rlp: &rlp::Rlp) -> Result { + let v: U256 = rlp.val_at(6)?; + let extract_chain_id = |v: u64| { + if v >= 35 { + Some((v - 35) / 2) + } else { + None + } + }; + + Ok(TransactionLegacySigned { + transaction_legacy_unsigned: { + TransactionLegacyUnsigned { + nonce: rlp.val_at(0)?, + gas_price: rlp.val_at(1)?, + gas: rlp.val_at(2)?, + to: { + let to = rlp.at(3)?; + if to.is_empty() { + None + } else { + Some(to.as_val()?) + } + }, + value: rlp.val_at(4)?, + input: Bytes(rlp.val_at(5)?), + chain_id: extract_chain_id(v.as_u64()).map(|v| v.into()), + r#type: Type0 {}, + } + }, + v, + r: rlp.val_at(7)?, + s: rlp.val_at(8)?, + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + use core::str::FromStr; + use secp256k1::{Message, PublicKey, Secp256k1, SecretKey}; + use sp_core::keccak_256; + + struct Account { + sk: SecretKey, + } + + impl Default for Account { + fn default() -> Self { + Account { + sk: SecretKey::from_str( + "a872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd57f", + ) + .unwrap(), + } + } + } + + impl Account { + fn address(&self) -> H160 { + let pub_key = + PublicKey::from_secret_key(&Secp256k1::new(), &self.sk).serialize_uncompressed(); + let hash = keccak_256(&pub_key[1..]); + H160::from_slice(&hash[12..]) + } + + fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { + let rlp_encoded = tx.rlp_bytes(); + let tx_hash = keccak_256(&rlp_encoded); + let secp = Secp256k1::new(); + let msg = Message::from_digest(tx_hash); + let sig = secp.sign_ecdsa_recoverable(&msg, &self.sk); + let (recovery_id, sig) = sig.serialize_compact(); + let sig = sig.into_iter().chain([recovery_id.to_i32() as u8]).collect::>(); + TransactionLegacySigned::from(tx, &sig.try_into().unwrap()) + } + } + + #[test] + fn encode_decode_legacy_transaction_works() { + let tx = TransactionLegacyUnsigned { + chain_id: Some(596.into()), + gas: U256::from(21000), + nonce: U256::from(1), + gas_price: U256::from("0x640000006a"), + to: Some(H160::from_str("0x1111111111222222222233333333334444444444").unwrap()), + value: U256::from(123123), + input: Bytes(vec![]), + r#type: Type0, + }; + + let rlp_bytes = rlp::encode(&tx); + let decoded = rlp::decode::(&rlp_bytes).unwrap(); + dbg!(&decoded); + } + + #[test] + fn recover_address_works() { + let account = Account::default(); + + let unsigned_tx = TransactionLegacyUnsigned { + value: 200_000_000_000_000_000_000u128.into(), + gas_price: 100_000_000_200u64.into(), + gas: 100_107u32.into(), + nonce: 3.into(), + to: Some(H160::from_str("75e480db528101a381ce68544611c169ad7eb342").unwrap()), + chain_id: Some(596.into()), + ..Default::default() + }; + + let tx = account.sign_transaction(unsigned_tx.clone()); + let recovered_address = tx.recover_eth_address().unwrap(); + + assert_eq!(account.address(), recovered_address); + } +} diff --git a/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs b/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs new file mode 100644 index 000000000000..525615bf957b --- /dev/null +++ b/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs @@ -0,0 +1,136 @@ +//! Generated JSON-RPC methods. +#![allow(missing_docs)] + +use super::*; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[rpc(server, client)] +pub trait EthRpc { + /// Returns a list of addresses owned by client. + #[method(name = "eth_accounts")] + async fn accounts(&self) -> RpcResult>; + + /// Returns the number of most recent block. + #[method(name = "eth_blockNumber")] + async fn block_number(&self) -> RpcResult; + + /// Executes a new message call immediately without creating a transaction on the block chain. + #[method(name = "eth_call")] + async fn call( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult; + + /// Returns the chain ID of the current network. + #[method(name = "eth_chainId")] + async fn chain_id(&self) -> RpcResult; + + /// Generates and returns an estimate of how much gas is necessary to allow the transaction to + /// complete. + #[method(name = "eth_estimateGas")] + async fn estimate_gas( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult; + + /// Returns the current price per gas in wei. + #[method(name = "eth_gasPrice")] + async fn gas_price(&self) -> RpcResult; + + /// Returns the balance of the account of given address. + #[method(name = "eth_getBalance")] + async fn get_balance(&self, address: Address, block: BlockNumberOrTagOrHash) + -> RpcResult; + + /// Returns information about a block by hash. + #[method(name = "eth_getBlockByHash")] + async fn get_block_by_hash( + &self, + block_hash: H256, + hydrated_transactions: bool, + ) -> RpcResult>; + + /// Returns information about a block by number. + #[method(name = "eth_getBlockByNumber")] + async fn get_block_by_number( + &self, + block: BlockNumberOrTag, + hydrated_transactions: bool, + ) -> RpcResult>; + + /// Returns the number of transactions in a block from a block matching the given block hash. + #[method(name = "eth_getBlockTransactionCountByHash")] + async fn get_block_transaction_count_by_hash( + &self, + block_hash: Option, + ) -> RpcResult>; + + /// Returns the number of transactions in a block matching the given block number. + #[method(name = "eth_getBlockTransactionCountByNumber")] + async fn get_block_transaction_count_by_number( + &self, + block: Option, + ) -> RpcResult>; + + /// Returns code at a given address. + #[method(name = "eth_getCode")] + async fn get_code(&self, address: Address, block: BlockNumberOrTagOrHash) -> RpcResult; + + /// Returns the value from a storage position at a given address. + #[method(name = "eth_getStorageAt")] + async fn get_storage_at( + &self, + address: Address, + storage_slot: U256, + block: BlockNumberOrTagOrHash, + ) -> RpcResult; + + /// Returns information about a transaction by block hash and transaction index position. + #[method(name = "eth_getTransactionByBlockHashAndIndex")] + async fn get_transaction_by_block_hash_and_index( + &self, + block_hash: H256, + transaction_index: U256, + ) -> RpcResult>; + + /// Returns information about a transaction by block number and transaction index position. + #[method(name = "eth_getTransactionByBlockNumberAndIndex")] + async fn get_transaction_by_block_number_and_index( + &self, + block: BlockNumberOrTag, + transaction_index: U256, + ) -> RpcResult>; + + /// Returns the information about a transaction requested by transaction hash. + #[method(name = "eth_getTransactionByHash")] + async fn get_transaction_by_hash( + &self, + transaction_hash: H256, + ) -> RpcResult>; + + /// Returns the number of transactions sent from an address. + #[method(name = "eth_getTransactionCount")] + async fn get_transaction_count( + &self, + address: Address, + block: BlockNumberOrTagOrHash, + ) -> RpcResult; + + /// Returns the receipt of a transaction by transaction hash. + #[method(name = "eth_getTransactionReceipt")] + async fn get_transaction_receipt( + &self, + transaction_hash: H256, + ) -> RpcResult>; + + /// Submits a raw transaction. For EIP-4844 transactions, the raw form must be the network form. + /// This means it includes the blobs, KZG commitments, and KZG proofs. + #[method(name = "eth_sendRawTransaction")] + async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult; + + /// The string value of current network id + #[method(name = "net_version")] + async fn net_version(&self) -> RpcResult; +} diff --git a/substrate/frame/revive/src/evm/api/rpc_types.rs b/substrate/frame/revive/src/evm/api/rpc_types.rs new file mode 100644 index 000000000000..22a2c3f7c263 --- /dev/null +++ b/substrate/frame/revive/src/evm/api/rpc_types.rs @@ -0,0 +1,16 @@ +//! Utility impl for the RPC types. +use super::{ReceiptInfo, TransactionInfo, TransactionSigned}; + +impl TransactionInfo { + /// Create a new [`TransactionInfo`] from a receipt and a signed transaction. + pub fn new(receipt: ReceiptInfo, transaction_signed: TransactionSigned) -> Self { + Self { + block_hash: receipt.block_hash, + block_number: receipt.block_number, + from: receipt.from, + hash: receipt.transaction_hash, + transaction_index: receipt.transaction_index, + transaction_signed, + } + } +} diff --git a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs new file mode 100644 index 000000000000..dc4e309f2568 --- /dev/null +++ b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs @@ -0,0 +1,634 @@ +//! Generated JSON-RPC types. +#![allow(missing_docs)] + +use super::{byte::*, Type0, Type1, Type2}; +use codec::{Decode, Encode}; +use derive_more::{From, TryInto}; +pub use ethereum_types::*; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; + +#[cfg(not(feature = "std"))] +use alloc::{string::String, vec::Vec}; + +/// Block object +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Block { + /// Base fee per gas + #[serde(rename = "baseFeePerGas", skip_serializing_if = "Option::is_none")] + pub base_fee_per_gas: Option, + /// Blob gas used + #[serde(rename = "blobGasUsed", skip_serializing_if = "Option::is_none")] + pub blob_gas_used: Option, + /// Difficulty + #[serde(skip_serializing_if = "Option::is_none")] + pub difficulty: Option, + /// Excess blob gas + #[serde(rename = "excessBlobGas", skip_serializing_if = "Option::is_none")] + pub excess_blob_gas: Option, + /// Extra data + #[serde(rename = "extraData")] + pub extra_data: Bytes, + /// Gas limit + #[serde(rename = "gasLimit")] + pub gas_limit: U256, + /// Gas used + #[serde(rename = "gasUsed")] + pub gas_used: U256, + /// Hash + pub hash: H256, + /// Bloom filter + #[serde(rename = "logsBloom")] + pub logs_bloom: Bytes256, + /// Coinbase + pub miner: Address, + /// Mix hash + #[serde(rename = "mixHash")] + pub mix_hash: H256, + /// Nonce + pub nonce: String, + /// Number + pub number: U256, + /// Parent Beacon Block Root + #[serde(rename = "parentBeaconBlockRoot", skip_serializing_if = "Option::is_none")] + pub parent_beacon_block_root: Option, + /// Parent block hash + #[serde(rename = "parentHash")] + pub parent_hash: H256, + /// Receipts root + #[serde(rename = "receiptsRoot")] + pub receipts_root: H256, + /// Ommers hash + #[serde(rename = "sha3Uncles")] + pub sha_3_uncles: H256, + /// Block size + pub size: U256, + /// State root + #[serde(rename = "stateRoot")] + pub state_root: H256, + /// Timestamp + pub timestamp: U256, + /// Total difficulty + #[serde(rename = "totalDifficulty", skip_serializing_if = "Option::is_none")] + pub total_difficulty: Option, + pub transactions: H256OrTransactionInfo, + /// Transactions root + #[serde(rename = "transactionsRoot")] + pub transactions_root: H256, + /// Uncles + pub uncles: Vec, + /// Withdrawals + #[serde(skip_serializing_if = "Option::is_none")] + pub withdrawals: Option>, + /// Withdrawals root + #[serde(rename = "withdrawalsRoot", skip_serializing_if = "Option::is_none")] + pub withdrawals_root: Option, +} + +/// Block number or tag +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum BlockNumberOrTag { + /// Block number + U256(U256), + /// Block tag + BlockTag(BlockTag), +} +impl Default for BlockNumberOrTag { + fn default() -> Self { + BlockNumberOrTag::U256(Default::default()) + } +} + +/// Block number, tag, or block hash +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum BlockNumberOrTagOrHash { + /// Block number + U256(U256), + /// Block tag + BlockTag(BlockTag), + /// Block hash + H256(H256), +} +impl Default for BlockNumberOrTagOrHash { + fn default() -> Self { + BlockNumberOrTagOrHash::U256(Default::default()) + } +} + +/// Transaction object generic to all types +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct GenericTransaction { + /// accessList + /// EIP-2930 access list + #[serde(rename = "accessList", skip_serializing_if = "Option::is_none")] + pub access_list: Option, + /// blobVersionedHashes + /// List of versioned blob hashes associated with the transaction's EIP-4844 data blobs. + #[serde(rename = "blobVersionedHashes", skip_serializing_if = "Option::is_none")] + pub blob_versioned_hashes: Option>, + /// blobs + /// Raw blob data. + #[serde(skip_serializing_if = "Option::is_none")] + pub blobs: Option>, + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId", skip_serializing_if = "Option::is_none")] + pub chain_id: Option, + /// from address + #[serde(skip_serializing_if = "Option::is_none")] + pub from: Option
, + /// gas limit + #[serde(skip_serializing_if = "Option::is_none")] + pub gas: Option, + /// gas price + /// The gas price willing to be paid by the sender in wei + #[serde(rename = "gasPrice", skip_serializing_if = "Option::is_none")] + pub gas_price: Option, + /// input data + #[serde(alias = "data", skip_serializing_if = "Option::is_none")] + pub input: Option, + /// max fee per blob gas + /// The maximum total fee per gas the sender is willing to pay for blob gas in wei + #[serde(rename = "maxFeePerBlobGas", skip_serializing_if = "Option::is_none")] + pub max_fee_per_blob_gas: Option, + /// max fee per gas + /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee + /// and miner / priority fee) in wei + #[serde(rename = "maxFeePerGas", skip_serializing_if = "Option::is_none")] + pub max_fee_per_gas: Option, + /// max priority fee per gas + /// Maximum fee per gas the sender is willing to pay to miners in wei + #[serde(rename = "maxPriorityFeePerGas", skip_serializing_if = "Option::is_none")] + pub max_priority_fee_per_gas: Option, + /// nonce + #[serde(skip_serializing_if = "Option::is_none")] + pub nonce: Option, + /// to address + pub to: Option
, + /// type + #[serde(skip_serializing_if = "Option::is_none")] + pub r#type: Option, + /// value + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, +} + +/// Receipt information +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct ReceiptInfo { + /// blob gas price + /// The actual value per gas deducted from the sender's account for blob gas. Only specified + /// for blob transactions as defined by EIP-4844. + #[serde(rename = "blobGasPrice", skip_serializing_if = "Option::is_none")] + pub blob_gas_price: Option, + /// blob gas used + /// The amount of blob gas used for this specific transaction. Only specified for blob + /// transactions as defined by EIP-4844. + #[serde(rename = "blobGasUsed", skip_serializing_if = "Option::is_none")] + pub blob_gas_used: Option, + /// block hash + #[serde(rename = "blockHash")] + pub block_hash: H256, + /// block number + #[serde(rename = "blockNumber")] + pub block_number: U256, + /// contract address + /// The contract address created, if the transaction was a contract creation, otherwise null. + #[serde(rename = "contractAddress")] + pub contract_address: Option
, + /// cumulative gas used + /// The sum of gas used by this transaction and all preceding transactions in the same block. + #[serde(rename = "cumulativeGasUsed")] + pub cumulative_gas_used: U256, + /// effective gas price + /// The actual value per gas deducted from the sender's account. Before EIP-1559, this is equal + /// to the transaction's gas price. After, it is equal to baseFeePerGas + min(maxFeePerGas - + /// baseFeePerGas, maxPriorityFeePerGas). + #[serde(rename = "effectiveGasPrice")] + pub effective_gas_price: U256, + /// from + pub from: Address, + /// gas used + /// The amount of gas used for this specific transaction alone. + #[serde(rename = "gasUsed")] + pub gas_used: U256, + /// logs + pub logs: Vec, + /// logs bloom + #[serde(rename = "logsBloom")] + pub logs_bloom: Bytes256, + /// state root + /// The post-transaction state root. Only specified for transactions included before the + /// Byzantium upgrade. + #[serde(skip_serializing_if = "Option::is_none")] + pub root: Option, + /// status + /// Either 1 (success) or 0 (failure). Only specified for transactions included after the + /// Byzantium upgrade. + #[serde(skip_serializing_if = "Option::is_none")] + pub status: Option, + /// to + /// Address of the receiver or null in a contract creation transaction. + pub to: Option
, + /// transaction hash + #[serde(rename = "transactionHash")] + pub transaction_hash: H256, + /// transaction index + #[serde(rename = "transactionIndex")] + pub transaction_index: U256, + /// type + #[serde(skip_serializing_if = "Option::is_none")] + pub r#type: Option, +} + +/// Transaction information +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct TransactionInfo { + /// block hash + #[serde(rename = "blockHash")] + pub block_hash: H256, + /// block number + #[serde(rename = "blockNumber")] + pub block_number: U256, + /// from address + pub from: Address, + /// transaction hash + pub hash: H256, + /// transaction index + #[serde(rename = "transactionIndex")] + pub transaction_index: U256, + #[serde(flatten)] + pub transaction_signed: TransactionSigned, +} + +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum TransactionUnsigned { + Transaction4844Unsigned(Transaction4844Unsigned), + Transaction1559Unsigned(Transaction1559Unsigned), + Transaction2930Unsigned(Transaction2930Unsigned), + TransactionLegacyUnsigned(TransactionLegacyUnsigned), +} +impl Default for TransactionUnsigned { + fn default() -> Self { + TransactionUnsigned::Transaction4844Unsigned(Default::default()) + } +} + +/// Access list +pub type AccessList = Vec; + +/// Block tag +/// `earliest`: The lowest numbered block the client has available; `finalized`: The most recent +/// crypto-economically secure block, cannot be re-orged outside of manual intervention driven by +/// community coordination; `safe`: The most recent block that is safe from re-orgs under honest +/// majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical +/// chain observed by the client, this block may be re-orged out of the canonical chain even under +/// healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` +/// and containing the set of transactions usually taken from local mempool. Before the merge +/// transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to +/// with `-39001: Unknown block` error +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub enum BlockTag { + #[serde(rename = "earliest")] + #[default] + Earliest, + #[serde(rename = "finalized")] + Finalized, + #[serde(rename = "safe")] + Safe, + #[serde(rename = "latest")] + Latest, + #[serde(rename = "pending")] + Pending, +} + +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum H256OrTransactionInfo { + /// Transaction hashes + H256s(Vec), + /// Full transactions + TransactionInfos(Vec), +} +impl Default for H256OrTransactionInfo { + fn default() -> Self { + H256OrTransactionInfo::H256s(Default::default()) + } +} + +/// log +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Log { + /// address + #[serde(skip_serializing_if = "Option::is_none")] + pub address: Option
, + /// block hash + #[serde(rename = "blockHash", skip_serializing_if = "Option::is_none")] + pub block_hash: Option, + /// block number + #[serde(rename = "blockNumber", skip_serializing_if = "Option::is_none")] + pub block_number: Option, + /// data + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, + /// log index + #[serde(rename = "logIndex", skip_serializing_if = "Option::is_none")] + pub log_index: Option, + /// removed + #[serde(skip_serializing_if = "Option::is_none")] + pub removed: Option, + /// topics + #[serde(skip_serializing_if = "Option::is_none")] + pub topics: Option>, + /// transaction hash + #[serde(rename = "transactionHash")] + pub transaction_hash: H256, + /// transaction index + #[serde(rename = "transactionIndex", skip_serializing_if = "Option::is_none")] + pub transaction_index: Option, +} + +/// EIP-1559 transaction. +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction1559Unsigned { + /// accessList + /// EIP-2930 access list + #[serde(rename = "accessList")] + pub access_list: AccessList, + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId")] + pub chain_id: U256, + /// gas limit + pub gas: U256, + /// gas price + /// The effective gas price paid by the sender in wei. For transactions not yet included in a + /// block, this value should be set equal to the max fee per gas. This field is DEPRECATED, + /// please transition to using effectiveGasPrice in the receipt object going forward. + #[serde(rename = "gasPrice")] + pub gas_price: U256, + /// input data + pub input: Bytes, + /// max fee per gas + /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee + /// and miner / priority fee) in wei + #[serde(rename = "maxFeePerGas")] + pub max_fee_per_gas: U256, + /// max priority fee per gas + /// Maximum fee per gas the sender is willing to pay to miners in wei + #[serde(rename = "maxPriorityFeePerGas")] + pub max_priority_fee_per_gas: U256, + /// nonce + pub nonce: U256, + /// to address + pub to: Option
, + /// type + pub r#type: Type2, + /// value + pub value: U256, +} + +/// EIP-2930 transaction. +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction2930Unsigned { + /// accessList + /// EIP-2930 access list + #[serde(rename = "accessList")] + pub access_list: AccessList, + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId")] + pub chain_id: U256, + /// gas limit + pub gas: U256, + /// gas price + /// The gas price willing to be paid by the sender in wei + #[serde(rename = "gasPrice")] + pub gas_price: U256, + /// input data + pub input: Bytes, + /// nonce + pub nonce: U256, + /// to address + pub to: Option
, + /// type + pub r#type: Type1, + /// value + pub value: U256, +} + +/// EIP-4844 transaction. +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction4844Unsigned { + /// accessList + /// EIP-2930 access list + #[serde(rename = "accessList")] + pub access_list: AccessList, + /// blobVersionedHashes + /// List of versioned blob hashes associated with the transaction's EIP-4844 data blobs. + #[serde(rename = "blobVersionedHashes")] + pub blob_versioned_hashes: Vec, + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId")] + pub chain_id: U256, + /// gas limit + pub gas: U256, + /// input data + pub input: Bytes, + /// max fee per blob gas + /// The maximum total fee per gas the sender is willing to pay for blob gas in wei + #[serde(rename = "maxFeePerBlobGas")] + pub max_fee_per_blob_gas: U256, + /// max fee per gas + /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee + /// and miner / priority fee) in wei + #[serde(rename = "maxFeePerGas")] + pub max_fee_per_gas: U256, + /// max priority fee per gas + /// Maximum fee per gas the sender is willing to pay to miners in wei + #[serde(rename = "maxPriorityFeePerGas")] + pub max_priority_fee_per_gas: U256, + /// nonce + pub nonce: U256, + /// to address + pub to: Address, + /// type + pub r#type: Byte, + /// value + pub value: U256, +} + +/// Legacy transaction. +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct TransactionLegacyUnsigned { + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId", skip_serializing_if = "Option::is_none")] + pub chain_id: Option, + /// gas limit + pub gas: U256, + /// gas price + /// The gas price willing to be paid by the sender in wei + #[serde(rename = "gasPrice")] + pub gas_price: U256, + /// input data + pub input: Bytes, + /// nonce + pub nonce: U256, + /// to address + pub to: Option
, + /// type + pub r#type: Type0, + /// value + pub value: U256, +} + +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum TransactionSigned { + Transaction4844Signed(Transaction4844Signed), + Transaction1559Signed(Transaction1559Signed), + Transaction2930Signed(Transaction2930Signed), + TransactionLegacySigned(TransactionLegacySigned), +} +impl Default for TransactionSigned { + fn default() -> Self { + TransactionSigned::Transaction4844Signed(Default::default()) + } +} + +/// Validator withdrawal +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Withdrawal { + /// recipient address for withdrawal value + pub address: Address, + /// value contained in withdrawal + pub amount: U256, + /// index of withdrawal + pub index: U256, + /// index of validator that generated withdrawal + #[serde(rename = "validatorIndex")] + pub validator_index: U256, +} + +/// Access list entry +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct AccessListEntry { + pub address: Address, + #[serde(rename = "storageKeys")] + pub storage_keys: Vec, +} + +/// Signed 1559 Transaction +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction1559Signed { + #[serde(flatten)] + pub transaction_1559_unsigned: Transaction1559Unsigned, + /// r + pub r: U256, + /// s + pub s: U256, + /// v + /// For backwards compatibility, `v` is optionally provided as an alternative to `yParity`. + /// This field is DEPRECATED and all use of it should migrate to `yParity`. + #[serde(skip_serializing_if = "Option::is_none")] + pub v: Option, + /// yParity + /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. + #[serde(rename = "yParity", skip_serializing_if = "Option::is_none")] + pub y_parity: Option, +} + +/// Signed 2930 Transaction +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction2930Signed { + #[serde(flatten)] + pub transaction_2930_unsigned: Transaction2930Unsigned, + /// r + pub r: U256, + /// s + pub s: U256, + /// v + /// For backwards compatibility, `v` is optionally provided as an alternative to `yParity`. + /// This field is DEPRECATED and all use of it should migrate to `yParity`. + #[serde(skip_serializing_if = "Option::is_none")] + pub v: Option, + /// yParity + /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. + #[serde(rename = "yParity")] + pub y_parity: U256, +} + +/// Signed 4844 Transaction +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction4844Signed { + #[serde(flatten)] + pub transaction_4844_unsigned: Transaction4844Unsigned, + /// r + pub r: U256, + /// s + pub s: U256, + /// yParity + /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. + #[serde(rename = "yParity", skip_serializing_if = "Option::is_none")] + pub y_parity: Option, +} + +/// Signed Legacy Transaction +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct TransactionLegacySigned { + #[serde(flatten)] + pub transaction_legacy_unsigned: TransactionLegacyUnsigned, + /// r + pub r: U256, + /// s + pub s: U256, + /// v + pub v: U256, +} diff --git a/substrate/frame/revive/src/evm/api/signature.rs b/substrate/frame/revive/src/evm/api/signature.rs new file mode 100644 index 000000000000..583a9f00c577 --- /dev/null +++ b/substrate/frame/revive/src/evm/api/signature.rs @@ -0,0 +1,67 @@ +//! Ethereum signature utilities +use super::{TransactionLegacySigned, TransactionLegacyUnsigned}; +use rlp::Encodable; +use sp_core::{H160, U256}; +use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; + +impl TransactionLegacyUnsigned { + /// Recover the Ethereum address, from an RLP encoded transaction and a 65 bytes signature. + pub fn recover_eth_address(rlp_encoded: &[u8], signature: &[u8; 65]) -> Result { + let hash = keccak_256(rlp_encoded); + + let mut addr = H160::default(); + addr.assign_from_slice( + &keccak_256(&secp256k1_ecdsa_recover(&signature, &hash).ok().unwrap()[..])[12..], + ); + + Ok(addr) + } +} + +impl TransactionLegacySigned { + /// Create a signed transaction from an [`TransactionLegacyUnsigned`] and a + /// [`RecoverableSignature`]. + pub fn from( + transaction_legacy_unsigned: TransactionLegacyUnsigned, + signature: &[u8; 65], + ) -> TransactionLegacySigned { + let r = U256::from_big_endian(&signature[..32]); + let s = U256::from_big_endian(&signature[32..64]); + let recovery_id = signature[64] as u32; + let v = transaction_legacy_unsigned + .chain_id + .map(|chain_id| chain_id * 2 + 35 + recovery_id) + .unwrap_or_else(|| U256::from(27) + recovery_id); + + TransactionLegacySigned { transaction_legacy_unsigned, r, s, v } + } + + /// Get the raw 65 bytes signature from the signed transaction. + pub fn raw_signature(&self) -> Result<[u8; 65], ()> { + let mut s = [0u8; 65]; + self.r.to_big_endian(s[0..32].as_mut()); + self.s.to_big_endian(s[32..64].as_mut()); + s[64] = self.extract_recovery_id().ok_or(())?; + Ok(s) + } + + /// Get the recovery ID from the signed transaction. + /// See https://eips.ethereum.org/EIPS/eip-155 + fn extract_recovery_id(&self) -> Option { + if let Some(chain_id) = self.transaction_legacy_unsigned.chain_id { + // self.v - chain_id * 2 - 35 + let v: u64 = self.v.try_into().ok()?; + let chain_id: u64 = chain_id.try_into().ok()?; + let r = v.checked_sub(chain_id.checked_mul(2)?)?.checked_sub(35)?; + r.try_into().ok() + } else { + self.v.try_into().ok() + } + } + + /// Recover the Ethereum address from the signed transaction. + pub fn recover_eth_address(&self) -> Result { + let rlp_encoded = self.transaction_legacy_unsigned.rlp_bytes(); + TransactionLegacyUnsigned::recover_eth_address(&rlp_encoded, &self.raw_signature()?) + } +} diff --git a/substrate/frame/revive/src/evm/api/type_id.rs b/substrate/frame/revive/src/evm/api/type_id.rs new file mode 100644 index 000000000000..368a4da3c1ac --- /dev/null +++ b/substrate/frame/revive/src/evm/api/type_id.rs @@ -0,0 +1,70 @@ +//! Ethereum Typed Transaction types +use super::Byte; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// A macro to generate Transaction type identifiers +/// See +macro_rules! transaction_type { + ($name:ident, $value:literal) => { + #[doc = concat!("Transaction type identifier: ", $value)] + #[derive(Clone, Default, Debug, Eq, PartialEq)] + pub struct $name; + + impl $name { + /// Convert to Byte + pub fn as_byte(&self) -> Byte { + Byte::from($value) + } + } + + impl Encode for $name { + fn using_encoded R>(&self, f: F) -> R { + f(&[$value]) + } + } + impl Decode for $name { + fn decode(input: &mut I) -> Result { + if $value == input.read_byte()? { + Ok(Self {}) + } else { + Err(codec::Error::from(concat!("expected ", $value))) + } + } + } + + impl TypeInfo for $name { + type Identity = u8; + fn type_info() -> scale_info::Type { + ::type_info() + } + } + + impl Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(concat!("0x", $value)) + } + } + impl<'de> Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: &str = Deserialize::deserialize(deserializer)?; + if s == concat!("0x", $value) { + Ok($name {}) + } else { + Err(serde::de::Error::custom(concat!("expected ", $value))) + } + } + } + }; +} + +transaction_type!(Type0, 0); +transaction_type!(Type1, 1); +transaction_type!(Type2, 2); diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs new file mode 100644 index 000000000000..e150202bef50 --- /dev/null +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -0,0 +1,269 @@ +//! Runtime types for integrating `pallet-revive` with the EVM. +#![allow(unused_imports, unused_variables)] +use crate::{ + evm::api::{TransactionLegacySigned, TransactionLegacyUnsigned, TransactionUnsigned}, + AccountIdOf, AddressMapper, BalanceOf, Config, EthInstantiateInput, EthTransactKind, MomentOf, + Weight, LOG_TARGET, +}; +use codec::{Decode, Encode}; +use core::marker::PhantomData; +use frame_support::{ + dispatch::{DispatchInfo, GetDispatchInfo}, + traits::ExtrinsicCall, + CloneNoBound, DebugNoBound, EqNoBound, PartialEqNoBound, +}; +use scale_info::TypeInfo; +use sp_arithmetic::Percent; +use sp_core::{ecdsa, ed25519, sr25519, Get, H160, U256}; +use sp_runtime::{ + generic::{self, CheckedExtrinsic}, + traits::{ + self, Checkable, Convert, DispatchInfoOf, Dispatchable, Extrinsic, ExtrinsicMetadata, Lazy, + Member, SignedExtension, Verify, + }, + transaction_validity::{ + InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, + }, + AccountId32, MultiSignature, MultiSigner, RuntimeDebug, Saturating, +}; + +#[cfg(not(feature = "std"))] +use alloc::{vec, vec::Vec}; + +/// Some way of identifying an account on the chain. +pub type AccountId = AccountId32; + +/// The type for looking up accounts. We don't expect more than 4 billion of them. +pub type AccountIndex = u32; + +/// The address format for describing accounts. +pub type MultiAddress = sp_runtime::MultiAddress; + +/// Wraps [`generic::UncheckedExtrinsic`] to support checking [`crate::Call::eth_transact`]. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[scale_info(skip_type_params(E))] +pub struct UncheckedExtrinsic( + generic::UncheckedExtrinsic, +); + +impl Extrinsic for UncheckedExtrinsic { + type Call = Call; + + type SignaturePayload = (MultiAddress, MultiSignature, E::Extra); + + fn is_signed(&self) -> Option { + self.0.is_signed() + } + + fn new(function: Call, signed_data: Option) -> Option { + Some(if let Some((address, signature, extra)) = signed_data { + Self(generic::UncheckedExtrinsic::new_signed(function, address, signature, extra)) + } else { + Self(generic::UncheckedExtrinsic::new_unsigned(function)) + }) + } +} + +impl ExtrinsicMetadata for UncheckedExtrinsic { + const VERSION: u8 = + generic::UncheckedExtrinsic::::VERSION; + type SignedExtensions = E::Extra; +} + +impl ExtrinsicCall for UncheckedExtrinsic { + fn call(&self) -> &Self::Call { + self.0.call() + } +} + +impl Checkable for UncheckedExtrinsic +where + Call: Encode + Member, + E: EthExtra, + ::Nonce: Into, + BalanceOf: Into + TryFrom, + MomentOf: Into, + + AccountIdOf: Into, + Call: From> + TryInto>, + E::Extra: SignedExtension, + Lookup: traits::Lookup, +{ + type Checked = CheckedExtrinsic; + + fn check(self, lookup: &Lookup) -> Result { + if self.0.signature.is_none() { + if let Ok(call) = self.0.function.clone().try_into() { + if let crate::Call::eth_transact { + payload, + gas_limit, + storage_deposit_limit, + transact_kind, + } = call + { + let checked = E::try_into_checked_extrinsic( + payload, + gas_limit, + storage_deposit_limit, + transact_kind, + )?; + return Ok(checked) + }; + } + } + self.0.check(lookup) + } + + #[cfg(feature = "try-runtime")] + fn unchecked_into_checked_i_know_what_i_am_doing( + self, + _: &Lookup, + ) -> Result { + unreachable!(); + } +} + +impl GetDispatchInfo for UncheckedExtrinsic +where + Call: GetDispatchInfo, + E: EthExtra, +{ + fn get_dispatch_info(&self) -> DispatchInfo { + self.0.get_dispatch_info() + } +} + +impl serde::Serialize for UncheckedExtrinsic { + fn serialize(&self, seq: S) -> Result + where + S: ::serde::Serializer, + { + self.0.serialize(seq) + } +} + +impl<'a, Call: Decode, E: EthExtra> serde::Deserialize<'a> for UncheckedExtrinsic { + fn deserialize(de: D) -> Result + where + D: serde::Deserializer<'a>, + { + let r = sp_core::bytes::deserialize(de)?; + Decode::decode(&mut &r[..]) + .map_err(|e| serde::de::Error::custom(sp_runtime::format!("Decode error: {}", e))) + } +} + +/// EthExtra convert an unsigned [`crate::Call::eth_transact`] into a [`CheckedExtrinsic`]. +pub trait EthExtra { + /// The Runtime configuration. + type Config: crate::Config; + + /// The Runtime's signed extension. + type Extra: SignedExtension; + + /// Get the signed extensions to apply to an unsigned [`crate::Call::eth_transact`] extrinsic. + fn get_eth_transact_extra(nonce: U256) -> Self::Extra; + + /// Convert the unsigned [`crate::Call::eth_transact`] into a [`CheckedExtrinsic`]. + fn try_into_checked_extrinsic( + payload: Vec, + gas_limit: Weight, + storage_deposit_limit: BalanceOf, + transact_kind: EthTransactKind, + ) -> Result, InvalidTransaction> + where + ::Nonce: Into, + BalanceOf: Into + TryFrom, + MomentOf: Into, + AccountIdOf: Into, + Call: From> + TryInto>, + { + let tx = rlp::decode::(&payload).map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to decode transaction: {err:?}"); + InvalidTransaction::Call + })?; + + let signer = tx.recover_eth_address().map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to recover signer: {err:?}"); + InvalidTransaction::BadProof + })?; + + let signer = + ::AddressMapper::to_account_id_contract(&signer); + let TransactionLegacyUnsigned { nonce, chain_id, to, value, input, gas, gas_price, .. } = + tx.transaction_legacy_unsigned; + + if chain_id.unwrap_or_default() != ::ChainId::get().into() { + log::debug!(target: LOG_TARGET, "Invalid chain_id {chain_id:?}"); + return Err(InvalidTransaction::Call); + } + + let account_nonce: U256 = >::account_nonce(&signer).into(); + if nonce > account_nonce { + log::debug!(target: LOG_TARGET, "Invalid nonce: expected {account_nonce}, got {nonce}"); + return Err(InvalidTransaction::Future); + } else if nonce < account_nonce { + log::debug!(target: LOG_TARGET, "Invalid nonce: expected {account_nonce}, got {nonce}"); + return Err(InvalidTransaction::Stale); + } + + let call = if let Some(dest) = to { + if !matches!(transact_kind, EthTransactKind::Call) { + log::debug!(target: LOG_TARGET, "Invalid transact_kind, expected Call"); + return Err(InvalidTransaction::Call); + } + + crate::Call::call:: { + dest, + value: value.try_into().map_err(|_| InvalidTransaction::Call)?, + gas_limit, + storage_deposit_limit, + data: input.0, + } + } else { + let EthTransactKind::InstantiateWithCode { code_len, data_len } = transact_kind else { + log::debug!(target: LOG_TARGET, "Invalid transact_kind, expected InstantiateWithCode"); + return Err(InvalidTransaction::Call); + }; + + let EthInstantiateInput { code, data } = EthInstantiateInput::decode(&mut &input.0[..]) + .map_err(|_| { + log::debug!(target: LOG_TARGET, "Failed to decoded eth_transact input"); + InvalidTransaction::Call + })?; + + if code.len() as u32 != code_len || data.len() as u32 != data_len { + log::debug!(target: LOG_TARGET, "Invalid code or data length"); + return Err(InvalidTransaction::Call); + } + + crate::Call::instantiate_with_code:: { + value: value.try_into().map_err(|_| InvalidTransaction::Call)?, + gas_limit, + storage_deposit_limit, + code, + data, + salt: None, + } + }; + + let dispatch_info = call.get_dispatch_info(); + let call_fee = ::WeightPrice::convert(dispatch_info.weight) + .saturating_add(storage_deposit_limit); + + let eth_fee = + gas_price.saturating_mul(gas).try_into().map_err(|_| InvalidTransaction::Call)?; + + // Make sure that that the fee computed from the signed payload is no more than 5% greater + // than the actual fee computed with the injected transaction parameters. + if Percent::from_rational(eth_fee, call_fee) > Percent::from_percent(105) { + log::debug!(target: LOG_TARGET, "Expected fees {eth_fee:?} to be within 5% of calculated fees {call_fee:?}"); + return Err(InvalidTransaction::Call.into()) + } + + Ok(CheckedExtrinsic { + signed: Some((signer.into(), Self::get_eth_transact_extra(nonce))), + function: call.into(), + }) + } +} diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 2e48bab29255..4581e332b762 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -890,7 +890,11 @@ where let address = if let Some(salt) = salt { address::create2(&deployer, executable.code(), input_data, salt) } else { - address::create1(&deployer, account_nonce.saturated_into()) + use sp_runtime::Saturating; + address::create1( + &deployer, + account_nonce.saturating_sub(1u32.into()).saturated_into(), + ) }; let contract = ContractInfo::new( &address, @@ -4153,7 +4157,14 @@ mod tests { // Successful instantiation should set the output let address = ctx .ext - .instantiate(Weight::zero(), U256::zero(), ok_ch, value, vec![], None) + .instantiate( + Weight::zero(), + U256::zero(), + ok_ch, + value, + vec![], + Some(&[0u8; 32]), + ) .unwrap(); assert_eq!( ctx.ext.last_frame_output(), @@ -4169,7 +4180,14 @@ mod tests { // Reverted instantiation should set the output ctx.ext - .instantiate(Weight::zero(), U256::zero(), revert_ch, value, vec![], None) + .instantiate( + Weight::zero(), + U256::zero(), + revert_ch, + value, + vec![], + Some(&[1u8; 32]), + ) .unwrap(); assert_eq!( ctx.ext.last_frame_output(), @@ -4178,7 +4196,14 @@ mod tests { // Trapped instantiation should clear the output ctx.ext - .instantiate(Weight::zero(), U256::zero(), trap_ch, value, vec![], None) + .instantiate( + Weight::zero(), + U256::zero(), + trap_ch, + value, + vec![], + Some(&[2u8; 32]), + ) .unwrap_err(); assert_eq!( ctx.ext.last_frame_output(), diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 114d51c89695..6d63f06f6b92 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -21,17 +21,19 @@ #![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "1024")] extern crate alloc; + mod address; mod benchmarking; mod benchmarking_dummy; mod exec; mod gas; mod primitives; -use crate::exec::MomentOf; +pub use crate::exec::MomentOf; use frame_support::traits::IsType; pub use primitives::*; use sp_core::U256; +pub mod evm; mod limits; mod storage; mod transient_storage; @@ -78,7 +80,7 @@ use sp_runtime::{ }; pub use crate::{ - address::{AddressMapper, DefaultAddressMapper}, + address::{create1, create2, AddressMapper, DefaultAddressMapper}, debug::Tracing, pallet::*, }; @@ -88,7 +90,7 @@ pub use weights::WeightInfo; pub use crate::wasm::SyscallDoc; type TrieId = BoundedVec>; -type BalanceOf = +pub type BalanceOf = <::Currency as Inspect<::AccountId>>::Balance; type CodeVec = BoundedVec>; type EventRecordOf = @@ -159,6 +161,7 @@ pub mod pallet { type RuntimeCall: Dispatchable + GetDispatchInfo + codec::Decode + + core::fmt::Debug + IsType<::RuntimeCall>; /// Overarching hold reason. @@ -715,6 +718,41 @@ pub mod pallet { BalanceOf: Into + TryFrom, MomentOf: Into, { + /// A raw EVM transaction, typically dispatched by an Ethereum JSON-RPC server. + /// + /// # Parameters + /// + /// * `payload`: The RLP-encoded [`pallet_revive_evm::api::TransactionLegacySigned`]. + /// * `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. + /// * `transact_kind`: The type of transaction to execute. + /// + /// # Note + /// + /// This call cannot be dispatched directly; attempting to do so will result in a failed + /// transaction. It serves as a wrapper for an Ethereum transaction. When submitted, the + /// runtime converts it into a [`sp_runtime::generic::CheckedExtrinsic`] by recovering the + /// signer and validating the transaction. + #[allow(unused_variables)] + #[pallet::call_index(0)] + #[pallet::weight( + match transact_kind { + EthTransactKind::Call => T::WeightInfo::call().saturating_add(*gas_limit), + EthTransactKind::InstantiateWithCode{code_len, data_len} => T::WeightInfo::instantiate_with_code(*code_len, *data_len) + .saturating_add(*gas_limit) + } + )] + pub fn eth_transact( + origin: OriginFor, + payload: Vec, + gas_limit: Weight, + #[pallet::compact] storage_deposit_limit: BalanceOf, + transact_kind: EthTransactKind, + ) -> DispatchResultWithPostInfo { + Err(frame_system::Error::CallFiltered::.into()) + } + /// Makes a call to an account, optionally transferring some balance. /// /// # Parameters @@ -731,7 +769,7 @@ pub mod pallet { /// * If the account is a regular account, any value will be transferred. /// * If no account exists and the call value is not less than `existential_deposit`, /// a regular account will be created and any value will be transferred. - #[pallet::call_index(0)] + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))] pub fn call( origin: OriginFor, @@ -741,6 +779,7 @@ pub mod pallet { #[pallet::compact] storage_deposit_limit: BalanceOf, data: Vec, ) -> DispatchResultWithPostInfo { + log::info!(target: LOG_TARGET, "Call: {:?} {:?} {:?}", dest, value, data); let mut output = Self::bare_call( origin, dest, @@ -764,7 +803,7 @@ pub mod pallet { /// This function is identical to [`Self::instantiate_with_code`] but without the /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary /// must be supplied. - #[pallet::call_index(1)] + #[pallet::call_index(2)] #[pallet::weight( T::WeightInfo::instantiate(data.len() as u32).saturating_add(*gas_limit) )] @@ -828,7 +867,7 @@ pub mod pallet { /// - The smart-contract account is created at the computed address. /// - The `value` is transferred to the new account. /// - The `deploy` function is executed in the context of the newly-created account. - #[pallet::call_index(2)] + #[pallet::call_index(3)] #[pallet::weight( T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32) .saturating_add(*gas_limit) @@ -879,7 +918,7 @@ pub mod pallet { /// To avoid this situation a constructor could employ access control so that it can /// only be instantiated by permissioned entities. The same is true when uploading /// through [`Self::instantiate_with_code`]. - #[pallet::call_index(3)] + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::upload_code_determinism_enforced(code.len() as u32))] pub fn upload_code( origin: OriginFor, @@ -893,7 +932,7 @@ pub mod pallet { /// /// A code can only be removed by its original uploader (its owner) and only if it is /// not used by any contract. - #[pallet::call_index(4)] + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::remove_code())] pub fn remove_code( origin: OriginFor, @@ -915,7 +954,7 @@ pub mod pallet { /// This does **not** change the address of the contract in question. This means /// that the contract address is no longer derived from its code hash after calling /// this dispatchable. - #[pallet::call_index(5)] + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::set_code())] pub fn set_code( origin: OriginFor, @@ -979,7 +1018,7 @@ where data: Vec, debug: DebugInfo, collect_events: CollectEvents, - ) -> ContractExecResult, EventRecordOf> { + ) -> ContractResult, EventRecordOf> { let mut gas_meter = GasMeter::new(gas_limit); let mut storage_deposit = Default::default(); let mut debug_message = if matches!(debug, DebugInfo::UnsafeDebug) { @@ -1008,7 +1047,7 @@ where } else { None }; - ContractExecResult { + ContractResult { result: result.map_err(|r| r.error), gas_consumed: gas_meter.gas_consumed(), gas_required: gas_meter.gas_required(), @@ -1034,7 +1073,7 @@ where salt: Option<[u8; 32]>, debug: DebugInfo, collect_events: CollectEvents, - ) -> ContractInstantiateResult, EventRecordOf> { + ) -> ContractResult, EventRecordOf> { let mut gas_meter = GasMeter::new(gas_limit); let mut storage_deposit = Default::default(); let mut debug_message = @@ -1076,7 +1115,7 @@ where } else { None }; - ContractInstantiateResult { + ContractResult { result: output .map(|(addr, result)| InstantiateReturnValue { result, addr }) .map_err(|e| e.error), @@ -1088,6 +1127,63 @@ where } } + /// A version of [`Self::eth_transact`] used to dry-run Ethereum calls. + pub fn bare_eth_transact( + origin: OriginFor, + dest: Option, + value: BalanceOf, + input: Vec, + gas_limit: Weight, + storage_deposit_limit: BalanceOf, + debug: DebugInfo, + collect_events: CollectEvents, + ) -> ContractResult, EventRecordOf> { + if let Some(dest) = dest { + crate::Pallet::::bare_call( + origin, + dest, + value, + gas_limit, + storage_deposit_limit, + input, + debug, + collect_events, + ) + .map(|result| EthTransactReturnValue { kind: EthTransactKind::Call, result }) + } else { + let Ok(EthInstantiateInput { code, data }) = + EthInstantiateInput::decode(&mut &input[..]) + else { + return ContractResult { + result: Err(>::DecodingFailed.into()), + gas_consumed: Default::default(), + gas_required: Default::default(), + storage_deposit: Default::default(), + debug_message: Default::default(), + events: Default::default(), + } + }; + + let code_len = code.len() as u32; + let data_len = data.len() as u32; + crate::Pallet::::bare_instantiate( + origin, + value, + gas_limit, + storage_deposit_limit, + Code::Upload(code), + data, + None, + DebugInfo::Skip, + CollectEvents::Skip, + ) + .map(|r| EthTransactReturnValue { + kind: EthTransactKind::InstantiateWithCode { code_len, data_len }, + result: r.result, + }) + } + } + /// A generalized version of [`Self::upload_code`]. /// /// It is identical to [`Self::upload_code`] and only differs in the information it returns. @@ -1176,7 +1272,7 @@ sp_api::decl_runtime_apis! { gas_limit: Option, storage_deposit_limit: Option, input_data: Vec, - ) -> ContractExecResult; + ) -> ContractResult; /// Instantiate a new contract. /// @@ -1189,7 +1285,20 @@ sp_api::decl_runtime_apis! { code: Code, data: Vec, salt: Option<[u8; 32]>, - ) -> ContractInstantiateResult; + ) -> ContractResult; + + + /// Perform an Ethereum call. + /// + /// See [`crate::Pallet::bare_eth_transact`] + fn eth_transact( + origin: H160, + dest: Option, + value: Balance, + input: Vec, + gas_limit: Option, + storage_deposit_limit: Option, + ) -> ContractResult; /// Upload new code without instantiating a contract from it. /// diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index 67bc144c3dd2..33e4052c96b8 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -76,19 +76,25 @@ pub struct ContractResult { /// RPC calls. pub debug_message: Vec, /// The execution result of the wasm code. - pub result: R, + pub result: Result, /// The events that were emitted during execution. It is an option as event collection is /// optional. pub events: Option>, } -/// Result type of a `bare_call` call as well as `ContractsApi::call`. -pub type ContractExecResult = - ContractResult, Balance, EventRecord>; - -/// Result type of a `bare_instantiate` call as well as `ContractsApi::instantiate`. -pub type ContractInstantiateResult = - ContractResult, Balance, EventRecord>; +impl ContractResult { + /// Maps the result of a contract execution, using the provided function. + pub fn map(self, f: impl FnOnce(R) -> V) -> ContractResult { + ContractResult { + gas_consumed: self.gas_consumed, + gas_required: self.gas_required, + storage_deposit: self.storage_deposit, + debug_message: self.debug_message, + result: self.result.map(f), + events: self.events, + } + } +} /// Result type of a `bare_code_upload` call. pub type CodeUploadResult = Result, DispatchError>; @@ -121,6 +127,29 @@ impl ExecReturnValue { } } +/// Describes the type of an [`crate::Call::eth_transact`] call. +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum EthTransactKind { + /// A Call to an existing contract. + Call, + /// The instantiation of a new contract. + InstantiateWithCode { + #[codec(compact)] + code_len: u32, + #[codec(compact)] + data_len: u32, + }, +} + +/// The result of a successful eth_transact call +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct EthTransactReturnValue { + /// The kind of transaction that was executed. + pub kind: EthTransactKind, + /// The output of the called constructor. + pub result: ExecReturnValue, +} + /// The result of a successful contract instantiation. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct InstantiateReturnValue { @@ -148,6 +177,15 @@ pub enum Code { Existing(sp_core::H256), } +/// A type used to encode the `input` field of an Ethereum transaction +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct EthInstantiateInput { + /// The bytecode of the contract. + pub code: Vec, + /// The data to pass to the constructor. + pub data: Vec, +} + /// The amount of balance that was either charged or refunded in order to pay for storage. #[derive( Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo, diff --git a/substrate/frame/revive/src/test_utils/builder.rs b/substrate/frame/revive/src/test_utils/builder.rs index d361590df95a..e64f58894432 100644 --- a/substrate/frame/revive/src/test_utils/builder.rs +++ b/substrate/frame/revive/src/test_utils/builder.rs @@ -17,9 +17,8 @@ use super::{deposit_limit, GAS_LIMIT}; use crate::{ - address::AddressMapper, AccountIdOf, BalanceOf, Code, CollectEvents, Config, - ContractExecResult, ContractInstantiateResult, DebugInfo, EventRecordOf, ExecReturnValue, - InstantiateReturnValue, OriginFor, Pallet, Weight, + address::AddressMapper, AccountIdOf, BalanceOf, Code, CollectEvents, Config, ContractResult, + DebugInfo, EventRecordOf, ExecReturnValue, InstantiateReturnValue, OriginFor, Pallet, Weight, }; use frame_support::pallet_prelude::DispatchResultWithPostInfo; use paste::paste; @@ -140,7 +139,7 @@ builder!( salt: Option<[u8; 32]>, debug: DebugInfo, collect_events: CollectEvents, - ) -> ContractInstantiateResult, EventRecordOf>; + ) -> ContractResult, EventRecordOf>; /// Build the instantiate call and unwrap the result. pub fn build_and_unwrap_result(self) -> InstantiateReturnValue { @@ -203,7 +202,7 @@ builder!( data: Vec, debug: DebugInfo, collect_events: CollectEvents, - ) -> ContractExecResult, EventRecordOf>; + ) -> ContractResult, EventRecordOf>; /// Build the call and unwrap the result. pub fn build_and_unwrap_result(self) -> ExecReturnValue { diff --git a/substrate/frame/revive/src/wasm/mod.rs b/substrate/frame/revive/src/wasm/mod.rs index cd274873975d..4b0422b2ff19 100644 --- a/substrate/frame/revive/src/wasm/mod.rs +++ b/substrate/frame/revive/src/wasm/mod.rs @@ -200,7 +200,10 @@ where &self.code_info.owner, deposit, ) - .map_err(|_| >::StorageDepositNotEnoughFunds)?; + .map_err(|err| { + log::debug!(target: LOG_TARGET, "failed to store code for owner: {:?}: {err:?}", self.code_info.owner); + >::StorageDepositNotEnoughFunds + })?; self.code_info.refcount = 0; >::insert(code_hash, &self.code); diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 83cbebbc61cd..bd073e2b91f0 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -492,7 +492,6 @@ serde = [ "pallet-parameters?/serde", "pallet-referenda?/serde", "pallet-remark?/serde", - "pallet-revive?/serde", "pallet-state-trie-migration?/serde", "pallet-tips?/serde", "pallet-transaction-payment?/serde", From 43a7bf01eaaf328b4a2f9eb16e914a30bf476cbf Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 30 Sep 2024 17:53:14 +0200 Subject: [PATCH 002/174] Add prdoc --- prdoc/pr_5866.prdoc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 prdoc/pr_5866.prdoc diff --git a/prdoc/pr_5866.prdoc b/prdoc/pr_5866.prdoc new file mode 100644 index 000000000000..86c08883dedb --- /dev/null +++ b/prdoc/pr_5866.prdoc @@ -0,0 +1,26 @@ +title: "[pallet-revive] Ethereum JSON-RPC integration" + +doc: + - audience: Runtime Dev + description: | + Related PR: https://github.com/paritytech/revive-ethereum-rpc/pull/5 + + Changes Included: + - A new pallet::call eth_transact. + - A custom UncheckedExtrinsic struct to dispatch unsigned eth_transact calls from an Ethereum JSON-RPC proxy. + - Generated types and traits to support implementing a JSON-RPC Ethereum proxy. + + Flow Overview: + - A user submits a transaction via MetaMask or another Ethereum-compatible wallet. + - The proxy dry run the transaction and add metadata to the call ( gas limit in Weight, Storage deposit limit, bytecode and constructor length for contract instantiation) + - The raw transaction, along with the additional metadata, is submitted to the node as an unsigned extrinsic. + - On the node, the custom UncheckedExtrinsic struct has a custom Checkable implementation that converts the unsigned extrinsics into checked ones + - It recovers the signer + - validates the payload, and injects default signed extensions, allowing the system to increment the nonce and charge the appropriate fees. + - re-route the call to pallet-revive::Call::call or pallet-revive::Call::instantiateWithCode +crates: + - name: pallet-revive + bump: patch + - name: polkadot-sdk + bump: patch + From e74852df79d0c8b6552cbe5439c11640acbb6358 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 30 Sep 2024 17:56:01 +0200 Subject: [PATCH 003/174] Add missing license headers --- substrate/frame/revive/src/evm/api.rs | 16 ++++++++++++++++ substrate/frame/revive/src/evm/api/byte.rs | 16 ++++++++++++++++ substrate/frame/revive/src/evm/api/rlp_codec.rs | 16 ++++++++++++++++ .../frame/revive/src/evm/api/rpc_methods_gen.rs | 16 ++++++++++++++++ substrate/frame/revive/src/evm/api/rpc_types.rs | 16 ++++++++++++++++ .../frame/revive/src/evm/api/rpc_types_gen.rs | 16 ++++++++++++++++ substrate/frame/revive/src/evm/api/signature.rs | 16 ++++++++++++++++ substrate/frame/revive/src/evm/api/type_id.rs | 16 ++++++++++++++++ substrate/frame/revive/src/evm/runtime.rs | 16 ++++++++++++++++ 9 files changed, 144 insertions(+) diff --git a/substrate/frame/revive/src/evm/api.rs b/substrate/frame/revive/src/evm/api.rs index 3fb620df2423..eef432609c1b 100644 --- a/substrate/frame/revive/src/evm/api.rs +++ b/substrate/frame/revive/src/evm/api.rs @@ -1,3 +1,19 @@ +// 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. //! JSON-RPC methods and types, for Ethereum. mod byte; diff --git a/substrate/frame/revive/src/evm/api/byte.rs b/substrate/frame/revive/src/evm/api/byte.rs index 164182d5e5a4..cafcaabf24ae 100644 --- a/substrate/frame/revive/src/evm/api/byte.rs +++ b/substrate/frame/revive/src/evm/api/byte.rs @@ -1,3 +1,19 @@ +// 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. //! Define Byte wrapper types for encoding and decoding hex strings use codec::{Decode, Encode}; use core::{ diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs index 1d4340eaf5d0..b022e5d85206 100644 --- a/substrate/frame/revive/src/evm/api/rlp_codec.rs +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -1,3 +1,19 @@ +// 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. //! RLP encoding and decoding for Ethereum transactions. //! See for more information about RLP encoding. diff --git a/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs b/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs index 525615bf957b..eb6bebe232b4 100644 --- a/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs +++ b/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs @@ -1,3 +1,19 @@ +// 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. //! Generated JSON-RPC methods. #![allow(missing_docs)] diff --git a/substrate/frame/revive/src/evm/api/rpc_types.rs b/substrate/frame/revive/src/evm/api/rpc_types.rs index 22a2c3f7c263..b15a0a53cd07 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types.rs @@ -1,3 +1,19 @@ +// 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. //! Utility impl for the RPC types. use super::{ReceiptInfo, TransactionInfo, TransactionSigned}; 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 dc4e309f2568..ea29c47d792b 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs @@ -1,3 +1,19 @@ +// 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. //! Generated JSON-RPC types. #![allow(missing_docs)] diff --git a/substrate/frame/revive/src/evm/api/signature.rs b/substrate/frame/revive/src/evm/api/signature.rs index 583a9f00c577..d06fb0122579 100644 --- a/substrate/frame/revive/src/evm/api/signature.rs +++ b/substrate/frame/revive/src/evm/api/signature.rs @@ -1,3 +1,19 @@ +// 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. //! Ethereum signature utilities use super::{TransactionLegacySigned, TransactionLegacyUnsigned}; use rlp::Encodable; diff --git a/substrate/frame/revive/src/evm/api/type_id.rs b/substrate/frame/revive/src/evm/api/type_id.rs index 368a4da3c1ac..72fea1e1761d 100644 --- a/substrate/frame/revive/src/evm/api/type_id.rs +++ b/substrate/frame/revive/src/evm/api/type_id.rs @@ -1,3 +1,19 @@ +// 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. //! Ethereum Typed Transaction types use super::Byte; use codec::{Decode, Encode}; diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index e150202bef50..5243c2fa293a 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -1,3 +1,19 @@ +// 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. //! Runtime types for integrating `pallet-revive` with the EVM. #![allow(unused_imports, unused_variables)] use crate::{ From 5b242f8a0981bbb6c2d0e566ea9090e6f79b3804 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 30 Sep 2024 18:00:34 +0200 Subject: [PATCH 004/174] missing license header --- substrate/frame/revive/src/evm.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/substrate/frame/revive/src/evm.rs b/substrate/frame/revive/src/evm.rs index 018c652aec75..c3495fc0559d 100644 --- a/substrate/frame/revive/src/evm.rs +++ b/substrate/frame/revive/src/evm.rs @@ -1,3 +1,19 @@ +// 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. //!Types, and traits to integrate pallet-revive with EVM. #![warn(missing_docs)] From 93f25dd6aa6cde242f2bbde216360d69345a659c Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 1 Oct 2024 12:59:46 +0200 Subject: [PATCH 005/174] rm unwrap --- substrate/frame/revive/src/evm/api/signature.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/substrate/frame/revive/src/evm/api/signature.rs b/substrate/frame/revive/src/evm/api/signature.rs index d06fb0122579..e1e89be53437 100644 --- a/substrate/frame/revive/src/evm/api/signature.rs +++ b/substrate/frame/revive/src/evm/api/signature.rs @@ -24,11 +24,9 @@ impl TransactionLegacyUnsigned { /// Recover the Ethereum address, from an RLP encoded transaction and a 65 bytes signature. pub fn recover_eth_address(rlp_encoded: &[u8], signature: &[u8; 65]) -> Result { let hash = keccak_256(rlp_encoded); - let mut addr = H160::default(); - addr.assign_from_slice( - &keccak_256(&secp256k1_ecdsa_recover(&signature, &hash).ok().unwrap()[..])[12..], - ); + let pk = secp256k1_ecdsa_recover(&signature, &hash).map_err(|_| ())?; + addr.assign_from_slice(&keccak_256(&pk[..])[12..]); Ok(addr) } From e4d6543a65a480953de3f1c4cace6e568babab85 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 1 Oct 2024 17:17:41 +0200 Subject: [PATCH 006/174] Add tests --- Cargo.lock | 1 + substrate/frame/revive/Cargo.toml | 7 +- substrate/frame/revive/src/evm/runtime.rs | 290 +++++++++++++++++++++- substrate/frame/revive/src/tests.rs | 12 +- 4 files changed, 303 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9263036d5a8..32ca83e0e19c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12416,6 +12416,7 @@ dependencies = [ "sp-weights 27.0.0", "staging-xcm", "staging-xcm-builder", + "subxt-signer", ] [[package]] diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 4a83ef3eceaa..10229e910e71 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -59,6 +59,10 @@ array-bytes = { workspace = true, default-features = true } assert_matches = { workspace = true } pretty_assertions = { workspace = true } pallet-revive-fixtures = { workspace = true, default-features = true } +secp256k1 = { workspace = true, features = ["recovery"] } +serde_json.workspace = true +hex-literal.workspace = true +subxt-signer.workspace = true # Polkadot SDK Dependencies pallet-balances = { workspace = true, default-features = true } @@ -70,9 +74,6 @@ pallet-proxy = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } xcm-builder = { workspace = true, default-features = true } -secp256k1 = { workspace = true, features = ["recovery"] } -serde_json.workspace = true -hex-literal.workspace = true [features] default = ["std"] diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 5243c2fa293a..b85b2fe9e17f 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -271,9 +271,10 @@ pub trait EthExtra { gas_price.saturating_mul(gas).try_into().map_err(|_| InvalidTransaction::Call)?; // Make sure that that the fee computed from the signed payload is no more than 5% greater - // than the actual fee computed with the injected transaction parameters. - if Percent::from_rational(eth_fee, call_fee) > Percent::from_percent(105) { - log::debug!(target: LOG_TARGET, "Expected fees {eth_fee:?} to be within 5% of calculated fees {call_fee:?}"); + if call_fee > eth_fee && + Percent::from_rational(call_fee - eth_fee, eth_fee) > Percent::from_percent(5) + { + log::debug!(target: LOG_TARGET, "Eth fees {eth_fee:?} should be no more than 5% higher than injected ees {call_fee:?}"); return Err(InvalidTransaction::Call.into()) } @@ -283,3 +284,286 @@ pub trait EthExtra { }) } } + +#[cfg(test)] +mod test { + use super::*; + use crate::{ + evm::*, + test_utils::*, + tests::{builder, ExtBuilder, RuntimeCall, Test}, + }; + use frame_support::{error::LookupError, traits::fungible::Mutate}; + use pallet_revive_fixtures::compile_module; + use rlp::Encodable; + use secp256k1::{Message, PublicKey, Secp256k1, SecretKey}; + use sp_core::keccak_256; + use sp_runtime::traits::{Checkable, IdentityLookup}; + + /// A simple account that can sign transactions + pub struct Account { + /// The secret key of the account + sk: SecretKey, + } + + impl Default for Account { + fn default() -> Self { + Account::from_keypair(&subxt_signer::ecdsa::dev::alice()) + } + } + + impl Account { + /// Create an account from a keypair. + pub fn from_keypair(pair: &subxt_signer::ecdsa::Keypair) -> Self { + let sb = pair.0.secret_key().secret_bytes(); + Account { sk: SecretKey::from_slice(&sb).unwrap() } + } + + pub fn account_id(&self) -> AccountId { + let address = self.address(); + ::AddressMapper::to_account_id_contract(&address) + } + + /// Get the [`H160`] address of the account. + pub fn address(&self) -> H160 { + let pub_key = + PublicKey::from_secret_key(&Secp256k1::new(), &self.sk).serialize_uncompressed(); + let hash = keccak_256(&pub_key[1..]); + H160::from_slice(&hash[12..]) + } + + /// Sign a transaction. + pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { + let rlp_encoded = tx.rlp_bytes(); + let tx_hash = keccak_256(&rlp_encoded); + let secp = Secp256k1::new(); + let msg = Message::from_digest(tx_hash); + let sig = secp.sign_ecdsa_recoverable(&msg, &self.sk); + let (recovery_id, sig) = sig.serialize_compact(); + let sig = sig.into_iter().chain([recovery_id.to_i32() as u8]).collect::>(); + TransactionLegacySigned::from(tx, &sig.try_into().unwrap()) + } + } + + #[derive(Clone, PartialEq, Eq, Debug)] + pub struct Extra; + + impl EthExtra for Extra { + type Config = Test; + type Extra = frame_system::CheckNonce; + + fn get_eth_transact_extra(nonce: U256) -> Self::Extra { + frame_system::CheckNonce::from(nonce.as_u32()) + } + } + + type Ex = UncheckedExtrinsic; + struct TestContext; + + impl traits::Lookup for TestContext { + type Source = MultiAddress; + type Target = AccountId; + fn lookup(&self, s: Self::Source) -> Result { + match s { + MultiAddress::Id(id) => Ok(id), + _ => Err(LookupError), + } + } + } + + #[derive(Clone)] + struct UncheckedExtrinsicBuilder { + tx: TransactionLegacyUnsigned, + gas_limit: Weight, + storage_deposit_limit: BalanceOf, + transact_kind: EthTransactKind, + } + + impl UncheckedExtrinsicBuilder { + fn new() -> Self { + Self { + tx: TransactionLegacyUnsigned { + chain_id: Some(::ChainId::get().into()), + gas: U256::from(21000), + nonce: U256::from(0), + gas_price: U256::from(100_000), + to: None, + value: U256::from(0), + input: Bytes(vec![]), + r#type: Type0, + }, + gas_limit: Weight::zero(), + storage_deposit_limit: 0, + transact_kind: EthTransactKind::Call, + } + } + + fn call_with(dest: H160) -> Self { + let mut builder = Self::new(); + builder.tx.to = Some(dest); + builder.transact_kind = EthTransactKind::Call; + builder + } + + fn instantiate_with(code: Vec, data: Vec) -> Self { + let mut builder = Self::new(); + builder.transact_kind = EthTransactKind::InstantiateWithCode { + code_len: code.len() as u32, + data_len: data.len() as u32, + }; + builder.tx.input = Bytes(EthInstantiateInput { code, data }.encode()); + builder + } + + fn update(mut self, f: impl FnOnce(&mut TransactionLegacyUnsigned) -> ()) -> Self { + f(&mut self.tx); + self + } + + fn transact_kind(mut self, kind: EthTransactKind) -> Self { + self.transact_kind = kind; + self + } + + fn check(&self) -> Result { + let UncheckedExtrinsicBuilder { tx, gas_limit, storage_deposit_limit, transact_kind } = + self.clone(); + let payload = Account::default().sign_transaction(tx).rlp_bytes().to_vec(); + let call = RuntimeCall::Contracts(crate::Call::eth_transact { + payload, + gas_limit, + storage_deposit_limit, + transact_kind, + }); + Ex::new(call, None).unwrap().check(&TestContext {}).map(|x| x.function) + } + } + + #[test] + fn check_eth_transact_works() { + ExtBuilder::default().build().execute_with(|| { + // Check a regular transfer call + let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])); + assert_eq!( + builder.check().unwrap(), + crate::Call::call:: { + dest: builder.tx.to.unwrap(), + value: builder.tx.value.as_u64(), + gas_limit: builder.gas_limit, + storage_deposit_limit: builder.storage_deposit_limit, + data: builder.tx.input.0 + } + .into() + ); + + // Check an instantiate call + let code = vec![]; + let data = vec![]; + let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()); + assert_eq!( + builder.check().unwrap(), + crate::Call::instantiate_with_code:: { + value: builder.tx.value.as_u64(), + gas_limit: builder.gas_limit, + storage_deposit_limit: builder.storage_deposit_limit, + code, + data, + salt: None + } + .into() + ); + }); + } + + #[test] + fn check_eth_transact_nonce_works() { + ExtBuilder::default().build().execute_with(|| { + let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])) + .update(|tx| tx.nonce = 1u32.into()); + + assert_eq!( + builder.check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Future)) + ); + + >::inc_account_nonce(Account::default().account_id()); + + let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])); + assert_eq!( + builder.check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)) + ); + }); + } + + #[test] + fn check_eth_transact_chain_id_works() { + ExtBuilder::default().build().execute_with(|| { + let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])) + .update(|tx| tx.chain_id = Some(42.into())); + + assert_eq!( + builder.check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + ); + }); + } + + #[test] + fn check_instantiate_data() { + ExtBuilder::default().build().execute_with(|| { + let code = vec![1, 2, 3]; + let data = vec![1]; + let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()); + + // Fail because the tx input should decode as an `EthInstantiateInput` + assert_eq!( + builder.clone().update(|tx| tx.input = Bytes(vec![1, 2, 3])).check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + ); + + let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()) + .transact_kind(EthTransactKind::InstantiateWithCode { + code_len: 0, + data_len: data.len() as u32, + }); + + // Fail because we are passing the wrong code length + assert_eq!( + builder + .clone() + .transact_kind(EthTransactKind::InstantiateWithCode { + code_len: 0, + data_len: data.len() as u32 + }) + .check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + ); + + // Fail because we are passing the wrong data length + assert_eq!( + builder + .clone() + .transact_kind(EthTransactKind::InstantiateWithCode { + code_len: code.len() as u32, + data_len: 0 + }) + .check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + ); + }); + } + + #[test] + fn check_injected_weight() { + ExtBuilder::default().build().execute_with(|| { + let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])) + .update(|tx| tx.gas_price = U256::from(1)); + + assert_eq!( + builder.check(), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) + ); + }); + } +} diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 5c5d144f24a2..324b329ce1a4 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -166,7 +166,7 @@ pub mod test_utils { } } -mod builder { +pub mod builder { use super::Test; use crate::{ test_utils::{builder::*, ALICE}, @@ -500,6 +500,16 @@ impl Config for Test { type ChainId = ChainId; } +impl TryInto> for RuntimeCall { + type Error = (); + fn try_into(self) -> Result, Self::Error> { + match self { + RuntimeCall::Contracts(call) => Ok(call), + _ => Err(()), + } + } +} + pub struct ExtBuilder { existential_deposit: u64, storage_version: Option, From 4a9ca424c55f836d1dbb65d28dc38bce0c4f0c5c Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 1 Oct 2024 17:29:31 +0200 Subject: [PATCH 007/174] fix docstr --- substrate/frame/revive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 6d63f06f6b92..8ab68c4f12b4 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -722,7 +722,7 @@ pub mod pallet { /// /// # Parameters /// - /// * `payload`: The RLP-encoded [`pallet_revive_evm::api::TransactionLegacySigned`]. + /// * `payload`: The RLP-encoded [`crate::api::TransactionLegacySigned`]. /// * `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. From 658f3ac801bb77daa2740e9f0ced6c65bc04064c Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 1 Oct 2024 17:30:26 +0200 Subject: [PATCH 008/174] fix docstring --- substrate/frame/revive/src/evm/api/signature.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/evm/api/signature.rs b/substrate/frame/revive/src/evm/api/signature.rs index e1e89be53437..0eb896a08c42 100644 --- a/substrate/frame/revive/src/evm/api/signature.rs +++ b/substrate/frame/revive/src/evm/api/signature.rs @@ -33,8 +33,7 @@ impl TransactionLegacyUnsigned { } impl TransactionLegacySigned { - /// Create a signed transaction from an [`TransactionLegacyUnsigned`] and a - /// [`RecoverableSignature`]. + /// Create a signed transaction from an [`TransactionLegacyUnsigned`] and a signature. pub fn from( transaction_legacy_unsigned: TransactionLegacyUnsigned, signature: &[u8; 65], From b75fa9989418c792f3ee814dceee9e616e7727ad Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 2 Oct 2024 14:32:08 +0200 Subject: [PATCH 009/174] rm log --- substrate/frame/revive/src/address.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/substrate/frame/revive/src/address.rs b/substrate/frame/revive/src/address.rs index 3418e49e6f20..4633fce1f327 100644 --- a/substrate/frame/revive/src/address.rs +++ b/substrate/frame/revive/src/address.rs @@ -17,7 +17,6 @@ //! Functions that deal contract addresses. -use crate::LOG_TARGET; use alloc::vec::Vec; use sp_core::H160; use sp_io::hashing::keccak_256; @@ -78,7 +77,6 @@ impl AddressMapper for DefaultAddressMapper { /// Determine the address of a contract using CREATE semantics. pub fn create1(deployer: &H160, nonce: u64) -> H160 { - log::debug!(target: LOG_TARGET, "create1: deployer={deployer:?}, nonce={nonce}"); let mut list = rlp::RlpStream::new_list(2); list.append(&deployer.as_bytes()); list.append(&nonce); From c2f4beeed2590cba14097f5b7187e0d7eae3a089 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 3 Oct 2024 02:16:39 +0200 Subject: [PATCH 010/174] Improve fee checking logic --- substrate/frame/revive/src/evm/runtime.rs | 117 +++++++++++++++++----- substrate/frame/revive/src/lib.rs | 87 ++++++++++++---- substrate/frame/revive/src/primitives.rs | 41 +++++--- 3 files changed, 187 insertions(+), 58 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index b85b2fe9e17f..83fd1a132128 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -24,10 +24,11 @@ use crate::{ use codec::{Decode, Encode}; use core::marker::PhantomData; use frame_support::{ - dispatch::{DispatchInfo, GetDispatchInfo}, + dispatch::{DispatchInfo, GetDispatchInfo, PostDispatchInfo}, traits::ExtrinsicCall, - CloneNoBound, DebugNoBound, EqNoBound, PartialEqNoBound, + CloneNoBound, DebugNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, }; +use pallet_transaction_payment::OnChargeTransaction; use scale_info::TypeInfo; use sp_arithmetic::Percent; use sp_core::{ecdsa, ed25519, sr25519, Get, H160, U256}; @@ -96,7 +97,7 @@ impl Checkable for UncheckedExtrinsic where Call: Encode + Member, E: EthExtra, - ::Nonce: Into, + ::Nonce: TryFrom, BalanceOf: Into + TryFrom, MomentOf: Into, @@ -169,16 +170,98 @@ impl<'a, Call: Decode, E: EthExtra> serde::Deserialize<'a> for UncheckedExtrinsi } } +/// A [`SignedExtension`] that performs pre-dispatch checks on the Ethereum transaction's fees. +#[derive(DebugNoBound, DefaultNoBound, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct CheckEthTransact { + /// The gas fee, computed from the signed Ethereum transaction. + /// This is only set by the custom `Checkable` impl of [`UncheckedExtrinsic`], Thus this is + /// marked as `#[codec(skip)]` as it should not be encoded by the client. + #[codec(skip)] + eth_fee: Option>, + _phantom: core::marker::PhantomData, +} + +impl CheckEthTransact { + /// Create a new `CheckEthTransact` with the given eth_fee. + pub fn from(eth_fee: BalanceOf) -> Self { + Self { eth_fee: Some(eth_fee), _phantom: Default::default() } + } +} + +impl SignedExtension for CheckEthTransact +where + T: Config + pallet_transaction_payment::Config, + ::RuntimeCall: Dispatchable, + BalanceOf: Into + TryFrom, + <::OnChargeTransaction as OnChargeTransaction>::Balance: Into>, +{ + const IDENTIFIER: &'static str = "CheckEthTransact"; + type AccountId = T::AccountId; + type Call = ::RuntimeCall; + type AdditionalSigned = (); + type Pre = (); + + fn additional_signed( + &self, + ) -> Result + { + Ok(()) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + call: &Self::Call, + info: &sp_runtime::traits::DispatchInfoOf, + len: usize, + ) -> Result { + let Some(eth_fee) = self.eth_fee else { + return Ok(()) + }; + + let tip = Default::default(); + + let actual_fee: BalanceOf = + pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, tip).into(); + + // Make sure that that the fee are not more than 5% higher than the eth_fee + if actual_fee > eth_fee && + Percent::from_rational(actual_fee - eth_fee, eth_fee) > Percent::from_percent(5) + { + log::debug!(target: LOG_TARGET, "Eth fees {eth_fee:?} should be no more than 5% higher + than injected fees {actual_fee:?}"); return Err(InvalidTransaction::Call.into()) + } else if actual_fee > eth_fee { + let ratio = Percent::from_rational(actual_fee - eth_fee, eth_fee); + log::debug!(target: LOG_TARGET, "Eth fees {eth_fee:?} is greater {ratio:?} than injected + fees {actual_fee:?}"); + } else { + let ratio = Percent::from_rational(eth_fee - actual_fee, eth_fee); + log::debug!(target: LOG_TARGET, "Eth fees {eth_fee:?} are less {ratio:?} than injected + fees {actual_fee:?}"); + } + + Ok(()) + } +} + /// EthExtra convert an unsigned [`crate::Call::eth_transact`] into a [`CheckedExtrinsic`]. pub trait EthExtra { /// The Runtime configuration. type Config: crate::Config; /// The Runtime's signed extension. + /// It should include at least: + /// [`CheckNonce`] to ensure that the nonce from the Ethereum transaction is correct. + /// [`CheckEthTransact`] to ensure that the fees from the Ethereum transaction correspond to + /// injected gas limit and storage deposit limit from the extrinsic. type Extra: SignedExtension; /// Get the signed extensions to apply to an unsigned [`crate::Call::eth_transact`] extrinsic. - fn get_eth_transact_extra(nonce: U256) -> Self::Extra; + fn get_eth_transact_extra( + nonce: ::Nonce, + gas_fee: BalanceOf, + ) -> Self::Extra; /// Convert the unsigned [`crate::Call::eth_transact`] into a [`CheckedExtrinsic`]. fn try_into_checked_extrinsic( @@ -188,7 +271,7 @@ pub trait EthExtra { transact_kind: EthTransactKind, ) -> Result, InvalidTransaction> where - ::Nonce: Into, + ::Nonce: TryFrom, BalanceOf: Into + TryFrom, MomentOf: Into, AccountIdOf: Into, @@ -214,15 +297,6 @@ pub trait EthExtra { return Err(InvalidTransaction::Call); } - let account_nonce: U256 = >::account_nonce(&signer).into(); - if nonce > account_nonce { - log::debug!(target: LOG_TARGET, "Invalid nonce: expected {account_nonce}, got {nonce}"); - return Err(InvalidTransaction::Future); - } else if nonce < account_nonce { - log::debug!(target: LOG_TARGET, "Invalid nonce: expected {account_nonce}, got {nonce}"); - return Err(InvalidTransaction::Stale); - } - let call = if let Some(dest) = to { if !matches!(transact_kind, EthTransactKind::Call) { log::debug!(target: LOG_TARGET, "Invalid transact_kind, expected Call"); @@ -263,23 +337,12 @@ pub trait EthExtra { } }; - let dispatch_info = call.get_dispatch_info(); - let call_fee = ::WeightPrice::convert(dispatch_info.weight) - .saturating_add(storage_deposit_limit); - + let nonce = nonce.try_into().map_err(|_| InvalidTransaction::Call)?; let eth_fee = gas_price.saturating_mul(gas).try_into().map_err(|_| InvalidTransaction::Call)?; - // Make sure that that the fee computed from the signed payload is no more than 5% greater - if call_fee > eth_fee && - Percent::from_rational(call_fee - eth_fee, eth_fee) > Percent::from_percent(5) - { - log::debug!(target: LOG_TARGET, "Eth fees {eth_fee:?} should be no more than 5% higher than injected ees {call_fee:?}"); - return Err(InvalidTransaction::Call.into()) - } - Ok(CheckedExtrinsic { - signed: Some((signer.into(), Self::get_eth_transact_extra(nonce))), + signed: Some((signer.into(), Self::get_eth_transact_extra(nonce, eth_fee))), function: call.into(), }) } diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 8ab68c4f12b4..7f86b6687d54 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1137,50 +1137,99 @@ where storage_deposit_limit: BalanceOf, debug: DebugInfo, collect_events: CollectEvents, - ) -> ContractResult, EventRecordOf> { + ) -> EthContractResultDetails> + where + ::RuntimeCall: From>, + ::RuntimeCall: Encode, + { if let Some(dest) = dest { - crate::Pallet::::bare_call( + let result = crate::Pallet::::bare_call( origin, dest, value, gas_limit, storage_deposit_limit, - input, + input.clone(), debug, collect_events, - ) - .map(|result| EthTransactReturnValue { kind: EthTransactKind::Call, result }) + ); + + let dispatch_call = crate::Call::::call { + dest, + value, + gas_limit: result.gas_required, + storage_deposit_limit: result.storage_deposit.charge_or_zero(), + data: input.clone(), + }; + + let dispatch_call: ::RuntimeCall = dispatch_call.into(); + //let weight = dispatch_call.get_dispatch_info().weight; + //let fees = T::WeightPrice::convert(weight); + //log::debug!(target: LOG_TARGET, "Dry-running weight: {weight:?} fees: {fees:?}"); + + EthContractResultDetails { + kind: EthTransactKind::Call, + dispatch_info: dispatch_call.get_dispatch_info(), + len: dispatch_call.encode().len() as u32, + gas_limit: result.gas_required, + storage_deposit: result.storage_deposit.charge_or_zero(), + result: result.result.map(|v| v.data), + } } else { let Ok(EthInstantiateInput { code, data }) = EthInstantiateInput::decode(&mut &input[..]) else { - return ContractResult { - result: Err(>::DecodingFailed.into()), - gas_consumed: Default::default(), - gas_required: Default::default(), + let dispatch_call = crate::Call::::instantiate_with_code { + value, + gas_limit: Default::default(), + storage_deposit_limit: 0u32.into(), + code: input, + data: Default::default(), + salt: None, + }; + return EthContractResultDetails { + kind: EthTransactKind::Call, + dispatch_info: dispatch_call.get_dispatch_info(), + gas_limit: Default::default(), storage_deposit: Default::default(), - debug_message: Default::default(), - events: Default::default(), + len: dispatch_call.encode().len() as u32, + result: Err(>::DecodingFailed.into()), } }; let code_len = code.len() as u32; let data_len = data.len() as u32; - crate::Pallet::::bare_instantiate( + let result = crate::Pallet::::bare_instantiate( origin, value, gas_limit, storage_deposit_limit, - Code::Upload(code), - data, + Code::Upload(code.clone()), + data.clone(), None, DebugInfo::Skip, CollectEvents::Skip, - ) - .map(|r| EthTransactReturnValue { + ); + + let dispatch_call = crate::Call::::instantiate_with_code { + value, + gas_limit: result.gas_required, + storage_deposit_limit: result.storage_deposit.charge_or_zero(), + code, + data, + salt: None, + }; + + let dispatch_call: ::RuntimeCall = dispatch_call.into(); + + EthContractResultDetails { kind: EthTransactKind::InstantiateWithCode { code_len, data_len }, - result: r.result, - }) + dispatch_info: dispatch_call.get_dispatch_info(), + len: dispatch_call.encode().len() as u32, + gas_limit: result.gas_required, + storage_deposit: result.storage_deposit.charge_or_zero(), + result: result.result.map(|v| v.result.data), + } } } @@ -1298,7 +1347,7 @@ sp_api::decl_runtime_apis! { input: Vec, gas_limit: Option, storage_deposit_limit: Option, - ) -> ContractResult; + ) -> EthContractResult; /// Upload new code without instantiating a contract from it. /// diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index 33e4052c96b8..22c0b6de5619 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -82,18 +82,35 @@ pub struct ContractResult { pub events: Option>, } -impl ContractResult { - /// Maps the result of a contract execution, using the provided function. - pub fn map(self, f: impl FnOnce(R) -> V) -> ContractResult { - ContractResult { - gas_consumed: self.gas_consumed, - gas_required: self.gas_required, - storage_deposit: self.storage_deposit, - debug_message: self.debug_message, - result: self.result.map(f), - events: self.events, - } - } +/// The result of the execution of a `eth_transact` call. +pub struct EthContractResultDetails { + /// The kind of transaction that was executed. + pub kind: EthTransactKind, + /// The call's dispatch info. + pub dispatch_info: frame_support::dispatch::DispatchInfo, + /// Length of the encoded call. + pub len: u32, + /// Gas limit of the transaction. + pub gas_limit: Weight, + /// Storage deposit charged. + pub storage_deposit: Balance, + /// The execution result. + pub result: Result, DispatchError>, +} + +/// Similar to `EthContractResultDetails` but with the fee instead of dispatch info and len. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct EthContractResult { + /// The kind of transaction that was executed. + pub kind: EthTransactKind, + /// The fee charged for the execution. + pub fee: Balance, + /// Gas limit of the transaction. + pub gas_limit: Weight, + /// Storage deposit charged. + pub storage_deposit: Balance, + /// The execution result. + pub result: Result, DispatchError>, } /// Result type of a `bare_code_upload` call. From 38fd68187124a817a7c755bcddd7e1b3652a7207 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 4 Oct 2024 10:49:22 +0200 Subject: [PATCH 011/174] Make tests pass again --- substrate/frame/revive/src/evm/runtime.rs | 42 ++++++++++++++--------- substrate/frame/revive/src/primitives.rs | 25 ++++++++++++-- substrate/frame/revive/src/tests.rs | 18 ++++++++-- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 83fd1a132128..529b3214fc65 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -229,16 +229,8 @@ where if actual_fee > eth_fee && Percent::from_rational(actual_fee - eth_fee, eth_fee) > Percent::from_percent(5) { - log::debug!(target: LOG_TARGET, "Eth fees {eth_fee:?} should be no more than 5% higher - than injected fees {actual_fee:?}"); return Err(InvalidTransaction::Call.into()) - } else if actual_fee > eth_fee { - let ratio = Percent::from_rational(actual_fee - eth_fee, eth_fee); - log::debug!(target: LOG_TARGET, "Eth fees {eth_fee:?} is greater {ratio:?} than injected - fees {actual_fee:?}"); - } else { - let ratio = Percent::from_rational(eth_fee - actual_fee, eth_fee); - log::debug!(target: LOG_TARGET, "Eth fees {eth_fee:?} are less {ratio:?} than injected - fees {actual_fee:?}"); + log::debug!(target: LOG_TARGET, "fees {actual_fee:?} should be no more than 5% higher than fees calculated from the Ethereum transaction {eth_fee:?}"); + return Err(InvalidTransaction::Call.into()) } Ok(()) @@ -413,10 +405,10 @@ mod test { impl EthExtra for Extra { type Config = Test; - type Extra = frame_system::CheckNonce; + type Extra = (frame_system::CheckNonce, CheckEthTransact); - fn get_eth_transact_extra(nonce: U256) -> Self::Extra { - frame_system::CheckNonce::from(nonce.as_u32()) + fn get_eth_transact_extra(nonce: u32, eth_fee: u64) -> Self::Extra { + (frame_system::CheckNonce::from(nonce), CheckEthTransact::from(eth_fee)) } } @@ -491,14 +483,29 @@ mod test { fn check(&self) -> Result { let UncheckedExtrinsicBuilder { tx, gas_limit, storage_deposit_limit, transact_kind } = self.clone(); - let payload = Account::default().sign_transaction(tx).rlp_bytes().to_vec(); + let account = Account::default(); + + let _ = ::Currency::set_balance(&account.account_id(), 100_000_000); + + let payload = account.sign_transaction(tx).rlp_bytes().to_vec(); let call = RuntimeCall::Contracts(crate::Call::eth_transact { payload, gas_limit, storage_deposit_limit, transact_kind, }); - Ex::new(call, None).unwrap().check(&TestContext {}).map(|x| x.function) + + let encoded_len = call.encode().len(); + let result = Ex::new(call, None).unwrap().check(&TestContext {})?; + let (account_id, extra) = result.signed.unwrap(); + extra.pre_dispatch( + &account_id, + &result.function, + &result.function.get_dispatch_info(), + encoded_len, + )?; + + Ok(result.function) } } @@ -522,7 +529,9 @@ mod test { // Check an instantiate call let code = vec![]; let data = vec![]; - let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()); + let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()) + .update(|tx| tx.nonce = 1u32.into()); + assert_eq!( builder.check().unwrap(), crate::Call::instantiate_with_code:: { @@ -620,6 +629,7 @@ mod test { #[test] fn check_injected_weight() { ExtBuilder::default().build().execute_with(|| { + /// Lower the gas_price to make the tx fees lower than the actual fees let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])) .update(|tx| tx.gas_price = U256::from(1)); diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index 22c0b6de5619..e62e45a26bce 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -20,7 +20,7 @@ use crate::H160; use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::weights::Weight; +use frame_support::{dispatch::DispatchInfo, weights::Weight}; use pallet_revive_uapi::ReturnFlags; use scale_info::TypeInfo; use sp_runtime::{ @@ -87,7 +87,7 @@ pub struct EthContractResultDetails { /// The kind of transaction that was executed. pub kind: EthTransactKind, /// The call's dispatch info. - pub dispatch_info: frame_support::dispatch::DispatchInfo, + pub dispatch_info: DispatchInfo, /// Length of the encoded call. pub len: u32, /// Gas limit of the transaction. @@ -98,6 +98,27 @@ pub struct EthContractResultDetails { pub result: Result, DispatchError>, } +impl> EthContractResultDetails { + /// Map to a EthContractResult, using the provided compute_fee function. + /// + /// # Parameters + /// + /// - `compute_fee`: A function that takes the length of the encoded call, the dispatch info and + /// the tip and returns the fee. + pub fn map( + self, + compute_fee: impl FnOnce(u32, &DispatchInfo, Balance) -> Balance, + ) -> EthContractResult { + EthContractResult { + kind: self.kind, + result: self.result, + gas_limit: self.gas_limit, + storage_deposit: self.storage_deposit, + fee: compute_fee(self.len, &self.dispatch_info, 0.into()), + } + } +} + /// Similar to `EthContractResultDetails` but with the fee instead of dispatch info and len. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct EthContractResult { diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 324b329ce1a4..3108b41a7900 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -58,16 +58,17 @@ use frame_support::{ tokens::Preservation, ConstU32, ConstU64, Contains, OnIdle, OnInitialize, StorageVersion, }, - weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight, WeightMeter}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, FixedFee, IdentityFee, Weight, WeightMeter}, }; use frame_system::{EventRecord, Phase}; use pallet_revive_fixtures::{bench::dummy_unique, compile_module}; use pallet_revive_uapi::ReturnErrorCode as RuntimeReturnCode; +use pallet_transaction_payment::{ConstFeeMultiplier, Multiplier}; use sp_io::hashing::blake2_256; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ testing::H256, - traits::{BlakeTwo256, Convert, IdentityLookup}, + traits::{BlakeTwo256, Convert, IdentityLookup, One}, AccountId32, BuildStorage, DispatchError, Perbill, TokenError, }; @@ -82,6 +83,7 @@ frame_support::construct_runtime!( Utility: pallet_utility, Contracts: pallet_revive, Proxy: pallet_proxy, + TransactionPayment: pallet_transaction_payment, Dummy: pallet_dummy } ); @@ -406,6 +408,18 @@ impl pallet_proxy::Config for Test { type AnnouncementDepositFactor = ConstU64<1>; } +parameter_types! { + pub FeeMultiplier: Multiplier = Multiplier::one(); +} + +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] +impl pallet_transaction_payment::Config for Test { + type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter; + type WeightToFee = IdentityFee<::Balance>; + type LengthToFee = FixedFee<100, ::Balance>; + type FeeMultiplierUpdate = ConstFeeMultiplier; +} + impl pallet_dummy::Config for Test {} parameter_types! { From e8947bc6a198282cff1f7dd23995a42963a3f972 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 4 Oct 2024 11:13:12 +0200 Subject: [PATCH 012/174] fixes --- substrate/bin/node/runtime/src/lib.rs | 1 + substrate/frame/revive/src/evm/runtime.rs | 42 +++++++++++++++++------ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index c59316e3b8db..4ff6df53b2d4 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2564,6 +2564,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + /// The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload; /// Extrinsic type that has already been checked. diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 529b3214fc65..e181065067e7 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -56,7 +56,8 @@ pub type AccountIndex = u32; /// The address format for describing accounts. pub type MultiAddress = sp_runtime::MultiAddress; -/// Wraps [`generic::UncheckedExtrinsic`] to support checking [`crate::Call::eth_transact`]. +/// Wraps [`generic::UncheckedExtrinsic`] to support checking unsigned +/// [`crate::Call::eth_transact`] extrinsic. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] #[scale_info(skip_type_params(E))] pub struct UncheckedExtrinsic( @@ -175,8 +176,11 @@ impl<'a, Call: Decode, E: EthExtra> serde::Deserialize<'a> for UncheckedExtrinsi #[scale_info(skip_type_params(T))] pub struct CheckEthTransact { /// The gas fee, computed from the signed Ethereum transaction. - /// This is only set by the custom `Checkable` impl of [`UncheckedExtrinsic`], Thus this is - /// marked as `#[codec(skip)]` as it should not be encoded by the client. + /// + /// # Note + /// + /// This is marked as `#[codec(skip)]` as this extracted from the Ethereum transaction and not + /// encoded as additional signed data. #[codec(skip)] eth_fee: Option>, _phantom: core::marker::PhantomData, @@ -246,10 +250,14 @@ pub trait EthExtra { /// It should include at least: /// [`CheckNonce`] to ensure that the nonce from the Ethereum transaction is correct. /// [`CheckEthTransact`] to ensure that the fees from the Ethereum transaction correspond to - /// injected gas limit and storage deposit limit from the extrinsic. + /// the pre-dispatch fees computed from the extrinsic. type Extra: SignedExtension; /// Get the signed extensions to apply to an unsigned [`crate::Call::eth_transact`] extrinsic. + /// + /// # Parameters + /// - `nonce`: The nonce from the Ethereum transaction. + /// - `gas_fee`: The gas fee from the Ethereum transaction. fn get_eth_transact_extra( nonce: ::Nonce, gas_fee: BalanceOf, @@ -374,6 +382,7 @@ mod test { Account { sk: SecretKey::from_slice(&sb).unwrap() } } + /// Get the [`AccountId`] of the account. pub fn account_id(&self) -> AccountId { let address = self.address(); ::AddressMapper::to_account_id_contract(&address) @@ -426,6 +435,7 @@ mod test { } } + /// A builder for creating an unchecked extrinsic, and test that the check function works. #[derive(Clone)] struct UncheckedExtrinsicBuilder { tx: TransactionLegacyUnsigned, @@ -435,6 +445,7 @@ mod test { } impl UncheckedExtrinsicBuilder { + /// Create a new builder with default values. fn new() -> Self { Self { tx: TransactionLegacyUnsigned { @@ -453,6 +464,7 @@ mod test { } } + /// Create a new builder with a call to the given address. fn call_with(dest: H160) -> Self { let mut builder = Self::new(); builder.tx.to = Some(dest); @@ -460,6 +472,7 @@ mod test { builder } + /// Create a new builder with an instantiate call. fn instantiate_with(code: Vec, data: Vec) -> Self { let mut builder = Self::new(); builder.transact_kind = EthTransactKind::InstantiateWithCode { @@ -470,21 +483,25 @@ mod test { builder } + /// Update the transaction with the given function. fn update(mut self, f: impl FnOnce(&mut TransactionLegacyUnsigned) -> ()) -> Self { f(&mut self.tx); self } + /// Set the transact kind fn transact_kind(mut self, kind: EthTransactKind) -> Self { self.transact_kind = kind; self } + /// Call `check` on the unchecked extrinsic, and `pre_dispatch` on the signed extension. fn check(&self) -> Result { let UncheckedExtrinsicBuilder { tx, gas_limit, storage_deposit_limit, transact_kind } = self.clone(); - let account = Account::default(); + // Fund the account. + let account = Account::default(); let _ = ::Currency::set_balance(&account.account_id(), 100_000_000); let payload = account.sign_transaction(tx).rlp_bytes().to_vec(); @@ -498,6 +515,7 @@ mod test { let encoded_len = call.encode().len(); let result = Ex::new(call, None).unwrap().check(&TestContext {})?; let (account_id, extra) = result.signed.unwrap(); + extra.pre_dispatch( &account_id, &result.function, @@ -510,9 +528,8 @@ mod test { } #[test] - fn check_eth_transact_works() { + fn check_eth_transact_call_works() { ExtBuilder::default().build().execute_with(|| { - // Check a regular transfer call let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])); assert_eq!( builder.check().unwrap(), @@ -525,12 +542,15 @@ mod test { } .into() ); + }); + } - // Check an instantiate call + #[test] + fn check_eth_transact_instantiate_works() { + ExtBuilder::default().build().execute_with(|| { let code = vec![]; let data = vec![]; - let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()) - .update(|tx| tx.nonce = 1u32.into()); + let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()); assert_eq!( builder.check().unwrap(), @@ -629,7 +649,7 @@ mod test { #[test] fn check_injected_weight() { ExtBuilder::default().build().execute_with(|| { - /// Lower the gas_price to make the tx fees lower than the actual fees + // Lower the gas_price to make the tx fees lower than the actual fees let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])) .update(|tx| tx.gas_price = U256::from(1)); From a5f6f7568de5bb2bc99aff20a360a289d3bb60eb Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 4 Oct 2024 11:23:14 +0200 Subject: [PATCH 013/174] fixes --- substrate/bin/node/runtime/src/lib.rs | 4 ++-- substrate/frame/revive/src/lib.rs | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 4ff6df53b2d4..59168ac6358b 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -3013,7 +3013,7 @@ impl_runtime_apis! { input: Vec, gas_limit: Option, storage_deposit_limit: Option, - ) -> pallet_revive::ContractResult + ) -> pallet_revive::EthContractResult { use pallet_revive::AddressMapper; let blockweights: BlockWeights = ::BlockWeights::get(); @@ -3027,7 +3027,7 @@ impl_runtime_apis! { storage_deposit_limit.unwrap_or(u128::MAX), pallet_revive::DebugInfo::UnsafeDebug, pallet_revive::CollectEvents::UnsafeCollect, - ) + ).map(pallet_transaction_payment::Pallet::::compute_fee) } fn call( diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 7f86b6687d54..9535d17f2e71 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1163,9 +1163,6 @@ where }; let dispatch_call: ::RuntimeCall = dispatch_call.into(); - //let weight = dispatch_call.get_dispatch_info().weight; - //let fees = T::WeightPrice::convert(weight); - //log::debug!(target: LOG_TARGET, "Dry-running weight: {weight:?} fees: {fees:?}"); EthContractResultDetails { kind: EthTransactKind::Call, From 2c5242af978cd058270f492d578fe3e70aced59d Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 4 Oct 2024 11:27:08 +0200 Subject: [PATCH 014/174] Remove unused --- substrate/frame/revive/src/primitives.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index e62e45a26bce..2a971290873e 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -179,15 +179,6 @@ pub enum EthTransactKind { }, } -/// The result of a successful eth_transact call -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct EthTransactReturnValue { - /// The kind of transaction that was executed. - pub kind: EthTransactKind, - /// The output of the called constructor. - pub result: ExecReturnValue, -} - /// The result of a successful contract instantiation. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct InstantiateReturnValue { From 8c358219886e0f660052eeb8c7b5919b8c6d9ccc Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 4 Oct 2024 11:38:06 +0200 Subject: [PATCH 015/174] Rm additional details from prdoc --- prdoc/pr_5866.prdoc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/prdoc/pr_5866.prdoc b/prdoc/pr_5866.prdoc index 86c08883dedb..ecafc3313774 100644 --- a/prdoc/pr_5866.prdoc +++ b/prdoc/pr_5866.prdoc @@ -9,15 +9,6 @@ doc: - A new pallet::call eth_transact. - A custom UncheckedExtrinsic struct to dispatch unsigned eth_transact calls from an Ethereum JSON-RPC proxy. - Generated types and traits to support implementing a JSON-RPC Ethereum proxy. - - Flow Overview: - - A user submits a transaction via MetaMask or another Ethereum-compatible wallet. - - The proxy dry run the transaction and add metadata to the call ( gas limit in Weight, Storage deposit limit, bytecode and constructor length for contract instantiation) - - The raw transaction, along with the additional metadata, is submitted to the node as an unsigned extrinsic. - - On the node, the custom UncheckedExtrinsic struct has a custom Checkable implementation that converts the unsigned extrinsics into checked ones - - It recovers the signer - - validates the payload, and injects default signed extensions, allowing the system to increment the nonce and charge the appropriate fees. - - re-route the call to pallet-revive::Call::call or pallet-revive::Call::instantiateWithCode crates: - name: pallet-revive bump: patch From dd56741db82e8b56b5d114503946dea3baeb3716 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 4 Oct 2024 14:44:56 +0200 Subject: [PATCH 016/174] prep kitchensink integration --- substrate/frame/revive/src/evm/api/byte.rs | 13 ++++++++++++- substrate/frame/revive/src/evm/runtime.rs | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/evm/api/byte.rs b/substrate/frame/revive/src/evm/api/byte.rs index cafcaabf24ae..13d29eaf74cf 100644 --- a/substrate/frame/revive/src/evm/api/byte.rs +++ b/substrate/frame/revive/src/evm/api/byte.rs @@ -139,10 +139,21 @@ impl_hex!(Bytes, Vec, vec![]); impl_hex!(Bytes256, [u8; 256], [0u8; 256]); #[test] -fn serialize_byte() { +fn serialize_works() { let a = Byte(42); let s = serde_json::to_string(&a).unwrap(); assert_eq!(s, "\"0x2a\""); let b = serde_json::from_str::(&s).unwrap(); assert_eq!(a, b); + + let a = Bytes(b"bello world".to_vec()); + let s = serde_json::to_string(&a).unwrap(); + assert_eq!(s, "\"0x62656c6c6f20776f726c64\""); + let b = serde_json::from_str::(&s).unwrap(); + assert_eq!(a, b); + + let a = Bytes256([42u8; 256]); + let s = serde_json::to_string(&a).unwrap(); + let b = serde_json::from_str::(&s).unwrap(); + assert_eq!(a, b); } diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index e181065067e7..a6563d3902e3 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -64,6 +64,26 @@ pub struct UncheckedExtrinsic( generic::UncheckedExtrinsic, ); +impl + From> + for UncheckedExtrinsic +{ + fn from( + utx: generic::UncheckedExtrinsic, + ) -> Self { + Self(utx) + } +} + +impl + Into> + for UncheckedExtrinsic +{ + fn into(self) -> generic::UncheckedExtrinsic { + self.0 + } +} + impl Extrinsic for UncheckedExtrinsic { type Call = Call; From 62ffb24cb33d0ef96119aed1c387f0a5812b3fd2 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 4 Oct 2024 14:56:14 +0200 Subject: [PATCH 017/174] fix kitchensink --- substrate/bin/node/cli/src/benchmarking.rs | 10 +++--- substrate/bin/node/cli/src/service.rs | 6 +++- substrate/bin/node/runtime/src/lib.rs | 39 +++++++++++++++++++++- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/substrate/bin/node/cli/src/benchmarking.rs b/substrate/bin/node/cli/src/benchmarking.rs index a2b28a0f317d..f67017c00a84 100644 --- a/substrate/bin/node/cli/src/benchmarking.rs +++ b/substrate/bin/node/cli/src/benchmarking.rs @@ -29,8 +29,8 @@ use node_primitives::{AccountId, Balance}; use sc_cli::Result; use sp_inherents::{InherentData, InherentDataProvider}; use sp_keyring::Sr25519Keyring; -use sp_runtime::OpaqueExtrinsic; +use sp_runtime::{generic, OpaqueExtrinsic}; use std::{sync::Arc, time::Duration}; /// Generates `System::Remark` extrinsics for the benchmarks. @@ -58,7 +58,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { fn build(&self, nonce: u32) -> std::result::Result { let acc = Sr25519Keyring::Bob.pair(); - let extrinsic: OpaqueExtrinsic = create_extrinsic( + let extrinsic: generic::UncheckedExtrinsic<_, _, _, _> = create_extrinsic( self.client.as_ref(), acc, SystemCall::remark { remark: vec![] }, @@ -66,7 +66,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { ) .into(); - Ok(extrinsic) + Ok(extrinsic.into()) } } @@ -97,7 +97,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { fn build(&self, nonce: u32) -> std::result::Result { let acc = Sr25519Keyring::Bob.pair(); - let extrinsic: OpaqueExtrinsic = create_extrinsic( + let extrinsic: generic::UncheckedExtrinsic<_, _, _, _> = create_extrinsic( self.client.as_ref(), acc, BalancesCall::transfer_keep_alive { @@ -108,7 +108,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { ) .into(); - Ok(extrinsic) + Ok(extrinsic.into()) } } diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 69e953f54e42..d3a1904bc996 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -138,6 +138,8 @@ pub fn create_extrinsic( >::from(tip, None), ), frame_metadata_hash_extension::CheckMetadataHash::new(false), + pallet_revive::evm::runtime::CheckEthTransact::::default( + ), ); let raw_payload = kitchensink_runtime::SignedPayload::from_raw( @@ -153,16 +155,18 @@ pub fn create_extrinsic( (), (), None, + (), ), ); let signature = raw_payload.using_encoded(|e| sender.sign(e)); - kitchensink_runtime::UncheckedExtrinsic::new_signed( + generic::UncheckedExtrinsic::new_signed( function, sp_runtime::AccountId32::from(sender.public()).into(), kitchensink_runtime::Signature::Sr25519(signature), extra, ) + .into() } /// Creates a new partial node. diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 59168ac6358b..3e2a00f8f1ad 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -76,6 +76,7 @@ use pallet_identity::legacy::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; +use pallet_revive::evm::runtime::EthExtra; use pallet_session::historical as pallet_session_historical; // Can't use `FungibleAdapter` here until Treasury pallet migrates to fungibles // @@ -1471,6 +1472,7 @@ where ), ), frame_metadata_hash_extension::CheckMetadataHash::new(false), + pallet_revive::evm::runtime::CheckEthTransact::::default(), ); let raw_payload = SignedPayload::new(call, extra) .map_err(|e| { @@ -2531,6 +2533,16 @@ mod runtime { pub type Revive = pallet_revive::Pallet; } +impl TryInto> for RuntimeCall { + type Error = (); + fn try_into(self) -> Result, Self::Error> { + match self { + RuntimeCall::Revive(call) => Ok(call), + _ => Err(()), + } + } +} + /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; /// Block header type as expected by this runtime. @@ -2559,11 +2571,36 @@ pub type SignedExtra = ( pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, >, frame_metadata_hash_extension::CheckMetadataHash, + pallet_revive::evm::runtime::CheckEthTransact, ); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct EthSignedExtra; + +impl EthExtra for EthSignedExtra { + type Config = Runtime; + type Extra = SignedExtra; + + fn get_eth_transact_extra(nonce: u32, eth_fee: u128) -> Self::Extra { + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::from(crate::generic::Era::Immortal), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::::from(0, None) + .into(), + frame_metadata_hash_extension::CheckMetadataHash::::new(false), + pallet_revive::evm::runtime::CheckEthTransact::::from(eth_fee), + ) + } +} + /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + pallet_revive::evm::runtime::UncheckedExtrinsic; /// The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload; From 0b5f646a46eeda79cf669f5a8ceb7211394ba7a5 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 4 Oct 2024 17:27:08 +0200 Subject: [PATCH 018/174] use subxt-signer & eth feature --- Cargo.lock | 38 +++++++++++++++++++++++ substrate/frame/revive/Cargo.toml | 2 +- substrate/frame/revive/src/evm/runtime.rs | 28 ++++------------- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32ca83e0e19c..cc2118e9f021 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,6 +1615,22 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "bip32" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b" +dependencies = [ + "bs58", + "hmac 0.12.1", + "k256", + "rand_core 0.6.4", + "ripemd", + "sha2 0.10.8", + "subtle 2.5.0", + "zeroize", +] + [[package]] name = "bip39" version = "2.0.0" @@ -2563,6 +2579,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ + "sha2 0.10.8", "tinyvec", ] @@ -8402,6 +8419,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-hash" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +dependencies = [ + "primitive-types", + "tiny-keccak", +] + [[package]] name = "keccak-hasher" version = "0.16.0" @@ -17734,6 +17761,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -24355,10 +24391,12 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49888ae6ae90fe01b471193528eea5bd4ed52d8eecd2d13f4a2333b87388850" dependencies = [ + "bip32", "bip39", "cfg-if", "hex", "hmac 0.12.1", + "keccak-hash", "parity-scale-codec", "pbkdf2", "regex", diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 10229e910e71..61fb5f7031ae 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -62,7 +62,7 @@ pallet-revive-fixtures = { workspace = true, default-features = true } secp256k1 = { workspace = true, features = ["recovery"] } serde_json.workspace = true hex-literal.workspace = true -subxt-signer.workspace = true +subxt-signer = { workspace = true, features = ["unstable-eth"] } # Polkadot SDK Dependencies pallet-balances = { workspace = true, default-features = true } diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index a6563d3902e3..eba6ecbc1aa1 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -361,6 +361,7 @@ pub trait EthExtra { let eth_fee = gas_price.saturating_mul(gas).try_into().map_err(|_| InvalidTransaction::Call)?; + log::debug!(target: LOG_TARGET, "Created checked Ethereum transaction with nonce {nonce:?}"); Ok(CheckedExtrinsic { signed: Some((signer.into(), Self::get_eth_transact_extra(nonce, eth_fee))), function: call.into(), @@ -384,24 +385,15 @@ mod test { use sp_runtime::traits::{Checkable, IdentityLookup}; /// A simple account that can sign transactions - pub struct Account { - /// The secret key of the account - sk: SecretKey, - } + pub struct Account(subxt_signer::eth::Keypair); impl Default for Account { fn default() -> Self { - Account::from_keypair(&subxt_signer::ecdsa::dev::alice()) + Self(subxt_signer::eth::dev::alith()) } } impl Account { - /// Create an account from a keypair. - pub fn from_keypair(pair: &subxt_signer::ecdsa::Keypair) -> Self { - let sb = pair.0.secret_key().secret_bytes(); - Account { sk: SecretKey::from_slice(&sb).unwrap() } - } - /// Get the [`AccountId`] of the account. pub fn account_id(&self) -> AccountId { let address = self.address(); @@ -410,22 +402,14 @@ mod test { /// Get the [`H160`] address of the account. pub fn address(&self) -> H160 { - let pub_key = - PublicKey::from_secret_key(&Secp256k1::new(), &self.sk).serialize_uncompressed(); - let hash = keccak_256(&pub_key[1..]); - H160::from_slice(&hash[12..]) + H160::from_slice(&self.0.account_id().as_ref()) } /// Sign a transaction. pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { let rlp_encoded = tx.rlp_bytes(); - let tx_hash = keccak_256(&rlp_encoded); - let secp = Secp256k1::new(); - let msg = Message::from_digest(tx_hash); - let sig = secp.sign_ecdsa_recoverable(&msg, &self.sk); - let (recovery_id, sig) = sig.serialize_compact(); - let sig = sig.into_iter().chain([recovery_id.to_i32() as u8]).collect::>(); - TransactionLegacySigned::from(tx, &sig.try_into().unwrap()) + let signature = self.0.sign(&rlp_encoded); + TransactionLegacySigned::from(tx, signature.as_ref()) } } From ad3c0eea9b7703cadb5dc9324fcba2dd4322d140 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 10:07:09 +0200 Subject: [PATCH 019/174] Move rpc stuff to new PR --- substrate/frame/revive/Cargo.toml | 6 +- substrate/frame/revive/src/evm/api.rs | 5 - .../revive/src/evm/api/rpc_methods_gen.rs | 152 ------------------ 3 files changed, 3 insertions(+), 160 deletions(-) delete mode 100644 substrate/frame/revive/src/evm/api/rpc_methods_gen.rs diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 61fb5f7031ae..19276b1cc6e0 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -84,22 +84,22 @@ riscv = ["pallet-revive-fixtures/riscv"] std = [ "codec/std", "environmental/std", + "ethereum-types/std", "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "hex/std", "jsonrpsee", "log/std", "pallet-balances?/std", "pallet-proxy/std", "pallet-revive-fixtures/std", "pallet-timestamp/std", + "pallet-transaction-payment/std", "pallet-utility/std", "polkavm/std", "rlp/std", "scale-info/std", - "ethereum-types/std", - "hex/std", - "pallet-transaction-payment/std", "secp256k1/std", "serde/std", "serde_json/std", diff --git a/substrate/frame/revive/src/evm/api.rs b/substrate/frame/revive/src/evm/api.rs index eef432609c1b..18cbb9473361 100644 --- a/substrate/frame/revive/src/evm/api.rs +++ b/substrate/frame/revive/src/evm/api.rs @@ -29,9 +29,4 @@ mod rpc_types; mod rpc_types_gen; pub use rpc_types_gen::*; -#[cfg(feature = "std")] -pub mod rpc_methods_gen; -#[cfg(feature = "std")] -pub use rpc_methods_gen::*; - mod signature; diff --git a/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs b/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs deleted file mode 100644 index eb6bebe232b4..000000000000 --- a/substrate/frame/revive/src/evm/api/rpc_methods_gen.rs +++ /dev/null @@ -1,152 +0,0 @@ -// 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. -//! Generated JSON-RPC methods. -#![allow(missing_docs)] - -use super::*; -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; - -#[rpc(server, client)] -pub trait EthRpc { - /// Returns a list of addresses owned by client. - #[method(name = "eth_accounts")] - async fn accounts(&self) -> RpcResult>; - - /// Returns the number of most recent block. - #[method(name = "eth_blockNumber")] - async fn block_number(&self) -> RpcResult; - - /// Executes a new message call immediately without creating a transaction on the block chain. - #[method(name = "eth_call")] - async fn call( - &self, - transaction: GenericTransaction, - block: Option, - ) -> RpcResult; - - /// Returns the chain ID of the current network. - #[method(name = "eth_chainId")] - async fn chain_id(&self) -> RpcResult; - - /// Generates and returns an estimate of how much gas is necessary to allow the transaction to - /// complete. - #[method(name = "eth_estimateGas")] - async fn estimate_gas( - &self, - transaction: GenericTransaction, - block: Option, - ) -> RpcResult; - - /// Returns the current price per gas in wei. - #[method(name = "eth_gasPrice")] - async fn gas_price(&self) -> RpcResult; - - /// Returns the balance of the account of given address. - #[method(name = "eth_getBalance")] - async fn get_balance(&self, address: Address, block: BlockNumberOrTagOrHash) - -> RpcResult; - - /// Returns information about a block by hash. - #[method(name = "eth_getBlockByHash")] - async fn get_block_by_hash( - &self, - block_hash: H256, - hydrated_transactions: bool, - ) -> RpcResult>; - - /// Returns information about a block by number. - #[method(name = "eth_getBlockByNumber")] - async fn get_block_by_number( - &self, - block: BlockNumberOrTag, - hydrated_transactions: bool, - ) -> RpcResult>; - - /// Returns the number of transactions in a block from a block matching the given block hash. - #[method(name = "eth_getBlockTransactionCountByHash")] - async fn get_block_transaction_count_by_hash( - &self, - block_hash: Option, - ) -> RpcResult>; - - /// Returns the number of transactions in a block matching the given block number. - #[method(name = "eth_getBlockTransactionCountByNumber")] - async fn get_block_transaction_count_by_number( - &self, - block: Option, - ) -> RpcResult>; - - /// Returns code at a given address. - #[method(name = "eth_getCode")] - async fn get_code(&self, address: Address, block: BlockNumberOrTagOrHash) -> RpcResult; - - /// Returns the value from a storage position at a given address. - #[method(name = "eth_getStorageAt")] - async fn get_storage_at( - &self, - address: Address, - storage_slot: U256, - block: BlockNumberOrTagOrHash, - ) -> RpcResult; - - /// Returns information about a transaction by block hash and transaction index position. - #[method(name = "eth_getTransactionByBlockHashAndIndex")] - async fn get_transaction_by_block_hash_and_index( - &self, - block_hash: H256, - transaction_index: U256, - ) -> RpcResult>; - - /// Returns information about a transaction by block number and transaction index position. - #[method(name = "eth_getTransactionByBlockNumberAndIndex")] - async fn get_transaction_by_block_number_and_index( - &self, - block: BlockNumberOrTag, - transaction_index: U256, - ) -> RpcResult>; - - /// Returns the information about a transaction requested by transaction hash. - #[method(name = "eth_getTransactionByHash")] - async fn get_transaction_by_hash( - &self, - transaction_hash: H256, - ) -> RpcResult>; - - /// Returns the number of transactions sent from an address. - #[method(name = "eth_getTransactionCount")] - async fn get_transaction_count( - &self, - address: Address, - block: BlockNumberOrTagOrHash, - ) -> RpcResult; - - /// Returns the receipt of a transaction by transaction hash. - #[method(name = "eth_getTransactionReceipt")] - async fn get_transaction_receipt( - &self, - transaction_hash: H256, - ) -> RpcResult>; - - /// Submits a raw transaction. For EIP-4844 transactions, the raw form must be the network form. - /// This means it includes the blobs, KZG commitments, and KZG proofs. - #[method(name = "eth_sendRawTransaction")] - async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult; - - /// The string value of current network id - #[method(name = "net_version")] - async fn net_version(&self) -> RpcResult; -} From 5634757af8fb3668ae2ee51bdc363d0d3ff40680 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Mon, 7 Oct 2024 11:10:29 +0200 Subject: [PATCH 020/174] Fixing compilation issues --- substrate/bin/node/testing/src/bench.rs | 6 ++++-- substrate/bin/node/testing/src/keyring.rs | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index 007d314684cf..3c68bbc11bc3 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -51,6 +51,7 @@ use sp_core::{ed25519, sr25519, traits::SpawnNamed, Pair, Public}; use sp_crypto_hashing::blake2_256; use sp_inherents::InherentData; use sp_runtime::{ + generic, traits::{Block as BlockT, IdentifyAccount, Verify}, OpaqueExtrinsic, }; @@ -582,12 +583,13 @@ impl BenchKeyring { key.sign(b) } }); - UncheckedExtrinsic { + generic::UncheckedExtrinsic { signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), function: payload.0, } + .into() }, - None => UncheckedExtrinsic { signature: None, function: xt.function }, + None => generic::UncheckedExtrinsic { signature: None, function: xt.function }.into(), } } diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index eab088d9100e..23311660653b 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -25,7 +25,7 @@ use node_primitives::{AccountId, Balance, Nonce}; use sp_core::{ecdsa, ed25519, sr25519}; use sp_crypto_hashing::blake2_256; use sp_keyring::AccountKeyring; -use sp_runtime::generic::Era; +use sp_runtime::{generic, generic::Era}; /// Alice's account id. pub fn alice() -> AccountId { @@ -116,11 +116,12 @@ pub fn sign( } }) .into(); - UncheckedExtrinsic { + generic::UncheckedExtrinsic { signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), function: payload.0, } + .into() }, - None => UncheckedExtrinsic { signature: None, function: xt.function }, + None => generic::UncheckedExtrinsic { signature: None, function: xt.function }.into(), } } From 7f6a356aacbc6c20e8ee696f8392963eac6f1020 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Mon, 7 Oct 2024 11:14:02 +0200 Subject: [PATCH 021/174] rustdoc fixes --- substrate/frame/revive/src/evm/runtime.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index eba6ecbc1aa1..459a1c4fe48a 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -268,9 +268,10 @@ pub trait EthExtra { /// The Runtime's signed extension. /// It should include at least: - /// [`CheckNonce`] to ensure that the nonce from the Ethereum transaction is correct. - /// [`CheckEthTransact`] to ensure that the fees from the Ethereum transaction correspond to - /// the pre-dispatch fees computed from the extrinsic. + /// - [`frame_system::CheckNonce`] to ensure that the nonce from the Ethereum transaction is + /// correct. + /// - [`CheckEthTransact`] to ensure that the fees from the Ethereum transaction + /// correspond to the pre-dispatch fees computed from the extrinsic. type Extra: SignedExtension; /// Get the signed extensions to apply to an unsigned [`crate::Call::eth_transact`] extrinsic. From 059f2472131c2fc13499acd8efbdc3f402104a31 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 11:21:42 +0200 Subject: [PATCH 022/174] Fix doclink --- substrate/frame/revive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 329efec8f249..71f5e6ab933d 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -741,7 +741,7 @@ pub mod pallet { /// /// # Parameters /// - /// * `payload`: The RLP-encoded [`crate::api::TransactionLegacySigned`]. + /// * `payload`: The RLP-encoded [`crate::evm::TransactionLegacySigned`]. /// * `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. From 3893465a6de56ae4400940b5472467a429fde4fa Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 11:30:57 +0200 Subject: [PATCH 023/174] fix prdoc --- prdoc/pr_5866.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_5866.prdoc b/prdoc/pr_5866.prdoc index ecafc3313774..86953089eb39 100644 --- a/prdoc/pr_5866.prdoc +++ b/prdoc/pr_5866.prdoc @@ -11,7 +11,7 @@ doc: - Generated types and traits to support implementing a JSON-RPC Ethereum proxy. crates: - name: pallet-revive - bump: patch + bump: major - name: polkadot-sdk bump: patch From 8ad166d6a5d8e71235af31fe62c6e97c2e1292c0 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 11:40:31 +0200 Subject: [PATCH 024/174] fix keyring --- substrate/bin/node/testing/src/keyring.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index 23311660653b..d11a026802b1 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -83,6 +83,8 @@ pub fn signed_extra(nonce: Nonce, extra_fee: Balance) -> SignedExtra { pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(extra_fee, None), ), frame_metadata_hash_extension::CheckMetadataHash::new(false), + frame_metadata_hash_extension::CheckMetadataHash::new(false), + pallet_revive::evm::runtime::CheckEthTransact::default(), ) } From 766a6c8e38f2d7985038e98fc75823c6172a4754 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 11:48:48 +0200 Subject: [PATCH 025/174] fix --- substrate/bin/node/testing/src/keyring.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index d11a026802b1..66d2c401be92 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -83,7 +83,6 @@ pub fn signed_extra(nonce: Nonce, extra_fee: Balance) -> SignedExtra { pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(extra_fee, None), ), frame_metadata_hash_extension::CheckMetadataHash::new(false), - frame_metadata_hash_extension::CheckMetadataHash::new(false), pallet_revive::evm::runtime::CheckEthTransact::default(), ) } From 2f22e12f2d2bcef1fdd59f30bf2f838618aff651 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 12:14:50 +0200 Subject: [PATCH 026/174] add misssing dep --- substrate/bin/node/testing/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index a5cec856717f..16112386ad7c 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -28,6 +28,7 @@ node-primitives = { workspace = true, default-features = true } kitchensink-runtime = { workspace = true } pallet-asset-conversion = { workspace = true, default-features = true } pallet-assets = { workspace = true, default-features = true } +pallet-revive = { workspace = true, default-features = true } pallet-asset-conversion-tx-payment = { workspace = true, default-features = true } pallet-asset-tx-payment = { workspace = true, default-features = true } pallet-skip-feeless-payment = { workspace = true, default-features = true } From b4fff28021d5231d36b91c6a491d067975f400e6 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 12:25:01 +0200 Subject: [PATCH 027/174] fix lock --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index af1287f9b3d8..2995c2035920 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10283,6 +10283,7 @@ dependencies = [ "pallet-asset-conversion-tx-payment", "pallet-asset-tx-payment", "pallet-assets", + "pallet-revive", "pallet-skip-feeless-payment", "parity-scale-codec", "sc-block-builder", From f228f16e4a52ca7ec4cde6a069ed69b3778ba77b Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 12:40:28 +0200 Subject: [PATCH 028/174] fix --- substrate/bin/node/cli/benches/transaction_pool.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index efec081427f4..da034b7da330 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -168,7 +168,7 @@ fn create_account_extrinsics( ), ] }) - .map(OpaqueExtrinsic::from) + .map(|utx| OpaqueExtrinsic::from(utx.into())) .collect() } @@ -192,7 +192,7 @@ fn create_benchmark_extrinsics( ) }) }) - .map(OpaqueExtrinsic::from) + .map(|utx| OpaqueExtrinsic::from(utx.into())) .collect() } From 034420a7aa040bb0a6a95a553fc331d13b82f27b Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 13:13:39 +0200 Subject: [PATCH 029/174] fix --- substrate/bin/node/cli/src/service.rs | 16 +++++++++++++--- .../bin/node/cli/tests/submit_transaction.rs | 6 +++--- substrate/frame/revive/src/evm/runtime.rs | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index d3a1904bc996..45c616753267 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -883,7 +883,7 @@ mod tests { use sp_keyring::AccountKeyring; use sp_keystore::KeystorePtr; use sp_runtime::{ - generic::{Digest, Era, SignedPayload}, + generic::{self, Digest, Era, SignedPayload}, key_types::BABE, traits::{Block as BlockT, Header as HeaderT, IdentifyAccount, Verify}, RuntimeAppPublic, @@ -1070,6 +1070,7 @@ mod tests { pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(0, None), ); let metadata_hash = frame_metadata_hash_extension::CheckMetadataHash::new(false); + let check_eth_transact = pallet_revive::evm::runtime::CheckEthTransact::default(); let extra = ( check_non_zero_sender, check_spec_version, @@ -1080,6 +1081,7 @@ mod tests { check_weight, tx_payment, metadata_hash, + check_eth_transact, ); let raw_payload = SignedPayload::from_raw( function, @@ -1094,13 +1096,21 @@ mod tests { (), (), None, + (), ), ); let signature = raw_payload.using_encoded(|payload| signer.sign(payload)); let (function, extra, _) = raw_payload.deconstruct(); index += 1; - UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra) - .into() + let utx: UncheckedExtrinsic = generic::UncheckedExtrinsic::new_signed( + function, + from.into(), + signature.into(), + extra, + ) + .into(); + + utx.0.into() }, ); } diff --git a/substrate/bin/node/cli/tests/submit_transaction.rs b/substrate/bin/node/cli/tests/submit_transaction.rs index 18826e7e90a7..45ead98dafd6 100644 --- a/substrate/bin/node/cli/tests/submit_transaction.rs +++ b/substrate/bin/node/cli/tests/submit_transaction.rs @@ -131,7 +131,7 @@ fn should_submit_signed_twice_from_the_same_account() { // now check that the transaction nonces are not equal let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { - let extra = tx.signature.unwrap().2; + let extra = tx.0.signature.unwrap().2; extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); @@ -180,7 +180,7 @@ fn should_submit_signed_twice_from_all_accounts() { // now check that the transaction nonces are not equal let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { - let extra = tx.signature.unwrap().2; + let extra = tx.0.signature.unwrap().2; extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); @@ -237,7 +237,7 @@ fn submitted_transaction_should_be_valid() { let source = TransactionSource::External; let extrinsic = UncheckedExtrinsic::decode(&mut &*tx0).unwrap(); // add balance to the account - let author = extrinsic.signature.clone().unwrap().0; + let author = extrinsic.0.signature.clone().unwrap().0; let address = Indices::lookup(author).unwrap(); let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() }; let account = frame_system::AccountInfo { providers: 1, data, ..Default::default() }; diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 459a1c4fe48a..46473446c140 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -61,7 +61,7 @@ pub type MultiAddress = sp_runtime::MultiAddress; #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] #[scale_info(skip_type_params(E))] pub struct UncheckedExtrinsic( - generic::UncheckedExtrinsic, + pub generic::UncheckedExtrinsic, ); impl From 14e8eb650a954d149ddf1dded45d7579748214b5 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 13:45:24 +0200 Subject: [PATCH 030/174] fix --- substrate/bin/node/cli/benches/block_production.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index de883d1051f5..31924abcc4b5 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -39,6 +39,7 @@ use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed} use sp_consensus::BlockOrigin; use sp_keyring::Sr25519Keyring; use sp_runtime::{ + self, transaction_validity::{InvalidTransaction, TransactionValidityError}, AccountId32, MultiAddress, OpaqueExtrinsic, }; @@ -120,7 +121,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { } fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { - kitchensink_runtime::UncheckedExtrinsic { + generic::UncheckedExtrinsic { signature: None, function: kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), } From acd95d80abb94918041a076d938184e500746caf Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 14:04:04 +0200 Subject: [PATCH 031/174] fixes --- substrate/bin/node/cli/benches/block_production.rs | 2 +- substrate/bin/node/cli/benches/transaction_pool.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index 31924abcc4b5..9959db39646f 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -39,7 +39,7 @@ use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed} use sp_consensus::BlockOrigin; use sp_keyring::Sr25519Keyring; use sp_runtime::{ - self, + generic, transaction_validity::{InvalidTransaction, TransactionValidityError}, AccountId32, MultiAddress, OpaqueExtrinsic, }; diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index da034b7da330..7ee18c7c8088 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -150,7 +150,8 @@ fn create_account_extrinsics( ), }, Some(start_nonce + (i as u32) * 2), - ), + ) + .0, // Give back funds create_extrinsic( client, @@ -165,10 +166,11 @@ fn create_account_extrinsics( ), }, Some(start_nonce + (i as u32) * 2 + 1), - ), + ) + .0, ] }) - .map(|utx| OpaqueExtrinsic::from(utx.into())) + .map(OpaqueExtrinsic::from) .collect() } @@ -192,7 +194,7 @@ fn create_benchmark_extrinsics( ) }) }) - .map(|utx| OpaqueExtrinsic::from(utx.into())) + .map(OpaqueExtrinsic::from) .collect() } From feaa97308fa6381514ba939b19e8e8ecbc248482 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Mon, 7 Oct 2024 14:43:44 +0200 Subject: [PATCH 032/174] fix tx-pool --- substrate/bin/node/cli/benches/transaction_pool.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index da034b7da330..135502f57d4c 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -150,7 +150,8 @@ fn create_account_extrinsics( ), }, Some(start_nonce + (i as u32) * 2), - ), + ) + .0, // Give back funds create_extrinsic( client, @@ -165,10 +166,11 @@ fn create_account_extrinsics( ), }, Some(start_nonce + (i as u32) * 2 + 1), - ), + ) + .0, ] }) - .map(|utx| OpaqueExtrinsic::from(utx.into())) + .map(OpaqueExtrinsic::from) .collect() } @@ -190,9 +192,10 @@ fn create_benchmark_extrinsics( }, Some(nonce as u32), ) + .0 }) }) - .map(|utx| OpaqueExtrinsic::from(utx.into())) + .map(OpaqueExtrinsic::from) .collect() } From 03bc88177cda3f16e8e3315bea672bf37800718d Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Mon, 7 Oct 2024 15:09:24 +0200 Subject: [PATCH 033/174] fix --- substrate/bin/node/cli/benches/block_production.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index 9959db39646f..9a75d22b8dc3 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -121,11 +121,12 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { } fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { - generic::UncheckedExtrinsic { + let utx: kitchensink_runtime::UncheckedExtrinsic = generic::UncheckedExtrinsic { signature: None, function: kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), } - .into() + .into(); + utx.0.into() } fn import_block(client: &FullClient, built: BuiltBlock) { From ea0d57dd121fada1eaf0ae6391ec777954d98e93 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Mon, 7 Oct 2024 15:57:01 +0200 Subject: [PATCH 034/174] fix --- substrate/bin/node/cli/benches/block_production.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index 9a75d22b8dc3..92947f5c215e 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -166,6 +166,7 @@ fn prepare_benchmark(client: &FullClient) -> (usize, Vec) { BalancesCall::transfer_allow_death { dest: dst.clone(), value: 1 * DOLLARS }, Some(nonce), ) + .0 .into(); match block_builder.push(extrinsic.clone()) { From c69817c8ed48111b3148f38e4002bf567bbbab39 Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Mon, 7 Oct 2024 20:26:34 +0200 Subject: [PATCH 035/174] tmp fix --- substrate/frame/revive/src/exec.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index cf623cab1dad..5ce5f07977ca 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -902,11 +902,9 @@ where let address = if let Some(salt) = salt { address::create2(&deployer, executable.code(), input_data, salt) } else { - use sp_runtime::Saturating; - address::create1( - &deployer, - account_nonce.saturating_sub(1u32.into()).saturated_into(), - ) + // TODO: Fix this the nonce is bumped on pre-dispatch, so when this is called by + // origin it will be off by one. + address::create1(&deployer, account_nonce.saturated_into()) }; let contract = ContractInfo::new( &address, @@ -1024,6 +1022,7 @@ where frame.contract_info.get(&frame.account_id), executable.code_info(), )?; + // Needs to be incremented before calling into the code so that it is visible // in case of recursion. >::inc_account_nonce(caller.account_id()?); From b401c6095fc4fada50be2f8fbb5705701120f82f Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Mon, 7 Oct 2024 21:03:15 +0200 Subject: [PATCH 036/174] fix nonce logic --- substrate/frame/revive/src/exec.rs | 17 ++++++++++++++--- substrate/frame/revive/src/tests.rs | 7 ++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 5ce5f07977ca..90d835a6da7b 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -838,6 +838,7 @@ where storage_meter, BalanceOf::::zero(), false, + true, )? else { return Ok(None); @@ -871,6 +872,7 @@ where storage_meter: &mut storage::meter::GenericMeter, deposit_limit: BalanceOf, read_only: bool, + origin_is_caller: bool, ) -> Result, E)>, ExecError> { let (account_id, contract_info, executable, delegate_caller, entry_point) = match frame_args { @@ -902,9 +904,17 @@ where let address = if let Some(salt) = salt { address::create2(&deployer, executable.code(), input_data, salt) } else { - // TODO: Fix this the nonce is bumped on pre-dispatch, so when this is called by - // origin it will be off by one. - address::create1(&deployer, account_nonce.saturated_into()) + use sp_runtime::Saturating; + address::create1( + &deployer, + // the Nonce from the origin has been incremented pre-dispatch, so we need + // to subtract 1 to get the nonce at the time of the call. + if origin_is_caller { + account_nonce.saturating_sub(1u32.into()).saturated_into() + } else { + account_nonce.saturated_into() + }, + ) }; let contract = ContractInfo::new( &address, @@ -975,6 +985,7 @@ where nested_storage, deposit_limit, read_only, + false, )? { self.frames.try_push(frame).map_err(|_| Error::::MaxCallDepthReached)?; Ok(Some(executable)) diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index adc8091aad62..13af6ea51f1d 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -751,15 +751,16 @@ mod run_tests { )); assert_eq!(System::account_nonce(&ALICE), 0); + System::inc_account_nonce(&ALICE); - for nonce in 0..3 { + for nonce in 1..3 { let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) .salt(None) .build_and_unwrap_contract(); assert!(ContractInfoOf::::contains_key(&addr)); assert_eq!( addr, - create1(&::AddressMapper::to_address(&ALICE), nonce) + create1(&::AddressMapper::to_address(&ALICE), nonce - 1) ); } assert_eq!(System::account_nonce(&ALICE), 3); @@ -771,7 +772,7 @@ mod run_tests { assert!(ContractInfoOf::::contains_key(&addr)); assert_eq!( addr, - create1(&::AddressMapper::to_address(&ALICE), nonce) + create1(&::AddressMapper::to_address(&ALICE), nonce - 1) ); } assert_eq!(System::account_nonce(&ALICE), 6); From 3cd749114ff61581c75547aaf59759bcd3bcafc9 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 09:00:51 +0200 Subject: [PATCH 037/174] cleanup tests --- .../frame/revive/src/evm/api/rlp_codec.rs | 47 ++++++++----------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs index b022e5d85206..5665cc8716d1 100644 --- a/substrate/frame/revive/src/evm/api/rlp_codec.rs +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -142,42 +142,33 @@ impl Decodable for TransactionLegacySigned { #[cfg(test)] mod test { use super::*; - use core::str::FromStr; - use secp256k1::{Message, PublicKey, Secp256k1, SecretKey}; - use sp_core::keccak_256; - struct Account { - sk: SecretKey, - } + /// A simple account that can sign transactions + pub struct Account(subxt_signer::eth::Keypair); impl Default for Account { fn default() -> Self { - Account { - sk: SecretKey::from_str( - "a872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd57f", - ) - .unwrap(), - } + Self(subxt_signer::eth::dev::alith()) + } + } + + impl From for Account { + fn from(kp: subxt_signer::eth::Keypair) -> Self { + Self(kp) } } impl Account { - fn address(&self) -> H160 { - let pub_key = - PublicKey::from_secret_key(&Secp256k1::new(), &self.sk).serialize_uncompressed(); - let hash = keccak_256(&pub_key[1..]); - H160::from_slice(&hash[12..]) + /// Get the [`H160`] address of the account. + pub fn address(&self) -> H160 { + H160::from_slice(&self.0.account_id().as_ref()) } - fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { + /// Sign a transaction. + pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { let rlp_encoded = tx.rlp_bytes(); - let tx_hash = keccak_256(&rlp_encoded); - let secp = Secp256k1::new(); - let msg = Message::from_digest(tx_hash); - let sig = secp.sign_ecdsa_recoverable(&msg, &self.sk); - let (recovery_id, sig) = sig.serialize_compact(); - let sig = sig.into_iter().chain([recovery_id.to_i32() as u8]).collect::>(); - TransactionLegacySigned::from(tx, &sig.try_into().unwrap()) + let signature = self.0.sign(&rlp_encoded); + TransactionLegacySigned::from(tx, signature.as_ref()) } } @@ -188,7 +179,7 @@ mod test { gas: U256::from(21000), nonce: U256::from(1), gas_price: U256::from("0x640000006a"), - to: Some(H160::from_str("0x1111111111222222222233333333334444444444").unwrap()), + to: Some(Account::from(subxt_signer::eth::dev::baltathar()).address()), value: U256::from(123123), input: Bytes(vec![]), r#type: Type0, @@ -196,7 +187,7 @@ mod test { let rlp_bytes = rlp::encode(&tx); let decoded = rlp::decode::(&rlp_bytes).unwrap(); - dbg!(&decoded); + assert_eq!(&tx, &decoded); } #[test] @@ -208,7 +199,7 @@ mod test { gas_price: 100_000_000_200u64.into(), gas: 100_107u32.into(), nonce: 3.into(), - to: Some(H160::from_str("75e480db528101a381ce68544611c169ad7eb342").unwrap()), + to: Some(Account::from(subxt_signer::eth::dev::baltathar()).address()), chain_id: Some(596.into()), ..Default::default() }; From e93ef66f978d779160f3677b2be59bf348eeea85 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 10:43:14 +0200 Subject: [PATCH 038/174] fix tests --- substrate/frame/revive/src/evm/api/rlp_codec.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs index 5665cc8716d1..6b5c4dc24a3b 100644 --- a/substrate/frame/revive/src/evm/api/rlp_codec.rs +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -188,6 +188,11 @@ mod test { let rlp_bytes = rlp::encode(&tx); let decoded = rlp::decode::(&rlp_bytes).unwrap(); assert_eq!(&tx, &decoded); + + let tx = Account::default().sign_transaction(tx); + let rlp_bytes = rlp::encode(&tx); + let decoded = rlp::decode::(&rlp_bytes).unwrap(); + assert_eq!(&tx, &decoded); } #[test] From 804f4026e44c5994d2ace0ddf827eca06451584a Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 10:59:25 +0200 Subject: [PATCH 039/174] fix fee dispatch_call --- substrate/frame/revive/src/lib.rs | 54 ++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 71f5e6ab933d..94d3a5ba55f6 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1161,24 +1161,36 @@ where ::RuntimeCall: From>, ::RuntimeCall: Encode, { + use crate::evm::{TransactionLegacySigned, TransactionLegacyUnsigned}; + if let Some(dest) = dest { + let tx = TransactionLegacySigned { + transaction_legacy_unsigned: TransactionLegacyUnsigned { + value: value.into(), + input: input.into(), + to: Some(dest), + ..Default::default() + }, + ..Default::default() + }; + + let payload = rlp::encode(&tx).to_vec(); let result = crate::Pallet::::bare_call( origin, dest, value, gas_limit, storage_deposit_limit, - input.clone(), + tx.transaction_legacy_unsigned.input.0, debug, collect_events, ); - let dispatch_call = crate::Call::::call { - dest, - value, + let dispatch_call = crate::Call::::eth_transact { + payload, gas_limit: result.gas_required, storage_deposit_limit: result.storage_deposit.charge_or_zero(), - data: input.clone(), + transact_kind: EthTransactKind::Call, }; let dispatch_call: ::RuntimeCall = dispatch_call.into(); @@ -1192,17 +1204,29 @@ where result: result.result.map(|v| v.data), } } else { + let tx = TransactionLegacySigned { + transaction_legacy_unsigned: TransactionLegacyUnsigned { + value: value.into(), + input: input.into(), + ..Default::default() + }, + ..Default::default() + }; + let payload = rlp::encode(&tx).to_vec(); + let Ok(EthInstantiateInput { code, data }) = - EthInstantiateInput::decode(&mut &input[..]) + EthInstantiateInput::decode(&mut &tx.transaction_legacy_unsigned.input.0[..]) else { - let dispatch_call = crate::Call::::instantiate_with_code { - value, + let dispatch_call = crate::Call::::eth_transact { + payload, gas_limit: Default::default(), storage_deposit_limit: 0u32.into(), - code: input, - data: Default::default(), - salt: None, + transact_kind: EthTransactKind::InstantiateWithCode { + code_len: tx.transaction_legacy_unsigned.input.0.len() as u32, + data_len: 0, + }, }; + return EthContractResultDetails { kind: EthTransactKind::Call, dispatch_info: dispatch_call.get_dispatch_info(), @@ -1227,13 +1251,11 @@ where CollectEvents::Skip, ); - let dispatch_call = crate::Call::::instantiate_with_code { - value, + let dispatch_call = crate::Call::::eth_transact { + payload, + transact_kind: EthTransactKind::InstantiateWithCode { code_len, data_len }, gas_limit: result.gas_required, storage_deposit_limit: result.storage_deposit.charge_or_zero(), - code, - data, - salt: None, }; let dispatch_call: ::RuntimeCall = dispatch_call.into(); From 179c2e3083b8bb706fde5b9dd7d0a4a188743e28 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 17:20:33 +0200 Subject: [PATCH 040/174] Fix fees --- substrate/bin/node/runtime/src/lib.rs | 2 +- .../frame/revive/src/evm/api/rlp_codec.rs | 39 ++++++++- substrate/frame/revive/src/lib.rs | 85 ++++++++++--------- substrate/frame/revive/src/primitives.rs | 8 +- 4 files changed, 87 insertions(+), 47 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 29b0175b018d..5a231ace440e 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -3057,7 +3057,7 @@ impl_runtime_apis! { let blockweights: BlockWeights = ::BlockWeights::get(); let origin = ::AddressMapper::to_account_id_contract(&from); Revive::bare_eth_transact( - RuntimeOrigin::signed(origin), + origin, dest, value, input, diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs index 6b5c4dc24a3b..d3e350494d7b 100644 --- a/substrate/frame/revive/src/evm/api/rlp_codec.rs +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -20,6 +20,20 @@ use super::*; use rlp::{Decodable, Encodable}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +impl TransactionLegacyUnsigned { + /// Get a rlp encoded bytes of a signed transaction with a dummy 65 bytes signature. + pub fn dummy_signed_payload(&self) -> Vec { + let mut s = rlp::RlpStream::new(); + s.append(self); + const DUMMY_SIGNATURE: [u8; 65] = [0u8; 65]; + s.append_raw(&DUMMY_SIGNATURE.as_ref(), 1); + s.out().to_vec() + } +} + /// See impl Encodable for TransactionLegacyUnsigned { fn rlp_append(&self, s: &mut rlp::RlpStream) { @@ -104,8 +118,9 @@ impl Encodable for TransactionLegacySigned { impl Decodable for TransactionLegacySigned { fn decode(rlp: &rlp::Rlp) -> Result { let v: U256 = rlp.val_at(6)?; - let extract_chain_id = |v: u64| { - if v >= 35 { + + let extract_chain_id = |v: U256| { + if v.ge(&35u32.into()) { Some((v - 35) / 2) } else { None @@ -128,7 +143,7 @@ impl Decodable for TransactionLegacySigned { }, value: rlp.val_at(4)?, input: Bytes(rlp.val_at(5)?), - chain_id: extract_chain_id(v.as_u64()).map(|v| v.into()), + chain_id: extract_chain_id(v).map(|v| v.into()), r#type: Type0 {}, } }, @@ -195,6 +210,24 @@ mod test { assert_eq!(&tx, &decoded); } + #[test] + fn dummy_signed_payload_works() { + let tx = TransactionLegacyUnsigned { + chain_id: Some(596.into()), + gas: U256::from(21000), + nonce: U256::from(1), + gas_price: U256::from("0x640000006a"), + to: Some(Account::from(subxt_signer::eth::dev::baltathar()).address()), + value: U256::from(123123), + input: Bytes(vec![]), + r#type: Type0, + }; + + let signed_tx = Account::default().sign_transaction(tx.clone()); + let rlp_bytes = rlp::encode(&signed_tx); + assert_eq!(tx.dummy_signed_payload().len(), rlp_bytes.len()); + } + #[test] fn recover_address_works() { let account = Account::default(); diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 94d3a5ba55f6..a342f3167a84 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -136,7 +136,7 @@ pub mod pallet { use sp_runtime::Perbill; /// The in-code storage version. - pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); + pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -1148,7 +1148,7 @@ where /// A version of [`Self::eth_transact`] used to dry-run Ethereum calls. pub fn bare_eth_transact( - origin: OriginFor, + origin: T::AccountId, dest: Option, value: BalanceOf, input: Vec, @@ -1160,43 +1160,48 @@ where where ::RuntimeCall: From>, ::RuntimeCall: Encode, + T::Nonce: Into, { - use crate::evm::{TransactionLegacySigned, TransactionLegacyUnsigned}; + use crate::evm::TransactionLegacyUnsigned; + use frame_support::traits::OriginTrait; + let nonce: T::Nonce = >::account_nonce(&origin); if let Some(dest) = dest { - let tx = TransactionLegacySigned { - transaction_legacy_unsigned: TransactionLegacyUnsigned { - value: value.into(), - input: input.into(), - to: Some(dest), - ..Default::default() - }, + let tx = TransactionLegacyUnsigned { + value: value.into(), + input: input.into(), + nonce: nonce.into(), + chain_id: Some(T::ChainId::get().into()), + gas_price: 1u32.into(), + gas: u128::MAX.into(), + to: Some(dest), ..Default::default() }; - let payload = rlp::encode(&tx).to_vec(); + let payload = tx.dummy_signed_payload(); + let result = crate::Pallet::::bare_call( - origin, + T::RuntimeOrigin::signed(origin), dest, value, gas_limit, storage_deposit_limit, - tx.transaction_legacy_unsigned.input.0, + tx.input.0, debug, collect_events, ); - let dispatch_call = crate::Call::::eth_transact { + let transact_kind = EthTransactKind::Call; + let dispatch_call: ::RuntimeCall = crate::Call::::eth_transact { payload, gas_limit: result.gas_required, storage_deposit_limit: result.storage_deposit.charge_or_zero(), - transact_kind: EthTransactKind::Call, - }; - - let dispatch_call: ::RuntimeCall = dispatch_call.into(); + transact_kind, + } + .into(); EthContractResultDetails { - kind: EthTransactKind::Call, + transact_kind, dispatch_info: dispatch_call.get_dispatch_info(), len: dispatch_call.encode().len() as u32, gas_limit: result.gas_required, @@ -1204,31 +1209,33 @@ where result: result.result.map(|v| v.data), } } else { - let tx = TransactionLegacySigned { - transaction_legacy_unsigned: TransactionLegacyUnsigned { - value: value.into(), - input: input.into(), - ..Default::default() - }, + let tx = TransactionLegacyUnsigned { + value: value.into(), + input: input.into(), + nonce: nonce.into(), + chain_id: Some(T::ChainId::get().into()), + gas_price: 1u32.into(), + gas: u128::MAX.into(), ..Default::default() }; - let payload = rlp::encode(&tx).to_vec(); + let payload = tx.dummy_signed_payload(); let Ok(EthInstantiateInput { code, data }) = - EthInstantiateInput::decode(&mut &tx.transaction_legacy_unsigned.input.0[..]) + EthInstantiateInput::decode(&mut &tx.input.0[..]) else { + let transact_kind = EthTransactKind::InstantiateWithCode { + code_len: tx.input.0.len() as u32, + data_len: 0, + }; let dispatch_call = crate::Call::::eth_transact { payload, gas_limit: Default::default(), storage_deposit_limit: 0u32.into(), - transact_kind: EthTransactKind::InstantiateWithCode { - code_len: tx.transaction_legacy_unsigned.input.0.len() as u32, - data_len: 0, - }, + transact_kind, }; return EthContractResultDetails { - kind: EthTransactKind::Call, + transact_kind, dispatch_info: dispatch_call.get_dispatch_info(), gas_limit: Default::default(), storage_deposit: Default::default(), @@ -1240,7 +1247,7 @@ where let code_len = code.len() as u32; let data_len = data.len() as u32; let result = crate::Pallet::::bare_instantiate( - origin, + T::RuntimeOrigin::signed(origin), value, gas_limit, storage_deposit_limit, @@ -1251,17 +1258,17 @@ where CollectEvents::Skip, ); - let dispatch_call = crate::Call::::eth_transact { + let transact_kind = EthTransactKind::InstantiateWithCode { code_len, data_len }; + let dispatch_call: ::RuntimeCall = crate::Call::::eth_transact { payload, - transact_kind: EthTransactKind::InstantiateWithCode { code_len, data_len }, + transact_kind, gas_limit: result.gas_required, storage_deposit_limit: result.storage_deposit.charge_or_zero(), - }; - - let dispatch_call: ::RuntimeCall = dispatch_call.into(); + } + .into(); EthContractResultDetails { - kind: EthTransactKind::InstantiateWithCode { code_len, data_len }, + transact_kind, dispatch_info: dispatch_call.get_dispatch_info(), len: dispatch_call.encode().len() as u32, gas_limit: result.gas_required, diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index 2a971290873e..87d1f86c9395 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -85,7 +85,7 @@ pub struct ContractResult { /// The result of the execution of a `eth_transact` call. pub struct EthContractResultDetails { /// The kind of transaction that was executed. - pub kind: EthTransactKind, + pub transact_kind: EthTransactKind, /// The call's dispatch info. pub dispatch_info: DispatchInfo, /// Length of the encoded call. @@ -110,7 +110,7 @@ impl> EthContractResultDetails { compute_fee: impl FnOnce(u32, &DispatchInfo, Balance) -> Balance, ) -> EthContractResult { EthContractResult { - kind: self.kind, + transact_kind: self.transact_kind, result: self.result, gas_limit: self.gas_limit, storage_deposit: self.storage_deposit, @@ -123,7 +123,7 @@ impl> EthContractResultDetails { #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct EthContractResult { /// The kind of transaction that was executed. - pub kind: EthTransactKind, + pub transact_kind: EthTransactKind, /// The fee charged for the execution. pub fee: Balance, /// Gas limit of the transaction. @@ -166,7 +166,7 @@ impl ExecReturnValue { } /// Describes the type of an [`crate::Call::eth_transact`] call. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum EthTransactKind { /// A Call to an existing contract. Call, From 0ac59c200444fa7ef6b3358fd4c6a7868ac1a7b4 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 17:31:11 +0200 Subject: [PATCH 041/174] why not --- substrate/frame/revive/src/evm/runtime.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 46473446c140..0c3f4795e17d 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -155,9 +155,9 @@ where #[cfg(feature = "try-runtime")] fn unchecked_into_checked_i_know_what_i_am_doing( self, - _: &Lookup, + lookup: &Lookup, ) -> Result { - unreachable!(); + self.0.unchecked_into_checked_i_know_what_i_am_doing(lookup) } } From b9ce758a994a45466e4ae25a759dedaea38117b0 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 17:39:51 +0200 Subject: [PATCH 042/174] restore test as they were --- substrate/frame/revive/src/evm/runtime.rs | 4 ++-- substrate/frame/revive/src/exec.rs | 27 +++-------------------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 0c3f4795e17d..08e92b08561f 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -199,8 +199,8 @@ pub struct CheckEthTransact { /// /// # Note /// - /// This is marked as `#[codec(skip)]` as this extracted from the Ethereum transaction and not - /// encoded as additional signed data. + /// This is marked as `#[codec(skip)]` as this extracted from the Ethereum transaction and + /// should have a zero size encoded representation. #[codec(skip)] eth_fee: Option>, _phantom: core::marker::PhantomData, diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 90d835a6da7b..e0b58c9abf84 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -4226,14 +4226,7 @@ mod tests { // Successful instantiation should set the output let address = ctx .ext - .instantiate( - Weight::zero(), - U256::zero(), - ok_ch, - value, - vec![], - Some(&[0u8; 32]), - ) + .instantiate(Weight::zero(), U256::zero(), ok_ch, value, vec![], None) .unwrap(); assert_eq!( ctx.ext.last_frame_output(), @@ -4249,14 +4242,7 @@ mod tests { // Reverted instantiation should set the output ctx.ext - .instantiate( - Weight::zero(), - U256::zero(), - revert_ch, - value, - vec![], - Some(&[1u8; 32]), - ) + .instantiate(Weight::zero(), U256::zero(), revert_ch, value, vec![], None) .unwrap(); assert_eq!( ctx.ext.last_frame_output(), @@ -4265,14 +4251,7 @@ mod tests { // Trapped instantiation should clear the output ctx.ext - .instantiate( - Weight::zero(), - U256::zero(), - trap_ch, - value, - vec![], - Some(&[2u8; 32]), - ) + .instantiate(Weight::zero(), U256::zero(), trap_ch, value, vec![], None) .unwrap_err(); assert_eq!( ctx.ext.last_frame_output(), From 3783095caeaabb3d937eda686c56424a83891484 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 18:00:51 +0200 Subject: [PATCH 043/174] wip --- Cargo.lock | 20 ++++++++++++++++---- Cargo.toml | 1 + substrate/frame/revive/Cargo.toml | 11 ++++++----- substrate/frame/revive/fixtures/Cargo.toml | 9 +-------- substrate/frame/revive/src/evm/api.rs | 9 +++++++++ substrate/frame/revive/src/evm/runtime.rs | 18 ++++++++++-------- substrate/frame/revive/src/lib.rs | 3 ++- substrate/frame/revive/src/primitives.rs | 9 --------- 8 files changed, 45 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2995c2035920..dbb19e85d231 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12400,6 +12400,7 @@ dependencies = [ "polkavm 0.11.0", "pretty_assertions", "rlp", + "rlp-derive", "scale-info", "secp256k1", "serde", @@ -16850,7 +16851,7 @@ checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.11.0", + "itertools 0.12.1", "log", "multimap", "once_cell", @@ -16871,7 +16872,7 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.11.0", + "itertools 0.12.1", "log", "multimap", "once_cell", @@ -16904,7 +16905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2 1.0.86", "quote 1.0.37", "syn 2.0.79", @@ -16917,7 +16918,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2 1.0.86", "quote 1.0.37", "syn 2.0.79", @@ -17730,6 +17731,17 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rlp-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "652db34deaaa57929e10ca18e5454a32cb0efc351ae80d320334bbf907b908b3" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.79", +] + [[package]] name = "rocksdb" version = "0.21.0" diff --git a/Cargo.toml b/Cargo.toml index df662ac26988..f1b9bc5ac588 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1104,6 +1104,7 @@ relay-utils = { path = "bridges/relays/utils" } remote-externalities = { path = "substrate/utils/frame/remote-externalities", default-features = false, package = "frame-remote-externalities" } reqwest = { version = "0.11", default-features = false } rlp = { version = "0.5.2", default-features = false } +rlp-derive = { version = "0.2.0", default-features = false } rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/relays/rococo" } rococo-parachain-runtime = { path = "cumulus/parachains/runtimes/testing/rococo-parachain" } rococo-runtime = { path = "polkadot/runtime/rococo" } diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 19276b1cc6e0..6a2cd54625f8 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -21,15 +21,16 @@ environmental = { workspace = true } paste = { workspace = true } polkavm = { version = "0.11.0", default-features = false } bitflags = { workspace = true } -codec = { features = [ - "derive", - "max-encoded-len", -], workspace = true } +codec = { features = ["derive", "max-encoded-len"], workspace = true } scale-info = { features = ["derive"], workspace = true } log = { workspace = true } -serde = { features = ["alloc", "derive"], workspace = true, default-features = false } +serde = { features = [ + "alloc", + "derive", +], workspace = true, default-features = false } impl-trait-for-tuples = { workspace = true } rlp = { workspace = true } +rlp-derive = { workspace = true } derive_more.workspace = true hex = { workspace = true } jsonrpsee = { workspace = true, features = ["full"], optional = true } diff --git a/substrate/frame/revive/fixtures/Cargo.toml b/substrate/frame/revive/fixtures/Cargo.toml index 53db08a3911a..9ff5c38fa64b 100644 --- a/substrate/frame/revive/fixtures/Cargo.toml +++ b/substrate/frame/revive/fixtures/Cargo.toml @@ -32,11 +32,4 @@ default = ["std"] # we will remove this once there is an upstream toolchain riscv = [] # only when std is enabled all fixtures are available -std = [ - "anyhow", - "frame-system", - "log/std", - "sp-core", - "sp-io", - "sp-runtime", -] +std = ["anyhow", "frame-system", "log/std", "sp-core", "sp-io", "sp-runtime"] diff --git a/substrate/frame/revive/src/evm/api.rs b/substrate/frame/revive/src/evm/api.rs index 18cbb9473361..7ec4a997b440 100644 --- a/substrate/frame/revive/src/evm/api.rs +++ b/substrate/frame/revive/src/evm/api.rs @@ -29,4 +29,13 @@ mod rpc_types; mod rpc_types_gen; pub use rpc_types_gen::*; +/// A type used to encode the `input` field of an Ethereum transaction +#[derive(Clone, rlp_derive::RlpEncodable, rlp_derive::RlpDecodable)] +pub struct EthInstantiateInput { + /// The bytecode of the contract. + pub code: Vec, + /// The data to pass to the constructor. + pub data: Vec, +} + mod signature; diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 08e92b08561f..d743ba0f0eb1 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -17,9 +17,11 @@ //! Runtime types for integrating `pallet-revive` with the EVM. #![allow(unused_imports, unused_variables)] use crate::{ - evm::api::{TransactionLegacySigned, TransactionLegacyUnsigned, TransactionUnsigned}, - AccountIdOf, AddressMapper, BalanceOf, Config, EthInstantiateInput, EthTransactKind, MomentOf, - Weight, LOG_TARGET, + evm::{ + api::{TransactionLegacySigned, TransactionLegacyUnsigned, TransactionUnsigned}, + EthInstantiateInput, + }, + AccountIdOf, AddressMapper, BalanceOf, Config, EthTransactKind, MomentOf, Weight, LOG_TARGET, }; use codec::{Decode, Encode}; use core::marker::PhantomData; @@ -337,11 +339,11 @@ pub trait EthExtra { return Err(InvalidTransaction::Call); }; - let EthInstantiateInput { code, data } = EthInstantiateInput::decode(&mut &input.0[..]) + let EthInstantiateInput { code, data } = rlp::decode::(&input.0) .map_err(|_| { - log::debug!(target: LOG_TARGET, "Failed to decoded eth_transact input"); - InvalidTransaction::Call - })?; + log::debug!(target: LOG_TARGET, "Failed to decoded eth_transact input"); + InvalidTransaction::Call + })?; if code.len() as u32 != code_len || data.len() as u32 != data_len { log::debug!(target: LOG_TARGET, "Invalid code or data length"); @@ -484,7 +486,7 @@ mod test { code_len: code.len() as u32, data_len: data.len() as u32, }; - builder.tx.input = Bytes(EthInstantiateInput { code, data }.encode()); + builder.tx.input = Bytes(rlp::encode(&EthInstantiateInput { code, data })); builder } diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index a342f3167a84..b8b0586232b1 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -47,6 +47,7 @@ pub mod weights; #[cfg(test)] mod tests; use crate::{ + evm::EthInstantiateInput, exec::{AccountIdOf, ExecError, Executable, Ext, Key, Origin, Stack as ExecStack}, gas::GasMeter, storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager}, @@ -1221,7 +1222,7 @@ where let payload = tx.dummy_signed_payload(); let Ok(EthInstantiateInput { code, data }) = - EthInstantiateInput::decode(&mut &tx.input.0[..]) + rlp::decode::(&tx.input.0) else { let transact_kind = EthTransactKind::InstantiateWithCode { code_len: tx.input.0.len() as u32, diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index 87d1f86c9395..b898717608d7 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -206,15 +206,6 @@ pub enum Code { Existing(sp_core::H256), } -/// A type used to encode the `input` field of an Ethereum transaction -#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct EthInstantiateInput { - /// The bytecode of the contract. - pub code: Vec, - /// The data to pass to the constructor. - pub data: Vec, -} - /// The amount of balance that was either charged or refunded in order to pay for storage. #[derive( Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, RuntimeDebug, TypeInfo, From ab8d7dbb97b8ec2845e447484918dfa0057132d4 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 18:11:54 +0200 Subject: [PATCH 044/174] fix comp issue --- substrate/frame/revive/src/evm/api.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/substrate/frame/revive/src/evm/api.rs b/substrate/frame/revive/src/evm/api.rs index 7ec4a997b440..d0a864e12381 100644 --- a/substrate/frame/revive/src/evm/api.rs +++ b/substrate/frame/revive/src/evm/api.rs @@ -29,6 +29,9 @@ mod rpc_types; mod rpc_types_gen; pub use rpc_types_gen::*; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// A type used to encode the `input` field of an Ethereum transaction #[derive(Clone, rlp_derive::RlpEncodable, rlp_derive::RlpDecodable)] pub struct EthInstantiateInput { From 741c3667bab778226feda060d39d7a767cabbfcd Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 18:44:31 +0200 Subject: [PATCH 045/174] fix --- substrate/frame/revive/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index b8b0586232b1..0069ed949c22 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -28,6 +28,7 @@ mod benchmarking_dummy; mod exec; mod gas; mod primitives; +use crate::evm::EthInstantiateInput; pub use crate::exec::MomentOf; use frame_support::traits::IsType; pub use primitives::*; @@ -47,7 +48,6 @@ pub mod weights; #[cfg(test)] mod tests; use crate::{ - evm::EthInstantiateInput, exec::{AccountIdOf, ExecError, Executable, Ext, Key, Origin, Stack as ExecStack}, gas::GasMeter, storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager}, @@ -1220,7 +1220,6 @@ where ..Default::default() }; let payload = tx.dummy_signed_payload(); - let Ok(EthInstantiateInput { code, data }) = rlp::decode::(&tx.input.0) else { From b8840e77180ec7232b42ad39aab489a2b5937233 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 21:28:02 +0200 Subject: [PATCH 046/174] fix test --- substrate/frame/revive/src/evm/runtime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index d743ba0f0eb1..3dd6a85c7b79 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -486,7 +486,7 @@ mod test { code_len: code.len() as u32, data_len: data.len() as u32, }; - builder.tx.input = Bytes(rlp::encode(&EthInstantiateInput { code, data })); + builder.tx.input = Bytes(rlp::encode(&EthInstantiateInput { code, data }).to_vec()); builder } From 4b853682143c359577b150319b87f0113b70682b Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 9 Oct 2024 12:47:20 +0200 Subject: [PATCH 047/174] fix rlp encoding --- Cargo.lock | 12 --------- Cargo.toml | 1 - substrate/frame/revive/Cargo.toml | 1 - substrate/frame/revive/src/evm/api.rs | 27 +++++++++++++++++-- substrate/frame/revive/src/evm/api/byte.rs | 1 + .../frame/revive/src/evm/api/rpc_types_gen.rs | 2 +- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbb19e85d231..33b74fe74c02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12400,7 +12400,6 @@ dependencies = [ "polkavm 0.11.0", "pretty_assertions", "rlp", - "rlp-derive", "scale-info", "secp256k1", "serde", @@ -17731,17 +17730,6 @@ dependencies = [ "rustc-hex", ] -[[package]] -name = "rlp-derive" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "652db34deaaa57929e10ca18e5454a32cb0efc351ae80d320334bbf907b908b3" -dependencies = [ - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 2.0.79", -] - [[package]] name = "rocksdb" version = "0.21.0" diff --git a/Cargo.toml b/Cargo.toml index f1b9bc5ac588..df662ac26988 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1104,7 +1104,6 @@ relay-utils = { path = "bridges/relays/utils" } remote-externalities = { path = "substrate/utils/frame/remote-externalities", default-features = false, package = "frame-remote-externalities" } reqwest = { version = "0.11", default-features = false } rlp = { version = "0.5.2", default-features = false } -rlp-derive = { version = "0.2.0", default-features = false } rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/relays/rococo" } rococo-parachain-runtime = { path = "cumulus/parachains/runtimes/testing/rococo-parachain" } rococo-runtime = { path = "polkadot/runtime/rococo" } diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 6a2cd54625f8..39cd1162f4b1 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -30,7 +30,6 @@ serde = { features = [ ], workspace = true, default-features = false } impl-trait-for-tuples = { workspace = true } rlp = { workspace = true } -rlp-derive = { workspace = true } derive_more.workspace = true hex = { workspace = true } jsonrpsee = { workspace = true, features = ["full"], optional = true } diff --git a/substrate/frame/revive/src/evm/api.rs b/substrate/frame/revive/src/evm/api.rs index d0a864e12381..14b9695c9474 100644 --- a/substrate/frame/revive/src/evm/api.rs +++ b/substrate/frame/revive/src/evm/api.rs @@ -32,8 +32,10 @@ pub use rpc_types_gen::*; #[cfg(not(feature = "std"))] use alloc::vec::Vec; +mod signature; + /// A type used to encode the `input` field of an Ethereum transaction -#[derive(Clone, rlp_derive::RlpEncodable, rlp_derive::RlpDecodable)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct EthInstantiateInput { /// The bytecode of the contract. pub code: Vec, @@ -41,4 +43,25 @@ pub struct EthInstantiateInput { pub data: Vec, } -mod signature; +impl rlp::Encodable for EthInstantiateInput { + fn rlp_append(&self, stream: &mut rlp::RlpStream) { + stream.begin_list(2usize); + stream.append(&self.code); + stream.append(&self.data); + } +} + +impl rlp::Decodable for EthInstantiateInput { + fn decode(rlp: &rlp::Rlp) -> Result { + let result = EthInstantiateInput { code: rlp.val_at(0)?, data: rlp.val_at(1)? }; + Ok(result) + } +} + +#[test] +fn eth_instantiate_rlp_codec_works() { + let input = EthInstantiateInput { code: vec![1, 2, 3], data: vec![4, 5, 6] }; + let encoded = rlp::encode(&input); + let decoded = rlp::decode::(&encoded).unwrap(); + assert_eq!(input, decoded); +} diff --git a/substrate/frame/revive/src/evm/api/byte.rs b/substrate/frame/revive/src/evm/api/byte.rs index 13d29eaf74cf..d33c21619a76 100644 --- a/substrate/frame/revive/src/evm/api/byte.rs +++ b/substrate/frame/revive/src/evm/api/byte.rs @@ -136,6 +136,7 @@ macro_rules! impl_hex { impl_hex!(Byte, u8, 0u8); impl_hex!(Bytes, Vec, vec![]); +impl_hex!(Bytes8, [u8; 8], [0u8; 8]); impl_hex!(Bytes256, [u8; 256], [0u8; 256]); #[test] 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 ea29c47d792b..9a706eb28357 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs @@ -64,7 +64,7 @@ pub struct Block { #[serde(rename = "mixHash")] pub mix_hash: H256, /// Nonce - pub nonce: String, + pub nonce: Bytes8, /// Number pub number: U256, /// Parent Beacon Block Root From 3739e452249a501782ef323ee013fc2910e9f26c Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 10 Oct 2024 11:33:35 +0200 Subject: [PATCH 048/174] wip --- substrate/frame/revive/Cargo.toml | 3 +- substrate/frame/revive/src/evm/api.rs | 13 +++++-- substrate/frame/revive/src/evm/api/account.rs | 35 +++++++++++++++++++ .../frame/revive/src/evm/api/rlp_codec.rs | 29 --------------- substrate/frame/revive/src/evm/api/type_id.rs | 9 +++++ substrate/frame/revive/src/evm/runtime.rs | 6 ++++ 6 files changed, 62 insertions(+), 33 deletions(-) create mode 100644 substrate/frame/revive/src/evm/api/account.rs diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 39cd1162f4b1..d557a96b284e 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -53,6 +53,7 @@ sp-std = { workspace = true } sp-weights = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } +subxt-signer = { workspace = true, optional = true, features = ["unstable-eth"] } [dev-dependencies] array-bytes = { workspace = true, default-features = true } @@ -62,7 +63,6 @@ pallet-revive-fixtures = { workspace = true, default-features = true } secp256k1 = { workspace = true, features = ["recovery"] } serde_json.workspace = true hex-literal.workspace = true -subxt-signer = { workspace = true, features = ["unstable-eth"] } # Polkadot SDK Dependencies pallet-balances = { workspace = true, default-features = true } @@ -82,6 +82,7 @@ default = ["std"] # apart from this the pallet will stay functional riscv = ["pallet-revive-fixtures/riscv"] std = [ + "subxt-signer", "codec/std", "environmental/std", "ethereum-types/std", diff --git a/substrate/frame/revive/src/evm/api.rs b/substrate/frame/revive/src/evm/api.rs index 14b9695c9474..6712726e40de 100644 --- a/substrate/frame/revive/src/evm/api.rs +++ b/substrate/frame/revive/src/evm/api.rs @@ -32,7 +32,14 @@ pub use rpc_types_gen::*; #[cfg(not(feature = "std"))] use alloc::vec::Vec; +#[cfg(feature = "std")] +mod account; + +#[cfg(feature = "std")] +pub use account::*; + mod signature; +use rlp::{Decodable, DecoderError, Encodable}; /// A type used to encode the `input` field of an Ethereum transaction #[derive(Debug, Clone, PartialEq, Eq)] @@ -43,7 +50,7 @@ pub struct EthInstantiateInput { pub data: Vec, } -impl rlp::Encodable for EthInstantiateInput { +impl Encodable for EthInstantiateInput { fn rlp_append(&self, stream: &mut rlp::RlpStream) { stream.begin_list(2usize); stream.append(&self.code); @@ -51,8 +58,8 @@ impl rlp::Encodable for EthInstantiateInput { } } -impl rlp::Decodable for EthInstantiateInput { - fn decode(rlp: &rlp::Rlp) -> Result { +impl Decodable for EthInstantiateInput { + fn decode(rlp: &rlp::Rlp) -> Result { let result = EthInstantiateInput { code: rlp.val_at(0)?, data: rlp.val_at(1)? }; Ok(result) } diff --git a/substrate/frame/revive/src/evm/api/account.rs b/substrate/frame/revive/src/evm/api/account.rs new file mode 100644 index 000000000000..a4a24eb45c48 --- /dev/null +++ b/substrate/frame/revive/src/evm/api/account.rs @@ -0,0 +1,35 @@ +//! Utilities for working with Ethereum accounts. +use crate::{ + evm::{TransactionLegacySigned, TransactionLegacyUnsigned}, + H160, +}; +use rlp::Encodable; + +/// A simple account that can sign transactions +pub struct Account(subxt_signer::eth::Keypair); + +impl Default for Account { + fn default() -> Self { + Self(subxt_signer::eth::dev::alith()) + } +} + +impl From for Account { + fn from(kp: subxt_signer::eth::Keypair) -> Self { + Self(kp) + } +} + +impl Account { + /// Get the [`H160`] address of the account. + pub fn address(&self) -> H160 { + H160::from_slice(&self.0.account_id().as_ref()) + } + + /// Sign a transaction. + pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { + let rlp_encoded = tx.rlp_bytes(); + let signature = self.0.sign(&rlp_encoded); + TransactionLegacySigned::from(tx, signature.as_ref()) + } +} diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs index d3e350494d7b..4d1302c39134 100644 --- a/substrate/frame/revive/src/evm/api/rlp_codec.rs +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -158,35 +158,6 @@ impl Decodable for TransactionLegacySigned { mod test { use super::*; - /// A simple account that can sign transactions - pub struct Account(subxt_signer::eth::Keypair); - - impl Default for Account { - fn default() -> Self { - Self(subxt_signer::eth::dev::alith()) - } - } - - impl From for Account { - fn from(kp: subxt_signer::eth::Keypair) -> Self { - Self(kp) - } - } - - impl Account { - /// Get the [`H160`] address of the account. - pub fn address(&self) -> H160 { - H160::from_slice(&self.0.account_id().as_ref()) - } - - /// Sign a transaction. - pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { - let rlp_encoded = tx.rlp_bytes(); - let signature = self.0.sign(&rlp_encoded); - TransactionLegacySigned::from(tx, signature.as_ref()) - } - } - #[test] fn encode_decode_legacy_transaction_works() { let tx = TransactionLegacyUnsigned { diff --git a/substrate/frame/revive/src/evm/api/type_id.rs b/substrate/frame/revive/src/evm/api/type_id.rs index 72fea1e1761d..7d75d53500b6 100644 --- a/substrate/frame/revive/src/evm/api/type_id.rs +++ b/substrate/frame/revive/src/evm/api/type_id.rs @@ -33,6 +33,15 @@ macro_rules! transaction_type { pub fn as_byte(&self) -> Byte { Byte::from($value) } + + /// Try to convert from Byte + pub fn try_from_byte(byte: Byte) -> Result { + if byte.0 == $value { + Ok(Self {}) + } else { + Err(byte) + } + } } impl Encode for $name { diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 3dd6a85c7b79..5c02b66158e9 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -396,6 +396,12 @@ mod test { } } + impl From for Account { + fn from(kp: subxt_signer::eth::Keypair) -> Self { + Self(kp) + } + } + impl Account { /// Get the [`AccountId`] of the account. pub fn account_id(&self) -> AccountId { From 46166f8f4c01fa4604c5aca79f683c1f0421f9fe Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 10 Oct 2024 11:49:28 +0200 Subject: [PATCH 049/174] PR review --- prdoc/pr_5866.prdoc | 2 ++ substrate/bin/node/runtime/src/lib.rs | 8 ++++---- substrate/frame/revive/Cargo.toml | 12 +++++++----- substrate/frame/revive/src/evm/runtime.rs | 9 ++++----- substrate/frame/revive/src/lib.rs | 4 ++-- substrate/frame/revive/src/tests.rs | 7 ++++--- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/prdoc/pr_5866.prdoc b/prdoc/pr_5866.prdoc index 86953089eb39..a12d5c0ce0c7 100644 --- a/prdoc/pr_5866.prdoc +++ b/prdoc/pr_5866.prdoc @@ -12,6 +12,8 @@ doc: crates: - name: pallet-revive bump: major + - name: pallet-revive-fixtures + bump: major - name: polkadot-sdk bump: patch diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 5a231ace440e..e9084af92566 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2534,16 +2534,16 @@ mod runtime { pub type Revive = pallet_revive::Pallet; } -impl TryInto> for RuntimeCall { +impl TryFrom for pallet_revive::Call { type Error = (); - fn try_into(self) -> Result, Self::Error> { - match self { + + fn try_from(value: RuntimeCall) -> Result { + match value { RuntimeCall::Revive(call) => Ok(call), _ => Err(()), } } } - /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; /// Block header type as expected by this runtime. diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index d557a96b284e..2a27e5c32bb3 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -30,7 +30,7 @@ serde = { features = [ ], workspace = true, default-features = false } impl-trait-for-tuples = { workspace = true } rlp = { workspace = true } -derive_more.workspace = true +derive_more = { workspace = true } hex = { workspace = true } jsonrpsee = { workspace = true, features = ["full"], optional = true } ethereum-types = { workspace = true, features = ["codec", "rlp", "serialize"] } @@ -53,7 +53,9 @@ sp-std = { workspace = true } sp-weights = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } -subxt-signer = { workspace = true, optional = true, features = ["unstable-eth"] } +subxt-signer = { workspace = true, optional = true, features = [ + "unstable-eth", +] } [dev-dependencies] array-bytes = { workspace = true, default-features = true } @@ -61,8 +63,8 @@ assert_matches = { workspace = true } pretty_assertions = { workspace = true } pallet-revive-fixtures = { workspace = true, default-features = true } secp256k1 = { workspace = true, features = ["recovery"] } -serde_json.workspace = true -hex-literal.workspace = true +serde_json = { workspace = true } +hex-literal = { workspace = true } # Polkadot SDK Dependencies pallet-balances = { workspace = true, default-features = true } @@ -82,7 +84,6 @@ default = ["std"] # apart from this the pallet will stay functional riscv = ["pallet-revive-fixtures/riscv"] std = [ - "subxt-signer", "codec/std", "environmental/std", "ethereum-types/std", @@ -112,6 +113,7 @@ std = [ "sp-runtime/std", "sp-std/std", "sp-weights/std", + "subxt-signer", "xcm-builder/std", "xcm/std", ] diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 5c02b66158e9..3e9ac2ee4361 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -77,12 +77,11 @@ impl } } -impl - Into> - for UncheckedExtrinsic +impl From> + for generic::UncheckedExtrinsic { - fn into(self) -> generic::UncheckedExtrinsic { - self.0 + fn from(extrinsic: UncheckedExtrinsic) -> Self { + extrinsic.0 } } diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 0069ed949c22..96b6210f444d 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -34,7 +34,6 @@ use frame_support::traits::IsType; pub use primitives::*; use sp_core::U256; -pub mod evm; mod limits; mod storage; mod transient_storage; @@ -42,6 +41,7 @@ mod wasm; pub mod chain_extension; pub mod debug; +pub mod evm; pub mod test_utils; pub mod weights; @@ -91,7 +91,7 @@ pub use weights::WeightInfo; pub use crate::wasm::SyscallDoc; type TrieId = BoundedVec>; -pub type BalanceOf = +type BalanceOf = <::Currency as Inspect<::AccountId>>::Balance; type CodeVec = BoundedVec>; type EventRecordOf = diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 13af6ea51f1d..e4a3ff8ad002 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -523,10 +523,11 @@ impl Config for Test { type ChainId = ChainId; } -impl TryInto> for RuntimeCall { +impl TryFrom for crate::Call { type Error = (); - fn try_into(self) -> Result, Self::Error> { - match self { + + fn try_from(value: RuntimeCall) -> Result { + match value { RuntimeCall::Contracts(call) => Ok(call), _ => Err(()), } From 2e12a9da9ae02588b3ec77ed305bde5a339e1b4d Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 10 Oct 2024 12:07:05 +0200 Subject: [PATCH 050/174] reorg use / mod --- substrate/frame/revive/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 96b6210f444d..358fd0827c43 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -27,14 +27,8 @@ mod benchmarking; mod benchmarking_dummy; mod exec; mod gas; -mod primitives; -use crate::evm::EthInstantiateInput; -pub use crate::exec::MomentOf; -use frame_support::traits::IsType; -pub use primitives::*; -use sp_core::U256; - mod limits; +mod primitives; mod storage; mod transient_storage; mod wasm; @@ -45,6 +39,12 @@ pub mod evm; pub mod test_utils; pub mod weights; +use crate::evm::EthInstantiateInput; +pub use crate::exec::MomentOf; +use frame_support::traits::IsType; +pub use primitives::*; +use sp_core::U256; + #[cfg(test)] mod tests; use crate::{ From 5100f67edf89beaf0d6aecfc64c02bdfa5e5df8b Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 10 Oct 2024 12:18:35 +0200 Subject: [PATCH 051/174] merge fixes --- Cargo.lock | 2 +- .../frame/revive/src/evm/api/signature.rs | 4 ++-- substrate/frame/revive/src/wasm/runtime.rs | 21 +++++++------------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f8802e8d3b0..93e98a329e76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8446,7 +8446,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" dependencies = [ - "primitive-types", + "primitive-types 0.12.2", "tiny-keccak", ] diff --git a/substrate/frame/revive/src/evm/api/signature.rs b/substrate/frame/revive/src/evm/api/signature.rs index 0eb896a08c42..957d50c8e324 100644 --- a/substrate/frame/revive/src/evm/api/signature.rs +++ b/substrate/frame/revive/src/evm/api/signature.rs @@ -52,8 +52,8 @@ impl TransactionLegacySigned { /// Get the raw 65 bytes signature from the signed transaction. pub fn raw_signature(&self) -> Result<[u8; 65], ()> { let mut s = [0u8; 65]; - self.r.to_big_endian(s[0..32].as_mut()); - self.s.to_big_endian(s[32..64].as_mut()); + self.r.write_as_big_endian(s[0..32].as_mut()); + self.s.write_as_big_endian(s[32..64].as_mut()); s[64] = self.extract_recovery_id().ok_or(())?; Ok(s) } diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 245c91278a7f..2c094e89d881 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -44,11 +44,6 @@ type CallOf = ::RuntimeCall; /// The maximum nesting depth a contract can use when encoding types. const MAX_DECODE_NESTING: u32 = 256; -/// Encode a `U256` into a 32 byte buffer. -fn as_bytes(u: U256) -> [u8; 32] { - u.to_little_endian() -} - #[derive(Clone, Copy)] pub enum ApiVersion { /// Expose all APIs even unversioned ones. Only used for testing and benchmarking. @@ -1555,7 +1550,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.balance()), + &self.ext.balance().to_little_endian(), false, already_charged, )?) @@ -1576,7 +1571,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.balance_of(&address)), + &self.ext.balance_of(&address).to_little_endian(), false, already_charged, )?) @@ -1589,7 +1584,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(U256::from(::ChainId::get())), + &U256::from(::ChainId::get()).to_little_endian(), false, |_| Some(RuntimeCosts::CopyToContract(32)), )?) @@ -1603,7 +1598,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.value_transferred()), + &self.ext.value_transferred().to_little_endian(), false, already_charged, )?) @@ -1617,7 +1612,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.now()), + &self.ext.now().to_little_endian(), false, already_charged, )?) @@ -1631,7 +1626,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.minimum_balance()), + &self.ext.minimum_balance().to_little_endian(), false, already_charged, )?) @@ -1685,7 +1680,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.block_number()), + &self.ext.block_number().to_little_endian(), false, already_charged, )?) @@ -2043,7 +2038,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(U256::from(self.ext.last_frame_output().data.len())), + &U256::from(self.ext.last_frame_output().data.len()).to_little_endian(), false, |len| Some(RuntimeCosts::CopyToContract(len)), )?) From b44294f3ea201bd88b924787e0943e85aaa874cb Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 10 Oct 2024 12:21:25 +0200 Subject: [PATCH 052/174] fix license --- substrate/frame/revive/src/evm/api/account.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/substrate/frame/revive/src/evm/api/account.rs b/substrate/frame/revive/src/evm/api/account.rs index a4a24eb45c48..c2217defc31f 100644 --- a/substrate/frame/revive/src/evm/api/account.rs +++ b/substrate/frame/revive/src/evm/api/account.rs @@ -1,3 +1,19 @@ +// 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. //! Utilities for working with Ethereum accounts. use crate::{ evm::{TransactionLegacySigned, TransactionLegacyUnsigned}, From 75ca3f94c19496aab6ea2cfea0cf01039e615b91 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 15:14:50 +0200 Subject: [PATCH 053/174] Add pallet-revive Ethereum JSON-RPC Depends on #5866 --- Cargo.lock | 152 +++- Cargo.toml | 2 + substrate/frame/revive/rpc/Cargo.toml | 67 ++ substrate/frame/revive/rpc/Makefile | 30 + substrate/frame/revive/rpc/examples/deploy.rs | 58 ++ .../frame/revive/rpc/examples/dummy.polkavm | Bin 0 -> 142 bytes .../frame/revive/rpc/examples/extrinsic.rs | 48 ++ .../revive/rpc/examples/rpc-playground.rs | 29 + .../frame/revive/rpc/examples/transfer.rs | 31 + substrate/frame/revive/rpc/kitchensink.scale | Bin 0 -> 651254 bytes substrate/frame/revive/rpc/metadata.scale | Bin 0 -> 57102 bytes substrate/frame/revive/rpc/src/client.rs | 741 ++++++++++++++++++ substrate/frame/revive/rpc/src/example.rs | 114 +++ substrate/frame/revive/rpc/src/lib.rs | 305 +++++++ substrate/frame/revive/rpc/src/main.rs | 128 +++ .../frame/revive/rpc/src/rpc_methods_gen.rs | 152 ++++ .../frame/revive/rpc/src/subxt_client.rs | 45 ++ 17 files changed, 1901 insertions(+), 1 deletion(-) create mode 100644 substrate/frame/revive/rpc/Cargo.toml create mode 100644 substrate/frame/revive/rpc/Makefile create mode 100644 substrate/frame/revive/rpc/examples/deploy.rs create mode 100644 substrate/frame/revive/rpc/examples/dummy.polkavm create mode 100644 substrate/frame/revive/rpc/examples/extrinsic.rs create mode 100644 substrate/frame/revive/rpc/examples/rpc-playground.rs create mode 100644 substrate/frame/revive/rpc/examples/transfer.rs create mode 100644 substrate/frame/revive/rpc/kitchensink.scale create mode 100644 substrate/frame/revive/rpc/metadata.scale create mode 100644 substrate/frame/revive/rpc/src/client.rs create mode 100644 substrate/frame/revive/rpc/src/example.rs create mode 100644 substrate/frame/revive/rpc/src/lib.rs create mode 100644 substrate/frame/revive/rpc/src/main.rs create mode 100644 substrate/frame/revive/rpc/src/rpc_methods_gen.rs create mode 100644 substrate/frame/revive/rpc/src/subxt_client.rs diff --git a/Cargo.lock b/Cargo.lock index 93e98a329e76..bb89ecdfff11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,6 +119,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "allocator-api2" version = "0.2.16" @@ -1145,6 +1160,22 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-compression" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd 0.13.0", + "zstd-safe 7.0.0", +] + [[package]] name = "async-executor" version = "1.5.1" @@ -2574,6 +2605,27 @@ dependencies = [ "tuplex", ] +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bs58" version = "0.5.1" @@ -7406,6 +7458,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +[[package]] +name = "http-range-header" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" + [[package]] name = "httparse" version = "1.8.0" @@ -7885,6 +7943,16 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "iri-string" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bd7eced44cfe2cebc674adb2a7124a754a4b5269288d22e9f39f8fada3562d" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -9667,6 +9735,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -12441,6 +12519,36 @@ dependencies = [ "subxt-signer", ] +[[package]] +name = "pallet-revive-eth-rpc" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap 4.5.13", + "env_logger 0.11.3", + "futures", + "hex", + "hex-literal", + "hyper 1.3.1", + "jsonrpsee 0.24.3", + "log", + "pallet-revive", + "parity-scale-codec", + "scale-info", + "secp256k1", + "serde_json", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", + "subxt", + "subxt-signer", + "thiserror", + "tokio", + "tower", + "tower-http 0.5.2", + "tracing-subscriber 0.3.18", +] + [[package]] name = "pallet-revive-fixtures" version = "0.1.0" @@ -25156,7 +25264,7 @@ dependencies = [ "futures-util", "http 0.2.9", "http-body 0.4.5", - "http-range-header", + "http-range-header 0.3.1", "mime", "pin-project-lite", "tower-layer", @@ -25170,14 +25278,29 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ + "async-compression", + "base64 0.21.7", "bitflags 2.6.0", "bytes", + "futures-core", + "futures-util", "http 1.1.0", "http-body 1.0.0", "http-body-util", + "http-range-header 0.4.1", + "httpdate", + "iri-string", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", + "tokio", + "tokio-util", + "tower", "tower-layer", "tower-service", + "tracing", + "uuid", ] [[package]] @@ -25594,6 +25717,15 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -27433,6 +27565,15 @@ dependencies = [ "zstd-safe 6.0.6", ] +[[package]] +name = "zstd" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +dependencies = [ + "zstd-safe 7.0.0", +] + [[package]] name = "zstd-safe" version = "5.0.2+zstd.1.5.2" @@ -27453,6 +27594,15 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.8+zstd.1.5.5" diff --git a/Cargo.toml b/Cargo.toml index fde05e90ca6e..d265f1a586f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -399,6 +399,7 @@ members = [ "substrate/frame/revive/fixtures", "substrate/frame/revive/mock-network", "substrate/frame/revive/proc-macro", + "substrate/frame/revive/rpc", "substrate/frame/revive/uapi", "substrate/frame/root-offences", "substrate/frame/root-testing", @@ -958,6 +959,7 @@ pallet-recovery = { path = "substrate/frame/recovery", default-features = false pallet-referenda = { path = "substrate/frame/referenda", default-features = false } pallet-remark = { default-features = false, path = "substrate/frame/remark" } pallet-revive = { path = "substrate/frame/revive", default-features = false } +pallet-revive-eth-rpc = { path = "substrate/frame/revive/rpc", default-features = false } pallet-revive-fixtures = { path = "substrate/frame/revive/fixtures", default-features = false } pallet-revive-mock-network = { default-features = false, path = "substrate/frame/revive/mock-network" } pallet-revive-proc-macro = { path = "substrate/frame/revive/proc-macro", default-features = false } diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml new file mode 100644 index 000000000000..dbb84af54446 --- /dev/null +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -0,0 +1,67 @@ +[package] +name = "pallet-revive-eth-rpc" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true +description = "An Ethereum JSON-RPC server for pallet-revive." + +[[bin]] +name = "eth-rpc" +path = "src/main.rs" + +[[example]] +name = "deploy" +path = "examples/deploy.rs" +required-features = ["example"] + +[[example]] +name = "transfer" +path = "examples/transfer.rs" +required-features = ["example"] + +[[example]] +name = "rpc-playground" +path = "examples/rpc-playground.rs" +required-features = ["example"] + +[[example]] +name = "extrinsic" +path = "examples/extrinsic.rs" +required-features = ["example"] + +[dependencies] +clap = { workspace = true, features = ["derive"] } +anyhow.workspace = true +futures = { workspace = true, features = ["thread-pool"] } +jsonrpsee = { workspace = true, features = ["full"] } +serde_json.workspace = true +thiserror.workspace = true +subxt = { workspace = true, default-features = true, features = ["unstable-reconnecting-rpc-client"] } +tokio = { workspace = true, features = ["full"] } +codec = { workspace = true, features = ["derive"] } +log.workspace = true +tracing-subscriber.workspace = true +pallet-revive = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-weights = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } + +tower.workspace = true +tower-http = { workspace = true, features = ["full"] } +hyper.workspace = true +subxt-signer = { workspace = true, optional = true } +hex = { workspace = true, optional = true } +hex-literal = { workspace = true, optional = true } +scale-info = { workspace = true } +secp256k1 = { workspace = true, optional = true, features = ["recovery"] } +env_logger = { workspace = true } + +[features] +dev = [] +example = ["hex", "hex-literal", "secp256k1", "subxt-signer"] + +[dev-dependencies] +hex-literal.workspace = true diff --git a/substrate/frame/revive/rpc/Makefile b/substrate/frame/revive/rpc/Makefile new file mode 100644 index 000000000000..64db1396a46c --- /dev/null +++ b/substrate/frame/revive/rpc/Makefile @@ -0,0 +1,30 @@ +.PHONY: node +node: + RUST_LOG="error,evm=debug,sc_rpc_server=info,runtime::revive=debug" cargo run -p node -- --dev --consensus instant-seal + +.PHONY: rpc +rpc: + RUST_LOG="info,eth-rpc=debug" cargo run --features dev + +# Generate the metadata file for the runtime +# Make sure your chain is running before running this command +# Usage: make metadata METADATA_FILE=.scale +CHAIN ?= kitchen_sink +.PHONY: metadata +metadata: +ifndef CHAIN + $(error CHAIN is not defined. Please specify it when running make, e.g., make metadata CHAIN=) +endif + @subxt explore --url ws://localhost:9944 pallet Revive constants chainId > /dev/null + subxt metadata --url ws://localhost:9944 -o $(CHAIN).scale + touch src/subxt_client.rs + +SALT ?= 0 +.PHONY: example_deploy +example_deploy: + RUST_LOG=info cargo run --manifest-path rpc/Cargo.toml --features example --example deploy $(SALT) + +.PHONY: example_transfer +example_transfer: + RUST_LOG=info cargo run --manifest-path rpc/Cargo.toml --features example --example transfer + diff --git a/substrate/frame/revive/rpc/examples/deploy.rs b/substrate/frame/revive/rpc/examples/deploy.rs new file mode 100644 index 000000000000..b75964fc424e --- /dev/null +++ b/substrate/frame/revive/rpc/examples/deploy.rs @@ -0,0 +1,58 @@ +use codec::Encode; +use eth_rpc::{example::Account, EthRpcClient, ReceiptInfo}; +use jsonrpsee::http_client::HttpClientBuilder; +use polkadot_sdk::pallet_revive::{ + create1, + evm::{BlockTag, Bytes, U256}, + EthInstantiateInput, +}; + +static DUMMY_BYTES: &[u8] = include_bytes!("./dummy.polkavm"); + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + env_logger::init(); + let account = Account::default(); + let data = vec![]; + let input = EthInstantiateInput { code: DUMMY_BYTES.to_vec(), data: data.clone() }; + + println!("Account address: {:?}", account.address()); + let client = HttpClientBuilder::default().build("http://localhost:9090".to_string())?; + + println!("\n\n=== Deploying contract ===\n\n"); + + let input = input.encode(); + let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; + let hash = account.send_transaction(&client, U256::zero(), input.into(), None).await?; + println!("Deploy Tx hash: {hash:?}"); + + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + let ReceiptInfo { block_number, gas_used, contract_address, .. } = + client.get_transaction_receipt(hash).await?.unwrap(); + println!("Receipt received: "); + println!("Block number: {block_number}"); + println!("Gas used: {gas_used}"); + println!("Contract address: {contract_address:?}"); + + if std::env::var("SKIP_CALL").is_ok() { + return Ok(()) + } + + let contract_address = create1(&account.address(), nonce.try_into().unwrap()); + println!("\n\n=== Calling contract ===\n\n"); + + let hash = account + .send_transaction(&client, U256::zero(), Bytes::default(), Some(contract_address)) + .await?; + + println!("Contract call tx hash: {hash:?}"); + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + + let ReceiptInfo { block_number, gas_used, to, .. } = + client.get_transaction_receipt(hash).await?.unwrap(); + println!("Receipt received: "); + println!("Block number: {block_number}"); + println!("Gas used: {gas_used}"); + println!("To: {to:?}"); + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/dummy.polkavm b/substrate/frame/revive/rpc/examples/dummy.polkavm new file mode 100644 index 0000000000000000000000000000000000000000..6dae51890f046a1c4efe5a8d6270c9d8b8755f68 GIT binary patch literal 142 zcmWFt^JQRUWKm(5z`&%OoS2hyZ|%PKAUZxTwJfzLCAA for SrcChainSigner { + fn account_id(&self) -> ::AccountId { + self.0.public_key().into() + } + fn address(&self) -> ::Address { + self.0.public_key().into() + } + + fn sign(&self, signer_payload: &[u8]) -> ::Signature { + MultiSignature::Sr25519(self.0.sign(signer_payload).0.into()) + } +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = OnlineClient::::new().await?; + + println!("\n\n=== Deploying contract ===\n\n"); + + let tx_payload = subxt_client::tx().revive().instantiate_with_code( + 0u32.into(), + Weight::from_parts(2_000, 2_000).into(), + 10000000u32.into(), + DUMMY_BYTES.to_vec(), + vec![], + None, + ); + + let res = client + .tx() + .sign_and_submit_default_then_watch(&tx_payload, &SrcChainSigner(dev::alice())) + .await? + .wait_for_finalized_success() + .await?; + println!("Transaction finalized: {:?}", res.extrinsic_hash()); + + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/rpc-playground.rs b/substrate/frame/revive/rpc/examples/rpc-playground.rs new file mode 100644 index 000000000000..6ada8bbf9405 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rpc-playground.rs @@ -0,0 +1,29 @@ +use eth_rpc::{example::Account, EthRpcClient}; +use jsonrpsee::http_client::HttpClientBuilder; +use polkadot_sdk::pallet::revive_evm::BlockTag; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let data = hex_literal::hex!("0xf86b800184254ac125947bf369283338e12c90514468aa3868a551ab29298898a7d9b8314c0000808204cba0d82f7414276d8c4925f69c1b1c2507be08973e03ea2cdf5d2cae86610929cbe2a0033f3f7e1dad86b3e2cb466abe41a1658c7247f5ac4cbe237d47564bf990139e"); + let tx = rlp::decode::(&data).unwrap(); + dbg!(tx); + + let account = Account::default(); + println!("Account address: {:?}", account.address()); + + let client = HttpClientBuilder::default().build("http://localhost:9090".to_string())?; + + let block = client.get_block_by_number(BlockTag::Latest.into(), false).await?; + println!("Latest block: {block:#?}"); + + let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; + println!("Account nonce: {nonce:?}"); + + let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; + println!("Account balance: {balance:?}"); + + Ok(()) +} +//method: eth_sendRawTransaction params: +// ["0xf86b800184254ac125947bf369283338e12c90514468aa3868a551ab29298898a7d9b8314c0000808204cba0d82f7414276d8c4925f69c1b1c2507be08973e03ea2cdf5d2cae86610929cbe2a0033f3f7e1dad86b3e2cb466abe41a1658c7247f5ac4cbe237d47564bf990139e" +// ], diff --git a/substrate/frame/revive/rpc/examples/transfer.rs b/substrate/frame/revive/rpc/examples/transfer.rs new file mode 100644 index 000000000000..f363ca09dc43 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/transfer.rs @@ -0,0 +1,31 @@ +use eth_rpc::{example::Account, EthRpcClient}; +use hex_literal::hex; +use jsonrpsee::http_client::HttpClientBuilder; +use polkadot_sdk::pallet_revive::evm::{BlockTag, Bytes, H160}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let account = Account::default(); + println!("Account address: {:?}", account.address()); + + let client = HttpClientBuilder::default().build("http://localhost:9090".to_string())?; + + let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; + println!("Account balance: {:?}", balance); + + let to = Some(H160(hex!("c543bb3eF11d96aCA20b3c906cF2C8Daaff925e4"))); + let value = 10_000_000_000_000_000_000u128.into(); // 10 ETH + println!("\n\n=== Transferring ===\n\n"); + + let hash = account.send_transaction(&client, value, Bytes::default(), to).await?; + println!("Transaction hash: {hash:?}"); + + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + let receipt = client.get_transaction_receipt(hash).await; + println!("Receipt: {receipt:?}"); + + let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; + println!("Account balance: {:?}", balance); + + Ok(()) +} diff --git a/substrate/frame/revive/rpc/kitchensink.scale b/substrate/frame/revive/rpc/kitchensink.scale new file mode 100644 index 0000000000000000000000000000000000000000..f9b520e7d67ad65ffacced036616f7eda0fdebf4 GIT binary patch literal 651254 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 G5Pd@M-notIn^{)N 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 literal 0 HcmV?d00001 diff --git a/substrate/frame/revive/rpc/examples/js/index.html b/substrate/frame/revive/rpc/examples/js/index.html new file mode 100644 index 000000000000..72f7026ce5f3 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/index.html @@ -0,0 +1,29 @@ + + + + + + + MetaMask Playground + + + + + + + + + + + + + + + diff --git a/substrate/frame/revive/rpc/examples/js/package.json b/substrate/frame/revive/rpc/examples/js/package.json new file mode 100644 index 000000000000..4d7136606b65 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/package.json @@ -0,0 +1,18 @@ +{ + "name": "demo", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "ethers": "^6.13.1" + }, + "devDependencies": { + "typescript": "^5.5.3", + "vite": "^5.4.8" + } +} diff --git a/substrate/frame/revive/rpc/examples/js/src/main.ts b/substrate/frame/revive/rpc/examples/js/src/main.ts new file mode 100644 index 000000000000..88b72755aae9 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/main.ts @@ -0,0 +1,141 @@ +import { + AddressLike, + BrowserProvider, + Contract, + ContractFactory, + Eip1193Provider, + JsonRpcSigner, + parseEther, +} from "ethers"; + +declare global { + interface Window { + ethereum?: Eip1193Provider; + } +} + +function str_to_bytes(str: string): Uint8Array { + return new TextEncoder().encode(str); +} + +document.addEventListener("DOMContentLoaded", async () => { + if (typeof window.ethereum == "undefined") { + return console.log("MetaMask is not installed"); + } + + console.log("MetaMask is installed!"); + const provider = new BrowserProvider(window.ethereum); + + console.log("Getting signer..."); + let signer: JsonRpcSigner; + try { + signer = await provider.getSigner(); + console.log(`Signer: ${signer.address}`); + } catch (e) { + console.error("Failed to get signer", e); + return; + } + + console.log("Getting block number..."); + try { + const blockNumber = await provider.getBlockNumber(); + console.log(`Block number: ${blockNumber}`); + } catch (e) { + console.error("Failed to get block number", e); + return; + } + + const nonce = await signer.getNonce(); + console.log(`Nonce: ${nonce}`); + + document.getElementById("transferButton")?.addEventListener( + "click", + async () => { + const address = + (document.getElementById("transferInput") as HTMLInputElement).value; + await transfer(address); + }, + ); + + document.getElementById("deployButton")?.addEventListener( + "click", + async () => { + await deploy(); + }, + ); + document.getElementById("deployAndCallButton")?.addEventListener( + "click", + async () => { + const nonce = await signer.getNonce(); + console.log(`deploy with nonce: ${nonce}`); + + const address = await deploy(); + if (address) { + const nonce = await signer.getNonce(); + console.log(`call with nonce: ${nonce}`); + await call(address); + } + }, + ); + document.getElementById("callButton")?.addEventListener("click", async () => { + const address = + (document.getElementById("callInput") as HTMLInputElement).value; + await call(address); + }); + + async function deploy() { + console.log("Deploying contract..."); + + const bytecode = await fetch("rpc_demo.polkavm").then((response) => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.arrayBuffer(); + }) + .then((arrayBuffer) => new Uint8Array(arrayBuffer)); + + const contractFactory = new ContractFactory( + [ + "constructor(bytes memory _data)", + ], + bytecode, + signer, + ); + + try { + const args = str_to_bytes("hello"); + const contract = await contractFactory.deploy(args); + await contract.waitForDeployment(); + const address = await contract.getAddress(); + console.log(`Contract deployed: ${address}`); + return address; + } catch (e) { + console.error("Failed to deploy contract", e); + return; + } + } + + async function call(address: string) { + const abi = ["function call(bytes data)"]; + const contract = new Contract(address, abi, signer); + const tx = await contract.call(str_to_bytes("world")); + + console.log("Transaction hash:", tx.hash); + } + + async function transfer(to: AddressLike) { + console.log(`transferring 1 DOT to ${to}...`); + try { + const tx = await signer.sendTransaction({ + to, + value: parseEther("1.0"), + }); + + const receipt = await tx.wait(); + console.log(`Transaction hash: ${receipt?.hash}`); + } catch (e) { + console.error("Failed to send transaction", e); + return; + } + } +}); diff --git a/substrate/frame/revive/rpc/examples/js/src/script.ts b/substrate/frame/revive/rpc/examples/js/src/script.ts new file mode 100644 index 000000000000..70131a2f17d3 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/script.ts @@ -0,0 +1,49 @@ +//! Run with bun run script.ts + +import { readFileSync } from "fs"; +import { Contract, ContractFactory, JsonRpcProvider } from "ethers"; + +const provider = new JsonRpcProvider("http://localhost:9090"); +const signer = await provider.getSigner(); +console.log( + `Signer address: ${await signer.getAddress()}, Nonce: ${await signer + .getNonce()}`, +); + +function str_to_bytes(str: string): Uint8Array { + return new TextEncoder().encode(str); +} + +// deploy +async function deploy() { + console.log(`Deploying Contract...`); + + const bytecode = readFileSync("rpc_demo.polkavm"); + const contractFactory = new ContractFactory( + [ + "constructor(bytes memory _data)", + ], + bytecode, + signer, + ); + + const args = str_to_bytes("hello"); + console.log("Deploying contract with args:", args); + const contract = await contractFactory.deploy(args); + await contract.waitForDeployment(); + const address = await contract.getAddress(); + console.log(`Contract deployed: ${address}`); + return address; +} + +async function call(address: string) { + console.log(`Calling Contract at ${address}...`); + + const abi = ["function call(bytes data)"]; + const contract = new Contract(address, abi, signer); + const tx = await contract.call(str_to_bytes("world")); + console.log("Call transaction hash:", tx.hash); +} + +const address = await deploy(); +await call(address); diff --git a/substrate/frame/revive/rpc/examples/js/tsconfig.json b/substrate/frame/revive/rpc/examples/js/tsconfig.json new file mode 100644 index 000000000000..0511b9f0e041 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/substrate/frame/revive/rpc/examples/rpc_demo.polkavm b/substrate/frame/revive/rpc/examples/rpc_demo.polkavm new file mode 120000 index 000000000000..63925dfcc544 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rpc_demo.polkavm @@ -0,0 +1 @@ +../../../../../target/pallet-revive-fixtures/rpc_demo.polkavm \ No newline at end of file diff --git a/substrate/frame/revive/rpc/examples/rust/deploy.rs b/substrate/frame/revive/rpc/examples/rust/deploy.rs new file mode 100644 index 000000000000..0d6c0996e71d --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/deploy.rs @@ -0,0 +1,65 @@ +// 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 jsonrpsee::http_client::HttpClientBuilder; +use pallet_revive::{ + create1, + evm::{Account, BlockTag, Bytes, ReceiptInfo, U256}, +}; +use pallet_revive_eth_rpc::{ + example::{send_transaction, wait_for_receipt}, + EthRpcClient, +}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + env_logger::init(); + let account = Account::default(); + let data = vec![]; + let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; + let input = bytes.into_iter().chain(data.clone()).collect::>(); + + println!("Account address: {:?}", account.address()); + let client = HttpClientBuilder::default().build("http://localhost:9090")?; + + println!("\n\n=== Deploying contract ===\n\n"); + + let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; + let hash = send_transaction(&account, &client, U256::zero(), input.into(), None).await?; + + println!("Deploy Tx hash: {hash:?}"); + let ReceiptInfo { block_number, gas_used, contract_address, .. } = + wait_for_receipt(&client, hash).await?; + println!("Receipt:"); + println!("- Block number: {block_number}"); + println!("- Gas used: {gas_used}"); + println!("- Contract address: {contract_address:?}"); + + let contract_address = create1(&account.address(), nonce.try_into().unwrap()); + println!("\n\n=== Calling contract ===\n\n"); + + let hash = + send_transaction(&account, &client, U256::zero(), Bytes::default(), Some(contract_address)) + .await?; + + println!("Contract call tx hash: {hash:?}"); + let ReceiptInfo { block_number, gas_used, to, .. } = wait_for_receipt(&client, hash).await?; + println!("Receipt:"); + println!("- Block number: {block_number}"); + println!("- Gas used: {gas_used}"); + println!("- To: {to:?}"); + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs new file mode 100644 index 000000000000..01cb5aaf978e --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs @@ -0,0 +1,46 @@ +// 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 pallet_revive_eth_rpc::subxt_client::{self, SrcChainConfig}; +use sp_weights::Weight; +use subxt::OnlineClient; +use subxt_signer::sr25519::dev; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = OnlineClient::::new().await?; + + let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; + + let tx_payload = subxt_client::tx().revive().instantiate_with_code( + 0u32.into(), + Weight::from_parts(100_000, 0).into(), + 3_000_000_000_000_000, + bytes, + vec![], + None, + ); + + let res = client + .tx() + .sign_and_submit_then_watch_default(&tx_payload, &dev::alice()) + .await? + .wait_for_finalized_success() + .await?; + println!("Transaction finalized: {:?}", res.extrinsic_hash()); + + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/rust/rpc-playground.rs b/substrate/frame/revive/rpc/examples/rust/rpc-playground.rs new file mode 100644 index 000000000000..635fbb74d5c2 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/rpc-playground.rs @@ -0,0 +1,41 @@ +// 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 jsonrpsee::http_client::HttpClientBuilder; +use pallet_revive::evm::{Account, BlockTag}; +use pallet_revive_eth_rpc::EthRpcClient; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let account = Account::default(); + println!("Account address: {:?}", account.address()); + + let client = HttpClientBuilder::default().build("http://localhost:9090")?; + + let block = client.get_block_by_number(BlockTag::Latest.into(), false).await?; + println!("Latest block: {block:#?}"); + + let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; + println!("Account nonce: {nonce:?}"); + + let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; + println!("Account balance: {balance:?}"); + + let sync_state = client.syncing().await?; + println!("Sync state: {sync_state:?}"); + + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/rust/transfer.rs b/substrate/frame/revive/rpc/examples/rust/transfer.rs new file mode 100644 index 000000000000..7c6f69f3b6a7 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/transfer.rs @@ -0,0 +1,55 @@ +// 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 jsonrpsee::http_client::HttpClientBuilder; +use pallet_revive::evm::{Account, BlockTag, Bytes, ReceiptInfo}; +use pallet_revive_eth_rpc::{ + example::{send_transaction, wait_for_receipt}, + EthRpcClient, +}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let alith = Account::default(); + let client = HttpClientBuilder::default().build("http://localhost:9090")?; + + let baltathar = Account::from(subxt_signer::eth::dev::baltathar()); + let value = 1_000_000_000_000_000_000u128.into(); // 1 ETH + + let print_balance = || async { + let balance = client.get_balance(alith.address(), BlockTag::Latest.into()).await?; + println!("Alith {:?} balance: {balance:?}", alith.address()); + let balance = client.get_balance(baltathar.address(), BlockTag::Latest.into()).await?; + println!("Baltathar {:?} balance: {balance:?}", baltathar.address()); + anyhow::Result::<()>::Ok(()) + }; + + print_balance().await?; + println!("\n\n=== Transferring ===\n\n"); + + let hash = + send_transaction(&alith, &client, value, Bytes::default(), Some(baltathar.address())) + .await?; + println!("Transaction hash: {hash:?}"); + + let ReceiptInfo { block_number, gas_used, .. } = wait_for_receipt(&client, hash).await?; + println!("Receipt: "); + println!("- Block number: {block_number}"); + println!("- Gas used: {gas_used}"); + + print_balance().await?; + Ok(()) +} diff --git a/substrate/frame/revive/rpc/kitchensink.scale b/substrate/frame/revive/rpc/kitchensink.scale new file mode 100644 index 0000000000000000000000000000000000000000..60c1834d3c7875d257a4bf1f3426a459a6f44cdc GIT binary patch literal 651459 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 +} + +/// The substrate block type. +pub type SubstrateBlock = subxt::blocks::Block>; + +/// The substrate block number type. +pub type SubstrateBlockNumber = <::Header as Header>::Number; + +/// The substrate block hash type. +pub type SubstrateBlockHash = ::Hash; + +/// Type alias for shared data. +pub type Shared = Arc>; + +/// The runtime balance type. +pub type Balance = u128; + +/// The cache maintains a buffer of the last N blocks, +#[derive(Default)] +struct BlockCache { + /// A double-ended queue of the last N blocks. + /// The most recent block is at the back of the queue, and the oldest block is at the front. + buffer: VecDeque>, + + /// A map of blocks by block number. + blocks_by_number: HashMap>, + + /// A map of blocks by block hash. + blocks_by_hash: HashMap>, + + /// A map of receipts by hash. + receipts_by_hash: HashMap, + + /// A map of Signed transaction by hash. + signed_tx_by_hash: HashMap, + + /// A map of receipt hashes by block hash. + tx_hashes_by_block_and_index: HashMap>, +} + +/// The error type for the client. +#[derive(Error, Debug)] +pub enum ClientError { + /// A [`subxt::Error`] wrapper error. + #[error("Subxt error: {0}")] + SubxtError(#[from] subxt::Error), + /// A [`RpcError`] wrapper error. + #[error("RPC error: {0}")] + RpcError(#[from] RpcError), + /// A [`codec::Error`] wrapper error. + #[error("Codec error: {0}")] + CodecError(#[from] codec::Error), + /// The dry run failed. + #[error("Dry run failed")] + DryRunFailed, + /// A decimal conversion failed. + #[error("Conversion failed")] + ConversionFailed, + /// The block hash was not found. + #[error("Hash not found")] + BlockNotFound, + /// The transaction fee could not be found + #[error("TransactionFeePaid event not found")] + TxFeeNotFound, + /// The token decimals property was not found + #[error("tokenDecimals not found in properties")] + TokenDecimalsNotFound, + /// The cache is empty. + #[error("Cache is empty")] + CacheEmpty, +} + +// Convert a `ClientError` to an RPC `ErrorObjectOwned`. +impl From for ErrorObjectOwned { + fn from(value: ClientError) -> Self { + log::debug!(target: LOG_TARGET, "ClientError: {value:?}"); + ErrorObjectOwned::owned::<()>( + ErrorCode::InternalError.code(), + ErrorCode::InternalError.message(), + None, + ) + } +} + +/// The number of recent blocks maintained by the cache. +/// For each block in the cache, we also store the EVM transaction receipts. +pub const CACHE_SIZE: usize = 10; + +impl BlockCache { + fn latest_block(&self) -> Option<&Arc> { + self.buffer.back() + } + + /// Insert an entry into the cache, and prune the oldest entry if the cache is full. + fn insert(&mut self, block: SubstrateBlock) { + if self.buffer.len() >= N { + if let Some(block) = self.buffer.pop_front() { + log::trace!(target: LOG_TARGET, "Pruning block: {}", block.number()); + let hash = block.hash(); + self.blocks_by_hash.remove(&hash); + self.blocks_by_number.remove(&block.number()); + if let Some(entries) = self.tx_hashes_by_block_and_index.remove(&hash) { + for hash in entries.values() { + self.receipts_by_hash.remove(hash); + } + } + } + } + + let block = Arc::new(block); + self.buffer.push_back(block.clone()); + self.blocks_by_number.insert(block.number(), block.clone()); + self.blocks_by_hash.insert(block.hash(), block); + } +} + +/// A client connect to a node and maintains a cache of the last `CACHE_SIZE` blocks. +pub struct Client { + inner: Arc, + join_set: JoinSet>, + /// A watch channel to signal cache updates. + pub updates: tokio::sync::watch::Receiver<()>, +} + +/// The inner state of the client. +struct ClientInner { + api: OnlineClient, + rpc_client: ReconnectingRpcClient, + rpc: LegacyRpcMethods, + cache: Shared>, + chain_id: u64, + max_block_weight: Weight, + native_to_evm_ratio: U256, +} + +impl ClientInner { + /// Create a new client instance connecting to the substrate node at the given URL. + async fn from_url(url: &str) -> Result { + let rpc_client = ReconnectingRpcClient::builder() + .retry_policy(ExponentialBackoff::from_millis(100).max_delay(Duration::from_secs(10))) + .build(url.to_string()) + .await?; + + let api = OnlineClient::::from_rpc_client(rpc_client.clone()).await?; + let cache = Arc::new(RwLock::new(BlockCache::::default())); + + let rpc = LegacyRpcMethods::::new(RpcClient::new(rpc_client.clone())); + + let (native_to_evm_ratio, chain_id, max_block_weight) = + tokio::try_join!(native_to_evm_ratio(&rpc), chain_id(&api), max_block_weight(&api))?; + + Ok(Self { api, rpc_client, rpc, cache, chain_id, max_block_weight, native_to_evm_ratio }) + } + + /// Convert a native balance to an EVM balance. + pub fn native_to_evm_decimals(&self, value: U256) -> U256 { + value.saturating_mul(self.native_to_evm_ratio) + } + + /// Get the receipt infos from the extrinsics in a block. + async fn receipt_infos( + &self, + block: &SubstrateBlock, + ) -> Result, ClientError> { + // Get extrinsics from the block + let extrinsics = block.extrinsics().await?; + + // Filter extrinsics from pallet_revive + let extrinsics = extrinsics.iter().flat_map(|ext| { + let ext = ext.ok()?; + + let call = ext.as_extrinsic::().ok()??; + let tx = rlp::decode::(&call.payload).ok()?; + let from = tx.recover_eth_address().ok()?; + let contract_address = if tx.transaction_legacy_unsigned.to.is_none() { + Some(create1(&from, tx.transaction_legacy_unsigned.nonce.try_into().ok()?)) + } else { + None + }; + + Some((from, tx, contract_address, ext)) + }); + + // Map each extrinsic to a receipt + stream::iter(extrinsics) + .map(|(from, tx, contract_address, ext)| async move { + let events = ext.events().await?; + let tx_fees = + events.find_first::()?.ok_or(ClientError::TxFeeNotFound)?; + + let gas_price = tx.transaction_legacy_unsigned.gas_price; + let gas_used = (tx_fees.tip.saturating_add(tx_fees.actual_fee)) + .checked_div(gas_price.as_u128()) + .unwrap_or_default(); + + let success = events.find_first::().is_ok(); + let transaction_index = ext.index(); + let transaction_hash = primitives::Hashing::hash(&Vec::from(ext.bytes()).encode()); + let block_hash = block.hash(); + let block_number = block.number().into(); + + let receipt = ReceiptInfo { + block_hash, + block_number, + contract_address, + from, + to: tx.transaction_legacy_unsigned.to, + effective_gas_price: gas_price, + gas_used: gas_used.into(), + status: Some(if success { U256::one() } else { U256::zero() }), + transaction_hash, + transaction_index: transaction_index.into(), + ..Default::default() + }; + + Ok::<_, ClientError>((receipt.transaction_hash, (tx.into(), receipt))) + }) + .buffer_unordered(10) + .collect::>>() + .await + .into_iter() + .collect::, _>>() + } +} + +/// Drop all the tasks spawned by the client on drop. +impl Drop for Client { + fn drop(&mut self) { + self.join_set.abort_all() + } +} + +/// Fetch the chain ID from the substrate chain. +async fn chain_id(api: &OnlineClient) -> Result { + let query = subxt_client::constants().revive().chain_id(); + api.constants().at(&query).map_err(|err| err.into()) +} + +/// Fetch the max block weight from the substrate chain. +async fn max_block_weight(api: &OnlineClient) -> Result { + let query = subxt_client::constants().system().block_weights(); + let weights = api.constants().at(&query)?; + let max_block = weights.per_class.normal.max_extrinsic.unwrap_or(weights.max_block); + Ok(max_block.0) +} + +/// Fetch the native to EVM ratio from the substrate chain. +async fn native_to_evm_ratio(rpc: &LegacyRpcMethods) -> Result { + let props = rpc.system_properties().await?; + let eth_decimals = U256::from(18u32); + let native_decimals: U256 = props + .get("tokenDecimals") + .and_then(|v| v.as_number()?.as_u64()) + .ok_or(ClientError::TokenDecimalsNotFound)? + .into(); + + Ok(U256::from(10u32).pow(eth_decimals - native_decimals)) +} + +/// Extract the block timestamp. +async fn extract_block_timestamp(block: &SubstrateBlock) -> Option { + let extrinsics = block.extrinsics().await.ok()?; + let ext = extrinsics + .find_first::() + .ok()??; + + Some(ext.value.now / 1000) +} + +impl Client { + /// Create a new client instance. + /// The client will subscribe to new blocks and maintain a cache of [`CACHE_SIZE`] blocks. + pub async fn from_url(url: &str) -> Result { + log::info!(target: LOG_TARGET, "Connecting to node at: {url} ..."); + let inner: Arc = Arc::new(ClientInner::from_url(url).await?); + log::info!(target: LOG_TARGET, "Connected to node at: {url}"); + + let (tx, mut updates) = tokio::sync::watch::channel(()); + let mut join_set = JoinSet::new(); + join_set.spawn(Self::subscribe_blocks(inner.clone(), tx)); + join_set.spawn(Self::subscribe_reconnect(inner.clone())); + + updates.changed().await.expect("tx is not dropped"); + Ok(Self { inner, join_set, updates }) + } + + /// Subscribe and log reconnection events. + async fn subscribe_reconnect(inner: Arc) -> Result<(), ClientError> { + let rpc = inner.as_ref().rpc_client.clone(); + loop { + let reconnected = rpc.reconnect_initiated().await; + log::info!("RPC client connection lost"); + let now = std::time::Instant::now(); + reconnected.await; + log::info!("RPC client reconnection took `{}s`", now.elapsed().as_secs()); + } + } + + /// Subscribe to new blocks and update the cache. + async fn subscribe_blocks(inner: Arc, tx: Sender<()>) -> Result<(), ClientError> { + log::info!("Subscribing to new blocks"); + let mut block_stream = + inner.as_ref().api.blocks().subscribe_finalized().await.inspect_err(|err| { + log::error!("Failed to subscribe to blocks: {err:?}"); + })?; + + while let Some(block) = block_stream.next().await { + let block = match block { + Ok(block) => block, + Err(err) => { + if err.is_disconnected_will_reconnect() { + log::warn!( + "The RPC connection was lost and we may have missed a few blocks" + ); + continue; + } + + log::error!("Failed to fetch block: {err:?}"); + return Err(err.into()); + }, + }; + + log::debug!("Pushing block: {}", block.number()); + let mut cache = inner.cache.write().await; + + let receipts = inner + .receipt_infos(&block) + .await + .inspect_err(|err| { + log::error!("Failed to get receipts: {err:?}"); + }) + .unwrap_or_default(); + + if !receipts.is_empty() { + log::debug!("Adding {} receipts", receipts.len()); + let values = receipts + .iter() + .map(|(hash, (_, receipt))| (receipt.transaction_index, *hash)) + .collect::>(); + + cache.tx_hashes_by_block_and_index.insert(block.hash(), values); + + cache + .receipts_by_hash + .extend(receipts.iter().map(|(hash, (_, receipt))| (*hash, receipt.clone()))); + + cache.signed_tx_by_hash.extend( + receipts.iter().map(|(hash, (signed_tx, _))| (*hash, signed_tx.clone())), + ) + } + + cache.insert(block); + tx.send_replace(()); + } + + log::info!("Block subscription ended"); + Ok(()) + } + + /// Get the most recent block stored in the cache. + pub async fn latest_block(&self) -> Option> { + let cache = self.inner.cache.read().await; + let block = cache.latest_block()?; + Some(block.clone()) + } + + /// Expose the transaction API. + pub fn tx(&self) -> TxClient> { + self.inner.api.tx() + } + + /// Get an EVM transaction receipt by hash. + pub async fn receipt(&self, tx_hash: &H256) -> Option { + let cache = self.inner.cache.read().await; + cache.receipts_by_hash.get(tx_hash).cloned() + } + + /// Get the syncing status of the chain. + pub async fn syncing(&self) -> Result { + let health = self.inner.rpc.system_health().await?; + + let status = if health.is_syncing { + let client = RpcClient::new(self.inner.rpc_client.clone()); + let sync_state: sc_rpc::system::SyncState = + client.request("system_syncState", Default::default()).await?; + + SyncingProgress { + current_block: Some(sync_state.current_block.into()), + highest_block: Some(sync_state.highest_block.into()), + starting_block: Some(sync_state.starting_block.into()), + } + .into() + } else { + SyncingStatus::Bool(false) + }; + + Ok(status) + } + + /// Get an EVM transaction receipt by hash. + pub async fn receipt_by_hash_and_index( + &self, + block_hash: &H256, + transaction_index: &U256, + ) -> Option { + let cache = self.inner.cache.read().await; + let receipt_hash = + cache.tx_hashes_by_block_and_index.get(block_hash)?.get(transaction_index)?; + let receipt = cache.receipts_by_hash.get(receipt_hash)?; + Some(receipt.clone()) + } + + pub async fn signed_tx_by_hash(&self, tx_hash: &H256) -> Option { + let cache = self.inner.cache.read().await; + cache.signed_tx_by_hash.get(tx_hash).cloned() + } + + /// Get receipts count per block. + pub async fn receipts_count_per_block(&self, block_hash: &SubstrateBlockHash) -> Option { + let cache = self.inner.cache.read().await; + cache.tx_hashes_by_block_and_index.get(block_hash).map(|v| v.len()) + } + + /// Expose the storage API. + pub async fn storage_api( + &self, + at: &BlockNumberOrTagOrHash, + ) -> Result>, ClientError> { + match at { + BlockNumberOrTagOrHash::U256(block_number) => { + let n: SubstrateBlockNumber = + (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; + + let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; + Ok(self.inner.api.storage().at(hash)) + }, + BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.storage().at(*hash)), + BlockNumberOrTagOrHash::BlockTag(_) => { + if let Some(block) = self.latest_block().await { + return Ok(self.inner.api.storage().at(block.hash())); + } + let storage = self.inner.api.storage().at_latest().await?; + Ok(storage) + }, + } + } + + /// Expose the runtime API. + pub async fn runtime_api( + &self, + at: &BlockNumberOrTagOrHash, + ) -> Result< + subxt::runtime_api::RuntimeApi>, + ClientError, + > { + match at { + BlockNumberOrTagOrHash::U256(block_number) => { + let n: SubstrateBlockNumber = + (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; + + let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; + Ok(self.inner.api.runtime_api().at(hash)) + }, + BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.runtime_api().at(*hash)), + BlockNumberOrTagOrHash::BlockTag(_) => { + if let Some(block) = self.latest_block().await { + return Ok(self.inner.api.runtime_api().at(block.hash())); + } + + let api = self.inner.api.runtime_api().at_latest().await?; + Ok(api) + }, + } + } + + /// Get the balance of the given address. + pub async fn balance( + &self, + address: H160, + at: &BlockNumberOrTagOrHash, + ) -> Result { + let account_id = self.account_id(&address); + let query = subxt_client::storage().system().account(account_id); + let Some(account) = self.storage_api(at).await?.fetch(&query).await? else { + return Ok(U256::zero()); + }; + + let native = account.data.free.into(); + Ok(self.inner.native_to_evm_decimals(native)) + } + + /// Get the contract storage for the given contract address and key. + pub async fn get_contract_storage( + &self, + contract_address: H160, + key: U256, + block: BlockNumberOrTagOrHash, + ) -> Result, ClientError> { + let runtime_api = self.runtime_api(&block).await?; + + // TODO: remove once subxt is updated + let contract_address = contract_address.0.into(); + + let payload = subxt_client::apis() + .revive_api() + .get_storage(contract_address, key.to_big_endian()); + let result = runtime_api.call(payload).await?.unwrap_or_default().unwrap_or_default(); + Ok(result) + } + + /// Get the contract code for the given contract address. + pub async fn get_contract_code( + &self, + contract_address: &H160, + block: BlockNumberOrTagOrHash, + ) -> Result, ClientError> { + let storage_api = self.storage_api(&block).await?; + let account_id = self.account_id(contract_address); + let code_hash: subxt::utils::H256 = account_id.0.into(); + + let query = subxt_client::storage().revive().pristine_code(code_hash); + let result = storage_api.fetch(&query).await?.map(|v| v.0).unwrap_or_default(); + Ok(result) + } + + /// Dry run a transaction and returns the [`EthContractResult`] for the transaction. + pub async fn dry_run( + &self, + tx: &GenericTransaction, + block: BlockNumberOrTagOrHash, + ) -> Result, ClientError> { + let runtime_api = self.runtime_api(&block).await?; + let from = tx.from.ok_or(ClientError::DryRunFailed)?; + let value = tx + .value + .unwrap_or_default() + .try_into() + .map_err(|_| ClientError::ConversionFailed)?; + + // TODO: remove once subxt is updated + let from = from.0.into(); + let to = tx.to.map(|v| v.0.into()); + + let payload = subxt_client::apis().revive_api().eth_transact( + from, + to, + value, + tx.input.clone().unwrap_or_default().0, + None, + None, + ); + let res = runtime_api.call(payload).await?.0; + Ok(res) + } + + /// Dry run a transaction and returns the gas estimate for the transaction. + pub async fn estimate_gas( + &self, + tx: &GenericTransaction, + block: BlockNumberOrTagOrHash, + ) -> Result { + let dry_run = self.dry_run(tx, block).await?; + Ok(U256::from(dry_run.fee / GAS_PRICE as u128) + 1) + } + + /// Get the nonce of the given address. + pub async fn nonce( + &self, + address: H160, + block: BlockNumberOrTagOrHash, + ) -> Result { + let account_id = self.account_id(&address); + let storage = self.storage_api(&block).await?; + let query = subxt_client::storage().system().account(account_id); + let Some(account) = storage.fetch(&query).await? else { + return Ok(0); + }; + + Ok(account.nonce) + } + + /// Get the block number of the latest block. + pub async fn block_number(&self) -> Result { + let cache = self.inner.cache.read().await; + let latest_block = cache.buffer.back().ok_or(ClientError::CacheEmpty)?; + Ok(latest_block.number()) + } + + /// Get a block hash for the given block number. + pub async fn get_block_hash( + &self, + block_number: SubstrateBlockNumber, + ) -> Result, ClientError> { + let cache = self.inner.cache.read().await; + if let Some(block) = cache.blocks_by_number.get(&block_number) { + return Ok(Some(block.hash())); + } + + let hash = self.inner.rpc.chain_get_block_hash(Some(block_number.into())).await?; + Ok(hash) + } + + /// Get a block for the specified hash or number. + pub async fn block_by_number_or_tag( + &self, + block: &BlockNumberOrTag, + ) -> Result>, ClientError> { + match block { + BlockNumberOrTag::U256(n) => { + let n = (*n).try_into().map_err(|_| ClientError::ConversionFailed)?; + self.block_by_number(n).await + }, + BlockNumberOrTag::BlockTag(_) => { + let cache = self.inner.cache.read().await; + Ok(cache.buffer.back().cloned()) + }, + } + } + + /// Get a block by hash + pub async fn block_by_hash( + &self, + hash: &SubstrateBlockHash, + ) -> Result>, ClientError> { + let cache = self.inner.cache.read().await; + if let Some(block) = cache.blocks_by_hash.get(hash) { + return Ok(Some(block.clone())); + } + + match self.inner.api.blocks().at(*hash).await { + Ok(block) => Ok(Some(Arc::new(block))), + Err(subxt::Error::Block(subxt::error::BlockError::NotFound(_))) => Ok(None), + Err(err) => Err(err.into()), + } + } + + /// Get a block by number + pub async fn block_by_number( + &self, + block_number: SubstrateBlockNumber, + ) -> Result>, ClientError> { + let cache = self.inner.cache.read().await; + if let Some(block) = cache.blocks_by_number.get(&block_number) { + return Ok(Some(block.clone())); + } + + let Some(hash) = self.get_block_hash(block_number).await? else { + return Ok(None); + }; + + self.block_by_hash(&hash).await + } + + /// Get the EVM block for the given hash. + pub async fn evm_block(&self, block: Arc) -> Result { + let runtime_api = self.inner.api.runtime_api().at(block.hash()); + let max_fee = Self::weight_to_fee(&runtime_api, self.max_block_weight()).await?; + let gas_limit = U256::from(max_fee / GAS_PRICE as u128); + + let header = block.header(); + let timestamp = extract_block_timestamp(&block).await.unwrap_or_default(); + + // TODO: remove once subxt is updated + let parent_hash = header.parent_hash.0.into(); + let state_root = header.state_root.0.into(); + let extrinsics_root = header.extrinsics_root.0.into(); + + Ok(Block { + hash: block.hash(), + parent_hash, + state_root, + transactions_root: extrinsics_root, + number: header.number.into(), + timestamp: timestamp.into(), + difficulty: Some(0u32.into()), + gas_limit, + logs_bloom: Bytes256([0u8; 256]), + receipts_root: extrinsics_root, + ..Default::default() + }) + } + + /// Convert a weight to a fee. + async fn weight_to_fee( + runtime_api: &subxt::runtime_api::RuntimeApi>, + weight: Weight, + ) -> Result { + let payload = subxt_client::apis() + .transaction_payment_api() + .query_weight_to_fee(weight.into()); + + let fee = runtime_api.call(payload).await?; + Ok(fee) + } + + /// Get the substrate account ID from the EVM address. + pub fn account_id(&self, address: &H160) -> AccountId32 { + let mut id: [u8; 32] = [0xEE; 32]; + id[..20].copy_from_slice(address.as_bytes()); + AccountId32(id) + } + + /// Get the chain ID. + pub fn chain_id(&self) -> u64 { + self.inner.chain_id + } + + /// Get the Max Block Weight. + pub fn max_block_weight(&self) -> Weight { + self.inner.max_block_weight + } +} diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs new file mode 100644 index 000000000000..cbd022fa3b73 --- /dev/null +++ b/substrate/frame/revive/rpc/src/example.rs @@ -0,0 +1,96 @@ +// 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. +//! Example utilities +#![cfg(feature = "example")] + +use crate::{EthRpcClient, ReceiptInfo}; +use anyhow::Context; +use jsonrpsee::http_client::HttpClient; +use pallet_revive::evm::{ + rlp::*, Account, BlockTag, Bytes, GenericTransaction, TransactionLegacyUnsigned, H160, H256, + U256, +}; + +/// Wait for a transaction receipt. +pub async fn wait_for_receipt(client: &HttpClient, hash: H256) -> anyhow::Result { + for _ in 0..6 { + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + let receipt = client.get_transaction_receipt(hash).await?; + if let Some(receipt) = receipt { + return Ok(receipt) + } + } + + anyhow::bail!("Failed to get receipt") +} + +/// Send a transaction. +pub async fn send_transaction( + signer: &Account, + client: &HttpClient, + value: U256, + input: Bytes, + to: Option, +) -> anyhow::Result { + let from = signer.address(); + + let chain_id = Some(client.chain_id().await?); + + let gas_price = client.gas_price().await?; + let nonce = client + .get_transaction_count(from, BlockTag::Latest.into()) + .await + .with_context(|| "Failed to fetch account nonce")?; + + let gas = client + .estimate_gas( + GenericTransaction { + from: Some(from), + input: Some(input.clone()), + value: Some(value), + gas_price: Some(gas_price), + to, + ..Default::default() + }, + None, + ) + .await + .with_context(|| "Failed to fetch gas estimate")?; + + println!("Estimated Gas: {gas:?}"); + + let unsigned_tx = TransactionLegacyUnsigned { + gas, + nonce, + to, + value, + input, + gas_price, + chain_id, + ..Default::default() + }; + + let tx = signer.sign_transaction(unsigned_tx.clone()); + let bytes = tx.rlp_bytes().to_vec(); + + let hash = client + .send_raw_transaction(bytes.clone().into()) + .await + .with_context(|| "transaction failed")?; + + Ok(hash) +} diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs new file mode 100644 index 000000000000..e740111d6591 --- /dev/null +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -0,0 +1,375 @@ +// 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. +//! The [`EthRpcServer`] RPC server implementation +#![cfg_attr(docsrs, feature(doc_cfg))] + +use crate::runtime::GAS_PRICE; +use client::ClientError; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + proc_macros::rpc, + types::{ErrorCode, ErrorObjectOwned}, +}; +pub use pallet_revive::{evm::*, EthContractResult}; +pub use sp_core::{H160, H256, U256}; +use thiserror::Error; +pub mod client; +pub mod example; +pub mod subxt_client; + +mod rpc_methods_gen; +pub use rpc_methods_gen::*; + +pub const LOG_TARGET: &str = "eth-rpc"; + +/// Additional RPC methods, exposed on the RPC server on top of all the eth_xxx methods. +#[rpc(server, client)] +pub trait MiscRpc { + /// Returns the health status of the server. + #[method(name = "healthcheck")] + async fn healthcheck(&self) -> RpcResult<()>; +} + +/// An EVM RPC server implementation. +pub struct EthRpcServerImpl { + /// The client used to interact with the substrate node. + client: client::Client, + + /// The accounts managed by the server. + accounts: Vec, +} + +impl EthRpcServerImpl { + /// Creates a new [`EthRpcServerImpl`]. + pub fn new(client: client::Client) -> Self { + Self { client, accounts: vec![] } + } + + /// Sets the accounts managed by the server. + pub fn with_accounts(mut self, accounts: Vec) -> Self { + self.accounts = accounts; + self + } +} + +/// The error type for the EVM RPC server. +#[derive(Error, Debug)] +pub enum EthRpcError { + /// A [`ClientError`] wrapper error. + #[error("Client error: {0}")] + ClientError(#[from] ClientError), + /// A [`rlp::DecoderError`] wrapper error. + #[error("Decoding error: {0}")] + RlpError(#[from] rlp::DecoderError), + /// A Decimals conversion error. + #[error("Conversion error")] + ConversionError, + /// An invalid signature error. + #[error("Invalid signature")] + InvalidSignature, + /// The account was not found at the given address + #[error("Account not found for address {0:?}")] + AccountNotFound(H160), + /// Received an invalid transaction + #[error("Invalid transaction")] + InvalidTransaction, + /// Received an invalid transaction + #[error("Invalid transaction {0:?}")] + TransactionTypeNotSupported(Byte), +} + +impl From for ErrorObjectOwned { + fn from(value: EthRpcError) -> Self { + let code = match value { + EthRpcError::ClientError(_) => ErrorCode::InternalError, + _ => ErrorCode::InvalidRequest, + }; + Self::owned::(code.code(), value.to_string(), None) + } +} + +#[async_trait] +impl EthRpcServer for EthRpcServerImpl { + async fn net_version(&self) -> RpcResult { + Ok(self.client.chain_id().to_string()) + } + + async fn syncing(&self) -> RpcResult { + Ok(self.client.syncing().await?) + } + + async fn block_number(&self) -> RpcResult { + let number = self.client.block_number().await?; + Ok(number.into()) + } + + async fn get_transaction_receipt( + &self, + transaction_hash: H256, + ) -> RpcResult> { + let receipt = self.client.receipt(&transaction_hash).await; + Ok(receipt) + } + + async fn estimate_gas( + &self, + transaction: GenericTransaction, + _block: Option, + ) -> RpcResult { + let result = self.client.estimate_gas(&transaction, BlockTag::Latest.into()).await?; + Ok(result) + } + + async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult { + let tx = rlp::decode::(&transaction.0).map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to decode transaction: {err:?}"); + EthRpcError::from(err) + })?; + + let eth_addr = tx.recover_eth_address().map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to recover eth address: {err:?}"); + EthRpcError::InvalidSignature + })?; + + // Dry run the transaction to get the weight limit and storage deposit limit + let TransactionLegacyUnsigned { to, input, value, .. } = tx.transaction_legacy_unsigned; + let dry_run = self + .client + .dry_run( + &GenericTransaction { + from: Some(eth_addr), + input: Some(input.clone()), + to, + value: Some(value), + ..Default::default() + }, + BlockTag::Latest.into(), + ) + .await?; + + let EthContractResult { gas_limit, storage_deposit, .. } = dry_run; + let call = subxt_client::tx().revive().eth_transact( + transaction.0, + gas_limit.into(), + storage_deposit, + ); + let ext = self.client.tx().create_unsigned(&call).map_err(ClientError::from)?; + let hash = ext.submit().await.map_err(|err| EthRpcError::ClientError(err.into()))?; + + Ok(hash) + } + + async fn send_transaction(&self, transaction: GenericTransaction) -> RpcResult { + log::debug!(target: LOG_TARGET, "{transaction:#?}"); + let GenericTransaction { from, gas, gas_price, input, to, value, r#type, .. } = transaction; + + let Some(from) = from else { + log::debug!(target: LOG_TARGET, "Transaction must have a sender"); + return Err(EthRpcError::InvalidTransaction.into()); + }; + + let account = self + .accounts + .iter() + .find(|account| account.address() == from) + .ok_or(EthRpcError::AccountNotFound(from))?; + + let gas_price = gas_price.unwrap_or_else(|| U256::from(GAS_PRICE)); + let chain_id = Some(self.client.chain_id().into()); + let input = input.unwrap_or_default(); + let value = value.unwrap_or_default(); + let r#type = r#type.unwrap_or_default(); + + let Some(gas) = gas else { + log::debug!(target: LOG_TARGET, "Transaction must have a gas limit"); + return Err(EthRpcError::InvalidTransaction.into()); + }; + + let r#type = Type0::try_from_byte(r#type.clone()) + .map_err(|_| EthRpcError::TransactionTypeNotSupported(r#type))?; + + let nonce = self.get_transaction_count(from, BlockTag::Latest.into()).await?; + + let tx = + TransactionLegacyUnsigned { chain_id, gas, gas_price, input, nonce, to, value, r#type }; + let tx = account.sign_transaction(tx); + let rlp_bytes = rlp::encode(&tx).to_vec(); + self.send_raw_transaction(Bytes(rlp_bytes)).await + } + + async fn get_block_by_hash( + &self, + block_hash: H256, + _hydrated_transactions: bool, + ) -> RpcResult> { + let Some(block) = self.client.block_by_hash(&block_hash).await? else { + return Ok(None); + }; + let block = self.client.evm_block(block).await?; + Ok(Some(block)) + } + + async fn get_balance(&self, address: H160, block: BlockNumberOrTagOrHash) -> RpcResult { + let balance = self.client.balance(address, &block).await?; + log::debug!(target: LOG_TARGET, "balance({address}): {balance:?}"); + Ok(balance) + } + + async fn chain_id(&self) -> RpcResult { + Ok(self.client.chain_id().into()) + } + + async fn gas_price(&self) -> RpcResult { + Ok(U256::from(GAS_PRICE)) + } + + async fn get_code(&self, address: H160, block: BlockNumberOrTagOrHash) -> RpcResult { + let code = self.client.get_contract_code(&address, block).await?; + Ok(code.into()) + } + + async fn accounts(&self) -> RpcResult> { + Ok(self.accounts.iter().map(|account| account.address()).collect()) + } + + async fn call( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult { + let dry_run = self + .client + .dry_run(&transaction, block.unwrap_or_else(|| BlockTag::Latest.into())) + .await?; + let output = dry_run.result.map_err(|err| { + log::debug!(target: LOG_TARGET, "Dry run failed: {err:?}"); + ClientError::DryRunFailed + })?; + + Ok(output.into()) + } + + async fn get_block_by_number( + &self, + block: BlockNumberOrTag, + _hydrated_transactions: bool, + ) -> RpcResult> { + let Some(block) = self.client.block_by_number_or_tag(&block).await? else { + return Ok(None); + }; + let block = self.client.evm_block(block).await?; + Ok(Some(block)) + } + + async fn get_block_transaction_count_by_hash( + &self, + block_hash: Option, + ) -> RpcResult> { + let block_hash = if let Some(block_hash) = block_hash { + block_hash + } else { + self.client.latest_block().await.ok_or(ClientError::BlockNotFound)?.hash() + }; + Ok(self.client.receipts_count_per_block(&block_hash).await.map(U256::from)) + } + + async fn get_block_transaction_count_by_number( + &self, + block: Option, + ) -> RpcResult> { + let Some(block) = self + .get_block_by_number(block.unwrap_or_else(|| BlockTag::Latest.into()), false) + .await? + else { + return Ok(None); + }; + + Ok(self.client.receipts_count_per_block(&block.hash).await.map(U256::from)) + } + + async fn get_storage_at( + &self, + address: H160, + storage_slot: U256, + block: BlockNumberOrTagOrHash, + ) -> RpcResult { + let bytes = self.client.get_contract_storage(address, storage_slot, block).await?; + Ok(bytes.into()) + } + + async fn get_transaction_by_block_hash_and_index( + &self, + block_hash: H256, + transaction_index: U256, + ) -> RpcResult> { + let Some(receipt) = + self.client.receipt_by_hash_and_index(&block_hash, &transaction_index).await + else { + return Ok(None); + }; + + let Some(signed_tx) = self.client.signed_tx_by_hash(&receipt.transaction_hash).await else { + return Ok(None); + }; + + Ok(Some(TransactionInfo::new(receipt, signed_tx))) + } + + async fn get_transaction_by_block_number_and_index( + &self, + block: BlockNumberOrTag, + transaction_index: U256, + ) -> RpcResult> { + let Some(block) = self.client.block_by_number_or_tag(&block).await? else { + return Ok(None); + }; + self.get_transaction_by_block_hash_and_index(block.hash(), transaction_index) + .await + } + + async fn get_transaction_by_hash( + &self, + transaction_hash: H256, + ) -> RpcResult> { + let receipt = self.client.receipt(&transaction_hash).await; + let signed_tx = self.client.signed_tx_by_hash(&transaction_hash).await; + if let (Some(receipt), Some(signed_tx)) = (receipt, signed_tx) { + return Ok(Some(TransactionInfo::new(receipt, signed_tx))); + } + + Ok(None) + } + + async fn get_transaction_count( + &self, + address: H160, + block: BlockNumberOrTagOrHash, + ) -> RpcResult { + let nonce = self.client.nonce(address, block).await?; + Ok(nonce.into()) + } +} + +/// A [`MiscRpcServer`] RPC server implementation. +pub struct MiscRpcServerImpl; + +#[async_trait] +impl MiscRpcServer for MiscRpcServerImpl { + async fn healthcheck(&self) -> RpcResult<()> { + Ok(()) + } +} diff --git a/substrate/frame/revive/rpc/src/main.rs b/substrate/frame/revive/rpc/src/main.rs new file mode 100644 index 000000000000..5dbaeba899b2 --- /dev/null +++ b/substrate/frame/revive/rpc/src/main.rs @@ -0,0 +1,151 @@ +// 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. +//! The Ethereum JSON-RPC server. +use clap::Parser; +use hyper::Method; +use jsonrpsee::{ + http_client::HttpClientBuilder, + server::{RpcModule, Server}, +}; +use pallet_revive_eth_rpc::{ + client::Client, EthRpcClient, EthRpcServer, EthRpcServerImpl, MiscRpcServer, MiscRpcServerImpl, + LOG_TARGET, +}; +use std::net::SocketAddr; +use tower_http::cors::{Any, CorsLayer}; +use tracing_subscriber::{util::SubscriberInitExt, EnvFilter, FmtSubscriber}; + +// Parsed command instructions from the command line +#[derive(Parser)] +#[clap(author, about, version)] +struct CliCommand { + /// The server address to bind to + #[clap(long, default_value = "127.0.0.1:9090")] + url: String, + + /// The node url to connect to + #[clap(long, default_value = "ws://127.0.0.1:9944")] + node_url: String, +} + +/// Initialize tracing +fn init_tracing() { + let env_filter = + EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("eth_rpc=trace")); + + FmtSubscriber::builder() + .with_env_filter(env_filter) + .finish() + .try_init() + .expect("failed to initialize tracing"); +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let CliCommand { url, node_url } = CliCommand::parse(); + init_tracing(); + + let client = Client::from_url(&node_url).await?; + let mut updates = client.updates.clone(); + + let server_addr = run_server(client, &url).await?; + log::info!(target: LOG_TARGET, "Server started on: {}", server_addr); + + let url = format!("http://{}", server_addr); + let client = HttpClientBuilder::default().build(url)?; + + let response = client.block_number().await?; + log::info!(target: LOG_TARGET, "client initialized with block number {:?}", response); + + // keep running server until ctrl-c or client subscription fails + let _ = updates.wait_for(|_| false).await; + Ok(()) +} + +#[cfg(feature = "dev")] +mod dev { + use crate::LOG_TARGET; + use futures::{future::BoxFuture, FutureExt}; + use jsonrpsee::{server::middleware::rpc::RpcServiceT, types::Request, MethodResponse}; + + /// Dev Logger middleware, that logs the method and params of the request, along with the + /// success of the response. + #[derive(Clone)] + pub struct DevLogger(pub S); + + impl<'a, S> RpcServiceT<'a> for DevLogger + where + S: RpcServiceT<'a> + Send + Sync + Clone + 'static, + { + type Future = BoxFuture<'a, MethodResponse>; + + fn call(&self, req: Request<'a>) -> Self::Future { + let service = self.0.clone(); + let method = req.method.clone(); + let params = req.params.clone().unwrap_or_default(); + + async move { + log::info!(target: LOG_TARGET, "method: {method} params: {params}"); + let resp = service.call(req).await; + if resp.is_success() { + log::info!(target: LOG_TARGET, "✅ rpc: {method}"); + } else { + log::info!(target: LOG_TARGET, "❌ rpc: {method} {}", resp.as_result()); + } + resp + } + .boxed() + } + } +} + +/// Starts the rpc server and returns the server address. +async fn run_server(client: Client, url: &str) -> anyhow::Result { + let cors = CorsLayer::new() + .allow_methods([Method::POST]) + .allow_origin(Any) + .allow_headers([hyper::header::CONTENT_TYPE]); + let cors_middleware = tower::ServiceBuilder::new().layer(cors); + + let builder = Server::builder().set_http_middleware(cors_middleware); + + #[cfg(feature = "dev")] + let builder = builder + .set_rpc_middleware(jsonrpsee::server::RpcServiceBuilder::new().layer_fn(dev::DevLogger)); + + let server = builder.build(url.parse::()?).await?; + let addr = server.local_addr()?; + + let eth_api = EthRpcServerImpl::new(client) + .with_accounts(if cfg!(feature = "dev") { + use pallet_revive::evm::Account; + vec![Account::default()] + } else { + vec![] + }) + .into_rpc(); + let misc_api = MiscRpcServerImpl.into_rpc(); + + let mut module = RpcModule::new(()); + module.merge(eth_api)?; + module.merge(misc_api)?; + + let handle = server.start(module); + tokio::spawn(handle.stopped()); + + Ok(addr) +} diff --git a/substrate/frame/revive/rpc/src/rpc_methods_gen.rs b/substrate/frame/revive/rpc/src/rpc_methods_gen.rs new file mode 100644 index 000000000000..339080368969 --- /dev/null +++ b/substrate/frame/revive/rpc/src/rpc_methods_gen.rs @@ -0,0 +1,160 @@ +// 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. +//! Generated JSON-RPC methods. +#![allow(missing_docs)] + +use super::*; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[rpc(server, client)] +pub trait EthRpc { + /// Returns a list of addresses owned by client. + #[method(name = "eth_accounts")] + async fn accounts(&self) -> RpcResult>; + + /// Returns the number of most recent block. + #[method(name = "eth_blockNumber")] + async fn block_number(&self) -> RpcResult; + + /// Executes a new message call immediately without creating a transaction on the block chain. + #[method(name = "eth_call")] + async fn call( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult; + + /// Returns the chain ID of the current network. + #[method(name = "eth_chainId")] + async fn chain_id(&self) -> RpcResult; + + /// Generates and returns an estimate of how much gas is necessary to allow the transaction to + /// complete. + #[method(name = "eth_estimateGas")] + async fn estimate_gas( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult; + + /// Returns the current price per gas in wei. + #[method(name = "eth_gasPrice")] + async fn gas_price(&self) -> RpcResult; + + /// Returns the balance of the account of given address. + #[method(name = "eth_getBalance")] + async fn get_balance(&self, address: Address, block: BlockNumberOrTagOrHash) + -> RpcResult; + + /// Returns information about a block by hash. + #[method(name = "eth_getBlockByHash")] + async fn get_block_by_hash( + &self, + block_hash: H256, + hydrated_transactions: bool, + ) -> RpcResult>; + + /// Returns information about a block by number. + #[method(name = "eth_getBlockByNumber")] + async fn get_block_by_number( + &self, + block: BlockNumberOrTag, + hydrated_transactions: bool, + ) -> RpcResult>; + + /// Returns the number of transactions in a block from a block matching the given block hash. + #[method(name = "eth_getBlockTransactionCountByHash")] + async fn get_block_transaction_count_by_hash( + &self, + block_hash: Option, + ) -> RpcResult>; + + /// Returns the number of transactions in a block matching the given block number. + #[method(name = "eth_getBlockTransactionCountByNumber")] + async fn get_block_transaction_count_by_number( + &self, + block: Option, + ) -> RpcResult>; + + /// Returns code at a given address. + #[method(name = "eth_getCode")] + async fn get_code(&self, address: Address, block: BlockNumberOrTagOrHash) -> RpcResult; + + /// Returns the value from a storage position at a given address. + #[method(name = "eth_getStorageAt")] + async fn get_storage_at( + &self, + address: Address, + storage_slot: U256, + block: BlockNumberOrTagOrHash, + ) -> RpcResult; + + /// Returns information about a transaction by block hash and transaction index position. + #[method(name = "eth_getTransactionByBlockHashAndIndex")] + async fn get_transaction_by_block_hash_and_index( + &self, + block_hash: H256, + transaction_index: U256, + ) -> RpcResult>; + + /// Returns information about a transaction by block number and transaction index position. + #[method(name = "eth_getTransactionByBlockNumberAndIndex")] + async fn get_transaction_by_block_number_and_index( + &self, + block: BlockNumberOrTag, + transaction_index: U256, + ) -> RpcResult>; + + /// Returns the information about a transaction requested by transaction hash. + #[method(name = "eth_getTransactionByHash")] + async fn get_transaction_by_hash( + &self, + transaction_hash: H256, + ) -> RpcResult>; + + /// Returns the number of transactions sent from an address. + #[method(name = "eth_getTransactionCount")] + async fn get_transaction_count( + &self, + address: Address, + block: BlockNumberOrTagOrHash, + ) -> RpcResult; + + /// Returns the receipt of a transaction by transaction hash. + #[method(name = "eth_getTransactionReceipt")] + async fn get_transaction_receipt( + &self, + transaction_hash: H256, + ) -> RpcResult>; + + /// Submits a raw transaction. For EIP-4844 transactions, the raw form must be the network form. + /// This means it includes the blobs, KZG commitments, and KZG proofs. + #[method(name = "eth_sendRawTransaction")] + async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult; + + /// Signs and submits a transaction. + #[method(name = "eth_sendTransaction")] + async fn send_transaction(&self, transaction: GenericTransaction) -> RpcResult; + + /// Returns an object with data about the sync status or false. + #[method(name = "eth_syncing")] + async fn syncing(&self) -> RpcResult; + + /// The string value of current network id + #[method(name = "net_version")] + async fn net_version(&self) -> RpcResult; +} diff --git a/substrate/frame/revive/rpc/src/subxt_client.rs b/substrate/frame/revive/rpc/src/subxt_client.rs new file mode 100644 index 000000000000..359fe62e4e4c --- /dev/null +++ b/substrate/frame/revive/rpc/src/subxt_client.rs @@ -0,0 +1,69 @@ +// 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. +//! The generated subxt client. +use subxt::config::{signed_extensions, Config, PolkadotConfig}; + +#[subxt::subxt( + runtime_metadata_path = "kitchensink.scale", + substitute_type( + path = "pallet_revive::primitives::EthContractResult", + with = "::subxt::utils::Static<::pallet_revive::EthContractResult>" + ), + substitute_type( + path = "sp_weights::weight_v2::Weight", + with = "::subxt::utils::Static<::sp_weights::Weight>" + ) +)] +mod src_chain {} +pub use src_chain::*; + +/// The configuration for the source chain. +pub enum SrcChainConfig {} +impl Config for SrcChainConfig { + type Hash = sp_core::H256; + type AccountId = ::AccountId; + type Address = ::Address; + type Signature = ::Signature; + type Hasher = BlakeTwo256; + type Header = subxt::config::substrate::SubstrateHeader; + type AssetId = ::AssetId; + type ExtrinsicParams = signed_extensions::AnyOf< + Self, + ( + signed_extensions::CheckSpecVersion, + signed_extensions::CheckTxVersion, + signed_extensions::CheckNonce, + signed_extensions::CheckGenesis, + signed_extensions::CheckMortality, + signed_extensions::ChargeAssetTxPayment, + signed_extensions::ChargeTransactionPayment, + signed_extensions::CheckMetadataHash, + ), + >; +} + +/// A type that can hash values using the blaks2_256 algorithm. +/// TODO remove once subxt is updated +#[derive(Debug, Clone, Copy, PartialEq, Eq, codec::Encode)] +pub struct BlakeTwo256; + +impl subxt::config::Hasher for BlakeTwo256 { + type Output = sp_core::H256; + fn hash(s: &[u8]) -> Self::Output { + sp_crypto_hashing::blake2_256(s).into() + } +} diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 9b45d0279185..fb7b891d91ba 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -148,7 +148,6 @@ std = [ "pallet-tx-pause?/std", "pallet-uniques?/std", "pallet-utility?/std", - "pallet-verify-signature?/std", "pallet-vesting?/std", "pallet-whitelist?/std", "pallet-xcm-benchmarks?/std", @@ -252,7 +251,6 @@ runtime-benchmarks = [ "frame-system?/runtime-benchmarks", "pallet-alliance?/runtime-benchmarks", "pallet-asset-conversion-ops?/runtime-benchmarks", - "pallet-asset-conversion-tx-payment?/runtime-benchmarks", "pallet-asset-conversion?/runtime-benchmarks", "pallet-asset-rate?/runtime-benchmarks", "pallet-asset-tx-payment?/runtime-benchmarks", @@ -323,13 +321,11 @@ runtime-benchmarks = [ "pallet-sudo?/runtime-benchmarks", "pallet-timestamp?/runtime-benchmarks", "pallet-tips?/runtime-benchmarks", - "pallet-transaction-payment?/runtime-benchmarks", "pallet-transaction-storage?/runtime-benchmarks", "pallet-treasury?/runtime-benchmarks", "pallet-tx-pause?/runtime-benchmarks", "pallet-uniques?/runtime-benchmarks", "pallet-utility?/runtime-benchmarks", - "pallet-verify-signature?/runtime-benchmarks", "pallet-vesting?/runtime-benchmarks", "pallet-whitelist?/runtime-benchmarks", "pallet-xcm-benchmarks?/runtime-benchmarks", @@ -464,7 +460,6 @@ try-runtime = [ "pallet-tx-pause?/try-runtime", "pallet-uniques?/try-runtime", "pallet-utility?/try-runtime", - "pallet-verify-signature?/try-runtime", "pallet-vesting?/try-runtime", "pallet-whitelist?/try-runtime", "pallet-xcm-bridge-hub-router?/try-runtime", @@ -540,7 +535,7 @@ with-tracing = [ "sp-tracing?/with-tracing", "sp-tracing?/with-tracing", ] -runtime-full = ["assets-common", "binary-merkle-tree", "bp-header-chain", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-assets-freezer", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-revive", "pallet-revive-fixtures", "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-verify-signature", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "xcm-procedural", "xcm-runtime-apis"] +runtime-full = ["assets-common", "binary-merkle-tree", "bp-header-chain", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-assets-freezer", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-revive", "pallet-revive-fixtures", "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "xcm-procedural", "xcm-runtime-apis"] runtime = [ "frame-benchmarking", "frame-benchmarking-pallet-pov", @@ -604,7 +599,7 @@ runtime = [ "sp-wasm-interface", "sp-weights", ] -node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-revive-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", "polkadot-node-core-candidate-validation", "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-omni-node-lib", "polkadot-overseer", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] +node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-revive-eth-rpc", "pallet-revive-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", "polkadot-node-core-candidate-validation", "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-omni-node-lib", "polkadot-overseer", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] tuples-96 = [ "frame-support-procedural?/tuples-96", "frame-support?/tuples-96", @@ -1336,11 +1331,6 @@ path = "../substrate/frame/utility" default-features = false optional = true -[dependencies.pallet-verify-signature] -path = "../substrate/frame/verify-signature" -default-features = false -optional = true - [dependencies.pallet-vesting] path = "../substrate/frame/vesting" default-features = false @@ -1901,6 +1891,11 @@ path = "../substrate/frame/contracts/mock-network" default-features = false optional = true +[dependencies.pallet-revive-eth-rpc] +path = "../substrate/frame/revive/rpc" +default-features = false +optional = true + [dependencies.pallet-revive-mock-network] path = "../substrate/frame/revive/mock-network" default-features = false diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs index f3fc949c66ec..90908d205325 100644 --- a/umbrella/src/lib.rs +++ b/umbrella/src/lib.rs @@ -580,6 +580,10 @@ pub use pallet_remark; #[cfg(feature = "pallet-revive")] pub use pallet_revive; +/// An Ethereum JSON-RPC server for pallet-revive. +#[cfg(feature = "pallet-revive-eth-rpc")] +pub use pallet_revive_eth_rpc; + /// Fixtures for testing and benchmarking. #[cfg(feature = "pallet-revive-fixtures")] pub use pallet_revive_fixtures; @@ -705,10 +709,6 @@ pub use pallet_uniques; #[cfg(feature = "pallet-utility")] pub use pallet_utility; -/// FRAME verify signature pallet. -#[cfg(feature = "pallet-verify-signature")] -pub use pallet_verify_signature; - /// FRAME pallet for manage vesting. #[cfg(feature = "pallet-vesting")] pub use pallet_vesting; From 5f88ef16d522e37fef811222593e3124af71ca84 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 09:50:10 +0200 Subject: [PATCH 137/174] mv prdoc --- prdoc/{pr_5953.prdoc => pr_6147.prdoc} | 1 + 1 file changed, 1 insertion(+) rename prdoc/{pr_5953.prdoc => pr_6147.prdoc} (99%) diff --git a/prdoc/pr_5953.prdoc b/prdoc/pr_6147.prdoc similarity index 99% rename from prdoc/pr_5953.prdoc rename to prdoc/pr_6147.prdoc index 498675df6520..13240b7ace4b 100644 --- a/prdoc/pr_5953.prdoc +++ b/prdoc/pr_6147.prdoc @@ -9,3 +9,4 @@ crates: bump: patch - name: pallet-revive-fixtures bump: patch + From 2f3122f1063f328cac38d738886ce422459c0f36 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 09:52:36 +0200 Subject: [PATCH 138/174] fix-up Cargo.toml --- Cargo.toml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d265f1a586f4..5761c1fbccd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -347,6 +347,7 @@ members = [ "substrate/frame/election-provider-support/solution-type/fuzzer", "substrate/frame/elections-phragmen", "substrate/frame/examples", + "substrate/frame/examples/authorization-tx-extension", "substrate/frame/examples/basic", "substrate/frame/examples/default-config", "substrate/frame/examples/dev-mode", @@ -443,6 +444,7 @@ members = [ "substrate/frame/tx-pause", "substrate/frame/uniques", "substrate/frame/utility", + "substrate/frame/verify-signature", "substrate/frame/vesting", "substrate/frame/whitelist", "substrate/primitives/api", @@ -588,6 +590,7 @@ alloy-primitives = { version = "0.4.2", default-features = false } alloy-sol-types = { version = "0.4.2", default-features = false } always-assert = { version = "0.1" } anyhow = { version = "1.0.81", default-features = false } +approx = { version = "0.5.1" } aquamarine = { version = "0.5.0" } arbitrary = { version = "1.3.2" } ark-bls12-377 = { version = "0.4.0", default-features = false } @@ -915,6 +918,7 @@ pallet-dev-mode = { path = "substrate/frame/examples/dev-mode", default-features pallet-election-provider-multi-phase = { path = "substrate/frame/election-provider-multi-phase", default-features = false } pallet-election-provider-support-benchmarking = { path = "substrate/frame/election-provider-support/benchmarking", default-features = false } pallet-elections-phragmen = { path = "substrate/frame/elections-phragmen", default-features = false } +pallet-example-authorization-tx-extension = { path = "substrate/frame/examples/authorization-tx-extension", default-features = false } pallet-example-basic = { path = "substrate/frame/examples/basic", default-features = false } pallet-example-frame-crate = { path = "substrate/frame/examples/frame-crate", default-features = false } pallet-example-kitchensink = { path = "substrate/frame/examples/kitchensink", default-features = false } @@ -992,6 +996,7 @@ pallet-treasury = { path = "substrate/frame/treasury", default-features = false pallet-tx-pause = { default-features = false, path = "substrate/frame/tx-pause" } pallet-uniques = { path = "substrate/frame/uniques", default-features = false } pallet-utility = { path = "substrate/frame/utility", default-features = false } +pallet-verify-signature = { path = "substrate/frame/verify-signature", default-features = false } pallet-vesting = { path = "substrate/frame/vesting", default-features = false } pallet-whitelist = { path = "substrate/frame/whitelist", default-features = false } pallet-xcm = { path = "polkadot/xcm/pallet-xcm", default-features = false } @@ -1017,7 +1022,7 @@ people-rococo-runtime = { path = "cumulus/parachains/runtimes/people/people-roco people-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend" } people-westend-runtime = { path = "cumulus/parachains/runtimes/people/people-westend" } pin-project = { version = "1.1.3" } -platforms = { version = "3.0" } +platforms = { version = "3.4" } polkadot-approval-distribution = { path = "polkadot/node/network/approval-distribution", default-features = false } polkadot-availability-bitfield-distribution = { path = "polkadot/node/network/bitfield-distribution", default-features = false } polkadot-availability-distribution = { path = "polkadot/node/network/availability-distribution", default-features = false } @@ -1322,7 +1327,7 @@ tiny-keccak = { version = "2.0.2" } tokio = { version = "1.40.0", default-features = false } tokio-retry = { version = "0.3.0" } tokio-stream = { version = "0.1.14" } -tokio-test = { version = "0.4.2" } +tokio-test = { version = "0.4.4" } tokio-tungstenite = { version = "0.20.1" } tokio-util = { version = "0.7.8" } toml = { version = "0.8.12" } From d5e132dbc4ebe9af7df894f519d055006acf7b11 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 09:55:09 +0200 Subject: [PATCH 139/174] fix up cargo.toml --- Cargo.lock | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + 2 files changed, 157 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9b55f50c0ec..6d2dbac6858a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,6 +119,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "allocator-api2" version = "0.2.16" @@ -1149,6 +1164,22 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-compression" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd 0.13.0", + "zstd-safe 7.0.0", +] + [[package]] name = "async-executor" version = "1.5.1" @@ -2581,6 +2612,27 @@ dependencies = [ "tuplex", ] +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bs58" version = "0.5.1" @@ -7417,6 +7469,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +[[package]] +name = "http-range-header" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" + [[package]] name = "httparse" version = "1.8.0" @@ -7896,6 +7954,16 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "iri-string" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0f0a572e8ffe56e2ff4f769f32ffe919282c3916799f8b68688b6030063bea" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -9679,6 +9747,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -12468,6 +12546,40 @@ dependencies = [ "subxt-signer", ] +[[package]] +name = "pallet-revive-eth-rpc" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap 4.5.13", + "env_logger 0.11.3", + "futures", + "hex", + "hex-literal", + "hyper 1.3.1", + "jsonrpsee 0.24.3", + "log", + "pallet-revive", + "pallet-revive-fixtures", + "parity-scale-codec", + "rlp 0.6.1", + "sc-rpc", + "scale-info", + "secp256k1", + "serde_json", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", + "subxt", + "subxt-signer", + "thiserror", + "tokio", + "tower", + "tower-http 0.5.2", + "tracing-subscriber 0.3.18", +] + [[package]] name = "pallet-revive-fixtures" version = "0.1.0" @@ -15391,6 +15503,7 @@ dependencies = [ "pallet-referenda", "pallet-remark", "pallet-revive", + "pallet-revive-eth-rpc", "pallet-revive-fixtures", "pallet-revive-mock-network", "pallet-revive-proc-macro", @@ -15422,7 +15535,6 @@ dependencies = [ "pallet-tx-pause", "pallet-uniques", "pallet-utility", - "pallet-verify-signature", "pallet-vesting", "pallet-whitelist", "pallet-xcm", @@ -25132,7 +25244,7 @@ dependencies = [ "futures-util", "http 0.2.9", "http-body 0.4.5", - "http-range-header", + "http-range-header 0.3.1", "mime", "pin-project-lite", "tower-layer", @@ -25146,14 +25258,29 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ + "async-compression", + "base64 0.21.7", "bitflags 2.6.0", "bytes", + "futures-core", + "futures-util", "http 1.1.0", "http-body 1.0.0", "http-body-util", + "http-range-header 0.4.1", + "httpdate", + "iri-string", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", + "tokio", + "tokio-util", + "tower", "tower-layer", "tower-service", + "tracing", + "uuid", ] [[package]] @@ -25570,6 +25697,15 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -27410,6 +27546,15 @@ dependencies = [ "zstd-safe 6.0.6", ] +[[package]] +name = "zstd" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +dependencies = [ + "zstd-safe 7.0.0", +] + [[package]] name = "zstd-safe" version = "5.0.2+zstd.1.5.2" @@ -27430,6 +27575,15 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.8+zstd.1.5.5" diff --git a/Cargo.toml b/Cargo.toml index 5761c1fbccd4..3c4d199113ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -684,6 +684,7 @@ color-print = { version = "0.3.4" } colored = { version = "2.0.4" } comfy-table = { version = "7.1.0", default-features = false } console = { version = "0.15.8" } +const-hex = { version = "1.10.0", default-features = false } contracts-rococo-runtime = { path = "cumulus/parachains/runtimes/contracts/contracts-rococo" } coretime-rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo" } coretime-rococo-runtime = { path = "cumulus/parachains/runtimes/coretime/coretime-rococo" } From d07c790c787970672f069dfded676ded5307230e Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 10:20:31 +0200 Subject: [PATCH 140/174] fixup --- Cargo.lock | 1 + substrate/frame/revive/Cargo.toml | 1 + umbrella/Cargo.toml | 12 +++++++++++- umbrella/src/lib.rs | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 6d2dbac6858a..820155b33dfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15535,6 +15535,7 @@ dependencies = [ "pallet-tx-pause", "pallet-uniques", "pallet-utility", + "pallet-verify-signature", "pallet-vesting", "pallet-whitelist", "pallet-xcm", diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 501353a02f1a..f54e9e8a63de 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -131,6 +131,7 @@ runtime-benchmarks = [ "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks" ] try-runtime = [ "frame-support/try-runtime", diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index fb7b891d91ba..d2acee137b5b 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -148,6 +148,7 @@ std = [ "pallet-tx-pause?/std", "pallet-uniques?/std", "pallet-utility?/std", + "pallet-verify-signature?/std", "pallet-vesting?/std", "pallet-whitelist?/std", "pallet-xcm-benchmarks?/std", @@ -251,6 +252,7 @@ runtime-benchmarks = [ "frame-system?/runtime-benchmarks", "pallet-alliance?/runtime-benchmarks", "pallet-asset-conversion-ops?/runtime-benchmarks", + "pallet-asset-conversion-tx-payment?/runtime-benchmarks", "pallet-asset-conversion?/runtime-benchmarks", "pallet-asset-rate?/runtime-benchmarks", "pallet-asset-tx-payment?/runtime-benchmarks", @@ -321,11 +323,13 @@ runtime-benchmarks = [ "pallet-sudo?/runtime-benchmarks", "pallet-timestamp?/runtime-benchmarks", "pallet-tips?/runtime-benchmarks", + "pallet-transaction-payment?/runtime-benchmarks", "pallet-transaction-storage?/runtime-benchmarks", "pallet-treasury?/runtime-benchmarks", "pallet-tx-pause?/runtime-benchmarks", "pallet-uniques?/runtime-benchmarks", "pallet-utility?/runtime-benchmarks", + "pallet-verify-signature?/runtime-benchmarks", "pallet-vesting?/runtime-benchmarks", "pallet-whitelist?/runtime-benchmarks", "pallet-xcm-benchmarks?/runtime-benchmarks", @@ -460,6 +464,7 @@ try-runtime = [ "pallet-tx-pause?/try-runtime", "pallet-uniques?/try-runtime", "pallet-utility?/try-runtime", + "pallet-verify-signature?/try-runtime", "pallet-vesting?/try-runtime", "pallet-whitelist?/try-runtime", "pallet-xcm-bridge-hub-router?/try-runtime", @@ -535,7 +540,7 @@ with-tracing = [ "sp-tracing?/with-tracing", "sp-tracing?/with-tracing", ] -runtime-full = ["assets-common", "binary-merkle-tree", "bp-header-chain", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-assets-freezer", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-revive", "pallet-revive-fixtures", "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "xcm-procedural", "xcm-runtime-apis"] +runtime-full = ["assets-common", "binary-merkle-tree", "bp-header-chain", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-assets-freezer", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-revive", "pallet-revive-fixtures", "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-verify-signature", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "xcm-procedural", "xcm-runtime-apis"] runtime = [ "frame-benchmarking", "frame-benchmarking-pallet-pov", @@ -1331,6 +1336,11 @@ path = "../substrate/frame/utility" default-features = false optional = true +[dependencies.pallet-verify-signature] +path = "../substrate/frame/verify-signature" +default-features = false +optional = true + [dependencies.pallet-vesting] path = "../substrate/frame/vesting" default-features = false diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs index 90908d205325..2216864fad0f 100644 --- a/umbrella/src/lib.rs +++ b/umbrella/src/lib.rs @@ -709,6 +709,10 @@ pub use pallet_uniques; #[cfg(feature = "pallet-utility")] pub use pallet_utility; +/// FRAME verify signature pallet. +#[cfg(feature = "pallet-verify-signature")] +pub use pallet_verify_signature; + /// FRAME pallet for manage vesting. #[cfg(feature = "pallet-vesting")] pub use pallet_vesting; From 744eef71c13a2900eb392680c082d4bcf1940420 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 16:39:32 +0200 Subject: [PATCH 141/174] fix --- .../revive/rpc/examples/rust/extrinsic.rs | 11 +++++++++-- substrate/frame/revive/rpc/kitchensink.scale | Bin 651459 -> 651595 bytes substrate/frame/revive/rpc/src/client.rs | 12 ++++++------ substrate/frame/revive/rpc/src/lib.rs | 4 ++-- .../frame/revive/rpc/src/subxt_client.rs | 2 ++ 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs index 01cb5aaf978e..fae4d4a01dc8 100644 --- a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs +++ b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs @@ -14,6 +14,7 @@ // 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 crate::subxt_client::contracts::calls::types::InstantiateWithCode; use pallet_revive_eth_rpc::subxt_client::{self, SrcChainConfig}; use sp_weights::Weight; use subxt::OnlineClient; @@ -28,7 +29,7 @@ async fn main() -> Result<(), Box> { let tx_payload = subxt_client::tx().revive().instantiate_with_code( 0u32.into(), Weight::from_parts(100_000, 0).into(), - 3_000_000_000_000_000, + 3_000_000_000_000_000_000, bytes, vec![], None, @@ -38,9 +39,15 @@ async fn main() -> Result<(), Box> { .tx() .sign_and_submit_then_watch_default(&tx_payload, &dev::alice()) .await? - .wait_for_finalized_success() + .wait_for_finalized() .await?; println!("Transaction finalized: {:?}", res.extrinsic_hash()); + let block_hash = res.block_hash(); + + let block = client.blocks().at(block_hash).await.unwrap(); + let extrinsics = block.extrinsics().await.unwrap(); + let _ = extrinsics.find_first::()?; + Ok(()) } diff --git a/substrate/frame/revive/rpc/kitchensink.scale b/substrate/frame/revive/rpc/kitchensink.scale index 60c1834d3c7875d257a4bf1f3426a459a6f44cdc..eb77a690e4642ce59987cd64c8d1eaf1db4c672a 100644 GIT binary patch delta 400 zcmX^7Q2q2H^$l&pd@e4T#RZ8a$r-L?sd*)n`-St-gf_E_Ok|YdFi0y(%uS6it}HG| z%|+GJyi>G&rzj&3GXXI(5VHU=>-L?ZY&(UmCGv|h(=+oznHUe)gjiVxmFAUX=BE0C z1r-vD6(FpTqQuM+J1eVz#GIVel46Kpd#fhf_Et^y!_$;`WE@jcic*V<8Rs&o1ZSq_ zC6<&Hr80hGVR2<(U}2EuXLOw&eSlro5~@r`!5L_hf0~V}m6daTURq|losI%rpN@hn zmz9-kMM-L2ab|v=9RtvS$rqSJw(mQ@{(_OwWcu<$>6c4bMBBG$vTfg@$$oH}Fo%G1VonaDB@>G)0|N_#EI*^>^ce@( zWsQ7Gb4oHDQ&Ngji;Hy>K#Ft}z+%Cf>3NAIrA4Va3a(aGt`#LkiClIJK%J8>Fo|qu zI>`Qlkx^&*>qG1dnHX%R3mj!v+J5UWd%eK)!|qI?(`_!W3v6$^!X7Km=-7V$HT(Aa PuQ~Q@+rDKH=X5^+t_xJ4 diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index a40ba56e4481..ce0df8dba69a 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -359,16 +359,16 @@ impl Client { let rpc = inner.as_ref().rpc_client.clone(); loop { let reconnected = rpc.reconnect_initiated().await; - log::info!("RPC client connection lost"); + log::info!(target: LOG_TARGET, "RPC client connection lost"); let now = std::time::Instant::now(); reconnected.await; - log::info!("RPC client reconnection took `{}s`", now.elapsed().as_secs()); + log::info!(target: LOG_TARGET, "RPC client reconnection took `{}s`", now.elapsed().as_secs()); } } /// Subscribe to new blocks and update the cache. async fn subscribe_blocks(inner: Arc, tx: Sender<()>) -> Result<(), ClientError> { - log::info!("Subscribing to new blocks"); + log::info!(target: LOG_TARGET, "Subscribing to new blocks"); let mut block_stream = inner.as_ref().api.blocks().subscribe_finalized().await.inspect_err(|err| { log::error!("Failed to subscribe to blocks: {err:?}"); @@ -390,7 +390,7 @@ impl Client { }, }; - log::debug!("Pushing block: {}", block.number()); + log::trace!(target: LOG_TARGET, "Pushing block: {}", block.number()); let mut cache = inner.cache.write().await; let receipts = inner @@ -402,7 +402,7 @@ impl Client { .unwrap_or_default(); if !receipts.is_empty() { - log::debug!("Adding {} receipts", receipts.len()); + log::debug!(target: LOG_TARGET, "Adding {} receipts", receipts.len()); let values = receipts .iter() .map(|(hash, (_, receipt))| (receipt.transaction_index, *hash)) @@ -423,7 +423,7 @@ impl Client { tx.send_replace(()); } - log::info!("Block subscription ended"); + log::info!(target: LOG_TARGET, "Block subscription ended"); Ok(()) } diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index e740111d6591..d935a9a001db 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -161,10 +161,10 @@ impl EthRpcServer for EthRpcServerImpl { ) .await?; - let EthContractResult { gas_limit, storage_deposit, .. } = dry_run; + let EthContractResult { gas_required, storage_deposit, .. } = dry_run; let call = subxt_client::tx().revive().eth_transact( transaction.0, - gas_limit.into(), + gas_required.into(), storage_deposit, ); let ext = self.client.tx().create_unsigned(&call).map_err(ClientError::from)?; diff --git a/substrate/frame/revive/rpc/src/subxt_client.rs b/substrate/frame/revive/rpc/src/subxt_client.rs index 359fe62e4e4c..fc151730fcb2 100644 --- a/substrate/frame/revive/rpc/src/subxt_client.rs +++ b/substrate/frame/revive/rpc/src/subxt_client.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. //! The generated subxt client. +//! Generated with +//! subxt metadata --url ws://localhost:9944 -o rpc/kitchensink.scale use subxt::config::{signed_extensions, Config, PolkadotConfig}; #[subxt::subxt( From 56748fccc3609f0f4852e98daa6e4c8a2a36373a Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 22 Oct 2024 14:09:14 +0200 Subject: [PATCH 142/174] wip --- substrate/frame/revive/rpc/Cargo.toml | 5 +++ .../revive/rpc/examples/rust/extrinsic.rs | 2 +- .../rpc/examples/rust/remark-extrinsic.rs | 44 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml index 14ac93a5e032..4c9ec4c963f1 100644 --- a/substrate/frame/revive/rpc/Cargo.toml +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -32,6 +32,11 @@ name = "extrinsic" path = "examples/rust/extrinsic.rs" required-features = ["example"] +[[example]] +name = "remark-extrinsic" +path = "examples/rust/remark-extrinsic.rs" +required-features = ["example"] + [dependencies] clap = { workspace = true, features = ["derive"] } anyhow = { workspace = true } diff --git a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs index fae4d4a01dc8..d2456a4c32a7 100644 --- a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs +++ b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs @@ -14,7 +14,7 @@ // 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 crate::subxt_client::contracts::calls::types::InstantiateWithCode; +use crate::subxt_client::revive::calls::types::InstantiateWithCode; use pallet_revive_eth_rpc::subxt_client::{self, SrcChainConfig}; use sp_weights::Weight; use subxt::OnlineClient; diff --git a/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs new file mode 100644 index 000000000000..3eee8a252dd8 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs @@ -0,0 +1,44 @@ +// 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 crate::subxt_client::system::calls::types::Remark; +use pallet_revive_eth_rpc::subxt_client::{self, SrcChainConfig}; +use subxt::{blocks::FoundExtrinsic, OnlineClient}; +use subxt_signer::sr25519::dev; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = OnlineClient::::new().await?; + let tx_payload = subxt_client::tx().system().remark(b"bonjour".to_vec()); + let res = client + .tx() + .sign_and_submit_then_watch_default(&tx_payload, &dev::alice()) + .await? + .wait_for_finalized() + .await?; + + println!("Transaction finalized: {:?}", res.extrinsic_hash()); + let block_hash = res.block_hash(); + let block = client.blocks().at(block_hash).await.unwrap(); + let extrinsics = block.extrinsics().await.unwrap(); + let remarks = extrinsics + .find::() + .map(|remark| remark.unwrap().value) + .collect::>(); + + dbg!(remarks); + Ok(()) +} From 3262d34628a1c9c811fcedff69113f5da1ef8f72 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 22 Oct 2024 16:38:24 +0200 Subject: [PATCH 143/174] bump subxt --- Cargo.lock | 413 ++++++++++++++++++++++++++++++++++++++--------------- Cargo.toml | 2 +- 2 files changed, 300 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a42f5baa4765..ec2116f0b853 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,6 +119,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "allocator-api2" version = "0.2.16" @@ -168,7 +183,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", "syn-solidity", "tiny-keccak", ] @@ -295,7 +310,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -753,7 +768,7 @@ checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", "synstructure 0.13.1", ] @@ -776,7 +791,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -1149,6 +1164,22 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-compression" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd 0.13.0", + "zstd-safe 7.0.0", +] + [[package]] name = "async-executor" version = "1.5.1" @@ -1384,7 +1415,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -1401,7 +1432,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -1616,7 +1647,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -2581,6 +2612,27 @@ dependencies = [ "tuplex", ] +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bs58" version = "0.5.1" @@ -3057,7 +3109,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -4415,7 +4467,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -4968,7 +5020,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5008,7 +5060,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "scratch", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5025,7 +5077,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5073,7 +5125,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "strsim 0.11.1", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5095,7 +5147,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5212,7 +5264,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5223,7 +5275,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5234,7 +5286,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5342,7 +5394,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5403,7 +5455,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "regex", - "syn 2.0.82", + "syn 2.0.79", "termcolor", "toml 0.8.12", "walkdir", @@ -5635,7 +5687,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5655,7 +5707,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5666,7 +5718,7 @@ checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5881,7 +5933,7 @@ dependencies = [ "prettyplease", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -5953,7 +6005,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -6296,7 +6348,7 @@ dependencies = [ "quote 1.0.37", "scale-info", "sp-arithmetic 23.0.0", - "syn 2.0.82", + "syn 2.0.79", "trybuild", ] @@ -6511,7 +6563,7 @@ dependencies = [ "sp-metadata-ir 0.6.0", "sp-runtime 31.0.1", "static_assertions", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -6522,7 +6574,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -6531,7 +6583,7 @@ version = "11.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -6785,7 +6837,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -7417,6 +7469,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +[[package]] +name = "http-range-header" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" + [[package]] name = "httparse" version = "1.8.0" @@ -7452,7 +7510,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -7896,6 +7954,16 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "iri-string" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0f0a572e8ffe56e2ff4f769f32ffe919282c3916799f8b68688b6030063bea" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -8309,7 +8377,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -9063,7 +9131,7 @@ dependencies = [ "proc-macro-warning 0.4.2", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -9347,7 +9415,7 @@ dependencies = [ "parking_lot 0.12.3", "pin-project", "prost 0.12.6", - "prost-build", + "prost-build 0.13.2", "rand", "rcgen", "ring 0.16.20", @@ -9471,7 +9539,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -9485,7 +9553,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -9496,7 +9564,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -9507,7 +9575,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -9679,6 +9747,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -9844,7 +9922,7 @@ dependencies = [ "cfg-if", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -10449,7 +10527,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -10625,7 +10703,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11397,7 +11475,7 @@ version = "18.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -12468,6 +12546,40 @@ dependencies = [ "subxt-signer", ] +[[package]] +name = "pallet-revive-eth-rpc" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap 4.5.13", + "env_logger 0.11.3", + "futures", + "hex", + "hex-literal", + "hyper 1.3.1", + "jsonrpsee 0.24.3", + "log", + "pallet-revive", + "pallet-revive-fixtures", + "parity-scale-codec", + "rlp 0.6.1", + "sc-rpc", + "scale-info", + "secp256k1", + "serde_json", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", + "subxt", + "subxt-signer", + "thiserror", + "tokio", + "tower", + "tower-http 0.5.2", + "tracing-subscriber 0.3.18", +] + [[package]] name = "pallet-revive-fixtures" version = "0.1.0" @@ -12526,7 +12638,7 @@ version = "0.1.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -12771,7 +12883,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "sp-runtime 31.0.1", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -13786,7 +13898,7 @@ dependencies = [ "pest_meta", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -13827,7 +13939,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -15391,6 +15503,7 @@ dependencies = [ "pallet-referenda", "pallet-remark", "pallet-revive", + "pallet-revive-eth-rpc", "pallet-revive-fixtures", "pallet-revive-mock-network", "pallet-revive-proc-macro", @@ -16295,7 +16408,7 @@ dependencies = [ "polkavm-common 0.8.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16307,7 +16420,7 @@ dependencies = [ "polkavm-common 0.9.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16319,7 +16432,7 @@ dependencies = [ "polkavm-common 0.13.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16329,7 +16442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" dependencies = [ "polkavm-derive-impl 0.8.0", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16339,7 +16452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl 0.9.0", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16349,7 +16462,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f3ad876ca1855038c21d48cbe35164552208a54b21f8295a7d76bc33ef1e38" dependencies = [ "polkavm-derive-impl 0.13.0", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16566,7 +16679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2 1.0.86", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16671,7 +16784,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16682,7 +16795,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16763,7 +16876,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16828,6 +16941,27 @@ dependencies = [ "prost-derive 0.13.2", ] +[[package]] +name = "prost-build" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools 0.11.0", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost 0.12.6", + "prost-types 0.12.4", + "regex", + "syn 2.0.79", + "tempfile", +] + [[package]] name = "prost-build" version = "0.13.2" @@ -16836,16 +16970,16 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", "heck 0.4.1", - "itertools 0.10.5", + "itertools 0.11.0", "log", "multimap", "once_cell", "petgraph", "prettyplease", "prost 0.13.2", - "prost-types", + "prost-types 0.13.2", "regex", - "syn 2.0.82", + "syn 2.0.79", "tempfile", ] @@ -16869,10 +17003,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -16882,10 +17016,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", +] + +[[package]] +name = "prost-types" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" +dependencies = [ + "prost 0.12.6", ] [[package]] @@ -17345,7 +17488,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -17964,7 +18107,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.82", + "syn 2.0.79", "unicode-ident", ] @@ -18394,7 +18537,7 @@ dependencies = [ "multihash 0.19.1", "parity-scale-codec", "prost 0.12.6", - "prost-build", + "prost-build 0.12.4", "quickcheck", "rand", "sc-client-api", @@ -18492,7 +18635,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -19210,7 +19353,7 @@ dependencies = [ "partial_sort", "pin-project", "prost 0.12.6", - "prost-build", + "prost-build 0.12.4", "rand", "sc-block-builder", "sc-client-api", @@ -19255,7 +19398,7 @@ dependencies = [ "futures", "libp2p-identity", "parity-scale-codec", - "prost-build", + "prost-build 0.12.4", "sc-consensus", "sc-network-types", "sp-consensus", @@ -19297,7 +19440,7 @@ dependencies = [ "log", "parity-scale-codec", "prost 0.12.6", - "prost-build", + "prost-build 0.12.4", "sc-client-api", "sc-network", "sc-network-types", @@ -19340,7 +19483,7 @@ dependencies = [ "mockall 0.11.4", "parity-scale-codec", "prost 0.12.6", - "prost-build", + "prost-build 0.12.4", "quickcheck", "sc-block-builder", "sc-client-api", @@ -19854,7 +19997,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -20037,7 +20180,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "scale-info", - "syn 2.0.82", + "syn 2.0.79", "thiserror", ] @@ -20359,7 +20502,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -20384,9 +20527,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "indexmap 2.2.3", "itoa", @@ -20461,7 +20604,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -21432,7 +21575,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -21447,7 +21590,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -21786,7 +21929,7 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "impl-serde 0.5.0", + "impl-serde 0.4.0", "itertools 0.11.0", "k256", "libsecp256k1", @@ -22057,7 +22200,7 @@ version = "0.1.0" dependencies = [ "quote 1.0.37", "sp-crypto-hashing 0.1.0", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -22068,7 +22211,7 @@ checksum = "b85d0f1f1e44bd8617eb2a48203ee854981229e3e79e6f468c7175d5fd37489b" dependencies = [ "quote 1.0.37", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -22086,7 +22229,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -22095,7 +22238,7 @@ version = "14.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -22106,7 +22249,7 @@ checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -22668,7 +22811,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -22680,7 +22823,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -22694,7 +22837,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -22902,7 +23045,7 @@ dependencies = [ name = "sp-storage" version = "19.0.0" dependencies = [ - "impl-serde 0.5.0", + "impl-serde 0.4.0", "parity-scale-codec", "ref-cast", "serde", @@ -23130,7 +23273,7 @@ dependencies = [ name = "sp-version" version = "29.0.0" dependencies = [ - "impl-serde 0.5.0", + "impl-serde 0.4.0", "parity-scale-codec", "parity-wasm", "scale-info", @@ -23169,7 +23312,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "sp-version 29.0.0", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -23181,7 +23324,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -23648,7 +23791,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -23661,7 +23804,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -24150,7 +24293,7 @@ dependencies = [ "scale-info", "scale-typegen", "subxt-metadata", - "syn 2.0.82", + "syn 2.0.79", "thiserror", "tokio", ] @@ -24213,7 +24356,7 @@ dependencies = [ "quote 1.0.37", "scale-typegen", "subxt-codegen", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -24368,9 +24511,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.82" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", @@ -24386,7 +24529,7 @@ dependencies = [ "paste", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -24415,7 +24558,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -24545,7 +24688,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -24685,9 +24828,9 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] @@ -24714,13 +24857,13 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -24882,7 +25025,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -25102,7 +25245,7 @@ dependencies = [ "futures-util", "http 0.2.9", "http-body 0.4.5", - "http-range-header", + "http-range-header 0.3.1", "mime", "pin-project-lite", "tower-layer", @@ -25116,14 +25259,29 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ + "async-compression", + "base64 0.21.7", "bitflags 2.6.0", "bytes", + "futures-core", + "futures-util", "http 1.1.0", "http-body 1.0.0", "http-body-util", + "http-range-header 0.4.1", + "httpdate", + "iri-string", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", + "tokio", + "tokio-util", + "tower", "tower-layer", "tower-service", + "tracing", + "uuid", ] [[package]] @@ -25158,7 +25316,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -25200,7 +25358,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -25540,6 +25698,15 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -25852,7 +26019,7 @@ dependencies = [ "once_cell", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -25886,7 +26053,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -27021,7 +27188,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "staging-xcm", - "syn 2.0.82", + "syn 2.0.79", "trybuild", ] @@ -27192,7 +27359,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -27212,7 +27379,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -27380,6 +27547,15 @@ dependencies = [ "zstd-safe 6.0.6", ] +[[package]] +name = "zstd" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +dependencies = [ + "zstd-safe 7.0.0", +] + [[package]] name = "zstd-safe" version = "5.0.2+zstd.1.5.2" @@ -27400,6 +27576,15 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.8+zstd.1.5.5" diff --git a/Cargo.toml b/Cargo.toml index 0345a88320d8..c681c9138813 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1305,7 +1305,7 @@ substrate-test-runtime-client = { path = "substrate/test-utils/runtime/client" } substrate-test-runtime-transaction-pool = { path = "substrate/test-utils/runtime/transaction-pool" } substrate-test-utils = { path = "substrate/test-utils" } substrate-wasm-builder = { path = "substrate/utils/wasm-builder", default-features = false } -subxt = { version = "0.37", default-features = false } +subxt = { version = "0.37.1", default-features = false } subxt-signer = { version = "0.37" } syn = { version = "2.0.82" } sysinfo = { version = "0.30" } From 8e51a2cb558795ed547599dbca0d23826e563a7e Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 23 Oct 2024 09:22:44 +0200 Subject: [PATCH 144/174] fix bump --- Cargo.lock | 262 ++++++++++++++++++++++++----------------------------- Cargo.toml | 2 +- 2 files changed, 117 insertions(+), 147 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec2116f0b853..311182baedb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -183,7 +183,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", "syn-solidity", "tiny-keccak", ] @@ -310,7 +310,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -768,7 +768,7 @@ checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", "synstructure 0.13.1", ] @@ -791,7 +791,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1415,7 +1415,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1432,7 +1432,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1647,7 +1647,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -3109,7 +3109,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -4467,7 +4467,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5020,7 +5020,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5060,7 +5060,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "scratch", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5077,7 +5077,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5125,7 +5125,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "strsim 0.11.1", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5147,7 +5147,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5264,7 +5264,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5275,7 +5275,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5286,7 +5286,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5394,7 +5394,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5455,7 +5455,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "regex", - "syn 2.0.79", + "syn 2.0.82", "termcolor", "toml 0.8.12", "walkdir", @@ -5687,7 +5687,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5707,7 +5707,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5718,7 +5718,7 @@ checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5933,7 +5933,7 @@ dependencies = [ "prettyplease", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6005,7 +6005,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6348,7 +6348,7 @@ dependencies = [ "quote 1.0.37", "scale-info", "sp-arithmetic 23.0.0", - "syn 2.0.79", + "syn 2.0.82", "trybuild", ] @@ -6563,7 +6563,7 @@ dependencies = [ "sp-metadata-ir 0.6.0", "sp-runtime 31.0.1", "static_assertions", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6574,7 +6574,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6583,7 +6583,7 @@ version = "11.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6837,7 +6837,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -7510,7 +7510,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -8377,7 +8377,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9131,7 +9131,7 @@ dependencies = [ "proc-macro-warning 0.4.2", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9415,7 +9415,7 @@ dependencies = [ "parking_lot 0.12.3", "pin-project", "prost 0.12.6", - "prost-build 0.13.2", + "prost-build", "rand", "rcgen", "ring 0.16.20", @@ -9539,7 +9539,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9553,7 +9553,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9564,7 +9564,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9575,7 +9575,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9922,7 +9922,7 @@ dependencies = [ "cfg-if", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -10527,7 +10527,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -10703,7 +10703,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -11475,7 +11475,7 @@ version = "18.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -12638,7 +12638,7 @@ version = "0.1.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -12883,7 +12883,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "sp-runtime 31.0.1", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -13898,7 +13898,7 @@ dependencies = [ "pest_meta", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -13939,7 +13939,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16408,7 +16408,7 @@ dependencies = [ "polkavm-common 0.8.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16420,7 +16420,7 @@ dependencies = [ "polkavm-common 0.9.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16432,7 +16432,7 @@ dependencies = [ "polkavm-common 0.13.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16442,7 +16442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" dependencies = [ "polkavm-derive-impl 0.8.0", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16452,7 +16452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl 0.9.0", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16462,7 +16462,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f3ad876ca1855038c21d48cbe35164552208a54b21f8295a7d76bc33ef1e38" dependencies = [ "polkavm-derive-impl 0.13.0", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16679,7 +16679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2 1.0.86", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16784,7 +16784,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16795,7 +16795,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16876,7 +16876,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -16941,27 +16941,6 @@ dependencies = [ "prost-derive 0.13.2", ] -[[package]] -name = "prost-build" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" -dependencies = [ - "bytes", - "heck 0.4.1", - "itertools 0.11.0", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost 0.12.6", - "prost-types 0.12.4", - "regex", - "syn 2.0.79", - "tempfile", -] - [[package]] name = "prost-build" version = "0.13.2" @@ -16969,17 +16948,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.11.0", + "heck 0.5.0", + "itertools 0.12.1", "log", "multimap", "once_cell", "petgraph", "prettyplease", "prost 0.13.2", - "prost-types 0.13.2", + "prost-types", "regex", - "syn 2.0.79", + "syn 2.0.82", "tempfile", ] @@ -17003,10 +16982,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -17016,19 +16995,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", -] - -[[package]] -name = "prost-types" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" -dependencies = [ - "prost 0.12.6", + "syn 2.0.82", ] [[package]] @@ -17488,7 +17458,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -18107,7 +18077,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.79", + "syn 2.0.82", "unicode-ident", ] @@ -18537,7 +18507,7 @@ dependencies = [ "multihash 0.19.1", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "quickcheck", "rand", "sc-client-api", @@ -18635,7 +18605,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -19353,7 +19323,7 @@ dependencies = [ "partial_sort", "pin-project", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "rand", "sc-block-builder", "sc-client-api", @@ -19398,7 +19368,7 @@ dependencies = [ "futures", "libp2p-identity", "parity-scale-codec", - "prost-build 0.12.4", + "prost-build", "sc-consensus", "sc-network-types", "sp-consensus", @@ -19440,7 +19410,7 @@ dependencies = [ "log", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "sc-client-api", "sc-network", "sc-network-types", @@ -19483,7 +19453,7 @@ dependencies = [ "mockall 0.11.4", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "quickcheck", "sc-block-builder", "sc-client-api", @@ -19997,7 +19967,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -20180,7 +20150,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "scale-info", - "syn 2.0.79", + "syn 2.0.82", "thiserror", ] @@ -20502,7 +20472,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -20527,9 +20497,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "indexmap 2.2.3", "itoa", @@ -20604,7 +20574,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -21575,7 +21545,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -21590,7 +21560,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -21929,7 +21899,7 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "impl-serde 0.4.0", + "impl-serde 0.5.0", "itertools 0.11.0", "k256", "libsecp256k1", @@ -22200,7 +22170,7 @@ version = "0.1.0" dependencies = [ "quote 1.0.37", "sp-crypto-hashing 0.1.0", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -22211,7 +22181,7 @@ checksum = "b85d0f1f1e44bd8617eb2a48203ee854981229e3e79e6f468c7175d5fd37489b" dependencies = [ "quote 1.0.37", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -22229,7 +22199,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -22238,7 +22208,7 @@ version = "14.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -22249,7 +22219,7 @@ checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -22811,7 +22781,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -22823,7 +22793,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -22837,7 +22807,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -23045,7 +23015,7 @@ dependencies = [ name = "sp-storage" version = "19.0.0" dependencies = [ - "impl-serde 0.4.0", + "impl-serde 0.5.0", "parity-scale-codec", "ref-cast", "serde", @@ -23273,7 +23243,7 @@ dependencies = [ name = "sp-version" version = "29.0.0" dependencies = [ - "impl-serde 0.4.0", + "impl-serde 0.5.0", "parity-scale-codec", "parity-wasm", "scale-info", @@ -23312,7 +23282,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "sp-version 29.0.0", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -23324,7 +23294,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -23791,7 +23761,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -23804,7 +23774,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -24293,16 +24263,16 @@ dependencies = [ "scale-info", "scale-typegen", "subxt-metadata", - "syn 2.0.79", + "syn 2.0.82", "thiserror", "tokio", ] [[package]] name = "subxt-core" -version = "0.37.0" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f41eb2e2eea6ed45649508cc735f92c27f1fcfb15229e75f8270ea73177345" +checksum = "3af3b36405538a36b424d229dc908d1396ceb0994c90825ce928709eac1a159a" dependencies = [ "base58", "blake2 0.10.6", @@ -24356,7 +24326,7 @@ dependencies = [ "quote 1.0.37", "scale-typegen", "subxt-codegen", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -24511,9 +24481,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", @@ -24529,7 +24499,7 @@ dependencies = [ "paste", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -24558,7 +24528,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -24688,7 +24658,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -24828,9 +24798,9 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] @@ -24857,13 +24827,13 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -25025,7 +24995,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -25316,7 +25286,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -25358,7 +25328,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -26019,7 +25989,7 @@ dependencies = [ "once_cell", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-shared", ] @@ -26053,7 +26023,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -27188,7 +27158,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "staging-xcm", - "syn 2.0.79", + "syn 2.0.82", "trybuild", ] @@ -27359,7 +27329,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -27379,7 +27349,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c681c9138813..0345a88320d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1305,7 +1305,7 @@ substrate-test-runtime-client = { path = "substrate/test-utils/runtime/client" } substrate-test-runtime-transaction-pool = { path = "substrate/test-utils/runtime/transaction-pool" } substrate-test-utils = { path = "substrate/test-utils" } substrate-wasm-builder = { path = "substrate/utils/wasm-builder", default-features = false } -subxt = { version = "0.37.1", default-features = false } +subxt = { version = "0.37", default-features = false } subxt-signer = { version = "0.37" } syn = { version = "2.0.82" } sysinfo = { version = "0.30" } From a812fb7cd79cbad0f2cafabd4c86a3816d269c35 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 23 Oct 2024 09:57:35 +0200 Subject: [PATCH 145/174] fix --- substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs index 3eee8a252dd8..f30d73e9055d 100644 --- a/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs +++ b/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::subxt_client::system::calls::types::Remark; use pallet_revive_eth_rpc::subxt_client::{self, SrcChainConfig}; -use subxt::{blocks::FoundExtrinsic, OnlineClient}; +use subxt::OnlineClient; use subxt_signer::sr25519::dev; #[tokio::main] From 93da77385db2973005ca2973409e33822cd4deab Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 23 Oct 2024 14:37:05 +0200 Subject: [PATCH 146/174] Fix hard coded gas estimate in tests --- substrate/frame/revive/src/evm/runtime.rs | 30 +++++++++++++++++------ substrate/frame/revive/src/lib.rs | 3 ++- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index e4340b27a187..4c3fdeca720c 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -356,12 +356,7 @@ pub trait EthExtra { Default::default(), ) .into(); - - log::debug!(target: LOG_TARGET, "Checking Ethereum transaction fees: - dispatch_info: {info:?} - encoded_len: {encoded_len:?} - fees: {actual_fee:?} - "); + log::debug!(target: LOG_TARGET, "try_into_checked_extrinsic: encoded_len: {encoded_len:?} actual_fee: {actual_fee:?} eth_fee: {eth_fee:?}"); if eth_fee < actual_fee { log::debug!(target: LOG_TARGET, "fees {eth_fee:?} too low for the extrinsic {actual_fee:?}"); @@ -490,11 +485,30 @@ mod test { } } + fn estimate_gas(&mut self) { + let dry_run = crate::Pallet::::bare_eth_transact( + Account::default().account_id(), + self.tx.to, + self.tx.value.try_into().unwrap(), + self.tx.input.clone().0, + Weight::MAX, + u64::MAX, + |call| { + let call = RuntimeCall::Contracts(call); + let uxt: Ex = sp_runtime::generic::UncheckedExtrinsic::new_bare(call).into(); + uxt.encoded_size() as u32 + }, + crate::DebugInfo::Skip, + crate::CollectEvents::Skip, + ); + self.tx.gas = ((dry_run.fee + GAS_PRICE as u64) / (GAS_PRICE as u64)).into(); + } + /// Create a new builder with a call to the given address. fn call_with(dest: H160) -> Self { let mut builder = Self::new(); builder.tx.to = Some(dest); - builder.tx.gas = U256::from(516_708u128); + builder.estimate_gas(); builder } @@ -502,7 +516,7 @@ mod test { fn instantiate_with(code: Vec, data: Vec) -> Self { let mut builder = Self::new(); builder.tx.input = Bytes(code.into_iter().chain(data.into_iter()).collect()); - builder.tx.gas = U256::from(1_035_070u128); + builder.estimate_gas(); builder } diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 9b0bbb2d6bcb..11752e47cf2a 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1212,6 +1212,7 @@ where to: Some(dest), ..Default::default() }; + let eth_dispatch_call = crate::Call::::eth_transact { payload: tx.dummy_signed_payload(), gas_limit: result.gas_required, @@ -1238,7 +1239,7 @@ where ) .into(); - log::debug!(target: LOG_TARGET, "Call dry run Result: dispatch_info: {dispatch_info:?} len: {encoded_len:?} fee: {fee:?}"); + log::debug!(target: LOG_TARGET, "bare_eth_call: len: {encoded_len:?} fee: {fee:?}"); EthContractResult { gas_required: result.gas_required, storage_deposit: result.storage_deposit.charge_or_zero(), From 7999974af87ba67ba064ec40241da0ba21b80e91 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 23 Oct 2024 12:41:52 +0000 Subject: [PATCH 147/174] Update from pgherveou running command 'prdoc --audience runtime_dev --bump minor' --- prdoc/pr_6192.prdoc | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 prdoc/pr_6192.prdoc diff --git a/prdoc/pr_6192.prdoc b/prdoc/pr_6192.prdoc new file mode 100644 index 000000000000..21d7edbce9ba --- /dev/null +++ b/prdoc/pr_6192.prdoc @@ -0,0 +1,7 @@ +title: '[pallet-revive] fix hardcoded gas in tests' +doc: +- audience: Runtime Dev + description: Fix hardcoded gas limits in tests +crates: +- name: pallet-revive + bump: minor From b43507344df404c3f70e812cc8ad627ec2c19a9f Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Wed, 23 Oct 2024 14:43:02 +0200 Subject: [PATCH 148/174] Update prdoc/pr_6192.prdoc --- prdoc/pr_6192.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_6192.prdoc b/prdoc/pr_6192.prdoc index 21d7edbce9ba..cd9255486706 100644 --- a/prdoc/pr_6192.prdoc +++ b/prdoc/pr_6192.prdoc @@ -4,4 +4,4 @@ doc: description: Fix hardcoded gas limits in tests crates: - name: pallet-revive - bump: minor + bump: patch From d71a0a0ce067b7ae25d6be3c3b203209cbb7e215 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 23 Oct 2024 14:49:02 +0200 Subject: [PATCH 149/174] fixes --- prdoc/pr_6147.prdoc | 2 ++ substrate/bin/node/runtime/Cargo.toml | 2 +- substrate/frame/revive/Cargo.toml | 2 +- .../frame/revive/rpc/examples/rust/extrinsic.rs | 5 +++-- .../revive/rpc/examples/rust/remark-extrinsic.rs | 3 +-- substrate/frame/revive/rpc/src/client.rs | 13 ++++--------- substrate/frame/revive/rpc/src/lib.rs | 4 ++-- 7 files changed, 14 insertions(+), 17 deletions(-) diff --git a/prdoc/pr_6147.prdoc b/prdoc/pr_6147.prdoc index 13240b7ace4b..9b5392033e91 100644 --- a/prdoc/pr_6147.prdoc +++ b/prdoc/pr_6147.prdoc @@ -5,6 +5,8 @@ doc: description: | Add a new Ethereum JSON-RPC server that can be used a substrate chain configured with pallet-revive crates: + - name: pallet-revive + bump: patch - name: pallet-revive-eth-rpc bump: patch - name: pallet-revive-fixtures diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 71265b5171e9..5495fc65eaf4 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -58,8 +58,8 @@ std = [ "scale-info/std", "serde_json/std", "sp-debug-derive/std", + "sp-debug-derive/std", "substrate-wasm-builder", - "sp-debug-derive/std" ] runtime-benchmarks = [ "pallet-example-mbm/runtime-benchmarks", diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index e988b1e57f4a..d11d656430af 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -129,10 +129,10 @@ runtime-benchmarks = [ "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks" ] try-runtime = [ "frame-support/try-runtime", diff --git a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs index d2456a4c32a7..e15743e2385e 100644 --- a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs +++ b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs @@ -14,8 +14,9 @@ // 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 crate::subxt_client::revive::calls::types::InstantiateWithCode; -use pallet_revive_eth_rpc::subxt_client::{self, SrcChainConfig}; +use pallet_revive_eth_rpc::subxt_client::{ + self, revive::calls::types::InstantiateWithCode, SrcChainConfig, +}; use sp_weights::Weight; use subxt::OnlineClient; use subxt_signer::sr25519::dev; diff --git a/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs index f30d73e9055d..b106d27c218a 100644 --- a/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs +++ b/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs @@ -14,8 +14,7 @@ // 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 crate::subxt_client::system::calls::types::Remark; -use pallet_revive_eth_rpc::subxt_client::{self, SrcChainConfig}; +use pallet_revive_eth_rpc::subxt_client::{self, system::calls::types::Remark, SrcChainConfig}; use subxt::OnlineClient; use subxt_signer::sr25519::dev; diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index ce0df8dba69a..c68fe8b60a95 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -32,7 +32,7 @@ use pallet_revive::{ }, EthContractResult, }; -use sp_runtime::traits::Hash; +use sp_runtime::traits::{BlakeTwo256, Hash}; use sp_weights::Weight; use std::{ collections::{HashMap, VecDeque}, @@ -63,13 +63,6 @@ use tokio::{ use crate::subxt_client::{self, system::events::ExtrinsicSuccess, SrcChainConfig}; -pub mod primitives { - pub type Hashing = sp_runtime::traits::BlakeTwo256; - pub type AccountId = sp_runtime::AccountId32; - pub type AccountIndex = u32; - pub type MultiAddress = sp_runtime::MultiAddress; -} - /// The substrate block type. pub type SubstrateBlock = subxt::blocks::Block>; @@ -186,7 +179,9 @@ impl BlockCache { /// A client connect to a node and maintains a cache of the last `CACHE_SIZE` blocks. pub struct Client { + /// The inner state of the client. inner: Arc, + // JoinSet to manage spawned tasks. join_set: JoinSet>, /// A watch channel to signal cache updates. pub updates: tokio::sync::watch::Receiver<()>, @@ -265,7 +260,7 @@ impl ClientInner { let success = events.find_first::().is_ok(); let transaction_index = ext.index(); - let transaction_hash = primitives::Hashing::hash(&Vec::from(ext.bytes()).encode()); + let transaction_hash = BlakeTwo256::hash(&Vec::from(ext.bytes()).encode()); let block_hash = block.hash(); let block_number = block.number().into(); diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index d935a9a001db..a1745ce2c1bb 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -24,8 +24,8 @@ use jsonrpsee::{ proc_macros::rpc, types::{ErrorCode, ErrorObjectOwned}, }; -pub use pallet_revive::{evm::*, EthContractResult}; -pub use sp_core::{H160, H256, U256}; +use pallet_revive::{evm::*, EthContractResult}; +use sp_core::{H160, H256, U256}; use thiserror::Error; pub mod client; pub mod example; From 570da4652c34137454430e2476b2b5a97a8cd66e Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 23 Oct 2024 15:16:59 +0200 Subject: [PATCH 150/174] unpub --- substrate/frame/revive/rpc/src/client.rs | 18 +++++++++++++----- substrate/frame/revive/rpc/src/lib.rs | 4 +--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index c68fe8b60a95..349cd3e9dbb0 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -50,7 +50,6 @@ use subxt::{ config::Header, error::RpcError, storage::Storage, - tx::TxClient, utils::AccountId32, Config, OnlineClient, }; @@ -332,6 +331,10 @@ async fn extract_block_timestamp(block: &SubstrateBlock) -> Option { Some(ext.value.now / 1000) } +//pub trait ClientT { +// async fn latest_block(&self) -> Option>; +//} + impl Client { /// Create a new client instance. /// The client will subscribe to new blocks and maintain a cache of [`CACHE_SIZE`] blocks. @@ -430,8 +433,13 @@ impl Client { } /// Expose the transaction API. - pub fn tx(&self) -> TxClient> { - self.inner.api.tx() + pub async fn submit( + &self, + call: subxt::tx::DefaultPayload, + ) -> Result { + let ext = self.inner.api.tx().create_unsigned(&call).map_err(ClientError::from)?; + let hash = ext.submit().await?; + Ok(hash) } /// Get an EVM transaction receipt by hash. @@ -487,7 +495,7 @@ impl Client { } /// Expose the storage API. - pub async fn storage_api( + async fn storage_api( &self, at: &BlockNumberOrTagOrHash, ) -> Result>, ClientError> { @@ -511,7 +519,7 @@ impl Client { } /// Expose the runtime API. - pub async fn runtime_api( + async fn runtime_api( &self, at: &BlockNumberOrTagOrHash, ) -> Result< diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index a1745ce2c1bb..2b14df43eb0f 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -167,9 +167,7 @@ impl EthRpcServer for EthRpcServerImpl { gas_required.into(), storage_deposit, ); - let ext = self.client.tx().create_unsigned(&call).map_err(ClientError::from)?; - let hash = ext.submit().await.map_err(|err| EthRpcError::ClientError(err.into()))?; - + let hash = self.client.submit(call).await?; Ok(hash) } From 8e8b692d61cb758dda7c6aa0bf94e34b3a3d9942 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 23 Oct 2024 16:50:53 +0200 Subject: [PATCH 151/174] fixup client --- substrate/frame/revive/rpc/src/client.rs | 135 ++++++++++++----------- 1 file changed, 71 insertions(+), 64 deletions(-) diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index 349cd3e9dbb0..1aa39ecec243 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -16,9 +16,12 @@ // limitations under the License. //! The client connects to the source substrate chain //! and is used by the rpc server to query and send transactions to the substrate chain. - use crate::{ - rlp, runtime::GAS_PRICE, subxt_client::revive::calls::types::EthTransact, + rlp, + runtime::GAS_PRICE, + subxt_client::{ + revive::calls::types::EthTransact, runtime_types::pallet_revive::storage::ContractInfo, + }, TransactionLegacySigned, LOG_TARGET, }; use codec::Encode; @@ -331,10 +334,6 @@ async fn extract_block_timestamp(block: &SubstrateBlock) -> Option { Some(ext.value.now / 1000) } -//pub trait ClientT { -// async fn latest_block(&self) -> Option>; -//} - impl Client { /// Create a new client instance. /// The client will subscribe to new blocks and maintain a cache of [`CACHE_SIZE`] blocks. @@ -352,6 +351,58 @@ impl Client { Ok(Self { inner, join_set, updates }) } + /// Expose the storage API. + async fn storage_api( + &self, + at: &BlockNumberOrTagOrHash, + ) -> Result>, ClientError> { + match at { + BlockNumberOrTagOrHash::U256(block_number) => { + let n: SubstrateBlockNumber = + (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; + + let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; + Ok(self.inner.api.storage().at(hash)) + }, + BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.storage().at(*hash)), + BlockNumberOrTagOrHash::BlockTag(_) => { + if let Some(block) = self.latest_block().await { + return Ok(self.inner.api.storage().at(block.hash())); + } + let storage = self.inner.api.storage().at_latest().await?; + Ok(storage) + }, + } + } + + /// Expose the runtime API. + async fn runtime_api( + &self, + at: &BlockNumberOrTagOrHash, + ) -> Result< + subxt::runtime_api::RuntimeApi>, + ClientError, + > { + match at { + BlockNumberOrTagOrHash::U256(block_number) => { + let n: SubstrateBlockNumber = + (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; + + let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; + Ok(self.inner.api.runtime_api().at(hash)) + }, + BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.runtime_api().at(*hash)), + BlockNumberOrTagOrHash::BlockTag(_) => { + if let Some(block) = self.latest_block().await { + return Ok(self.inner.api.runtime_api().at(block.hash())); + } + + let api = self.inner.api.runtime_api().at_latest().await?; + Ok(api) + }, + } + } + /// Subscribe and log reconnection events. async fn subscribe_reconnect(inner: Arc) -> Result<(), ClientError> { let rpc = inner.as_ref().rpc_client.clone(); @@ -424,7 +475,9 @@ impl Client { log::info!(target: LOG_TARGET, "Block subscription ended"); Ok(()) } +} +impl Client { /// Get the most recent block stored in the cache. pub async fn latest_block(&self) -> Option> { let cache = self.inner.cache.read().await; @@ -494,65 +547,13 @@ impl Client { cache.tx_hashes_by_block_and_index.get(block_hash).map(|v| v.len()) } - /// Expose the storage API. - async fn storage_api( - &self, - at: &BlockNumberOrTagOrHash, - ) -> Result>, ClientError> { - match at { - BlockNumberOrTagOrHash::U256(block_number) => { - let n: SubstrateBlockNumber = - (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; - - let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; - Ok(self.inner.api.storage().at(hash)) - }, - BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.storage().at(*hash)), - BlockNumberOrTagOrHash::BlockTag(_) => { - if let Some(block) = self.latest_block().await { - return Ok(self.inner.api.storage().at(block.hash())); - } - let storage = self.inner.api.storage().at_latest().await?; - Ok(storage) - }, - } - } - - /// Expose the runtime API. - async fn runtime_api( - &self, - at: &BlockNumberOrTagOrHash, - ) -> Result< - subxt::runtime_api::RuntimeApi>, - ClientError, - > { - match at { - BlockNumberOrTagOrHash::U256(block_number) => { - let n: SubstrateBlockNumber = - (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; - - let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; - Ok(self.inner.api.runtime_api().at(hash)) - }, - BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.runtime_api().at(*hash)), - BlockNumberOrTagOrHash::BlockTag(_) => { - if let Some(block) = self.latest_block().await { - return Ok(self.inner.api.runtime_api().at(block.hash())); - } - - let api = self.inner.api.runtime_api().at_latest().await?; - Ok(api) - }, - } - } - /// Get the balance of the given address. pub async fn balance( &self, address: H160, at: &BlockNumberOrTagOrHash, ) -> Result { - let account_id = self.account_id(&address); + let account_id = self.account_id(&address).await?; let query = subxt_client::storage().system().account(account_id); let Some(account) = self.storage_api(at).await?.fetch(&query).await? else { return Ok(U256::zero()); @@ -588,8 +589,14 @@ impl Client { block: BlockNumberOrTagOrHash, ) -> Result, ClientError> { let storage_api = self.storage_api(&block).await?; - let account_id = self.account_id(contract_address); - let code_hash: subxt::utils::H256 = account_id.0.into(); + + // TODO: remove once subxt is updated + let contract_address = contract_address.0.into(); + + let query = subxt_client::storage().revive().contract_info_of(&contract_address); + let Some(ContractInfo { code_hash, .. }) = storage_api.fetch(&query).await? else { + return Ok(Vec::new()); + }; let query = subxt_client::storage().revive().pristine_code(code_hash); let result = storage_api.fetch(&query).await?.map(|v| v.0).unwrap_or_default(); @@ -642,7 +649,7 @@ impl Client { address: H160, block: BlockNumberOrTagOrHash, ) -> Result { - let account_id = self.account_id(&address); + let account_id = self.account_id(&address).await?; let storage = self.storage_api(&block).await?; let query = subxt_client::storage().system().account(account_id); let Some(account) = storage.fetch(&query).await? else { @@ -767,10 +774,10 @@ impl Client { } /// Get the substrate account ID from the EVM address. - pub fn account_id(&self, address: &H160) -> AccountId32 { + async fn account_id(&self, address: &H160) -> Result { let mut id: [u8; 32] = [0xEE; 32]; id[..20].copy_from_slice(address.as_bytes()); - AccountId32(id) + Ok(AccountId32(id)) } /// Get the chain ID. From 7a217b9a947f482ec75ce4efc23e6bfdaf804302 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 23 Oct 2024 17:27:30 +0200 Subject: [PATCH 152/174] fixes --- substrate/bin/node/runtime/src/lib.rs | 14 ++++++- substrate/frame/revive/rpc/kitchensink.scale | Bin 651595 -> 651742 bytes substrate/frame/revive/rpc/src/client.rs | 37 +++++++------------ substrate/frame/revive/src/evm/runtime.rs | 2 +- substrate/frame/revive/src/lib.rs | 9 ++++- 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index d6a17856e470..1c21a665133d 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -76,7 +76,7 @@ use pallet_identity::legacy::IdentityInfo; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; -use pallet_revive::evm::runtime::EthExtra; +use pallet_revive::{evm::runtime::EthExtra, AddressMapper}; use pallet_session::historical as pallet_session_historical; // Can't use `FungibleAdapter` here until Treasury pallet migrates to fungibles // @@ -3157,8 +3157,18 @@ impl_runtime_apis! { } } - impl pallet_revive::ReviveApi for Runtime + impl pallet_revive::ReviveApi for Runtime { + fn balance(address: H160) -> Balance { + let account = ::AddressMapper::to_account_id(&address); + Balances::free_balance(account) + } + + fn nonce(address: H160) -> Nonce { + let account = ::AddressMapper::to_account_id(&address); + System::account_nonce(account) + } + fn eth_transact( from: H160, dest: Option, diff --git a/substrate/frame/revive/rpc/kitchensink.scale b/substrate/frame/revive/rpc/kitchensink.scale index eb77a690e4642ce59987cd64c8d1eaf1db4c672a..79d351c763d844d8169d60989a63bffdeb0e19c9 100644 GIT binary patch delta 183 zcmX^8Nd4Yp^@bM47N!>F7M2#)7Pc1l7LF~P)hFv^WRend67!N%S!5DZQi@WGi#^#T zSRN<@rIwTyObuO delta 35 rcmccjSpD=P^@bM47N!>F7M2#)7Pc1l7LF~P)h8K6w)3CjJg*J_0f-GI diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index 1aa39ecec243..a2f88b61f878 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -53,7 +53,6 @@ use subxt::{ config::Header, error::RpcError, storage::Storage, - utils::AccountId32, Config, OnlineClient, }; use subxt_client::transaction_payment::events::TransactionFeePaid; @@ -553,14 +552,13 @@ impl Client { address: H160, at: &BlockNumberOrTagOrHash, ) -> Result { - let account_id = self.account_id(&address).await?; - let query = subxt_client::storage().system().account(account_id); - let Some(account) = self.storage_api(at).await?.fetch(&query).await? else { - return Ok(U256::zero()); - }; + // TODO: remove once subxt is updated + let address = address.0.into(); - let native = account.data.free.into(); - Ok(self.inner.native_to_evm_decimals(native)) + let runtime_api = self.runtime_api(&at).await?; + let payload = subxt_client::apis().revive_api().balance(address); + let balance = runtime_api.call(payload).await?.into(); + Ok(self.inner.native_to_evm_decimals(balance)) } /// Get the contract storage for the given contract address and key. @@ -640,23 +638,21 @@ impl Client { block: BlockNumberOrTagOrHash, ) -> Result { let dry_run = self.dry_run(tx, block).await?; - Ok(U256::from(dry_run.fee / GAS_PRICE as u128) + 1) + Ok(U256::from(dry_run.fee / GAS_PRICE as u128) + GAS_PRICE) } /// Get the nonce of the given address. pub async fn nonce( &self, address: H160, - block: BlockNumberOrTagOrHash, + at: BlockNumberOrTagOrHash, ) -> Result { - let account_id = self.account_id(&address).await?; - let storage = self.storage_api(&block).await?; - let query = subxt_client::storage().system().account(account_id); - let Some(account) = storage.fetch(&query).await? else { - return Ok(0); - }; + let address = address.0.into(); - Ok(account.nonce) + let runtime_api = self.runtime_api(&at).await?; + let payload = subxt_client::apis().revive_api().nonce(address); + let nonce = runtime_api.call(payload).await?; + Ok(nonce.into()) } /// Get the block number of the latest block. @@ -773,13 +769,6 @@ impl Client { Ok(fee) } - /// Get the substrate account ID from the EVM address. - async fn account_id(&self, address: &H160) -> Result { - let mut id: [u8; 32] = [0xEE; 32]; - id[..20].copy_from_slice(address.as_bytes()); - Ok(AccountId32(id)) - } - /// Get the chain ID. pub fn chain_id(&self) -> u64 { self.inner.chain_id diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 58110bcf186f..9c3d4fafe679 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -48,7 +48,7 @@ type CallOf = ::RuntimeCall; /// We use a fixed value for the gas price. /// This let us calculate the gas estimate for a transaction with the formula: /// `estimate_gas = substrate_fee / gas_price`. -pub const GAS_PRICE: u32 = 1_000u32; +pub const GAS_PRICE: u32 = 1u32; /// Wraps [`generic::UncheckedExtrinsic`] to support checking unsigned /// [`crate::Call::eth_transact`] extrinsic. diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 9b0bbb2d6bcb..a88d46e6a554 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1393,12 +1393,19 @@ environmental!(executing_contract: bool); sp_api::decl_runtime_apis! { /// The API used to dry-run contract interactions. #[api_version(1)] - pub trait ReviveApi where + pub trait ReviveApi where AccountId: Codec, Balance: Codec, + Nonce: Codec, BlockNumber: Codec, EventRecord: Codec, { + /// Returns the free balance of the given `[H160]` address. + fn balance(address: H160) -> Balance; + + /// Returns the nonce of the given `[H160]` address. + fn nonce(address: H160) -> Nonce; + /// Perform a call from a specified account to a given contract. /// /// See [`crate::Pallet::bare_call`]. From ac700fcce94f4396716c362a407b00e40bcba204 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 23 Oct 2024 17:29:52 +0200 Subject: [PATCH 153/174] fix AH config with new runtime api --- .../runtimes/assets/asset-hub-westend/src/lib.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 9a60de77a584..3840096091aa 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -2069,8 +2069,17 @@ impl_runtime_apis! { } } - impl pallet_revive::ReviveApi for Runtime + impl pallet_revive::ReviveApi for Runtime { + fn balance(address: H160) -> Balance { + let account = ::AddressMapper::to_account_id(&address); + Balances::free_balance(account) + } + + fn nonce(address: H160) -> Nonce { + let account = ::AddressMapper::to_account_id(&address); + System::account_nonce(account) + } fn eth_transact( from: H160, dest: Option, From 80182e3f5e7391efa176b70a17c5e7176c2b8dde Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 23 Oct 2024 17:33:07 +0200 Subject: [PATCH 154/174] fix missing use --- cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 3840096091aa..a125aa2c18ba 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -58,7 +58,7 @@ use frame_system::{ }; use pallet_asset_conversion_tx_payment::SwapAssetAdapter; use pallet_nfts::{DestroyWitness, PalletFeatures}; -use pallet_revive::evm::runtime::EthExtra; +use pallet_revive::{evm::runtime::EthExtra, AddressMapper}; use parachains_common::{ impls::DealWithFees, message_queue::*, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, CollectionId, Hash, Header, ItemId, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, From bf00157e9070291be863ca024c2b410b9cffa15f Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 00:04:18 +0200 Subject: [PATCH 155/174] add test --- Cargo.lock | 2 + substrate/frame/revive/rpc/Cargo.toml | 3 + substrate/frame/revive/rpc/src/example.rs | 10 +-- substrate/frame/revive/rpc/src/lib.rs | 3 + substrate/frame/revive/rpc/src/main.rs | 18 +++--- substrate/frame/revive/rpc/src/tests.rs | 79 +++++++++++++++++++++++ 6 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 substrate/frame/revive/rpc/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 3c875ecbf12c..fccef4a55126 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12552,6 +12552,7 @@ name = "pallet-revive-eth-rpc" version = "0.1.0" dependencies = [ "anyhow", + "assert_cmd", "clap 4.5.13", "env_logger 0.11.3", "futures", @@ -12572,6 +12573,7 @@ dependencies = [ "sp-crypto-hashing 0.1.0", "sp-runtime 31.0.1", "sp-weights 27.0.0", + "substrate-cli-test-utils", "subxt", "subxt-signer", "thiserror", diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml index 4c9ec4c963f1..aa20ff8613aa 100644 --- a/substrate/frame/revive/rpc/Cargo.toml +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -77,5 +77,8 @@ dev = [] example = ["hex", "hex-literal", "rlp", "secp256k1", "subxt-signer"] [dev-dependencies] +pallet-revive = { workspace = true, default-features = true, features = ["riscv"] } hex-literal = { workspace = true } pallet-revive-fixtures = { workspace = true } +substrate-cli-test-utils = { workspace = true } +assert_cmd = { workspace = true } diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs index cbd022fa3b73..b01a918d23ad 100644 --- a/substrate/frame/revive/rpc/src/example.rs +++ b/substrate/frame/revive/rpc/src/example.rs @@ -15,18 +15,20 @@ // See the License for the specific language governing permissions and // limitations under the License. //! Example utilities -#![cfg(feature = "example")] +#![cfg(any(feature = "example", test))] use crate::{EthRpcClient, ReceiptInfo}; use anyhow::Context; -use jsonrpsee::http_client::HttpClient; use pallet_revive::evm::{ rlp::*, Account, BlockTag, Bytes, GenericTransaction, TransactionLegacyUnsigned, H160, H256, U256, }; /// Wait for a transaction receipt. -pub async fn wait_for_receipt(client: &HttpClient, hash: H256) -> anyhow::Result { +pub async fn wait_for_receipt( + client: &(impl EthRpcClient + Send + Sync), + hash: H256, +) -> anyhow::Result { for _ in 0..6 { tokio::time::sleep(std::time::Duration::from_secs(2)).await; let receipt = client.get_transaction_receipt(hash).await?; @@ -41,7 +43,7 @@ pub async fn wait_for_receipt(client: &HttpClient, hash: H256) -> anyhow::Result /// Send a transaction. pub async fn send_transaction( signer: &Account, - client: &HttpClient, + client: &(impl EthRpcClient + Send + Sync), value: U256, input: Bytes, to: Option, diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index 2b14df43eb0f..7605bedf9926 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -31,6 +31,9 @@ pub mod client; pub mod example; pub mod subxt_client; +#[cfg(test)] +mod tests; + mod rpc_methods_gen; pub use rpc_methods_gen::*; diff --git a/substrate/frame/revive/rpc/src/main.rs b/substrate/frame/revive/rpc/src/main.rs index 5dbaeba899b2..e966e199ad70 100644 --- a/substrate/frame/revive/rpc/src/main.rs +++ b/substrate/frame/revive/rpc/src/main.rs @@ -34,12 +34,12 @@ use tracing_subscriber::{util::SubscriberInitExt, EnvFilter, FmtSubscriber}; #[clap(author, about, version)] struct CliCommand { /// The server address to bind to - #[clap(long, default_value = "127.0.0.1:9090")] - url: String, + #[clap(long, default_value = "9090")] + rpc_port: String, /// The node url to connect to #[clap(long, default_value = "ws://127.0.0.1:9944")] - node_url: String, + node_rpc_url: String, } /// Initialize tracing @@ -56,20 +56,20 @@ fn init_tracing() { #[tokio::main] async fn main() -> anyhow::Result<()> { - let CliCommand { url, node_url } = CliCommand::parse(); + let CliCommand { rpc_port, node_rpc_url } = CliCommand::parse(); init_tracing(); - let client = Client::from_url(&node_url).await?; + let client = Client::from_url(&node_rpc_url).await?; let mut updates = client.updates.clone(); - let server_addr = run_server(client, &url).await?; - log::info!(target: LOG_TARGET, "Server started on: {}", server_addr); + let server_addr = run_server(client, &format!("127.0.0.1:{rpc_port}")).await?; + log::info!("Running JSON-RPC server: addr={server_addr},"); let url = format!("http://{}", server_addr); let client = HttpClientBuilder::default().build(url)?; let response = client.block_number().await?; - log::info!(target: LOG_TARGET, "client initialized with block number {:?}", response); + log::info!(target: LOG_TARGET, "Client initialized with block number {:?}", response); // keep running server until ctrl-c or client subscription fails let _ = updates.wait_for(|_| false).await; @@ -99,7 +99,7 @@ mod dev { let params = req.params.clone().unwrap_or_default(); async move { - log::info!(target: LOG_TARGET, "method: {method} params: {params}"); + log::info!(target: LOG_TARGET, "Method: {method} params: {params}"); let resp = service.call(req).await; if resp.is_success() { log::info!(target: LOG_TARGET, "✅ rpc: {method}"); diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs new file mode 100644 index 000000000000..1757d477a9e5 --- /dev/null +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -0,0 +1,79 @@ +use crate::{ + example::{send_transaction, wait_for_receipt}, + EthRpcClient, +}; +use assert_cmd::cargo::cargo_bin; +use jsonrpsee::ws_client::WsClientBuilder; +use pallet_revive::{ + create1, + evm::{Account, BlockTag, Bytes, U256}, +}; +use std::{ + io::{BufRead, BufReader}, + process::{self, Child, Command}, +}; +use substrate_cli_test_utils::*; + +/// Start eth-rpc server, and return the child process and the WebSocket URL. +fn start_eth_rpc_server(node_ws_url: &str) -> (Child, String) { + let mut child = Command::new(cargo_bin("eth-rpc")) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) + .env("RUST_LOG", "info,eth-rpc=debug") + .args(&["--rpc-port=45788", &format!("--node-rpc-url={node_ws_url}")]) + .spawn() + .unwrap(); + + let mut data = String::new(); + let ws_url = BufReader::new(child.stdout.take().unwrap()) + .lines() + .find_map(|line| { + let line = line.expect("failed to obtain next line while extracting node info"); + data.push_str(&line); + data.push_str("\n"); + + // does the line contain our port (we expect this specific output from eth-rpc). + let sock_addr = match line.split_once("Running JSON-RPC server: addr=") { + None => return None, + Some((_, after)) => after.split_once(",").unwrap().0, + }; + + Some(format!("ws://{}", sock_addr)) + }) + .unwrap_or_else(|| { + eprintln!("Observed eth-rpc output:\n{}", data); + panic!("We should get a WebSocket address") + }); + + (child, ws_url) +} + +#[tokio::test] +async fn test_jsonrpsee_server() -> anyhow::Result<()> { + let mut node_child = substrate_cli_test_utils::start_node(); + let (info, _) = extract_info_from_output(node_child.stderr.take().unwrap()); + let (_rpc_child, ws_url) = start_eth_rpc_server(&info.ws_url); + + let data = b"hello world".to_vec(); + let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; + let input = bytes.into_iter().chain(data.clone()).collect::>(); + + let account = Account::default(); + let client = WsClientBuilder::default().build(ws_url).await?; + + // Deploy contract + let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; + let hash = send_transaction(&account, &client, U256::zero(), input.into(), None).await?; + let receipt = wait_for_receipt(&client, hash).await?; + let contract_address = create1(&account.address(), nonce.try_into().unwrap()); + assert_eq!(contract_address, receipt.contract_address.unwrap()); + + // Call contract + let hash = + send_transaction(&account, &client, U256::zero(), Bytes::default(), Some(contract_address)) + .await?; + let receipt = wait_for_receipt(&client, hash).await?; + assert_eq!(contract_address, receipt.to.unwrap()); + + Ok(()) +} From 15b9c27b7c66138a8cc6992127257530a2c6e814 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 00:29:31 +0200 Subject: [PATCH 156/174] lint fixes --- substrate/frame/revive/rpc/Cargo.toml | 2 +- substrate/frame/revive/rpc/src/client.rs | 8 ++++---- substrate/frame/revive/rpc/src/lib.rs | 2 +- substrate/frame/revive/rpc/src/tests.rs | 8 ++++++-- umbrella/Cargo.toml | 1 + 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml index aa20ff8613aa..04e7a1de74fc 100644 --- a/substrate/frame/revive/rpc/Cargo.toml +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -75,9 +75,9 @@ env_logger = { workspace = true } [features] dev = [] example = ["hex", "hex-literal", "rlp", "secp256k1", "subxt-signer"] +riscv = ["pallet-revive/riscv"] [dev-dependencies] -pallet-revive = { workspace = true, default-features = true, features = ["riscv"] } hex-literal = { workspace = true } pallet-revive-fixtures = { workspace = true } substrate-cli-test-utils = { workspace = true } diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index a2f88b61f878..b74d63b0ff98 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -555,7 +555,7 @@ impl Client { // TODO: remove once subxt is updated let address = address.0.into(); - let runtime_api = self.runtime_api(&at).await?; + let runtime_api = self.runtime_api(at).await?; let payload = subxt_client::apis().revive_api().balance(address); let balance = runtime_api.call(payload).await?.into(); Ok(self.inner.native_to_evm_decimals(balance)) @@ -589,9 +589,9 @@ impl Client { let storage_api = self.storage_api(&block).await?; // TODO: remove once subxt is updated - let contract_address = contract_address.0.into(); + let contract_address: subxt::utils::H160 = contract_address.0.into(); - let query = subxt_client::storage().revive().contract_info_of(&contract_address); + let query = subxt_client::storage().revive().contract_info_of(contract_address); let Some(ContractInfo { code_hash, .. }) = storage_api.fetch(&query).await? else { return Ok(Vec::new()); }; @@ -646,7 +646,7 @@ impl Client { &self, address: H160, at: BlockNumberOrTagOrHash, - ) -> Result { + ) -> Result { let address = address.0.into(); let runtime_api = self.runtime_api(&at).await?; diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index 7605bedf9926..8907195c2c10 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -361,7 +361,7 @@ impl EthRpcServer for EthRpcServerImpl { block: BlockNumberOrTagOrHash, ) -> RpcResult { let nonce = self.client.nonce(address, block).await?; - Ok(nonce.into()) + Ok(nonce) } } diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 1757d477a9e5..8ea86eac5bfd 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -1,3 +1,7 @@ +//! Test the eth-rpc cli with the kitchensink node. + +// We require the `riscv` feature to get access to the compiled fixtures. +#![cfg(feature = "riscv")] use crate::{ example::{send_transaction, wait_for_receipt}, EthRpcClient, @@ -20,7 +24,7 @@ fn start_eth_rpc_server(node_ws_url: &str) -> (Child, String) { .stdout(process::Stdio::piped()) .stderr(process::Stdio::piped()) .env("RUST_LOG", "info,eth-rpc=debug") - .args(&["--rpc-port=45788", &format!("--node-rpc-url={node_ws_url}")]) + .args(["--rpc-port=45788", &format!("--node-rpc-url={node_ws_url}")]) .spawn() .unwrap(); @@ -30,7 +34,7 @@ fn start_eth_rpc_server(node_ws_url: &str) -> (Child, String) { .find_map(|line| { let line = line.expect("failed to obtain next line while extracting node info"); data.push_str(&line); - data.push_str("\n"); + data.push('\n'); // does the line contain our port (we expect this specific output from eth-rpc). let sock_addr = match line.split_once("Running JSON-RPC server: addr=") { diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 21ad5cd7bf76..4e0168df2f36 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -614,6 +614,7 @@ riscv = [ "pallet-revive-fixtures?/riscv", "pallet-revive-mock-network?/riscv", "pallet-revive?/riscv", + "pallet-revive-eth-rpc?/riscv" ] [package.edition] From 52c7290608c2070bbd8a0f3bd94f4c3cb9fac4e6 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 00:35:28 +0200 Subject: [PATCH 157/174] clean up --- substrate/frame/revive/rpc/src/example.rs | 2 -- substrate/frame/revive/rpc/src/tests.rs | 9 ++++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs index b01a918d23ad..b9b6fdd26167 100644 --- a/substrate/frame/revive/rpc/src/example.rs +++ b/substrate/frame/revive/rpc/src/example.rs @@ -73,8 +73,6 @@ pub async fn send_transaction( .await .with_context(|| "Failed to fetch gas estimate")?; - println!("Estimated Gas: {gas:?}"); - let unsigned_tx = TransactionLegacyUnsigned { gas, nonce, diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 8ea86eac5bfd..7cb9ba54f42a 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -58,14 +58,13 @@ async fn test_jsonrpsee_server() -> anyhow::Result<()> { let (info, _) = extract_info_from_output(node_child.stderr.take().unwrap()); let (_rpc_child, ws_url) = start_eth_rpc_server(&info.ws_url); - let data = b"hello world".to_vec(); - let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; - let input = bytes.into_iter().chain(data.clone()).collect::>(); - - let account = Account::default(); let client = WsClientBuilder::default().build(ws_url).await?; + let account = Account::default(); // Deploy contract + let data = b"hello world".to_vec(); + let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; + let input = bytes.into_iter().chain(data.clone()).collect::>(); let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; let hash = send_transaction(&account, &client, U256::zero(), input.into(), None).await?; let receipt = wait_for_receipt(&client, hash).await?; From a0deaf609588794000347611144242a413006abe Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 00:44:37 +0200 Subject: [PATCH 158/174] cleanup --- substrate/frame/revive/rpc/src/main.rs | 2 +- substrate/frame/revive/rpc/src/tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/rpc/src/main.rs b/substrate/frame/revive/rpc/src/main.rs index e966e199ad70..6b613274416d 100644 --- a/substrate/frame/revive/rpc/src/main.rs +++ b/substrate/frame/revive/rpc/src/main.rs @@ -63,7 +63,7 @@ async fn main() -> anyhow::Result<()> { let mut updates = client.updates.clone(); let server_addr = run_server(client, &format!("127.0.0.1:{rpc_port}")).await?; - log::info!("Running JSON-RPC server: addr={server_addr},"); + log::info!("Running JSON-RPC server: addr={server_addr}"); let url = format!("http://{}", server_addr); let client = HttpClientBuilder::default().build(url)?; diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 7cb9ba54f42a..33ba15478bc2 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -39,7 +39,7 @@ fn start_eth_rpc_server(node_ws_url: &str) -> (Child, String) { // does the line contain our port (we expect this specific output from eth-rpc). let sock_addr = match line.split_once("Running JSON-RPC server: addr=") { None => return None, - Some((_, after)) => after.split_once(",").unwrap().0, + Some((_, after)) => after.trim(), }; Some(format!("ws://{}", sock_addr)) From deb191cf369bfbc8337bb24326b3774d12bf4dda Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 07:51:20 +0200 Subject: [PATCH 159/174] fix ci --- prdoc/pr_6147.prdoc | 2 ++ substrate/frame/revive/rpc/src/tests.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/prdoc/pr_6147.prdoc b/prdoc/pr_6147.prdoc index 9b5392033e91..7ecd08612d9a 100644 --- a/prdoc/pr_6147.prdoc +++ b/prdoc/pr_6147.prdoc @@ -7,6 +7,8 @@ doc: crates: - name: pallet-revive bump: patch + - name: asset-hub-westend-runtime + bump: patch - name: pallet-revive-eth-rpc bump: patch - name: pallet-revive-fixtures diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 33ba15478bc2..29060773f659 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -1,3 +1,19 @@ +// 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. //! Test the eth-rpc cli with the kitchensink node. // We require the `riscv` feature to get access to the compiled fixtures. From 81956a064a488502da17b9e26c5f4811e94ae7a8 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 08:34:31 +0200 Subject: [PATCH 160/174] fix umbrella --- umbrella/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 4e0168df2f36..28d6a2c3fb01 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -611,10 +611,10 @@ tuples-96 = [ "frame-support?/tuples-96", ] riscv = [ + "pallet-revive-eth-rpc?/riscv", "pallet-revive-fixtures?/riscv", "pallet-revive-mock-network?/riscv", "pallet-revive?/riscv", - "pallet-revive-eth-rpc?/riscv" ] [package.edition] From 8bb9db2f1e27c4deee1ce9255faf84736d1dbeab Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 09:46:27 +0200 Subject: [PATCH 161/174] fix prdoc --- prdoc/pr_6147.prdoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prdoc/pr_6147.prdoc b/prdoc/pr_6147.prdoc index 7ecd08612d9a..eef0d0936675 100644 --- a/prdoc/pr_6147.prdoc +++ b/prdoc/pr_6147.prdoc @@ -13,4 +13,5 @@ crates: bump: patch - name: pallet-revive-fixtures bump: patch - + - name: polkadot-sdk + bump: patch From 2efc281397f9e7d7f8980730f543f38d30caf0f0 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 10:58:03 +0200 Subject: [PATCH 162/174] update deploy --- substrate/frame/revive/rpc/examples/rust/deploy.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/substrate/frame/revive/rpc/examples/rust/deploy.rs b/substrate/frame/revive/rpc/examples/rust/deploy.rs index 0d6c0996e71d..8f90fe61fe22 100644 --- a/substrate/frame/revive/rpc/examples/rust/deploy.rs +++ b/substrate/frame/revive/rpc/examples/rust/deploy.rs @@ -38,19 +38,25 @@ async fn main() -> anyhow::Result<()> { println!("\n\n=== Deploying contract ===\n\n"); let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; - let hash = send_transaction(&account, &client, U256::zero(), input.into(), None).await?; + let hash = + send_transaction(&account, &client, 5_000_000_000_000u128.into(), input.into(), None) + .await?; println!("Deploy Tx hash: {hash:?}"); let ReceiptInfo { block_number, gas_used, contract_address, .. } = wait_for_receipt(&client, hash).await?; + + let contract_address = contract_address.unwrap(); + assert_eq!(contract_address, create1(&account.address(), nonce.try_into().unwrap())); + println!("Receipt:"); println!("- Block number: {block_number}"); println!("- Gas used: {gas_used}"); println!("- Contract address: {contract_address:?}"); + let balance = client.get_balance(contract_address, BlockTag::Latest.into()).await?; + println!("- Contract balance: {balance:?}"); - let contract_address = create1(&account.address(), nonce.try_into().unwrap()); println!("\n\n=== Calling contract ===\n\n"); - let hash = send_transaction(&account, &client, U256::zero(), Bytes::default(), Some(contract_address)) .await?; From 7f88f8e8a9daa365ff84709f756e277f0dc6c18f Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 11:03:37 +0200 Subject: [PATCH 163/174] revive_api should use usable balance instead of free_balance --- cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- substrate/bin/node/runtime/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index a125aa2c18ba..5fbf0d33d576 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -2073,7 +2073,7 @@ impl_runtime_apis! { { fn balance(address: H160) -> Balance { let account = ::AddressMapper::to_account_id(&address); - Balances::free_balance(account) + Balances::usable_balance(account) } fn nonce(address: H160) -> Nonce { diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 1c21a665133d..d5b384632a37 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -3161,7 +3161,7 @@ impl_runtime_apis! { { fn balance(address: H160) -> Balance { let account = ::AddressMapper::to_account_id(&address); - Balances::free_balance(account) + Balances::usable_balance(account) } fn nonce(address: H160) -> Nonce { From 22eef3a18818de0917b74ed9155e3b21476cccf4 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 11:33:38 +0200 Subject: [PATCH 164/174] Tweak tests --- substrate/frame/revive/rpc/src/client.rs | 2 +- substrate/frame/revive/rpc/src/tests.rs | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index b74d63b0ff98..bd2f08661b3f 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -219,7 +219,7 @@ impl ClientInner { } /// Convert a native balance to an EVM balance. - pub fn native_to_evm_decimals(&self, value: U256) -> U256 { + fn native_to_evm_decimals(&self, value: U256) -> U256 { value.saturating_mul(self.native_to_evm_ratio) } diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 29060773f659..86c0b06549c7 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -79,20 +79,36 @@ async fn test_jsonrpsee_server() -> anyhow::Result<()> { // Deploy contract let data = b"hello world".to_vec(); + let value = U256::from(5_000_000_000_000u128); let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; let input = bytes.into_iter().chain(data.clone()).collect::>(); let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; - let hash = send_transaction(&account, &client, U256::zero(), input.into(), None).await?; + let hash = send_transaction(&account, &client, value, input.into(), None).await?; let receipt = wait_for_receipt(&client, hash).await?; let contract_address = create1(&account.address(), nonce.try_into().unwrap()); - assert_eq!(contract_address, receipt.contract_address.unwrap()); + assert_eq!( + Some(contract_address), + receipt.contract_address, + "Contract should be deployed with the correct address." + ); + + let balance = client.get_balance(contract_address, BlockTag::Latest.into()).await?; + assert_eq!( + value * 1_000_000, + balance, + "Contract balance should be the same as the value sent." + ); // Call contract let hash = send_transaction(&account, &client, U256::zero(), Bytes::default(), Some(contract_address)) .await?; let receipt = wait_for_receipt(&client, hash).await?; - assert_eq!(contract_address, receipt.to.unwrap()); + assert_eq!( + Some(contract_address), + receipt.to, + "Receipt should have the correct contract address." + ); Ok(()) } From 82b4ca250b2d517e9677321cc6c78b2914d4babf Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 13:45:37 +0200 Subject: [PATCH 165/174] fix test --- substrate/frame/revive/rpc/src/tests.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 86c0b06549c7..e077bedd4d44 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -71,8 +71,17 @@ fn start_eth_rpc_server(node_ws_url: &str) -> (Child, String) { #[tokio::test] async fn test_jsonrpsee_server() -> anyhow::Result<()> { let mut node_child = substrate_cli_test_utils::start_node(); - let (info, _) = extract_info_from_output(node_child.stderr.take().unwrap()); - let (_rpc_child, ws_url) = start_eth_rpc_server(&info.ws_url); + + let _ = std::thread::spawn(move || { + match common::start_node_inline(vec!["--dev", "--rpc-port=45788"]) { + Ok(_) => {}, + Err(e) => { + panic!("Node exited with error: {}", e); + }, + } + }); + + let (_rpc_child, ws_url) = start_eth_rpc_server("ws://localhost:45788"); let client = WsClientBuilder::default().build(ws_url).await?; let account = Account::default(); From 67db7c41731337f47e0b3a84185968604bf2021f Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 14:05:47 +0200 Subject: [PATCH 166/174] fix test --- substrate/frame/revive/rpc/src/tests.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index e077bedd4d44..3ba89b528766 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -31,6 +31,7 @@ use pallet_revive::{ use std::{ io::{BufRead, BufReader}, process::{self, Child, Command}, + thread, }; use substrate_cli_test_utils::*; @@ -70,15 +71,11 @@ fn start_eth_rpc_server(node_ws_url: &str) -> (Child, String) { #[tokio::test] async fn test_jsonrpsee_server() -> anyhow::Result<()> { - let mut node_child = substrate_cli_test_utils::start_node(); - - let _ = std::thread::spawn(move || { - match common::start_node_inline(vec!["--dev", "--rpc-port=45788"]) { - Ok(_) => {}, - Err(e) => { - panic!("Node exited with error: {}", e); - }, - } + let _ = thread::spawn(move || match start_node_inline(vec!["--dev", "--rpc-port=45788"]) { + Ok(_) => {}, + Err(e) => { + panic!("Node exited with error: {}", e); + }, }); let (_rpc_child, ws_url) = start_eth_rpc_server("ws://localhost:45788"); From 072734f59e16d7f0e31879072e7f44714133d7ce Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 15:39:54 +0200 Subject: [PATCH 167/174] fix test --- Cargo.lock | 1 - substrate/frame/revive/rpc/Cargo.toml | 1 - substrate/frame/revive/rpc/src/cli.rs | 136 ++++++++++++++++++++++++ substrate/frame/revive/rpc/src/lib.rs | 2 + substrate/frame/revive/rpc/src/main.rs | 118 +------------------- substrate/frame/revive/rpc/src/tests.rs | 67 +++++------- 6 files changed, 166 insertions(+), 159 deletions(-) create mode 100644 substrate/frame/revive/rpc/src/cli.rs diff --git a/Cargo.lock b/Cargo.lock index 9ef72a9332c1..8c3119464b96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12552,7 +12552,6 @@ name = "pallet-revive-eth-rpc" version = "0.1.0" dependencies = [ "anyhow", - "assert_cmd", "clap 4.5.13", "env_logger 0.11.3", "futures", diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml index 04e7a1de74fc..304a77d0c377 100644 --- a/substrate/frame/revive/rpc/Cargo.toml +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -81,4 +81,3 @@ riscv = ["pallet-revive/riscv"] hex-literal = { workspace = true } pallet-revive-fixtures = { workspace = true } substrate-cli-test-utils = { workspace = true } -assert_cmd = { workspace = true } diff --git a/substrate/frame/revive/rpc/src/cli.rs b/substrate/frame/revive/rpc/src/cli.rs new file mode 100644 index 000000000000..4d61fad9d53d --- /dev/null +++ b/substrate/frame/revive/rpc/src/cli.rs @@ -0,0 +1,136 @@ +// 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. +//! The Ethereum JSON-RPC server. +use crate::{ + client::Client, EthRpcClient, EthRpcServer, EthRpcServerImpl, MiscRpcServer, MiscRpcServerImpl, + LOG_TARGET, +}; +use clap::Parser; +use hyper::Method; +use jsonrpsee::{ + http_client::HttpClientBuilder, + server::{RpcModule, Server}, +}; +use std::net::SocketAddr; +use tower_http::cors::{Any, CorsLayer}; + +// Parsed command instructions from the command line +#[derive(Parser)] +#[clap(author, about, version)] +pub struct CliCommand { + /// The server address to bind to + #[clap(long, default_value = "9090")] + pub rpc_port: String, + + /// The node url to connect to + #[clap(long, default_value = "ws://127.0.0.1:9944")] + pub node_rpc_url: String, +} + +/// Run the JSON-RPC server. +pub async fn run(cmd: CliCommand) -> anyhow::Result<()> { + let CliCommand { rpc_port, node_rpc_url } = cmd; + let client = Client::from_url(&node_rpc_url).await?; + let mut updates = client.updates.clone(); + + let server_addr = run_server(client, &format!("127.0.0.1:{rpc_port}")).await?; + log::info!("Running JSON-RPC server: addr={server_addr}"); + + let url = format!("http://{}", server_addr); + let client = HttpClientBuilder::default().build(url)?; + + let block_number = client.block_number().await?; + log::info!(target: LOG_TARGET, "Client initialized with block number {block_number:?}"); + + // keep running server until ctrl-c or client subscription fails + let _ = updates.wait_for(|_| false).await; + Ok(()) +} + +#[cfg(feature = "dev")] +mod dev { + use crate::LOG_TARGET; + use futures::{future::BoxFuture, FutureExt}; + use jsonrpsee::{server::middleware::rpc::RpcServiceT, types::Request, MethodResponse}; + + /// Dev Logger middleware, that logs the method and params of the request, along with the + /// success of the response. + #[derive(Clone)] + pub struct DevLogger(pub S); + + impl<'a, S> RpcServiceT<'a> for DevLogger + where + S: RpcServiceT<'a> + Send + Sync + Clone + 'static, + { + type Future = BoxFuture<'a, MethodResponse>; + + fn call(&self, req: Request<'a>) -> Self::Future { + let service = self.0.clone(); + let method = req.method.clone(); + let params = req.params.clone().unwrap_or_default(); + + async move { + log::info!(target: LOG_TARGET, "Method: {method} params: {params}"); + let resp = service.call(req).await; + if resp.is_success() { + log::info!(target: LOG_TARGET, "✅ rpc: {method}"); + } else { + log::info!(target: LOG_TARGET, "❌ rpc: {method} {}", resp.as_result()); + } + resp + } + .boxed() + } + } +} + +/// Starts the rpc server and returns the server address. +async fn run_server(client: Client, url: &str) -> anyhow::Result { + let cors = CorsLayer::new() + .allow_methods([Method::POST]) + .allow_origin(Any) + .allow_headers([hyper::header::CONTENT_TYPE]); + let cors_middleware = tower::ServiceBuilder::new().layer(cors); + + let builder = Server::builder().set_http_middleware(cors_middleware); + + #[cfg(feature = "dev")] + let builder = builder + .set_rpc_middleware(jsonrpsee::server::RpcServiceBuilder::new().layer_fn(dev::DevLogger)); + + let server = builder.build(url.parse::()?).await?; + let addr = server.local_addr()?; + + let eth_api = EthRpcServerImpl::new(client) + .with_accounts(if cfg!(feature = "dev") { + use pallet_revive::evm::Account; + vec![Account::default()] + } else { + vec![] + }) + .into_rpc(); + let misc_api = MiscRpcServerImpl.into_rpc(); + + let mut module = RpcModule::new(()); + module.merge(eth_api)?; + module.merge(misc_api)?; + + let handle = server.start(module); + tokio::spawn(handle.stopped()); + + Ok(addr) +} diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index 8907195c2c10..75e58dd112af 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -27,6 +27,8 @@ use jsonrpsee::{ use pallet_revive::{evm::*, EthContractResult}; use sp_core::{H160, H256, U256}; use thiserror::Error; + +pub mod cli; pub mod client; pub mod example; pub mod subxt_client; diff --git a/substrate/frame/revive/rpc/src/main.rs b/substrate/frame/revive/rpc/src/main.rs index 6b613274416d..b1306ad096b0 100644 --- a/substrate/frame/revive/rpc/src/main.rs +++ b/substrate/frame/revive/rpc/src/main.rs @@ -16,32 +16,9 @@ // limitations under the License. //! The Ethereum JSON-RPC server. use clap::Parser; -use hyper::Method; -use jsonrpsee::{ - http_client::HttpClientBuilder, - server::{RpcModule, Server}, -}; -use pallet_revive_eth_rpc::{ - client::Client, EthRpcClient, EthRpcServer, EthRpcServerImpl, MiscRpcServer, MiscRpcServerImpl, - LOG_TARGET, -}; -use std::net::SocketAddr; -use tower_http::cors::{Any, CorsLayer}; +use pallet_revive_eth_rpc::cli; use tracing_subscriber::{util::SubscriberInitExt, EnvFilter, FmtSubscriber}; -// Parsed command instructions from the command line -#[derive(Parser)] -#[clap(author, about, version)] -struct CliCommand { - /// The server address to bind to - #[clap(long, default_value = "9090")] - rpc_port: String, - - /// The node url to connect to - #[clap(long, default_value = "ws://127.0.0.1:9944")] - node_rpc_url: String, -} - /// Initialize tracing fn init_tracing() { let env_filter = @@ -56,96 +33,7 @@ fn init_tracing() { #[tokio::main] async fn main() -> anyhow::Result<()> { - let CliCommand { rpc_port, node_rpc_url } = CliCommand::parse(); init_tracing(); - - let client = Client::from_url(&node_rpc_url).await?; - let mut updates = client.updates.clone(); - - let server_addr = run_server(client, &format!("127.0.0.1:{rpc_port}")).await?; - log::info!("Running JSON-RPC server: addr={server_addr}"); - - let url = format!("http://{}", server_addr); - let client = HttpClientBuilder::default().build(url)?; - - let response = client.block_number().await?; - log::info!(target: LOG_TARGET, "Client initialized with block number {:?}", response); - - // keep running server until ctrl-c or client subscription fails - let _ = updates.wait_for(|_| false).await; - Ok(()) -} - -#[cfg(feature = "dev")] -mod dev { - use crate::LOG_TARGET; - use futures::{future::BoxFuture, FutureExt}; - use jsonrpsee::{server::middleware::rpc::RpcServiceT, types::Request, MethodResponse}; - - /// Dev Logger middleware, that logs the method and params of the request, along with the - /// success of the response. - #[derive(Clone)] - pub struct DevLogger(pub S); - - impl<'a, S> RpcServiceT<'a> for DevLogger - where - S: RpcServiceT<'a> + Send + Sync + Clone + 'static, - { - type Future = BoxFuture<'a, MethodResponse>; - - fn call(&self, req: Request<'a>) -> Self::Future { - let service = self.0.clone(); - let method = req.method.clone(); - let params = req.params.clone().unwrap_or_default(); - - async move { - log::info!(target: LOG_TARGET, "Method: {method} params: {params}"); - let resp = service.call(req).await; - if resp.is_success() { - log::info!(target: LOG_TARGET, "✅ rpc: {method}"); - } else { - log::info!(target: LOG_TARGET, "❌ rpc: {method} {}", resp.as_result()); - } - resp - } - .boxed() - } - } -} - -/// Starts the rpc server and returns the server address. -async fn run_server(client: Client, url: &str) -> anyhow::Result { - let cors = CorsLayer::new() - .allow_methods([Method::POST]) - .allow_origin(Any) - .allow_headers([hyper::header::CONTENT_TYPE]); - let cors_middleware = tower::ServiceBuilder::new().layer(cors); - - let builder = Server::builder().set_http_middleware(cors_middleware); - - #[cfg(feature = "dev")] - let builder = builder - .set_rpc_middleware(jsonrpsee::server::RpcServiceBuilder::new().layer_fn(dev::DevLogger)); - - let server = builder.build(url.parse::()?).await?; - let addr = server.local_addr()?; - - let eth_api = EthRpcServerImpl::new(client) - .with_accounts(if cfg!(feature = "dev") { - use pallet_revive::evm::Account; - vec![Account::default()] - } else { - vec![] - }) - .into_rpc(); - let misc_api = MiscRpcServerImpl.into_rpc(); - - let mut module = RpcModule::new(()); - module.merge(eth_api)?; - module.merge(misc_api)?; - - let handle = server.start(module); - tokio::spawn(handle.stopped()); - - Ok(addr) + let cmd = cli::CliCommand::parse(); + cli::run(cmd).await } diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 3ba89b528766..a23aa7c8820e 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -19,68 +19,51 @@ // We require the `riscv` feature to get access to the compiled fixtures. #![cfg(feature = "riscv")] use crate::{ + cli, example::{send_transaction, wait_for_receipt}, EthRpcClient, }; -use assert_cmd::cargo::cargo_bin; -use jsonrpsee::ws_client::WsClientBuilder; +use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use pallet_revive::{ create1, evm::{Account, BlockTag, Bytes, U256}, }; -use std::{ - io::{BufRead, BufReader}, - process::{self, Child, Command}, - thread, -}; +use std::thread; use substrate_cli_test_utils::*; -/// Start eth-rpc server, and return the child process and the WebSocket URL. -fn start_eth_rpc_server(node_ws_url: &str) -> (Child, String) { - let mut child = Command::new(cargo_bin("eth-rpc")) - .stdout(process::Stdio::piped()) - .stderr(process::Stdio::piped()) - .env("RUST_LOG", "info,eth-rpc=debug") - .args(["--rpc-port=45788", &format!("--node-rpc-url={node_ws_url}")]) - .spawn() - .unwrap(); - - let mut data = String::new(); - let ws_url = BufReader::new(child.stdout.take().unwrap()) - .lines() - .find_map(|line| { - let line = line.expect("failed to obtain next line while extracting node info"); - data.push_str(&line); - data.push('\n'); - - // does the line contain our port (we expect this specific output from eth-rpc). - let sock_addr = match line.split_once("Running JSON-RPC server: addr=") { - None => return None, - Some((_, after)) => after.trim(), - }; - - Some(format!("ws://{}", sock_addr)) - }) - .unwrap_or_else(|| { - eprintln!("Observed eth-rpc output:\n{}", data); - panic!("We should get a WebSocket address") - }); - - (child, ws_url) +/// Create a websocket client with a 30s timeout. +async fn ws_client_with_retry(url: &str) -> WsClient { + let timeout = tokio::time::Duration::from_secs(30); + tokio::time::timeout(timeout, async { + loop { + if let Ok(client) = WsClientBuilder::default().build(url).await { + return client + } else { + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + } + } + }) + .await + .expect("Hit timeout"); } #[tokio::test] async fn test_jsonrpsee_server() -> anyhow::Result<()> { - let _ = thread::spawn(move || match start_node_inline(vec!["--dev", "--rpc-port=45788"]) { + // Start the node. + let _ = thread::spawn(move || match start_node_inline(vec!["--dev", "--rpc-port=45789"]) { Ok(_) => {}, Err(e) => { panic!("Node exited with error: {}", e); }, }); - let (_rpc_child, ws_url) = start_eth_rpc_server("ws://localhost:45788"); + // Start the rpc server. + tokio::spawn(cli::run(cli::CliCommand { + rpc_port: "45788".to_string(), + node_rpc_url: "ws://localhost:45789".to_string(), + })); - let client = WsClientBuilder::default().build(ws_url).await?; + let client = ws_client_with_retry("ws://localhost:45788").await; let account = Account::default(); // Deploy contract From 83f6686c379d34d8d88ea6eedf90e4c60486fb73 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 17:43:20 +0200 Subject: [PATCH 168/174] fix ; --- substrate/frame/revive/rpc/src/cli.rs | 2 +- substrate/frame/revive/rpc/src/tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/rpc/src/cli.rs b/substrate/frame/revive/rpc/src/cli.rs index 4d61fad9d53d..348c3bbbc3d9 100644 --- a/substrate/frame/revive/rpc/src/cli.rs +++ b/substrate/frame/revive/rpc/src/cli.rs @@ -54,7 +54,7 @@ pub async fn run(cmd: CliCommand) -> anyhow::Result<()> { let client = HttpClientBuilder::default().build(url)?; let block_number = client.block_number().await?; - log::info!(target: LOG_TARGET, "Client initialized with block number {block_number:?}"); + log::info!(target: LOG_TARGET, "Client initialized - Current 📦 block: #{block_number:?}"); // keep running server until ctrl-c or client subscription fails let _ = updates.wait_for(|_| false).await; diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index a23aa7c8820e..8b618469f25d 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -44,7 +44,7 @@ async fn ws_client_with_retry(url: &str) -> WsClient { } }) .await - .expect("Hit timeout"); + .expect("Hit timeout") } #[tokio::test] From a0c79709d5b15e2bd47814aabbcd606e06177559 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 17:43:58 +0200 Subject: [PATCH 169/174] fix log message --- substrate/frame/revive/rpc/src/client.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index bd2f08661b3f..4915e7eaf2fd 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -608,7 +608,10 @@ impl Client { block: BlockNumberOrTagOrHash, ) -> Result, ClientError> { let runtime_api = self.runtime_api(&block).await?; - let from = tx.from.ok_or(ClientError::DryRunFailed)?; + let from = tx.from.ok_or_else(|| { + log::debug!(target: LOG_TARGET, "Dry run failed: from address is missing"); + ClientError::DryRunFailed + })?; let value = tx .value .unwrap_or_default() From f0fe2b9cc1e29e46df54572d81cf2a2f61bee7f0 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 19:27:06 +0200 Subject: [PATCH 170/174] PR review --- prdoc/pr_6192.prdoc | 7 ------- substrate/bin/node/runtime/Cargo.toml | 1 - substrate/frame/revive/Cargo.toml | 1 - 3 files changed, 9 deletions(-) delete mode 100644 prdoc/pr_6192.prdoc diff --git a/prdoc/pr_6192.prdoc b/prdoc/pr_6192.prdoc deleted file mode 100644 index cd9255486706..000000000000 --- a/prdoc/pr_6192.prdoc +++ /dev/null @@ -1,7 +0,0 @@ -title: '[pallet-revive] fix hardcoded gas in tests' -doc: -- audience: Runtime Dev - description: Fix hardcoded gas limits in tests -crates: -- name: pallet-revive - bump: patch diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 5495fc65eaf4..7acf4294c51b 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -58,7 +58,6 @@ std = [ "scale-info/std", "serde_json/std", "sp-debug-derive/std", - "sp-debug-derive/std", "substrate-wasm-builder", ] runtime-benchmarks = [ diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index d11d656430af..8dbad5ffd8b6 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -129,7 +129,6 @@ runtime-benchmarks = [ "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-transaction-payment/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", From 552c547d69c96836d85680920b958dd9b0393d24 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 19:33:15 +0200 Subject: [PATCH 171/174] rm Misc --- substrate/frame/revive/rpc/src/cli.rs | 7 +------ substrate/frame/revive/rpc/src/lib.rs | 18 ------------------ 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/substrate/frame/revive/rpc/src/cli.rs b/substrate/frame/revive/rpc/src/cli.rs index 348c3bbbc3d9..426554fd0318 100644 --- a/substrate/frame/revive/rpc/src/cli.rs +++ b/substrate/frame/revive/rpc/src/cli.rs @@ -15,10 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. //! The Ethereum JSON-RPC server. -use crate::{ - client::Client, EthRpcClient, EthRpcServer, EthRpcServerImpl, MiscRpcServer, MiscRpcServerImpl, - LOG_TARGET, -}; +use crate::{client::Client, EthRpcClient, EthRpcServer, EthRpcServerImpl, LOG_TARGET}; use clap::Parser; use hyper::Method; use jsonrpsee::{ @@ -123,11 +120,9 @@ async fn run_server(client: Client, url: &str) -> anyhow::Result { vec![] }) .into_rpc(); - let misc_api = MiscRpcServerImpl.into_rpc(); let mut module = RpcModule::new(()); module.merge(eth_api)?; - module.merge(misc_api)?; let handle = server.start(module); tokio::spawn(handle.stopped()); diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index 75e58dd112af..1e59d6d55d0e 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -41,14 +41,6 @@ pub use rpc_methods_gen::*; pub const LOG_TARGET: &str = "eth-rpc"; -/// Additional RPC methods, exposed on the RPC server on top of all the eth_xxx methods. -#[rpc(server, client)] -pub trait MiscRpc { - /// Returns the health status of the server. - #[method(name = "healthcheck")] - async fn healthcheck(&self) -> RpcResult<()>; -} - /// An EVM RPC server implementation. pub struct EthRpcServerImpl { /// The client used to interact with the substrate node. @@ -366,13 +358,3 @@ impl EthRpcServer for EthRpcServerImpl { Ok(nonce) } } - -/// A [`MiscRpcServer`] RPC server implementation. -pub struct MiscRpcServerImpl; - -#[async_trait] -impl MiscRpcServer for MiscRpcServerImpl { - async fn healthcheck(&self) -> RpcResult<()> { - Ok(()) - } -} From acd84d8801bb2f2e0ecbe95fc1ccb28fefcab136 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Thu, 24 Oct 2024 21:04:13 +0200 Subject: [PATCH 172/174] fix ci check --- substrate/frame/revive/rpc/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index 1e59d6d55d0e..a6d47063ef90 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -21,7 +21,6 @@ use crate::runtime::GAS_PRICE; use client::ClientError; use jsonrpsee::{ core::{async_trait, RpcResult}, - proc_macros::rpc, types::{ErrorCode, ErrorObjectOwned}, }; use pallet_revive::{evm::*, EthContractResult}; From 42b99263d6367c3094da78f00500a2b00a3d1193 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 25 Oct 2024 12:11:13 +0200 Subject: [PATCH 173/174] Nit changes after testing against AH --- substrate/frame/revive/rpc/Cargo.toml | 10 +++++----- .../frame/revive/rpc/examples/rust/deploy.rs | 4 +++- substrate/frame/revive/rpc/kitchensink.scale | Bin 651742 -> 0 bytes substrate/frame/revive/rpc/src/example.rs | 2 +- substrate/frame/revive/rpc/src/subxt_client.rs | 6 +++--- substrate/frame/revive/src/evm/api/account.rs | 9 +++++++++ 6 files changed, 21 insertions(+), 10 deletions(-) delete mode 100644 substrate/frame/revive/rpc/kitchensink.scale diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml index 304a77d0c377..3c05bdeef478 100644 --- a/substrate/frame/revive/rpc/Cargo.toml +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -15,27 +15,27 @@ path = "src/main.rs" [[example]] name = "deploy" path = "examples/rust/deploy.rs" -required-features = ["example"] +required-features = ["example", "riscv"] [[example]] name = "transfer" path = "examples/rust/transfer.rs" -required-features = ["example"] +required-features = ["example", "riscv"] [[example]] name = "rpc-playground" path = "examples/rust/rpc-playground.rs" -required-features = ["example"] +required-features = ["example", "riscv"] [[example]] name = "extrinsic" path = "examples/rust/extrinsic.rs" -required-features = ["example"] +required-features = ["example", "riscv"] [[example]] name = "remark-extrinsic" path = "examples/rust/remark-extrinsic.rs" -required-features = ["example"] +required-features = ["example", "riscv"] [dependencies] clap = { workspace = true, features = ["derive"] } diff --git a/substrate/frame/revive/rpc/examples/rust/deploy.rs b/substrate/frame/revive/rpc/examples/rust/deploy.rs index 8f90fe61fe22..225d44b14c8c 100644 --- a/substrate/frame/revive/rpc/examples/rust/deploy.rs +++ b/substrate/frame/revive/rpc/examples/rust/deploy.rs @@ -32,7 +32,9 @@ async fn main() -> anyhow::Result<()> { let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; let input = bytes.into_iter().chain(data.clone()).collect::>(); - println!("Account address: {:?}", account.address()); + println!("Account:"); + println!("- address: {:?}", account.address()); + println!("- substrate: {}", account.substrate_account()); let client = HttpClientBuilder::default().build("http://localhost:9090")?; println!("\n\n=== Deploying contract ===\n\n"); diff --git a/substrate/frame/revive/rpc/kitchensink.scale b/substrate/frame/revive/rpc/kitchensink.scale deleted file mode 100644 index 79d351c763d844d8169d60989a63bffdeb0e19c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 651742 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

N(hBdNNi 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 diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs index b9b6fdd26167..cdf5ce9d1b98 100644 --- a/substrate/frame/revive/rpc/src/example.rs +++ b/substrate/frame/revive/rpc/src/example.rs @@ -29,7 +29,7 @@ pub async fn wait_for_receipt( client: &(impl EthRpcClient + Send + Sync), hash: H256, ) -> anyhow::Result { - for _ in 0..6 { + for _ in 0..30 { tokio::time::sleep(std::time::Duration::from_secs(2)).await; let receipt = client.get_transaction_receipt(hash).await?; if let Some(receipt) = receipt { diff --git a/substrate/frame/revive/rpc/src/subxt_client.rs b/substrate/frame/revive/rpc/src/subxt_client.rs index fc151730fcb2..1362143fa3a7 100644 --- a/substrate/frame/revive/rpc/src/subxt_client.rs +++ b/substrate/frame/revive/rpc/src/subxt_client.rs @@ -15,12 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. //! The generated subxt client. -//! Generated with -//! subxt metadata --url ws://localhost:9944 -o rpc/kitchensink.scale +//! Generated against a substrate chain configured with [`pallet_revive`] using: +//! subxt metadata --url ws://localhost:9944 -o rpc/revive_chain.scale use subxt::config::{signed_extensions, Config, PolkadotConfig}; #[subxt::subxt( - runtime_metadata_path = "kitchensink.scale", + runtime_metadata_path = "revive_chain.scale", substitute_type( path = "pallet_revive::primitives::EthContractResult", with = "::subxt::utils::Static<::pallet_revive::EthContractResult>" diff --git a/substrate/frame/revive/src/evm/api/account.rs b/substrate/frame/revive/src/evm/api/account.rs index c2217defc31f..06fb6e7e9c21 100644 --- a/substrate/frame/revive/src/evm/api/account.rs +++ b/substrate/frame/revive/src/evm/api/account.rs @@ -20,6 +20,7 @@ use crate::{ H160, }; use rlp::Encodable; +use sp_runtime::AccountId32; /// A simple account that can sign transactions pub struct Account(subxt_signer::eth::Keypair); @@ -42,6 +43,14 @@ impl Account { H160::from_slice(&self.0.account_id().as_ref()) } + /// Get the substrate [`AccountId32`] of the account. + pub fn substrate_account(&self) -> AccountId32 { + let mut account_id = AccountId32::new([0xEE; 32]); + >::as_mut(&mut account_id)[..20] + .copy_from_slice(self.address().as_ref()); + account_id + } + /// Sign a transaction. pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { let rlp_encoded = tx.rlp_bytes(); From 5bdd9d7c4ee1569aa035f5f4d75770c42c2566b6 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 25 Oct 2024 13:06:20 +0200 Subject: [PATCH 174/174] Best block is fine --- substrate/frame/revive/rpc/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index 4915e7eaf2fd..ef7945f1591a 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -418,7 +418,7 @@ impl Client { async fn subscribe_blocks(inner: Arc, tx: Sender<()>) -> Result<(), ClientError> { log::info!(target: LOG_TARGET, "Subscribing to new blocks"); let mut block_stream = - inner.as_ref().api.blocks().subscribe_finalized().await.inspect_err(|err| { + inner.as_ref().api.blocks().subscribe_best().await.inspect_err(|err| { log::error!("Failed to subscribe to blocks: {err:?}"); })?;

jV`D222cER1+5Gr5w-x^4a4StyJl@v!_!5B|G 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 Q3%ekid;HMSXIt5S0w)E}`2YX_ literal 0 HcmV?d00001 diff --git a/substrate/frame/revive/rpc/metadata.scale b/substrate/frame/revive/rpc/metadata.scale new file mode 100644 index 0000000000000000000000000000000000000000..ffd5662a46e848ca6ce0ef9c6a2d88d03bf18705 GIT binary patch literal 57102 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 literal 0 HcmV?d00001 diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs new file mode 100644 index 000000000000..9e8db2c72f01 --- /dev/null +++ b/substrate/frame/revive/rpc/src/client.rs @@ -0,0 +1,741 @@ +//! The client connects to the source substrate chain +//! and is used by the rpc server to query and send transactions to the substrate chain. + +#![allow(unused_imports, unused_variables)] +use crate::{ + rlp, + subxt_client::{ + revive::calls::types::EthTransact, + runtime_types::{frame_system::EventRecord, revive_runtime::RuntimeEvent}, + }, + TransactionLegacySigned, LOG_TARGET, +}; +use codec::{Decode, Encode}; +use futures::{stream, StreamExt}; +use jsonrpsee::types::{ErrorCode, ErrorObjectOwned}; +use pallet_revive::{ + create1, + evm::{ + Block, BlockNumberOrTag, BlockNumberOrTagOrHash, Bytes256, GenericTransaction, ReceiptInfo, + TransactionSigned, H160, H256, U256, + }, + ContractResult, EthContractResult, EthInstantiateInput, +}; +use sp_runtime::traits::Hash; +use sp_weights::Weight; +use std::{ + collections::{HashMap, VecDeque}, + sync::Arc, + time::Duration, +}; +use subxt::{ + backend::{ + legacy::LegacyRpcMethods, + rpc::{ + reconnecting_rpc_client::{Client as ReconnectingRpcClient, ExponentialBackoff}, + RpcClient, + }, + }, + config::{signed_extensions::CheckNonce, Header}, + error::RpcError, + storage::Storage, + tx::TxClient, + utils::AccountId32, + Config, OnlineClient, +}; +use subxt_client::transaction_payment::events::TransactionFeePaid; +use thiserror::Error; +use tokio::{ + sync::{watch::Sender, RwLock}, + task::JoinSet, +}; + +use crate::subxt_client::{self, system::events::ExtrinsicSuccess, SrcChainConfig}; + +pub mod primitives { + use sp_core::H160; + pub type Hashing = sp_runtime::traits::BlakeTwo256; + pub type AccountId = sp_runtime::AccountId32; + pub type AccountIndex = u32; + pub type MultiAddress = sp_runtime::MultiAddress; +} + +/// The substrate block type. +pub type SubstrateBlock = subxt::blocks::Block>; + +/// The substrate block number type. +pub type SubstrateBlockNumber = <::Header as Header>::Number; + +/// The substrate block hash type. +pub type SubstrateBlockHash = ::Hash; + +/// Type alias for shared data. +pub type Shared = Arc>; + +/// The runtime balance type. +pub type Balance = u128; + +/// The EVM gas price. +/// We use a fixed value for the gas price. +/// This let us calculate the gas estimate for a transaction with the formula: +/// `estimate_gas = substrate_fee / gas_price`. +pub const GAS_PRICE: u128 = 1u128; + +/// The cache maintains a buffer of the last N blocks, +#[derive(Default)] +struct BlockCache { + /// A double-ended queue of the last N blocks. + /// The most recent block is at the back of the queue, and the oldest block is at the front. + buffer: VecDeque>, + + /// A map of blocks by block number. + blocks_by_number: HashMap>, + + /// A map of blocks by block hash. + blocks_by_hash: HashMap>, + + /// A map of receipts by hash. + receipts_by_hash: HashMap, + + /// A map of Signed transaction by hash. + signed_tx_by_hash: HashMap, + + /// A map of receipt hashes by block hash. + tx_hashes_by_block_and_index: HashMap>, +} + +/// The error type for the client. +#[derive(Error, Debug)] +pub enum ClientError { + /// A [`subxt::Error`] wrapper error. + #[error("Subxt error: {0}")] + SubxtError(#[from] subxt::Error), + /// A [`RpcError`] wrapper error. + #[error("RPC error: {0}")] + RpcError(#[from] RpcError), + /// A [`codec::Error`] wrapper error. + #[error("Codec error: {0}")] + CodecError(#[from] codec::Error), + /// The dry run failed. + #[error("Dry run failed")] + DryRunFailed, + /// A decimal conversion failed. + #[error("Conversion failed")] + ConversionFailed, + /// The block hash was not found. + #[error("Hash not found")] + BlockNotFound, + /// The transaction fee could not be found + #[error("TransactionFeePaid event not found")] + TxFeeNotFound, + /// The token decimals property was not found + #[error("tokenDecimals not found in properties")] + TokenDecimalsNotFound, + /// The cache is empty. + #[error("Cache is empty")] + CacheEmpty, +} + +// Convert a `ClientError` to an RPC `ErrorObjectOwned`. +impl From for ErrorObjectOwned { + fn from(_value: ClientError) -> Self { + ErrorObjectOwned::owned::<()>( + ErrorCode::InternalError.code(), + ErrorCode::InternalError.message(), + None, + ) + } +} + +/// The number of recent blocks maintained by the cache. +/// For each block in the cache, we also store the EVM transaction receipts. +pub const CACHE_SIZE: usize = 10; + +impl BlockCache { + fn latest_block(&self) -> Option<&Arc> { + self.buffer.back() + } + + /// Insert an entry into the cache, and prune the oldest entry if the cache is full. + fn insert(&mut self, block: SubstrateBlock) { + if self.buffer.len() >= N { + if let Some(block) = self.buffer.pop_front() { + log::trace!(target: LOG_TARGET, "Pruning block: {}", block.number()); + let hash = block.hash(); + self.blocks_by_hash.remove(&hash); + self.blocks_by_number.remove(&block.number()); + if let Some(entries) = self.tx_hashes_by_block_and_index.remove(&hash) { + for hash in entries.values() { + self.receipts_by_hash.remove(hash); + } + } + } + } + + let block = Arc::new(block); + self.buffer.push_back(block.clone()); + self.blocks_by_number.insert(block.number(), block.clone()); + self.blocks_by_hash.insert(block.hash(), block); + } +} + +/// A client connect to a node and maintains a cache of the last `CACHE_SIZE` blocks. +pub struct Client { + inner: Arc, + join_set: JoinSet>, + /// A watch channel to signal cache updates. + pub updates: tokio::sync::watch::Receiver<()>, +} + +/// The inner state of the client. +struct ClientInner { + api: OnlineClient, + rpc_client: ReconnectingRpcClient, + rpc: LegacyRpcMethods, + cache: Shared>, + chain_id: u64, + max_block_weight: Weight, + native_to_evm_ratio: U256, +} + +impl ClientInner { + /// Create a new client instance connecting to the substrate node at the given URL. + async fn from_url(url: &str) -> Result { + let rpc_client = ReconnectingRpcClient::builder() + .retry_policy(ExponentialBackoff::from_millis(100).max_delay(Duration::from_secs(10))) + .build(url.to_string()) + .await?; + + let api = OnlineClient::::from_rpc_client(rpc_client.clone()).await?; + let cache = Arc::new(RwLock::new(BlockCache::::default())); + + let rpc = LegacyRpcMethods::::new(RpcClient::new(rpc_client.clone())); + + let (native_to_evm_ratio, chain_id, max_block_weight) = + tokio::try_join!(native_to_evm_ratio(&rpc), chain_id(&api), max_block_weight(&api))?; + + Ok(Self { api, rpc_client, rpc, cache, chain_id, max_block_weight, native_to_evm_ratio }) + } + + /// Convert a native balance to an EVM balance. + pub fn native_to_evm_decimals(&self, value: U256) -> U256 { + value.saturating_mul(self.native_to_evm_ratio) + } + + /// Get the receipt infos from the extrinsics in a block. + async fn receipt_infos( + &self, + block: &SubstrateBlock, + ) -> Result, ClientError> { + // Get extrinsics from the block + let extrinsics = block.extrinsics().await?; + + // Filter extrinsics from pallet_revive + let extrinsics = extrinsics.iter().flat_map(|ext| { + let ext = ext.ok()?; + + let call = ext.as_extrinsic::().ok()??; + let tx = rlp::decode::(&call.payload).ok()?; + let from = tx.recover_eth_address().ok()?; + let contract_address = if tx.transaction_legacy_unsigned.to.is_none() { + Some(create1(&from, tx.transaction_legacy_unsigned.nonce.try_into().ok()?)) + } else { + None + }; + + Some((from, tx, contract_address, ext)) + }); + + // Map each extrinsic to a receipt + stream::iter(extrinsics) + .map(|(from, tx, contract_address, ext)| async move { + let events = ext.events().await?; + let tx_fees = + events.find_first::()?.ok_or(ClientError::TxFeeNotFound)?; + + let gas_price = tx.transaction_legacy_unsigned.gas_price; + let gas_used = (tx_fees.tip.saturating_add(tx_fees.actual_fee)) + .checked_div(gas_price.as_u128()) + .unwrap_or_default(); + + let success = events.find_first::().is_ok(); + let transaction_index = ext.index(); + let transaction_hash = primitives::Hashing::hash(&Vec::from(ext.bytes()).encode()); + let block_hash = block.hash(); + let block_number = block.number().into(); + + let receipt = ReceiptInfo { + block_hash, + block_number, + contract_address, + from, + to: tx.transaction_legacy_unsigned.to, + effective_gas_price: gas_price, + gas_used: gas_used.into(), + status: Some(if success { U256::one() } else { U256::zero() }), + transaction_hash, + transaction_index: transaction_index.into(), + ..Default::default() + }; + + Ok::<_, ClientError>((receipt.transaction_hash, (tx.into(), receipt))) + }) + .buffer_unordered(10) + .collect::>>() + .await + .into_iter() + .collect::, _>>() + } +} + +/// Drop all the tasks spawned by the client on drop. +impl Drop for Client { + fn drop(&mut self) { + self.join_set.abort_all() + } +} + +/// Fetch the chain ID from the substrate chain. +async fn chain_id(api: &OnlineClient) -> Result { + let query = subxt_client::constants().revive().chain_id(); + api.constants().at(&query).map_err(|err| err.into()) +} + +/// Fetch the max block weight from the substrate chain. +async fn max_block_weight(api: &OnlineClient) -> Result { + let query = subxt_client::constants().system().block_weights(); + let weights = api.constants().at(&query)?; + let max_block = weights.per_class.normal.max_extrinsic.unwrap_or(weights.max_block); + Ok(max_block.0) +} + +/// Fetch the native to EVM ratio from the substrate chain. +async fn native_to_evm_ratio(rpc: &LegacyRpcMethods) -> Result { + let props = rpc.system_properties().await?; + let eth_decimals = U256::from(18u32); + let native_decimals: U256 = props + .get("tokenDecimals") + .and_then(|v| v.as_number()?.as_u64()) + .ok_or(ClientError::TokenDecimalsNotFound)? + .into(); + + Ok(U256::from(10u32).pow(eth_decimals - native_decimals)) +} + +/// Extract the block timestamp. +async fn extract_block_timestamp(block: &SubstrateBlock) -> Option { + let extrinsics = block.extrinsics().await.ok()?; + let ext = extrinsics + .find_first::() + .ok()??; + + Some(ext.value.now / 1000) +} + +impl Client { + /// Create a new client instance. + /// The client will subscribe to new blocks and maintain a cache of [`CACHE_SIZE`] blocks. + pub async fn from_url(url: &str) -> Result { + log::info!(target: LOG_TARGET, "Connecting to node at: {url} ..."); + let inner: Arc = Arc::new(ClientInner::from_url(url).await?); + log::info!(target: LOG_TARGET, "Connected to node at: {url}"); + + let (tx, mut updates) = tokio::sync::watch::channel(()); + let mut join_set = JoinSet::new(); + join_set.spawn(Self::subscribe_blocks(inner.clone(), tx)); + join_set.spawn(Self::subscribe_reconnect(inner.clone())); + + updates.changed().await.expect("tx is not dropped"); + Ok(Self { inner, join_set, updates }) + } + + /// Subscribe and log reconnection events. + async fn subscribe_reconnect(inner: Arc) -> Result<(), ClientError> { + let rpc = inner.as_ref().rpc_client.clone(); + loop { + let reconnected = rpc.reconnect_initiated().await; + log::info!("RPC client connection lost"); + let now = std::time::Instant::now(); + reconnected.await; + log::info!("RPC client reconnection took `{}s`", now.elapsed().as_secs()); + } + } + + /// Subscribe to new blocks and update the cache. + async fn subscribe_blocks(inner: Arc, tx: Sender<()>) -> Result<(), ClientError> { + log::info!("Subscribing to new blocks"); + let mut block_stream = + inner.as_ref().api.blocks().subscribe_finalized().await.inspect_err(|err| { + log::error!("Failed to subscribe to blocks: {err:?}"); + })?; + + while let Some(block) = block_stream.next().await { + let block = match block { + Ok(block) => block, + Err(err) => { + if err.is_disconnected_will_reconnect() { + log::warn!( + "The RPC connection was lost and we may have missed a few blocks" + ); + continue; + } + + log::error!("Failed to fetch block: {err:?}"); + return Err(err.into()); + }, + }; + + log::debug!("Pushing block: {}", block.number()); + let mut cache = inner.cache.write().await; + + let receipts = inner + .receipt_infos(&block) + .await + .inspect_err(|err| { + log::error!("Failed to get receipts: {err:?}"); + }) + .unwrap_or_default(); + + if !receipts.is_empty() { + log::debug!("Adding {} receipts", receipts.len()); + let values = receipts + .iter() + .map(|(hash, (_, receipt))| (receipt.transaction_index, *hash)) + .collect::>(); + + cache.tx_hashes_by_block_and_index.insert(block.hash(), values); + + cache + .receipts_by_hash + .extend(receipts.iter().map(|(hash, (_, receipt))| (*hash, receipt.clone()))); + + cache.signed_tx_by_hash.extend( + receipts.iter().map(|(hash, (signed_tx, _))| (*hash, signed_tx.clone())), + ) + } + + cache.insert(block); + tx.send_replace(()); + } + + log::info!("Block subscription ended"); + Ok(()) + } + + /// Get the most recent block stored in the cache. + pub async fn latest_block(&self) -> Option> { + let cache = self.inner.cache.read().await; + let block = cache.latest_block()?; + Some(block.clone()) + } + + /// Expose the transaction API. + pub fn tx(&self) -> TxClient> { + self.inner.api.tx() + } + + /// Get an EVM transaction receipt by hash. + pub async fn receipt(&self, tx_hash: &H256) -> Option { + let cache = self.inner.cache.read().await; + cache.receipts_by_hash.get(tx_hash).cloned() + } + + /// Get an EVM transaction receipt by hash. + pub async fn receipt_by_hash_and_index( + &self, + block_hash: &H256, + transaction_index: &U256, + ) -> Option { + let cache = self.inner.cache.read().await; + let receipt_hash = + cache.tx_hashes_by_block_and_index.get(block_hash)?.get(transaction_index)?; + let receipt = cache.receipts_by_hash.get(receipt_hash)?; + Some(receipt.clone()) + } + + pub async fn signed_tx_by_hash(&self, tx_hash: &H256) -> Option { + let cache = self.inner.cache.read().await; + cache.signed_tx_by_hash.get(tx_hash).cloned() + } + + /// Get receipts count per block. + pub async fn receipts_count_per_block(&self, block_hash: &SubstrateBlockHash) -> Option { + let cache = self.inner.cache.read().await; + cache.tx_hashes_by_block_and_index.get(block_hash).map(|v| v.len()) + } + + /// Expose the storage API. + pub async fn storage_api( + &self, + at: &BlockNumberOrTagOrHash, + ) -> Result>, ClientError> { + match at { + BlockNumberOrTagOrHash::U256(block_number) => { + let n: SubstrateBlockNumber = + (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; + + let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; + Ok(self.inner.api.storage().at(hash)) + }, + BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.storage().at(*hash)), + BlockNumberOrTagOrHash::BlockTag(_) => { + if let Some(block) = self.latest_block().await { + return Ok(self.inner.api.storage().at(block.hash())); + } + let storage = self.inner.api.storage().at_latest().await?; + Ok(storage) + }, + } + } + + /// Expose the runtime API. + pub async fn runtime_api( + &self, + at: &BlockNumberOrTagOrHash, + ) -> Result< + subxt::runtime_api::RuntimeApi>, + ClientError, + > { + match at { + BlockNumberOrTagOrHash::U256(block_number) => { + let n: SubstrateBlockNumber = + (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; + + let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; + Ok(self.inner.api.runtime_api().at(hash)) + }, + BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.runtime_api().at(*hash)), + BlockNumberOrTagOrHash::BlockTag(_) => { + if let Some(block) = self.latest_block().await { + return Ok(self.inner.api.runtime_api().at(block.hash())); + } + + let api = self.inner.api.runtime_api().at_latest().await?; + Ok(api) + }, + } + } + + /// Get the balance of the given address. + pub async fn balance( + &self, + address: H160, + at: &BlockNumberOrTagOrHash, + ) -> Result { + let account_id = self.account_id(&address); + let query = subxt_client::storage().system().account(account_id); + let Some(account) = self.storage_api(at).await?.fetch(&query).await? else { + return Ok(U256::zero()); + }; + + let native = account.data.free.into(); + Ok(self.inner.native_to_evm_decimals(native)) + } + + /// Get the contract storage for the given contract address and key. + pub async fn get_contract_storage( + &self, + contract_address: H160, + key: U256, + block: BlockNumberOrTagOrHash, + ) -> Result, ClientError> { + let runtime_api = self.runtime_api(&block).await?; + + let mut bytes = [0u8; 32]; + key.to_big_endian(&mut bytes); + + let payload = subxt_client::apis().revive_api().get_storage(contract_address, bytes); + let result = runtime_api.call(payload).await?.unwrap_or_default().unwrap_or_default(); + Ok(result) + } + + /// Get the contract code for the given contract address. + pub async fn get_contract_code( + &self, + contract_address: &H160, + block: BlockNumberOrTagOrHash, + ) -> Result, ClientError> { + let storage_api = self.storage_api(&block).await?; + let account_id = self.account_id(contract_address); + let code_hash: H256 = account_id.0.into(); + let query = subxt_client::storage().revive().pristine_code(code_hash); + let result = storage_api.fetch(&query).await?.map(|v| v.0).unwrap_or_default(); + Ok(result) + } + + /// Dry run a transaction and returns the [`DryRunInfo`] for the transaction. + pub async fn dry_run( + &self, + tx: &GenericTransaction, + block: BlockNumberOrTagOrHash, + ) -> Result, ClientError> { + let runtime_api = self.runtime_api(&block).await?; + let from = tx.from.ok_or(ClientError::DryRunFailed)?; + let value = tx + .value + .unwrap_or_default() + .try_into() + .map_err(|_| ClientError::ConversionFailed)?; + + let payload = subxt_client::apis().revive_api().eth_transact( + from, + tx.to, + value, + tx.input.clone().unwrap_or_default().0, + None, + None, + ); + let res = runtime_api.call(payload).await?.0; + Ok(res) + } + + /// Dry run a transaction and returns the gas estimate for the transaction. + pub async fn estimate_gas( + &self, + tx: &GenericTransaction, + block: BlockNumberOrTagOrHash, + ) -> Result { + let dry_run = self.dry_run(tx, block).await?; + Ok(U256::from(dry_run.fee / GAS_PRICE) + 1) + } + + /// Get the nonce of the given address. + pub async fn nonce( + &self, + address: H160, + block: BlockNumberOrTagOrHash, + ) -> Result { + let account_id = self.account_id(&address); + let storage = self.storage_api(&block).await?; + let query = subxt_client::storage().system().account(account_id); + let Some(account) = storage.fetch(&query).await? else { + return Ok(0); + }; + + Ok(account.nonce) + } + + /// Get the block number of the latest block. + pub async fn block_number(&self) -> Result { + let cache = self.inner.cache.read().await; + let latest_block = cache.buffer.back().ok_or(ClientError::CacheEmpty)?; + Ok(latest_block.number()) + } + + /// Get a block hash for the given block number. + pub async fn get_block_hash( + &self, + block_number: SubstrateBlockNumber, + ) -> Result, ClientError> { + let cache = self.inner.cache.read().await; + if let Some(block) = cache.blocks_by_number.get(&block_number) { + return Ok(Some(block.hash())); + } + + let hash = self.inner.rpc.chain_get_block_hash(Some(block_number.into())).await?; + Ok(hash) + } + + /// Get a block for the specified hash or number. + pub async fn block_by_number_or_tag( + &self, + block: &BlockNumberOrTag, + ) -> Result>, ClientError> { + match block { + BlockNumberOrTag::U256(n) => { + let n = (*n).try_into().map_err(|_| ClientError::ConversionFailed)?; + self.block_by_number(n).await + }, + BlockNumberOrTag::BlockTag(_) => { + let cache = self.inner.cache.read().await; + Ok(cache.buffer.back().cloned()) + }, + } + } + + /// Get a block by hash + pub async fn block_by_hash( + &self, + hash: &SubstrateBlockHash, + ) -> Result>, ClientError> { + let cache = self.inner.cache.read().await; + if let Some(block) = cache.blocks_by_hash.get(hash) { + return Ok(Some(block.clone())); + } + + match self.inner.api.blocks().at(*hash).await { + Ok(block) => Ok(Some(Arc::new(block))), + Err(subxt::Error::Block(subxt::error::BlockError::NotFound(_))) => Ok(None), + Err(err) => Err(err.into()), + } + } + + /// Get a block by number + pub async fn block_by_number( + &self, + block_number: SubstrateBlockNumber, + ) -> Result>, ClientError> { + let cache = self.inner.cache.read().await; + if let Some(block) = cache.blocks_by_number.get(&block_number) { + return Ok(Some(block.clone())); + } + + let Some(hash) = self.get_block_hash(block_number).await? else { + return Ok(None); + }; + + self.block_by_hash(&hash).await + } + + /// Get the EVM block for the given hash. + pub async fn evm_block(&self, block: Arc) -> Result { + let runtime_api = self.inner.api.runtime_api().at(block.hash()); + let max_fee = Self::weight_to_fee(&runtime_api, self.max_block_weight()).await?; + let gas_limit = U256::from(max_fee / GAS_PRICE); + + let header = block.header(); + let timestamp = extract_block_timestamp(&block).await.unwrap_or_default(); + Ok(Block { + hash: block.hash(), + parent_hash: header.parent_hash, + state_root: header.state_root, + transactions_root: header.extrinsics_root, + number: header.number.into(), + timestamp: timestamp.into(), + gas_limit, + logs_bloom: Bytes256([0u8; 256]), + receipts_root: header.extrinsics_root, + ..Default::default() + }) + } + + /// Convert a weight to a fee. + async fn weight_to_fee( + runtime_api: &subxt::runtime_api::RuntimeApi>, + weight: Weight, + ) -> Result { + let payload = subxt_client::apis() + .transaction_payment_api() + .query_weight_to_fee(weight.into()); + + let fee = runtime_api.call(payload).await?; + Ok(fee) + } + + /// Get the substrate account ID from the EVM address. + pub fn account_id(&self, address: &H160) -> AccountId32 { + let mut id: [u8; 32] = [0xEE; 32]; + id[..20].copy_from_slice(address.as_bytes()); + AccountId32(id) + } + + /// Get the chain ID. + pub fn chain_id(&self) -> u64 { + self.inner.chain_id + } + + /// Get the Max Block Weight. + pub fn max_block_weight(&self) -> Weight { + self.inner.max_block_weight + } +} diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs new file mode 100644 index 000000000000..d1c39aa95d23 --- /dev/null +++ b/substrate/frame/revive/rpc/src/example.rs @@ -0,0 +1,114 @@ +//! Example utilities +#![cfg(feature = "example")] + +use anyhow::Context; +use jsonrpsee::http_client::HttpClient; +use pallet_revive::evm::{ + rlp::*, BlockTag, Bytes, EthRpcClient, GenericTransaction, TransactionLegacySigned, + TransactionLegacyUnsigned, H160, H256, U256, +}; +use secp256k1::{Message, PublicKey, Secp256k1, SecretKey}; +use sp_core::keccak_256; +use std::str::FromStr; + +/// A simple account that can sign transactions +pub struct Account { + /// The secret key of the account + sk: SecretKey, +} + +impl Default for Account { + fn default() -> Self { + Account { + sk: SecretKey::from_str( + "a872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd57f", + ) + .unwrap(), + } + } +} + +impl Account { + /// Create an account from a keypair. + pub fn from_keypair(pair: &subxt_signer::ecdsa::Keypair) -> Self { + let sb = pair.0.secret_key().secret_bytes(); + Account { sk: SecretKey::from_slice(&sb).unwrap() } + } + + /// Get the [`H160`] address of the account. + pub fn address(&self) -> H160 { + let pub_key = + PublicKey::from_secret_key(&Secp256k1::new(), &self.sk).serialize_uncompressed(); + let hash = keccak_256(&pub_key[1..]); + H160::from_slice(&hash[12..]) + } + + /// Sign a transaction. + pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { + let rlp_encoded = tx.rlp_bytes(); + let tx_hash = keccak_256(&rlp_encoded); + let secp = Secp256k1::new(); + let msg = Message::from_digest(tx_hash); + let sig = secp.sign_ecdsa_recoverable(&msg, &self.sk); + let (recovery_id, sig) = sig.serialize_compact(); + let sig = sig.into_iter().chain([recovery_id.to_i32() as u8]).collect::>(); + TransactionLegacySigned::from(tx, &sig.try_into().unwrap()) + } + + /// Send a transaction. + pub async fn send_transaction( + &self, + client: &HttpClient, + value: U256, + input: Bytes, + to: Option, + ) -> anyhow::Result { + let from = self.address(); + + let chain_id = Some(client.chain_id().await?); + + let gas_price = client.gas_price().await?; + let nonce = client + .get_transaction_count(from, BlockTag::Latest.into()) + .await + .with_context(|| "Failed to fetch account nonce")?; + + let gas = client + .estimate_gas( + GenericTransaction { + from: Some(from), + input: Some(input.clone()), + value: Some(value), + gas_price: Some(gas_price), + to, + ..Default::default() + }, + None, + ) + .await + .with_context(|| "Failed to fetch gas estimate")?; + + println!("Estimated Gas: {gas:?}"); + + let unsigned_tx = TransactionLegacyUnsigned { + gas, + nonce, + to, + value, + input, + gas_price, + chain_id, + ..Default::default() + }; + + let tx = self.sign_transaction(unsigned_tx.clone()); + let bytes = tx.rlp_bytes().to_vec(); + + let hash = client + .send_raw_transaction(bytes.clone().into()) + .await + .with_context(|| "transaction failed")?; + + Ok(hash) + } +} diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs new file mode 100644 index 000000000000..5bbed3c3af09 --- /dev/null +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -0,0 +1,305 @@ +//! The [`EthRpcServer`] RPC server implementation +#![cfg_attr(docsrs, feature(doc_cfg))] + +use client::{ClientError, GAS_PRICE}; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + proc_macros::rpc, + types::{ErrorCode, ErrorObjectOwned}, +}; +pub use pallet_revive::{evm::*, EthContractResult}; +pub use sp_core::{H160, H256, U256}; +use thiserror::Error; +pub mod client; +pub mod example; +pub mod subxt_client; + +mod rpc_methods_gen; +pub use rpc_methods_gen::*; + +pub const LOG_TARGET: &str = "eth-rpc"; + +/// Additional RPC methods, exposed on the RPC server on top of all the eth_xxx methods. +#[rpc(server, client)] +pub trait MiscRpc { + /// Returns the health status of the server. + #[method(name = "healthcheck")] + async fn healthcheck(&self) -> RpcResult<()>; +} + +/// An EVM RPC server implementation. +pub struct EthRpcServerImpl { + client: client::Client, +} + +impl EthRpcServerImpl { + /// Creates a new [`EthRpcServerImpl`]. + pub fn new(client: client::Client) -> Self { + Self { client } + } +} + +/// The error type for the EVM RPC server. +#[derive(Error, Debug)] +pub enum EthRpcError { + /// A [`ClientError`] wrapper error. + #[error("Client error: {0}")] + ClientError(#[from] ClientError), + /// A [`rlp::DecoderError`] wrapper error. + #[error("Decoding error: {0}")] + RlpError(#[from] rlp::DecoderError), + /// A Decimals conversion error. + #[error("Conversion error")] + ConversionError, + /// An invalid signature error. + #[error("Invalid signature")] + InvalidSignature, + /// The account was not found at the given address + #[error("Account not found for address {0:?}")] + AccountNotFound(H160), +} + +impl From for ErrorObjectOwned { + fn from(value: EthRpcError) -> Self { + let code = match value { + EthRpcError::ClientError(_) => ErrorCode::InternalError, + _ => ErrorCode::InvalidRequest, + }; + Self::owned::(code.code(), value.to_string(), None) + } +} + +#[async_trait] +impl EthRpcServer for EthRpcServerImpl { + async fn net_version(&self) -> RpcResult { + Ok(self.client.chain_id().to_string()) + } + + async fn block_number(&self) -> RpcResult { + let number = self.client.block_number().await?; + Ok(number.into()) + } + + async fn get_transaction_receipt( + &self, + transaction_hash: H256, + ) -> RpcResult> { + let receipt = self.client.receipt(&transaction_hash).await; + Ok(receipt) + } + + async fn estimate_gas( + &self, + transaction: GenericTransaction, + _block: Option, + ) -> RpcResult { + let result = self.client.estimate_gas(&transaction, BlockTag::Latest.into()).await?; + Ok(result) + } + + async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult { + let tx = rlp::decode::(&transaction.0).map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to decode transaction: {err:?}"); + EthRpcError::from(err) + })?; + + let eth_addr = tx.recover_eth_address().map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to recover eth address: {err:?}"); + EthRpcError::InvalidSignature + })?; + + // Dry run the transaction to get the weight limit and storage deposit limit + let TransactionLegacyUnsigned { to, input, value, .. } = tx.transaction_legacy_unsigned; + let dry_run = self + .client + .dry_run( + &GenericTransaction { + from: Some(eth_addr), + input: Some(input.clone()), + to, + value: Some(value), + ..Default::default() + }, + BlockTag::Latest.into(), + ) + .await?; + + let EthContractResult { kind, gas_limit, storage_deposit, .. } = dry_run; + let call = subxt_client::tx().revive().eth_transact( + transaction.0, + gas_limit.into(), + storage_deposit, + kind.into(), + ); + let ext = self.client.tx().create_unsigned(&call).map_err(|err| ClientError::from(err))?; + let hash = ext.submit().await.map_err(|err| EthRpcError::ClientError(err.into()))?; + + Ok(hash) + } + + async fn get_block_by_hash( + &self, + block_hash: H256, + _hydrated_transactions: bool, + ) -> RpcResult> { + let Some(block) = self.client.block_by_hash(&block_hash).await? else { + return Ok(None); + }; + let block = self.client.evm_block(block).await?; + Ok(Some(block)) + } + + async fn get_balance( + &self, + address: Address, + block: BlockNumberOrTagOrHash, + ) -> RpcResult { + let balance = self.client.balance(address, &block).await?; + log::debug!(target: LOG_TARGET, "balance({address}): {balance:?}"); + Ok(balance) + } + + async fn chain_id(&self) -> RpcResult { + Ok(self.client.chain_id().into()) + } + + async fn gas_price(&self) -> RpcResult { + Ok(U256::from(GAS_PRICE)) + } + + async fn get_code(&self, address: Address, block: BlockNumberOrTagOrHash) -> RpcResult { + let code = self.client.get_contract_code(&address, block).await?; + Ok(code.into()) + } + + async fn accounts(&self) -> RpcResult> { + Ok(vec![]) + } + + async fn call( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult { + let dry_run = self + .client + .dry_run(&transaction, block.unwrap_or_else(|| BlockTag::Latest.into())) + .await?; + let output = dry_run.result.map_err(|err| { + log::debug!(target: LOG_TARGET, "Dry run failed: {err:?}"); + ClientError::DryRunFailed + })?; + + Ok(output.into()) + } + + async fn get_block_by_number( + &self, + block: BlockNumberOrTag, + _hydrated_transactions: bool, + ) -> RpcResult> { + let Some(block) = self.client.block_by_number_or_tag(&block).await? else { + return Ok(None); + }; + let block = self.client.evm_block(block).await?; + Ok(Some(block)) + } + + async fn get_block_transaction_count_by_hash( + &self, + block_hash: Option, + ) -> RpcResult> { + let block_hash = if let Some(block_hash) = block_hash { + block_hash + } else { + self.client.latest_block().await.ok_or(ClientError::BlockNotFound)?.hash() + }; + Ok(self.client.receipts_count_per_block(&block_hash).await.map(U256::from)) + } + + async fn get_block_transaction_count_by_number( + &self, + block: Option, + ) -> RpcResult> { + let Some(block) = self + .get_block_by_number(block.unwrap_or_else(|| BlockTag::Latest.into()), false) + .await? + else { + return Ok(None); + }; + + Ok(self.client.receipts_count_per_block(&block.hash).await.map(U256::from)) + } + + async fn get_storage_at( + &self, + address: Address, + storage_slot: U256, + block: BlockNumberOrTagOrHash, + ) -> RpcResult { + let bytes = self.client.get_contract_storage(address, storage_slot, block).await?; + Ok(bytes.into()) + } + + async fn get_transaction_by_block_hash_and_index( + &self, + block_hash: H256, + transaction_index: U256, + ) -> RpcResult> { + let Some(receipt) = + self.client.receipt_by_hash_and_index(&block_hash, &transaction_index).await + else { + return Ok(None); + }; + + let Some(signed_tx) = self.client.signed_tx_by_hash(&receipt.transaction_hash).await else { + return Ok(None); + }; + + Ok(Some(TransactionInfo::new(receipt, signed_tx))) + } + + async fn get_transaction_by_block_number_and_index( + &self, + block: BlockNumberOrTag, + transaction_index: U256, + ) -> RpcResult> { + let Some(block) = self.client.block_by_number_or_tag(&block).await? else { + return Ok(None); + }; + self.get_transaction_by_block_hash_and_index(block.hash(), transaction_index) + .await + } + + async fn get_transaction_by_hash( + &self, + transaction_hash: H256, + ) -> RpcResult> { + let receipt = self.client.receipt(&transaction_hash).await; + let signed_tx = self.client.signed_tx_by_hash(&transaction_hash).await; + if let (Some(receipt), Some(signed_tx)) = (receipt, signed_tx) { + return Ok(Some(TransactionInfo::new(receipt, signed_tx))); + } + + Ok(None) + } + + async fn get_transaction_count( + &self, + address: Address, + block: BlockNumberOrTagOrHash, + ) -> RpcResult { + let nonce = self.client.nonce(address, block).await?; + Ok(nonce.into()) + } +} + +/// A [`MiscRpcServer`] RPC server implementation. +pub struct MiscRpcServerImpl; + +#[async_trait] +impl MiscRpcServer for MiscRpcServerImpl { + async fn healthcheck(&self) -> RpcResult<()> { + Ok(()) + } +} diff --git a/substrate/frame/revive/rpc/src/main.rs b/substrate/frame/revive/rpc/src/main.rs new file mode 100644 index 000000000000..06e1d2a0de68 --- /dev/null +++ b/substrate/frame/revive/rpc/src/main.rs @@ -0,0 +1,128 @@ +//! The Ethereum JSON-RPC server. +use clap::Parser; +use hyper::Method; +use jsonrpsee::{ + http_client::HttpClientBuilder, + server::{RpcModule, Server}, +}; +use pallet_revive_eth_rpc::{ + client::Client, EthRpcClient, EthRpcServer, EthRpcServerImpl, MiscRpcServer, MiscRpcServerImpl, + LOG_TARGET, +}; +use std::net::SocketAddr; +use tower_http::cors::{Any, CorsLayer}; +use tracing_subscriber::{util::SubscriberInitExt, EnvFilter, FmtSubscriber}; + +// Parsed command instructions from the command line +#[derive(Parser)] +#[clap(author, about, version)] +struct CliCommand { + /// The server address to bind to + #[clap(long, default_value = "127.0.0.1:9090")] + url: String, + + /// The node url to connect to + #[clap(long, default_value = "ws://127.0.0.1:9944")] + node_url: String, +} + +/// Initialize tracing +fn init_tracing() { + let env_filter = + EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("eth_rpc=trace")); + + FmtSubscriber::builder() + .with_env_filter(env_filter) + .finish() + .try_init() + .expect("failed to initialize tracing"); +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let CliCommand { url, node_url } = CliCommand::parse(); + init_tracing(); + + let client = Client::from_url(&node_url).await.unwrap(); + let mut updates = client.updates.clone(); + + let server_addr = run_server(client, &url).await?; + log::info!(target: LOG_TARGET, "Server started on: {}", server_addr); + + let url = format!("http://{}", server_addr); + let client = HttpClientBuilder::default().build(url)?; + + let response = client.block_number().await?; + log::info!(target: LOG_TARGET, "client initialized with block number {:?}", response); + + // keep running server until ctrl-c or client subscription fails + let _ = updates.wait_for(|_| false).await; + Ok(()) +} + +#[cfg(feature = "dev")] +mod dev { + use crate::LOG_TARGET; + use futures::{future::BoxFuture, FutureExt}; + use jsonrpsee::{server::middleware::rpc::RpcServiceT, types::Request, MethodResponse}; + + /// Dev Logger middleware, that logs the method and params of the request, along with the + /// success of the response. + #[derive(Clone)] + pub struct DevLogger(pub S); + + impl<'a, S> RpcServiceT<'a> for DevLogger + where + S: RpcServiceT<'a> + Send + Sync + Clone + 'static, + { + type Future = BoxFuture<'a, MethodResponse>; + + fn call(&self, req: Request<'a>) -> Self::Future { + let service = self.0.clone(); + let method = req.method.clone(); + let params = req.params.clone().unwrap_or_default(); + + async move { + log::info!(target: LOG_TARGET, "method: {method} params: {params}"); + let resp = service.call(req).await; + if resp.is_success() { + log::info!(target: LOG_TARGET, "✅ method: {method}"); + } else { + log::info!(target: LOG_TARGET, "❌ method: {method} {}", resp.as_result()); + } + resp + } + .boxed() + } + } +} + +/// Starts the rpc server and returns the server address. +async fn run_server(client: Client, url: &str) -> anyhow::Result { + let cors = CorsLayer::new() + .allow_methods([Method::POST]) + .allow_origin(Any) + .allow_headers([hyper::header::CONTENT_TYPE]); + let cors_middleware = tower::ServiceBuilder::new().layer(cors); + + let builder = Server::builder().set_http_middleware(cors_middleware); + + #[cfg(feature = "dev")] + let builder = builder + .set_rpc_middleware(jsonrpsee::server::RpcServiceBuilder::new().layer_fn(dev::DevLogger)); + + let server = builder.build(url.parse::()?).await?; + let addr = server.local_addr()?; + + let eth_api = EthRpcServerImpl::new(client).into_rpc(); + let misc_api = MiscRpcServerImpl.into_rpc(); + + let mut module = RpcModule::new(()); + module.merge(eth_api)?; + module.merge(misc_api)?; + + let handle = server.start(module); + tokio::spawn(handle.stopped()); + + Ok(addr) +} diff --git a/substrate/frame/revive/rpc/src/rpc_methods_gen.rs b/substrate/frame/revive/rpc/src/rpc_methods_gen.rs new file mode 100644 index 000000000000..eb6bebe232b4 --- /dev/null +++ b/substrate/frame/revive/rpc/src/rpc_methods_gen.rs @@ -0,0 +1,152 @@ +// 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. +//! Generated JSON-RPC methods. +#![allow(missing_docs)] + +use super::*; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[rpc(server, client)] +pub trait EthRpc { + /// Returns a list of addresses owned by client. + #[method(name = "eth_accounts")] + async fn accounts(&self) -> RpcResult>; + + /// Returns the number of most recent block. + #[method(name = "eth_blockNumber")] + async fn block_number(&self) -> RpcResult; + + /// Executes a new message call immediately without creating a transaction on the block chain. + #[method(name = "eth_call")] + async fn call( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult; + + /// Returns the chain ID of the current network. + #[method(name = "eth_chainId")] + async fn chain_id(&self) -> RpcResult; + + /// Generates and returns an estimate of how much gas is necessary to allow the transaction to + /// complete. + #[method(name = "eth_estimateGas")] + async fn estimate_gas( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult; + + /// Returns the current price per gas in wei. + #[method(name = "eth_gasPrice")] + async fn gas_price(&self) -> RpcResult; + + /// Returns the balance of the account of given address. + #[method(name = "eth_getBalance")] + async fn get_balance(&self, address: Address, block: BlockNumberOrTagOrHash) + -> RpcResult; + + /// Returns information about a block by hash. + #[method(name = "eth_getBlockByHash")] + async fn get_block_by_hash( + &self, + block_hash: H256, + hydrated_transactions: bool, + ) -> RpcResult>; + + /// Returns information about a block by number. + #[method(name = "eth_getBlockByNumber")] + async fn get_block_by_number( + &self, + block: BlockNumberOrTag, + hydrated_transactions: bool, + ) -> RpcResult>; + + /// Returns the number of transactions in a block from a block matching the given block hash. + #[method(name = "eth_getBlockTransactionCountByHash")] + async fn get_block_transaction_count_by_hash( + &self, + block_hash: Option, + ) -> RpcResult>; + + /// Returns the number of transactions in a block matching the given block number. + #[method(name = "eth_getBlockTransactionCountByNumber")] + async fn get_block_transaction_count_by_number( + &self, + block: Option, + ) -> RpcResult>; + + /// Returns code at a given address. + #[method(name = "eth_getCode")] + async fn get_code(&self, address: Address, block: BlockNumberOrTagOrHash) -> RpcResult; + + /// Returns the value from a storage position at a given address. + #[method(name = "eth_getStorageAt")] + async fn get_storage_at( + &self, + address: Address, + storage_slot: U256, + block: BlockNumberOrTagOrHash, + ) -> RpcResult; + + /// Returns information about a transaction by block hash and transaction index position. + #[method(name = "eth_getTransactionByBlockHashAndIndex")] + async fn get_transaction_by_block_hash_and_index( + &self, + block_hash: H256, + transaction_index: U256, + ) -> RpcResult>; + + /// Returns information about a transaction by block number and transaction index position. + #[method(name = "eth_getTransactionByBlockNumberAndIndex")] + async fn get_transaction_by_block_number_and_index( + &self, + block: BlockNumberOrTag, + transaction_index: U256, + ) -> RpcResult>; + + /// Returns the information about a transaction requested by transaction hash. + #[method(name = "eth_getTransactionByHash")] + async fn get_transaction_by_hash( + &self, + transaction_hash: H256, + ) -> RpcResult>; + + /// Returns the number of transactions sent from an address. + #[method(name = "eth_getTransactionCount")] + async fn get_transaction_count( + &self, + address: Address, + block: BlockNumberOrTagOrHash, + ) -> RpcResult; + + /// Returns the receipt of a transaction by transaction hash. + #[method(name = "eth_getTransactionReceipt")] + async fn get_transaction_receipt( + &self, + transaction_hash: H256, + ) -> RpcResult>; + + /// Submits a raw transaction. For EIP-4844 transactions, the raw form must be the network form. + /// This means it includes the blobs, KZG commitments, and KZG proofs. + #[method(name = "eth_sendRawTransaction")] + async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult; + + /// The string value of current network id + #[method(name = "net_version")] + async fn net_version(&self) -> RpcResult; +} diff --git a/substrate/frame/revive/rpc/src/subxt_client.rs b/substrate/frame/revive/rpc/src/subxt_client.rs new file mode 100644 index 000000000000..eaff1b021f03 --- /dev/null +++ b/substrate/frame/revive/rpc/src/subxt_client.rs @@ -0,0 +1,45 @@ +//! The generated subxt client. +use subxt::config::{signed_extensions, Config, PolkadotConfig}; + +#[subxt::subxt( + runtime_metadata_path = "metadata.scale", + substitute_type( + path = "pallet_revive::primitives::EthContractResult", + with = "::subxt::utils::Static<::pallet_revive::EthContractResult>" + ), + substitute_type( + path = "pallet_revive::primitives::EthTransactKind", + with = "::subxt::utils::Static<::pallet_revive::EthTransactKind>" + ), + substitute_type( + path = "sp_weights::weight_v2::Weight", + with = "::subxt::utils::Static<::sp_weights::Weight>" + ) +)] +mod src_chain {} +pub use src_chain::*; + +/// The configuration for the source chain. +pub enum SrcChainConfig {} +impl Config for SrcChainConfig { + type Hash = ::Hash; + type AccountId = ::AccountId; + type Address = ::Address; + type Signature = ::Signature; + type Hasher = ::Hasher; + type Header = ::Header; + type AssetId = ::AssetId; + type ExtrinsicParams = signed_extensions::AnyOf< + Self, + ( + signed_extensions::CheckSpecVersion, + signed_extensions::CheckTxVersion, + signed_extensions::CheckNonce, + signed_extensions::CheckGenesis, + signed_extensions::CheckMortality, + signed_extensions::ChargeAssetTxPayment, + signed_extensions::ChargeTransactionPayment, + signed_extensions::CheckMetadataHash, + ), + >; +} From 19dbf4c94ba2cb934312f23aa085d3aff80c2268 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 21:04:22 +0200 Subject: [PATCH 054/174] wip --- substrate/bin/node/cli/src/chain_spec.rs | 8 ++++++++ substrate/frame/revive/rpc/Makefile | 4 ++-- substrate/frame/revive/rpc/kitchensink.scale | Bin 651254 -> 651612 bytes substrate/frame/revive/rpc/src/main.rs | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index bc7821bfcf30..e0cad10c6f9c 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -20,6 +20,7 @@ use polkadot_sdk::*; +use crate::chain_spec::sc_service::Properties; use kitchensink_runtime::{ constants::currency::*, wasm_binary_unwrap, Block, MaxNominations, SessionKeys, StakerStatus, }; @@ -447,12 +448,19 @@ fn development_config_genesis_json() -> serde_json::Value { ) } +fn props() -> Properties { + let mut properties = Properties::new(); + properties.insert("tokenDecimals".to_string(), "12".into()); + properties +} + /// Development config (single validator Alice). pub fn development_config() -> ChainSpec { ChainSpec::builder(wasm_binary_unwrap(), Default::default()) .with_name("Development") .with_id("dev") .with_chain_type(ChainType::Development) + .with_properties(props()) .with_genesis_config_patch(development_config_genesis_json()) .build() } diff --git a/substrate/frame/revive/rpc/Makefile b/substrate/frame/revive/rpc/Makefile index 64db1396a46c..6cf88b3b9ede 100644 --- a/substrate/frame/revive/rpc/Makefile +++ b/substrate/frame/revive/rpc/Makefile @@ -15,8 +15,8 @@ metadata: ifndef CHAIN $(error CHAIN is not defined. Please specify it when running make, e.g., make metadata CHAIN=) endif - @subxt explore --url ws://localhost:9944 pallet Revive constants chainId > /dev/null - subxt metadata --url ws://localhost:9944 -o $(CHAIN).scale + @subxt explore --url ws://localhost:9944 pallet Revive constants chainId > /dev/null + subxt metadata --url ws://localhost:9944 -o $(CHAIN).scale touch src/subxt_client.rs SALT ?= 0 diff --git a/substrate/frame/revive/rpc/kitchensink.scale b/substrate/frame/revive/rpc/kitchensink.scale index f9b520e7d67ad65ffacced036616f7eda0fdebf4..ceb4c6ba3ea2df0d0183637825654c3b7a0a6e18 100644 GIT binary patch delta 3376 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 B?5F?$ delta 3105 zcmZuz4Nz3q6~6cJ*t<8%zDETMDn=xTYa&@1XcvE4iEJXK1QgV0Yv~qV!V1gc?qZ;o zI;5duJ2r_9Il;)ZRB1wlshY7*XNn5`A_{KBA5@~oG99#7nTeU2%1qDOr*+?KXLk19 zci;KG^WE>>d+xjbWy;q#QcP~e@07OGnd(in-XzqUBI-?It0}TM!ddCs%$p-s-fa5d z5!AkCnhB%rkrMPavA+pq5GtEk98CV0Eu}-?{Fu$8A3?&0riW_nPNrJmkNZtCr`@s; zBF-MRj95l3W0nV&aSN3qr6?&@BE#^golSwo?aW3;^#1SK+4JCQXH#LIou$Abtv9)Y z&4mAGy@C!lYr;bdo#^m733+JQeqM-CKk8sRWje0o^A58YD20uO**q~)GB-eOR^+$0 z-?L7D>xbF=crMW;d6j;br(!|jym?tZpW@Fc`92{WY)4o!je_4FVKZRE5jK57v_$1x zPl-ZEv^Khk#=^}bEM16~w5%}aD9$zkaf}`Cm9tyfy55?r}CJEk_b(yjcZ3$Y%f*d&PkRCTTZexo6A7s)@as0vA`WdvmX0sm|KIcf{~MG zMDZ!MkXAv3OzLYLuwBoX|LB1G?pFg?;B(LTaO7hE3WGOCPUs zQ^*8MgY#?Bxb3tVXn-YR)7H!8BYQC6+X0qiYc*(X3)kAFYt(PVP^|Jzc4i5KY&VW9j!QeVzF^j&yo}>B#KxaQ5GIW>7$_I5*C>sTw-n-t@W2;LH+k7_8n_1 z5S;?9N112#Xlc-~~Ml{F8kz@nF8V<1P04uayVX=^N1&hQ> zSJ-6u%N4wws^A}2*blKuA7sg?X@;4nqh%S$7c9EzPc6&P2{T~xAp7g4OasOiim`=Z z78-)Hv_<(}hAgCgQW_tp(1t{_L(Y|n1G_?wOmbv%wy(0t?e-Q`dR=Z8bYEpw*ngG9 zet3g zhRAhcAGd`zBq%abpz%6x1{XvOu~qZkNb+gesZf4<~JJ=A;H1hw##` zh3+Ai@=TrfKG{s_W!RfVC#(Dmc07s>ZSK3v)V{msNq?p>@Z}Evg(~mloYFycN;BUc zxoOCfPsC;+Qy3F(S!OR;T&fh8;f=dS@p=lBiW0>;Y-v~&94)9+idQOL&4&?-Y!8kV zRzDsYwaB*M$g4_);&b`NEa`eguE*BVOZGY zS0_lbe^%}(E-S(XE=^ynj(y4(3z8x|=kq)LiYBCoxzxpb_-8^yl~kkN@8J0YtyQ!3 z@_Q3$9oRbgCcG5)cJf8ojCJz&=@!73uc)UF^E*PsRvj}{P|qLZ+XTD`ulDdZsYBOd zmwnE1zkMG}J;i@3bV{(Nmv1zaiDgQS{e-02&hnKM-s$11uxM*I`Bo^d7V9Yjm%`8) zK8=pSH)r@uSol(V`7ea=AlI*Gr267n{!99Nf;6#QsgR>&lD)o4@zxZ*sVGGyXsxT< zXP#J9?SC8)EfcsO;M3Kw&+$?LKlh5x^I`}f2e!8FUfs`Bk72L)ZH+U;e zgP5EAyEGGCyUEM&YfZh$Pg)#uOpq>DUM9zU1<&5*Q`FX5_LiYZXua2N~YVv)a JP9y4N@?TDZoxuPA diff --git a/substrate/frame/revive/rpc/src/main.rs b/substrate/frame/revive/rpc/src/main.rs index 06e1d2a0de68..f03d3321fb74 100644 --- a/substrate/frame/revive/rpc/src/main.rs +++ b/substrate/frame/revive/rpc/src/main.rs @@ -43,7 +43,7 @@ async fn main() -> anyhow::Result<()> { let CliCommand { url, node_url } = CliCommand::parse(); init_tracing(); - let client = Client::from_url(&node_url).await.unwrap(); + let client = Client::from_url(&node_url).await?; let mut updates = client.updates.clone(); let server_addr = run_server(client, &url).await?; From 595e66a982ec30c355bfd56c25dd4f5a6a81c2b5 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 7 Oct 2024 22:59:11 +0200 Subject: [PATCH 055/174] fixes --- Cargo.lock | 1 + substrate/bin/node/cli/Cargo.toml | 1 + substrate/bin/node/cli/src/chain_spec.rs | 16 +++++++- substrate/frame/revive/rpc/Cargo.toml | 3 +- substrate/frame/revive/rpc/examples/deploy.rs | 24 +++++++++--- .../frame/revive/rpc/examples/transfer.rs | 4 +- substrate/frame/revive/rpc/src/example.rs | 38 ++++--------------- 7 files changed, 47 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb89ecdfff11..7dc93f867d56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23565,6 +23565,7 @@ dependencies = [ "soketto 0.8.0", "staging-node-inspect", "substrate-cli-test-utils", + "subxt-signer", "tempfile", "tokio", "tokio-util", diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 6e734a723cd3..65c98bac5c38 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -46,6 +46,7 @@ futures = { workspace = true } log = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +subxt-signer = { workspace = true, features = ["unstable-eth"] } # The Polkadot-SDK: polkadot-sdk = { features = ["node"], workspace = true, default-features = true } diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index e0cad10c6f9c..722c3e41fdf0 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -322,6 +322,12 @@ fn configure_accounts( get_account_id_from_seed::("Dave//stash"), get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), + eth_account(subxt_signer::eth::dev::alith()), + eth_account(subxt_signer::eth::dev::baltathar()), + eth_account(subxt_signer::eth::dev::charleth()), + eth_account(subxt_signer::eth::dev::dorothy()), + eth_account(subxt_signer::eth::dev::ethan()), + eth_account(subxt_signer::eth::dev::faith()), ] }); // endow all authorities and nominators. @@ -450,10 +456,18 @@ fn development_config_genesis_json() -> serde_json::Value { fn props() -> Properties { let mut properties = Properties::new(); - properties.insert("tokenDecimals".to_string(), "12".into()); + properties.insert("tokenDecimals".to_string(), 12.into()); properties } +use crate::chain_spec::sp_runtime::AccountId32; +fn eth_account(from: subxt_signer::eth::Keypair) -> AccountId32 { + let mut account_id = AccountId32::new([0xEE; 32]); + >::as_mut(&mut account_id)[..20] + .copy_from_slice(&from.account_id().0); + account_id +} + /// Development config (single validator Alice). pub fn development_config() -> ChainSpec { ChainSpec::builder(wasm_binary_unwrap(), Default::default()) diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml index dbb84af54446..a54cdc4f9c0b 100644 --- a/substrate/frame/revive/rpc/Cargo.toml +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -52,7 +52,8 @@ sp-runtime = { workspace = true, default-features = true } tower.workspace = true tower-http = { workspace = true, features = ["full"] } hyper.workspace = true -subxt-signer = { workspace = true, optional = true } + +subxt-signer = { workspace = true, optional = true, features = ["unstable-eth"] } hex = { workspace = true, optional = true } hex-literal = { workspace = true, optional = true } scale-info = { workspace = true } diff --git a/substrate/frame/revive/rpc/examples/deploy.rs b/substrate/frame/revive/rpc/examples/deploy.rs index b75964fc424e..14d72b804d6e 100644 --- a/substrate/frame/revive/rpc/examples/deploy.rs +++ b/substrate/frame/revive/rpc/examples/deploy.rs @@ -1,11 +1,11 @@ use codec::Encode; -use eth_rpc::{example::Account, EthRpcClient, ReceiptInfo}; use jsonrpsee::http_client::HttpClientBuilder; -use polkadot_sdk::pallet_revive::{ +use pallet_revive::{ create1, - evm::{BlockTag, Bytes, U256}, + evm::{BlockTag, Bytes, ReceiptInfo, U256}, EthInstantiateInput, }; +use pallet_revive_eth_rpc::{example::Account, EthRpcClient}; static DUMMY_BYTES: &[u8] = include_bytes!("./dummy.polkavm"); @@ -26,7 +26,14 @@ async fn main() -> anyhow::Result<()> { let hash = account.send_transaction(&client, U256::zero(), input.into(), None).await?; println!("Deploy Tx hash: {hash:?}"); - tokio::time::sleep(std::time::Duration::from_secs(2)).await; + for _ in 0..6 { + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + let receipt = client.get_transaction_receipt(hash).await?; + if receipt.is_some() { + break; + } + } + let ReceiptInfo { block_number, gas_used, contract_address, .. } = client.get_transaction_receipt(hash).await?.unwrap(); println!("Receipt received: "); @@ -46,7 +53,14 @@ async fn main() -> anyhow::Result<()> { .await?; println!("Contract call tx hash: {hash:?}"); - tokio::time::sleep(std::time::Duration::from_secs(2)).await; + + for _ in 0..6 { + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + let receipt = client.get_transaction_receipt(hash).await?; + if receipt.is_some() { + break + } + } let ReceiptInfo { block_number, gas_used, to, .. } = client.get_transaction_receipt(hash).await?.unwrap(); diff --git a/substrate/frame/revive/rpc/examples/transfer.rs b/substrate/frame/revive/rpc/examples/transfer.rs index f363ca09dc43..9e1b615022a5 100644 --- a/substrate/frame/revive/rpc/examples/transfer.rs +++ b/substrate/frame/revive/rpc/examples/transfer.rs @@ -1,7 +1,7 @@ -use eth_rpc::{example::Account, EthRpcClient}; use hex_literal::hex; use jsonrpsee::http_client::HttpClientBuilder; -use polkadot_sdk::pallet_revive::evm::{BlockTag, Bytes, H160}; +use pallet_revive::evm::{BlockTag, Bytes, H160}; +use pallet_revive_eth_rpc::{example::Account, EthRpcClient}; #[tokio::main] async fn main() -> anyhow::Result<()> { diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs index d1c39aa95d23..1aa9b2f9b108 100644 --- a/substrate/frame/revive/rpc/src/example.rs +++ b/substrate/frame/revive/rpc/src/example.rs @@ -1,58 +1,34 @@ //! Example utilities #![cfg(feature = "example")] +use crate::EthRpcClient; use anyhow::Context; use jsonrpsee::http_client::HttpClient; use pallet_revive::evm::{ - rlp::*, BlockTag, Bytes, EthRpcClient, GenericTransaction, TransactionLegacySigned, + rlp::*, BlockTag, Bytes, GenericTransaction, TransactionLegacySigned, TransactionLegacyUnsigned, H160, H256, U256, }; -use secp256k1::{Message, PublicKey, Secp256k1, SecretKey}; -use sp_core::keccak_256; -use std::str::FromStr; /// A simple account that can sign transactions -pub struct Account { - /// The secret key of the account - sk: SecretKey, -} +pub struct Account(subxt_signer::eth::Keypair); impl Default for Account { fn default() -> Self { - Account { - sk: SecretKey::from_str( - "a872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd57f", - ) - .unwrap(), - } + Self(subxt_signer::eth::dev::alith()) } } impl Account { - /// Create an account from a keypair. - pub fn from_keypair(pair: &subxt_signer::ecdsa::Keypair) -> Self { - let sb = pair.0.secret_key().secret_bytes(); - Account { sk: SecretKey::from_slice(&sb).unwrap() } - } - /// Get the [`H160`] address of the account. pub fn address(&self) -> H160 { - let pub_key = - PublicKey::from_secret_key(&Secp256k1::new(), &self.sk).serialize_uncompressed(); - let hash = keccak_256(&pub_key[1..]); - H160::from_slice(&hash[12..]) + H160::from_slice(&self.0.account_id().as_ref()) } /// Sign a transaction. pub fn sign_transaction(&self, tx: TransactionLegacyUnsigned) -> TransactionLegacySigned { let rlp_encoded = tx.rlp_bytes(); - let tx_hash = keccak_256(&rlp_encoded); - let secp = Secp256k1::new(); - let msg = Message::from_digest(tx_hash); - let sig = secp.sign_ecdsa_recoverable(&msg, &self.sk); - let (recovery_id, sig) = sig.serialize_compact(); - let sig = sig.into_iter().chain([recovery_id.to_i32() as u8]).collect::>(); - TransactionLegacySigned::from(tx, &sig.try_into().unwrap()) + let signature = self.0.sign(&rlp_encoded); + TransactionLegacySigned::from(tx, signature.as_ref()) } /// Send a transaction. From 96fa31d72c761f05a5cf8a9b042995cea9d134ab Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 08:51:41 +0200 Subject: [PATCH 056/174] wip --- Cargo.lock | 2 ++ substrate/bin/node/runtime/Cargo.toml | 1 + substrate/bin/node/runtime/src/lib.rs | 5 ++++- substrate/frame/revive/rpc/src/example.rs | 2 ++ substrate/frame/transaction-payment/Cargo.toml | 1 + substrate/frame/transaction-payment/src/lib.rs | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 7dc93f867d56..864151895231 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8548,6 +8548,7 @@ dependencies = [ "primitive-types 0.13.1", "scale-info", "serde_json", + "sp-debug-derive 14.0.0", "static_assertions", "substrate-wasm-builder", ] @@ -12986,6 +12987,7 @@ version = "28.0.0" dependencies = [ "frame-support", "frame-system", + "log", "pallet-balances", "parity-scale-codec", "scale-info", diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 6310e16d5a14..d389247bb872 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -27,6 +27,7 @@ scale-info = { features = ["derive", "serde"], workspace = true } static_assertions = { workspace = true, default-features = true } log = { workspace = true } serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } +sp-debug-derive = { workspace = true, features = ["force-debug"] } # pallet-asset-conversion: turn on "num-traits" feature primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index e9084af92566..61b353e981c6 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -3065,7 +3065,10 @@ impl_runtime_apis! { storage_deposit_limit.unwrap_or(u128::MAX), pallet_revive::DebugInfo::UnsafeDebug, pallet_revive::CollectEvents::UnsafeCollect, - ).map(pallet_transaction_payment::Pallet::::compute_fee) + ).map(|len, info, tip| { + log::info!(target: "evm", "compute_fee: len: {}, info: {:?}, tip: {:?}", len, info, tip); + pallet_transaction_payment::Pallet::::compute_fee(len, info, tip) + }) } fn call( diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs index 1aa9b2f9b108..c9613f188261 100644 --- a/substrate/frame/revive/rpc/src/example.rs +++ b/substrate/frame/revive/rpc/src/example.rs @@ -80,6 +80,8 @@ impl Account { let tx = self.sign_transaction(unsigned_tx.clone()); let bytes = tx.rlp_bytes().to_vec(); + println!("Encode transaction len: {:?}", bytes.len()); + let hash = client .send_raw_transaction(bytes.clone().into()) .await diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 4161a97f3cde..190d2de61351 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -26,6 +26,7 @@ frame-system = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } +log = { workspace = true } [dev-dependencies] serde_json = { workspace = true, default-features = true } diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index c17ab393b5d3..7e524f1d606f 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -577,6 +577,7 @@ impl Pallet { where T::RuntimeCall: Dispatchable, { + log::info!(target: "evm", "compute_fee: len: {len:?}, info: {info:?}, tip: {tip:?}"); Self::compute_fee_details(len, info, tip).final_fee() } From 551cd3daea1e84ef4ba2f50443a3b28f6c9214e0 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 17:19:00 +0200 Subject: [PATCH 057/174] update rpc stuff --- substrate/frame/revive/rpc/examples/deploy.rs | 29 +++++------------- .../frame/revive/rpc/examples/transfer.rs | 14 ++++++--- substrate/frame/revive/rpc/kitchensink.scale | Bin 651612 -> 651621 bytes substrate/frame/revive/rpc/metadata.scale | Bin 57102 -> 0 bytes substrate/frame/revive/rpc/src/client.rs | 8 ++--- substrate/frame/revive/rpc/src/example.rs | 17 ++++++++-- substrate/frame/revive/rpc/src/lib.rs | 4 +-- .../frame/revive/rpc/src/subxt_client.rs | 2 +- 8 files changed, 36 insertions(+), 38 deletions(-) delete mode 100644 substrate/frame/revive/rpc/metadata.scale diff --git a/substrate/frame/revive/rpc/examples/deploy.rs b/substrate/frame/revive/rpc/examples/deploy.rs index 14d72b804d6e..3b030c5f21bb 100644 --- a/substrate/frame/revive/rpc/examples/deploy.rs +++ b/substrate/frame/revive/rpc/examples/deploy.rs @@ -5,7 +5,10 @@ use pallet_revive::{ evm::{BlockTag, Bytes, ReceiptInfo, U256}, EthInstantiateInput, }; -use pallet_revive_eth_rpc::{example::Account, EthRpcClient}; +use pallet_revive_eth_rpc::{ + example::{wait_for_receipt, Account}, + EthRpcClient, +}; static DUMMY_BYTES: &[u8] = include_bytes!("./dummy.polkavm"); @@ -24,18 +27,10 @@ async fn main() -> anyhow::Result<()> { let input = input.encode(); let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; let hash = account.send_transaction(&client, U256::zero(), input.into(), None).await?; - println!("Deploy Tx hash: {hash:?}"); - - for _ in 0..6 { - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - let receipt = client.get_transaction_receipt(hash).await?; - if receipt.is_some() { - break; - } - } + println!("Deploy Tx hash: {hash:?}"); let ReceiptInfo { block_number, gas_used, contract_address, .. } = - client.get_transaction_receipt(hash).await?.unwrap(); + wait_for_receipt(&client, hash).await?; println!("Receipt received: "); println!("Block number: {block_number}"); println!("Gas used: {gas_used}"); @@ -53,17 +48,7 @@ async fn main() -> anyhow::Result<()> { .await?; println!("Contract call tx hash: {hash:?}"); - - for _ in 0..6 { - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - let receipt = client.get_transaction_receipt(hash).await?; - if receipt.is_some() { - break - } - } - - let ReceiptInfo { block_number, gas_used, to, .. } = - client.get_transaction_receipt(hash).await?.unwrap(); + let ReceiptInfo { block_number, gas_used, to, .. } = wait_for_receipt(&client, hash).await?; println!("Receipt received: "); println!("Block number: {block_number}"); println!("Gas used: {gas_used}"); diff --git a/substrate/frame/revive/rpc/examples/transfer.rs b/substrate/frame/revive/rpc/examples/transfer.rs index 9e1b615022a5..e89ca0e4c86a 100644 --- a/substrate/frame/revive/rpc/examples/transfer.rs +++ b/substrate/frame/revive/rpc/examples/transfer.rs @@ -1,7 +1,10 @@ use hex_literal::hex; use jsonrpsee::http_client::HttpClientBuilder; -use pallet_revive::evm::{BlockTag, Bytes, H160}; -use pallet_revive_eth_rpc::{example::Account, EthRpcClient}; +use pallet_revive::evm::{BlockTag, Bytes, ReceiptInfo, H160}; +use pallet_revive_eth_rpc::{ + example::{wait_for_receipt, Account}, + EthRpcClient, +}; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -20,9 +23,10 @@ async fn main() -> anyhow::Result<()> { let hash = account.send_transaction(&client, value, Bytes::default(), to).await?; println!("Transaction hash: {hash:?}"); - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - let receipt = client.get_transaction_receipt(hash).await; - println!("Receipt: {receipt:?}"); + let ReceiptInfo { block_number, gas_used, .. } = wait_for_receipt(&client, hash).await?; + println!("Receipt received: "); + println!("Block number: {block_number}"); + println!("Gas used: {gas_used}"); let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; println!("Account balance: {:?}", balance); diff --git a/substrate/frame/revive/rpc/kitchensink.scale b/substrate/frame/revive/rpc/kitchensink.scale index ceb4c6ba3ea2df0d0183637825654c3b7a0a6e18..86f6ce6ccdac59f2bcd930c8415f28c297f15f59 100644 GIT binary patch delta 42 xcmccfNd4&}^@bM47N!>F7M2#)7Pc+yZdazq&0$q)kH5kW#2nk>uWF7M2#)7Pc+yZdVuu+5@hz12M<;fGeD$vH(O84&nd+ diff --git a/substrate/frame/revive/rpc/metadata.scale b/substrate/frame/revive/rpc/metadata.scale deleted file mode 100644 index ffd5662a46e848ca6ce0ef9c6a2d88d03bf18705..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57102 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 diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index 9e8db2c72f01..203fab37ffb1 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -4,10 +4,7 @@ #![allow(unused_imports, unused_variables)] use crate::{ rlp, - subxt_client::{ - revive::calls::types::EthTransact, - runtime_types::{frame_system::EventRecord, revive_runtime::RuntimeEvent}, - }, + subxt_client::{revive::calls::types::EthTransact, runtime_types::frame_system::EventRecord}, TransactionLegacySigned, LOG_TARGET, }; use codec::{Decode, Encode}; @@ -138,7 +135,8 @@ pub enum ClientError { // Convert a `ClientError` to an RPC `ErrorObjectOwned`. impl From for ErrorObjectOwned { - fn from(_value: ClientError) -> Self { + fn from(value: ClientError) -> Self { + log::debug!(target: LOG_TARGET, "ClientError: {value:?}"); ErrorObjectOwned::owned::<()>( ErrorCode::InternalError.code(), ErrorCode::InternalError.message(), diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs index c9613f188261..e6787cef24f6 100644 --- a/substrate/frame/revive/rpc/src/example.rs +++ b/substrate/frame/revive/rpc/src/example.rs @@ -1,7 +1,7 @@ //! Example utilities #![cfg(feature = "example")] -use crate::EthRpcClient; +use crate::{EthRpcClient, ReceiptInfo}; use anyhow::Context; use jsonrpsee::http_client::HttpClient; use pallet_revive::evm::{ @@ -18,6 +18,19 @@ impl Default for Account { } } +/// Wait for a transaction receipt. +pub async fn wait_for_receipt(client: &HttpClient, hash: H256) -> anyhow::Result { + for _ in 0..6 { + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + let receipt = client.get_transaction_receipt(hash).await?; + if let Some(receipt) = receipt { + return Ok(receipt) + } + } + + anyhow::bail!("Failed to get receipt") +} + impl Account { /// Get the [`H160`] address of the account. pub fn address(&self) -> H160 { @@ -80,8 +93,6 @@ impl Account { let tx = self.sign_transaction(unsigned_tx.clone()); let bytes = tx.rlp_bytes().to_vec(); - println!("Encode transaction len: {:?}", bytes.len()); - let hash = client .send_raw_transaction(bytes.clone().into()) .await diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index 5bbed3c3af09..0f830bba7c1a 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -124,12 +124,12 @@ impl EthRpcServer for EthRpcServerImpl { ) .await?; - let EthContractResult { kind, gas_limit, storage_deposit, .. } = dry_run; + let EthContractResult { transact_kind, gas_limit, storage_deposit, .. } = dry_run; let call = subxt_client::tx().revive().eth_transact( transaction.0, gas_limit.into(), storage_deposit, - kind.into(), + transact_kind.into(), ); let ext = self.client.tx().create_unsigned(&call).map_err(|err| ClientError::from(err))?; let hash = ext.submit().await.map_err(|err| EthRpcError::ClientError(err.into()))?; diff --git a/substrate/frame/revive/rpc/src/subxt_client.rs b/substrate/frame/revive/rpc/src/subxt_client.rs index eaff1b021f03..847de2f7efdf 100644 --- a/substrate/frame/revive/rpc/src/subxt_client.rs +++ b/substrate/frame/revive/rpc/src/subxt_client.rs @@ -2,7 +2,7 @@ use subxt::config::{signed_extensions, Config, PolkadotConfig}; #[subxt::subxt( - runtime_metadata_path = "metadata.scale", + runtime_metadata_path = "kitchensink.scale", substitute_type( path = "pallet_revive::primitives::EthContractResult", with = "::subxt::utils::Static<::pallet_revive::EthContractResult>" From 2a90e9b6ae67b108ce060c7cf03bb066f202bde5 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 18:25:31 +0200 Subject: [PATCH 058/174] rlp encoding --- substrate/frame/revive/rpc/Cargo.toml | 3 ++- substrate/frame/revive/rpc/examples/deploy.rs | 6 ++---- substrate/frame/revive/rpc/src/client.rs | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml index a54cdc4f9c0b..c6b53ff4e89c 100644 --- a/substrate/frame/revive/rpc/Cargo.toml +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -53,6 +53,7 @@ tower.workspace = true tower-http = { workspace = true, features = ["full"] } hyper.workspace = true +rlp = { workspace = true, optional = true } subxt-signer = { workspace = true, optional = true, features = ["unstable-eth"] } hex = { workspace = true, optional = true } hex-literal = { workspace = true, optional = true } @@ -62,7 +63,7 @@ env_logger = { workspace = true } [features] dev = [] -example = ["hex", "hex-literal", "secp256k1", "subxt-signer"] +example = ["hex", "hex-literal", "secp256k1", "subxt-signer", "rlp"] [dev-dependencies] hex-literal.workspace = true diff --git a/substrate/frame/revive/rpc/examples/deploy.rs b/substrate/frame/revive/rpc/examples/deploy.rs index 3b030c5f21bb..cb0579d7e978 100644 --- a/substrate/frame/revive/rpc/examples/deploy.rs +++ b/substrate/frame/revive/rpc/examples/deploy.rs @@ -1,9 +1,7 @@ -use codec::Encode; use jsonrpsee::http_client::HttpClientBuilder; use pallet_revive::{ create1, - evm::{BlockTag, Bytes, ReceiptInfo, U256}, - EthInstantiateInput, + evm::{BlockTag, Bytes, EthInstantiateInput, ReceiptInfo, U256}, }; use pallet_revive_eth_rpc::{ example::{wait_for_receipt, Account}, @@ -24,7 +22,7 @@ async fn main() -> anyhow::Result<()> { println!("\n\n=== Deploying contract ===\n\n"); - let input = input.encode(); + let input = rlp::encode(&input).to_vec(); let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; let hash = account.send_transaction(&client, U256::zero(), input.into(), None).await?; diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index 203fab37ffb1..f75d157a1f78 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -13,10 +13,10 @@ use jsonrpsee::types::{ErrorCode, ErrorObjectOwned}; use pallet_revive::{ create1, evm::{ - Block, BlockNumberOrTag, BlockNumberOrTagOrHash, Bytes256, GenericTransaction, ReceiptInfo, - TransactionSigned, H160, H256, U256, + Block, BlockNumberOrTag, BlockNumberOrTagOrHash, Bytes256, EthInstantiateInput, + GenericTransaction, ReceiptInfo, TransactionSigned, H160, H256, U256, }, - ContractResult, EthContractResult, EthInstantiateInput, + ContractResult, EthContractResult, }; use sp_runtime::traits::Hash; use sp_weights::Weight; From 4dede9c30160a9c151b106353ffeb4e3a86f4527 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Tue, 8 Oct 2024 19:30:02 +0200 Subject: [PATCH 059/174] Update --- Cargo.lock | 1 + substrate/frame/revive/rpc/examples/deploy.rs | 16 ++++++++-------- substrate/frame/revive/rpc/examples/transfer.rs | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 864151895231..3ae156c6295d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12535,6 +12535,7 @@ dependencies = [ "log", "pallet-revive", "parity-scale-codec", + "rlp", "scale-info", "secp256k1", "serde_json", diff --git a/substrate/frame/revive/rpc/examples/deploy.rs b/substrate/frame/revive/rpc/examples/deploy.rs index cb0579d7e978..bae3697e96b5 100644 --- a/substrate/frame/revive/rpc/examples/deploy.rs +++ b/substrate/frame/revive/rpc/examples/deploy.rs @@ -29,10 +29,10 @@ async fn main() -> anyhow::Result<()> { println!("Deploy Tx hash: {hash:?}"); let ReceiptInfo { block_number, gas_used, contract_address, .. } = wait_for_receipt(&client, hash).await?; - println!("Receipt received: "); - println!("Block number: {block_number}"); - println!("Gas used: {gas_used}"); - println!("Contract address: {contract_address:?}"); + println!("Receipt:"); + println!("- Block number: {block_number}"); + println!("- Gas used: {gas_used}"); + println!("- Contract address: {contract_address:?}"); if std::env::var("SKIP_CALL").is_ok() { return Ok(()) @@ -47,9 +47,9 @@ async fn main() -> anyhow::Result<()> { println!("Contract call tx hash: {hash:?}"); let ReceiptInfo { block_number, gas_used, to, .. } = wait_for_receipt(&client, hash).await?; - println!("Receipt received: "); - println!("Block number: {block_number}"); - println!("Gas used: {gas_used}"); - println!("To: {to:?}"); + println!("Receipt:"); + println!("- Block number: {block_number}"); + println!("- Gas used: {gas_used}"); + println!("- To: {to:?}"); Ok(()) } diff --git a/substrate/frame/revive/rpc/examples/transfer.rs b/substrate/frame/revive/rpc/examples/transfer.rs index e89ca0e4c86a..634131f4da92 100644 --- a/substrate/frame/revive/rpc/examples/transfer.rs +++ b/substrate/frame/revive/rpc/examples/transfer.rs @@ -24,9 +24,9 @@ async fn main() -> anyhow::Result<()> { println!("Transaction hash: {hash:?}"); let ReceiptInfo { block_number, gas_used, .. } = wait_for_receipt(&client, hash).await?; - println!("Receipt received: "); - println!("Block number: {block_number}"); - println!("Gas used: {gas_used}"); + println!("Receipt: "); + println!("- Block number: {block_number}"); + println!("- Gas used: {gas_used}"); let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; println!("Account balance: {:?}", balance); From c2609faf0e979d2df364dd3a8e1a6691b02e8cfc Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 9 Oct 2024 09:52:39 +0200 Subject: [PATCH 060/174] add js stuff --- substrate/frame/revive/rpc/demo/package.json | 24 + .../frame/revive/rpc/demo/src/global.d.ts | 7 + .../frame/revive/rpc/demo/src/index.html | 28 + substrate/frame/revive/rpc/demo/src/main.ts | 102 ++++ substrate/frame/revive/rpc/demo/tsconfig.json | 13 + .../frame/revive/rpc/demo/vite.config.ts | 10 + substrate/frame/revive/rpc/demo/yarn.lock | 535 ++++++++++++++++++ .../frame/revive/rpc/examples/transfer.rs | 30 +- substrate/frame/revive/rpc/src/example.rs | 6 + 9 files changed, 742 insertions(+), 13 deletions(-) create mode 100644 substrate/frame/revive/rpc/demo/package.json create mode 100644 substrate/frame/revive/rpc/demo/src/global.d.ts create mode 100644 substrate/frame/revive/rpc/demo/src/index.html create mode 100644 substrate/frame/revive/rpc/demo/src/main.ts create mode 100644 substrate/frame/revive/rpc/demo/tsconfig.json create mode 100644 substrate/frame/revive/rpc/demo/vite.config.ts create mode 100644 substrate/frame/revive/rpc/demo/yarn.lock diff --git a/substrate/frame/revive/rpc/demo/package.json b/substrate/frame/revive/rpc/demo/package.json new file mode 100644 index 000000000000..a2e7e432013e --- /dev/null +++ b/substrate/frame/revive/rpc/demo/package.json @@ -0,0 +1,24 @@ +{ + "name": "metamask-deploy", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "dev": "vite", + "build": "vite build", + "prettier": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,md}\"" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@polkadot/types": "^12.2.1", + "@polkadot/util": "^13.0.2", + "ethers": "^6.13.1" + }, + "devDependencies": { + "@types/node": "^14.14.6", + "prettier": "^3.3.3", + "typescript": "^4.1.2", + "vite": "^2.5.0" + } +} diff --git a/substrate/frame/revive/rpc/demo/src/global.d.ts b/substrate/frame/revive/rpc/demo/src/global.d.ts new file mode 100644 index 000000000000..1500e4142af7 --- /dev/null +++ b/substrate/frame/revive/rpc/demo/src/global.d.ts @@ -0,0 +1,7 @@ +import { MetaMaskInpageProvider } from '@metamask/providers'; + +declare global { + interface Window { + ethereum?: MetaMaskInpageProvider; + } +} diff --git a/substrate/frame/revive/rpc/demo/src/index.html b/substrate/frame/revive/rpc/demo/src/index.html new file mode 100644 index 000000000000..c479742690d6 --- /dev/null +++ b/substrate/frame/revive/rpc/demo/src/index.html @@ -0,0 +1,28 @@ + + + + + + Deploy Contract with MetaMask + + + + + + + + + + + + + + + diff --git a/substrate/frame/revive/rpc/demo/src/main.ts b/substrate/frame/revive/rpc/demo/src/main.ts new file mode 100644 index 000000000000..564f16328e73 --- /dev/null +++ b/substrate/frame/revive/rpc/demo/src/main.ts @@ -0,0 +1,102 @@ +import { BrowserProvider, Contract, ContractFactory, JsonRpcSigner, parseEther, encodeRlp, AddressLike } from 'ethers'; +import { hexToU8a } from '@polkadot/util'; + +document.addEventListener('DOMContentLoaded', async () => { + if (typeof window.ethereum == 'undefined') { + return console.log('MetaMask is not installed'); + } + + console.log('MetaMask is installed!'); + const provider = new BrowserProvider(window.ethereum); + + console.log('Getting signer...'); + let signer: JsonRpcSigner; + try { + signer = await provider.getSigner(); + console.log(`Signer: ${signer.address}`); + } catch (e) { + console.error('Failed to get signer', e); + return; + } + + console.log('Getting block number...'); + try { + const blockNumber = await provider.getBlockNumber(); + console.log(`Block number: ${blockNumber}`); + } catch (e) { + console.error('Failed to get block number', e); + return; + } + + const nonce = await signer.getNonce(); + console.log(`Nonce: ${nonce}`); + + document.getElementById('transferButton')?.addEventListener('click', async () => { + const address = (document.getElementById('transferInput') as HTMLInputElement).value; + await transfer(address); + }); + + document.getElementById('deployButton')?.addEventListener('click', async () => { + await deploy(); + }); + document.getElementById('deployAndCallButton')?.addEventListener('click', async () => { + const nonce = await signer.getNonce(); + console.log(`deploy with nonce: ${nonce}`); + + const address = await deploy(); + if (address) { + const nonce = await signer.getNonce(); + console.log(`call with nonce: ${nonce}`); + await call(address); + } + + }); + document.getElementById('callButton')?.addEventListener('click', async () => { + const address = (document.getElementById('callInput') as HTMLInputElement).value; + await call(address); + }); + + async function deploy() { + console.log('Deploying contract...'); + const code = hexToU8a('0x50564d0001010424009000022363616c6cdeadbeef63616c6c5f6e657665726465706c6f797365616c5f72657475726e041001000000007365616c5f72657475726e051b03000a63616c6c5f6e6576657204066465706c6f79060463616c6c062c06011f000406081b1c06100408130013000211fc03100408040001040904040706100a05004e13005129a4b800'); + const args = new Uint8Array() + const bytecode = encodeRlp([ code, args ]); + const contractFactory = new ContractFactory([], bytecode, signer); + + try { + const contract = await contractFactory.deploy(); + await contract.waitForDeployment(); + const address = await contract.getAddress(); + console.log(`Contract deployed: ${address}`); + return address; + } catch (e) { + console.error('Failed to deploy contract', e); + return; + } + } + + async function call(address: string) { + const abi = ['function getValue() view returns (uint256)', 'function setValue(uint256 _value)']; + + const contract = new Contract(address, abi, signer); + const tx = await contract.setValue(42); + + console.log('Transaction hash:', tx.hash); + } + + async function transfer(to: AddressLike) { + console.log(`transferring 1 DOT to ${to}...`); + try { + const tx = await signer.sendTransaction({ + to, + value: parseEther('1.0'), + }); + + const receipt = await tx.wait(); + console.log(`Transaction hash: ${receipt?.hash}`); + } catch (e) { + console.error('Failed to send transaction', e); + return; + } + } +}); diff --git a/substrate/frame/revive/rpc/demo/tsconfig.json b/substrate/frame/revive/rpc/demo/tsconfig.json new file mode 100644 index 000000000000..19f43a33fa9f --- /dev/null +++ b/substrate/frame/revive/rpc/demo/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "moduleResolution": "node", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx" + }, + "include": ["src"] +} diff --git a/substrate/frame/revive/rpc/demo/vite.config.ts b/substrate/frame/revive/rpc/demo/vite.config.ts new file mode 100644 index 000000000000..825b100e3da2 --- /dev/null +++ b/substrate/frame/revive/rpc/demo/vite.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vite'; + +export default defineConfig({ + root: 'src', + build: { + sourcemap: true, + target: 'esnext', + outDir: '../dist', + }, +}); diff --git a/substrate/frame/revive/rpc/demo/yarn.lock b/substrate/frame/revive/rpc/demo/yarn.lock new file mode 100644 index 000000000000..744071a85412 --- /dev/null +++ b/substrate/frame/revive/rpc/demo/yarn.lock @@ -0,0 +1,535 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + +"@esbuild/linux-loong64@0.14.54": + version "0.14.54" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028" + integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw== + +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + +"@noble/curves@^1.3.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.6.0.tgz#be5296ebcd5a1730fccea4786d420f87abfeb40b" + integrity sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ== + dependencies: + "@noble/hashes" "1.5.0" + +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + +"@noble/hashes@1.5.0", "@noble/hashes@^1.3.3": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0" + integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== + +"@polkadot/keyring@^13.0.2": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-13.1.1.tgz#14b85d4e73ebfa8ccb0fadcdee127e102624dc11" + integrity sha512-Wm+9gn946GIPjGzvueObLGBBS9s541HE6mvKdWGEmPFMzH93ESN931RZlOd67my5MWryiSP05h5SHTp7bSaQTA== + dependencies: + "@polkadot/util" "13.1.1" + "@polkadot/util-crypto" "13.1.1" + tslib "^2.7.0" + +"@polkadot/networks@13.1.1": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-13.1.1.tgz#e1a05ef6f78ffc37272c6474df7b55244b311f9c" + integrity sha512-eEQ4+Mfl1xFtApeU5PdXZ2XBhxNSvUz9yW+YQVGUCkXRjWFbqNRsTOYWGd9uFbiAOXiiiXbtqfZpxSDzIm4XOg== + dependencies: + "@polkadot/util" "13.1.1" + "@substrate/ss58-registry" "^1.50.0" + tslib "^2.7.0" + +"@polkadot/types-augment@12.4.2": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/types-augment/-/types-augment-12.4.2.tgz#8b8e278f4cbecbdd586470d31c27576e06e87074" + integrity sha512-3fDCOy2BEMuAtMYl4crKg76bv/0pDNEuzpAzV4EBUMIlJwypmjy5sg3gUPCMcA+ckX3xb8DhkWU4ceUdS7T2KQ== + dependencies: + "@polkadot/types" "12.4.2" + "@polkadot/types-codec" "12.4.2" + "@polkadot/util" "^13.0.2" + tslib "^2.6.3" + +"@polkadot/types-codec@12.4.2": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/types-codec/-/types-codec-12.4.2.tgz#aa601ddbbe4bb28ef751e4565bd87037dee9a49b" + integrity sha512-DiPGRFWtVMepD9i05eC3orSbGtpN7un/pXOrXu0oriU+oxLkpvZH68ZsPNtJhKdQy03cAYtvB8elJOFJZYqoqQ== + dependencies: + "@polkadot/util" "^13.0.2" + "@polkadot/x-bigint" "^13.0.2" + tslib "^2.6.3" + +"@polkadot/types-create@12.4.2": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/types-create/-/types-create-12.4.2.tgz#1113746ab92694c3402abc59feb3e3fcaf980997" + integrity sha512-nOpeAKZLdSqNMfzS3waQXgyPPaNt8rUHEmR5+WNv6c/Ke/vyf710wjxiTewfp0wpBgtdrimlgG4DLX1J9Ms1LA== + dependencies: + "@polkadot/types-codec" "12.4.2" + "@polkadot/util" "^13.0.2" + tslib "^2.6.3" + +"@polkadot/types@12.4.2", "@polkadot/types@^12.2.1": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-12.4.2.tgz#948e0191b30c37f0d89b8e120174d6be31ed9f9d" + integrity sha512-ivYtt7hYcRvo69ULb1BJA9BE1uefijXcaR089Dzosr9+sMzvsB1yslNQReOq+Wzq6h6AQj4qex6qVqjWZE6Z4A== + dependencies: + "@polkadot/keyring" "^13.0.2" + "@polkadot/types-augment" "12.4.2" + "@polkadot/types-codec" "12.4.2" + "@polkadot/types-create" "12.4.2" + "@polkadot/util" "^13.0.2" + "@polkadot/util-crypto" "^13.0.2" + rxjs "^7.8.1" + tslib "^2.6.3" + +"@polkadot/util-crypto@13.1.1", "@polkadot/util-crypto@^13.0.2": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-13.1.1.tgz#26960046a9bd6b3b63dc9b006c1a24dc6391b875" + integrity sha512-FG68rrLPdfLcscEyH10vnGkakM4O2lqr71S3GDhgc9WXaS8y9jisLgMPg8jbMHiQBJ3iKYkmtPKiLBowRslj2w== + dependencies: + "@noble/curves" "^1.3.0" + "@noble/hashes" "^1.3.3" + "@polkadot/networks" "13.1.1" + "@polkadot/util" "13.1.1" + "@polkadot/wasm-crypto" "^7.3.2" + "@polkadot/wasm-util" "^7.3.2" + "@polkadot/x-bigint" "13.1.1" + "@polkadot/x-randomvalues" "13.1.1" + "@scure/base" "^1.1.7" + tslib "^2.7.0" + +"@polkadot/util@13.1.1", "@polkadot/util@^13.0.2": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-13.1.1.tgz#9cbf81e8c48e2ac549dbe2a40384624870016658" + integrity sha512-M4iQ5Um8tFdDmD7a96nPzfrEt+kxyWOqQDPqXyaax4QBnq/WCbq0jo8IO61uz55mdMQnGZvq8jd8uge4V6JzzQ== + dependencies: + "@polkadot/x-bigint" "13.1.1" + "@polkadot/x-global" "13.1.1" + "@polkadot/x-textdecoder" "13.1.1" + "@polkadot/x-textencoder" "13.1.1" + "@types/bn.js" "^5.1.5" + bn.js "^5.2.1" + tslib "^2.7.0" + +"@polkadot/wasm-bridge@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-bridge/-/wasm-bridge-7.3.2.tgz#e1b01906b19e06cbca3d94f10f5666f2ae0baadc" + integrity sha512-AJEXChcf/nKXd5Q/YLEV5dXQMle3UNT7jcXYmIffZAo/KI394a+/24PaISyQjoNC0fkzS1Q8T5pnGGHmXiVz2g== + dependencies: + "@polkadot/wasm-util" "7.3.2" + tslib "^2.6.2" + +"@polkadot/wasm-crypto-asmjs@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.3.2.tgz#c6d41bc4b48b5359d57a24ca3066d239f2d70a34" + integrity sha512-QP5eiUqUFur/2UoF2KKKYJcesc71fXhQFLT3D4ZjG28Mfk2ZPI0QNRUfpcxVQmIUpV5USHg4geCBNuCYsMm20Q== + dependencies: + tslib "^2.6.2" + +"@polkadot/wasm-crypto-init@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-init/-/wasm-crypto-init-7.3.2.tgz#7e1fe79ba978fb0a4a0f74a92d976299d38bc4b8" + integrity sha512-FPq73zGmvZtnuJaFV44brze3Lkrki3b4PebxCy9Fplw8nTmisKo9Xxtfew08r0njyYh+uiJRAxPCXadkC9sc8g== + dependencies: + "@polkadot/wasm-bridge" "7.3.2" + "@polkadot/wasm-crypto-asmjs" "7.3.2" + "@polkadot/wasm-crypto-wasm" "7.3.2" + "@polkadot/wasm-util" "7.3.2" + tslib "^2.6.2" + +"@polkadot/wasm-crypto-wasm@7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-7.3.2.tgz#44e08ed5cf6499ce4a3aa7247071a5d01f6a74f4" + integrity sha512-15wd0EMv9IXs5Abp1ZKpKKAVyZPhATIAHfKsyoWCEFDLSOA0/K0QGOxzrAlsrdUkiKZOq7uzSIgIDgW8okx2Mw== + dependencies: + "@polkadot/wasm-util" "7.3.2" + tslib "^2.6.2" + +"@polkadot/wasm-crypto@^7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-7.3.2.tgz#61bbcd9e591500705c8c591e6aff7654bdc8afc9" + integrity sha512-+neIDLSJ6jjVXsjyZ5oLSv16oIpwp+PxFqTUaZdZDoA2EyFRQB8pP7+qLsMNk+WJuhuJ4qXil/7XiOnZYZ+wxw== + dependencies: + "@polkadot/wasm-bridge" "7.3.2" + "@polkadot/wasm-crypto-asmjs" "7.3.2" + "@polkadot/wasm-crypto-init" "7.3.2" + "@polkadot/wasm-crypto-wasm" "7.3.2" + "@polkadot/wasm-util" "7.3.2" + tslib "^2.6.2" + +"@polkadot/wasm-util@7.3.2", "@polkadot/wasm-util@^7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-util/-/wasm-util-7.3.2.tgz#4fe6370d2b029679b41a5c02cd7ebf42f9b28de1" + integrity sha512-bmD+Dxo1lTZyZNxbyPE380wd82QsX+43mgCm40boyKrRppXEyQmWT98v/Poc7chLuskYb6X8IQ6lvvK2bGR4Tg== + dependencies: + tslib "^2.6.2" + +"@polkadot/x-bigint@13.1.1", "@polkadot/x-bigint@^13.0.2": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-bigint/-/x-bigint-13.1.1.tgz#1a9036c9529ce15deab808bee7333bcbd3ab0078" + integrity sha512-Cq4Y6fd9UWtRBZz8RX2tWEBL1IFwUtY6cL8p6HC9yhZtUR6OPjKZe6RIZQa9gSOoIuqZWd6PmtvSNGVH32yfkQ== + dependencies: + "@polkadot/x-global" "13.1.1" + tslib "^2.7.0" + +"@polkadot/x-global@13.1.1": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-13.1.1.tgz#1db0c16e45a20eddf682c98b1d3487619203c8a9" + integrity sha512-DViIMmmEs29Qlsp058VTg2Mn7e3/CpGazNnKJrsBa0o1Ptxl13/4Z0fjqCpNi2GB+kaOsnREzxUORrHcU+PqcQ== + dependencies: + tslib "^2.7.0" + +"@polkadot/x-randomvalues@13.1.1": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-13.1.1.tgz#e3fc6e77cdfe6f345fca7433dd92a914807a7e4f" + integrity sha512-cXj4omwbgzQQSiBtV1ZBw+XhJUU3iz/DS6ghUnGllSZEK+fGqiyaNgeFQzDY0tKjm6kYaDpvtOHR3mHsbzDuTg== + dependencies: + "@polkadot/x-global" "13.1.1" + tslib "^2.7.0" + +"@polkadot/x-textdecoder@13.1.1": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-13.1.1.tgz#305e9a1be38aa435942bc2a73b088a2ca1c1c89b" + integrity sha512-LpZ9KYc6HdBH+i86bCmun4g4GWMiWN/1Pzs0hNdanlQMfqp3UGzl1Dqp0nozMvjWAlvyG7ip235VgNMd8HEbqg== + dependencies: + "@polkadot/x-global" "13.1.1" + tslib "^2.7.0" + +"@polkadot/x-textencoder@13.1.1": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-13.1.1.tgz#2588c57c1fae68493a5588a156313d25b91a577e" + integrity sha512-w1mT15B9ptN5CJNgN/A0CmBqD5y9OePjBdU6gmAd8KRhwXCF0MTBKcEZk1dHhXiXtX+28ULJWLrfefC5gxy69Q== + dependencies: + "@polkadot/x-global" "13.1.1" + tslib "^2.7.0" + +"@scure/base@^1.1.7": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" + integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== + +"@substrate/ss58-registry@^1.50.0": + version "1.50.0" + resolved "https://registry.yarnpkg.com/@substrate/ss58-registry/-/ss58-registry-1.50.0.tgz#2d2a3d060cd4eadd200e4538078461ba73e13d6d" + integrity sha512-mkmlMlcC+MSd9rA+PN8ljGAm5fVZskvVwkXIsbx4NFwaT8kt38r7e9cyDWscG3z2Zn40POviZvEMrJSk+r2SgQ== + +"@types/bn.js@^5.1.5": + version "5.1.6" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.6.tgz#9ba818eec0c85e4d3c679518428afdf611d03203" + integrity sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "22.6.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.6.0.tgz#b604c9a628760221905c1b272fd6aee661f45042" + integrity sha512-QyR8d5bmq+eR72TwQDfujwShHMcIrWIYsaQFtXRE58MHPTEKUNxjxvl0yS0qPMds5xbSDWtp7ZpvGFtd7dfMdQ== + dependencies: + undici-types "~6.19.2" + +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + +"@types/node@^14.14.6": + version "14.18.63" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b" + integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ== + +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + +bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +esbuild-android-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be" + integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ== + +esbuild-android-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771" + integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg== + +esbuild-darwin-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25" + integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug== + +esbuild-darwin-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73" + integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw== + +esbuild-freebsd-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d" + integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg== + +esbuild-freebsd-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48" + integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q== + +esbuild-linux-32@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5" + integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw== + +esbuild-linux-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652" + integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg== + +esbuild-linux-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b" + integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig== + +esbuild-linux-arm@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59" + integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw== + +esbuild-linux-mips64le@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34" + integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw== + +esbuild-linux-ppc64le@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e" + integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ== + +esbuild-linux-riscv64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8" + integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg== + +esbuild-linux-s390x@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6" + integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA== + +esbuild-netbsd-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81" + integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w== + +esbuild-openbsd-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b" + integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw== + +esbuild-sunos-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da" + integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw== + +esbuild-windows-32@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31" + integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w== + +esbuild-windows-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4" + integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ== + +esbuild-windows-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982" + integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg== + +esbuild@^0.14.27: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2" + integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA== + optionalDependencies: + "@esbuild/linux-loong64" "0.14.54" + esbuild-android-64 "0.14.54" + esbuild-android-arm64 "0.14.54" + esbuild-darwin-64 "0.14.54" + esbuild-darwin-arm64 "0.14.54" + esbuild-freebsd-64 "0.14.54" + esbuild-freebsd-arm64 "0.14.54" + esbuild-linux-32 "0.14.54" + esbuild-linux-64 "0.14.54" + esbuild-linux-arm "0.14.54" + esbuild-linux-arm64 "0.14.54" + esbuild-linux-mips64le "0.14.54" + esbuild-linux-ppc64le "0.14.54" + esbuild-linux-riscv64 "0.14.54" + esbuild-linux-s390x "0.14.54" + esbuild-netbsd-64 "0.14.54" + esbuild-openbsd-64 "0.14.54" + esbuild-sunos-64 "0.14.54" + esbuild-windows-32 "0.14.54" + esbuild-windows-64 "0.14.54" + esbuild-windows-arm64 "0.14.54" + +ethers@^6.13.1: + version "6.13.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.2.tgz#4b67d4b49e69b59893931a032560999e5e4419fe" + integrity sha512-9VkriTTed+/27BGuY1s0hf441kqwHJ1wtN2edksEtiRvXx+soxRX3iSXTfFqq2+YwrOqbDoTHjIhQnjJRlzKmg== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.17.1" + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +is-core-module@^2.13.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + +postcss@^8.4.13: + version "8.4.47" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" + integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.0" + source-map-js "^1.2.1" + +prettier@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + +resolve@^1.22.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +"rollup@>=2.59.0 <2.78.0": + version "2.77.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.77.3.tgz#8f00418d3a2740036e15deb653bed1a90ee0cc12" + integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g== + optionalDependencies: + fsevents "~2.3.2" + +rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +scale-codec@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/scale-codec/-/scale-codec-0.13.0.tgz#7c9842412e0e4fdab5f9f10b475e3fbd40fdb23f" + integrity sha512-HxLaGxglkZP7SwjCLZPMsWGKN8Q/h5bjIH9YLFRcsG3Fmh+qsCOZYRLhntvTyP6B/Q7xHPBc2YKODOSfH0rH8g== + +scale-ts@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/scale-ts/-/scale-ts-1.6.0.tgz#e9641093c5a9e50f964ddb1607139034e3e932e9" + integrity sha512-Ja5VCjNZR8TGKhUumy9clVVxcDpM+YFjAnkMuwQy68Hixio3VRRvWdE3g8T/yC+HXA0ZDQl2TGyUmtmbcVl40Q== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + +tslib@^2.1.0, tslib@^2.6.2, tslib@^2.6.3, tslib@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +typescript@^4.1.2: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +vite@^2.5.0: + version "2.9.18" + resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.18.tgz#74e2a83b29da81e602dac4c293312cc575f091c7" + integrity sha512-sAOqI5wNM9QvSEE70W3UGMdT8cyEn0+PmJMTFvTB8wB0YbYUWw3gUbY62AOyrXosGieF2htmeLATvNxpv/zNyQ== + dependencies: + esbuild "^0.14.27" + postcss "^8.4.13" + resolve "^1.22.0" + rollup ">=2.59.0 <2.78.0" + optionalDependencies: + fsevents "~2.3.2" + +ws@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== diff --git a/substrate/frame/revive/rpc/examples/transfer.rs b/substrate/frame/revive/rpc/examples/transfer.rs index 634131f4da92..ba5182e5730a 100644 --- a/substrate/frame/revive/rpc/examples/transfer.rs +++ b/substrate/frame/revive/rpc/examples/transfer.rs @@ -1,6 +1,5 @@ -use hex_literal::hex; use jsonrpsee::http_client::HttpClientBuilder; -use pallet_revive::evm::{BlockTag, Bytes, ReceiptInfo, H160}; +use pallet_revive::evm::{BlockTag, Bytes, ReceiptInfo}; use pallet_revive_eth_rpc::{ example::{wait_for_receipt, Account}, EthRpcClient, @@ -8,19 +7,26 @@ use pallet_revive_eth_rpc::{ #[tokio::main] async fn main() -> anyhow::Result<()> { - let account = Account::default(); - println!("Account address: {:?}", account.address()); - + let alith = Account::default(); let client = HttpClientBuilder::default().build("http://localhost:9090".to_string())?; - let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; - println!("Account balance: {:?}", balance); + let baltathar = Account::from(subxt_signer::eth::dev::baltathar()); + let value = 1_000_000_000_000_000_000u128.into(); // 1 ETH + + let print_balance = || async { + let balance = client.get_balance(alith.address(), BlockTag::Latest.into()).await?; + println!("Alith {:?} balance: {balance:?}", alith.address()); + let balance = client.get_balance(baltathar.address(), BlockTag::Latest.into()).await?; + println!("Baltathar {:?} balance: {balance:?}", baltathar.address()); + anyhow::Result::<()>::Ok(()) + }; - let to = Some(H160(hex!("c543bb3eF11d96aCA20b3c906cF2C8Daaff925e4"))); - let value = 10_000_000_000_000_000_000u128.into(); // 10 ETH + print_balance().await?; println!("\n\n=== Transferring ===\n\n"); - let hash = account.send_transaction(&client, value, Bytes::default(), to).await?; + let hash = alith + .send_transaction(&client, value, Bytes::default(), Some(baltathar.address())) + .await?; println!("Transaction hash: {hash:?}"); let ReceiptInfo { block_number, gas_used, .. } = wait_for_receipt(&client, hash).await?; @@ -28,8 +34,6 @@ async fn main() -> anyhow::Result<()> { println!("- Block number: {block_number}"); println!("- Gas used: {gas_used}"); - let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; - println!("Account balance: {:?}", balance); - + print_balance().await?; Ok(()) } diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs index e6787cef24f6..c7e8e72f35e7 100644 --- a/substrate/frame/revive/rpc/src/example.rs +++ b/substrate/frame/revive/rpc/src/example.rs @@ -18,6 +18,12 @@ impl Default for Account { } } +impl From for Account { + fn from(keypair: subxt_signer::eth::Keypair) -> Self { + Self(keypair) + } +} + /// Wait for a transaction receipt. pub async fn wait_for_receipt(client: &HttpClient, hash: H256) -> anyhow::Result { for _ in 0..6 { From 444970b3cc73b45cbcb192de1df469918371bc9c Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 9 Oct 2024 10:13:34 +0200 Subject: [PATCH 061/174] update yarn.lock --- substrate/frame/revive/rpc/demo/yarn.lock | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/substrate/frame/revive/rpc/demo/yarn.lock b/substrate/frame/revive/rpc/demo/yarn.lock index 744071a85412..6a3de3e17417 100644 --- a/substrate/frame/revive/rpc/demo/yarn.lock +++ b/substrate/frame/revive/rpc/demo/yarn.lock @@ -477,16 +477,6 @@ rxjs@^7.8.1: dependencies: tslib "^2.1.0" -scale-codec@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/scale-codec/-/scale-codec-0.13.0.tgz#7c9842412e0e4fdab5f9f10b475e3fbd40fdb23f" - integrity sha512-HxLaGxglkZP7SwjCLZPMsWGKN8Q/h5bjIH9YLFRcsG3Fmh+qsCOZYRLhntvTyP6B/Q7xHPBc2YKODOSfH0rH8g== - -scale-ts@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/scale-ts/-/scale-ts-1.6.0.tgz#e9641093c5a9e50f964ddb1607139034e3e932e9" - integrity sha512-Ja5VCjNZR8TGKhUumy9clVVxcDpM+YFjAnkMuwQy68Hixio3VRRvWdE3g8T/yC+HXA0ZDQl2TGyUmtmbcVl40Q== - source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" From f10cf13b4368c9ca8c74cb1a70ddb76787cb7563 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 9 Oct 2024 10:16:47 +0200 Subject: [PATCH 062/174] nit --- substrate/frame/revive/rpc/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/rpc/src/main.rs b/substrate/frame/revive/rpc/src/main.rs index f03d3321fb74..500e1efe7373 100644 --- a/substrate/frame/revive/rpc/src/main.rs +++ b/substrate/frame/revive/rpc/src/main.rs @@ -86,9 +86,9 @@ mod dev { log::info!(target: LOG_TARGET, "method: {method} params: {params}"); let resp = service.call(req).await; if resp.is_success() { - log::info!(target: LOG_TARGET, "✅ method: {method}"); + log::info!(target: LOG_TARGET, "✅ rpc: {method}"); } else { - log::info!(target: LOG_TARGET, "❌ method: {method} {}", resp.as_result()); + log::info!(target: LOG_TARGET, "❌ rpc: {method} {}", resp.as_result()); } resp } From f0e21af67c661c23aa8148741f0341414fc972c6 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 9 Oct 2024 12:46:37 +0200 Subject: [PATCH 063/174] server fixes --- substrate/frame/revive/rpc/demo/README.md | 59 +++++++++++++++++++ substrate/frame/revive/rpc/demo/package.json | 2 - .../frame/revive/rpc/demo/src/index.html | 1 + substrate/frame/revive/rpc/demo/src/main.ts | 13 +++- substrate/frame/revive/rpc/examples/deploy.rs | 2 + substrate/frame/revive/rpc/src/client.rs | 3 +- 6 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 substrate/frame/revive/rpc/demo/README.md diff --git a/substrate/frame/revive/rpc/demo/README.md b/substrate/frame/revive/rpc/demo/README.md new file mode 100644 index 000000000000..6b9cd12b8420 --- /dev/null +++ b/substrate/frame/revive/rpc/demo/README.md @@ -0,0 +1,59 @@ +## Start the node + +Start the kitchensink node + +```bash +RUST_LOG="error,evm=debug,sc_rpc_server=info,runtime::revive=debug" cargo run --bin substrate-node -- --dev +``` + +## Start the RPC server + +This command starts the Ethereum JSON-RPC server, by default it runs on `localhost:9090` + +```bash +RUST_LOG="info,eth-rpc=debug" cargo run -p pallet-revive-eth-rpc --features dev +``` + +## Send a transaction using provided examples + +You can run one of the examples from the `examples` directory to send a transaction to the node. + +```bash +RUST_LOG="info,eth-rpc=debug" cargo run -p pallet-revive-eth-rpc --features example --example deploy +``` + +## Interact with the node using MetaMask & Ether.js + +Start the Ether.js demo server, and open the demo Ether.js web page at `http://localhost:3000` + +```bash +cd substrate/frame/revive/rpc/demo && yarn && yarn dev +``` + +### Configure MetaMask + +You can use the following instructions to setup [MetaMask](https://metamask.io) with the local chain. + +> Note: When you interact with MetaMask and restart the chain, you need to clear the activity tab (Settings > Advanced > Clear activity tab data) +> See [here](https://support.metamask.io/managing-my-wallet/resetting-deleting-and-restoring/how-to-clear-your-account-activity-reset-account) for more info on how to reset the account activity. + +#### Add a new network + +To interact with the local chain, you need to add a new network in [MetaMask](https://metamask.io). +See [here](https://support.metamask.io/networks-and-sidechains/managing-networks/how-to-add-a-custom-network-rpc/#adding-a-network-manually) for more info on how to add a custom network. + +Make sure the node and the rpc server are started, and use the following settings to configure the network (MetaMask > Networks > Add a network manually): + +- Network name: KitchenSink +- RPC URL: +- Chain ID: 420420420 +- Currency Symbol: `DEV` + +#### Import Dev account + +You will need to import the following account that is endowed with some balance at genesis to interact with the chain. +See [here](https://support.metamask.io/managing-my-wallet/accounts-and-addresses/how-to-import-an-account/) for more info on how to import an account. + +- Account: `0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac` +- Private Key: `5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133` + diff --git a/substrate/frame/revive/rpc/demo/package.json b/substrate/frame/revive/rpc/demo/package.json index a2e7e432013e..8c737a2eca22 100644 --- a/substrate/frame/revive/rpc/demo/package.json +++ b/substrate/frame/revive/rpc/demo/package.json @@ -11,8 +11,6 @@ "author": "", "license": "ISC", "dependencies": { - "@polkadot/types": "^12.2.1", - "@polkadot/util": "^13.0.2", "ethers": "^6.13.1" }, "devDependencies": { diff --git a/substrate/frame/revive/rpc/demo/src/index.html b/substrate/frame/revive/rpc/demo/src/index.html index c479742690d6..8d8bb4d9f432 100644 --- a/substrate/frame/revive/rpc/demo/src/index.html +++ b/substrate/frame/revive/rpc/demo/src/index.html @@ -2,6 +2,7 @@ + Deploy Contract with MetaMask - - - - - - - - - - - - - - diff --git a/substrate/frame/revive/rpc/examples/js/package.json b/substrate/frame/revive/rpc/examples/js/package.json deleted file mode 100644 index 4d7136606b65..000000000000 --- a/substrate/frame/revive/rpc/examples/js/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "demo", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "ethers": "^6.13.1" - }, - "devDependencies": { - "typescript": "^5.5.3", - "vite": "^5.4.8" - } -} diff --git a/substrate/frame/revive/rpc/examples/js/src/main.ts b/substrate/frame/revive/rpc/examples/js/src/main.ts deleted file mode 100644 index ba22935aa51b..000000000000 --- a/substrate/frame/revive/rpc/examples/js/src/main.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { - AddressLike, - BrowserProvider, - Contract, - ContractFactory, - Eip1193Provider, - JsonRpcSigner, - parseEther, -} from "ethers"; - -declare global { - interface Window { - ethereum?: Eip1193Provider; - } -} - -function str_to_bytes(str: string): Uint8Array { - return new TextEncoder().encode(str); -} - -document.addEventListener("DOMContentLoaded", async () => { - if (typeof window.ethereum == "undefined") { - return console.log("MetaMask is not installed"); - } - - console.log("MetaMask is installed!"); - const provider = new BrowserProvider(window.ethereum); - - console.log("Getting signer..."); - let signer: JsonRpcSigner; - try { - signer = await provider.getSigner(); - console.log(`Signer: ${signer.address}`); - } catch (e) { - console.error("Failed to get signer", e); - return; - } - - console.log("Getting block number..."); - try { - const blockNumber = await provider.getBlockNumber(); - console.log(`Block number: ${blockNumber}`); - } catch (e) { - console.error("Failed to get block number", e); - return; - } - - const nonce = await signer.getNonce(); - console.log(`Nonce: ${nonce}`); - - document.getElementById("transferButton")?.addEventListener( - "click", - async () => { - const address = - (document.getElementById("transferInput") as HTMLInputElement).value; - await transfer(address); - }, - ); - - document.getElementById("deployButton")?.addEventListener( - "click", - async () => { - await deploy(); - }, - ); - document.getElementById("deployAndCallButton")?.addEventListener( - "click", - async () => { - const nonce = await signer.getNonce(); - console.log(`deploy with nonce: ${nonce}`); - - const address = await deploy(); - if (address) { - const nonce = await signer.getNonce(); - console.log(`call with nonce: ${nonce}`); - await call(address); - } - }, - ); - document.getElementById("callButton")?.addEventListener("click", async () => { - const address = - (document.getElementById("callInput") as HTMLInputElement).value; - await call(address); - }); - - async function deploy() { - console.log("Deploying contract..."); - - const bytecode = await fetch("demo.polkavm").then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.arrayBuffer(); - }) - .then((arrayBuffer) => new Uint8Array(arrayBuffer)); - - const contractFactory = new ContractFactory( - [ - "constructor(bytes memory _data)", - ], - bytecode, - signer, - ); - - try { - const args = str_to_bytes("hello"); - const contract = await contractFactory.deploy(args); - await contract.waitForDeployment(); - const address = await contract.getAddress(); - console.log(`Contract deployed: ${address}`); - return address; - } catch (e) { - console.error("Failed to deploy contract", e); - return; - } - } - - async function call(address: string) { - const abi = ["function call(bytes data)"]; - const contract = new Contract(address, abi, signer); - const tx = await contract.call(str_to_bytes("world")); - - console.log("Transaction hash:", tx.hash); - } - - async function transfer(to: AddressLike) { - console.log(`transferring 1 DOT to ${to}...`); - try { - const tx = await signer.sendTransaction({ - to, - value: parseEther("1.0"), - }); - - const receipt = await tx.wait(); - console.log(`Transaction hash: ${receipt?.hash}`); - } catch (e) { - console.error("Failed to send transaction", e); - return; - } - } -}); diff --git a/substrate/frame/revive/rpc/examples/js/src/script.ts b/substrate/frame/revive/rpc/examples/js/src/script.ts deleted file mode 100644 index c5c2c6c2e839..000000000000 --- a/substrate/frame/revive/rpc/examples/js/src/script.ts +++ /dev/null @@ -1,49 +0,0 @@ -//! Run with bun run script.ts - -import { readFileSync } from "fs"; -import { Contract, ContractFactory, JsonRpcProvider } from "ethers"; - -const provider = new JsonRpcProvider("http://localhost:9090"); -const signer = await provider.getSigner(); -console.log( - `Signer address: ${await signer.getAddress()}, Nonce: ${await signer - .getNonce()}`, -); - -function str_to_bytes(str: string): Uint8Array { - return new TextEncoder().encode(str); -} - -// deploy -async function deploy() { - console.log(`Deploying Contract...`); - - const bytecode = readFileSync("demo.polkavm"); - const contractFactory = new ContractFactory( - [ - "constructor(bytes memory _data)", - ], - bytecode, - signer, - ); - - const args = str_to_bytes("hello"); - console.log("Deploying contract with args:", args); - const contract = await contractFactory.deploy(args); - await contract.waitForDeployment(); - const address = await contract.getAddress(); - console.log(`Contract deployed: ${address}`); - return address; -} - -async function call(address: string) { - console.log(`Calling Contract at ${address}...`); - - const abi = ["function call(bytes data)"]; - const contract = new Contract(address, abi, signer); - const tx = await contract.call(str_to_bytes("world")); - console.log("Call transaction hash:", tx.hash); -} - -const address = await deploy(); -await call(address); diff --git a/substrate/frame/revive/rpc/examples/js/tsconfig.json b/substrate/frame/revive/rpc/examples/js/tsconfig.json deleted file mode 100644 index 0511b9f0e041..000000000000 --- a/substrate/frame/revive/rpc/examples/js/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/substrate/frame/revive/rpc/examples/rust/deploy.rs b/substrate/frame/revive/rpc/examples/rust/deploy.rs deleted file mode 100644 index 0d6c0996e71d..000000000000 --- a/substrate/frame/revive/rpc/examples/rust/deploy.rs +++ /dev/null @@ -1,65 +0,0 @@ -// 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 jsonrpsee::http_client::HttpClientBuilder; -use pallet_revive::{ - create1, - evm::{Account, BlockTag, Bytes, ReceiptInfo, U256}, -}; -use pallet_revive_eth_rpc::{ - example::{send_transaction, wait_for_receipt}, - EthRpcClient, -}; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - env_logger::init(); - let account = Account::default(); - let data = vec![]; - let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; - let input = bytes.into_iter().chain(data.clone()).collect::>(); - - println!("Account address: {:?}", account.address()); - let client = HttpClientBuilder::default().build("http://localhost:9090")?; - - println!("\n\n=== Deploying contract ===\n\n"); - - let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; - let hash = send_transaction(&account, &client, U256::zero(), input.into(), None).await?; - - println!("Deploy Tx hash: {hash:?}"); - let ReceiptInfo { block_number, gas_used, contract_address, .. } = - wait_for_receipt(&client, hash).await?; - println!("Receipt:"); - println!("- Block number: {block_number}"); - println!("- Gas used: {gas_used}"); - println!("- Contract address: {contract_address:?}"); - - let contract_address = create1(&account.address(), nonce.try_into().unwrap()); - println!("\n\n=== Calling contract ===\n\n"); - - let hash = - send_transaction(&account, &client, U256::zero(), Bytes::default(), Some(contract_address)) - .await?; - - println!("Contract call tx hash: {hash:?}"); - let ReceiptInfo { block_number, gas_used, to, .. } = wait_for_receipt(&client, hash).await?; - println!("Receipt:"); - println!("- Block number: {block_number}"); - println!("- Gas used: {gas_used}"); - println!("- To: {to:?}"); - Ok(()) -} diff --git a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs deleted file mode 100644 index 01cb5aaf978e..000000000000 --- a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs +++ /dev/null @@ -1,46 +0,0 @@ -// 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 pallet_revive_eth_rpc::subxt_client::{self, SrcChainConfig}; -use sp_weights::Weight; -use subxt::OnlineClient; -use subxt_signer::sr25519::dev; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let client = OnlineClient::::new().await?; - - let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; - - let tx_payload = subxt_client::tx().revive().instantiate_with_code( - 0u32.into(), - Weight::from_parts(100_000, 0).into(), - 3_000_000_000_000_000, - bytes, - vec![], - None, - ); - - let res = client - .tx() - .sign_and_submit_then_watch_default(&tx_payload, &dev::alice()) - .await? - .wait_for_finalized_success() - .await?; - println!("Transaction finalized: {:?}", res.extrinsic_hash()); - - Ok(()) -} diff --git a/substrate/frame/revive/rpc/examples/rust/rpc-playground.rs b/substrate/frame/revive/rpc/examples/rust/rpc-playground.rs deleted file mode 100644 index 635fbb74d5c2..000000000000 --- a/substrate/frame/revive/rpc/examples/rust/rpc-playground.rs +++ /dev/null @@ -1,41 +0,0 @@ -// 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 jsonrpsee::http_client::HttpClientBuilder; -use pallet_revive::evm::{Account, BlockTag}; -use pallet_revive_eth_rpc::EthRpcClient; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let account = Account::default(); - println!("Account address: {:?}", account.address()); - - let client = HttpClientBuilder::default().build("http://localhost:9090")?; - - let block = client.get_block_by_number(BlockTag::Latest.into(), false).await?; - println!("Latest block: {block:#?}"); - - let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; - println!("Account nonce: {nonce:?}"); - - let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; - println!("Account balance: {balance:?}"); - - let sync_state = client.syncing().await?; - println!("Sync state: {sync_state:?}"); - - Ok(()) -} diff --git a/substrate/frame/revive/rpc/examples/rust/transfer.rs b/substrate/frame/revive/rpc/examples/rust/transfer.rs deleted file mode 100644 index 7c6f69f3b6a7..000000000000 --- a/substrate/frame/revive/rpc/examples/rust/transfer.rs +++ /dev/null @@ -1,55 +0,0 @@ -// 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 jsonrpsee::http_client::HttpClientBuilder; -use pallet_revive::evm::{Account, BlockTag, Bytes, ReceiptInfo}; -use pallet_revive_eth_rpc::{ - example::{send_transaction, wait_for_receipt}, - EthRpcClient, -}; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let alith = Account::default(); - let client = HttpClientBuilder::default().build("http://localhost:9090")?; - - let baltathar = Account::from(subxt_signer::eth::dev::baltathar()); - let value = 1_000_000_000_000_000_000u128.into(); // 1 ETH - - let print_balance = || async { - let balance = client.get_balance(alith.address(), BlockTag::Latest.into()).await?; - println!("Alith {:?} balance: {balance:?}", alith.address()); - let balance = client.get_balance(baltathar.address(), BlockTag::Latest.into()).await?; - println!("Baltathar {:?} balance: {balance:?}", baltathar.address()); - anyhow::Result::<()>::Ok(()) - }; - - print_balance().await?; - println!("\n\n=== Transferring ===\n\n"); - - let hash = - send_transaction(&alith, &client, value, Bytes::default(), Some(baltathar.address())) - .await?; - println!("Transaction hash: {hash:?}"); - - let ReceiptInfo { block_number, gas_used, .. } = wait_for_receipt(&client, hash).await?; - println!("Receipt: "); - println!("- Block number: {block_number}"); - println!("- Gas used: {gas_used}"); - - print_balance().await?; - Ok(()) -} diff --git a/substrate/frame/revive/rpc/kitchensink.scale b/substrate/frame/revive/rpc/kitchensink.scale deleted file mode 100644 index 60c1834d3c7875d257a4bf1f3426a459a6f44cdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 651459 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 -} - -/// The substrate block type. -pub type SubstrateBlock = subxt::blocks::Block>; - -/// The substrate block number type. -pub type SubstrateBlockNumber = <::Header as Header>::Number; - -/// The substrate block hash type. -pub type SubstrateBlockHash = ::Hash; - -/// Type alias for shared data. -pub type Shared = Arc>; - -/// The runtime balance type. -pub type Balance = u128; - -/// The cache maintains a buffer of the last N blocks, -#[derive(Default)] -struct BlockCache { - /// A double-ended queue of the last N blocks. - /// The most recent block is at the back of the queue, and the oldest block is at the front. - buffer: VecDeque>, - - /// A map of blocks by block number. - blocks_by_number: HashMap>, - - /// A map of blocks by block hash. - blocks_by_hash: HashMap>, - - /// A map of receipts by hash. - receipts_by_hash: HashMap, - - /// A map of Signed transaction by hash. - signed_tx_by_hash: HashMap, - - /// A map of receipt hashes by block hash. - tx_hashes_by_block_and_index: HashMap>, -} - -/// The error type for the client. -#[derive(Error, Debug)] -pub enum ClientError { - /// A [`subxt::Error`] wrapper error. - #[error("Subxt error: {0}")] - SubxtError(#[from] subxt::Error), - /// A [`RpcError`] wrapper error. - #[error("RPC error: {0}")] - RpcError(#[from] RpcError), - /// A [`codec::Error`] wrapper error. - #[error("Codec error: {0}")] - CodecError(#[from] codec::Error), - /// The dry run failed. - #[error("Dry run failed")] - DryRunFailed, - /// A decimal conversion failed. - #[error("Conversion failed")] - ConversionFailed, - /// The block hash was not found. - #[error("Hash not found")] - BlockNotFound, - /// The transaction fee could not be found - #[error("TransactionFeePaid event not found")] - TxFeeNotFound, - /// The token decimals property was not found - #[error("tokenDecimals not found in properties")] - TokenDecimalsNotFound, - /// The cache is empty. - #[error("Cache is empty")] - CacheEmpty, -} - -// Convert a `ClientError` to an RPC `ErrorObjectOwned`. -impl From for ErrorObjectOwned { - fn from(value: ClientError) -> Self { - log::debug!(target: LOG_TARGET, "ClientError: {value:?}"); - ErrorObjectOwned::owned::<()>( - ErrorCode::InternalError.code(), - ErrorCode::InternalError.message(), - None, - ) - } -} - -/// The number of recent blocks maintained by the cache. -/// For each block in the cache, we also store the EVM transaction receipts. -pub const CACHE_SIZE: usize = 10; - -impl BlockCache { - fn latest_block(&self) -> Option<&Arc> { - self.buffer.back() - } - - /// Insert an entry into the cache, and prune the oldest entry if the cache is full. - fn insert(&mut self, block: SubstrateBlock) { - if self.buffer.len() >= N { - if let Some(block) = self.buffer.pop_front() { - log::trace!(target: LOG_TARGET, "Pruning block: {}", block.number()); - let hash = block.hash(); - self.blocks_by_hash.remove(&hash); - self.blocks_by_number.remove(&block.number()); - if let Some(entries) = self.tx_hashes_by_block_and_index.remove(&hash) { - for hash in entries.values() { - self.receipts_by_hash.remove(hash); - } - } - } - } - - let block = Arc::new(block); - self.buffer.push_back(block.clone()); - self.blocks_by_number.insert(block.number(), block.clone()); - self.blocks_by_hash.insert(block.hash(), block); - } -} - -/// A client connect to a node and maintains a cache of the last `CACHE_SIZE` blocks. -pub struct Client { - inner: Arc, - join_set: JoinSet>, - /// A watch channel to signal cache updates. - pub updates: tokio::sync::watch::Receiver<()>, -} - -/// The inner state of the client. -struct ClientInner { - api: OnlineClient, - rpc_client: ReconnectingRpcClient, - rpc: LegacyRpcMethods, - cache: Shared>, - chain_id: u64, - max_block_weight: Weight, - native_to_evm_ratio: U256, -} - -impl ClientInner { - /// Create a new client instance connecting to the substrate node at the given URL. - async fn from_url(url: &str) -> Result { - let rpc_client = ReconnectingRpcClient::builder() - .retry_policy(ExponentialBackoff::from_millis(100).max_delay(Duration::from_secs(10))) - .build(url.to_string()) - .await?; - - let api = OnlineClient::::from_rpc_client(rpc_client.clone()).await?; - let cache = Arc::new(RwLock::new(BlockCache::::default())); - - let rpc = LegacyRpcMethods::::new(RpcClient::new(rpc_client.clone())); - - let (native_to_evm_ratio, chain_id, max_block_weight) = - tokio::try_join!(native_to_evm_ratio(&rpc), chain_id(&api), max_block_weight(&api))?; - - Ok(Self { api, rpc_client, rpc, cache, chain_id, max_block_weight, native_to_evm_ratio }) - } - - /// Convert a native balance to an EVM balance. - pub fn native_to_evm_decimals(&self, value: U256) -> U256 { - value.saturating_mul(self.native_to_evm_ratio) - } - - /// Get the receipt infos from the extrinsics in a block. - async fn receipt_infos( - &self, - block: &SubstrateBlock, - ) -> Result, ClientError> { - // Get extrinsics from the block - let extrinsics = block.extrinsics().await?; - - // Filter extrinsics from pallet_revive - let extrinsics = extrinsics.iter().flat_map(|ext| { - let ext = ext.ok()?; - - let call = ext.as_extrinsic::().ok()??; - let tx = rlp::decode::(&call.payload).ok()?; - let from = tx.recover_eth_address().ok()?; - let contract_address = if tx.transaction_legacy_unsigned.to.is_none() { - Some(create1(&from, tx.transaction_legacy_unsigned.nonce.try_into().ok()?)) - } else { - None - }; - - Some((from, tx, contract_address, ext)) - }); - - // Map each extrinsic to a receipt - stream::iter(extrinsics) - .map(|(from, tx, contract_address, ext)| async move { - let events = ext.events().await?; - let tx_fees = - events.find_first::()?.ok_or(ClientError::TxFeeNotFound)?; - - let gas_price = tx.transaction_legacy_unsigned.gas_price; - let gas_used = (tx_fees.tip.saturating_add(tx_fees.actual_fee)) - .checked_div(gas_price.as_u128()) - .unwrap_or_default(); - - let success = events.find_first::().is_ok(); - let transaction_index = ext.index(); - let transaction_hash = primitives::Hashing::hash(&Vec::from(ext.bytes()).encode()); - let block_hash = block.hash(); - let block_number = block.number().into(); - - let receipt = ReceiptInfo { - block_hash, - block_number, - contract_address, - from, - to: tx.transaction_legacy_unsigned.to, - effective_gas_price: gas_price, - gas_used: gas_used.into(), - status: Some(if success { U256::one() } else { U256::zero() }), - transaction_hash, - transaction_index: transaction_index.into(), - ..Default::default() - }; - - Ok::<_, ClientError>((receipt.transaction_hash, (tx.into(), receipt))) - }) - .buffer_unordered(10) - .collect::>>() - .await - .into_iter() - .collect::, _>>() - } -} - -/// Drop all the tasks spawned by the client on drop. -impl Drop for Client { - fn drop(&mut self) { - self.join_set.abort_all() - } -} - -/// Fetch the chain ID from the substrate chain. -async fn chain_id(api: &OnlineClient) -> Result { - let query = subxt_client::constants().revive().chain_id(); - api.constants().at(&query).map_err(|err| err.into()) -} - -/// Fetch the max block weight from the substrate chain. -async fn max_block_weight(api: &OnlineClient) -> Result { - let query = subxt_client::constants().system().block_weights(); - let weights = api.constants().at(&query)?; - let max_block = weights.per_class.normal.max_extrinsic.unwrap_or(weights.max_block); - Ok(max_block.0) -} - -/// Fetch the native to EVM ratio from the substrate chain. -async fn native_to_evm_ratio(rpc: &LegacyRpcMethods) -> Result { - let props = rpc.system_properties().await?; - let eth_decimals = U256::from(18u32); - let native_decimals: U256 = props - .get("tokenDecimals") - .and_then(|v| v.as_number()?.as_u64()) - .ok_or(ClientError::TokenDecimalsNotFound)? - .into(); - - Ok(U256::from(10u32).pow(eth_decimals - native_decimals)) -} - -/// Extract the block timestamp. -async fn extract_block_timestamp(block: &SubstrateBlock) -> Option { - let extrinsics = block.extrinsics().await.ok()?; - let ext = extrinsics - .find_first::() - .ok()??; - - Some(ext.value.now / 1000) -} - -impl Client { - /// Create a new client instance. - /// The client will subscribe to new blocks and maintain a cache of [`CACHE_SIZE`] blocks. - pub async fn from_url(url: &str) -> Result { - log::info!(target: LOG_TARGET, "Connecting to node at: {url} ..."); - let inner: Arc = Arc::new(ClientInner::from_url(url).await?); - log::info!(target: LOG_TARGET, "Connected to node at: {url}"); - - let (tx, mut updates) = tokio::sync::watch::channel(()); - let mut join_set = JoinSet::new(); - join_set.spawn(Self::subscribe_blocks(inner.clone(), tx)); - join_set.spawn(Self::subscribe_reconnect(inner.clone())); - - updates.changed().await.expect("tx is not dropped"); - Ok(Self { inner, join_set, updates }) - } - - /// Subscribe and log reconnection events. - async fn subscribe_reconnect(inner: Arc) -> Result<(), ClientError> { - let rpc = inner.as_ref().rpc_client.clone(); - loop { - let reconnected = rpc.reconnect_initiated().await; - log::info!("RPC client connection lost"); - let now = std::time::Instant::now(); - reconnected.await; - log::info!("RPC client reconnection took `{}s`", now.elapsed().as_secs()); - } - } - - /// Subscribe to new blocks and update the cache. - async fn subscribe_blocks(inner: Arc, tx: Sender<()>) -> Result<(), ClientError> { - log::info!("Subscribing to new blocks"); - let mut block_stream = - inner.as_ref().api.blocks().subscribe_finalized().await.inspect_err(|err| { - log::error!("Failed to subscribe to blocks: {err:?}"); - })?; - - while let Some(block) = block_stream.next().await { - let block = match block { - Ok(block) => block, - Err(err) => { - if err.is_disconnected_will_reconnect() { - log::warn!( - "The RPC connection was lost and we may have missed a few blocks" - ); - continue; - } - - log::error!("Failed to fetch block: {err:?}"); - return Err(err.into()); - }, - }; - - log::debug!("Pushing block: {}", block.number()); - let mut cache = inner.cache.write().await; - - let receipts = inner - .receipt_infos(&block) - .await - .inspect_err(|err| { - log::error!("Failed to get receipts: {err:?}"); - }) - .unwrap_or_default(); - - if !receipts.is_empty() { - log::debug!("Adding {} receipts", receipts.len()); - let values = receipts - .iter() - .map(|(hash, (_, receipt))| (receipt.transaction_index, *hash)) - .collect::>(); - - cache.tx_hashes_by_block_and_index.insert(block.hash(), values); - - cache - .receipts_by_hash - .extend(receipts.iter().map(|(hash, (_, receipt))| (*hash, receipt.clone()))); - - cache.signed_tx_by_hash.extend( - receipts.iter().map(|(hash, (signed_tx, _))| (*hash, signed_tx.clone())), - ) - } - - cache.insert(block); - tx.send_replace(()); - } - - log::info!("Block subscription ended"); - Ok(()) - } - - /// Get the most recent block stored in the cache. - pub async fn latest_block(&self) -> Option> { - let cache = self.inner.cache.read().await; - let block = cache.latest_block()?; - Some(block.clone()) - } - - /// Expose the transaction API. - pub fn tx(&self) -> TxClient> { - self.inner.api.tx() - } - - /// Get an EVM transaction receipt by hash. - pub async fn receipt(&self, tx_hash: &H256) -> Option { - let cache = self.inner.cache.read().await; - cache.receipts_by_hash.get(tx_hash).cloned() - } - - /// Get the syncing status of the chain. - pub async fn syncing(&self) -> Result { - let health = self.inner.rpc.system_health().await?; - - let status = if health.is_syncing { - let client = RpcClient::new(self.inner.rpc_client.clone()); - let sync_state: sc_rpc::system::SyncState = - client.request("system_syncState", Default::default()).await?; - - SyncingProgress { - current_block: Some(sync_state.current_block.into()), - highest_block: Some(sync_state.highest_block.into()), - starting_block: Some(sync_state.starting_block.into()), - } - .into() - } else { - SyncingStatus::Bool(false) - }; - - Ok(status) - } - - /// Get an EVM transaction receipt by hash. - pub async fn receipt_by_hash_and_index( - &self, - block_hash: &H256, - transaction_index: &U256, - ) -> Option { - let cache = self.inner.cache.read().await; - let receipt_hash = - cache.tx_hashes_by_block_and_index.get(block_hash)?.get(transaction_index)?; - let receipt = cache.receipts_by_hash.get(receipt_hash)?; - Some(receipt.clone()) - } - - pub async fn signed_tx_by_hash(&self, tx_hash: &H256) -> Option { - let cache = self.inner.cache.read().await; - cache.signed_tx_by_hash.get(tx_hash).cloned() - } - - /// Get receipts count per block. - pub async fn receipts_count_per_block(&self, block_hash: &SubstrateBlockHash) -> Option { - let cache = self.inner.cache.read().await; - cache.tx_hashes_by_block_and_index.get(block_hash).map(|v| v.len()) - } - - /// Expose the storage API. - pub async fn storage_api( - &self, - at: &BlockNumberOrTagOrHash, - ) -> Result>, ClientError> { - match at { - BlockNumberOrTagOrHash::U256(block_number) => { - let n: SubstrateBlockNumber = - (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; - - let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; - Ok(self.inner.api.storage().at(hash)) - }, - BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.storage().at(*hash)), - BlockNumberOrTagOrHash::BlockTag(_) => { - if let Some(block) = self.latest_block().await { - return Ok(self.inner.api.storage().at(block.hash())); - } - let storage = self.inner.api.storage().at_latest().await?; - Ok(storage) - }, - } - } - - /// Expose the runtime API. - pub async fn runtime_api( - &self, - at: &BlockNumberOrTagOrHash, - ) -> Result< - subxt::runtime_api::RuntimeApi>, - ClientError, - > { - match at { - BlockNumberOrTagOrHash::U256(block_number) => { - let n: SubstrateBlockNumber = - (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; - - let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; - Ok(self.inner.api.runtime_api().at(hash)) - }, - BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.runtime_api().at(*hash)), - BlockNumberOrTagOrHash::BlockTag(_) => { - if let Some(block) = self.latest_block().await { - return Ok(self.inner.api.runtime_api().at(block.hash())); - } - - let api = self.inner.api.runtime_api().at_latest().await?; - Ok(api) - }, - } - } - - /// Get the balance of the given address. - pub async fn balance( - &self, - address: H160, - at: &BlockNumberOrTagOrHash, - ) -> Result { - let account_id = self.account_id(&address); - let query = subxt_client::storage().system().account(account_id); - let Some(account) = self.storage_api(at).await?.fetch(&query).await? else { - return Ok(U256::zero()); - }; - - let native = account.data.free.into(); - Ok(self.inner.native_to_evm_decimals(native)) - } - - /// Get the contract storage for the given contract address and key. - pub async fn get_contract_storage( - &self, - contract_address: H160, - key: U256, - block: BlockNumberOrTagOrHash, - ) -> Result, ClientError> { - let runtime_api = self.runtime_api(&block).await?; - - // TODO: remove once subxt is updated - let contract_address = contract_address.0.into(); - - let payload = subxt_client::apis() - .revive_api() - .get_storage(contract_address, key.to_big_endian()); - let result = runtime_api.call(payload).await?.unwrap_or_default().unwrap_or_default(); - Ok(result) - } - - /// Get the contract code for the given contract address. - pub async fn get_contract_code( - &self, - contract_address: &H160, - block: BlockNumberOrTagOrHash, - ) -> Result, ClientError> { - let storage_api = self.storage_api(&block).await?; - let account_id = self.account_id(contract_address); - let code_hash: subxt::utils::H256 = account_id.0.into(); - - let query = subxt_client::storage().revive().pristine_code(code_hash); - let result = storage_api.fetch(&query).await?.map(|v| v.0).unwrap_or_default(); - Ok(result) - } - - /// Dry run a transaction and returns the [`EthContractResult`] for the transaction. - pub async fn dry_run( - &self, - tx: &GenericTransaction, - block: BlockNumberOrTagOrHash, - ) -> Result, ClientError> { - let runtime_api = self.runtime_api(&block).await?; - let from = tx.from.ok_or(ClientError::DryRunFailed)?; - let value = tx - .value - .unwrap_or_default() - .try_into() - .map_err(|_| ClientError::ConversionFailed)?; - - // TODO: remove once subxt is updated - let from = from.0.into(); - let to = tx.to.map(|v| v.0.into()); - - let payload = subxt_client::apis().revive_api().eth_transact( - from, - to, - value, - tx.input.clone().unwrap_or_default().0, - None, - None, - ); - let res = runtime_api.call(payload).await?.0; - Ok(res) - } - - /// Dry run a transaction and returns the gas estimate for the transaction. - pub async fn estimate_gas( - &self, - tx: &GenericTransaction, - block: BlockNumberOrTagOrHash, - ) -> Result { - let dry_run = self.dry_run(tx, block).await?; - Ok(U256::from(dry_run.fee / GAS_PRICE as u128) + 1) - } - - /// Get the nonce of the given address. - pub async fn nonce( - &self, - address: H160, - block: BlockNumberOrTagOrHash, - ) -> Result { - let account_id = self.account_id(&address); - let storage = self.storage_api(&block).await?; - let query = subxt_client::storage().system().account(account_id); - let Some(account) = storage.fetch(&query).await? else { - return Ok(0); - }; - - Ok(account.nonce) - } - - /// Get the block number of the latest block. - pub async fn block_number(&self) -> Result { - let cache = self.inner.cache.read().await; - let latest_block = cache.buffer.back().ok_or(ClientError::CacheEmpty)?; - Ok(latest_block.number()) - } - - /// Get a block hash for the given block number. - pub async fn get_block_hash( - &self, - block_number: SubstrateBlockNumber, - ) -> Result, ClientError> { - let cache = self.inner.cache.read().await; - if let Some(block) = cache.blocks_by_number.get(&block_number) { - return Ok(Some(block.hash())); - } - - let hash = self.inner.rpc.chain_get_block_hash(Some(block_number.into())).await?; - Ok(hash) - } - - /// Get a block for the specified hash or number. - pub async fn block_by_number_or_tag( - &self, - block: &BlockNumberOrTag, - ) -> Result>, ClientError> { - match block { - BlockNumberOrTag::U256(n) => { - let n = (*n).try_into().map_err(|_| ClientError::ConversionFailed)?; - self.block_by_number(n).await - }, - BlockNumberOrTag::BlockTag(_) => { - let cache = self.inner.cache.read().await; - Ok(cache.buffer.back().cloned()) - }, - } - } - - /// Get a block by hash - pub async fn block_by_hash( - &self, - hash: &SubstrateBlockHash, - ) -> Result>, ClientError> { - let cache = self.inner.cache.read().await; - if let Some(block) = cache.blocks_by_hash.get(hash) { - return Ok(Some(block.clone())); - } - - match self.inner.api.blocks().at(*hash).await { - Ok(block) => Ok(Some(Arc::new(block))), - Err(subxt::Error::Block(subxt::error::BlockError::NotFound(_))) => Ok(None), - Err(err) => Err(err.into()), - } - } - - /// Get a block by number - pub async fn block_by_number( - &self, - block_number: SubstrateBlockNumber, - ) -> Result>, ClientError> { - let cache = self.inner.cache.read().await; - if let Some(block) = cache.blocks_by_number.get(&block_number) { - return Ok(Some(block.clone())); - } - - let Some(hash) = self.get_block_hash(block_number).await? else { - return Ok(None); - }; - - self.block_by_hash(&hash).await - } - - /// Get the EVM block for the given hash. - pub async fn evm_block(&self, block: Arc) -> Result { - let runtime_api = self.inner.api.runtime_api().at(block.hash()); - let max_fee = Self::weight_to_fee(&runtime_api, self.max_block_weight()).await?; - let gas_limit = U256::from(max_fee / GAS_PRICE as u128); - - let header = block.header(); - let timestamp = extract_block_timestamp(&block).await.unwrap_or_default(); - - // TODO: remove once subxt is updated - let parent_hash = header.parent_hash.0.into(); - let state_root = header.state_root.0.into(); - let extrinsics_root = header.extrinsics_root.0.into(); - - Ok(Block { - hash: block.hash(), - parent_hash, - state_root, - transactions_root: extrinsics_root, - number: header.number.into(), - timestamp: timestamp.into(), - difficulty: Some(0u32.into()), - gas_limit, - logs_bloom: Bytes256([0u8; 256]), - receipts_root: extrinsics_root, - ..Default::default() - }) - } - - /// Convert a weight to a fee. - async fn weight_to_fee( - runtime_api: &subxt::runtime_api::RuntimeApi>, - weight: Weight, - ) -> Result { - let payload = subxt_client::apis() - .transaction_payment_api() - .query_weight_to_fee(weight.into()); - - let fee = runtime_api.call(payload).await?; - Ok(fee) - } - - /// Get the substrate account ID from the EVM address. - pub fn account_id(&self, address: &H160) -> AccountId32 { - let mut id: [u8; 32] = [0xEE; 32]; - id[..20].copy_from_slice(address.as_bytes()); - AccountId32(id) - } - - /// Get the chain ID. - pub fn chain_id(&self) -> u64 { - self.inner.chain_id - } - - /// Get the Max Block Weight. - pub fn max_block_weight(&self) -> Weight { - self.inner.max_block_weight - } -} diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs deleted file mode 100644 index cbd022fa3b73..000000000000 --- a/substrate/frame/revive/rpc/src/example.rs +++ /dev/null @@ -1,96 +0,0 @@ -// 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. -//! Example utilities -#![cfg(feature = "example")] - -use crate::{EthRpcClient, ReceiptInfo}; -use anyhow::Context; -use jsonrpsee::http_client::HttpClient; -use pallet_revive::evm::{ - rlp::*, Account, BlockTag, Bytes, GenericTransaction, TransactionLegacyUnsigned, H160, H256, - U256, -}; - -/// Wait for a transaction receipt. -pub async fn wait_for_receipt(client: &HttpClient, hash: H256) -> anyhow::Result { - for _ in 0..6 { - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - let receipt = client.get_transaction_receipt(hash).await?; - if let Some(receipt) = receipt { - return Ok(receipt) - } - } - - anyhow::bail!("Failed to get receipt") -} - -/// Send a transaction. -pub async fn send_transaction( - signer: &Account, - client: &HttpClient, - value: U256, - input: Bytes, - to: Option, -) -> anyhow::Result { - let from = signer.address(); - - let chain_id = Some(client.chain_id().await?); - - let gas_price = client.gas_price().await?; - let nonce = client - .get_transaction_count(from, BlockTag::Latest.into()) - .await - .with_context(|| "Failed to fetch account nonce")?; - - let gas = client - .estimate_gas( - GenericTransaction { - from: Some(from), - input: Some(input.clone()), - value: Some(value), - gas_price: Some(gas_price), - to, - ..Default::default() - }, - None, - ) - .await - .with_context(|| "Failed to fetch gas estimate")?; - - println!("Estimated Gas: {gas:?}"); - - let unsigned_tx = TransactionLegacyUnsigned { - gas, - nonce, - to, - value, - input, - gas_price, - chain_id, - ..Default::default() - }; - - let tx = signer.sign_transaction(unsigned_tx.clone()); - let bytes = tx.rlp_bytes().to_vec(); - - let hash = client - .send_raw_transaction(bytes.clone().into()) - .await - .with_context(|| "transaction failed")?; - - Ok(hash) -} diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs deleted file mode 100644 index e740111d6591..000000000000 --- a/substrate/frame/revive/rpc/src/lib.rs +++ /dev/null @@ -1,375 +0,0 @@ -// 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. -//! The [`EthRpcServer`] RPC server implementation -#![cfg_attr(docsrs, feature(doc_cfg))] - -use crate::runtime::GAS_PRICE; -use client::ClientError; -use jsonrpsee::{ - core::{async_trait, RpcResult}, - proc_macros::rpc, - types::{ErrorCode, ErrorObjectOwned}, -}; -pub use pallet_revive::{evm::*, EthContractResult}; -pub use sp_core::{H160, H256, U256}; -use thiserror::Error; -pub mod client; -pub mod example; -pub mod subxt_client; - -mod rpc_methods_gen; -pub use rpc_methods_gen::*; - -pub const LOG_TARGET: &str = "eth-rpc"; - -/// Additional RPC methods, exposed on the RPC server on top of all the eth_xxx methods. -#[rpc(server, client)] -pub trait MiscRpc { - /// Returns the health status of the server. - #[method(name = "healthcheck")] - async fn healthcheck(&self) -> RpcResult<()>; -} - -/// An EVM RPC server implementation. -pub struct EthRpcServerImpl { - /// The client used to interact with the substrate node. - client: client::Client, - - /// The accounts managed by the server. - accounts: Vec, -} - -impl EthRpcServerImpl { - /// Creates a new [`EthRpcServerImpl`]. - pub fn new(client: client::Client) -> Self { - Self { client, accounts: vec![] } - } - - /// Sets the accounts managed by the server. - pub fn with_accounts(mut self, accounts: Vec) -> Self { - self.accounts = accounts; - self - } -} - -/// The error type for the EVM RPC server. -#[derive(Error, Debug)] -pub enum EthRpcError { - /// A [`ClientError`] wrapper error. - #[error("Client error: {0}")] - ClientError(#[from] ClientError), - /// A [`rlp::DecoderError`] wrapper error. - #[error("Decoding error: {0}")] - RlpError(#[from] rlp::DecoderError), - /// A Decimals conversion error. - #[error("Conversion error")] - ConversionError, - /// An invalid signature error. - #[error("Invalid signature")] - InvalidSignature, - /// The account was not found at the given address - #[error("Account not found for address {0:?}")] - AccountNotFound(H160), - /// Received an invalid transaction - #[error("Invalid transaction")] - InvalidTransaction, - /// Received an invalid transaction - #[error("Invalid transaction {0:?}")] - TransactionTypeNotSupported(Byte), -} - -impl From for ErrorObjectOwned { - fn from(value: EthRpcError) -> Self { - let code = match value { - EthRpcError::ClientError(_) => ErrorCode::InternalError, - _ => ErrorCode::InvalidRequest, - }; - Self::owned::(code.code(), value.to_string(), None) - } -} - -#[async_trait] -impl EthRpcServer for EthRpcServerImpl { - async fn net_version(&self) -> RpcResult { - Ok(self.client.chain_id().to_string()) - } - - async fn syncing(&self) -> RpcResult { - Ok(self.client.syncing().await?) - } - - async fn block_number(&self) -> RpcResult { - let number = self.client.block_number().await?; - Ok(number.into()) - } - - async fn get_transaction_receipt( - &self, - transaction_hash: H256, - ) -> RpcResult> { - let receipt = self.client.receipt(&transaction_hash).await; - Ok(receipt) - } - - async fn estimate_gas( - &self, - transaction: GenericTransaction, - _block: Option, - ) -> RpcResult { - let result = self.client.estimate_gas(&transaction, BlockTag::Latest.into()).await?; - Ok(result) - } - - async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult { - let tx = rlp::decode::(&transaction.0).map_err(|err| { - log::debug!(target: LOG_TARGET, "Failed to decode transaction: {err:?}"); - EthRpcError::from(err) - })?; - - let eth_addr = tx.recover_eth_address().map_err(|err| { - log::debug!(target: LOG_TARGET, "Failed to recover eth address: {err:?}"); - EthRpcError::InvalidSignature - })?; - - // Dry run the transaction to get the weight limit and storage deposit limit - let TransactionLegacyUnsigned { to, input, value, .. } = tx.transaction_legacy_unsigned; - let dry_run = self - .client - .dry_run( - &GenericTransaction { - from: Some(eth_addr), - input: Some(input.clone()), - to, - value: Some(value), - ..Default::default() - }, - BlockTag::Latest.into(), - ) - .await?; - - let EthContractResult { gas_limit, storage_deposit, .. } = dry_run; - let call = subxt_client::tx().revive().eth_transact( - transaction.0, - gas_limit.into(), - storage_deposit, - ); - let ext = self.client.tx().create_unsigned(&call).map_err(ClientError::from)?; - let hash = ext.submit().await.map_err(|err| EthRpcError::ClientError(err.into()))?; - - Ok(hash) - } - - async fn send_transaction(&self, transaction: GenericTransaction) -> RpcResult { - log::debug!(target: LOG_TARGET, "{transaction:#?}"); - let GenericTransaction { from, gas, gas_price, input, to, value, r#type, .. } = transaction; - - let Some(from) = from else { - log::debug!(target: LOG_TARGET, "Transaction must have a sender"); - return Err(EthRpcError::InvalidTransaction.into()); - }; - - let account = self - .accounts - .iter() - .find(|account| account.address() == from) - .ok_or(EthRpcError::AccountNotFound(from))?; - - let gas_price = gas_price.unwrap_or_else(|| U256::from(GAS_PRICE)); - let chain_id = Some(self.client.chain_id().into()); - let input = input.unwrap_or_default(); - let value = value.unwrap_or_default(); - let r#type = r#type.unwrap_or_default(); - - let Some(gas) = gas else { - log::debug!(target: LOG_TARGET, "Transaction must have a gas limit"); - return Err(EthRpcError::InvalidTransaction.into()); - }; - - let r#type = Type0::try_from_byte(r#type.clone()) - .map_err(|_| EthRpcError::TransactionTypeNotSupported(r#type))?; - - let nonce = self.get_transaction_count(from, BlockTag::Latest.into()).await?; - - let tx = - TransactionLegacyUnsigned { chain_id, gas, gas_price, input, nonce, to, value, r#type }; - let tx = account.sign_transaction(tx); - let rlp_bytes = rlp::encode(&tx).to_vec(); - self.send_raw_transaction(Bytes(rlp_bytes)).await - } - - async fn get_block_by_hash( - &self, - block_hash: H256, - _hydrated_transactions: bool, - ) -> RpcResult> { - let Some(block) = self.client.block_by_hash(&block_hash).await? else { - return Ok(None); - }; - let block = self.client.evm_block(block).await?; - Ok(Some(block)) - } - - async fn get_balance(&self, address: H160, block: BlockNumberOrTagOrHash) -> RpcResult { - let balance = self.client.balance(address, &block).await?; - log::debug!(target: LOG_TARGET, "balance({address}): {balance:?}"); - Ok(balance) - } - - async fn chain_id(&self) -> RpcResult { - Ok(self.client.chain_id().into()) - } - - async fn gas_price(&self) -> RpcResult { - Ok(U256::from(GAS_PRICE)) - } - - async fn get_code(&self, address: H160, block: BlockNumberOrTagOrHash) -> RpcResult { - let code = self.client.get_contract_code(&address, block).await?; - Ok(code.into()) - } - - async fn accounts(&self) -> RpcResult> { - Ok(self.accounts.iter().map(|account| account.address()).collect()) - } - - async fn call( - &self, - transaction: GenericTransaction, - block: Option, - ) -> RpcResult { - let dry_run = self - .client - .dry_run(&transaction, block.unwrap_or_else(|| BlockTag::Latest.into())) - .await?; - let output = dry_run.result.map_err(|err| { - log::debug!(target: LOG_TARGET, "Dry run failed: {err:?}"); - ClientError::DryRunFailed - })?; - - Ok(output.into()) - } - - async fn get_block_by_number( - &self, - block: BlockNumberOrTag, - _hydrated_transactions: bool, - ) -> RpcResult> { - let Some(block) = self.client.block_by_number_or_tag(&block).await? else { - return Ok(None); - }; - let block = self.client.evm_block(block).await?; - Ok(Some(block)) - } - - async fn get_block_transaction_count_by_hash( - &self, - block_hash: Option, - ) -> RpcResult> { - let block_hash = if let Some(block_hash) = block_hash { - block_hash - } else { - self.client.latest_block().await.ok_or(ClientError::BlockNotFound)?.hash() - }; - Ok(self.client.receipts_count_per_block(&block_hash).await.map(U256::from)) - } - - async fn get_block_transaction_count_by_number( - &self, - block: Option, - ) -> RpcResult> { - let Some(block) = self - .get_block_by_number(block.unwrap_or_else(|| BlockTag::Latest.into()), false) - .await? - else { - return Ok(None); - }; - - Ok(self.client.receipts_count_per_block(&block.hash).await.map(U256::from)) - } - - async fn get_storage_at( - &self, - address: H160, - storage_slot: U256, - block: BlockNumberOrTagOrHash, - ) -> RpcResult { - let bytes = self.client.get_contract_storage(address, storage_slot, block).await?; - Ok(bytes.into()) - } - - async fn get_transaction_by_block_hash_and_index( - &self, - block_hash: H256, - transaction_index: U256, - ) -> RpcResult> { - let Some(receipt) = - self.client.receipt_by_hash_and_index(&block_hash, &transaction_index).await - else { - return Ok(None); - }; - - let Some(signed_tx) = self.client.signed_tx_by_hash(&receipt.transaction_hash).await else { - return Ok(None); - }; - - Ok(Some(TransactionInfo::new(receipt, signed_tx))) - } - - async fn get_transaction_by_block_number_and_index( - &self, - block: BlockNumberOrTag, - transaction_index: U256, - ) -> RpcResult> { - let Some(block) = self.client.block_by_number_or_tag(&block).await? else { - return Ok(None); - }; - self.get_transaction_by_block_hash_and_index(block.hash(), transaction_index) - .await - } - - async fn get_transaction_by_hash( - &self, - transaction_hash: H256, - ) -> RpcResult> { - let receipt = self.client.receipt(&transaction_hash).await; - let signed_tx = self.client.signed_tx_by_hash(&transaction_hash).await; - if let (Some(receipt), Some(signed_tx)) = (receipt, signed_tx) { - return Ok(Some(TransactionInfo::new(receipt, signed_tx))); - } - - Ok(None) - } - - async fn get_transaction_count( - &self, - address: H160, - block: BlockNumberOrTagOrHash, - ) -> RpcResult { - let nonce = self.client.nonce(address, block).await?; - Ok(nonce.into()) - } -} - -/// A [`MiscRpcServer`] RPC server implementation. -pub struct MiscRpcServerImpl; - -#[async_trait] -impl MiscRpcServer for MiscRpcServerImpl { - async fn healthcheck(&self) -> RpcResult<()> { - Ok(()) - } -} diff --git a/substrate/frame/revive/rpc/src/main.rs b/substrate/frame/revive/rpc/src/main.rs deleted file mode 100644 index 5dbaeba899b2..000000000000 --- a/substrate/frame/revive/rpc/src/main.rs +++ /dev/null @@ -1,151 +0,0 @@ -// 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. -//! The Ethereum JSON-RPC server. -use clap::Parser; -use hyper::Method; -use jsonrpsee::{ - http_client::HttpClientBuilder, - server::{RpcModule, Server}, -}; -use pallet_revive_eth_rpc::{ - client::Client, EthRpcClient, EthRpcServer, EthRpcServerImpl, MiscRpcServer, MiscRpcServerImpl, - LOG_TARGET, -}; -use std::net::SocketAddr; -use tower_http::cors::{Any, CorsLayer}; -use tracing_subscriber::{util::SubscriberInitExt, EnvFilter, FmtSubscriber}; - -// Parsed command instructions from the command line -#[derive(Parser)] -#[clap(author, about, version)] -struct CliCommand { - /// The server address to bind to - #[clap(long, default_value = "127.0.0.1:9090")] - url: String, - - /// The node url to connect to - #[clap(long, default_value = "ws://127.0.0.1:9944")] - node_url: String, -} - -/// Initialize tracing -fn init_tracing() { - let env_filter = - EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("eth_rpc=trace")); - - FmtSubscriber::builder() - .with_env_filter(env_filter) - .finish() - .try_init() - .expect("failed to initialize tracing"); -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let CliCommand { url, node_url } = CliCommand::parse(); - init_tracing(); - - let client = Client::from_url(&node_url).await?; - let mut updates = client.updates.clone(); - - let server_addr = run_server(client, &url).await?; - log::info!(target: LOG_TARGET, "Server started on: {}", server_addr); - - let url = format!("http://{}", server_addr); - let client = HttpClientBuilder::default().build(url)?; - - let response = client.block_number().await?; - log::info!(target: LOG_TARGET, "client initialized with block number {:?}", response); - - // keep running server until ctrl-c or client subscription fails - let _ = updates.wait_for(|_| false).await; - Ok(()) -} - -#[cfg(feature = "dev")] -mod dev { - use crate::LOG_TARGET; - use futures::{future::BoxFuture, FutureExt}; - use jsonrpsee::{server::middleware::rpc::RpcServiceT, types::Request, MethodResponse}; - - /// Dev Logger middleware, that logs the method and params of the request, along with the - /// success of the response. - #[derive(Clone)] - pub struct DevLogger(pub S); - - impl<'a, S> RpcServiceT<'a> for DevLogger - where - S: RpcServiceT<'a> + Send + Sync + Clone + 'static, - { - type Future = BoxFuture<'a, MethodResponse>; - - fn call(&self, req: Request<'a>) -> Self::Future { - let service = self.0.clone(); - let method = req.method.clone(); - let params = req.params.clone().unwrap_or_default(); - - async move { - log::info!(target: LOG_TARGET, "method: {method} params: {params}"); - let resp = service.call(req).await; - if resp.is_success() { - log::info!(target: LOG_TARGET, "✅ rpc: {method}"); - } else { - log::info!(target: LOG_TARGET, "❌ rpc: {method} {}", resp.as_result()); - } - resp - } - .boxed() - } - } -} - -/// Starts the rpc server and returns the server address. -async fn run_server(client: Client, url: &str) -> anyhow::Result { - let cors = CorsLayer::new() - .allow_methods([Method::POST]) - .allow_origin(Any) - .allow_headers([hyper::header::CONTENT_TYPE]); - let cors_middleware = tower::ServiceBuilder::new().layer(cors); - - let builder = Server::builder().set_http_middleware(cors_middleware); - - #[cfg(feature = "dev")] - let builder = builder - .set_rpc_middleware(jsonrpsee::server::RpcServiceBuilder::new().layer_fn(dev::DevLogger)); - - let server = builder.build(url.parse::()?).await?; - let addr = server.local_addr()?; - - let eth_api = EthRpcServerImpl::new(client) - .with_accounts(if cfg!(feature = "dev") { - use pallet_revive::evm::Account; - vec![Account::default()] - } else { - vec![] - }) - .into_rpc(); - let misc_api = MiscRpcServerImpl.into_rpc(); - - let mut module = RpcModule::new(()); - module.merge(eth_api)?; - module.merge(misc_api)?; - - let handle = server.start(module); - tokio::spawn(handle.stopped()); - - Ok(addr) -} diff --git a/substrate/frame/revive/rpc/src/rpc_methods_gen.rs b/substrate/frame/revive/rpc/src/rpc_methods_gen.rs deleted file mode 100644 index 339080368969..000000000000 --- a/substrate/frame/revive/rpc/src/rpc_methods_gen.rs +++ /dev/null @@ -1,160 +0,0 @@ -// 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. -//! Generated JSON-RPC methods. -#![allow(missing_docs)] - -use super::*; -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; - -#[rpc(server, client)] -pub trait EthRpc { - /// Returns a list of addresses owned by client. - #[method(name = "eth_accounts")] - async fn accounts(&self) -> RpcResult>; - - /// Returns the number of most recent block. - #[method(name = "eth_blockNumber")] - async fn block_number(&self) -> RpcResult; - - /// Executes a new message call immediately without creating a transaction on the block chain. - #[method(name = "eth_call")] - async fn call( - &self, - transaction: GenericTransaction, - block: Option, - ) -> RpcResult; - - /// Returns the chain ID of the current network. - #[method(name = "eth_chainId")] - async fn chain_id(&self) -> RpcResult; - - /// Generates and returns an estimate of how much gas is necessary to allow the transaction to - /// complete. - #[method(name = "eth_estimateGas")] - async fn estimate_gas( - &self, - transaction: GenericTransaction, - block: Option, - ) -> RpcResult; - - /// Returns the current price per gas in wei. - #[method(name = "eth_gasPrice")] - async fn gas_price(&self) -> RpcResult; - - /// Returns the balance of the account of given address. - #[method(name = "eth_getBalance")] - async fn get_balance(&self, address: Address, block: BlockNumberOrTagOrHash) - -> RpcResult; - - /// Returns information about a block by hash. - #[method(name = "eth_getBlockByHash")] - async fn get_block_by_hash( - &self, - block_hash: H256, - hydrated_transactions: bool, - ) -> RpcResult>; - - /// Returns information about a block by number. - #[method(name = "eth_getBlockByNumber")] - async fn get_block_by_number( - &self, - block: BlockNumberOrTag, - hydrated_transactions: bool, - ) -> RpcResult>; - - /// Returns the number of transactions in a block from a block matching the given block hash. - #[method(name = "eth_getBlockTransactionCountByHash")] - async fn get_block_transaction_count_by_hash( - &self, - block_hash: Option, - ) -> RpcResult>; - - /// Returns the number of transactions in a block matching the given block number. - #[method(name = "eth_getBlockTransactionCountByNumber")] - async fn get_block_transaction_count_by_number( - &self, - block: Option, - ) -> RpcResult>; - - /// Returns code at a given address. - #[method(name = "eth_getCode")] - async fn get_code(&self, address: Address, block: BlockNumberOrTagOrHash) -> RpcResult; - - /// Returns the value from a storage position at a given address. - #[method(name = "eth_getStorageAt")] - async fn get_storage_at( - &self, - address: Address, - storage_slot: U256, - block: BlockNumberOrTagOrHash, - ) -> RpcResult; - - /// Returns information about a transaction by block hash and transaction index position. - #[method(name = "eth_getTransactionByBlockHashAndIndex")] - async fn get_transaction_by_block_hash_and_index( - &self, - block_hash: H256, - transaction_index: U256, - ) -> RpcResult>; - - /// Returns information about a transaction by block number and transaction index position. - #[method(name = "eth_getTransactionByBlockNumberAndIndex")] - async fn get_transaction_by_block_number_and_index( - &self, - block: BlockNumberOrTag, - transaction_index: U256, - ) -> RpcResult>; - - /// Returns the information about a transaction requested by transaction hash. - #[method(name = "eth_getTransactionByHash")] - async fn get_transaction_by_hash( - &self, - transaction_hash: H256, - ) -> RpcResult>; - - /// Returns the number of transactions sent from an address. - #[method(name = "eth_getTransactionCount")] - async fn get_transaction_count( - &self, - address: Address, - block: BlockNumberOrTagOrHash, - ) -> RpcResult; - - /// Returns the receipt of a transaction by transaction hash. - #[method(name = "eth_getTransactionReceipt")] - async fn get_transaction_receipt( - &self, - transaction_hash: H256, - ) -> RpcResult>; - - /// Submits a raw transaction. For EIP-4844 transactions, the raw form must be the network form. - /// This means it includes the blobs, KZG commitments, and KZG proofs. - #[method(name = "eth_sendRawTransaction")] - async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult; - - /// Signs and submits a transaction. - #[method(name = "eth_sendTransaction")] - async fn send_transaction(&self, transaction: GenericTransaction) -> RpcResult; - - /// Returns an object with data about the sync status or false. - #[method(name = "eth_syncing")] - async fn syncing(&self) -> RpcResult; - - /// The string value of current network id - #[method(name = "net_version")] - async fn net_version(&self) -> RpcResult; -} diff --git a/substrate/frame/revive/rpc/src/subxt_client.rs b/substrate/frame/revive/rpc/src/subxt_client.rs deleted file mode 100644 index 359fe62e4e4c..000000000000 --- a/substrate/frame/revive/rpc/src/subxt_client.rs +++ /dev/null @@ -1,69 +0,0 @@ -// 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. -//! The generated subxt client. -use subxt::config::{signed_extensions, Config, PolkadotConfig}; - -#[subxt::subxt( - runtime_metadata_path = "kitchensink.scale", - substitute_type( - path = "pallet_revive::primitives::EthContractResult", - with = "::subxt::utils::Static<::pallet_revive::EthContractResult>" - ), - substitute_type( - path = "sp_weights::weight_v2::Weight", - with = "::subxt::utils::Static<::sp_weights::Weight>" - ) -)] -mod src_chain {} -pub use src_chain::*; - -/// The configuration for the source chain. -pub enum SrcChainConfig {} -impl Config for SrcChainConfig { - type Hash = sp_core::H256; - type AccountId = ::AccountId; - type Address = ::Address; - type Signature = ::Signature; - type Hasher = BlakeTwo256; - type Header = subxt::config::substrate::SubstrateHeader; - type AssetId = ::AssetId; - type ExtrinsicParams = signed_extensions::AnyOf< - Self, - ( - signed_extensions::CheckSpecVersion, - signed_extensions::CheckTxVersion, - signed_extensions::CheckNonce, - signed_extensions::CheckGenesis, - signed_extensions::CheckMortality, - signed_extensions::ChargeAssetTxPayment, - signed_extensions::ChargeTransactionPayment, - signed_extensions::CheckMetadataHash, - ), - >; -} - -/// A type that can hash values using the blaks2_256 algorithm. -/// TODO remove once subxt is updated -#[derive(Debug, Clone, Copy, PartialEq, Eq, codec::Encode)] -pub struct BlakeTwo256; - -impl subxt::config::Hasher for BlakeTwo256 { - type Output = sp_core::H256; - fn hash(s: &[u8]) -> Self::Output { - sp_crypto_hashing::blake2_256(s).into() - } -} diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index fb7b891d91ba..80e72e83c4ce 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -599,7 +599,7 @@ runtime = [ "sp-wasm-interface", "sp-weights", ] -node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-revive-eth-rpc", "pallet-revive-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", "polkadot-node-core-candidate-validation", "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-omni-node-lib", "polkadot-overseer", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] +node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-revive-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", "polkadot-node-core-candidate-validation", "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-omni-node-lib", "polkadot-overseer", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] tuples-96 = [ "frame-support-procedural?/tuples-96", "frame-support?/tuples-96", @@ -1891,11 +1891,6 @@ path = "../substrate/frame/contracts/mock-network" default-features = false optional = true -[dependencies.pallet-revive-eth-rpc] -path = "../substrate/frame/revive/rpc" -default-features = false -optional = true - [dependencies.pallet-revive-mock-network] path = "../substrate/frame/revive/mock-network" default-features = false diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs index 90908d205325..7778706d515d 100644 --- a/umbrella/src/lib.rs +++ b/umbrella/src/lib.rs @@ -580,10 +580,6 @@ pub use pallet_remark; #[cfg(feature = "pallet-revive")] pub use pallet_revive; -/// An Ethereum JSON-RPC server for pallet-revive. -#[cfg(feature = "pallet-revive-eth-rpc")] -pub use pallet_revive_eth_rpc; - /// Fixtures for testing and benchmarking. #[cfg(feature = "pallet-revive-fixtures")] pub use pallet_revive_fixtures; From f646c9e410ea5c879f4ab0637044aa66b3d3321e Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Sat, 19 Oct 2024 15:46:20 +0200 Subject: [PATCH 124/174] Update substrate/frame/revive/src/primitives.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Theißen --- substrate/frame/revive/src/primitives.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index 513a6cbdb4d8..af0100d59cbe 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -87,8 +87,8 @@ pub struct ContractResult { pub struct EthContractResult { /// The fee charged for the execution. pub fee: Balance, - /// Gas limit of the transaction. - pub gas_limit: Weight, + /// The amount of gas that was necessary to execute the transaction. + pub gas_required: Weight, /// Storage deposit charged. pub storage_deposit: Balance, /// The execution result. From 50015cbd892991e2fbd1f73b147d8cbac89b9415 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Sat, 19 Oct 2024 15:52:31 +0200 Subject: [PATCH 125/174] gas_limit pr review --- Cargo.lock | 157 +----------------------------- substrate/frame/revive/src/lib.rs | 4 +- 2 files changed, 3 insertions(+), 158 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4c6373bd9ca..64c39028c8c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,21 +119,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "allocator-api2" version = "0.2.16" @@ -1160,22 +1145,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-compression" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" -dependencies = [ - "brotli", - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", - "zstd 0.13.0", - "zstd-safe 7.0.0", -] - [[package]] name = "async-executor" version = "1.5.1" @@ -2605,27 +2574,6 @@ dependencies = [ "tuplex", ] -[[package]] -name = "brotli" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - [[package]] name = "bs58" version = "0.5.1" @@ -7458,12 +7406,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" -[[package]] -name = "http-range-header" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" - [[package]] name = "httparse" version = "1.8.0" @@ -7943,16 +7885,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" -[[package]] -name = "iri-string" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0f0a572e8ffe56e2ff4f769f32ffe919282c3916799f8b68688b6030063bea" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "is-terminal" version = "0.4.9" @@ -9736,16 +9668,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -12520,40 +12442,6 @@ dependencies = [ "subxt-signer", ] -[[package]] -name = "pallet-revive-eth-rpc" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap 4.5.13", - "env_logger 0.11.3", - "futures", - "hex", - "hex-literal", - "hyper 1.3.1", - "jsonrpsee 0.24.3", - "log", - "pallet-revive", - "pallet-revive-fixtures", - "parity-scale-codec", - "rlp 0.6.1", - "sc-rpc", - "scale-info", - "secp256k1", - "serde_json", - "sp-core 28.0.0", - "sp-crypto-hashing 0.1.0", - "sp-runtime 31.0.1", - "sp-weights 27.0.0", - "subxt", - "subxt-signer", - "thiserror", - "tokio", - "tower", - "tower-http 0.5.2", - "tracing-subscriber 0.3.18", -] - [[package]] name = "pallet-revive-fixtures" version = "0.1.0" @@ -15540,7 +15428,6 @@ dependencies = [ "pallet-referenda", "pallet-remark", "pallet-revive", - "pallet-revive-eth-rpc", "pallet-revive-fixtures", "pallet-revive-mock-network", "pallet-revive-proc-macro", @@ -25271,7 +25158,7 @@ dependencies = [ "futures-util", "http 0.2.9", "http-body 0.4.5", - "http-range-header 0.3.1", + "http-range-header", "mime", "pin-project-lite", "tower-layer", @@ -25285,29 +25172,14 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "async-compression", - "base64 0.21.7", "bitflags 2.6.0", "bytes", - "futures-core", - "futures-util", "http 1.1.0", "http-body 1.0.0", "http-body-util", - "http-range-header 0.4.1", - "httpdate", - "iri-string", - "mime", - "mime_guess", - "percent-encoding", "pin-project-lite", - "tokio", - "tokio-util", - "tower", "tower-layer", "tower-service", - "tracing", - "uuid", ] [[package]] @@ -25724,15 +25596,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.13" @@ -27572,15 +27435,6 @@ dependencies = [ "zstd-safe 6.0.6", ] -[[package]] -name = "zstd" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" -dependencies = [ - "zstd-safe 7.0.0", -] - [[package]] name = "zstd-safe" version = "5.0.2+zstd.1.5.2" @@ -27601,15 +27455,6 @@ dependencies = [ "zstd-sys", ] -[[package]] -name = "zstd-safe" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" -dependencies = [ - "zstd-sys", -] - [[package]] name = "zstd-sys" version = "2.0.8+zstd.1.5.5" diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 1bad13093acb..9b0bbb2d6bcb 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1240,7 +1240,7 @@ where log::debug!(target: LOG_TARGET, "Call dry run Result: dispatch_info: {dispatch_info:?} len: {encoded_len:?} fee: {fee:?}"); EthContractResult { - gas_limit: result.gas_required, + gas_required: result.gas_required, storage_deposit: result.storage_deposit.charge_or_zero(), result: result.result.map(|v| v.data), fee, @@ -1313,7 +1313,7 @@ where log::debug!(target: LOG_TARGET, "Call dry run Result: dispatch_info: {dispatch_info:?} len: {encoded_len:?} fee: {fee:?}"); EthContractResult { - gas_limit: result.gas_required, + gas_required: result.gas_required, storage_deposit: result.storage_deposit.charge_or_zero(), result: result.result.map(|v| v.result.data), fee, From 483b6385eb631d412e0124f6169256768ac5a9cc Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Sun, 20 Oct 2024 23:42:56 +0200 Subject: [PATCH 126/174] Update substrate/bin/node/runtime/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Theißen --- substrate/bin/node/runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 7df52d2f776d..8fcf52548286 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -3171,7 +3171,7 @@ impl_runtime_apis! { { use pallet_revive::AddressMapper; let blockweights: BlockWeights = ::BlockWeights::get(); - let origin = ::AddressMapper::to_account_id_contract(&from); + let origin = ::AddressMapper::to_account_id(&from); let encoded_size = |pallet_call| { let call = RuntimeCall::Revive(pallet_call); From 6a58fa577bfed217c2dbacedc77eaedb89c28d13 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Sun, 20 Oct 2024 23:45:38 +0200 Subject: [PATCH 127/174] Add comment on GAS_PRICE constant --- substrate/frame/revive/src/evm/runtime.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 722451917942..9c0a686d9a72 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -43,6 +43,8 @@ use alloc::vec::Vec; type CallOf = ::RuntimeCall; /// The EVM gas price. +/// This constant is used by the proxy to advertise it via the eth_gas_price RPC. +/// /// We use a fixed value for the gas price. /// This let us calculate the gas estimate for a transaction with the formula: /// `estimate_gas = substrate_fee / gas_price`. From 13fed3df0f671ece204194dbdff101de35f183f8 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Sun, 20 Oct 2024 23:46:23 +0200 Subject: [PATCH 128/174] rm demo.rs --- .../frame/revive/fixtures/contracts/demo.rs | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 substrate/frame/revive/fixtures/contracts/demo.rs diff --git a/substrate/frame/revive/fixtures/contracts/demo.rs b/substrate/frame/revive/fixtures/contracts/demo.rs deleted file mode 100644 index 0d75c6eb8df6..000000000000 --- a/substrate/frame/revive/fixtures/contracts/demo.rs +++ /dev/null @@ -1,36 +0,0 @@ -// 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. - -#![no_std] -#![no_main] - -use common::input; -use uapi::{HostFn, HostFnImpl as api}; - -#[no_mangle] -#[polkavm_derive::polkavm_export] -pub extern "C" fn deploy() { - input!(128, data: [u8],); - api::deposit_event(&[], data); -} - -#[no_mangle] -#[polkavm_derive::polkavm_export] -pub extern "C" fn call() { - input!(128, data: [u8],); - api::deposit_event(&[], data); -} From 83c0a386e7783bf189f614b66a7ca1a0f1ff533e Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 00:29:04 +0200 Subject: [PATCH 129/174] fix tests --- substrate/frame/revive/src/evm/runtime.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 9c0a686d9a72..94f42bd6072e 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -379,12 +379,15 @@ mod test { use crate::{ evm::*, test_utils::*, - tests::{ExtBuilder, RuntimeCall, Test}, + tests::{ExtBuilder, RuntimeCall, RuntimeOrigin, Test}, }; use frame_support::{error::LookupError, traits::fungible::Mutate}; use pallet_revive_fixtures::compile_module; use rlp::Encodable; - use sp_runtime::{traits::Checkable, MultiAddress, MultiSignature}; + use sp_runtime::{ + traits::{Checkable, DispatchTransaction}, + MultiAddress, MultiSignature, + }; type AccountIdOf = ::AccountId; /// A simple account that can sign transactions @@ -436,8 +439,7 @@ mod test { } } - type Ex = - UncheckedExtrinsic, RuntimeCall, MultiSignature, Extra>; + type Ex = UncheckedExtrinsic, MultiSignature, Extra>; struct TestContext; impl traits::Lookup for TestContext { @@ -514,11 +516,15 @@ mod test { }); let encoded_len = call.encoded_size(); - let result = Ex::new(call, None).unwrap().check(&TestContext {})?; - let (account_id, extra) = result.signed.unwrap(); + let uxt: Ex = generic::UncheckedExtrinsic::new_bare(call).into(); + let result: CheckedExtrinsic<_, _, _> = uxt.check(&TestContext {})?; + let (account_id, extra): (AccountId32, SignedExtra) = match result.format { + ExtrinsicFormat::Signed(signer, extra) => (signer, extra), + _ => unreachable!(), + }; - extra.clone().pre_dispatch( - &account_id, + extra.clone().validate_and_prepare( + RuntimeOrigin::signed(account_id), &result.function, &result.function.get_dispatch_info(), encoded_len, From 9d06cfeb35ba87be41e1c846a038396f765145f6 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 07:52:35 +0200 Subject: [PATCH 130/174] fix --- substrate/bin/node/testing/src/bench.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index 6a308312a339..3812524f0b1f 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -53,7 +53,7 @@ use sp_core::{ use sp_crypto_hashing::blake2_256; use sp_inherents::InherentData; use sp_runtime::{ - generic::{generic, ExtrinsicFormat, Preamble, EXTRINSIC_FORMAT_VERSION}, + generic::{self, ExtrinsicFormat, Preamble, EXTRINSIC_FORMAT_VERSION}, traits::{Block as BlockT, IdentifyAccount, Verify}, OpaqueExtrinsic, }; From 9e98cbb16b7ecbfb7a4aa43404f328463ca2e17a Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 08:26:58 +0200 Subject: [PATCH 131/174] simplify --- .../bin/node/cli/benches/block_production.rs | 4 +--- .../bin/node/cli/benches/transaction_pool.rs | 7 ++----- substrate/bin/node/cli/src/benchmarking.rs | 14 +++++++------- substrate/frame/revive/src/evm/runtime.rs | 18 +++++++++++++++++- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index c98d556ea963..d8041ed400c7 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -39,7 +39,6 @@ use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed} use sp_consensus::BlockOrigin; use sp_keyring::Sr25519Keyring; use sp_runtime::{ - generic, transaction_validity::{InvalidTransaction, TransactionValidityError}, AccountId32, MultiAddress, OpaqueExtrinsic, }; @@ -121,7 +120,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { } fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { - generic::UncheckedExtrinsic::new_bare(kitchensink_runtime::RuntimeCall::Timestamp( + kitchensink_runtime::UncheckedExtrinsic::new_bare(kitchensink_runtime::RuntimeCall::Timestamp( pallet_timestamp::Call::set { now }, )) .into() @@ -164,7 +163,6 @@ fn prepare_benchmark(client: &FullClient) -> (usize, Vec) { BalancesCall::transfer_allow_death { dest: dst.clone(), value: 1 * DOLLARS }, Some(nonce), ) - .0 .into(); match block_builder.push(extrinsic.clone()) { diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index c3790bdb539b..c07cb3ec0d13 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -145,8 +145,7 @@ fn create_account_extrinsics( ), }, Some(start_nonce + (i as u32) * 2), - ) - .0, + ), // Give back funds create_extrinsic( client, @@ -161,8 +160,7 @@ fn create_account_extrinsics( ), }, Some(start_nonce + (i as u32) * 2 + 1), - ) - .0, + ), ] }) .map(OpaqueExtrinsic::from) @@ -187,7 +185,6 @@ fn create_benchmark_extrinsics( }, Some(nonce as u32), ) - .0 }) }) .map(OpaqueExtrinsic::from) diff --git a/substrate/bin/node/cli/src/benchmarking.rs b/substrate/bin/node/cli/src/benchmarking.rs index 0172a5b10fad..a2b28a0f317d 100644 --- a/substrate/bin/node/cli/src/benchmarking.rs +++ b/substrate/bin/node/cli/src/benchmarking.rs @@ -29,8 +29,8 @@ use node_primitives::{AccountId, Balance}; use sc_cli::Result; use sp_inherents::{InherentData, InherentDataProvider}; use sp_keyring::Sr25519Keyring; +use sp_runtime::OpaqueExtrinsic; -use sp_runtime::{generic, OpaqueExtrinsic}; use std::{sync::Arc, time::Duration}; /// Generates `System::Remark` extrinsics for the benchmarks. @@ -58,15 +58,15 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { fn build(&self, nonce: u32) -> std::result::Result { let acc = Sr25519Keyring::Bob.pair(); - let extrinsic: generic::UncheckedExtrinsic<_, _, _, _> = create_extrinsic( + let extrinsic: OpaqueExtrinsic = create_extrinsic( self.client.as_ref(), acc, SystemCall::remark { remark: vec![] }, Some(nonce), ) - .0; + .into(); - Ok(extrinsic.into()) + Ok(extrinsic) } } @@ -97,7 +97,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { fn build(&self, nonce: u32) -> std::result::Result { let acc = Sr25519Keyring::Bob.pair(); - let extrinsic: generic::UncheckedExtrinsic<_, _, _, _> = create_extrinsic( + let extrinsic: OpaqueExtrinsic = create_extrinsic( self.client.as_ref(), acc, BalancesCall::transfer_keep_alive { @@ -106,9 +106,9 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { }, Some(nonce), ) - .0; + .into(); - Ok(extrinsic.into()) + Ok(extrinsic) } } diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 94f42bd6072e..b77a2daa743f 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -35,7 +35,7 @@ use sp_runtime::{ TransactionExtension, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, - RuntimeDebug, Saturating, + OpaqueExtrinsic, RuntimeDebug, Saturating, }; use alloc::vec::Vec; @@ -215,6 +215,22 @@ where } } +impl From> + for OpaqueExtrinsic +where + Address: Encode, + Signature: Encode, + CallOf: Encode, + E::Extra: Encode, +{ + fn from(extrinsic: UncheckedExtrinsic) -> Self { + Self::from_bytes(extrinsic.encode().as_slice()).expect( + "both OpaqueExtrinsic and UncheckedExtrinsic have encoding that is compatible with \ + raw Vec encoding; qed", + ) + } +} + /// EthExtra convert an unsigned [`crate::Call::eth_transact`] into a [`CheckedExtrinsic`]. pub trait EthExtra { /// The Runtime configuration. From 07a6717650a46d02898957be5f524e3f071afbfd Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 08:48:54 +0200 Subject: [PATCH 132/174] Rename things to match #3685 --- substrate/bin/node/runtime/src/lib.rs | 11 +++--- substrate/frame/revive/src/evm/runtime.rs | 44 +++++++++++------------ 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 8fcf52548286..d6a17856e470 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2630,13 +2630,13 @@ pub type TxExtension = ( ); #[derive(Clone, PartialEq, Eq, Debug)] -pub struct EthSignedExtra; +pub struct EthExtraImpl; -impl EthExtra for EthSignedExtra { +impl EthExtra for EthExtraImpl { type Config = Runtime; - type Extra = TxExtension; + type Extension = TxExtension; - fn get_eth_transact_extra(nonce: u32, tip: Balance) -> Self::Extra { + fn get_eth_extension(nonce: u32, tip: Balance) -> Self::Extension { ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), @@ -2654,11 +2654,10 @@ impl EthExtra for EthSignedExtra { /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - pallet_revive::evm::runtime::UncheckedExtrinsic; + pallet_revive::evm::runtime::UncheckedExtrinsic; /// Unchecked signature payload type as expected by this runtime. pub type UncheckedSignaturePayload = generic::UncheckedSignaturePayload; - /// The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload; /// Extrinsic type that has already been checked. diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index b77a2daa743f..6620bf152f60 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -55,15 +55,15 @@ pub const GAS_PRICE: u32 = 1_000u32; #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] #[scale_info(skip_type_params(E))] pub struct UncheckedExtrinsic( - pub generic::UncheckedExtrinsic, Signature, E::Extra>, + pub generic::UncheckedExtrinsic, Signature, E::Extension>, ); impl - From, Signature, E::Extra>> + From, Signature, E::Extension>> for UncheckedExtrinsic { fn from( - utx: generic::UncheckedExtrinsic, Signature, E::Extra>, + utx: generic::UncheckedExtrinsic, Signature, E::Extension>, ) -> Self { Self(utx) } @@ -81,8 +81,8 @@ impl ExtrinsicMetadata for UncheckedExtrinsic { const VERSION: u8 = - generic::UncheckedExtrinsic::, Signature, E::Extra>::VERSION; - type TransactionExtensions = E::Extra; + generic::UncheckedExtrinsic::, Signature, E::Extension>::VERSION; + type TransactionExtensions = E::Extension; } impl ExtrinsicCall @@ -115,10 +115,10 @@ where CallOf: Encode + Member + Dispatchable, Signature: Member + traits::Verify, ::Signer: IdentifyAccount>, - E::Extra: Encode + TransactionExtension>, + E::Extension: Encode + TransactionExtension>, Lookup: traits::Lookup>, { - type Checked = CheckedExtrinsic, CallOf, E::Extra>; + type Checked = CheckedExtrinsic, CallOf, E::Extension>; fn check(self, lookup: &Lookup) -> Result { if !self.0.is_signed() { @@ -187,17 +187,17 @@ where Address: TypeInfo, CallOf: TypeInfo, Signature: TypeInfo, - E::Extra: TypeInfo, + E::Extension: TypeInfo, { type Address = Address; type Signature = Signature; - type Extension = E::Extra; + type Extension = E::Extension; fn new_signed_transaction( call: Self::Call, signed: Address, signature: Signature, - tx_ext: E::Extra, + tx_ext: E::Extension, ) -> Self { generic::UncheckedExtrinsic::new_signed(call, signed, signature, tx_ext).into() } @@ -208,7 +208,7 @@ where Address: TypeInfo, CallOf: TypeInfo, Signature: TypeInfo, - E::Extra: TypeInfo, + E::Extension: TypeInfo, { fn new_inherent(call: Self::Call) -> Self { generic::UncheckedExtrinsic::new_bare(call).into() @@ -236,21 +236,22 @@ pub trait EthExtra { /// The Runtime configuration. type Config: crate::Config + pallet_transaction_payment::Config; - /// The Runtime's signed extension. + /// The Runtime's transaction extension. /// It should include at least: /// - [`frame_system::CheckNonce`] to ensure that the nonce from the Ethereum transaction is /// correct. - type Extra: TransactionExtension>; + type Extension: TransactionExtension>; - /// Get the signed extensions to apply to an unsigned [`crate::Call::eth_transact`] extrinsic. + /// Get the transaction extension to apply to an unsigned [`crate::Call::eth_transact`] + /// extrinsic. /// /// # Parameters /// - `nonce`: The nonce extracted from the Ethereum transaction. /// - `tip`: The transaction tip calculated from the Ethereum transaction. - fn get_eth_transact_extra( + fn get_eth_extension( nonce: ::Nonce, tip: BalanceOf, - ) -> Self::Extra; + ) -> Self::Extension; /// Convert the unsigned [`crate::Call::eth_transact`] into a [`CheckedExtrinsic`]. /// and ensure that the fees from the Ethereum transaction correspond to the fees computed from @@ -267,7 +268,7 @@ pub trait EthExtra { storage_deposit_limit: BalanceOf, encoded_len: usize, ) -> Result< - CheckedExtrinsic, CallOf, Self::Extra>, + CheckedExtrinsic, CallOf, Self::Extension>, InvalidTransaction, > where @@ -380,10 +381,7 @@ pub trait EthExtra { let tip = eth_fee.saturating_sub(eth_fee_no_tip); log::debug!(target: LOG_TARGET, "Created checked Ethereum transaction with nonce {nonce:?} and tip: {tip:?}"); Ok(CheckedExtrinsic { - format: ExtrinsicFormat::Signed( - signer.into(), - Self::get_eth_transact_extra(nonce, tip), - ), + format: ExtrinsicFormat::Signed(signer.into(), Self::get_eth_extension(nonce, tip)), function, }) } @@ -448,9 +446,9 @@ mod test { use pallet_transaction_payment::ChargeTransactionPayment; impl EthExtra for Extra { type Config = Test; - type Extra = SignedExtra; + type Extension = SignedExtra; - fn get_eth_transact_extra(nonce: u32, tip: BalanceOf) -> Self::Extra { + fn get_eth_extension(nonce: u32, tip: BalanceOf) -> Self::Extension { (frame_system::CheckNonce::from(nonce), ChargeTransactionPayment::from(tip)) } } From 58a6942b9a7b8e276ecc4160bff7cfbfbeb0bd00 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 09:05:26 +0200 Subject: [PATCH 133/174] typo --- substrate/frame/revive/src/evm/api/rlp_codec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs index da1901f86ab5..e5f24c28a482 100644 --- a/substrate/frame/revive/src/evm/api/rlp_codec.rs +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -22,7 +22,7 @@ use alloc::vec::Vec; use rlp::{Decodable, Encodable}; impl TransactionLegacyUnsigned { - /// Get a rlp encoded bytes of a signed transaction with a dummy 65 bytes signature. + /// Get the rlp encoded bytes of a signed transaction with a dummy 65 bytes signature. pub fn dummy_signed_payload(&self) -> Vec { let mut s = rlp::RlpStream::new(); s.append(self); From d1de70fc03b9232881e29aa71fe0dd63c88e21bb Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 09:22:16 +0200 Subject: [PATCH 134/174] fix --- substrate/frame/revive/src/evm/runtime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 6620bf152f60..58110bcf186f 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -221,7 +221,7 @@ where Address: Encode, Signature: Encode, CallOf: Encode, - E::Extra: Encode, + E::Extension: Encode, { fn from(extrinsic: UncheckedExtrinsic) -> Self { Self::from_bytes(extrinsic.encode().as_slice()).expect( From e3f3f4b3c9461363605ee8cd5ad6f9de9379df35 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 10:11:03 +0200 Subject: [PATCH 135/174] CI build fixes --- .../bin/node/cli/benches/block_production.rs | 3 ++- substrate/bin/node/cli/src/service.rs | 19 +++++++++++-------- substrate/bin/node/cli/tests/basic.rs | 8 ++++---- substrate/bin/node/cli/tests/fees.rs | 2 +- .../bin/node/cli/tests/submit_transaction.rs | 3 ++- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index d8041ed400c7..2645ec24e888 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -39,6 +39,7 @@ use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed} use sp_consensus::BlockOrigin; use sp_keyring::Sr25519Keyring; use sp_runtime::{ + generic, transaction_validity::{InvalidTransaction, TransactionValidityError}, AccountId32, MultiAddress, OpaqueExtrinsic, }; @@ -120,7 +121,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { } fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { - kitchensink_runtime::UncheckedExtrinsic::new_bare(kitchensink_runtime::RuntimeCall::Timestamp( + generic::UncheckedExtrinsic::new_bare(kitchensink_runtime::RuntimeCall::Timestamp( pallet_timestamp::Call::set { now }, )) .into() diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 7b690e1c81fd..d71f1304caf5 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -867,7 +867,7 @@ mod tests { use codec::Encode; use kitchensink_runtime::{ constants::{currency::CENTS, time::SLOT_DURATION}, - Address, BalancesCall, RuntimeCall, TxExtension, UncheckedExtrinsic, + Address, BalancesCall, RuntimeCall, TxExtension, }; use node_primitives::{Block, DigestItem, Signature}; use polkadot_sdk::{sc_transaction_pool_api::MaintainedTransactionPool, *}; @@ -1100,13 +1100,16 @@ mod tests { let signature = raw_payload.using_encoded(|payload| signer.sign(payload)); let (function, tx_ext, _) = raw_payload.deconstruct(); index += 1; - generic::UncheckedExtrinsic::new_signed( - function, - from.into(), - signature.into(), - tx_ext, - ) - .into() + let utx: kitchensink_runtime::UncheckedExtrinsic = + generic::UncheckedExtrinsic::new_signed( + function, + from.into(), + signature.into(), + tx_ext, + ) + .into(); + + utx.into() }, ); } diff --git a/substrate/bin/node/cli/tests/basic.rs b/substrate/bin/node/cli/tests/basic.rs index 616d813f78e3..8f1475fce4f8 100644 --- a/substrate/bin/node/cli/tests/basic.rs +++ b/substrate/bin/node/cli/tests/basic.rs @@ -61,14 +61,14 @@ pub fn bloaty_code_unwrap() -> &'static [u8] { /// correct multiplier. fn transfer_fee(extrinsic: &UncheckedExtrinsic) -> Balance { let mut info = default_transfer_call().get_dispatch_info(); - info.extension_weight = extrinsic.extension_weight(); + info.extension_weight = extrinsic.0.extension_weight(); TransactionPayment::compute_fee(extrinsic.encode().len() as u32, &info, 0) } /// Default transfer fee, same as `transfer_fee`, but with a weight refund factored in. fn transfer_fee_with_refund(extrinsic: &UncheckedExtrinsic, weight_refund: Weight) -> Balance { let mut info = default_transfer_call().get_dispatch_info(); - info.extension_weight = extrinsic.extension_weight(); + info.extension_weight = extrinsic.0.extension_weight(); let post_info = (Some(info.total_weight().saturating_sub(weight_refund)), info.pays_fee).into(); TransactionPayment::compute_actual_fee(extrinsic.encode().len() as u32, &info, &post_info, 0) } @@ -324,7 +324,7 @@ fn full_native_block_import_works() { let mut alice_last_known_balance: Balance = Default::default(); let mut fees = t.execute_with(|| transfer_fee(&xt())); - let extension_weight = xt().extension_weight(); + let extension_weight = xt().0.extension_weight(); let weight_refund = Weight::zero(); let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); @@ -427,7 +427,7 @@ fn full_native_block_import_works() { fees = t.execute_with(|| transfer_fee(&xt())); let pot = t.execute_with(|| Treasury::pot()); - let extension_weight = xt().extension_weight(); + let extension_weight = xt().0.extension_weight(); let weight_refund = Weight::zero(); let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); diff --git a/substrate/bin/node/cli/tests/fees.rs b/substrate/bin/node/cli/tests/fees.rs index 59ade9b8547b..da9d2662408e 100644 --- a/substrate/bin/node/cli/tests/fees.rs +++ b/substrate/bin/node/cli/tests/fees.rs @@ -175,7 +175,7 @@ fn transaction_fee_is_correct() { balance_alice -= length_fee; let mut info = default_transfer_call().get_dispatch_info(); - info.extension_weight = xt.extension_weight(); + info.extension_weight = xt.0.extension_weight(); let weight = info.total_weight(); let weight_fee = IdentityFee::::weight_to_fee(&weight); diff --git a/substrate/bin/node/cli/tests/submit_transaction.rs b/substrate/bin/node/cli/tests/submit_transaction.rs index c603af5c0bb4..3672432ae342 100644 --- a/substrate/bin/node/cli/tests/submit_transaction.rs +++ b/substrate/bin/node/cli/tests/submit_transaction.rs @@ -23,6 +23,7 @@ use sp_application_crypto::AppCrypto; use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt}; use sp_keyring::sr25519::Keyring::Alice; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; +use sp_runtime::generic; pub mod common; use self::common::*; @@ -44,7 +45,7 @@ fn should_submit_unsigned_transaction() { }; let call = pallet_im_online::Call::heartbeat { heartbeat: heartbeat_data, signature }; - let xt = UncheckedExtrinsic::new_bare(call.into()); + let xt = generic::UncheckedExtrinsic::new_bare(call.into()).into(); SubmitTransaction::>::submit_transaction(xt) .unwrap(); From 05688e2cd10f251ae6af1848949ac25a4eeee525 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Mon, 21 Oct 2024 09:47:28 +0200 Subject: [PATCH 136/174] Restore files from previous PR --- Cargo.toml | 12 +- prdoc/pr_5953.prdoc | 11 + .../revive/fixtures/contracts/rpc_demo.rs | 36 + substrate/frame/revive/rpc/Cargo.toml | 76 ++ substrate/frame/revive/rpc/examples/README.md | 84 ++ .../frame/revive/rpc/examples/js/.gitignore | 24 + .../frame/revive/rpc/examples/js/bun.lockb | Bin 0 -> 23039 bytes .../frame/revive/rpc/examples/js/index.html | 29 + .../frame/revive/rpc/examples/js/package.json | 18 + .../frame/revive/rpc/examples/js/src/main.ts | 141 ++++ .../revive/rpc/examples/js/src/script.ts | 49 ++ .../revive/rpc/examples/js/tsconfig.json | 23 + .../revive/rpc/examples/rpc_demo.polkavm | 1 + .../frame/revive/rpc/examples/rust/deploy.rs | 65 ++ .../revive/rpc/examples/rust/extrinsic.rs | 46 ++ .../rpc/examples/rust/rpc-playground.rs | 41 + .../revive/rpc/examples/rust/transfer.rs | 55 ++ substrate/frame/revive/rpc/kitchensink.scale | Bin 0 -> 651459 bytes substrate/frame/revive/rpc/src/client.rs | 782 ++++++++++++++++++ substrate/frame/revive/rpc/src/example.rs | 96 +++ substrate/frame/revive/rpc/src/lib.rs | 375 +++++++++ substrate/frame/revive/rpc/src/main.rs | 151 ++++ .../frame/revive/rpc/src/rpc_methods_gen.rs | 160 ++++ .../frame/revive/rpc/src/subxt_client.rs | 69 ++ umbrella/Cargo.toml | 19 +- umbrella/src/lib.rs | 8 +- 26 files changed, 2347 insertions(+), 24 deletions(-) create mode 100644 prdoc/pr_5953.prdoc create mode 100644 substrate/frame/revive/fixtures/contracts/rpc_demo.rs create mode 100644 substrate/frame/revive/rpc/Cargo.toml create mode 100644 substrate/frame/revive/rpc/examples/README.md create mode 100644 substrate/frame/revive/rpc/examples/js/.gitignore create mode 100755 substrate/frame/revive/rpc/examples/js/bun.lockb create mode 100644 substrate/frame/revive/rpc/examples/js/index.html create mode 100644 substrate/frame/revive/rpc/examples/js/package.json create mode 100644 substrate/frame/revive/rpc/examples/js/src/main.ts create mode 100644 substrate/frame/revive/rpc/examples/js/src/script.ts create mode 100644 substrate/frame/revive/rpc/examples/js/tsconfig.json create mode 120000 substrate/frame/revive/rpc/examples/rpc_demo.polkavm create mode 100644 substrate/frame/revive/rpc/examples/rust/deploy.rs create mode 100644 substrate/frame/revive/rpc/examples/rust/extrinsic.rs create mode 100644 substrate/frame/revive/rpc/examples/rust/rpc-playground.rs create mode 100644 substrate/frame/revive/rpc/examples/rust/transfer.rs create mode 100644 substrate/frame/revive/rpc/kitchensink.scale create mode 100644 substrate/frame/revive/rpc/src/client.rs create mode 100644 substrate/frame/revive/rpc/src/example.rs create mode 100644 substrate/frame/revive/rpc/src/lib.rs create mode 100644 substrate/frame/revive/rpc/src/main.rs create mode 100644 substrate/frame/revive/rpc/src/rpc_methods_gen.rs create mode 100644 substrate/frame/revive/rpc/src/subxt_client.rs diff --git a/Cargo.toml b/Cargo.toml index 77586ae9d8e3..d265f1a586f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -347,7 +347,6 @@ members = [ "substrate/frame/election-provider-support/solution-type/fuzzer", "substrate/frame/elections-phragmen", "substrate/frame/examples", - "substrate/frame/examples/authorization-tx-extension", "substrate/frame/examples/basic", "substrate/frame/examples/default-config", "substrate/frame/examples/dev-mode", @@ -400,6 +399,7 @@ members = [ "substrate/frame/revive/fixtures", "substrate/frame/revive/mock-network", "substrate/frame/revive/proc-macro", + "substrate/frame/revive/rpc", "substrate/frame/revive/uapi", "substrate/frame/root-offences", "substrate/frame/root-testing", @@ -443,7 +443,6 @@ members = [ "substrate/frame/tx-pause", "substrate/frame/uniques", "substrate/frame/utility", - "substrate/frame/verify-signature", "substrate/frame/vesting", "substrate/frame/whitelist", "substrate/primitives/api", @@ -589,7 +588,6 @@ alloy-primitives = { version = "0.4.2", default-features = false } alloy-sol-types = { version = "0.4.2", default-features = false } always-assert = { version = "0.1" } anyhow = { version = "1.0.81", default-features = false } -approx = { version = "0.5.1" } aquamarine = { version = "0.5.0" } arbitrary = { version = "1.3.2" } ark-bls12-377 = { version = "0.4.0", default-features = false } @@ -683,7 +681,6 @@ color-print = { version = "0.3.4" } colored = { version = "2.0.4" } comfy-table = { version = "7.1.0", default-features = false } console = { version = "0.15.8" } -const-hex = { version = "1.10.0", default-features = false } contracts-rococo-runtime = { path = "cumulus/parachains/runtimes/contracts/contracts-rococo" } coretime-rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo" } coretime-rococo-runtime = { path = "cumulus/parachains/runtimes/coretime/coretime-rococo" } @@ -918,7 +915,6 @@ pallet-dev-mode = { path = "substrate/frame/examples/dev-mode", default-features pallet-election-provider-multi-phase = { path = "substrate/frame/election-provider-multi-phase", default-features = false } pallet-election-provider-support-benchmarking = { path = "substrate/frame/election-provider-support/benchmarking", default-features = false } pallet-elections-phragmen = { path = "substrate/frame/elections-phragmen", default-features = false } -pallet-example-authorization-tx-extension = { path = "substrate/frame/examples/authorization-tx-extension", default-features = false } pallet-example-basic = { path = "substrate/frame/examples/basic", default-features = false } pallet-example-frame-crate = { path = "substrate/frame/examples/frame-crate", default-features = false } pallet-example-kitchensink = { path = "substrate/frame/examples/kitchensink", default-features = false } @@ -963,6 +959,7 @@ pallet-recovery = { path = "substrate/frame/recovery", default-features = false pallet-referenda = { path = "substrate/frame/referenda", default-features = false } pallet-remark = { default-features = false, path = "substrate/frame/remark" } pallet-revive = { path = "substrate/frame/revive", default-features = false } +pallet-revive-eth-rpc = { path = "substrate/frame/revive/rpc", default-features = false } pallet-revive-fixtures = { path = "substrate/frame/revive/fixtures", default-features = false } pallet-revive-mock-network = { default-features = false, path = "substrate/frame/revive/mock-network" } pallet-revive-proc-macro = { path = "substrate/frame/revive/proc-macro", default-features = false } @@ -995,7 +992,6 @@ pallet-treasury = { path = "substrate/frame/treasury", default-features = false pallet-tx-pause = { default-features = false, path = "substrate/frame/tx-pause" } pallet-uniques = { path = "substrate/frame/uniques", default-features = false } pallet-utility = { path = "substrate/frame/utility", default-features = false } -pallet-verify-signature = { path = "substrate/frame/verify-signature", default-features = false } pallet-vesting = { path = "substrate/frame/vesting", default-features = false } pallet-whitelist = { path = "substrate/frame/whitelist", default-features = false } pallet-xcm = { path = "polkadot/xcm/pallet-xcm", default-features = false } @@ -1021,7 +1017,7 @@ people-rococo-runtime = { path = "cumulus/parachains/runtimes/people/people-roco people-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend" } people-westend-runtime = { path = "cumulus/parachains/runtimes/people/people-westend" } pin-project = { version = "1.1.3" } -platforms = { version = "3.4" } +platforms = { version = "3.0" } polkadot-approval-distribution = { path = "polkadot/node/network/approval-distribution", default-features = false } polkadot-availability-bitfield-distribution = { path = "polkadot/node/network/bitfield-distribution", default-features = false } polkadot-availability-distribution = { path = "polkadot/node/network/availability-distribution", default-features = false } @@ -1326,7 +1322,7 @@ tiny-keccak = { version = "2.0.2" } tokio = { version = "1.40.0", default-features = false } tokio-retry = { version = "0.3.0" } tokio-stream = { version = "0.1.14" } -tokio-test = { version = "0.4.4" } +tokio-test = { version = "0.4.2" } tokio-tungstenite = { version = "0.20.1" } tokio-util = { version = "0.7.8" } toml = { version = "0.8.12" } diff --git a/prdoc/pr_5953.prdoc b/prdoc/pr_5953.prdoc new file mode 100644 index 000000000000..498675df6520 --- /dev/null +++ b/prdoc/pr_5953.prdoc @@ -0,0 +1,11 @@ +title: "[pallet-revive] Ethereum JSON-RPC" + +doc: + - audience: Runtime Dev + description: | + Add a new Ethereum JSON-RPC server that can be used a substrate chain configured with pallet-revive +crates: + - name: pallet-revive-eth-rpc + bump: patch + - name: pallet-revive-fixtures + bump: patch diff --git a/substrate/frame/revive/fixtures/contracts/rpc_demo.rs b/substrate/frame/revive/fixtures/contracts/rpc_demo.rs new file mode 100644 index 000000000000..0d75c6eb8df6 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/rpc_demo.rs @@ -0,0 +1,36 @@ +// 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. + +#![no_std] +#![no_main] + +use common::input; +use uapi::{HostFn, HostFnImpl as api}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() { + input!(128, data: [u8],); + api::deposit_event(&[], data); +} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + input!(128, data: [u8],); + api::deposit_event(&[], data); +} diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml new file mode 100644 index 000000000000..14ac93a5e032 --- /dev/null +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -0,0 +1,76 @@ +[package] +name = "pallet-revive-eth-rpc" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true +description = "An Ethereum JSON-RPC server for pallet-revive." + +[[bin]] +name = "eth-rpc" +path = "src/main.rs" + +[[example]] +name = "deploy" +path = "examples/rust/deploy.rs" +required-features = ["example"] + +[[example]] +name = "transfer" +path = "examples/rust/transfer.rs" +required-features = ["example"] + +[[example]] +name = "rpc-playground" +path = "examples/rust/rpc-playground.rs" +required-features = ["example"] + +[[example]] +name = "extrinsic" +path = "examples/rust/extrinsic.rs" +required-features = ["example"] + +[dependencies] +clap = { workspace = true, features = ["derive"] } +anyhow = { workspace = true } +futures = { workspace = true, features = ["thread-pool"] } +jsonrpsee = { workspace = true, features = ["full"] } +serde_json = { workspace = true } +thiserror = { workspace = true } +sp-crypto-hashing = { workspace = true } +subxt = { workspace = true, default-features = true, features = [ + "unstable-reconnecting-rpc-client", +] } +tokio = { workspace = true, features = ["full"] } +codec = { workspace = true, features = ["derive"] } +log.workspace = true +tracing-subscriber.workspace = true +pallet-revive = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-weights = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } + +tower.workspace = true +tower-http = { workspace = true, features = ["full"] } +hyper.workspace = true + +rlp = { workspace = true, optional = true } +subxt-signer = { workspace = true, optional = true, features = [ + "unstable-eth", +] } +hex = { workspace = true, optional = true } +hex-literal = { workspace = true, optional = true } +scale-info = { workspace = true } +secp256k1 = { workspace = true, optional = true, features = ["recovery"] } +env_logger = { workspace = true } + +[features] +dev = [] +example = ["hex", "hex-literal", "rlp", "secp256k1", "subxt-signer"] + +[dev-dependencies] +hex-literal = { workspace = true } +pallet-revive-fixtures = { workspace = true } diff --git a/substrate/frame/revive/rpc/examples/README.md b/substrate/frame/revive/rpc/examples/README.md new file mode 100644 index 000000000000..ebb17fabb724 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/README.md @@ -0,0 +1,84 @@ +## Pre-requisites + + Build `pallet-revive-fixture`, as we need some compiled contracts to exercise the RPC server. + +```bash +cargo build -p pallet-revive-fixtures --features riscv +``` + +## Start the node + +Start the kitchensink node: + +```bash +RUST_LOG="error,evm=debug,sc_rpc_server=info,runtime::revive=debug" cargo run --bin substrate-node -- --dev +``` + +## Start the RPC server + +This command starts the Ethereum JSON-RPC server, which runs on `localhost:9090` by default: + +```bash +RUST_LOG="info,eth-rpc=debug" cargo run -p pallet-revive-eth-rpc --features dev +``` + +## Rust examples + +Run one of the examples from the `examples` directory to send a transaction to the node: + +```bash +RUST_LOG="info,eth-rpc=debug" cargo run -p pallet-revive-eth-rpc --features example --example deploy +``` + +## JS examples + +Interact with the node using MetaMask & Ether.js, by starting the example web app: + +```bash + +cd substrate/frame/revive/rpc/examples/js +bun install +bun run dev +``` + +Alternatively, you can run the example script directly: + +```bash +cd substrate/frame/revive/rpc/examples/js +bun src/script.ts +``` + +### Configure MetaMask + +You can use the following instructions to setup [MetaMask] with the local chain. + +> **Note**: When you interact with MetaMask and restart the chain, you need to clear the activity tab (Settings > +Advanced > Clear activity tab data), and in some cases lock/unlock MetaMask to reset the nonce. +See [this guide][reset-account] for more info on how to reset the account activity. + +#### Add a new network + +To interact with the local chain, add a new network in [MetaMask]. +See [this guide][add-network] for more info on how to add a custom network. + +Make sure the node and the RPC server are started, and use the following settings to configure the network +(MetaMask > Networks > Add a network manually): + +- Network name: KitchenSink +- RPC URL: +- Chain ID: 420420420 +- Currency Symbol: `DEV` + +#### Import Dev account + +You will need to import the following account, endowed with some balance at genesis, to interact with the chain. +See [this guide][import-account] for more info on how to import an account. + +- Account: `0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac` +- Private Key: `5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133` + +[MetaMask]: https://metamask.io +[add-network]: https://support.metamask.io/networks-and-sidechains/managing-networks/how-to-add-a-custom-network-rpc/#adding-a-network-manually +[import-account]: https://support.metamask.io/managing-my-wallet/accounts-and-addresses/how-to-import-an-account/ +[reset-account]: https://support.metamask.io/managing-my-wallet/resetting-deleting-and-restoring/how-to-clear-your-account-activity-reset-account + diff --git a/substrate/frame/revive/rpc/examples/js/.gitignore b/substrate/frame/revive/rpc/examples/js/.gitignore new file mode 100644 index 000000000000..a547bf36d8d1 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/substrate/frame/revive/rpc/examples/js/bun.lockb b/substrate/frame/revive/rpc/examples/js/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..8bf47d7eb8b82734467165627413c33adede6fd6 GIT binary patch literal 23039 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