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:
@ -11,9 +11,7 @@ Reth RPC types
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-primitives = { path = "../../primitives" }
|
||||
|
||||
# eth
|
||||
fastrlp = { version = "0.1" }
|
||||
reth-rlp = {path = "../../common/rlp"}
|
||||
|
||||
# misc
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@ -2,7 +2,7 @@ use crate::eth::transaction::typed::{
|
||||
EIP1559TransactionRequest, EIP2930TransactionRequest, LegacyTransactionRequest,
|
||||
TransactionKind, TypedTransactionRequest,
|
||||
};
|
||||
use reth_primitives::{rpc::transaction::eip2930::AccessListItem, Address, Bytes, U256};
|
||||
use reth_primitives::{AccessList, Address, Bytes, U256};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Represents _all_ transaction requests received from RPC
|
||||
@ -33,7 +33,7 @@ pub struct TransactionRequest {
|
||||
pub nonce: Option<U256>,
|
||||
/// warm storage access pre-payment
|
||||
#[serde(default)]
|
||||
pub access_list: Option<Vec<AccessListItem>>,
|
||||
pub access_list: Option<AccessList>,
|
||||
/// EIP-2718 type
|
||||
#[serde(rename = "type")]
|
||||
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
|
||||
//! container type [`TypedTransactionRequest`].
|
||||
|
||||
use fastrlp::{RlpDecodable, RlpEncodable};
|
||||
use reth_primitives::{rpc::transaction::eip2930::AccessListItem, Address, Bytes, U256};
|
||||
use reth_primitives::{AccessList, Address, Bytes, U256};
|
||||
use reth_rlp::{BufMut, Decodable, DecodeError, Encodable, RlpDecodable, RlpEncodable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Container type for various Ethereum transaction requests
|
||||
@ -42,7 +42,7 @@ pub struct EIP2930TransactionRequest {
|
||||
pub kind: TransactionKind,
|
||||
pub value: U256,
|
||||
pub input: Bytes,
|
||||
pub access_list: Vec<AccessListItem>,
|
||||
pub access_list: AccessList,
|
||||
}
|
||||
|
||||
/// Represents an EIP-1559 transaction request
|
||||
@ -56,7 +56,7 @@ pub struct EIP1559TransactionRequest {
|
||||
pub kind: TransactionKind,
|
||||
pub value: U256,
|
||||
pub input: Bytes,
|
||||
pub access_list: Vec<AccessListItem>,
|
||||
pub access_list: AccessList,
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
match self {
|
||||
TransactionKind::Call(to) => to.length(),
|
||||
TransactionKind::Create => ([]).length(),
|
||||
}
|
||||
}
|
||||
fn encode(&self, out: &mut dyn fastrlp::BufMut) {
|
||||
fn encode(&self, out: &mut dyn BufMut) {
|
||||
match self {
|
||||
TransactionKind::Call(to) => to.encode(out),
|
||||
TransactionKind::Create => ([]).encode(out),
|
||||
@ -97,18 +97,18 @@ impl fastrlp::Encodable for TransactionKind {
|
||||
}
|
||||
}
|
||||
|
||||
impl fastrlp::Decodable for TransactionKind {
|
||||
fn decode(buf: &mut &[u8]) -> Result<Self, fastrlp::DecodeError> {
|
||||
impl Decodable for TransactionKind {
|
||||
fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError> {
|
||||
if let Some(&first) = buf.first() {
|
||||
if first == 0x80 {
|
||||
*buf = &buf[1..];
|
||||
Ok(TransactionKind::Create)
|
||||
} else {
|
||||
let addr = <Address as fastrlp::Decodable>::decode(buf)?;
|
||||
let addr = <Address as Decodable>::decode(buf)?;
|
||||
Ok(TransactionKind::Call(addr))
|
||||
}
|
||||
} 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 error;
|
||||
mod header;
|
||||
mod hex_bytes;
|
||||
mod integer_list;
|
||||
mod jsonu256;
|
||||
mod log;
|
||||
@ -23,6 +24,7 @@ pub use account::Account;
|
||||
pub use block::{Block, BlockLocked};
|
||||
pub use chain::Chain;
|
||||
pub use header::{Header, HeaderLocked};
|
||||
pub use hex_bytes::Bytes;
|
||||
pub use integer_list::IntegerList;
|
||||
pub use jsonu256::JsonU256;
|
||||
pub use log::Log;
|
||||
@ -51,10 +53,9 @@ pub type StorageKey = H256;
|
||||
/// Storage value
|
||||
pub type StorageValue = H256;
|
||||
|
||||
// NOTE: There is a benefit of using wrapped Bytes as it gives us serde and debug
|
||||
pub use ethers_core::{
|
||||
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)]
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
use reth_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Address, H256};
|
||||
|
||||
/// A list of addresses and storage keys that the transaction plans to access.
|
||||
/// 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 {
|
||||
/// Account addresses that would be loaded at the start of execution
|
||||
pub address: Address,
|
||||
@ -13,5 +16,16 @@ pub struct AccessListItem {
|
||||
}
|
||||
|
||||
/// 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>);
|
||||
|
||||
@ -632,10 +632,10 @@ mod tests {
|
||||
|
||||
use crate::{
|
||||
transaction::{signature::Signature, TransactionKind},
|
||||
Address, Transaction, TransactionSigned, H256, U256,
|
||||
Address, Bytes, Transaction, TransactionSigned, H256, U256,
|
||||
};
|
||||
use bytes::BytesMut;
|
||||
use ethers_core::{types::Bytes, utils::hex};
|
||||
use ethers_core::utils::hex;
|
||||
use reth_rlp::{Decodable, Encodable};
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user