Skip to content

Commit

Permalink
Merge pull request #184 from quake/quake/fix-chain-tx-in-same-block-bug
Browse files Browse the repository at this point in the history
fix: resolve cell filter bug when chain txs are committed in same block
  • Loading branch information
quake authored Jan 22, 2024
2 parents 5fc2a81 + 5d460ff commit 789b08c
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@ impl Storage {
let block_number: BlockNumber = block.header().raw().number().unpack();
let mut filter_matched = false;
let mut batch = self.batch();
let mut txs: HashMap<Byte32, (u32, Transaction)> = HashMap::new();
block
.transactions()
.into_iter()
Expand All @@ -675,11 +676,14 @@ impl Storage {
.into_iter()
.enumerate()
.for_each(|(input_index, input)| {
let previous_tx_hash = input.previous_output().tx_hash();
if let Some((
generated_by_block_number,
generated_by_tx_index,
previous_tx,
)) = self.get_transaction(&input.previous_output().tx_hash())
)) = self.get_transaction(&previous_tx_hash).or(txs
.get(&previous_tx_hash)
.map(|(tx_index, tx)| (block_number, *tx_index, tx.clone())))
{
let previous_output_index = input.previous_output().index().unpack();
if let Some(previous_output) =
Expand Down Expand Up @@ -827,6 +831,8 @@ impl Storage {
}
}
});

txs.insert(tx.calc_tx_hash(), (tx_index as u32, tx));
});
if filter_matched {
let block_hash = block.calc_header_hash();
Expand Down
111 changes: 111 additions & 0 deletions src/tests/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1538,3 +1538,114 @@ fn test_set_scripts_partial_min_filtered_block_number_bug() {
// min_filtered_block_number should be same as before when storage scripts is not empty
assert_eq!(storage.get_min_filtered_block_number(), 1234,);
}

#[test]
fn test_chain_txs_in_same_block_bug() {
let storage = new_storage("chain_txs_in_same_block_bug");
let swc = StorageWithChainData::new(storage.clone(), create_peers());
let rpc = BlockFilterRpcImpl { swc };

// setup test data
let lock_script1 = ScriptBuilder::default()
.code_hash(H256(rand::random()).pack())
.hash_type(ScriptHashType::Data.into())
.args(Bytes::from(b"lock_script1".to_vec()).pack())
.build();

let lock_script2 = ScriptBuilder::default()
.code_hash(H256(rand::random()).pack())
.hash_type(ScriptHashType::Data.into())
.args(Bytes::from(b"lock_script2".to_vec()).pack())
.build();

let tx00 = TransactionBuilder::default()
.output(
CellOutputBuilder::default()
.capacity(capacity_bytes!(222).pack())
.lock(lock_script1.clone())
.build(),
)
.output(
CellOutputBuilder::default()
.capacity(capacity_bytes!(333).pack())
.lock(lock_script1.clone())
.build(),
)
.output_data(Default::default())
.output_data(Default::default())
.build();

let block0 = BlockBuilder::default()
.transaction(tx00.clone())
.header(
HeaderBuilder::default()
.epoch(EpochNumberWithFraction::new(0, 0, 1000).pack())
.number(0.pack())
.build(),
)
.build();
storage.init_genesis_block(block0.data());
storage.update_filter_scripts(
vec![
storage::ScriptStatus {
script: lock_script1.clone(),
script_type: storage::ScriptType::Lock,
block_number: 0,
},
storage::ScriptStatus {
script: lock_script2.clone(),
script_type: storage::ScriptType::Lock,
block_number: 0,
},
],
Default::default(),
);

let tx10 = TransactionBuilder::default()
.output(
CellOutputBuilder::default()
.capacity(capacity_bytes!(100).pack())
.lock(lock_script2.clone())
.build(),
)
.output_data(Default::default())
.build();

let tx11 = TransactionBuilder::default()
.input(CellInput::new(OutPoint::new(tx10.hash(), 0), 0))
.output(
CellOutputBuilder::default()
.capacity(capacity_bytes!(100).pack())
.lock(lock_script2.clone())
.build(),
)
.output_data(Default::default())
.build();

let block1 = BlockBuilder::default()
.transaction(tx10)
.transaction(tx11)
.header(
HeaderBuilder::default()
.epoch(EpochNumberWithFraction::new(0, 1, 1000).pack())
.number(1.pack())
.build(),
)
.build();
storage.filter_block(block1.data());
storage.update_block_number(1);

let cells_page_1 = rpc
.get_cells(
SearchKey {
script: lock_script2.into(),
..Default::default()
},
Order::Asc,
150.into(),
None,
)
.unwrap();

assert_eq!(1, cells_page_1.objects.len());
}

0 comments on commit 789b08c

Please sign in to comment.