fix(core): encode absent tx access_list correctly (#1137)
The optional access list on `Transaction` was being incorrectly encoded as an empty string (0x80) when omitted, when it should be encoded as an empty list (0xc0). Fixes #1134.
This commit is contained in:
parent
7799634479
commit
286f842a2a
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
### Unreleased
|
### Unreleased
|
||||||
|
|
||||||
|
- Fix RLP encoding of absent access list in `Transaction` [1137](https://github.com/gakonst/ethers-rs/pull/1137)
|
||||||
- Pass compilation time as additional argument to `Reporter::on_solc_success` [1098](https://github.com/gakonst/ethers-rs/pull/1098)
|
- Pass compilation time as additional argument to `Reporter::on_solc_success` [1098](https://github.com/gakonst/ethers-rs/pull/1098)
|
||||||
- Fix aws signer bug which maps un-normalized signature to error if no normalization occurs (in `aws::utils::decode_signature`)
|
- Fix aws signer bug which maps un-normalized signature to error if no normalization occurs (in `aws::utils::decode_signature`)
|
||||||
- Implement signed transaction RLP decoding [#1096](https://github.com/gakonst/ethers-rs/pull/1096)
|
- Implement signed transaction RLP decoding [#1096](https://github.com/gakonst/ethers-rs/pull/1096)
|
||||||
|
|
|
@ -25,6 +25,15 @@ pub(super) fn rlp_opt<T: rlp::Encodable>(rlp: &mut rlp::RlpStream, opt: &Option<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn rlp_opt_list<T: rlp::Encodable>(rlp: &mut rlp::RlpStream, opt: &Option<T>) {
|
||||||
|
if let Some(inner) = opt {
|
||||||
|
rlp.append(inner);
|
||||||
|
} else {
|
||||||
|
// Choice of `u8` type here is arbitrary as all empty lists are encoded the same.
|
||||||
|
rlp.append_list::<u8, u8>(&[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// normalizes the signature back to 0/1
|
/// normalizes the signature back to 0/1
|
||||||
pub(crate) fn normalize_v(v: u64, chain_id: crate::types::U64) -> u64 {
|
pub(crate) fn normalize_v(v: u64, chain_id: crate::types::U64) -> u64 {
|
||||||
if v > 1 {
|
if v > 1 {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! Transaction types
|
//! Transaction types
|
||||||
use super::{
|
use super::{
|
||||||
decode_signature, eip2718::TypedTransaction, eip2930::AccessList, normalize_v, rlp_opt,
|
decode_signature, eip2718::TypedTransaction, eip2930::AccessList, normalize_v, rlp_opt,
|
||||||
|
rlp_opt_list,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
types::{Address, Bloom, Bytes, Log, Signature, SignatureError, H256, U256, U64},
|
types::{Address, Bloom, Bytes, Log, Signature, SignatureError, H256, U256, U64},
|
||||||
|
@ -147,7 +148,7 @@ impl Transaction {
|
||||||
rlp_opt(&mut rlp, &self.to);
|
rlp_opt(&mut rlp, &self.to);
|
||||||
rlp.append(&self.value);
|
rlp.append(&self.value);
|
||||||
rlp.append(&self.input.as_ref());
|
rlp.append(&self.input.as_ref());
|
||||||
rlp_opt(&mut rlp, &self.access_list);
|
rlp_opt_list(&mut rlp, &self.access_list);
|
||||||
if let Some(chain_id) = self.chain_id {
|
if let Some(chain_id) = self.chain_id {
|
||||||
rlp.append(&normalize_v(self.v.as_u64(), U64::from(chain_id.as_u64())));
|
rlp.append(&normalize_v(self.v.as_u64(), U64::from(chain_id.as_u64())));
|
||||||
}
|
}
|
||||||
|
@ -162,7 +163,7 @@ impl Transaction {
|
||||||
rlp_opt(&mut rlp, &self.to);
|
rlp_opt(&mut rlp, &self.to);
|
||||||
rlp.append(&self.value);
|
rlp.append(&self.value);
|
||||||
rlp.append(&self.input.as_ref());
|
rlp.append(&self.input.as_ref());
|
||||||
rlp_opt(&mut rlp, &self.access_list);
|
rlp_opt_list(&mut rlp, &self.access_list);
|
||||||
if let Some(chain_id) = self.chain_id {
|
if let Some(chain_id) = self.chain_id {
|
||||||
rlp.append(&normalize_v(self.v.as_u64(), U64::from(chain_id.as_u64())));
|
rlp.append(&normalize_v(self.v.as_u64(), U64::from(chain_id.as_u64())));
|
||||||
}
|
}
|
||||||
|
@ -534,6 +535,49 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rlp_london_no_access_list() {
|
||||||
|
let tx = Transaction {
|
||||||
|
block_hash: None,
|
||||||
|
block_number: None,
|
||||||
|
from: Address::from_str("057f8d0f6fb2703197363f75c002f766f1c4287a").unwrap(),
|
||||||
|
gas: U256::from_str_radix("0x6d22", 16).unwrap(),
|
||||||
|
gas_price: Some(U256::from_str_radix("0x1344ead983", 16).unwrap()),
|
||||||
|
hash: H256::from_str(
|
||||||
|
"781d57642f4e3277fe01d370bd45ba1361b475bea6a35f26814e02a0a2b26549",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
max_fee_per_gas: Some(U256::from_str_radix("0x1344ead983", 16).unwrap()),
|
||||||
|
max_priority_fee_per_gas: Some(U256::from_str_radix("0x1344ead983", 16).unwrap()),
|
||||||
|
input: Bytes::from(hex::decode("d0e30db0").unwrap()),
|
||||||
|
nonce: U256::from(479),
|
||||||
|
to: Some(Address::from_str("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2").unwrap()),
|
||||||
|
transaction_index: None,
|
||||||
|
value: U256::from_str_radix("0x2b40d6d551c8970c", 16).unwrap(),
|
||||||
|
transaction_type: Some(U64::from(0x2)),
|
||||||
|
access_list: None,
|
||||||
|
chain_id: Some(U256::from(1)),
|
||||||
|
v: U64::from(0x1),
|
||||||
|
r: U256::from_str_radix(
|
||||||
|
"0x5616cdaec839ca14d209b59eafb706e623169dc9d0fa58fbf13931cef5b5e3b0",
|
||||||
|
16,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str_radix(
|
||||||
|
"0x3e708f8044bd158d29c2e250b6a98ea637c3bc460beeea63a8f00f7cebac432a",
|
||||||
|
16,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
};
|
||||||
|
println!("0x{}", hex::encode(&tx.rlp()));
|
||||||
|
assert_eq!(
|
||||||
|
tx.rlp(),
|
||||||
|
Bytes::from(
|
||||||
|
hex::decode("02f87a018201df851344ead983851344ead983826d2294c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2882b40d6d551c8970c84d0e30db0c001a05616cdaec839ca14d209b59eafb706e623169dc9d0fa58fbf13931cef5b5e3b0a03e708f8044bd158d29c2e250b6a98ea637c3bc460beeea63a8f00f7cebac432a").unwrap()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rlp_legacy_tx() {
|
fn rlp_legacy_tx() {
|
||||||
let tx = Transaction {
|
let tx = Transaction {
|
||||||
|
|
Loading…
Reference in New Issue