11/// Unit tests — beacon chain state transition functions
22
3+ use blst:: min_pk:: { AggregateSignature , SecretKey } ;
34use eip_7732:: beacon_chain:: {
45 constants:: * ,
56 containers:: * ,
@@ -8,27 +9,35 @@ use eip_7732::beacon_chain::{
89 types:: * ,
910 withdrawals:: { process_withdrawals_consensus, verify_payload_withdrawals, WithdrawalError , WithdrawalState } ,
1011} ;
12+ use eip_7732:: utils:: { crypto, ssz} ;
1113
1214// ── Mock beacon state ──────────────────────────────────────────────────────────
1315
1416struct MockState {
1517 builders : std:: collections:: HashMap < BuilderIndex , Gwei > ,
18+ builder_pubkeys : std:: collections:: HashMap < BuilderIndex , BLSPubkey > ,
1619 pending_payments : Vec < BuilderPendingPayment > ,
1720 slot : Slot ,
1821 latest_block_hash : Hash32 ,
1922 expected_withdrawals : Vec < Withdrawal > ,
23+ ptc_pubkeys : Vec < BLSPubkey > ,
2024}
2125
2226impl MockState {
2327 fn new ( slot : Slot ) -> Self {
2428 let mut builders = std:: collections:: HashMap :: new ( ) ;
2529 builders. insert ( 1u64 , 32_000_000_000u64 ) ;
30+ let mut builder_pubkeys = std:: collections:: HashMap :: new ( ) ;
31+ builder_pubkeys. insert ( 1u64 , test_pubkey ( ) ) ;
32+ let ptc_pubkeys = vec ! [ test_pubkey( ) ; PTC_SIZE as usize ] ;
2633 Self {
2734 builders,
35+ builder_pubkeys,
2836 pending_payments : vec ! [ ] ,
2937 slot,
3038 latest_block_hash : [ 0x01u8 ; 32 ] ,
3139 expected_withdrawals : vec ! [ ] ,
40+ ptc_pubkeys,
3241 }
3342 }
3443}
@@ -37,6 +46,9 @@ impl BeaconStateMut for MockState {
3746 fn builder_balance ( & self , index : BuilderIndex ) -> Option < Gwei > {
3847 self . builders . get ( & index) . copied ( )
3948 }
49+ fn builder_pubkey ( & self , index : BuilderIndex ) -> Option < BLSPubkey > {
50+ self . builder_pubkeys . get ( & index) . copied ( )
51+ }
4052 fn deduct_builder_balance ( & mut self , index : BuilderIndex , amount : Gwei ) {
4153 if let Some ( bal) = self . builders . get_mut ( & index) {
4254 * bal -= amount;
@@ -54,6 +66,9 @@ impl BeaconStateRead for MockState {
5466 fn get_ptc ( & self , _slot : Slot ) -> Vec < ValidatorIndex > {
5567 ( 0 ..PTC_SIZE as u64 ) . collect ( )
5668 }
69+ fn ptc_pubkeys ( & self , _slot : Slot ) -> Vec < BLSPubkey > {
70+ self . ptc_pubkeys . clone ( )
71+ }
5772 fn parent_beacon_block_root ( & self ) -> [ u8 ; 32 ] { [ 0xBBu8 ; 32 ] }
5873}
5974
@@ -70,21 +85,24 @@ impl WithdrawalState for MockState {
7085}
7186
7287fn make_valid_bid ( slot : Slot ) -> SignedExecutionPayloadBid {
88+ let message = ExecutionPayloadBid {
89+ parent_block_hash : [ 0x01u8 ; 32 ] ,
90+ parent_block_root : [ 0x02u8 ; 32 ] ,
91+ block_hash : [ 0xAAu8 ; 32 ] ,
92+ prev_randao : [ 0u8 ; 32 ] ,
93+ fee_recipient : [ 0xFEu8 ; 20 ] ,
94+ gas_limit : 30_000_000 ,
95+ builder_index : 1 ,
96+ slot,
97+ value : 1_000_000_000 ,
98+ execution_payment : 0 ,
99+ blob_kzg_commitments : vec ! [ ] ,
100+ } ;
101+ let domain = ssz:: compute_domain_simple ( DOMAIN_BEACON_BUILDER ) ;
102+ let signing_root = ssz:: signing_root ( & message, domain) ;
73103 SignedExecutionPayloadBid {
74- message : ExecutionPayloadBid {
75- parent_block_hash : [ 0x01u8 ; 32 ] ,
76- parent_block_root : [ 0x02u8 ; 32 ] ,
77- block_hash : [ 0xAAu8 ; 32 ] ,
78- prev_randao : [ 0u8 ; 32 ] ,
79- fee_recipient : [ 0xFEu8 ; 20 ] ,
80- gas_limit : 30_000_000 ,
81- builder_index : 1 ,
82- slot,
83- value : 1_000_000_000 ,
84- execution_payment : 0 ,
85- blob_kzg_commitments : vec ! [ ] ,
86- } ,
87- signature : [ 0u8 ; 96 ] ,
104+ message,
105+ signature : crypto:: bls_sign ( & test_secret_key ( ) , & signing_root) ,
88106 }
89107}
90108
@@ -188,15 +206,20 @@ fn withdrawal_cleared_after_valid_payload() {
188206#[ test]
189207fn valid_ptc_attestation_accepted ( ) {
190208 let state = MockState :: new ( 100 ) ;
209+ let aggregation_bits = vec ! [ true ; PTC_SIZE as usize ] ;
210+ let data = PayloadAttestationData {
211+ beacon_block_root : [ 0xBBu8 ; 32 ] ,
212+ slot : 99 , // parent slot
213+ payload_present : true ,
214+ blob_data_available : true ,
215+ } ;
216+ let domain = ssz:: compute_domain_simple ( DOMAIN_PTC_ATTESTER ) ;
217+ let signing_root = ssz:: signing_root ( & data, domain) ;
218+ let signature = aggregate_signature ( & aggregation_bits, & signing_root) ;
191219 let att = PayloadAttestation {
192- aggregation_bits : vec ! [ true ; PTC_SIZE as usize ] ,
193- data : PayloadAttestationData {
194- beacon_block_root : [ 0xBBu8 ; 32 ] ,
195- slot : 99 , // parent slot
196- payload_present : true ,
197- blob_data_available : true ,
198- } ,
199- signature : [ 0u8 ; 96 ] ,
220+ aggregation_bits,
221+ data,
222+ signature,
200223 } ;
201224 assert ! ( process_payload_attestation( & state, & att) . is_ok( ) ) ;
202225}
@@ -233,4 +256,24 @@ fn ptc_wrong_slot_rejected() {
233256 } ;
234257 let err = process_payload_attestation ( & state, & att) . unwrap_err ( ) ;
235258 assert ! ( matches!( err, PayloadAttestationError :: WrongSlot { .. } ) ) ;
236- }
259+ }
260+
261+ fn test_secret_key ( ) -> SecretKey {
262+ SecretKey :: from_bytes ( & [ 7u8 ; 32 ] ) . expect ( "valid secret key" )
263+ }
264+
265+ fn test_pubkey ( ) -> BLSPubkey {
266+ test_secret_key ( ) . sk_to_pk ( ) . to_bytes ( )
267+ }
268+
269+ fn aggregate_signature ( bits : & [ bool ] , signing_root : & [ u8 ] ) -> BLSSignature {
270+ let sk = test_secret_key ( ) ;
271+ let mut agg = AggregateSignature :: new ( ) ;
272+ for bit in bits {
273+ if * bit {
274+ agg. add ( & sk. sign ( signing_root, crypto:: ETH_DST , & [ ] ) )
275+ . expect ( "aggregate add" ) ;
276+ }
277+ }
278+ agg. to_signature ( ) . to_bytes ( )
279+ }
0 commit comments