From 4ca52e3ccede34d6ef22b821ca92e73871a61600 Mon Sep 17 00:00:00 2001 From: Vid Kersic <vid.kersic@yahoo.com> Date: Thu, 1 Dec 2022 10:40:44 +0100 Subject: [PATCH] User operation pack and hash, remove packages bytes and ethereum_types (#22) --- Cargo.lock | 3 +- Cargo.toml | 3 +- Makefile | 3 + src/rpc/eth.rs | 2 +- src/rpc/eth_api.rs | 2 +- src/types/user_operation.rs | 169 +++++++++++++++++++++++++++++++++++- src/uopool/mod.rs | 4 +- 7 files changed, 174 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 508d093b..350c4496 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,14 +18,13 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "bytes", "clap", "dirs", "educe", "ethereum-interfaces", - "ethereum-types", "ethers", "expanded-pathbuf", + "hex", "jsonrpsee", "parking_lot 0.12.1", "prost", diff --git a/Cargo.toml b/Cargo.toml index c599c85d..9812ac37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,14 +9,13 @@ default-run = "bundler" [dependencies] anyhow = "1" async-trait = "0.1" -bytes = { version = "1", features = ["serde"] } clap = { version = "4", features = ["derive"] } dirs = "4.0" educe = { version = "0.4", features = ["Debug", "Default"] } ethereum-interfaces = { git = "https://github.com/ledgerwatch/interfaces" } -ethereum-types = { version = "0.14", features = ["codec"] } ethers = "1.0.0" expanded-pathbuf = "0.1" +hex = { version = "0.4.3", default-features = false, features = ["std"] } jsonrpsee = { version = "0.16", features = ["server", "macros"] } parking_lot = "0.12" prost = "0.11" diff --git a/Makefile b/Makefile index 7661010e..8c8f0f4a 100644 --- a/Makefile +++ b/Makefile @@ -13,5 +13,8 @@ run-create-wallet: cargo-fmt: cargo fmt --all +cargo-test: + cargo test + fetch-thirdparty: git submodule update --init \ No newline at end of file diff --git a/src/rpc/eth.rs b/src/rpc/eth.rs index 9106216e..50598c4a 100644 --- a/src/rpc/eth.rs +++ b/src/rpc/eth.rs @@ -1,6 +1,6 @@ use crate::{rpc::eth_api::EthApiServer, types::user_operation::UserOperation}; use async_trait::async_trait; -use ethereum_types::{Address, U64}; +use ethers::types::{Address, U64}; use jsonrpsee::{core::RpcResult, tracing::info}; pub struct EthApiServerImpl { diff --git a/src/rpc/eth_api.rs b/src/rpc/eth_api.rs index 77511835..9e30550a 100644 --- a/src/rpc/eth_api.rs +++ b/src/rpc/eth_api.rs @@ -1,4 +1,4 @@ -use ethereum_types::{Address, U64}; +use ethers::types::{Address, U64}; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use crate::types::user_operation::UserOperation; diff --git a/src/types/user_operation.rs b/src/types/user_operation.rs index 1d5bf96c..c0101c61 100644 --- a/src/types/user_operation.rs +++ b/src/types/user_operation.rs @@ -1,10 +1,13 @@ -use bytes::Bytes; -use ethereum_types::{Address, H512, U256}; +use ethers::abi::AbiEncode; +use ethers::prelude::{EthAbiCodec, EthAbiType}; +use ethers::types::{Address, Bytes, H256, U256}; +use ethers::utils::keccak256; use serde::{Deserialize, Serialize}; +use std::str::FromStr; -pub type UoId = H512; +pub type UserOperationHash = H256; -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, EthAbiCodec, EthAbiType)] #[serde(rename_all = "camelCase")] pub struct UserOperation { pub sender: Address, @@ -19,3 +22,161 @@ pub struct UserOperation { pub paymaster_and_data: Bytes, pub signature: Bytes, } + +impl UserOperation { + pub fn pack(&self) -> Vec<u8> { + self.clone().encode_hex().into_bytes() + } + + pub fn pack_for_signature(&self) -> Vec<u8> { + let mut encoded = String::from("0x"); + let packed = hex::encode( + UserOperation { + signature: Bytes::from_str("0x").unwrap(), + ..self.clone() + } + .encode(), + ); + encoded.push_str(&packed[..packed.len() - 64]); + encoded.into_bytes() + } + + pub fn hash(&self, entry_point_address: Address, chain_id: U256) -> UserOperationHash { + H256::from_slice( + keccak256( + [ + keccak256(hex::decode(&self.pack_for_signature()[2..]).unwrap()).to_vec(), + entry_point_address.encode(), + chain_id.encode(), + ] + .concat(), + ) + .as_slice(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn user_operation_pack() { + let user_operations = vec![ + UserOperation { + sender: Address::zero(), + nonce: U256::zero(), + init_code: Bytes::default(), + call_data: Bytes::default(), + call_gas_limit: U256::zero(), + verification_gas_limit: U256::from(100000), + pre_verification_gas: U256::from(21000), + max_fee_per_gas: U256::zero(), + max_priority_fee_per_gas: U256::from(1e9 as u64), + paymaster_and_data: Bytes::default(), + signature: Bytes::default(), + }, + UserOperation { + sender: "0x663F3ad617193148711d28f5334eE4Ed07016602".parse().unwrap(), + nonce: U256::zero(), + init_code: Bytes::default(), + call_data: Bytes::default(), + call_gas_limit: U256::from(200000), + verification_gas_limit: U256::from(100000), + pre_verification_gas: U256::from(21000), + max_fee_per_gas: U256::from(3000000000 as u64), + max_priority_fee_per_gas: U256::from(1000000000), + paymaster_and_data: Bytes::default(), + signature: Bytes::from_str("0x7cb39607585dee8e297d0d7a669ad8c5e43975220b6773c10a138deadbc8ec864981de4b9b3c735288a217115fb33f8326a61ddabc60a534e3b5536515c70f931c").unwrap(), + }, + ]; + assert_eq!(user_operations[0].pack(), String::from("0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000052080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into_bytes()); + assert_eq!(user_operations[1].pack(), String::from("0x000000000000000000000000663f3ad617193148711d28f5334ee4ed070166020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000000000000000000186a0000000000000000000000000000000000000000000000000000000000000520800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417cb39607585dee8e297d0d7a669ad8c5e43975220b6773c10a138deadbc8ec864981de4b9b3c735288a217115fb33f8326a61ddabc60a534e3b5536515c70f931c00000000000000000000000000000000000000000000000000000000000000").into_bytes()); + } + + #[test] + fn user_operation_pack_for_signature() { + let user_operations = vec![ + UserOperation { + sender: Address::zero(), + nonce: U256::zero(), + init_code: Bytes::default(), + call_data: Bytes::default(), + call_gas_limit: U256::zero(), + verification_gas_limit: U256::from(100000), + pre_verification_gas: U256::from(21000), + max_fee_per_gas: U256::zero(), + max_priority_fee_per_gas: U256::from(1e9 as u64), + paymaster_and_data: Bytes::default(), + signature: Bytes::default(), + }, + UserOperation { + sender: "0x663F3ad617193148711d28f5334eE4Ed07016602".parse().unwrap(), + nonce: U256::zero(), + init_code: Bytes::default(), + call_data: Bytes::default(), + call_gas_limit: U256::from(200000), + verification_gas_limit: U256::from(100000), + pre_verification_gas: U256::from(21000), + max_fee_per_gas: U256::from(3000000000 as u64), + max_priority_fee_per_gas: U256::from(1000000000), + paymaster_and_data: Bytes::default(), + signature: Bytes::from_str("0x7cb39607585dee8e297d0d7a669ad8c5e43975220b6773c10a138deadbc8ec864981de4b9b3c735288a217115fb33f8326a61ddabc60a534e3b5536515c70f931c").unwrap(), + }, + ]; + assert_eq!(user_operations[0].pack_for_signature(), String::from("0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000052080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into_bytes()); + assert_eq!(user_operations[1].pack_for_signature(), String::from("0x000000000000000000000000663f3ad617193148711d28f5334ee4ed070166020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000000000000000000186a0000000000000000000000000000000000000000000000000000000000000520800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into_bytes()); + } + + #[test] + fn user_operation_hash() { + let user_operations = vec![ + UserOperation { + sender: Address::zero(), + nonce: U256::zero(), + init_code: Bytes::default(), + call_data: Bytes::default(), + call_gas_limit: U256::zero(), + verification_gas_limit: U256::from(100000), + pre_verification_gas: U256::from(21000), + max_fee_per_gas: U256::zero(), + max_priority_fee_per_gas: U256::from(1e9 as u64), + paymaster_and_data: Bytes::default(), + signature: Bytes::default(), + }, + UserOperation { + sender: "0x663F3ad617193148711d28f5334eE4Ed07016602".parse().unwrap(), + nonce: U256::zero(), + init_code: Bytes::default(), + call_data: Bytes::default(), + call_gas_limit: U256::from(200000), + verification_gas_limit: U256::from(100000), + pre_verification_gas: U256::from(21000), + max_fee_per_gas: U256::from(3000000000 as u64), + max_priority_fee_per_gas: U256::from(1000000000), + paymaster_and_data: Bytes::default(), + signature: Bytes::from_str("0x7cb39607585dee8e297d0d7a669ad8c5e43975220b6773c10a138deadbc8ec864981de4b9b3c735288a217115fb33f8326a61ddabc60a534e3b5536515c70f931c").unwrap(), + }, + ]; + assert_eq!( + user_operations[0].hash( + "0x2DF1592238420ecFe7f2431360e224707e77fA0E" + .parse() + .unwrap(), + U256::from(1) + ), + H256::from_str("0x42e145138104ec4124367ea3f7994833071b2011927290f6844d593e05011279") + .unwrap() + ); + assert_eq!( + user_operations[1].hash( + "0x2DF1592238420ecFe7f2431360e224707e77fA0E" + .parse() + .unwrap(), + U256::from(1) + ), + H256::from_str("0x583c8fcba470fd9da514f9482ccd31c299b0161a36b365aab353a6bfebaa0bb2") + .unwrap() + ); + } +} diff --git a/src/uopool/mod.rs b/src/uopool/mod.rs index 013ea288..f0131168 100644 --- a/src/uopool/mod.rs +++ b/src/uopool/mod.rs @@ -1,5 +1,5 @@ use crate::{ - types::user_operation::{UoId, UserOperation}, + types::user_operation::{UserOperation, UserOperationHash}, uopool::{server::server::uo_pool_server::UoPoolServer, services::UoPoolService}, }; use anyhow::Result; @@ -15,7 +15,7 @@ pub mod services; #[derive(Educe)] #[educe(Debug)] pub struct UserOperationPool { - pub pool: Arc<RwLock<HashMap<UoId, UserOperation>>>, + pub pool: Arc<RwLock<HashMap<UserOperationHash, UserOperation>>>, } impl UserOperationPool {