From 5d460ff112be94871805403a913b474ea72f1a3b Mon Sep 17 00:00:00 2001 From: quake Date: Sat, 20 Jan 2024 11:50:27 +0800 Subject: [PATCH] fix: resolve cell filter bug when chain txs are committed in same block --- src/storage.rs | 8 +++- src/tests/service.rs | 111 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/src/storage.rs b/src/storage.rs index ba8ccb6..a1d3727 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -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 = HashMap::new(); block .transactions() .into_iter() @@ -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) = @@ -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(); diff --git a/src/tests/service.rs b/src/tests/service.rs index a8fcfb2..e868b07 100644 --- a/src/tests/service.rs +++ b/src/tests/service.rs @@ -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()); +}