mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
fix(rpc): type encoding (#155)
* fix(rpc): type encoding * copy bytes from ethers
This commit is contained in:
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -1261,17 +1261,6 @@ dependencies = [
|
|||||||
"instant",
|
"instant",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fastrlp"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "089263294bb1c38ac73649a6ad563dd9a5142c8dc0482be15b8b9acb22a1611e"
|
|
||||||
dependencies = [
|
|
||||||
"arrayvec",
|
|
||||||
"auto_impl",
|
|
||||||
"bytes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ff"
|
name = "ff"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
@ -3342,8 +3331,8 @@ dependencies = [
|
|||||||
name = "reth-rpc-types"
|
name = "reth-rpc-types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrlp",
|
|
||||||
"reth-primitives",
|
"reth-primitives",
|
||||||
|
"reth-rlp",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -11,9 +11,7 @@ Reth RPC types
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
# reth
|
# reth
|
||||||
reth-primitives = { path = "../../primitives" }
|
reth-primitives = { path = "../../primitives" }
|
||||||
|
reth-rlp = {path = "../../common/rlp"}
|
||||||
# eth
|
|
||||||
fastrlp = { version = "0.1" }
|
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use crate::eth::transaction::typed::{
|
|||||||
EIP1559TransactionRequest, EIP2930TransactionRequest, LegacyTransactionRequest,
|
EIP1559TransactionRequest, EIP2930TransactionRequest, LegacyTransactionRequest,
|
||||||
TransactionKind, TypedTransactionRequest,
|
TransactionKind, TypedTransactionRequest,
|
||||||
};
|
};
|
||||||
use reth_primitives::{rpc::transaction::eip2930::AccessListItem, Address, Bytes, U256};
|
use reth_primitives::{AccessList, Address, Bytes, U256};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Represents _all_ transaction requests received from RPC
|
/// Represents _all_ transaction requests received from RPC
|
||||||
@ -33,7 +33,7 @@ pub struct TransactionRequest {
|
|||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
/// warm storage access pre-payment
|
/// warm storage access pre-payment
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub access_list: Option<Vec<AccessListItem>>,
|
pub access_list: Option<AccessList>,
|
||||||
/// EIP-2718 type
|
/// EIP-2718 type
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub transaction_type: Option<U256>,
|
pub transaction_type: Option<U256>,
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
//! json input of an RPC call. Depending on what fields are set, it can be converted into the
|
//! json input of an RPC call. Depending on what fields are set, it can be converted into the
|
||||||
//! container type [`TypedTransactionRequest`].
|
//! container type [`TypedTransactionRequest`].
|
||||||
|
|
||||||
use fastrlp::{RlpDecodable, RlpEncodable};
|
use reth_primitives::{AccessList, Address, Bytes, U256};
|
||||||
use reth_primitives::{rpc::transaction::eip2930::AccessListItem, Address, Bytes, U256};
|
use reth_rlp::{BufMut, Decodable, DecodeError, Encodable, RlpDecodable, RlpEncodable};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Container type for various Ethereum transaction requests
|
/// Container type for various Ethereum transaction requests
|
||||||
@ -42,7 +42,7 @@ pub struct EIP2930TransactionRequest {
|
|||||||
pub kind: TransactionKind,
|
pub kind: TransactionKind,
|
||||||
pub value: U256,
|
pub value: U256,
|
||||||
pub input: Bytes,
|
pub input: Bytes,
|
||||||
pub access_list: Vec<AccessListItem>,
|
pub access_list: AccessList,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an EIP-1559 transaction request
|
/// Represents an EIP-1559 transaction request
|
||||||
@ -56,7 +56,7 @@ pub struct EIP1559TransactionRequest {
|
|||||||
pub kind: TransactionKind,
|
pub kind: TransactionKind,
|
||||||
pub value: U256,
|
pub value: U256,
|
||||||
pub input: Bytes,
|
pub input: Bytes,
|
||||||
pub access_list: Vec<AccessListItem>,
|
pub access_list: AccessList,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the `to` field of a transaction request
|
/// Represents the `to` field of a transaction request
|
||||||
@ -82,14 +82,14 @@ impl TransactionKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fastrlp::Encodable for TransactionKind {
|
impl Encodable for TransactionKind {
|
||||||
fn length(&self) -> usize {
|
fn length(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
TransactionKind::Call(to) => to.length(),
|
TransactionKind::Call(to) => to.length(),
|
||||||
TransactionKind::Create => ([]).length(),
|
TransactionKind::Create => ([]).length(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn encode(&self, out: &mut dyn fastrlp::BufMut) {
|
fn encode(&self, out: &mut dyn BufMut) {
|
||||||
match self {
|
match self {
|
||||||
TransactionKind::Call(to) => to.encode(out),
|
TransactionKind::Call(to) => to.encode(out),
|
||||||
TransactionKind::Create => ([]).encode(out),
|
TransactionKind::Create => ([]).encode(out),
|
||||||
@ -97,18 +97,18 @@ impl fastrlp::Encodable for TransactionKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fastrlp::Decodable for TransactionKind {
|
impl Decodable for TransactionKind {
|
||||||
fn decode(buf: &mut &[u8]) -> Result<Self, fastrlp::DecodeError> {
|
fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError> {
|
||||||
if let Some(&first) = buf.first() {
|
if let Some(&first) = buf.first() {
|
||||||
if first == 0x80 {
|
if first == 0x80 {
|
||||||
*buf = &buf[1..];
|
*buf = &buf[1..];
|
||||||
Ok(TransactionKind::Create)
|
Ok(TransactionKind::Create)
|
||||||
} else {
|
} else {
|
||||||
let addr = <Address as fastrlp::Decodable>::decode(buf)?;
|
let addr = <Address as Decodable>::decode(buf)?;
|
||||||
Ok(TransactionKind::Call(addr))
|
Ok(TransactionKind::Call(addr))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(fastrlp::DecodeError::InputTooShort)
|
Err(DecodeError::InputTooShort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
226
crates/primitives/src/hex_bytes.rs
Normal file
226
crates/primitives/src/hex_bytes.rs
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
use reth_rlp::{Decodable, DecodeError, Encodable};
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
|
clone::Clone,
|
||||||
|
fmt::{Debug, Display, Formatter, LowerHex, Result as FmtResult},
|
||||||
|
ops::Deref,
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Wrapper type around Bytes to deserialize/serialize "0x" prefixed ethereum hex strings
|
||||||
|
#[derive(Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
|
||||||
|
pub struct Bytes(
|
||||||
|
#[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")]
|
||||||
|
pub bytes::Bytes,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn bytes_to_hex(b: &Bytes) -> String {
|
||||||
|
hex::encode(b.0.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Bytes {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||||
|
write!(f, "Bytes(0x{})", bytes_to_hex(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Bytes {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||||
|
write!(f, "0x{}", bytes_to_hex(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LowerHex for Bytes {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||||
|
write!(f, "0x{}", bytes_to_hex(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bytes {
|
||||||
|
/// Return bytes as [Vec::<u8>]
|
||||||
|
pub fn to_vec(&self) -> Vec<u8> {
|
||||||
|
self.as_ref().to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Bytes {
|
||||||
|
type Target = [u8];
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &[u8] {
|
||||||
|
self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Bytes {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Borrow<[u8]> for Bytes {
|
||||||
|
fn borrow(&self) -> &[u8] {
|
||||||
|
self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for Bytes {
|
||||||
|
type Item = u8;
|
||||||
|
type IntoIter = bytes::buf::IntoIter<bytes::Bytes>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a Bytes {
|
||||||
|
type Item = &'a u8;
|
||||||
|
type IntoIter = core::slice::Iter<'a, u8>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.as_ref().iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bytes::Bytes> for Bytes {
|
||||||
|
fn from(src: bytes::Bytes) -> Self {
|
||||||
|
Self(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<u8>> for Bytes {
|
||||||
|
fn from(src: Vec<u8>) -> Self {
|
||||||
|
Self(src.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> From<[u8; N]> for Bytes {
|
||||||
|
fn from(src: [u8; N]) -> Self {
|
||||||
|
src.to_vec().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, const N: usize> From<&'a [u8; N]> for Bytes {
|
||||||
|
fn from(src: &'a [u8; N]) -> Self {
|
||||||
|
src.to_vec().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<[u8]> for Bytes {
|
||||||
|
fn eq(&self, other: &[u8]) -> bool {
|
||||||
|
self.as_ref() == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Bytes> for [u8] {
|
||||||
|
fn eq(&self, other: &Bytes) -> bool {
|
||||||
|
*other == *self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Vec<u8>> for Bytes {
|
||||||
|
fn eq(&self, other: &Vec<u8>) -> bool {
|
||||||
|
self.as_ref() == &other[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Bytes> for Vec<u8> {
|
||||||
|
fn eq(&self, other: &Bytes) -> bool {
|
||||||
|
*other == *self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<bytes::Bytes> for Bytes {
|
||||||
|
fn eq(&self, other: &bytes::Bytes) -> bool {
|
||||||
|
other == self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for Bytes {
|
||||||
|
fn length(&self) -> usize {
|
||||||
|
self.0.length()
|
||||||
|
}
|
||||||
|
fn encode(&self, out: &mut dyn bytes::BufMut) {
|
||||||
|
self.0.encode(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for Bytes {
|
||||||
|
fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError> {
|
||||||
|
Ok(Self(bytes::Bytes::decode(buf)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Error)]
|
||||||
|
#[error("Failed to parse bytes: {0}")]
|
||||||
|
pub struct ParseBytesError(String);
|
||||||
|
|
||||||
|
impl FromStr for Bytes {
|
||||||
|
type Err = ParseBytesError;
|
||||||
|
|
||||||
|
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||||
|
if let Some(value) = value.strip_prefix("0x") {
|
||||||
|
hex::decode(value)
|
||||||
|
} else {
|
||||||
|
hex::decode(value)
|
||||||
|
}
|
||||||
|
.map(Into::into)
|
||||||
|
.map_err(|e| ParseBytesError(format!("Invalid hex: {}", e)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_bytes<S, T>(x: T, s: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
T: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
s.serialize_str(&format!("0x{}", hex::encode(x.as_ref())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_bytes<'de, D>(d: D) -> Result<bytes::Bytes, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let value = String::deserialize(d)?;
|
||||||
|
if let Some(value) = value.strip_prefix("0x") {
|
||||||
|
hex::decode(value)
|
||||||
|
} else {
|
||||||
|
hex::decode(&value)
|
||||||
|
}
|
||||||
|
.map(Into::into)
|
||||||
|
.map_err(|e| serde::de::Error::custom(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hex_formatting() {
|
||||||
|
let b = Bytes::from(vec![1, 35, 69, 103, 137, 171, 205, 239]);
|
||||||
|
let expected = String::from("0x0123456789abcdef");
|
||||||
|
assert_eq!(format!("{:x}", b), expected);
|
||||||
|
assert_eq!(format!("{}", b), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_str() {
|
||||||
|
let b = Bytes::from_str("0x1213");
|
||||||
|
assert!(b.is_ok());
|
||||||
|
let b = b.unwrap();
|
||||||
|
assert_eq!(b.as_ref(), hex::decode("1213").unwrap());
|
||||||
|
|
||||||
|
let b = Bytes::from_str("1213");
|
||||||
|
let b = b.unwrap();
|
||||||
|
assert_eq!(b.as_ref(), hex::decode("1213").unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_debug_formatting() {
|
||||||
|
let b = Bytes::from(vec![1, 35, 69, 103, 137, 171, 205, 239]);
|
||||||
|
assert_eq!(format!("{:?}", b), "Bytes(0x0123456789abcdef)");
|
||||||
|
assert_eq!(format!("{:#?}", b), "Bytes(0x0123456789abcdef)");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@ mod block;
|
|||||||
mod chain;
|
mod chain;
|
||||||
mod error;
|
mod error;
|
||||||
mod header;
|
mod header;
|
||||||
|
mod hex_bytes;
|
||||||
mod integer_list;
|
mod integer_list;
|
||||||
mod jsonu256;
|
mod jsonu256;
|
||||||
mod log;
|
mod log;
|
||||||
@ -23,6 +24,7 @@ pub use account::Account;
|
|||||||
pub use block::{Block, BlockLocked};
|
pub use block::{Block, BlockLocked};
|
||||||
pub use chain::Chain;
|
pub use chain::Chain;
|
||||||
pub use header::{Header, HeaderLocked};
|
pub use header::{Header, HeaderLocked};
|
||||||
|
pub use hex_bytes::Bytes;
|
||||||
pub use integer_list::IntegerList;
|
pub use integer_list::IntegerList;
|
||||||
pub use jsonu256::JsonU256;
|
pub use jsonu256::JsonU256;
|
||||||
pub use log::Log;
|
pub use log::Log;
|
||||||
@ -51,10 +53,9 @@ pub type StorageKey = H256;
|
|||||||
/// Storage value
|
/// Storage value
|
||||||
pub type StorageValue = H256;
|
pub type StorageValue = H256;
|
||||||
|
|
||||||
// NOTE: There is a benefit of using wrapped Bytes as it gives us serde and debug
|
|
||||||
pub use ethers_core::{
|
pub use ethers_core::{
|
||||||
types as rpc,
|
types as rpc,
|
||||||
types::{BigEndianHash, Bloom, Bytes, H128, H160, H256, H512, H64, U128, U256, U64},
|
types::{BigEndianHash, Bloom, H128, H160, H256, H512, H64, U128, U256, U64},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
use reth_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
|
use reth_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{Address, H256};
|
use crate::{Address, H256};
|
||||||
|
|
||||||
/// A list of addresses and storage keys that the transaction plans to access.
|
/// A list of addresses and storage keys that the transaction plans to access.
|
||||||
/// Accesses outside the list are possible, but become more expensive.
|
/// Accesses outside the list are possible, but become more expensive.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, RlpDecodable, RlpEncodable)]
|
#[derive(
|
||||||
|
Clone, Debug, PartialEq, Eq, Hash, Default, RlpDecodable, RlpEncodable, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub struct AccessListItem {
|
pub struct AccessListItem {
|
||||||
/// Account addresses that would be loaded at the start of execution
|
/// Account addresses that would be loaded at the start of execution
|
||||||
pub address: Address,
|
pub address: Address,
|
||||||
@ -13,5 +16,16 @@ pub struct AccessListItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// AccessList as defined in EIP-2930
|
/// AccessList as defined in EIP-2930
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, RlpDecodableWrapper, RlpEncodableWrapper)]
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
Debug,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
Hash,
|
||||||
|
Default,
|
||||||
|
RlpDecodableWrapper,
|
||||||
|
RlpEncodableWrapper,
|
||||||
|
Serialize,
|
||||||
|
Deserialize,
|
||||||
|
)]
|
||||||
pub struct AccessList(pub Vec<AccessListItem>);
|
pub struct AccessList(pub Vec<AccessListItem>);
|
||||||
|
|||||||
@ -632,10 +632,10 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
transaction::{signature::Signature, TransactionKind},
|
transaction::{signature::Signature, TransactionKind},
|
||||||
Address, Transaction, TransactionSigned, H256, U256,
|
Address, Bytes, Transaction, TransactionSigned, H256, U256,
|
||||||
};
|
};
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use ethers_core::{types::Bytes, utils::hex};
|
use ethers_core::utils::hex;
|
||||||
use reth_rlp::{Decodable, Encodable};
|
use reth_rlp::{Decodable, Encodable};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user