Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: resolve cell filter bug when chain txs are committed in same block #184

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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());
}
Loading