Skip to content

Commit 24739cc

Browse files
authored
Dedicated enveloped transaction/receipt encoding and decoding (#44)
1 parent 755dffa commit 24739cc

File tree

7 files changed

+270
-114
lines changed

7 files changed

+270
-114
lines changed

README.md

+1-15
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,3 @@
11
# ethereum-rs
22

3-
Apache-2 licensed common Ethereum structs shared by crates. Nightly version of etcommon-rs.
4-
5-
## List of Crates
6-
7-
Below are all crates provided by the ethereum-rs project.
8-
9-
| Name | Description | Crates.io | Documentation |
10-
| ---- | ----------- | --------- | ------------- |
11-
| ethereum-rlp | Recursive-length prefix encoding, decoding, and compression | [crates.io](https://crates.io/crates/ethereum-rlp) | [Documentation](https://docs.rs/ethereum-rlp) |
12-
| ethereum-bigint | Big integer and hash implementation | [crates.io](https://crates.io/crates/ethereum-bigint) | [Documentation](https://docs.rs/ethereum-bigint) |
13-
| ethereum-hexutil | Small hex decoding helpers | [crates.io](https://crates.io/crates/ethereum-hexutil) | [Documentation](https://docs.rs/ethereum-hexutil) |
14-
| ethereum-bloom | Log bloom for Ethereum | [crates.io](https://crates.io/crates/ethereum-bloom) | [Documentation](https://docs.rs/ethereum-bloom) |
15-
| ethereum-trie | Merkle Trie specialized for Ethereum | [crates.io](https://crates.io/crates/ethereum-trie) | [Documentation](https://docs.rs/ethereum-trie) |
16-
| ethereum-block | Block, transaction and account structs for Ethereum | [crates.io](https://crates.io/crates/ethereum-block) | [Documentation](https://docs.rs/ethereum-block) |
17-
| ethereum-block-core | Core block, transaction and account structs for Ethereum | [crates.io](https://crates.io/crates/ethereum-block-core) | [Documentation](https://docs.rs/ethereum-block-core) |
3+
Apache-2 licensed common Ethereum structs shared by crates.

src/block.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
2-
util::ordered_trie_root, Header, PartialHeader, TransactionAny, TransactionV0, TransactionV1,
3-
TransactionV2,
2+
util::ordered_trie_root, EnvelopedDecodable, EnvelopedEncodable, Header, PartialHeader,
3+
TransactionAny, TransactionV0, TransactionV1, TransactionV2,
44
};
55
use alloc::vec::Vec;
66
use ethereum_types::H256;
@@ -19,20 +19,33 @@ pub struct Block<T> {
1919
pub ommers: Vec<Header>,
2020
}
2121

22-
impl<T: Encodable> Encodable for Block<T> {
22+
impl<T: EnvelopedEncodable> Encodable for Block<T> {
2323
fn rlp_append(&self, s: &mut RlpStream) {
2424
s.begin_list(3);
2525
s.append(&self.header);
26-
s.append_list(&self.transactions);
26+
s.append_list::<Vec<u8>, _>(
27+
&self
28+
.transactions
29+
.iter()
30+
.map(|tx| EnvelopedEncodable::encode(tx).to_vec())
31+
.collect::<Vec<_>>(),
32+
);
2733
s.append_list(&self.ommers);
2834
}
2935
}
3036

31-
impl<T: Decodable> Decodable for Block<T> {
37+
impl<T: EnvelopedDecodable> Decodable for Block<T> {
3238
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
3339
Ok(Self {
3440
header: rlp.val_at(0)?,
35-
transactions: rlp.list_at(1)?,
41+
transactions: rlp
42+
.list_at::<Vec<u8>>(1)?
43+
.into_iter()
44+
.map(|raw_tx| {
45+
EnvelopedDecodable::decode(&raw_tx)
46+
.map_err(|_| DecoderError::Custom("decode enveloped transaction failed"))
47+
})
48+
.collect::<Result<Vec<_>, _>>()?,
3649
ommers: rlp.list_at(2)?,
3750
})
3851
}

src/enveloped.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use bytes::BytesMut;
2+
3+
/// DecoderError for typed transactions.
4+
#[derive(Clone, Debug, Eq, PartialEq)]
5+
pub enum EnvelopedDecoderError<T> {
6+
UnknownTypeId,
7+
Payload(T),
8+
}
9+
10+
impl<T> From<T> for EnvelopedDecoderError<T> {
11+
fn from(e: T) -> Self {
12+
Self::Payload(e)
13+
}
14+
}
15+
16+
/// Encodable typed transactions.
17+
pub trait EnvelopedEncodable {
18+
/// Convert self to an owned vector.
19+
fn encode(&self) -> BytesMut {
20+
let type_id = self.type_id();
21+
22+
let mut out = BytesMut::new();
23+
if let Some(type_id) = type_id {
24+
assert!(type_id <= 0x7f);
25+
out.extend_from_slice(&[type_id]);
26+
}
27+
28+
out.extend_from_slice(&self.encode_payload()[..]);
29+
out
30+
}
31+
32+
/// Type Id of the transaction.
33+
fn type_id(&self) -> Option<u8>;
34+
35+
/// Encode inner payload.
36+
fn encode_payload(&self) -> BytesMut;
37+
}
38+
39+
/// Decodable typed transactions.
40+
pub trait EnvelopedDecodable: Sized {
41+
/// Inner payload decoder error.
42+
type PayloadDecoderError;
43+
44+
/// Decode raw bytes to a Self type.
45+
fn decode(bytes: &[u8]) -> Result<Self, EnvelopedDecoderError<Self::PayloadDecoderError>>;
46+
}

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ extern crate alloc;
44

55
mod account;
66
mod block;
7+
mod enveloped;
78
mod header;
89
mod log;
910
mod receipt;
@@ -15,6 +16,7 @@ type Bytes = alloc::vec::Vec<u8>;
1516

1617
pub use account::Account;
1718
pub use block::*;
19+
pub use enveloped::*;
1820
pub use header::{Header, PartialHeader};
1921
pub use log::Log;
2022
pub use receipt::*;

src/receipt.rs

+119-52
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use crate::util::enveloped;
2-
use crate::Log;
1+
use crate::{EnvelopedDecodable, EnvelopedDecoderError, EnvelopedEncodable, Log};
32
use alloc::vec::Vec;
3+
use bytes::BytesMut;
44
use ethereum_types::{Bloom, H256, U256};
5-
use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
5+
use rlp::{Decodable, DecoderError, Rlp};
66
use rlp_derive::{RlpDecodable, RlpEncodable};
77

88
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable)]
@@ -37,8 +37,42 @@ pub type EIP1559ReceiptData = EIP658ReceiptData;
3737

3838
pub type ReceiptV0 = FrontierReceiptData;
3939

40+
impl EnvelopedEncodable for ReceiptV0 {
41+
fn type_id(&self) -> Option<u8> {
42+
None
43+
}
44+
fn encode_payload(&self) -> BytesMut {
45+
rlp::encode(self)
46+
}
47+
}
48+
49+
impl EnvelopedDecodable for ReceiptV0 {
50+
type PayloadDecoderError = DecoderError;
51+
52+
fn decode(bytes: &[u8]) -> Result<Self, EnvelopedDecoderError<Self::PayloadDecoderError>> {
53+
Ok(rlp::decode(bytes)?)
54+
}
55+
}
56+
4057
pub type ReceiptV1 = EIP658ReceiptData;
4158

59+
impl EnvelopedEncodable for ReceiptV1 {
60+
fn type_id(&self) -> Option<u8> {
61+
None
62+
}
63+
fn encode_payload(&self) -> BytesMut {
64+
rlp::encode(self)
65+
}
66+
}
67+
68+
impl EnvelopedDecodable for ReceiptV1 {
69+
type PayloadDecoderError = DecoderError;
70+
71+
fn decode(bytes: &[u8]) -> Result<Self, EnvelopedDecoderError<Self::PayloadDecoderError>> {
72+
Ok(rlp::decode(bytes)?)
73+
}
74+
}
75+
4276
#[derive(Clone, Debug, PartialEq, Eq)]
4377
#[cfg_attr(
4478
feature = "with-codec",
@@ -52,34 +86,44 @@ pub enum ReceiptV2 {
5286
EIP2930(EIP2930ReceiptData),
5387
}
5488

55-
impl Encodable for ReceiptV2 {
56-
fn rlp_append(&self, s: &mut RlpStream) {
89+
impl EnvelopedEncodable for ReceiptV2 {
90+
fn type_id(&self) -> Option<u8> {
91+
match self {
92+
Self::Legacy(_) => None,
93+
Self::EIP2930(_) => Some(1),
94+
}
95+
}
96+
97+
fn encode_payload(&self) -> BytesMut {
5798
match self {
58-
Self::Legacy(r) => r.rlp_append(s),
59-
Self::EIP2930(r) => enveloped(1, r, s),
99+
Self::Legacy(r) => rlp::encode(r),
100+
Self::EIP2930(r) => rlp::encode(r),
60101
}
61102
}
62103
}
63104

64-
impl Decodable for ReceiptV2 {
65-
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
66-
let slice = rlp.data()?;
105+
impl EnvelopedDecodable for ReceiptV2 {
106+
type PayloadDecoderError = DecoderError;
107+
108+
fn decode(bytes: &[u8]) -> Result<Self, EnvelopedDecoderError<Self::PayloadDecoderError>> {
109+
if bytes.is_empty() {
110+
return Err(EnvelopedDecoderError::UnknownTypeId);
111+
}
67112

68-
let first = *slice.get(0).ok_or(DecoderError::Custom("empty slice"))?;
113+
let first = bytes[0];
69114

115+
let rlp = Rlp::new(bytes);
70116
if rlp.is_list() {
71-
return Ok(Self::Legacy(Decodable::decode(rlp)?));
117+
return Ok(Self::Legacy(Decodable::decode(&rlp)?));
72118
}
73119

74-
let s = slice
75-
.get(1..)
76-
.ok_or(DecoderError::Custom("no receipt body"))?;
120+
let s = &bytes[1..];
77121

78122
if first == 0x01 {
79-
return rlp::decode(s).map(Self::EIP2930);
123+
return Ok(Self::EIP2930(rlp::decode(s)?));
80124
}
81125

82-
Err(DecoderError::Custom("invalid receipt type"))
126+
Err(DecoderError::Custom("invalid receipt type").into())
83127
}
84128
}
85129

@@ -107,39 +151,50 @@ pub enum ReceiptV3 {
107151
EIP1559(EIP1559ReceiptData),
108152
}
109153

110-
impl Encodable for ReceiptV3 {
111-
fn rlp_append(&self, s: &mut RlpStream) {
154+
impl EnvelopedEncodable for ReceiptV3 {
155+
fn type_id(&self) -> Option<u8> {
156+
match self {
157+
Self::Legacy(_) => None,
158+
Self::EIP2930(_) => Some(1),
159+
Self::EIP1559(_) => Some(2),
160+
}
161+
}
162+
163+
fn encode_payload(&self) -> BytesMut {
112164
match self {
113-
Self::Legacy(r) => r.rlp_append(s),
114-
Self::EIP2930(r) => enveloped(1, r, s),
115-
Self::EIP1559(r) => enveloped(2, r, s),
165+
Self::Legacy(r) => rlp::encode(r),
166+
Self::EIP2930(r) => rlp::encode(r),
167+
Self::EIP1559(r) => rlp::encode(r),
116168
}
117169
}
118170
}
119171

120-
impl Decodable for ReceiptV3 {
121-
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
122-
let slice = rlp.data()?;
172+
impl EnvelopedDecodable for ReceiptV3 {
173+
type PayloadDecoderError = DecoderError;
123174

124-
let first = *slice.get(0).ok_or(DecoderError::Custom("empty slice"))?;
175+
fn decode(bytes: &[u8]) -> Result<Self, EnvelopedDecoderError<Self::PayloadDecoderError>> {
176+
if bytes.is_empty() {
177+
return Err(EnvelopedDecoderError::UnknownTypeId);
178+
}
179+
180+
let first = bytes[0];
125181

182+
let rlp = Rlp::new(bytes);
126183
if rlp.is_list() {
127-
return Ok(Self::Legacy(Decodable::decode(rlp)?));
184+
return Ok(Self::Legacy(Decodable::decode(&rlp)?));
128185
}
129186

130-
let s = slice
131-
.get(1..)
132-
.ok_or(DecoderError::Custom("no receipt body"))?;
187+
let s = &bytes[1..];
133188

134189
if first == 0x01 {
135-
return rlp::decode(s).map(Self::EIP2930);
190+
return Ok(Self::EIP2930(rlp::decode(s)?));
136191
}
137192

138193
if first == 0x02 {
139-
return rlp::decode(s).map(Self::EIP1559);
194+
return Ok(Self::EIP1559(rlp::decode(s)?));
140195
}
141196

142-
Err(DecoderError::Custom("invalid receipt type"))
197+
Err(DecoderError::Custom("invalid receipt type").into())
143198
}
144199
}
145200

@@ -170,48 +225,60 @@ pub enum ReceiptAny {
170225
EIP1559(EIP1559ReceiptData),
171226
}
172227

173-
impl Encodable for ReceiptAny {
174-
fn rlp_append(&self, s: &mut RlpStream) {
228+
impl EnvelopedEncodable for ReceiptAny {
229+
fn type_id(&self) -> Option<u8> {
230+
match self {
231+
Self::Frontier(_) => None,
232+
Self::EIP658(_) => None,
233+
Self::EIP2930(_) => Some(1),
234+
Self::EIP1559(_) => Some(2),
235+
}
236+
}
237+
238+
fn encode_payload(&self) -> BytesMut {
175239
match self {
176-
Self::Frontier(r) => r.rlp_append(s),
177-
Self::EIP658(r) => r.rlp_append(s),
178-
Self::EIP2930(r) => enveloped(1, r, s),
179-
Self::EIP1559(r) => enveloped(2, r, s),
240+
Self::Frontier(r) => rlp::encode(r),
241+
Self::EIP658(r) => rlp::encode(r),
242+
Self::EIP2930(r) => rlp::encode(r),
243+
Self::EIP1559(r) => rlp::encode(r),
180244
}
181245
}
182246
}
183247

184-
impl Decodable for ReceiptAny {
185-
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
186-
let slice = rlp.data()?;
248+
impl EnvelopedDecodable for ReceiptAny {
249+
type PayloadDecoderError = DecoderError;
250+
251+
fn decode(bytes: &[u8]) -> Result<Self, EnvelopedDecoderError<Self::PayloadDecoderError>> {
252+
if bytes.is_empty() {
253+
return Err(EnvelopedDecoderError::UnknownTypeId);
254+
}
187255

188-
let first = *slice.get(0).ok_or(DecoderError::Custom("empty slice"))?;
256+
let first = bytes[0];
189257

258+
let rlp = Rlp::new(bytes);
190259
if rlp.is_list() {
191260
if rlp.item_count()? == 4 {
192261
let first = rlp.at(0)?;
193262
if first.is_data() && first.data()?.len() <= 1 {
194-
return Ok(Self::Frontier(Decodable::decode(rlp)?));
263+
return Ok(Self::Frontier(Decodable::decode(&rlp)?));
195264
} else {
196-
return Ok(Self::EIP658(Decodable::decode(rlp)?));
265+
return Ok(Self::EIP658(Decodable::decode(&rlp)?));
197266
}
198267
}
199268

200-
return Err(DecoderError::RlpIncorrectListLen);
269+
return Err(DecoderError::RlpIncorrectListLen.into());
201270
}
202271

203-
let s = slice
204-
.get(1..)
205-
.ok_or(DecoderError::Custom("no receipt body"))?;
272+
let s = &bytes[1..];
206273

207274
if first == 0x01 {
208-
return rlp::decode(s).map(Self::EIP2930);
275+
return Ok(Self::EIP2930(rlp::decode(s)?));
209276
}
210277

211278
if first == 0x02 {
212-
return rlp::decode(s).map(Self::EIP1559);
279+
return Ok(Self::EIP1559(rlp::decode(s)?));
213280
}
214281

215-
Err(DecoderError::Custom("invalid receipt type"))
282+
Err(DecoderError::Custom("invalid receipt type").into())
216283
}
217284
}

0 commit comments

Comments
 (0)