Skip to content

Commit ab328b0

Browse files
authored
test: Add some missing sc messages tests (#3187)
# Description ## Linked Issues - Fixes # (issue, if applicable) - Related to # (issue) ## Testing Describe how these changes were tested. If you've added new features, have you added unit tests? ## Docs Describe where this code is documented. If it changes a documented interface, have the docs been updated?
1 parent 34cb50c commit ab328b0

File tree

2 files changed

+163
-5
lines changed

2 files changed

+163
-5
lines changed

bin/citrea/tests/bitcoin/light_client_test.rs

Lines changed: 126 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use citrea_e2e::Result;
2727
use citrea_fullnode::rpc::FullNodeRpcClient;
2828
use citrea_light_client_prover::circuit::{
2929
AddSecurityCouncilMember, BatchProofMethodIdUpdate, RemoveBatchProofMethodId,
30-
RemoveSecurityCouncilMember, UpdateBatchProverDaPubKey, UpdateSecurityCouncilThreshold,
31-
UpdateSequencerDaPubKey,
30+
RemoveSecurityCouncilMember, ReplaceSecurityCouncilMember, UpdateBatchProverDaPubKey,
31+
UpdateSecurityCouncilThreshold, UpdateSequencerDaPubKey,
3232
};
3333
use citrea_light_client_prover::rpc::LightClientProverRpcClient;
3434
use citrea_primitives::compression::{compress_blob, decompress_blob};
@@ -39,9 +39,10 @@ use risc0_zkvm::{FakeReceipt, InnerReceipt, MaybePruned, ReceiptClaim};
3939
use sov_modules_api::BlobReaderTrait;
4040
use sov_rollup_interface::da::{
4141
AddSecurityCouncilMemberV1Body, BatchProofMethodIdBody, DaTxRequest, DaVerifier, DataOnDa,
42-
RemoveBatchProofMethodIdV1Body, RemoveSecurityCouncilMemberV1Body, SecurityCouncilTx,
43-
SecurityCouncilTxType, SequencerCommitment, UpdateBatchProverDaPubKeyV1Body,
44-
UpdateSecurityCouncilThresholdV1Body, UpdateSequencerDaPubKeyV1Body,
42+
RemoveBatchProofMethodIdV1Body, RemoveSecurityCouncilMemberV1Body,
43+
ReplaceSecurityCouncilMemberV1Body, SecurityCouncilTx, SecurityCouncilTxType,
44+
SequencerCommitment, UpdateBatchProverDaPubKeyV1Body, UpdateSecurityCouncilThresholdV1Body,
45+
UpdateSequencerDaPubKeyV1Body,
4546
};
4647
use sov_rollup_interface::rpc::BatchProofMethodIdRpcResponse;
4748
use sov_rollup_interface::services::da::DaService;
@@ -4530,6 +4531,126 @@ impl TestCase for SecurityCouncilMemberManagementTest {
45304531
"CASE 7: Should still have 4 members (below min rejected)"
45314532
);
45324533

4534+
// --- CASE 8: Replace non-existent member (rejected) ---
4535+
// Try to replace a member that doesn't exist in the council.
4536+
let replace_body_1 = ReplaceSecurityCouncilMemberV1Body {
4537+
to_be_replaced: [0xAAu8; 20], // not in council
4538+
new_member: [0x33u8; 20],
4539+
nonce: 7,
4540+
};
4541+
let payload = ReplaceSecurityCouncilMember::from(replace_body_1.clone());
4542+
let signatures_with_index = create_valid_signatures(&signers, &payload, 2);
4543+
bitcoin_da_service
4544+
.send_transaction_with_fee_rate(
4545+
DaTxRequest::SecurityCouncilTx(SecurityCouncilTx {
4546+
tx_type: SecurityCouncilTxType::ReplaceSecurityCouncilMemberV1(replace_body_1),
4547+
signatures_with_index,
4548+
}),
4549+
1.0,
4550+
)
4551+
.await?;
4552+
da.wait_mempool_len(2, None).await?;
4553+
da.generate(DEFAULT_FINALITY_DEPTH).await?;
4554+
let l1_height = da.get_finalized_height(None).await?;
4555+
light_client_prover
4556+
.wait_for_l1_height(l1_height, Some(TEN_MINS))
4557+
.await?;
4558+
4559+
let addresses = light_client_prover
4560+
.client
4561+
.http_client()
4562+
.get_security_council_addresses()
4563+
.await?;
4564+
assert_eq!(
4565+
addresses.len(),
4566+
4,
4567+
"CASE 8: Should still have 4 members (non-existent member replace rejected)"
4568+
);
4569+
4570+
// --- CASE 9: Replace with already existing member (rejected) ---
4571+
// Try to replace one member with another who is already in the council.
4572+
let replace_body_2 = ReplaceSecurityCouncilMemberV1Body {
4573+
to_be_replaced: _initial_addresses[0].0 .0,
4574+
new_member: _initial_addresses[1].0 .0, // already in council
4575+
nonce: 7,
4576+
};
4577+
let payload = ReplaceSecurityCouncilMember::from(replace_body_2.clone());
4578+
let signatures_with_index = create_valid_signatures(&signers, &payload, 2);
4579+
bitcoin_da_service
4580+
.send_transaction_with_fee_rate(
4581+
DaTxRequest::SecurityCouncilTx(SecurityCouncilTx {
4582+
tx_type: SecurityCouncilTxType::ReplaceSecurityCouncilMemberV1(replace_body_2),
4583+
signatures_with_index,
4584+
}),
4585+
1.0,
4586+
)
4587+
.await?;
4588+
da.wait_mempool_len(2, None).await?;
4589+
da.generate(DEFAULT_FINALITY_DEPTH).await?;
4590+
let l1_height = da.get_finalized_height(None).await?;
4591+
light_client_prover
4592+
.wait_for_l1_height(l1_height, Some(TEN_MINS))
4593+
.await?;
4594+
4595+
let addresses = light_client_prover
4596+
.client
4597+
.http_client()
4598+
.get_security_council_addresses()
4599+
.await?;
4600+
assert_eq!(
4601+
addresses.len(),
4602+
4,
4603+
"CASE 9: Should still have 4 members (duplicate member replace rejected)"
4604+
);
4605+
4606+
// --- CASE 10: Valid replace member ---
4607+
// Replace _initial_addresses[2] with a new address.
4608+
let new_replacement = [0x33u8; 20];
4609+
let replace_body_3 = ReplaceSecurityCouncilMemberV1Body {
4610+
to_be_replaced: _initial_addresses[2].0 .0,
4611+
new_member: new_replacement,
4612+
nonce: 7,
4613+
};
4614+
let payload = ReplaceSecurityCouncilMember::from(replace_body_3.clone());
4615+
let signatures_with_index = create_valid_signatures(&signers, &payload, 2);
4616+
bitcoin_da_service
4617+
.send_transaction_with_fee_rate(
4618+
DaTxRequest::SecurityCouncilTx(SecurityCouncilTx {
4619+
tx_type: SecurityCouncilTxType::ReplaceSecurityCouncilMemberV1(replace_body_3),
4620+
signatures_with_index,
4621+
}),
4622+
1.0,
4623+
)
4624+
.await?;
4625+
da.wait_mempool_len(2, None).await?;
4626+
da.generate(DEFAULT_FINALITY_DEPTH).await?;
4627+
let l1_height = da.get_finalized_height(None).await?;
4628+
light_client_prover
4629+
.wait_for_l1_height(l1_height, Some(TEN_MINS))
4630+
.await?;
4631+
4632+
let addresses = light_client_prover
4633+
.client
4634+
.http_client()
4635+
.get_security_council_addresses()
4636+
.await?;
4637+
assert_eq!(
4638+
addresses.len(),
4639+
4,
4640+
"CASE 10: Should still have 4 members after replace"
4641+
);
4642+
// Verify the old member is gone and new member is present
4643+
let old_member_addr = format!("{:?}", _initial_addresses[2]);
4644+
let new_member_addr = format!("{:?}", Address::from_slice(&new_replacement));
4645+
assert!(
4646+
!addresses.contains(&old_member_addr),
4647+
"CASE 10: Old member should be removed"
4648+
);
4649+
assert!(
4650+
addresses.contains(&new_member_addr),
4651+
"CASE 10: New member should be present"
4652+
);
4653+
45334654
Ok(())
45344655
}
45354656
}

crates/light-client-prover/src/circuit/method_id_verifier.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,43 @@ mod tests {
282282
));
283283
}
284284

285+
#[test]
286+
fn test_below_threshold_signature_count_rejected() {
287+
let body = BatchProofMethodIdBody {
288+
method_id: [0u32; 8],
289+
activation_l2_height: 0,
290+
nonce: 0,
291+
};
292+
293+
let payload = BatchProofMethodIdUpdate::from(body.clone());
294+
295+
let (initial_addresses, signers) = generate_initial_addresses_with_signers();
296+
297+
// Create only 2 signatures when threshold is 3
298+
let signatures_with_index =
299+
crate::create_valid_signatures_with_count(&signers, &payload, 2);
300+
301+
assert!(!verify_security_council_signatures(
302+
&initial_addresses,
303+
BatchProofMethodIdUpdate::from(body.clone()),
304+
&signatures_with_index,
305+
TEST_THRESHOLD,
306+
mockda::EIP712_SECURITY_COUNCIL_MESSAGE_DOMAIN_NAME.to_string(),
307+
citrea_network_to_chain_id(Network::Nightly),
308+
));
309+
310+
// Create 0 signatures
311+
let empty_signatures: Vec<([u8; 65], u8)> = vec![];
312+
assert!(!verify_security_council_signatures(
313+
&initial_addresses,
314+
BatchProofMethodIdUpdate::from(body),
315+
&empty_signatures,
316+
TEST_THRESHOLD,
317+
mockda::EIP712_SECURITY_COUNCIL_MESSAGE_DOMAIN_NAME.to_string(),
318+
citrea_network_to_chain_id(Network::Nightly),
319+
));
320+
}
321+
285322
#[test]
286323
fn test_signature_index_swapped() {
287324
let body = BatchProofMethodIdBody {

0 commit comments

Comments
 (0)