Skip to content

Commit

Permalink
fix: update the Transaction RPC type and fix response of txpool_conte…
Browse files Browse the repository at this point in the history
…nt RPC (polkadot-evm#1234)

* fix: update the Transaction type and fix response of txpool_content RPC

- fix the response of txpool_content RPC
- update the `Transaction` response type of some RPC response

* remove Option wrapper of transaction type
  • Loading branch information
koushiro committed Nov 2, 2023
1 parent 5cf30ca commit 1d523e0
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 239 deletions.
11 changes: 7 additions & 4 deletions client/rpc-core/src/txpool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ pub trait TxPoolApi {
/// associative arrays, in which each entry maps an origin-address to a batch of scheduled
/// transactions. These batches themselves are maps associating nonces with actual transactions.
///
/// For details, see [txpool_content](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool#txpool-content)
/// For details, see [txpool_content (geth)](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool#txpool-content)
/// or [txpool_content (nethermind)](https://docs.nethermind.io/nethermind/ethereum-client/json-rpc/txpool#txpool_content).
#[method(name = "txpool_content")]
fn content(&self) -> RpcResult<TxPoolResult<TransactionMap<TxPoolTransaction>>>;
fn content(&self) -> RpcResult<TxPoolResult<TransactionMap<Transaction>>>;

/// The inspect inspection property can be queried to list a textual summary of all the
/// transactions currently pending for inclusion in the next block(s), as well as the ones that
Expand All @@ -48,7 +49,8 @@ pub trait TxPoolApi {
/// transactions. These batches themselves are maps associating nonces with transactions
/// summary strings.
///
/// For details, see [txpool_inspect](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool#txpool-content)
/// For details, see [txpool_inspect (geth)](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool#txpool-inspect)
/// or [txpool_inspect (nethermind)](https://docs.nethermind.io/nethermind/ethereum-client/json-rpc/txpool#txpool_inspect).
#[method(name = "txpool_inspect")]
fn inspect(&self) -> RpcResult<TxPoolResult<TransactionMap<Summary>>>;

Expand All @@ -59,7 +61,8 @@ pub trait TxPoolApi {
/// The result is an object with two fields pending and queued, each of which is a counter
/// representing the number of transactions in that particular state.
///
/// For details, see [txpool_status](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool#txpool-status)
/// For details, see [txpool_status (geth)](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool#txpool-status)
/// or [txpool_status (nethermind)](https://docs.nethermind.io/nethermind/ethereum-client/json-rpc/txpool#txpool_status).
#[method(name = "txpool_status")]
fn status(&self) -> RpcResult<TxPoolResult<U256>>;
}
9 changes: 8 additions & 1 deletion client/rpc-core/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ mod work;

pub mod pubsub;

use ethereum::TransactionV2 as EthereumTransaction;
use ethereum_types::H160;
use serde::{de::Error, Deserialize, Deserializer};

#[cfg(feature = "txpool")]
pub use self::txpool::{Get, Summary, TransactionMap, TxPoolResult, TxPoolTransaction};
pub use self::txpool::{Summary, TransactionMap, TxPoolResult};
pub use self::{
account_info::{AccountInfo, EthAccount, ExtAccountInfo, RecoveredAccount, StorageProof},
block::{Block, BlockTransactions, Header, Rich, RichBlock, RichHeader},
Expand Down Expand Up @@ -89,3 +91,8 @@ pub(crate) fn deserialize_data_or_input<'d, D: Deserializer<'d>>(
(_, _) => Ok(data.or(input)),
}
}

/// The trait that used to build types from the `from` address and ethereum `transaction`.
pub trait BuildFrom {
fn build_from(from: H160, transaction: &EthereumTransaction) -> Self;
}
116 changes: 60 additions & 56 deletions client/rpc-core/src/types/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use ethereum::{AccessListItem, TransactionV2};
use ethereum_types::{H160, H256, H512, U256, U64};
use ethereum::{AccessListItem, TransactionAction, TransactionV2 as EthereumTransaction};
use ethereum_types::{H160, H256, U256, U64};
use serde::{ser::SerializeStruct, Serialize, Serializer};

use crate::types::Bytes;
use crate::types::{BuildFrom, Bytes};

/// Transaction
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Transaction {
/// EIP-2718 transaction type
#[serde(rename = "type")]
pub transaction_type: U256,
/// Hash
pub hash: H256,
/// Nonce
Expand All @@ -42,6 +45,8 @@ pub struct Transaction {
pub to: Option<H160>,
/// Transfered value
pub value: U256,
/// Gas
pub gas: U256,
/// Gas Price
#[serde(skip_serializing_if = "Option::is_none")]
pub gas_price: Option<U256>,
Expand All @@ -51,114 +56,113 @@ pub struct Transaction {
/// The miner's tip.
#[serde(skip_serializing_if = "Option::is_none")]
pub max_priority_fee_per_gas: Option<U256>,
/// Gas
pub gas: U256,
/// Data
pub input: Bytes,
/// Creates contract
pub creates: Option<H160>,
/// Raw transaction data
pub raw: Bytes,
/// Public key of the signer.
pub public_key: Option<H512>,
/// The network id of the transaction, if any.
#[serde(skip_serializing_if = "Option::is_none")]
pub chain_id: Option<U64>,
/// The standardised V field of the signature (0 or 1).
pub standard_v: U256,
/// Pre-pay to warm storage access.
#[serde(skip_serializing_if = "Option::is_none")]
pub access_list: Option<Vec<AccessListItem>>,
/// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature.
#[serde(skip_serializing_if = "Option::is_none")]
pub y_parity: Option<U256>,
/// The standardised V field of the signature.
pub v: U256,
///
/// 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<U256>,
/// The R field of the signature.
pub r: U256,
/// The S field of the signature.
pub s: U256,
/// Pre-pay to warm storage access.
#[cfg_attr(feature = "std", serde(skip_serializing_if = "Option::is_none"))]
pub access_list: Option<Vec<AccessListItem>>,
/// EIP-2718 type
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub transaction_type: Option<U256>,
}

impl From<TransactionV2> for Transaction {
fn from(transaction: TransactionV2) -> Self {
let serialized = ethereum::EnvelopedEncodable::encode(&transaction);
impl BuildFrom for Transaction {
fn build_from(from: H160, transaction: &EthereumTransaction) -> Self {
let hash = transaction.hash();
let raw = Bytes(serialized.to_vec());
match transaction {
TransactionV2::Legacy(t) => Transaction {
EthereumTransaction::Legacy(t) => Self {
transaction_type: U256::from(0),
hash,
nonce: t.nonce,
block_hash: None,
block_number: None,
transaction_index: None,
from: H160::default(),
to: None,
from,
to: match t.action {
TransactionAction::Call(to) => Some(to),
TransactionAction::Create => None,
},
value: t.value,
gas: t.gas_limit,
gas_price: Some(t.gas_price),
max_fee_per_gas: None,
max_priority_fee_per_gas: None,
gas: t.gas_limit,
input: Bytes(t.clone().input),
input: Bytes(t.input.clone()),
creates: None,
raw,
public_key: None,
chain_id: t.signature.chain_id().map(U64::from),
standard_v: U256::from(t.signature.standard_v()),
v: U256::from(t.signature.v()),
access_list: None,
y_parity: None,
v: Some(U256::from(t.signature.v())),
r: U256::from(t.signature.r().as_bytes()),
s: U256::from(t.signature.s().as_bytes()),
access_list: None,
transaction_type: Some(U256::from(0)),
},
TransactionV2::EIP2930(t) => Transaction {
EthereumTransaction::EIP2930(t) => Self {
transaction_type: U256::from(1),
hash,
nonce: t.nonce,
block_hash: None,
block_number: None,
transaction_index: None,
from: H160::default(),
to: None,
from,
to: match t.action {
TransactionAction::Call(to) => Some(to),
TransactionAction::Create => None,
},
value: t.value,
gas: t.gas_limit,
gas_price: Some(t.gas_price),
max_fee_per_gas: None,
max_priority_fee_per_gas: None,
gas: t.gas_limit,
input: Bytes(t.clone().input),
input: Bytes(t.input.clone()),
creates: None,
raw,
public_key: None,
chain_id: Some(U64::from(t.chain_id)),
standard_v: U256::from(t.odd_y_parity as u8),
v: U256::from(t.odd_y_parity as u8),
access_list: Some(t.access_list.clone()),
y_parity: Some(U256::from(t.odd_y_parity as u8)),
v: Some(U256::from(t.odd_y_parity as u8)),
r: U256::from(t.r.as_bytes()),
s: U256::from(t.s.as_bytes()),
access_list: Some(t.access_list),
transaction_type: Some(U256::from(1)),
},
TransactionV2::EIP1559(t) => Transaction {
EthereumTransaction::EIP1559(t) => Self {
transaction_type: U256::from(2),
hash,
nonce: t.nonce,
block_hash: None,
block_number: None,
transaction_index: None,
from: H160::default(),
to: None,
from,
to: match t.action {
TransactionAction::Call(to) => Some(to),
TransactionAction::Create => None,
},
value: t.value,
gas_price: None,
gas: t.gas_limit,
// If transaction is not mined yet, gas price is considered just max fee per gas.
gas_price: Some(t.max_fee_per_gas),
max_fee_per_gas: Some(t.max_fee_per_gas),
max_priority_fee_per_gas: Some(t.max_priority_fee_per_gas),
gas: t.gas_limit,
input: Bytes(t.clone().input),
input: Bytes(t.input.clone()),
creates: None,
raw,
public_key: None,
chain_id: Some(U64::from(t.chain_id)),
standard_v: U256::from(t.odd_y_parity as u8),
v: U256::from(t.odd_y_parity as u8),
access_list: Some(t.access_list.clone()),
y_parity: Some(U256::from(t.odd_y_parity as u8)),
v: Some(U256::from(t.odd_y_parity as u8)),
r: U256::from(t.r.as_bytes()),
s: U256::from(t.s.as_bytes()),
access_list: Some(t.access_list),
transaction_type: Some(U256::from(2)),
},
}
}
Expand Down
107 changes: 6 additions & 101 deletions client/rpc-core/src/types/txpool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,15 @@
use std::collections::HashMap;

use ethereum::{TransactionAction, TransactionV2 as EthereumTransaction};
use ethereum_types::{H160, H256, U256};
use ethereum_types::{H160, U256};
use serde::{Serialize, Serializer};

use crate::types::Bytes;
use crate::types::BuildFrom;

/// The entry maps an origin-address to a batch of scheduled transactions.
/// These batches themselves are maps associating nonces with actual transactions.
pub type TransactionMap<T> = HashMap<H160, HashMap<U256, T>>;

pub trait Get {
fn get(hash: H256, from_address: H160, txn: &EthereumTransaction) -> Self;
}

/// The result type of `txpool` API.
#[derive(Debug, Serialize)]
pub struct TxPoolResult<T: Serialize> {
Expand Down Expand Up @@ -68,9 +64,9 @@ impl Serialize for Summary {
}
}

impl Get for Summary {
fn get(_hash: H256, _from_address: H160, txn: &EthereumTransaction) -> Self {
let (action, value, gas_price, gas_limit) = match txn {
impl BuildFrom for Summary {
fn build_from(_from: H160, transaction: &EthereumTransaction) -> Self {
let (action, value, gas_price, gas) = match transaction {
EthereumTransaction::Legacy(t) => (t.action, t.value, t.gas_price, t.gas_limit),
EthereumTransaction::EIP2930(t) => (t.action, t.value, t.gas_price, t.gas_limit),
EthereumTransaction::EIP1559(t) => (t.action, t.value, t.max_fee_per_gas, t.gas_limit),
Expand All @@ -82,98 +78,7 @@ impl Get for Summary {
},
value,
gas_price,
gas: gas_limit,
}
}
}

/// The exact details of all the transactions currently pending for inclusion in the next block(s)
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TxPoolTransaction {
/// Hash
pub hash: H256,
/// Nonce
pub nonce: U256,
/// Block hash
#[serde(serialize_with = "block_hash_serialize")]
pub block_hash: Option<H256>,
/// Block number
pub block_number: Option<U256>,
/// Sender
pub from: H160,
/// Recipient
#[serde(serialize_with = "to_serialize")]
pub to: Option<H160>,
/// Transferred value
pub value: U256,
/// Gas Price
pub gas_price: U256,
/// Gas
pub gas: U256,
/// Data
pub input: Bytes,
/// Transaction Index
pub transaction_index: Option<U256>,
}

fn block_hash_serialize<S>(hash: &Option<H256>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&format!("0x{:x}", hash.unwrap_or_default()))
}

fn to_serialize<S>(hash: &Option<H160>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&format!("0x{:x}", hash.unwrap_or_default()))
}

impl Get for TxPoolTransaction {
fn get(hash: H256, from_address: H160, txn: &EthereumTransaction) -> Self {
let (nonce, action, value, gas_price, gas_limit, input) = match txn {
EthereumTransaction::Legacy(t) => (
t.nonce,
t.action,
t.value,
t.gas_price,
t.gas_limit,
t.input.clone(),
),
EthereumTransaction::EIP2930(t) => (
t.nonce,
t.action,
t.value,
t.gas_price,
t.gas_limit,
t.input.clone(),
),
EthereumTransaction::EIP1559(t) => (
t.nonce,
t.action,
t.value,
t.max_fee_per_gas,
t.gas_limit,
t.input.clone(),
),
};
Self {
hash,
nonce,
block_hash: None,
block_number: None,
from: from_address,
to: match action {
TransactionAction::Call(to) => Some(to),
_ => None,
},
value,
gas_price,
gas: gas_limit,
input: Bytes(input),
transaction_index: None,
gas,
}
}
}
Loading

0 comments on commit 1d523e0

Please sign in to comment.