Skip to content

Commit

Permalink
Add unit tests for encoded transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
Lohann committed Nov 6, 2023
1 parent 38fbb6a commit 659ce27
Show file tree
Hide file tree
Showing 21 changed files with 1,277 additions and 407 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

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

4 changes: 1 addition & 3 deletions chains/ethereum/backend/src/jsonrpsee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ use ::core::{
pin::Pin,
};

use crate::{
AccessListWithGasUsed, AtBlock, EthereumPubSub, EthereumRpc, ExitReason, CallRequest,
};
use crate::{AccessListWithGasUsed, AtBlock, CallRequest, EthereumPubSub, EthereumRpc, ExitReason};
use alloc::boxed::Box;
pub use jsonrpsee_core as core;
use jsonrpsee_core::{
Expand Down
2 changes: 1 addition & 1 deletion chains/ethereum/backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ extern crate alloc;
use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
use futures_core::future::BoxFuture;
use rosetta_ethereum_primitives::{
Address, Block, BlockIdentifier, Bytes, EIP1186ProofResponse, Log, CallRequest,
Address, Block, BlockIdentifier, Bytes, CallRequest, EIP1186ProofResponse, Log,
TransactionReceipt, TxHash, H256, U256, U64,
};

Expand Down
6 changes: 3 additions & 3 deletions chains/ethereum/executor/src/rust_evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
};
use revm::{evm_inner, inspectors::NoOpInspector};
use rosetta_ethereum_backend::{AtBlock, EthereumRpc, ExitReason};
use rosetta_ethereum_primitives::{Address, Block, BlockIdentifier, Bytes, TransactionCall, H256};
use rosetta_ethereum_primitives::{Address, Block, BlockIdentifier, Bytes, CallRequest, H256};

pub type EvmError = revm::primitives::EVMError<StateError>;

Expand Down Expand Up @@ -139,7 +139,7 @@ where
#[allow(clippy::missing_errors_doc)]
pub fn execute(
&mut self,
tx: &TransactionCall,
tx: &CallRequest,
block: &Block<H256>,
) -> Result<ExecutionResult, EvmError> {
let mut env = revm::primitives::Env::default();
Expand Down Expand Up @@ -198,7 +198,7 @@ where
#[allow(clippy::missing_errors_doc)]
pub async fn call(
&mut self,
tx: &TransactionCall,
tx: &CallRequest,
at: AtBlock,
) -> Result<ExecutionResult, Error<RPC::Error>> {
let prefetch = self.db.prefetch_state(tx, at).await.map_err(Error::PrefetchFailed)?;
Expand Down
4 changes: 1 addition & 3 deletions chains/ethereum/executor/src/sputnik_evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ use crate::{
},
};
use rosetta_ethereum_backend::{AtBlock, EthereumRpc, ExitReason};
use rosetta_ethereum_primitives::{
Address, Block, BlockIdentifier, CallRequest, H256, U256, U64,
};
use rosetta_ethereum_primitives::{Address, Block, BlockIdentifier, CallRequest, H256, U256, U64};

#[derive(Debug)]
#[cfg_attr(feature = "std", derive(thiserror::Error))]
Expand Down
2 changes: 1 addition & 1 deletion chains/ethereum/executor/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloc::{borrow::ToOwned, collections::BTreeMap, vec::Vec};
use rosetta_ethereum_backend::{AccessListItem, AccessListWithGasUsed, AtBlock, EthereumRpc};
use rosetta_ethereum_primitives::{
Address, Block, BlockIdentifier, Bytes, EIP1186ProofResponse, CallRequest, H256,
Address, Block, BlockIdentifier, Bytes, CallRequest, EIP1186ProofResponse, H256,
};

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
2 changes: 2 additions & 0 deletions chains/ethereum/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const-hex = { version = "1.9", default-features = false, features = ["alloc"] }
ethbloom = { version = "0.13", default-features = false }
primitive-types = { version = "0.12", default-features = false, features = ["byteorder", "rustc-hex", "num-traits"] }
uint = { version = "0.9", default-features = false }
void = { version = "1.0", default-features = false }

fixed-hash = { version = "0.8", default-features = false, features = ["byteorder", "rustc-hex"] }
impl-codec-macro = { package = "impl-codec", version = "0.6", default-features = false, optional = true }
Expand Down Expand Up @@ -62,6 +63,7 @@ std = [
"ethbloom/std",
"primitive-types/std",
"uint/std",
"void/std",
"fixed-hash/std",
"parity-scale-codec/std",
"scale-info/std",
Expand Down
87 changes: 80 additions & 7 deletions chains/ethereum/primitives/src/call_request.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#![allow(clippy::missing_errors_doc)]
use crate::{
bytes::Bytes,
eth_hash::{Address, H256},
eth_hash::Address,
eth_uint::{U256, U64},
transactions::{
access_list::AccessList, eip1559::Eip1559Transaction, eip2930::Eip2930Transaction,
legacy::LegacyTransaction, typed_transaction::TypedTransaction,
},
};
use alloc::vec::Vec;

/// Parameters for sending a transaction
#[derive(Clone, Default, PartialEq, Eq, Debug)]
Expand Down Expand Up @@ -47,7 +50,7 @@ pub struct CallRequest {

/// The nonce of the transaction. If set to `None`, no checks are performed.
#[cfg_attr(feature = "with-serde", serde(skip_serializing_if = "Option::is_none"))]
pub nonce: Option<U256>,
pub nonce: Option<U64>,

/// The chain ID of the transaction. If set to `None`, no checks are performed.
///
Expand All @@ -73,11 +76,11 @@ pub struct CallRequest {
#[cfg_attr(
feature = "with-serde",
serde(
skip_serializing_if = "Vec::is_empty",
skip_serializing_if = "AccessList::is_empty",
deserialize_with = "deserialize_null_default"
)
)]
pub access_list: Vec<(Address, Vec<H256>)>,
pub access_list: AccessList,

/// The max fee per gas.
///
Expand All @@ -88,8 +91,11 @@ pub struct CallRequest {
pub max_fee_per_gas: Option<U256>,

/// EIP-2718 type
#[cfg_attr(feature = "with-serde", serde(rename = "type", skip_serializing_if = "Option::is_none"))]
pub transaction_type: Option<U64>,
#[cfg_attr(
feature = "with-serde",
serde(rename = "type", skip_serializing_if = "Option::is_none")
)]
pub transaction_type: Option<U64>,
}

#[cfg(feature = "with-serde")]
Expand All @@ -101,3 +107,70 @@ where
let opt = <Option<T> as serde::Deserialize<'de>>::deserialize(deserializer)?;
Ok(opt.unwrap_or_default())
}

impl From<LegacyTransaction> for CallRequest {
fn from(tx: LegacyTransaction) -> Self {
Self {
from: None,
to: tx.to,
gas_limit: Some(tx.gas_limit),
gas_price: Some(tx.gas_price),
value: Some(tx.value),
data: Some(tx.data.clone()),
nonce: Some(tx.nonce),
chain_id: tx.chain_id,
max_priority_fee_per_gas: None,
access_list: AccessList::default(),
max_fee_per_gas: None,
transaction_type: Some(U64([0x00])),
}
}
}

impl From<Eip2930Transaction> for CallRequest {
fn from(tx: Eip2930Transaction) -> Self {
Self {
from: None,
to: tx.to,
gas_limit: Some(tx.gas_limit),
gas_price: Some(tx.gas_price),
value: Some(tx.value),
data: Some(tx.data.clone()),
nonce: Some(tx.nonce),
chain_id: Some(tx.chain_id),
max_priority_fee_per_gas: None,
access_list: tx.access_list,
max_fee_per_gas: None,
transaction_type: Some(U64([0x01])),
}
}
}

impl From<Eip1559Transaction> for CallRequest {
fn from(tx: Eip1559Transaction) -> Self {
Self {
from: None,
to: tx.to,
gas_limit: Some(tx.gas_limit),
gas_price: None,
max_priority_fee_per_gas: Some(tx.max_priority_fee_per_gas),
max_fee_per_gas: Some(tx.max_fee_per_gas),
value: Some(tx.value),
data: Some(tx.data.clone()),
nonce: Some(tx.nonce),
chain_id: Some(tx.chain_id),
access_list: tx.access_list,
transaction_type: Some(U64([0x02])),
}
}
}

impl From<TypedTransaction> for CallRequest {
fn from(tx: TypedTransaction) -> Self {
match tx {
TypedTransaction::Legacy(tx) => tx.into(),
TypedTransaction::Eip2930(tx) => tx.into(),
TypedTransaction::Eip1559(tx) => tx.into(),
}
}
}
8 changes: 6 additions & 2 deletions chains/ethereum/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,28 @@ extern crate alloc;

mod block;
mod bytes;
mod call_request;
mod eth_hash;
mod eth_uint;
mod log;
#[cfg(feature = "with-rlp")]
pub mod rlp_utils;
mod storage_proof;
mod call_request;
pub mod transactions;
mod tx_receipt;

pub use block::Block;
pub use bytes::Bytes;
pub use call_request::CallRequest;
pub use eth_hash::{Address, Public, Secret, Signature, TxHash, H128, H256, H384, H512, H520};
pub use eth_uint::{U128, U256, U512, U64};
pub use ethbloom::{Bloom, BloomRef, Input as BloomInput};
pub use log::Log;
pub use storage_proof::{EIP1186ProofResponse, StorageProof};
pub use call_request::CallRequest;
pub use transactions::{
access_list::{AccessList, AccessListItem, AccessListWithGasUsed},
typed_transaction::TypedTransaction,
};
pub use tx_receipt::TransactionReceipt;

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
Expand Down
43 changes: 43 additions & 0 deletions chains/ethereum/primitives/src/rlp_utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::transactions::signature::Signature;
use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};

pub trait RlpStreamExt {
Expand Down Expand Up @@ -47,3 +48,45 @@ impl RlpExt for Rlp<'_> {
Ok(to)
}
}

#[cfg(feature = "with-rlp")]
pub trait RlpEncodableTransaction {
fn rlp_append(&self, s: &mut rlp::RlpStream, signature: Option<&Signature>);

fn rlp_unsigned(&self) -> bytes::Bytes {
let mut stream = rlp::RlpStream::new();
self.rlp_append(&mut stream, None);
stream.out().freeze()
}

fn rlp_signed(&self, signature: &Signature) -> bytes::Bytes {
let mut stream = rlp::RlpStream::new();
self.rlp_append(&mut stream, Some(signature));
stream.out().freeze()
}
}

#[cfg(feature = "with-rlp")]
pub trait RlpDecodableTransaction: Sized {
/// Decode a raw transaction, returning the decoded transaction and the signature if present.
/// # Errors
/// Returns an error if the transaction or signature is invalid.
fn rlp_decode(
rlp: &Rlp,
decode_signature: bool,
) -> Result<(Self, Option<Signature>), rlp::DecoderError>;

/// Decode a raw transaction without signature
/// # Errors
/// Returns an error if the transaction is invalid.
fn rlp_decode_unsigned(rlp: &Rlp) -> Result<Self, DecoderError> {
Self::rlp_decode(rlp, false).map(|tx| tx.0)
}

/// Decode a raw transaction with signature
/// # Errors
/// Returns an error if the transaction or signature is invalid.
fn rlp_decode_signed(rlp: &Rlp) -> Result<(Self, Option<Signature>), rlp::DecoderError> {
Self::rlp_decode(rlp, true)
}
}
Loading

0 comments on commit 659ce27

Please sign in to comment.