Skip to content

Commit 291f6a5

Browse files
committed
Add benchmark for validate_submit_bundle and validate_singleton_receipt
Signed-off-by: linning <[email protected]>
1 parent 3a2333c commit 291f6a5

File tree

4 files changed

+258
-13
lines changed

4 files changed

+258
-13
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pallet-domains/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ frame-benchmarking = { workspace = true, optional = true }
1818
frame-support.workspace = true
1919
frame-system.workspace = true
2020
hexlit.workspace = true
21+
hex-literal = { workspace = true, optional = true }
2122
log.workspace = true
2223
pallet-balances.workspace = true
2324
scale-info = { workspace = true, features = ["derive"] }
25+
schnorrkel = { workspace = true, optional = true }
2426
sp-consensus-slots.workspace = true
2527
sp-consensus-subspace.workspace = true
2628
sp-core.workspace = true
@@ -70,7 +72,10 @@ runtime-benchmarks = [
7072
"frame-system/runtime-benchmarks",
7173
"frame-benchmarking",
7274
"frame-benchmarking/runtime-benchmarks",
75+
"sp-consensus-subspace/runtime-benchmarks",
7376
"sp-domains/runtime-benchmarks",
7477
"sp-domains-fraud-proof/runtime-benchmarks",
7578
"sp-runtime/runtime-benchmarks",
79+
"schnorrkel",
80+
"hex-literal",
7681
]

crates/pallet-domains/src/benchmarking.rs

Lines changed: 251 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use super::*;
66
use crate::block_tree::{prune_receipt, BlockTreeNode};
77
use crate::bundle_storage_fund::refund_storage_fee;
88
use crate::domain_registry::{into_domain_config, DomainConfigParams};
9+
use crate::runtime_registry::DomainRuntimeUpgradeEntry;
910
use crate::staking::{
1011
do_convert_previous_epoch_withdrawal, do_mark_operators_as_slashed, do_reward_operators,
1112
Error as StakingError, OperatorConfig, OperatorStatus, WithdrawStake,
@@ -15,7 +16,8 @@ use crate::staking_epoch::{
1516
operator_take_reward_tax_and_stake,
1617
};
1718
use crate::{
18-
DomainBlockNumberFor, Pallet as Domains, RawOrigin as DomainOrigin, MAX_NOMINATORS_TO_SLASH,
19+
DomainBlockNumberFor, ExecutionReceiptOf, Pallet as Domains, RawOrigin as DomainOrigin,
20+
MAX_NOMINATORS_TO_SLASH,
1921
};
2022
#[cfg(not(feature = "std"))]
2123
use alloc::borrow::ToOwned;
@@ -26,15 +28,22 @@ use frame_support::assert_ok;
2628
use frame_support::traits::fungible::{Inspect, Mutate};
2729
use frame_support::traits::Hooks;
2830
use frame_system::{Pallet as System, RawOrigin};
31+
use hex_literal::hex;
32+
use sp_consensus_slots::Slot;
2933
use sp_core::crypto::{Ss58Codec, UncheckedFrom};
34+
use sp_core::sr25519::vrf::{VrfPreOutput, VrfProof, VrfSignature};
35+
use sp_core::H256;
36+
use sp_domains::merkle_tree::MerkleTree;
3037
use sp_domains::{
31-
dummy_opaque_bundle, DomainId, ExecutionReceipt, OperatorAllowList, OperatorId,
32-
OperatorPublicKey, OperatorRewardSource, OperatorSignature, PermissionedActionAllowedBy,
33-
ProofOfElection, RuntimeType, SealedSingletonReceipt, SingletonReceipt,
38+
dummy_opaque_bundle, BundleHeader, DomainId, ExecutionReceipt, OpaqueBundle, OperatorAllowList,
39+
OperatorId, OperatorPublicKey, OperatorRewardSource, OperatorSignature,
40+
PermissionedActionAllowedBy, ProofOfElection, RuntimeType, SealedBundleHeader,
41+
SealedSingletonReceipt, SingletonReceipt, EMPTY_EXTRINSIC_ROOT,
3442
};
3543
use sp_domains_fraud_proof::fraud_proof::FraudProof;
3644
use sp_runtime::traits::{CheckedAdd, One, Zero};
3745
use sp_std::collections::btree_set::BTreeSet;
46+
use subspace_core_primitives::pot::PotOutput;
3847

3948
const SEED: u32 = 0;
4049
const MAX_NOMINATORS_TO_SLASH_WITHOUT_OPERATOR: u32 = MAX_NOMINATORS_TO_SLASH - 1;
@@ -894,6 +903,133 @@ mod benchmarks {
894903
assert_eq!(Domains::<T>::head_receipt_number(domain_id), 1u32.into());
895904
}
896905

906+
#[benchmark]
907+
fn validate_submit_bundle() {
908+
let domain_id = register_domain::<T>();
909+
910+
// Use `Alice` as signing key
911+
let signing_key =
912+
OperatorPublicKey::from_ss58check("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
913+
.unwrap();
914+
let (_, operator_id) = register_operator_with_key::<T>(
915+
domain_id,
916+
1u32,
917+
signing_key,
918+
T::MinNominatorStake::get(),
919+
);
920+
do_finalize_domain_current_epoch::<T>(domain_id)
921+
.expect("finalize domain staking should success");
922+
923+
let proof_of_election = mock_constant_proof_of_election(domain_id, operator_id);
924+
let receipt = mock_constant_receipt::<T>(domain_id);
925+
926+
// Instead of inserting consensus hash into `ConsensusBlockHash` for the receipt check
927+
// insert `DomainRuntimeUpgradeRecords` to routed to a worse path
928+
DomainRuntimeUpgradeRecords::<T>::mutate(
929+
Domains::<T>::runtime_id(domain_id).unwrap(),
930+
|upgrade_record| {
931+
upgrade_record.insert(
932+
receipt.consensus_block_number,
933+
DomainRuntimeUpgradeEntry {
934+
at_hash: receipt.consensus_block_hash,
935+
reference_count: 1,
936+
},
937+
)
938+
},
939+
);
940+
941+
let header = BundleHeader {
942+
proof_of_election,
943+
receipt,
944+
estimated_bundle_weight: Default::default(),
945+
bundle_extrinsics_root: EMPTY_EXTRINSIC_ROOT.into(),
946+
};
947+
948+
// Hardcoded signature of the constant bundle header, signed by `Alice`
949+
// NOTE: we can't sign in no-std because it requires randomness
950+
let signature = OperatorSignature::unchecked_from([
951+
212, 250, 46, 171, 239, 93, 105, 105, 36, 78, 32, 229, 166, 253, 168, 142, 109, 123,
952+
213, 159, 210, 106, 192, 62, 54, 82, 64, 64, 19, 27, 136, 33, 19, 241, 58, 116, 252,
953+
133, 147, 129, 32, 182, 201, 18, 47, 80, 117, 124, 136, 186, 168, 15, 193, 71, 236,
954+
201, 155, 176, 188, 254, 114, 173, 96, 134,
955+
]);
956+
957+
let opaque_bundle = OpaqueBundle {
958+
sealed_header: SealedBundleHeader::new(header, signature),
959+
extrinsics: Vec::new(),
960+
};
961+
962+
#[block]
963+
{
964+
assert_ok!(Domains::<T>::validate_submit_bundle(&opaque_bundle, true));
965+
}
966+
}
967+
968+
#[benchmark]
969+
fn validate_singleton_receipt() {
970+
let domain_id = register_domain::<T>();
971+
972+
// Use `Alice` as signing key
973+
let signing_key =
974+
OperatorPublicKey::from_ss58check("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
975+
.unwrap();
976+
let (_, operator_id) = register_operator_with_key::<T>(
977+
domain_id,
978+
1u32,
979+
signing_key,
980+
T::MinNominatorStake::get(),
981+
);
982+
do_finalize_domain_current_epoch::<T>(domain_id)
983+
.expect("finalize domain staking should success");
984+
985+
let proof_of_election = mock_constant_proof_of_election(domain_id, operator_id);
986+
let receipt = mock_constant_receipt::<T>(domain_id);
987+
988+
// Instead of inserting consensus hash into `ConsensusBlockHash` for the receipt check
989+
// insert `DomainRuntimeUpgradeRecords` to routed to a worse path
990+
DomainRuntimeUpgradeRecords::<T>::mutate(
991+
Domains::<T>::runtime_id(domain_id).unwrap(),
992+
|upgrade_record| {
993+
upgrade_record.insert(
994+
receipt.consensus_block_number,
995+
DomainRuntimeUpgradeEntry {
996+
at_hash: receipt.consensus_block_hash,
997+
reference_count: 1,
998+
},
999+
)
1000+
},
1001+
);
1002+
1003+
let singleton_receipt: SingletonReceipt<_, _, T::DomainHeader, _> = SingletonReceipt {
1004+
proof_of_election,
1005+
receipt,
1006+
};
1007+
1008+
// Hardcoded signature of the constant singleton receipt, signed by `Alice`
1009+
// NOTE: we can't sign in no-std because it requires randomness
1010+
let signature = OperatorSignature::unchecked_from([
1011+
10, 180, 139, 94, 205, 225, 15, 19, 141, 141, 133, 23, 32, 66, 177, 60, 131, 89, 91,
1012+
110, 161, 218, 6, 228, 214, 118, 106, 108, 217, 36, 108, 40, 85, 150, 165, 177, 40, 9,
1013+
98, 82, 203, 27, 32, 98, 122, 123, 78, 221, 229, 50, 118, 153, 61, 111, 95, 51, 130,
1014+
195, 94, 212, 225, 14, 184, 141,
1015+
]);
1016+
1017+
let sealed_singleton_receipt = SealedSingletonReceipt {
1018+
singleton_receipt,
1019+
signature,
1020+
};
1021+
1022+
HeadDomainNumber::<T>::set(domain_id, 10u32.into());
1023+
1024+
#[block]
1025+
{
1026+
assert_ok!(Domains::<T>::validate_singleton_receipt(
1027+
&sealed_singleton_receipt,
1028+
true
1029+
));
1030+
}
1031+
}
1032+
8971033
fn register_runtime<T: Config>() -> RuntimeId {
8981034
let genesis_storage = include_bytes!("../res/evm-domain-genesis-storage").to_vec();
8991035
let runtime_id = NextRuntimeId::<T>::get();
@@ -961,28 +1097,43 @@ mod benchmarks {
9611097
operator_seed: u32,
9621098
minimum_nominator_stake: BalanceOf<T>,
9631099
) -> (T::AccountId, OperatorId) {
964-
let operator_account = account("operator", operator_seed, SEED);
965-
T::Currency::set_balance(
966-
&operator_account,
967-
T::MinOperatorStake::get() + T::MinNominatorStake::get(),
968-
);
969-
9701100
let key = {
9711101
let mut k = [0u8; 32];
9721102
(k[..4]).copy_from_slice(&operator_seed.to_be_bytes()[..]);
9731103
k
9741104
};
1105+
let signing_key = OperatorPublicKey::unchecked_from(key);
1106+
register_operator_with_key::<T>(
1107+
domain_id,
1108+
operator_seed,
1109+
signing_key,
1110+
minimum_nominator_stake,
1111+
)
1112+
}
1113+
1114+
fn register_operator_with_key<T: Config>(
1115+
domain_id: DomainId,
1116+
operator_seed: u32,
1117+
signing_key: OperatorPublicKey,
1118+
minimum_nominator_stake: BalanceOf<T>,
1119+
) -> (T::AccountId, OperatorId) {
1120+
let operator_account = account("operator", operator_seed, SEED);
1121+
T::Currency::set_balance(
1122+
&operator_account,
1123+
T::MinOperatorStake::get() * 100u32.into() + T::MinNominatorStake::get(),
1124+
);
1125+
9751126
let operator_id = NextOperatorId::<T>::get();
9761127
let operator_config = OperatorConfig {
977-
signing_key: OperatorPublicKey::unchecked_from(key),
1128+
signing_key,
9781129
minimum_nominator_stake,
9791130
nomination_tax: Default::default(),
9801131
};
9811132

9821133
assert_ok!(crate::do_register_operator::<T>(
9831134
operator_account.clone(),
9841135
domain_id,
985-
T::MinOperatorStake::get(),
1136+
T::MinOperatorStake::get() * 50u32.into(),
9861137
operator_config.clone(),
9871138
));
9881139
assert_eq!(
@@ -995,6 +1146,94 @@ mod benchmarks {
9951146
(operator_account, operator_id)
9961147
}
9971148

1149+
// Return a mock `proof_of_election` which should be a constant value, otherwise,
1150+
// it won't match with the hardcoded signature
1151+
fn mock_constant_proof_of_election(
1152+
domain_id: DomainId,
1153+
operator_id: OperatorId,
1154+
) -> ProofOfElection {
1155+
let (proof_of_time, slot) = (PotOutput::default(), Slot::from(1));
1156+
1157+
// VRF signature generated by signing:
1158+
// ```
1159+
// let global_challenge = proof_of_time
1160+
// .derive_global_randomness()
1161+
// .derive_global_challenge(slot.into());
1162+
// let vrf_sign_data = make_transcript(domain_id, &global_challenge).into_sign_data();
1163+
// ```
1164+
// with the key `Alice`
1165+
let vrf_signature = VrfSignature {
1166+
pre_output: VrfPreOutput(
1167+
schnorrkel::vrf::VRFPreOut::from_bytes(&[
1168+
248, 47, 99, 253, 224, 36, 127, 251, 30, 132, 220, 112, 51, 251, 195, 246, 140,
1169+
97, 153, 49, 166, 36, 114, 142, 73, 214, 185, 156, 2, 142, 180, 57,
1170+
])
1171+
.unwrap(),
1172+
),
1173+
proof: VrfProof(
1174+
schnorrkel::vrf::VRFProof::from_bytes(&[
1175+
28, 138, 214, 43, 79, 128, 75, 106, 98, 232, 188, 139, 101, 206, 174, 146, 138,
1176+
210, 101, 72, 184, 227, 115, 72, 37, 246, 182, 247, 102, 34, 11, 3, 22, 106,
1177+
116, 209, 34, 220, 216, 20, 93, 101, 182, 130, 15, 71, 73, 27, 51, 126, 100,
1178+
43, 80, 253, 101, 132, 222, 234, 196, 167, 19, 126, 16, 8,
1179+
])
1180+
.unwrap(),
1181+
),
1182+
};
1183+
ProofOfElection {
1184+
domain_id,
1185+
slot_number: slot.into(),
1186+
proof_of_time,
1187+
vrf_signature,
1188+
operator_id,
1189+
}
1190+
}
1191+
1192+
// Return a mock `receipt` which should be a constant value, otherwise, it won't match
1193+
// with the hardcoded signature
1194+
fn mock_constant_receipt<T: Config>(domain_id: DomainId) -> ExecutionReceiptOf<T> {
1195+
// The genesis ER will changed as the runtime code changed, thus using a mock genesis
1196+
// ER hash to ensure the return ER is constant
1197+
let mock_genesis_er_hash = H256::from_slice(
1198+
hex!("5207cc85cfd1f53e11f4b9e85bf2d0a4f33e24d0f0f18b818b935a6aa47d3930").as_slice(),
1199+
);
1200+
BlockTree::<T>::insert::<_, DomainBlockNumberFor<T>, <T as Config>::DomainHash>(
1201+
domain_id,
1202+
Zero::zero(),
1203+
mock_genesis_er_hash.into(),
1204+
);
1205+
1206+
let trace: Vec<<T as Config>::DomainHash> = vec![
1207+
H256::repeat_byte(1).into(),
1208+
H256::repeat_byte(2).into(),
1209+
H256::repeat_byte(3).into(),
1210+
];
1211+
let execution_trace_root = {
1212+
let trace: Vec<_> = trace
1213+
.iter()
1214+
.map(|t| t.encode().try_into().unwrap())
1215+
.collect();
1216+
MerkleTree::from_leaves(trace.as_slice())
1217+
.root()
1218+
.unwrap()
1219+
.into()
1220+
};
1221+
ExecutionReceipt {
1222+
domain_block_number: One::one(),
1223+
domain_block_hash: H256::repeat_byte(7).into(),
1224+
domain_block_extrinsic_root: EMPTY_EXTRINSIC_ROOT.into(),
1225+
parent_domain_block_receipt_hash: mock_genesis_er_hash.into(),
1226+
consensus_block_number: One::one(),
1227+
consensus_block_hash: H256::repeat_byte(9).into(),
1228+
inboxed_bundles: vec![],
1229+
final_state_root: trace[2],
1230+
execution_trace: trace,
1231+
execution_trace_root,
1232+
block_fees: Default::default(),
1233+
transfers: Default::default(),
1234+
}
1235+
}
1236+
9981237
fn run_to_block<T: Config>(block_number: BlockNumberFor<T>, parent_hash: T::Hash) {
9991238
if let Some(parent_block_number) = block_number.checked_sub(&One::one()) {
10001239
Domains::<T>::on_finalize(parent_block_number);

crates/pallet-domains/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ pub struct DummyBlockSlot;
185185

186186
impl BlockSlot<Test> for DummyBlockSlot {
187187
fn future_slot(_block_number: BlockNumberFor<Test>) -> Option<sp_consensus_slots::Slot> {
188-
Some(0u64.into())
188+
None
189189
}
190190

191191
fn slot_produced_after(_slot: sp_consensus_slots::Slot) -> Option<BlockNumberFor<Test>> {

0 commit comments

Comments
 (0)