Skip to content

Commit 0d5f45f

Browse files
committed
test: cover BLS signing roots in unit and integration suites (PR #1)
1 parent 6f7e0f2 commit 0d5f45f

1 file changed

Lines changed: 66 additions & 23 deletions

File tree

tests/unit/beacon_chain_test.rs

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// Unit tests — beacon chain state transition functions
22
3+
use blst::min_pk::{AggregateSignature, SecretKey};
34
use 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

1416
struct 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

2226
impl 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

7287
fn 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]
189207
fn 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

Comments
 (0)