Skip to content

Commit

Permalink
Add full block data for testing and benchmarking
Browse files Browse the repository at this point in the history
- Added the block 866,342 to `testdata`, as well as the spent UTXOs
- `get_validation_flags` doesn't need to ask the chainstore for the block hash
- Changed the name of the inner `validate_block` to `validate_block_no_acc`
  • Loading branch information
JoseSK999 committed Oct 25, 2024
1 parent 6a286a6 commit 2e2d96b
Show file tree
Hide file tree
Showing 4 changed files with 31,963 additions and 11 deletions.
31 changes: 30 additions & 1 deletion crates/floresta-chain/benches/chain_state_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use bitcoin::block::Header as BlockHeader;
use bitcoin::consensus::deserialize;
use bitcoin::consensus::Decodable;
use bitcoin::Block;
use bitcoin::TxOut;
use criterion::criterion_group;
use criterion::criterion_main;
use criterion::Criterion;
Expand Down Expand Up @@ -91,10 +92,38 @@ fn connect_blocks_benchmark(c: &mut Criterion) {
});
}

fn validate_full_block_benchmark(c: &mut Criterion) {
let raw_bytes = std::fs::read("./testdata/block_866342/raw").unwrap();
let block: Block = deserialize(&raw_bytes).unwrap();

// Get txos spent in the block
let str = std::fs::read_to_string("./testdata/block_866342/spent_txos.json").unwrap();
let mut stxos: Vec<TxOut> = serde_json::from_str(&str).unwrap();

let inputs: HashMap<_, _> = block
.txdata
.iter()
.skip(1) // Skip the coinbase transaction
.flat_map(|tx| &tx.input)
.map(|txin| (txin.previous_output, stxos.remove(0)))
.collect();

let chain = setup_test_chain(Network::Bitcoin, AssumeValidArg::Disabled);

c.bench_function("validate_block_866342", |b| {
b.iter(|| {
chain
.validate_block_no_acc(&block, 866342, inputs.clone())
.unwrap()
})
});
}

criterion_group!(
benches,
accept_mainnet_headers_benchmark,
accept_headers_benchmark,
connect_blocks_benchmark
connect_blocks_benchmark,
validate_full_block_benchmark
);
criterion_main!(benches);
53 changes: 43 additions & 10 deletions crates/floresta-chain/src/pruned_utreexo/chain_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,9 @@ impl<PersistedState: ChainStore> ChainState<PersistedState> {
}
#[cfg(feature = "bitcoinconsensus")]
/// Returns the validation flags, given the current block height
fn get_validation_flags(&self, height: u32) -> c_uint {
fn get_validation_flags(&self, height: u32, hash: BlockHash) -> c_uint {
let chains_params = &read_lock!(self).consensus.parameters;
let hash = read_lock!(self)
.chainstore
.get_block_hash(height)
.unwrap()
.unwrap();

if let Some(flag) = chains_params.exceptions.get(&hash) {
return *flag;
}
Expand Down Expand Up @@ -710,7 +706,12 @@ impl<PersistedState: ChainStore> ChainState<PersistedState> {
}
last_block.target()
}
fn validate_block(
/// Validates the block without checking whether the inputs are present in the UTXO set. This
/// function contains the core validation logic.
///
/// The methods `BlockchainInterface::validate_block` and `UpdatableChainstate::connect_block`
/// call this and additionally verify the inclusion proof (i.e., they perform full validation).
pub fn validate_block_no_acc(
&self,
block: &Block,
height: u32,
Expand Down Expand Up @@ -738,7 +739,7 @@ impl<PersistedState: ChainStore> ChainState<PersistedState> {
let subsidy = read_lock!(self).consensus.get_subsidy(height);
let verify_script = self.verify_script(height);
#[cfg(feature = "bitcoinconsensus")]
let flags = self.get_validation_flags(height);
let flags = self.get_validation_flags(height, block.header.block_hash());
#[cfg(not(feature = "bitcoinconsensus"))]
let flags = 0;
Consensus::verify_block_transactions(
Expand Down Expand Up @@ -804,7 +805,7 @@ impl<PersistedState: ChainStore> BlockchainInterface for ChainState<PersistedSta
.get_block_height(&block.block_hash())?
.ok_or(BlockchainError::BlockNotPresent)?;

self.validate_block(block, height, inputs)
self.validate_block_no_acc(block, height, inputs)
}

fn get_block_locator_for_tip(&self, tip: BlockHash) -> Result<Vec<BlockHash>, BlockchainError> {
Expand Down Expand Up @@ -1051,7 +1052,7 @@ impl<PersistedState: ChainStore> UpdatableChainstate for ChainState<PersistedSta
return Ok(height);
}

self.validate_block(block, height, inputs)?;
self.validate_block_no_acc(block, height, inputs)?;
let acc = Consensus::update_acc(&self.acc(), block, height, proof, del_hashes)?;

self.update_view(height, &block.header, acc)?;
Expand Down Expand Up @@ -1288,6 +1289,7 @@ mod test {
use bitcoin::hashes::hex::FromHex;
use bitcoin::Block;
use bitcoin::BlockHash;
use bitcoin::TxOut;
use rand::Rng;
use rustreexo::accumulator::proof::Proof;

Expand All @@ -1311,6 +1313,37 @@ mod test {
ChainState::new(chainstore, network, assume_valid_arg)
}

#[test]
fn test_validate_block() {
let raw_bytes = std::fs::read("./testdata/block_866342/raw").unwrap();
let block: Block = deserialize(&raw_bytes).unwrap();

assert_eq!(
block.block_hash(),
BlockHash::from_str("000000000000000000014ce9ba7c6760053c3c82ce6ab43d60afb101d3c8f1f1")
.unwrap(),
);

// Get txos spent in the block
let str = std::fs::read_to_string("./testdata/block_866342/spent_txos.json").unwrap();
let mut stxos: Vec<TxOut> = serde_json::from_str(&str).unwrap();

let inputs = block
.txdata
.iter()
.skip(1) // Skip the coinbase transaction
.flat_map(|tx| &tx.input)
.map(|txin| (txin.previous_output, stxos.remove(0)))
.collect();

assert!(stxos.is_empty(), "Moved all stxos to the inputs map");

// Check whether the block validation passes or not
let chain = setup_test_chain(Network::Bitcoin, AssumeValidArg::Disabled);
chain
.validate_block_no_acc(&block, 866342, inputs)
.expect("Block must be valid");
}
#[test]
fn accept_mainnet_headers() {
// Accepts the first 10235 mainnet headers
Expand Down
Binary file added crates/floresta-chain/testdata/block_866342/raw
Binary file not shown.
Loading

0 comments on commit 2e2d96b

Please sign in to comment.