use super::helper::{build_chain, new_transaction};
use crate::relayer::packed::{CellInput, OutPoint};
use crate::relayer::ReconstructionResult;
use crate::StatusCode;
use ckb_tx_pool::{PlugTarget, TxEntry};
use ckb_types::prelude::*;
use ckb_types::{
core::{BlockBuilder, Capacity, TransactionView},
packed::{self, CompactBlockBuilder},
};
use std::collections::HashSet;
#[test]
fn test_missing_txs() {
let (relayer, always_success_out_point) = build_chain(5);
let prepare: Vec<TransactionView> = (0..20)
.map(|i| new_transaction(&relayer, i, &always_success_out_point))
.collect();
{
let compact_block_builder = CompactBlockBuilder::default();
let short_ids = prepare.iter().map(|tx| tx.proposal_short_id());
let transactions: Vec<TransactionView> = prepare.iter().skip(1).cloned().collect();
let compact = compact_block_builder.short_ids(short_ids.pack()).build();
assert_eq!(
relayer.reconstruct_block(
&relayer.shared().active_chain(),
&compact,
transactions,
&[],
&[]
),
ReconstructionResult::Missing(vec![0], vec![]),
);
}
{
let compact_block_builder = CompactBlockBuilder::default();
let short_ids = prepare.iter().map(|tx| tx.proposal_short_id());
let transactions: Vec<TransactionView> =
prepare.iter().skip(1).step_by(2).cloned().collect();
let missing = prepare
.iter()
.enumerate()
.step_by(2)
.map(|(i, _)| i)
.collect();
let compact = compact_block_builder.short_ids(short_ids.pack()).build();
assert_eq!(
relayer.reconstruct_block(
&relayer.shared().active_chain(),
&compact,
transactions,
&[],
&[]
),
ReconstructionResult::Missing(missing, vec![]),
);
}
}
#[test]
fn test_reconstruct_transactions_and_uncles() {
let (relayer, always_success_out_point) = build_chain(5);
let parent = new_transaction(&relayer, 0, &always_success_out_point);
let mut prepare = vec![parent];
while prepare.len() <= 20 {
let parent = prepare.last().unwrap();
let child = parent
.as_advanced_builder()
.set_inputs(vec![{
CellInput::new_builder()
.previous_output(OutPoint::new(parent.hash(), 0))
.build()
}])
.set_outputs(vec![parent.output(0).unwrap()])
.build();
prepare.push(child);
}
let uncle = BlockBuilder::default().build();
let block = BlockBuilder::default()
.transactions(prepare.clone())
.uncles(vec![uncle.as_uncle()])
.build();
let uncle_hash = uncle.hash();
let (short_transactions, prefilled) = {
let short_transactions: Vec<TransactionView> = prepare.iter().step_by(2).cloned().collect();
let prefilled: HashSet<usize> = prepare
.iter()
.enumerate()
.skip(1)
.step_by(2)
.map(|(i, _)| i)
.collect();
(short_transactions, prefilled)
};
let ext = packed::BlockExtBuilder::default()
.verified(Some(true).pack())
.build();
let compact = packed::CompactBlock::build_from_block(&block, &prefilled);
let (pool_transactions, short_transactions) = short_transactions.split_at(2);
let short_transactions: Vec<TransactionView> = short_transactions.to_vec();
let entries = pool_transactions
.iter()
.cloned()
.map(|tx| TxEntry::dummy_resolve(tx, 0, Capacity::shannons(0), 0))
.collect();
relayer
.shared
.shared()
.tx_pool_controller()
.plug_entry(entries, PlugTarget::Pending)
.unwrap();
{
let db_txn = relayer.shared().shared().store().begin_transaction();
db_txn.insert_block(&uncle).unwrap();
db_txn.insert_block_ext(&uncle_hash, &ext.unpack()).unwrap();
db_txn.commit().unwrap();
}
relayer.shared().shared().refresh_snapshot();
let ret = relayer.reconstruct_block(
&relayer.shared().active_chain(),
&compact,
short_transactions,
&[],
&[],
);
assert_eq!(ret, ReconstructionResult::Block(block), "{ret:?}");
}
#[test]
fn test_reconstruct_invalid_uncles() {
let (relayer, _) = build_chain(5);
let uncle = BlockBuilder::default().build();
let ext = packed::BlockExtBuilder::default()
.verified(Some(false).pack())
.build();
let block = BlockBuilder::default()
.uncles(vec![uncle.as_uncle()])
.build();
let uncle_hash = uncle.hash();
let compact = packed::CompactBlock::build_from_block(&block, &Default::default());
{
let db_txn = relayer.shared().shared().store().begin_transaction();
db_txn.insert_block(&uncle).unwrap();
db_txn.attach_block(&uncle).unwrap();
db_txn.insert_block_ext(&uncle_hash, &ext.unpack()).unwrap();
db_txn.commit().unwrap();
}
relayer.shared().shared().refresh_snapshot();
assert_eq!(
relayer.reconstruct_block(&relayer.shared().active_chain(), &compact, vec![], &[], &[]),
ReconstructionResult::Error(StatusCode::CompactBlockHasInvalidUncle.into()),
);
}