11use anyhow:: anyhow;
2-
32use std:: { cmp:: Ordering , collections:: HashSet , convert:: TryFrom } ;
43
54use ckb_types:: {
@@ -9,11 +8,27 @@ use ckb_types::{
98 prelude:: * ,
109} ;
1110
12- use crate :: types:: omni_lock:: OmniLockWitnessLock ;
1311use crate :: { traits:: TransactionDependencyProvider , unlock:: omni_lock:: OmniLockFlags } ;
12+ use crate :: {
13+ tx_builder:: { gen_script_groups, ScriptGroups } ,
14+ types:: omni_lock:: OmniLockWitnessLock ,
15+ } ;
1416
1517use super :: OpenTxError ;
1618
19+ /// Check if different
20+ fn check_script_groups ( group_vec : & [ ScriptGroups ] ) -> Result < ( ) , OpenTxError > {
21+ let mut keys = HashSet :: new ( ) ;
22+ for group in group_vec. iter ( ) {
23+ let len = keys. len ( ) ;
24+ keys. extend ( group. lock_groups . keys ( ) . clone ( ) ) ;
25+ if len + group. lock_groups . len ( ) > keys. len ( ) {
26+ return Err ( OpenTxError :: SameLockInDifferentOpenTx ) ;
27+ }
28+ }
29+ Ok ( ( ) )
30+ }
31+
1732/// Assemble a transaction from multiple opentransaction, remove duplicate cell deps and header deps.
1833/// Alter base input/output index.
1934pub fn assemble_new_tx (
@@ -29,21 +44,33 @@ pub fn assemble_new_tx(
2944 let mut header_deps = HashSet :: new ( ) ;
3045 let mut base_input_idx = 0usize ;
3146 let mut base_output_idx = 0usize ;
47+ let mut base_input_cap = 0usize ;
48+ let mut base_output_cap = 0usize ;
49+ let group_vec: Result < Vec < _ > , _ > = transactions
50+ . iter ( )
51+ . map ( |tx| gen_script_groups ( tx, provider) )
52+ . collect ( ) ;
53+ let group_vec = group_vec?;
54+ check_script_groups ( & group_vec) ?;
3255 for tx in transactions. iter ( ) {
3356 cell_deps. extend ( tx. cell_deps ( ) ) ;
3457 header_deps. extend ( tx. header_deps ( ) ) ;
3558 builder = builder. inputs ( tx. inputs ( ) ) ;
59+ base_input_cap += tx. inputs ( ) . len ( ) ;
60+ base_output_cap += tx. outputs ( ) . len ( ) ;
3661 // Handle opentx witness
3762 for ( input, witness) in tx. inputs ( ) . into_iter ( ) . zip ( tx. witnesses ( ) . into_iter ( ) ) {
3863 let lock = provider. get_cell ( & input. previous_output ( ) ) ?. lock ( ) ;
3964 let code_hash = lock. code_hash ( ) ;
40- if code_hash. cmp ( & opentx_code_hash) == Ordering :: Equal {
65+ // empty witness should be in a script group
66+ if !witness. is_empty ( ) && code_hash. cmp ( & opentx_code_hash) == Ordering :: Equal {
4167 let args = & lock. args ( ) . raw_data ( ) ;
42- if args. len ( ) >= 22
68+ let witness_data = witness. raw_data ( ) ;
69+ if witness_data. len ( ) > 8 // sizeof base_input + sizeof base_output
70+ && args. len ( ) >= 22
4371 && OmniLockFlags :: from_bits_truncate ( args[ 21 ] ) . contains ( OmniLockFlags :: OPENTX )
4472 {
4573 // Parse lock data
46- let witness_data = witness. raw_data ( ) ;
4774 let current_witness: WitnessArgs =
4875 WitnessArgs :: from_slice ( witness_data. as_ref ( ) ) ?;
4976 let lock_field = current_witness
@@ -64,11 +91,17 @@ pub fn assemble_new_tx(
6491 tmp. copy_from_slice ( & data[ 0 ..4 ] ) ;
6592 let this_base_input_idx = u32:: from_le_bytes ( tmp)
6693 + u32:: try_from ( base_input_idx) . map_err ( |e| anyhow ! ( e) ) ?;
94+ if this_base_input_idx as usize > base_input_cap {
95+ return Err ( OpenTxError :: BaseInputIndexOverFlow ) ;
96+ }
6797 data[ 0 ..4 ] . copy_from_slice ( & this_base_input_idx. to_le_bytes ( ) ) ;
6898
6999 tmp. copy_from_slice ( & data[ 4 ..8 ] ) ;
70100 let this_base_output_idx = u32:: from_le_bytes ( tmp)
71101 + u32:: try_from ( base_output_idx) . map_err ( |e| anyhow ! ( e) ) ?;
102+ if this_base_output_idx as usize > base_output_cap {
103+ return Err ( OpenTxError :: BaseOutputIndexOverFlow ) ;
104+ }
72105 data[ 4 ..8 ] . copy_from_slice ( & this_base_output_idx. to_le_bytes ( ) ) ;
73106
74107 let omnilock_witnesslock = omnilock_witnesslock
0 commit comments