Skip to content

Commit 7b76499

Browse files
authored
Merge pull request #3542 from autonomys/pallet-domains-extension-benchmark
Benchmarks for pallet domains extension
2 parents 7a0675a + 8d46c2c commit 7b76499

File tree

9 files changed

+513
-44
lines changed

9 files changed

+513
-44
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,10 +18,12 @@ 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
pallet-subspace = { workspace = true, optional = true }
2425
scale-info = { workspace = true, features = ["derive"] }
26+
schnorrkel = { workspace = true, optional = true }
2527
sp-consensus-slots.workspace = true
2628
sp-consensus-subspace.workspace = true
2729
sp-core.workspace = true
@@ -73,8 +75,11 @@ runtime-benchmarks = [
7375
"frame-system/runtime-benchmarks",
7476
"frame-benchmarking",
7577
"frame-benchmarking/runtime-benchmarks",
78+
"sp-consensus-subspace/runtime-benchmarks",
7679
"pallet-subspace/runtime-benchmarks",
7780
"sp-domains/runtime-benchmarks",
7881
"sp-domains-fraud-proof/runtime-benchmarks",
7982
"sp-runtime/runtime-benchmarks",
83+
"schnorrkel",
84+
"hex-literal",
8085
]

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,16 +28,23 @@ 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;
2932
use pallet_subspace::BlockRandomness;
33+
use sp_consensus_slots::Slot;
3034
use sp_core::crypto::{Ss58Codec, UncheckedFrom};
35+
use sp_core::sr25519::vrf::{VrfPreOutput, VrfProof, VrfSignature};
36+
use sp_core::H256;
37+
use sp_domains::merkle_tree::MerkleTree;
3138
use sp_domains::{
32-
dummy_opaque_bundle, DomainId, ExecutionReceipt, OperatorAllowList, OperatorId,
33-
OperatorPublicKey, OperatorRewardSource, OperatorSignature, PermissionedActionAllowedBy,
34-
ProofOfElection, RuntimeType, SealedSingletonReceipt, SingletonReceipt,
39+
dummy_opaque_bundle, BundleHeader, DomainId, ExecutionReceipt, OpaqueBundle, OperatorAllowList,
40+
OperatorId, OperatorPublicKey, OperatorRewardSource, OperatorSignature,
41+
PermissionedActionAllowedBy, ProofOfElection, RuntimeType, SealedBundleHeader,
42+
SealedSingletonReceipt, SingletonReceipt, EMPTY_EXTRINSIC_ROOT,
3543
};
3644
use sp_domains_fraud_proof::fraud_proof::FraudProof;
3745
use sp_runtime::traits::{CheckedAdd, One, Zero};
3846
use sp_std::collections::btree_set::BTreeSet;
47+
use subspace_core_primitives::pot::PotOutput;
3948
use subspace_core_primitives::Randomness;
4049

4150
const SEED: u32 = 0;
@@ -900,6 +909,133 @@ mod benchmarks {
900909
assert_eq!(Domains::<T>::head_receipt_number(domain_id), 1u32.into());
901910
}
902911

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

9881139
assert_ok!(crate::do_register_operator::<T>(
9891140
operator_account.clone(),
9901141
domain_id,
991-
T::MinOperatorStake::get(),
1142+
T::MinOperatorStake::get() * 50u32.into(),
9921143
operator_config.clone(),
9931144
));
9941145
assert_eq!(
@@ -1001,6 +1152,94 @@ mod benchmarks {
10011152
(operator_account, operator_id)
10021153
}
10031154

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

0 commit comments

Comments
 (0)