TypedTransaction (EIP-2718) and Optional access list (EIP-2930) (#135)

This commit is contained in:
rakita
2020-12-10 16:42:05 +01:00
committed by draganrakita
parent 1bce9fa76d
commit fb975731bb
83 changed files with 1858 additions and 805 deletions

View File

@@ -762,7 +762,7 @@ mod tests {
use triehash_ethereum::ordered_trie_root;
use types::{
header::Header as BlockHeader,
transaction::{SignedTransaction, Transaction},
transaction::{SignedTransaction, Transaction, TypedTransaction},
};
fn dummy_header(number: u64, parent_hash: H256) -> BlockHeader {
@@ -778,7 +778,7 @@ mod tests {
fn dummy_signed_tx() -> SignedTransaction {
let keypair = Random.generate().unwrap();
Transaction::default().sign(keypair.secret(), None)
TypedTransaction::Legacy(Transaction::default()).sign(keypair.secret(), None)
}
fn import_headers(
@@ -949,8 +949,16 @@ mod tests {
::rlp::EMPTY_LIST_RLP.to_vec()
};
let txs = encode_list(&[dummy_signed_tx()]);
let tx_root = ordered_trie_root(Rlp::new(&txs).iter().map(|r| r.as_raw()));
let mut rlp_strem = RlpStream::new();
SignedTransaction::rlp_append_list(&mut rlp_strem, &[dummy_signed_tx()]);
let txs = rlp_strem.drain();
let tx_root = ordered_trie_root(Rlp::new(&txs).iter().map(|r| {
if r.is_list() {
r.as_raw()
} else {
r.data().expect("It is expected that raw rlp list is valid")
}
}));
let mut rlp = RlpStream::new_list(2);
rlp.append_raw(&txs, 1);
@@ -1019,14 +1027,20 @@ mod tests {
// Construct the receipts. Receipt root for the first two blocks is the same.
//
// The RLP-encoded integers are clearly not receipts, but the BlockDownloader treats
// all receipts as byte blobs, so it does not matter.
// all receipts as byte blobs, so it does not matter. It is just important that they are
// represended as list (0xc1) so that they passes as legacy list
let receipts_rlp = if i < 2 {
encode_list(&[0u32])
vec![0xC1, 0]
} else {
encode_list(&[i as u32])
vec![0xC1, i as u8]
};
let receipts_root =
ordered_trie_root(Rlp::new(&receipts_rlp).iter().map(|r| r.as_raw()));
let receipts_root = ordered_trie_root(Rlp::new(&receipts_rlp).iter().map(|r| {
if r.is_list() {
r.as_raw()
} else {
r.data().expect("expect proper test data")
}
}));
receipts.push(receipts_rlp);
// Construct the block header.

View File

@@ -23,7 +23,10 @@ use network;
use rlp::{DecoderError, Rlp, RlpStream};
use std::collections::{hash_map, BTreeMap, HashMap, HashSet};
use triehash_ethereum::ordered_trie_root;
use types::{header::Header as BlockHeader, transaction::UnverifiedTransaction};
use types::{
header::Header as BlockHeader,
transaction::{TypedTransaction, UnverifiedTransaction},
};
known_heap_size!(0, HeaderId);
@@ -65,7 +68,7 @@ impl SyncBody {
let result = SyncBody {
transactions_bytes: transactions_rlp.as_raw().to_vec(),
transactions: transactions_rlp.as_list()?,
transactions: TypedTransaction::decode_rlp_list(&transactions_rlp)?,
uncles_bytes: uncles_rlp.as_raw().to_vec(),
uncles: uncles_rlp.as_list()?,
};
@@ -454,11 +457,14 @@ impl BlockCollection {
fn insert_body(&mut self, body: SyncBody) -> Result<H256, network::Error> {
let header_id = {
let tx_root = ordered_trie_root(
Rlp::new(&body.transactions_bytes)
.iter()
.map(|r| r.as_raw()),
);
let tx_root = ordered_trie_root(Rlp::new(&body.transactions_bytes).iter().map(|r| {
if r.is_list() {
r.as_raw()
} else {
// this list is already decoded and passed validation, for this we are okay to expect proper data
r.data().expect("Expect raw transaction list to be valid")
}
}));
let uncles = keccak(&body.uncles_bytes);
HeaderId {
transactions_root: tx_root,
@@ -491,7 +497,22 @@ impl BlockCollection {
fn insert_receipt(&mut self, r: Bytes) -> Result<Vec<H256>, network::Error> {
let receipt_root = {
let receipts = Rlp::new(&r);
ordered_trie_root(receipts.iter().map(|r| r.as_raw()))
//check receipts data before calculating trie root
let mut temp_receipts: Vec<&[u8]> = Vec::new();
for receipt_byte in receipts.iter() {
if receipt_byte.is_list() {
temp_receipts.push(receipt_byte.as_raw())
} else {
temp_receipts.push(
receipt_byte
.data()
.map_err(|e| network::ErrorKind::Rlp(e))?,
);
}
}
// calculate trie root and use it as hash
ordered_trie_root(temp_receipts.iter())
};
self.downloading_receipts.remove(&receipt_root);
match self.receipt_ids.entry(receipt_root) {

View File

@@ -837,9 +837,12 @@ impl SyncHandler {
let item_count = r.item_count()?;
trace!(target: "sync", "{:02} -> Transactions ({} entries)", peer_id, item_count);
let mut transactions = Vec::with_capacity(item_count);
for i in 0..item_count {
let rlp = r.at(i)?;
let tx = rlp.as_raw().to_vec();
for i in r.iter() {
let tx = if i.is_list() {
i.as_raw().to_vec() // legacy transaction. just add it raw
} else {
i.data()?.to_vec() // typed transaction. remove header from start and send only payload.
};
transactions.push(tx);
}
io.chain().queue_transactions(transactions, peer_id);

View File

@@ -21,7 +21,7 @@ use ethereum_types::H256;
use fastmap::H256FastSet;
use network::{client_version::ClientCapabilities, PeerId};
use rand::Rng;
use rlp::{Encodable, RlpStream};
use rlp::RlpStream;
use sync_io::SyncIo;
use types::{blockchain_info::BlockChainInfo, transaction::SignedTransaction, BlockNumber};
@@ -121,7 +121,7 @@ impl SyncPropagator {
let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions
.iter()
.map(|tx| tx.signed())
.partition(|tx| !tx.gas_price.is_zero());
.partition(|tx| !tx.tx().gas_price.is_zero());
// usual transactions could be propagated to all peers
let mut affected_peers = HashSet::new();
@@ -171,7 +171,7 @@ impl SyncPropagator {
let all_transactions_rlp = {
let mut packet = RlpStream::new_list(transactions.len());
for tx in &transactions {
packet.append(&**tx);
tx.rlp_append(&mut packet);
}
packet.out()
};
@@ -238,13 +238,8 @@ impl SyncPropagator {
for tx in &transactions {
let hash = tx.hash();
if to_send.contains(&hash) {
let mut transaction = RlpStream::new();
tx.rlp_append(&mut transaction);
let appended = packet.append_raw_checked(
&transaction.drain(),
1,
MAX_TRANSACTION_PACKET_SIZE,
);
let appended =
packet.append_raw_checked(&tx.encode(), 1, MAX_TRANSACTION_PACKET_SIZE);
if !appended {
// Maximal packet size reached just proceed with sending
debug!(target: "sync", "Transaction packet size limit reached. Sending incomplete set of {}/{} transactions.", pushed, to_send.len());
@@ -373,6 +368,7 @@ mod tests {
use rlp::Rlp;
use std::collections::VecDeque;
use tests::{helpers::TestIo, snapshot::TestSnapshotService};
use types::transaction::TypedTransaction;
use super::{
super::{tests::*, *},
@@ -707,7 +703,9 @@ mod tests {
return None;
}
rlp.at(0).ok().and_then(|r| r.as_val().ok())
rlp.at(0)
.ok()
.and_then(|r| TypedTransaction::decode_rlp(&r).ok())
})
.collect();
assert_eq!(sent_transactions.len(), 2);

View File

@@ -26,18 +26,18 @@ use ethkey::{KeyPair, Secret};
use hash::keccak;
use io::{IoChannel, IoHandler};
use std::sync::Arc;
use types::transaction::{Action, PendingTransaction, Transaction};
use types::transaction::{Action, PendingTransaction, Transaction, TypedTransaction};
use SyncConfig;
fn new_tx(secret: &Secret, nonce: U256, chain_id: u64) -> PendingTransaction {
let signed = Transaction {
let signed = TypedTransaction::Legacy(Transaction {
nonce: nonce.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(Address::default()),
value: 0.into(),
data: Vec::new(),
}
})
.sign(secret, Some(chain_id));
PendingTransaction::new(signed, None)
}