diff --git a/src/ballet/pack/fd_pack.c b/src/ballet/pack/fd_pack.c index fc1b010613..c2bf9f708a 100644 --- a/src/ballet/pack/fd_pack.c +++ b/src/ballet/pack/fd_pack.c @@ -620,11 +620,10 @@ fd_pack_insert_txn_fini( fd_pack_t * pack, ord->expires_at = expires_at; - fd_txn_acct_iter_t ctrl[1]; int writes_to_sysvar = 0; - for( ulong i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE & FD_TXN_ACCT_CAT_IMM, ctrl ); irw_bitset ); FD_PACK_BITSET_CLEAR( ord->w_bitset ); - for( ulong i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE & FD_TXN_ACCT_CAT_IMM, ctrl ); iacct_to_bitset, accts[i], NULL ); + for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE & FD_TXN_ACCT_CAT_IMM ); + iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) { + fd_acct_addr_t acct = accts[fd_txn_acct_iter_idx( iter )]; + fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct, NULL ); if( FD_UNLIKELY( q==NULL ) ) { - q = bitset_map_insert( pack->acct_to_bitset, accts[i] ); + q = bitset_map_insert( pack->acct_to_bitset, acct ); q->ref_cnt = 0UL; q->first_instance = ord; q->first_instance_was_write = 1; @@ -692,13 +692,15 @@ fd_pack_insert_txn_fini( fd_pack_t * pack, FD_PACK_BITSET_SETN( ord->w_bitset , q->bit ); } - for( ulong i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY & FD_TXN_ACCT_CAT_IMM, ctrl ); iacct_to_bitset, accts[i], NULL ); + fd_acct_addr_t acct = accts[fd_txn_acct_iter_idx( iter )]; + if( FD_UNLIKELY( fd_pack_unwritable_contains( &acct ) ) ) continue; + + fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct, NULL ); if( FD_UNLIKELY( q==NULL ) ) { - q = bitset_map_insert( pack->acct_to_bitset, accts[i] ); + q = bitset_map_insert( pack->acct_to_bitset, acct ); q->ref_cnt = 0UL; q->first_instance = ord; q->first_instance_was_write = 0; @@ -807,11 +809,12 @@ fd_pack_schedule_microblock_impl( fd_pack_t * pack, } if( FD_PACK_BITSET_INTERSECT4_EMPTY( bitset_rw_in_use, bitset_w_in_use, cur->w_bitset, cur->rw_bitset ) ) { - fd_txn_acct_iter_t ctrl[1]; /* Check conflicts between this transaction's writable accounts and current readers */ - for( ulong i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE & FD_TXN_ACCT_CAT_IMM, ctrl ); itotal_cost+cur->compute_est > FD_PACK_MAX_WRITE_COST_PER_ACCT ) { @@ -827,8 +830,10 @@ fd_pack_schedule_microblock_impl( fd_pack_t * pack, /* Check conflicts between this transaction's readonly accounts and current writers */ - for( ulong i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY & FD_TXN_ACCT_CAT_IMM, ctrl ); iflags = cur->txn->flags; out++; - fd_txn_acct_iter_t ctrl[1]; - for( ulong i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE & FD_TXN_ACCT_CAT_IMM, ctrl ); itotal_cost = 0UL; } @@ -871,7 +875,7 @@ fd_pack_schedule_microblock_impl( fd_pack_t * pack, use_by_bank[use_by_bank_cnt++] = *use; - fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct[i], NULL ); + fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct_addr, NULL ); if( FD_UNLIKELY( !(--q->ref_cnt) ) ) { ushort bit = q->bit; bitset_map_remove( pack->acct_to_bitset, q ); @@ -886,11 +890,12 @@ fd_pack_schedule_microblock_impl( fd_pack_t * pack, if( FD_LIKELY( bitbitset_avail[ ++(pack->bitset_avail_cnt) ] = bit; } } - for( ulong i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY & FD_TXN_ACCT_CAT_IMM, ctrl ); iin_use_by = 0UL; } @@ -898,7 +903,7 @@ fd_pack_schedule_microblock_impl( fd_pack_t * pack, if( !(use->in_use_by & bank_tile_mask) ) use_by_bank[use_by_bank_cnt++] = *use; use->in_use_by |= bank_tile_mask; - fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct[i], NULL ); + fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct_addr, NULL ); if( FD_UNLIKELY( !(--q->ref_cnt) ) ) { ushort bit = q->bit; bitset_map_remove( pack->acct_to_bitset, q ); @@ -1196,9 +1201,9 @@ fd_pack_delete_transaction( fd_pack_t * pack, fd_txn_t * _txn = TXN( containing->txn ); fd_acct_addr_t const * accts = fd_txn_get_acct_addrs( _txn, containing->txn->payload ); - fd_txn_acct_iter_t ctrl[1]; - for( ulong i=fd_txn_acct_iter_init( _txn, FD_TXN_ACCT_CAT_WRITABLE & FD_TXN_ACCT_CAT_IMM, ctrl ); iacct_to_bitset, accts[i], NULL ); FD_TEST( q ); /* q==NULL not be possible */ @@ -1217,8 +1222,10 @@ fd_pack_delete_transaction( fd_pack_t * pack, } } } - for( ulong i=fd_txn_acct_iter_init( _txn, FD_TXN_ACCT_CAT_READONLY & FD_TXN_ACCT_CAT_IMM, ctrl ); iacct_to_bitset, accts[i], NULL ); diff --git a/src/ballet/pack/test_pack.c b/src/ballet/pack/test_pack.c index 45c755040c..8027f9b601 100644 --- a/src/ballet/pack/test_pack.c +++ b/src/ballet/pack/test_pack.c @@ -227,17 +227,18 @@ schedule_validate_microblock( fd_pack_t * pack, total_rewards += rewards; fd_acct_addr_t const * acct = fd_txn_get_acct_addrs( txn, txnp->payload ); - fd_txn_acct_iter_t ctrl[1]; - for( ulong j=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM, ctrl ); jsignature_cnt; + ulong q = txn->readonly_signed_cnt; + ulong r = txn->readonly_unsigned_cnt; + ulong a = txn->acct_addr_cnt; + ulong t = txn->addr_table_adtl_cnt; + ulong u = txn->addr_table_adtl_writable_cnt; + + /* All the branches here should be known at compile time. */ + /* If WRITABLE_SIGNER is included, then f>>1 is 0, so the second + branch will always be true, setting control[0]=0. */ +# define INCLUDE_RANGE(f, start, cnt) \ + if( include_cat & (f) ) { \ + if( !(include_cat & ((f)>>1) ) ) control[ ++i ]=(start); \ + control[ i ] += (cnt)<<8; \ + } -static inline ulong -fd_txn_acct_iter_init( fd_txn_t * txn, - int include_cat, - ulong * ctrl ) { - /* Our goal is to output something that looks like [end0-1, start1-1, - end1-1, start2-1, end2-1, don't care, don't care, don't care], but - we initially construct [255, 255, start0-1, end0-1, start1-1, - end1-1, start2-1, end2-1]. If include_cat==0 and we don't end up - doing anything below, then this is the right answer. Otherwise, - we'll immediately advance to the next interval when we compare with - it. */ - union { - uchar control[9]; /* The last dummy write might be to [8]. We want - to ignore it in that case. */ - ulong _ctrl; - } u; - u._ctrl = ULONG_MAX; - ulong i = 0; - - /* One less than the start and end of the account address indices - corresponding to the category r. Starting these at -1 handles all - the -1's necessary. */ - ulong start = (ulong)(-1L); - ulong end = (ulong)(-1L); - - /* Note: This has to be invoked in the account address index order */ -# define EXTEND_REGION( r ) \ - do{ \ - ulong cnt = fd_txn_account_cnt( txn, r ); \ - start = end; \ - end += cnt; \ - /* If cnt==0, we want to do nothing. The easiest way to do that is \ - to make the interval [endi, endi). */ \ - ulong endi = (ulong)u.control[2*i+1]; \ - ulong _start = fd_ulong_if( cnt>0, start, endi ); \ - ulong _end = fd_ulong_if( cnt>0, end, endi ); \ - if( include_cat & r ) { /* Hopefully a compile-time const */ \ - /* If the start of this sub-interval equals the end of the current \ - interval, then we just extend the interval. This next write is \ - a dummy in that case (overwritten before being read) but saves \ - a branch. If it is not, then we write the current start and \ - end as the next interval and advance i. */ \ - u.control[2*i+2] = (uchar)_start; \ - i = fd_ulong_if( endi==_start, i, i+1 ); \ - u.control[2*i+1] = (uchar)_end; \ - } \ - } while( 0 ) - - EXTEND_REGION( FD_TXN_ACCT_CAT_WRITABLE_SIGNER ); - EXTEND_REGION( FD_TXN_ACCT_CAT_READONLY_SIGNER ); - EXTEND_REGION( FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM ); - EXTEND_REGION( FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM ); - /* FIXME: Right now we don't have a way of iterating over addresses in - lookup tables. */ - EXTEND_REGION( FD_TXN_ACCT_CAT_WRITABLE_ALT ); - EXTEND_REGION( FD_TXN_ACCT_CAT_READONLY_ALT ); -#undef EXTEND_REGION - - /* Undo last dummy write. In the worst case, i==3 at this point, so - we might write to u.control[8], but we don't care about that write - then. */ - u.control[2*i+2] = (uchar)0xFF; - - *ctrl = (0xFFFFFFUL<<40) | (u._ctrl >> 24); - ulong start0 = ((ulong)u.control[2] + 1UL) & 0xFFUL; /* Do the arithmetic as uchars so that 0xFF -> 0 */ - return fd_ulong_if( i==0UL, 256UL, start0 ); + INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_SIGNER, 0, s-q ); + INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_SIGNER, s-q, q ); + INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM, s, a-r-s ); + INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM, a-r, r ); + INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_ALT, a, u ); + INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_ALT, a+u, t-u ); +# undef INCLUDE_RANGE + + /* We now need to delete the empty intervals (if any). */ + ulong control0 = control[0]; + ulong control1 = control[1]; + ulong control2 = control[2]; + + int control2_empty = !(control2&0xFF00UL); + control2 = fd_ulong_if( control2_empty, 0UL, control2 ); + + int control1_empty = !(control1&0xFF00UL); + control1 = fd_ulong_if( control1_empty, control2, control1 ); + control2 = fd_ulong_if( control1_empty, 0UL, control2 ); + + int control0_empty = !(control0&0xFF00UL); + control0 = fd_ulong_if( control0_empty, control1, control0 ); + control1 = fd_ulong_if( control0_empty, control2, control1 ); + control2 = fd_ulong_if( control0_empty, 0UL, control2 ); + + return control0 | (control1<<16) | (control2<<32); } -static inline ulong -fd_txn_acct_iter_next( ulong cur, - ulong * _ctrl ) { - ulong control = *_ctrl; - ulong end = control & 0xFF; /* this is end-1, as explained above, but - the interval is half-open */ - ulong next_start = ((control>>8)&0xFFUL)+1UL; - *_ctrl = fd_ulong_if( cur==end, control>>16, control ); - return fd_ulong_if( cur==end, next_start, cur+1UL ); +static inline fd_txn_acct_iter_t FD_FN_CONST +fd_txn_acct_iter_next( fd_txn_acct_iter_t cur ) { + cur = cur + 0x0001UL - 0x0100UL; /* Increment low byte, decrement count */ + /* Move to the next interval if we're done with this one. */ + return fd_ulong_if( cur&0xFF00UL, cur, cur>>16 ); } -static inline ulong FD_FN_CONST fd_txn_acct_iter_end( void ) { return FD_TXN_ACCT_ADDR_MAX; } +static inline fd_txn_acct_iter_t FD_FN_CONST fd_txn_acct_iter_end( void ) { return 0UL; } +static inline ulong FD_FN_CONST fd_txn_acct_iter_idx( fd_txn_acct_iter_t cur ) { return cur & 0xFFUL; } /* fd_txn_parse_core: Parses a transaction from the canonical encoding, i.e. the format used on the wire. diff --git a/src/ballet/txn/test_txn.c b/src/ballet/txn/test_txn.c index 45f196064a..3fde62bf1f 100644 --- a/src/ballet/txn/test_txn.c +++ b/src/ballet/txn/test_txn.c @@ -106,101 +106,101 @@ test_iter( fd_txn_t * txn, ulong wa, ulong ra ) { - ulong expected[128]; + ulong expected[128] = { 0 }; ulong expected_cnt = 0UL; - fd_txn_acct_iter_t ctrl; - ulong i; + fd_txn_acct_iter_t i; - ulong j, _j; + ulong j=0UL, _j=0UL; #define RESET() j=0UL; _j=0UL; expected_cnt=0UL #define INCLUDE(cnt) for( ulong i=0UL; i<(cnt); i++ ) { expected[ expected_cnt++ ]=_j+i; } _j += (cnt) #define SKIP(cnt) _j+=(cnt) - i=fd_txn_acct_iter_init( txn, 0, &ctrl ); + i=fd_txn_acct_iter_init( txn, 0 ); RESET(); SKIP(ws); SKIP(rs); SKIP(wi); SKIP(ri); SKIP(wa); SKIP(ra); - for( ; i