v2.5.8-stable (#11041)
* add more tx tests (#11038) * Fix parallel transactions race-condition (#10995) * Add blake2_f precompile (#11017) * [trace] introduce trace failed to Ext (#11019) * Edit publish-onchain.sh to use https (#11016) * Fix deadlock in network-devp2p (#11013) * EIP 1108: Reduce alt_bn128 precompile gas costs (#11008) * xDai chain support and nodes list update (#10989) * EIP 2028: transaction gas lowered from 68 to 16 (#10987) * EIP-1344 Add CHAINID op-code (#10983) * manual publish jobs for releases, no changes for nightlies (#10977) * [blooms-db] Fix benchmarks (#10974) * Verify transaction against its block during import (#10954) * Better error message for rpc gas price errors (#10931) * tx-pool: accept local tx with higher gas price when pool full (#10901) * Fix fork choice (#10837) * Cleanup unused vm dependencies (#10787) * Fix compilation on recent nightlies (#10991)
This commit is contained in:
@@ -713,6 +713,10 @@ impl BlockChain {
|
||||
///
|
||||
/// If the tree route verges into pruned or unknown blocks,
|
||||
/// `None` is returned.
|
||||
///
|
||||
/// `is_from_route_finalized` returns whether the `from` part of the
|
||||
/// route contains a finalized block. This only holds if the two parts (from
|
||||
/// and to) are on different branches, ie. on 2 different forks.
|
||||
pub fn tree_route(&self, from: H256, to: H256) -> Option<TreeRoute> {
|
||||
let mut from_branch = vec![];
|
||||
let mut is_from_route_finalized = false;
|
||||
@@ -726,9 +730,9 @@ impl BlockChain {
|
||||
// reset from && to to the same level
|
||||
while from_details.number > to_details.number {
|
||||
from_branch.push(current_from);
|
||||
is_from_route_finalized = is_from_route_finalized || from_details.is_finalized;
|
||||
current_from = from_details.parent.clone();
|
||||
from_details = self.block_details(&from_details.parent)?;
|
||||
is_from_route_finalized = is_from_route_finalized || from_details.is_finalized;
|
||||
}
|
||||
|
||||
while to_details.number > from_details.number {
|
||||
@@ -742,9 +746,9 @@ impl BlockChain {
|
||||
// move to shared parent
|
||||
while current_from != current_to {
|
||||
from_branch.push(current_from);
|
||||
is_from_route_finalized = is_from_route_finalized || from_details.is_finalized;
|
||||
current_from = from_details.parent.clone();
|
||||
from_details = self.block_details(&from_details.parent)?;
|
||||
is_from_route_finalized = is_from_route_finalized || from_details.is_finalized;
|
||||
|
||||
to_branch.push(current_to);
|
||||
current_to = to_details.parent.clone();
|
||||
@@ -2491,4 +2495,74 @@ mod tests {
|
||||
assert_eq!(bc.epoch_transition_for(fork_hash).unwrap().block_number, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tree_rout_with_finalization() {
|
||||
let genesis = BlockBuilder::genesis();
|
||||
let a = genesis.add_block();
|
||||
// First branch
|
||||
let a1 = a.add_block_with_random_transactions();
|
||||
let a2 = a1.add_block_with_random_transactions();
|
||||
let a3 = a2.add_block_with_random_transactions();
|
||||
// Second branch
|
||||
let b1 = a.add_block_with_random_transactions();
|
||||
let b2 = b1.add_block_with_random_transactions();
|
||||
|
||||
let a_hash = a.last().hash();
|
||||
let a1_hash = a1.last().hash();
|
||||
let a2_hash = a2.last().hash();
|
||||
let a3_hash = a3.last().hash();
|
||||
let b2_hash = b2.last().hash();
|
||||
|
||||
let bootstrap_chain = |blocks: Vec<&BlockBuilder>| {
|
||||
let db = new_db();
|
||||
let bc = new_chain(genesis.last().encoded(), db.clone());
|
||||
let mut batch = db.key_value().transaction();
|
||||
for block in blocks {
|
||||
insert_block_batch(&mut batch, &bc, block.last().encoded(), vec![]);
|
||||
bc.commit();
|
||||
}
|
||||
db.key_value().write(batch).unwrap();
|
||||
(db, bc)
|
||||
};
|
||||
|
||||
let mark_finalized = |block_hash: H256, db: &Arc<dyn BlockChainDB>, bc: &BlockChain| {
|
||||
let mut batch = db.key_value().transaction();
|
||||
bc.mark_finalized(&mut batch, block_hash).unwrap();
|
||||
bc.commit();
|
||||
db.key_value().write(batch).unwrap();
|
||||
};
|
||||
|
||||
// Case 1: fork, with finalized common ancestor
|
||||
{
|
||||
let (db, bc) = bootstrap_chain(vec![&a, &a1, &a2, &a3, &b1, &b2]);
|
||||
assert_eq!(bc.best_block_hash(), a3_hash);
|
||||
assert_eq!(bc.block_hash(2).unwrap(), a1_hash);
|
||||
|
||||
mark_finalized(a_hash, &db, &bc);
|
||||
assert!(!bc.tree_route(a3_hash, b2_hash).unwrap().is_from_route_finalized);
|
||||
assert!(!bc.tree_route(b2_hash, a3_hash).unwrap().is_from_route_finalized);
|
||||
}
|
||||
|
||||
// Case 2: fork with a finalized block on a branch
|
||||
{
|
||||
let (db, bc) = bootstrap_chain(vec![&a, &a1, &a2, &a3, &b1, &b2]);
|
||||
assert_eq!(bc.best_block_hash(), a3_hash);
|
||||
assert_eq!(bc.block_hash(2).unwrap(), a1_hash);
|
||||
|
||||
mark_finalized(a2_hash, &db, &bc);
|
||||
assert!(bc.tree_route(a3_hash, b2_hash).unwrap().is_from_route_finalized);
|
||||
assert!(!bc.tree_route(b2_hash, a3_hash).unwrap().is_from_route_finalized);
|
||||
}
|
||||
|
||||
// Case 3: no-fork, with a finalized block
|
||||
{
|
||||
let (db, bc) = bootstrap_chain(vec![&a, &a1, &a2]);
|
||||
assert_eq!(bc.best_block_hash(), a2_hash);
|
||||
|
||||
mark_finalized(a1_hash, &db, &bc);
|
||||
assert!(!bc.tree_route(a1_hash, a2_hash).unwrap().is_from_route_finalized);
|
||||
assert!(!bc.tree_route(a2_hash, a1_hash).unwrap().is_from_route_finalized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,13 @@ use ethereum_types::{U256, H256, Bloom};
|
||||
|
||||
use common_types::encoded;
|
||||
use common_types::header::Header;
|
||||
use common_types::transaction::SignedTransaction;
|
||||
use common_types::transaction::{SignedTransaction, Transaction, Action};
|
||||
use common_types::view;
|
||||
use common_types::views::BlockView;
|
||||
use keccak_hash::keccak;
|
||||
use rlp::encode;
|
||||
use rlp_derive::RlpEncodable;
|
||||
use triehash_ethereum::ordered_trie_root;
|
||||
|
||||
/// Helper structure, used for encoding blocks.
|
||||
#[derive(Default, Clone, RlpEncodable)]
|
||||
@@ -136,6 +138,29 @@ impl BlockBuilder {
|
||||
})
|
||||
}
|
||||
|
||||
/// Add a block with randomly generated transactions.
|
||||
#[inline]
|
||||
pub fn add_block_with_random_transactions(&self) -> Self {
|
||||
// Maximum of ~50 transactions
|
||||
let count = rand::random::<u8>() as usize / 5;
|
||||
let transactions = std::iter::repeat_with(|| {
|
||||
let data_len = rand::random::<u8>();
|
||||
let data = std::iter::repeat_with(|| rand::random::<u8>())
|
||||
.take(data_len as usize)
|
||||
.collect::<Vec<_>>();
|
||||
Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data,
|
||||
}.sign(&keccak("").into(), None)
|
||||
}).take(count);
|
||||
|
||||
self.add_block_with_transactions(transactions)
|
||||
}
|
||||
|
||||
/// Add a block with given transactions.
|
||||
#[inline]
|
||||
pub fn add_block_with_transactions<T>(&self, transactions: T) -> Self
|
||||
@@ -166,11 +191,15 @@ impl BlockBuilder {
|
||||
let mut block = Block::default();
|
||||
let metadata = get_metadata();
|
||||
let block_number = parent_number + 1;
|
||||
let transactions = metadata.transactions;
|
||||
let transactions_root = ordered_trie_root(transactions.iter().map(rlp::encode));
|
||||
|
||||
block.header.set_parent_hash(parent_hash);
|
||||
block.header.set_number(block_number);
|
||||
block.header.set_log_bloom(metadata.bloom);
|
||||
block.header.set_difficulty(metadata.difficulty);
|
||||
block.transactions = metadata.transactions;
|
||||
block.header.set_transactions_root(transactions_root);
|
||||
block.transactions = transactions;
|
||||
|
||||
parent_hash = block.hash();
|
||||
parent_number = block_number;
|
||||
|
||||
Reference in New Issue
Block a user