Compare commits
No commits in common. "main" and "ghost-exodus" have entirely different histories.
main
...
ghost-exod
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -1195,7 +1195,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "casper-runtime"
|
||||
version = "4.0.18"
|
||||
version = "4.0.10"
|
||||
dependencies = [
|
||||
"casper-runtime-constants",
|
||||
"frame-benchmarking",
|
||||
@ -1209,7 +1209,6 @@ dependencies = [
|
||||
"frame-try-runtime",
|
||||
"ghost-core-primitives",
|
||||
"ghost-exodus",
|
||||
"ghost-exodus-runtime-api",
|
||||
"ghost-governance",
|
||||
"ghost-helpers",
|
||||
"ghost-networks",
|
||||
@ -3685,7 +3684,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ghost-exodus"
|
||||
version = "0.1.7"
|
||||
version = "0.0.11"
|
||||
dependencies = [
|
||||
"chacha20poly1305",
|
||||
"frame-benchmarking",
|
||||
@ -3695,7 +3694,6 @@ dependencies = [
|
||||
"frost-core",
|
||||
"frost-ed25519",
|
||||
"frost-secp256k1-tr",
|
||||
"ghost-exodus-runtime-api",
|
||||
"ghost-helpers",
|
||||
"ghost-networks",
|
||||
"ghost-traits",
|
||||
@ -3727,17 +3725,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ghost-exodus-runtime-api"
|
||||
version = "0.0.2"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"ghost-helpers",
|
||||
"parity-scale-codec",
|
||||
"sp-api",
|
||||
"sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.12.0)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghost-governance"
|
||||
version = "0.3.11"
|
||||
version = "0.3.7"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
@ -3747,7 +3743,6 @@ dependencies = [
|
||||
"ghost-traits",
|
||||
"hex-literal",
|
||||
"libsecp256k1",
|
||||
"num-traits",
|
||||
"pallet-balances",
|
||||
"parity-scale-codec",
|
||||
"rustc-hex",
|
||||
@ -3762,7 +3757,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ghost-helpers"
|
||||
version = "0.0.16"
|
||||
version = "0.0.11"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"ghost-traits",
|
||||
@ -3844,7 +3839,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ghost-networks"
|
||||
version = "0.2.12"
|
||||
version = "0.2.10"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
@ -4090,7 +4085,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ghost-traits"
|
||||
version = "0.4.10"
|
||||
version = "0.4.6"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"frost-core",
|
||||
@ -4114,7 +4109,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ghost-weaver"
|
||||
version = "0.0.26"
|
||||
version = "0.0.8"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
|
||||
@ -239,7 +239,6 @@ ghost-networks = { path = "pallets/networks", default-features = false }
|
||||
ghost-governance = { path = "pallets/governance", default-features = false }
|
||||
ghost-weaver = { path = "pallets/weaver", default-features = false }
|
||||
ghost-exodus = { path = "pallets/exodus", default-features = false }
|
||||
ghost-exodus-runtime-api = { path = "pallets/exodus/runtime-api", default-features = false }
|
||||
ghost-sudo = { path = "pallets/sudo", default-features = false }
|
||||
ghost-nomination-pools = { path = "pallets/pools", default-features = false }
|
||||
ghost-nomination-pools-runtime-api = { path = "pallets/pools/runtime-api", default-features = false }
|
||||
|
||||
@ -346,7 +346,7 @@ sha256sum /etc/ghost/casper.json
|
||||
|
||||
You should see:
|
||||
```
|
||||
74f5a6df5e33dac94a8852ddfb73e472283bba0b30e260ca581919eb50c734db /etc/ghost/casper.json
|
||||
9da6045ed6d4fd844e3939573b31c013d0e564e542029330faa6d978cb4a915a
|
||||
```
|
||||
|
||||
Create running `ghost-node` service that starts on system boot using `--unit-file` flag.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-exodus"
|
||||
version = "0.1.7"
|
||||
version = "0.0.11"
|
||||
description = "Threshold signature generation with DKG included"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
@ -40,7 +40,6 @@ parking_lot = { workspace = true }
|
||||
|
||||
ghost-traits = { workspace = true }
|
||||
ghost-helpers = { workspace = true }
|
||||
ghost-exodus-runtime-api = { workspace = true }
|
||||
|
||||
pallet-balances = { workspace = true }
|
||||
pallet-session = { workspace = true }
|
||||
@ -81,7 +80,6 @@ std = [
|
||||
"frost-core/std",
|
||||
"ghost-traits/std",
|
||||
"ghost-helpers/std",
|
||||
"ghost-exodus-runtime-api/std",
|
||||
"pallet-balances/std",
|
||||
"pallet-session/std",
|
||||
"pallet-staking/std",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-exodus-runtime-api"
|
||||
version = "0.0.2"
|
||||
version = "0.0.0"
|
||||
description = "RPC runtime API for ghost EXODUS pallet"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
@ -14,14 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
|
||||
[dependencies]
|
||||
codec = { workspace = true, features = ["derive"] }
|
||||
sp-api = { workspace = true }
|
||||
sp-std = { workspace = true }
|
||||
ghost-helpers = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"sp-api/std",
|
||||
"sp-std/std",
|
||||
"ghost-helpers/std",
|
||||
]
|
||||
std = ["codec/std", "sp-api/std"]
|
||||
@ -1,17 +1,7 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use sp_std::vec::Vec;
|
||||
use ghost_helpers::networks::{NetworkType, NetworkCurve};
|
||||
|
||||
pub type PreparedEvmMessage = Option<(Vec<u8>, Vec<u8>, Vec<u8>)>;
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
pub trait ExodusApi {
|
||||
fn get_evm_rotation_metadata(dkg_index: u64, network_type: NetworkType) -> PreparedEvmMessage;
|
||||
fn get_evm_bridge_metadata(dkg_index: u64, network_id: u64, session: u64) -> PreparedEvmMessage;
|
||||
fn get_evm_governance_metadata(dkg_index: u64, network_id: u64, session: u64) -> PreparedEvmMessage;
|
||||
|
||||
fn pending_exodus_request_count() -> u32;
|
||||
fn is_qualification_ongoing(curve: NetworkCurve) -> bool;
|
||||
pub trait ExodusApi<NetworkId> {
|
||||
fn verifying_key(network_id: NetworkId) -> Vec<u8>;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ use frame_system::RawOrigin;
|
||||
use ghost_helpers::networks::NetworkDataBuilder;
|
||||
|
||||
fn prepare_pallet<T: Config>(authorities_len: usize) -> (
|
||||
PendingDkgAuthorities<T>,
|
||||
PendingDkgAuthorities<ParticipantsBitmap<T>, BlockNumberFor<T>>,
|
||||
NetworkCurve,
|
||||
T::AuthorityId,
|
||||
AuthIndex
|
||||
@ -47,13 +47,11 @@ mod benchmarks {
|
||||
prepare_pallet::<T>(1);
|
||||
|
||||
dkg_state.next_phase();
|
||||
let dkg_index = dkg_state.get_dkg_index();
|
||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||
|
||||
let round0_package = PackageContext::default()
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(0)
|
||||
.with_dkg_index(dkg_index)
|
||||
.with_dkg_round0(dummy_hash);
|
||||
|
||||
let dkg_package = DkgPackage::Round0(round0_package);
|
||||
@ -85,10 +83,10 @@ mod benchmarks {
|
||||
dkg_state.next_phase();
|
||||
|
||||
dkg_state.insert_index(authority_index);
|
||||
let dkg_index = dkg_state.get_dkg_index();
|
||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||
|
||||
let mut rng = ChaCha20Rng::seed_from_u64(694201337);
|
||||
let mut rng = Pallet::<T>::get_offchain_rng(authority_index);
|
||||
|
||||
let (_, public_package) = network_curve.dkg_part1(
|
||||
authority_index,
|
||||
max_signers,
|
||||
@ -99,12 +97,9 @@ mod benchmarks {
|
||||
let package_hash = ExodusHash::from(blake2_256(&public_package));
|
||||
Round0Packages::<T>::insert(network_curve, authority_index, package_hash);
|
||||
|
||||
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||
let round1_package = PackageContext::default()
|
||||
.with_block_number(current_block)
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(0)
|
||||
.with_dkg_index(dkg_index)
|
||||
.with_dkg_round1(public_package)
|
||||
.expect("Round1 package should be valid");
|
||||
|
||||
@ -125,9 +120,9 @@ mod benchmarks {
|
||||
|
||||
#[benchmark]
|
||||
fn register_encrypted_round2_packages(
|
||||
c: Linear<1, { T::MaxAuthorities::get() }>
|
||||
c: Linear<1, { T::MaxAuthorities::get() / 8 }>
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let max_signers = c as AuthIndex;
|
||||
let max_signers = (c * 8) as AuthIndex;
|
||||
|
||||
let (mut dkg_state, network_curve, authority, authority_index) =
|
||||
prepare_pallet::<T>(max_signers as usize);
|
||||
@ -136,8 +131,6 @@ mod benchmarks {
|
||||
dkg_state.next_phase();
|
||||
dkg_state.next_phase();
|
||||
|
||||
let dkg_index = dkg_state.get_dkg_index();
|
||||
|
||||
(0..max_signers).for_each(|i| {
|
||||
dkg_state.insert_index(i);
|
||||
});
|
||||
@ -149,29 +142,29 @@ mod benchmarks {
|
||||
|
||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||
|
||||
let bitmask_len = padded_participants.div_ceil(8);
|
||||
let blob_len = round2_encrypted_package_size(
|
||||
padded_participants - 1,
|
||||
padded_participants,
|
||||
network_curve.scalar_bytes_len(),
|
||||
network_curve.header_bytes_len(),
|
||||
);
|
||||
|
||||
let mut bitmask = ParticipantsBitmap::<T>::empty(padded_participants);
|
||||
let mut bitmask = vec![0u8; bitmask_len];
|
||||
let blob = vec![0u8; blob_len];
|
||||
|
||||
(0..max_signers).for_each(|i| {
|
||||
if i != authority_index {
|
||||
bitmask.insert(i);
|
||||
let byte_index = (i / 8) as usize;
|
||||
let bit_index = (i % 8) as u8;
|
||||
bitmask[byte_index] |= 1 << bit_index;
|
||||
}
|
||||
});
|
||||
|
||||
let encryption_bundle = BundledPackages { bitmask, blob };
|
||||
|
||||
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||
let round2_package = PackageContext::default()
|
||||
.with_block_number(current_block)
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(authority_index)
|
||||
.with_dkg_index(dkg_index)
|
||||
.with_dkg_round2(encryption_bundle)
|
||||
.expect("Round2 package should be valid");
|
||||
|
||||
@ -192,9 +185,9 @@ mod benchmarks {
|
||||
|
||||
#[benchmark]
|
||||
fn register_round3_complaints(
|
||||
c: Linear<1, { T::MaxAuthorities::get() }>
|
||||
c: Linear<1, { T::MaxAuthorities::get() / 8 }>
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let max_signers = c as AuthIndex;
|
||||
let max_signers = (c * 8) as AuthIndex;
|
||||
|
||||
let (mut dkg_state, network_curve, authority, authority_index) =
|
||||
prepare_pallet::<T>(max_signers as usize);
|
||||
@ -204,28 +197,26 @@ mod benchmarks {
|
||||
dkg_state.next_phase();
|
||||
dkg_state.next_phase();
|
||||
|
||||
let dkg_index = dkg_state.get_dkg_index();
|
||||
|
||||
(0..max_signers).for_each(|i| {
|
||||
dkg_state.insert_index(i);
|
||||
});
|
||||
|
||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||
|
||||
let mut accused_indexes = ParticipantsBitmap::<T>::empty(max_signers);
|
||||
let bitvec_len = (max_signers + 7) / 8;
|
||||
let mut accused_indexes = vec![0u8; bitvec_len as usize];
|
||||
|
||||
(0..max_signers).for_each(|i| {
|
||||
if i != authority_index {
|
||||
accused_indexes.insert(i);
|
||||
let byte_index = (i / 8) as usize;
|
||||
let bit_index = (i % 8) as u8;
|
||||
accused_indexes[byte_index] |= 1 << bit_index;
|
||||
}
|
||||
});
|
||||
|
||||
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||
let round3_package = PackageContext::default()
|
||||
.with_block_number(current_block)
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(authority_index)
|
||||
.with_dkg_index(dkg_index)
|
||||
.with_dkg_round3(accused_indexes)
|
||||
.expect("Round3 package should be valid");
|
||||
|
||||
@ -249,9 +240,9 @@ mod benchmarks {
|
||||
|
||||
#[benchmark]
|
||||
fn register_round4_justifications(
|
||||
c: Linear<1, { T::MaxAuthorities::get() }>
|
||||
c: Linear<1, { T::MaxAuthorities::get() / 8 }>
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let max_signers = c as AuthIndex;
|
||||
let max_signers = (c * 8) as AuthIndex;
|
||||
|
||||
let (mut dkg_state, network_curve, authority, authority_index) =
|
||||
prepare_pallet::<T>(max_signers as usize);
|
||||
@ -262,8 +253,6 @@ mod benchmarks {
|
||||
dkg_state.next_phase();
|
||||
dkg_state.next_phase();
|
||||
|
||||
let dkg_index = dkg_state.get_dkg_index();
|
||||
|
||||
(0..max_signers).for_each(|i| {
|
||||
dkg_state.insert_index(i);
|
||||
});
|
||||
@ -275,29 +264,29 @@ mod benchmarks {
|
||||
|
||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||
|
||||
let bitmask_len = padded_participants.div_ceil(8);
|
||||
let blob_len = round2_package_size(
|
||||
padded_participants - 1,
|
||||
padded_participants,
|
||||
network_curve.scalar_bytes_len(),
|
||||
network_curve.header_bytes_len(),
|
||||
);
|
||||
|
||||
let mut bitmask = ParticipantsBitmap::<T>::empty(padded_participants);
|
||||
let mut bitmask = vec![0u8; bitmask_len];
|
||||
let blob = vec![0u8; blob_len];
|
||||
|
||||
(0..max_signers).for_each(|i| {
|
||||
if i != authority_index {
|
||||
bitmask.insert(i);
|
||||
let byte_index = (i / 8) as usize;
|
||||
let bit_index = (i % 8) as u8;
|
||||
bitmask[byte_index] |= 1 << bit_index;
|
||||
}
|
||||
});
|
||||
|
||||
let justification_bundle = BundledPackages { bitmask, blob };
|
||||
|
||||
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||
let round4_package = PackageContext::default()
|
||||
.with_block_number(current_block)
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(authority_index)
|
||||
.with_dkg_index(dkg_index)
|
||||
.with_dkg_round4(justification_bundle)
|
||||
.expect("Round4 package should be valid");
|
||||
|
||||
@ -343,19 +332,11 @@ mod benchmarks {
|
||||
|
||||
let dummy_merkle_root = ExodusHash::repeat_byte(69);
|
||||
let dummy_verifying_key = vec![69u8; network_curve.element_bytes_len()];
|
||||
let dummy_key_members = ParticipantsBitmap::<T>::empty(4);
|
||||
|
||||
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||
let round5_package = PackageContext::default()
|
||||
.with_block_number(current_block)
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(authority_index)
|
||||
.with_dkg_index(dkg_index)
|
||||
.with_dkg_round5(
|
||||
dummy_verifying_key.clone(),
|
||||
dummy_key_members.clone(),
|
||||
dummy_merkle_root,
|
||||
)
|
||||
.with_dkg_round5(dummy_verifying_key.clone(), dummy_merkle_root)
|
||||
.expect("Round5 package should be valid");
|
||||
|
||||
let dkg_package = DkgPackage::Round5(round5_package);
|
||||
@ -373,22 +354,20 @@ mod benchmarks {
|
||||
).expect("Bounded verifying key should be correct");
|
||||
|
||||
let metadata_hashes = [
|
||||
dummy_merkle_root.as_ref(),
|
||||
bounded_verifying_key.as_ref(),
|
||||
dummy_key_members.inner_as_ref(),
|
||||
SubstrateBlake2Hasher::hash(dummy_merkle_root.as_ref()),
|
||||
SubstrateBlake2Hasher::hash(bounded_verifying_key.as_ref()),
|
||||
];
|
||||
let verifying_hash = cumulative_hash::<SubstrateBlake2Hasher, _>(metadata_hashes);
|
||||
let verifying_hash = sequential_hash::<SubstrateBlake2Hasher, _>(metadata_hashes);
|
||||
|
||||
let verification_key = (network_curve, dkg_index, verifying_hash);
|
||||
let participants = Verifications::<T>::get(verification_key);
|
||||
assert!(participants.contains(authority_index));
|
||||
|
||||
let consensus = VerifyingKeyConsensus::<T>::get(&network_curve, dkg_index);
|
||||
assert!(consensus.state.participants.contains(authority_index));
|
||||
assert_eq!(consensus.state.participants.count_ones::<AuthIndex>(), 1);
|
||||
assert_eq!(consensus.state.merkle_root, dummy_merkle_root);
|
||||
assert_eq!(consensus.state.element_bytes, bounded_verifying_key);
|
||||
assert_eq!(consensus.members, dummy_key_members);
|
||||
assert!(consensus.participants.contains(authority_index));
|
||||
assert_eq!(consensus.participants.count_ones::<AuthIndex>(), 1);
|
||||
assert_eq!(consensus.merkle_root, dummy_merkle_root);
|
||||
assert_eq!(consensus.element_bytes, bounded_verifying_key);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -436,16 +415,10 @@ mod benchmarks {
|
||||
dummy_values.insert(identifier, dummy_value.clone());
|
||||
}
|
||||
|
||||
let identifier_size = network_curve.scalar_bytes_len();
|
||||
|
||||
let merkle_tree =
|
||||
NetworkCurve::build_merkle_tree(
|
||||
identifier_size + dummy_value.len(),
|
||||
&dummy_values,
|
||||
|value, buffer| {
|
||||
buffer.extend_from_slice(value.as_ref());
|
||||
Ok(())
|
||||
}
|
||||
|value: &Vec<u8>| Ok(value.clone()),
|
||||
).expect("Merkle tree for verifying shares should be valid");
|
||||
|
||||
let merkle_root = merkle_tree.last().copied().unwrap();
|
||||
@ -461,16 +434,13 @@ mod benchmarks {
|
||||
});
|
||||
|
||||
VerifyingKeyConsensus::<T>::mutate(&network_curve, &dkg_index, |consensus| {
|
||||
consensus.state.participants.insert(authority_index);
|
||||
consensus.state.merkle_root = dummy_merkle_root;
|
||||
consensus.participants.insert(authority_index);
|
||||
consensus.merkle_root = dummy_merkle_root;
|
||||
});
|
||||
|
||||
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||
let round6_package = PackageContext::default()
|
||||
.with_block_number(current_block)
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(authority_index)
|
||||
.with_dkg_index(dkg_index)
|
||||
.with_dkg_round6(dummy_verifying_share.clone(), dummy_merkle_proof)
|
||||
.expect("Round6 package should be valid");
|
||||
|
||||
@ -512,54 +482,39 @@ mod benchmarks {
|
||||
}
|
||||
|
||||
dkg_state.insert_index(authority_index);
|
||||
let all_exodus_sessions = CurrentExodusSessions::<T>::get();
|
||||
let exodus_session = all_exodus_sessions
|
||||
.get(&network_id)
|
||||
.copied()
|
||||
.unwrap_or(0);
|
||||
let exodus_session = CurrentExodus::<T>::get();
|
||||
|
||||
let dummy_context = ExodusContext::new(network_id, exodus_session);
|
||||
let dummy_address = EvmAddress::repeat_byte(69);
|
||||
|
||||
// generator point for secp256k1
|
||||
let dummy_nonce = [
|
||||
0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55,
|
||||
0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc,
|
||||
0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b, 0x16,
|
||||
0xf8, 0x17, 0x98
|
||||
];
|
||||
let dummy_nonce = vec![0u8; network_curve.element_bytes_len()];
|
||||
|
||||
let create_bond = GovernanceAction::Create {
|
||||
market: [69, 420, 1337, 0],
|
||||
market: [69, 420, 1337],
|
||||
terms: [420, 1337],
|
||||
token: dummy_address,
|
||||
intervals: [34, 35],
|
||||
booleans: [true, true],
|
||||
};
|
||||
let request = ExodusRequest::<T>::evm_governance(
|
||||
let request = ExodusRequest::<NetworkIdOf<T>, BalanceOf<T>>::evm_governance(
|
||||
exodus_session,
|
||||
network_id,
|
||||
dummy_address,
|
||||
create_bond,
|
||||
);
|
||||
|
||||
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||
let authorities = QualificationAuthorities::<T>::get(&network_curve);
|
||||
let active_dkg: ReadyDkgAuthorities<T> = (&dkg_state).into();
|
||||
let active_dkg_index = active_dkg.get_dkg_index();
|
||||
|
||||
let active_dkg: ActivatedState<T> = (&dkg_state).into();
|
||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||
ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
|
||||
ActiveAuthorities::<T>::insert(&network_curve, authorities);
|
||||
ExodusRequests::<T>::insert((&network_curve, &dummy_context), request);
|
||||
ExodusRequests::<T>::insert(network_curve, exodus_session, request);
|
||||
|
||||
let nonce_package = PackageContext::default()
|
||||
.with_block_number(current_block)
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(authority_index)
|
||||
.with_dkg_index(active_dkg_index)
|
||||
.with_exodus_nonce_commitment(
|
||||
dummy_context,
|
||||
dummy_nonce.to_vec(),
|
||||
dummy_nonce.to_vec(),
|
||||
exodus_session,
|
||||
dummy_nonce.clone(),
|
||||
dummy_nonce.clone(),
|
||||
)
|
||||
.expect("Nonce commitment package should be valid");
|
||||
|
||||
@ -572,21 +527,21 @@ mod benchmarks {
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::None, exodus_package, signature);
|
||||
|
||||
let roast_session = RoastSessions::<T>::get(&dummy_context, authority_index)
|
||||
let roast_session = RoastSessions::<T>::get(&exodus_session, authority_index)
|
||||
.expect("ROAST session should exist after nonce commitment");
|
||||
|
||||
let roast_state = RoastSessionStates::<T>::get(&dummy_context, roast_session);
|
||||
let roast_state = RoastSessionStates::<T>::get(&exodus_session, roast_session);
|
||||
assert!(roast_state.nonce_committers.contains(authority_index));
|
||||
assert!(!roast_state.group_committers.contains(authority_index));
|
||||
assert!(!roast_state.partial_signers.contains(authority_index));
|
||||
|
||||
let registered_nonces = NonceCommitments::<T>::get(
|
||||
(dummy_context, roast_session),
|
||||
(exodus_session, roast_session),
|
||||
authority_index,
|
||||
).expect("Nonces should be registered during nonce commitment");
|
||||
|
||||
assert_eq!(registered_nonces.hiding.as_ref(), dummy_nonce);
|
||||
assert_eq!(registered_nonces.binding.as_ref(), dummy_nonce);
|
||||
assert_eq!(registered_nonces.hiding, dummy_nonce.clone());
|
||||
assert_eq!(registered_nonces.binding, dummy_nonce);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -603,55 +558,47 @@ mod benchmarks {
|
||||
}
|
||||
|
||||
dkg_state.insert_index(authority_index);
|
||||
let all_exodus_sessions = CurrentExodusSessions::<T>::get();
|
||||
let exodus_session = all_exodus_sessions
|
||||
.get(&network_id)
|
||||
.copied()
|
||||
.unwrap_or(0);
|
||||
let exodus_session = CurrentExodus::<T>::get();
|
||||
|
||||
let dummy_context = ExodusContext::new(network_id, exodus_session);
|
||||
let dummy_bytes = EvmBytes32::repeat_byte(69);
|
||||
let dummy_address = EvmAddress::repeat_byte(69);
|
||||
let dummy_merkle_root = ExodusHash::repeat_byte(69);
|
||||
let dummy_group_commitment = vec![0u8; network_curve.element_bytes_len()];
|
||||
|
||||
let create_bond = GovernanceAction::Create {
|
||||
market: [69, 420, 1337, 0],
|
||||
market: [69, 420, 1337],
|
||||
terms: [420, 1337],
|
||||
token: dummy_address,
|
||||
intervals: [34, 35],
|
||||
booleans: [true, true],
|
||||
};
|
||||
let request = ExodusRequest::<T>::evm_governance(
|
||||
let request = ExodusRequest::<NetworkIdOf<T>, BalanceOf<T>>::evm_governance(
|
||||
exodus_session,
|
||||
network_id,
|
||||
dummy_address,
|
||||
create_bond,
|
||||
);
|
||||
|
||||
let authorities = QualificationAuthorities::<T>::get(&network_curve);
|
||||
let active_dkg: ReadyDkgAuthorities<T> = (&dkg_state).into();
|
||||
let active_dkg_index = active_dkg.get_dkg_index();
|
||||
|
||||
let active_dkg: ActivatedState<T> = (&dkg_state).into();
|
||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||
ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
|
||||
ActiveAuthorities::<T>::insert(&network_curve, authorities);
|
||||
ExodusRequests::<T>::insert((network_curve, dummy_context), request);
|
||||
ExodusRequests::<T>::insert(network_curve, exodus_session, request);
|
||||
|
||||
let mut roast_state = RoastSessionState::<ParticipantsBitmap::<T>>::default();
|
||||
roast_state.status = RoastStatus::GroupCommitments;
|
||||
roast_state.nonce_committers.insert(authority_index);
|
||||
|
||||
let roast_session = 3;
|
||||
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||
RoastSessions::<T>::insert(&dummy_context, authority_index, roast_session);
|
||||
RoastSessionStates::<T>::insert(dummy_context, roast_session, roast_state);
|
||||
RoastSessions::<T>::insert(&exodus_session, authority_index, roast_session);
|
||||
RoastSessionStates::<T>::insert(exodus_session, roast_session, roast_state);
|
||||
|
||||
let group_package = PackageContext::default()
|
||||
.with_block_number(current_block)
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(authority_index)
|
||||
.with_dkg_index(active_dkg_index)
|
||||
.with_exodus_group_commitment(
|
||||
dummy_context,
|
||||
exodus_session,
|
||||
dummy_group_commitment.clone(),
|
||||
dummy_bytes,
|
||||
)
|
||||
@ -671,16 +618,16 @@ mod benchmarks {
|
||||
dummy_group_commitment,
|
||||
).expect("Group commtiment should be valid");
|
||||
|
||||
let roast_state = RoastSessionStates::<T>::get(&dummy_context, roast_session);
|
||||
let roast_state = RoastSessionStates::<T>::get(&exodus_session, roast_session);
|
||||
assert!(roast_state.nonce_committers.contains(authority_index));
|
||||
assert!(roast_state.group_committers.contains(authority_index));
|
||||
|
||||
let consensus = GroupCommitmentsConsensus::<T>::get(dummy_context, roast_session);
|
||||
let consensus = GroupCommitmentsConsensus::<T>::get(exodus_session, roast_session);
|
||||
assert!(consensus.participants.contains(authority_index));
|
||||
assert_eq!(&consensus.element_bytes, &bounded_group_commitment);
|
||||
assert_eq!(consensus.merkle_root, dummy_merkle_root);
|
||||
|
||||
let group_commitment_key = (dummy_context, roast_session, dummy_merkle_root, bounded_group_commitment);
|
||||
let group_commitment_key = (exodus_session, roast_session, dummy_merkle_root, bounded_group_commitment);
|
||||
let participants = GroupCommitters::<T>::get(group_commitment_key);
|
||||
assert!(participants.contains(authority_index));
|
||||
|
||||
@ -703,13 +650,7 @@ mod benchmarks {
|
||||
|
||||
dkg_state.insert_index(authority_index);
|
||||
let dkg_index = dkg_state.get_dkg_index();
|
||||
let all_exodus_sessions = CurrentExodusSessions::<T>::get();
|
||||
let exodus_session = all_exodus_sessions
|
||||
.get(&network_id)
|
||||
.copied()
|
||||
.unwrap_or(0);
|
||||
|
||||
let exodus_context = ExodusContext::new(network_id, exodus_session);
|
||||
let exodus_session = CurrentExodus::<T>::get();
|
||||
|
||||
let mut dummy_element = vec![0u8; network_curve.element_bytes_len()];
|
||||
dummy_element[0] = 0x02;
|
||||
@ -723,13 +664,15 @@ mod benchmarks {
|
||||
|
||||
let dummy_address = EvmAddress::repeat_byte(69);
|
||||
let create_bond = GovernanceAction::Create {
|
||||
market: [69, 420, 1337, 0],
|
||||
market: [69, 420, 1337],
|
||||
terms: [420, 1337],
|
||||
token: dummy_address,
|
||||
intervals: [34, 35],
|
||||
booleans: [true, true],
|
||||
};
|
||||
let request = ExodusRequest::<T>::evm_governance(
|
||||
let request = ExodusRequest::<NetworkIdOf<T>, BalanceOf<T>>::evm_governance(
|
||||
exodus_session,
|
||||
network_id,
|
||||
dummy_address,
|
||||
create_bond,
|
||||
);
|
||||
@ -754,16 +697,10 @@ mod benchmarks {
|
||||
dummy_values.insert(identifier, dummy_binding_factor.clone());
|
||||
}
|
||||
|
||||
let identifier_size = network_curve.scalar_bytes_len();
|
||||
|
||||
let merkle_tree =
|
||||
NetworkCurve::build_merkle_tree(
|
||||
identifier_size + dummy_scalar.len(),
|
||||
&dummy_values,
|
||||
|value, buffer| {
|
||||
buffer.extend_from_slice(value.as_ref());
|
||||
Ok(())
|
||||
}
|
||||
|value: &Vec<u8>| Ok(value.clone()),
|
||||
).expect("Merkle tree for binding factor should be valid");
|
||||
|
||||
let merkle_root = merkle_tree.last().copied().unwrap();
|
||||
@ -780,13 +717,13 @@ mod benchmarks {
|
||||
});
|
||||
|
||||
let authorities = QualificationAuthorities::<T>::get(&network_curve);
|
||||
let active_dkg: ReadyDkgAuthorities<T> = (&dkg_state).into();
|
||||
let active_dkg: ActivatedState<T> = (&dkg_state).into();
|
||||
let active_dkg_index = active_dkg.get_dkg_index();
|
||||
|
||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||
ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
|
||||
ActiveAuthorities::<T>::insert(&network_curve, authorities);
|
||||
ExodusRequests::<T>::insert((network_curve, exodus_context), request);
|
||||
ExodusRequests::<T>::insert(network_curve, exodus_session, request);
|
||||
|
||||
let mut roast_state = RoastSessionState::<ParticipantsBitmap::<T>>::default();
|
||||
roast_state.status = RoastStatus::PartialSignatures;
|
||||
@ -799,8 +736,8 @@ mod benchmarks {
|
||||
});
|
||||
|
||||
let roast_session = 3;
|
||||
RoastSessions::<T>::insert(&exodus_context, authority_index, roast_session);
|
||||
RoastSessionStates::<T>::insert(exodus_context, roast_session, roast_state);
|
||||
RoastSessions::<T>::insert(&exodus_session, authority_index, roast_session);
|
||||
RoastSessionStates::<T>::insert(exodus_session, roast_session, roast_state);
|
||||
|
||||
let bounded_group_commitment = BoundedVec::try_from(dummy_group_commitment).unwrap();
|
||||
let dummy_verifying_key = BoundedVec::try_from(dummy_element.clone()).unwrap();
|
||||
@ -813,9 +750,9 @@ mod benchmarks {
|
||||
|
||||
ActiveVerifyingKey::<T>::insert(&network_curve, dummy_verifying_key);
|
||||
VerifyingShares::<T>::insert((&network_curve, active_dkg_index, authority_index), dummy_verifying_share);
|
||||
NonceCommitments::<T>::insert((&exodus_context, &roast_session), authority_index, dummy_nonce);
|
||||
NonceCommitments::<T>::insert((&exodus_session, &roast_session), authority_index, dummy_nonce);
|
||||
|
||||
GroupCommitmentsConsensus::<T>::mutate(&exodus_context, &roast_session, |consensus| {
|
||||
GroupCommitmentsConsensus::<T>::mutate(&exodus_session, &roast_session, |consensus| {
|
||||
consensus.element_bytes = bounded_group_commitment.clone();
|
||||
consensus.merkle_root = dummy_merkle_root;
|
||||
(0..threshold).for_each(|i| {
|
||||
@ -823,14 +760,11 @@ mod benchmarks {
|
||||
});
|
||||
});
|
||||
|
||||
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||
let share_package = PackageContext::default()
|
||||
.with_block_number(current_block)
|
||||
.with_network_curve(NetworkCurve::Secp256k1)
|
||||
.with_authority_index(authority_index)
|
||||
.with_dkg_index(active_dkg_index)
|
||||
.with_exodus_signature_share(
|
||||
exodus_context,
|
||||
exodus_session,
|
||||
dummy_signature_share.clone(),
|
||||
dummy_merkle_proof,
|
||||
dummy_binding_factor
|
||||
@ -846,13 +780,13 @@ mod benchmarks {
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::None, exodus_package, signature);
|
||||
|
||||
let maybe_roast_session = RoastSessions::<T>::get(&exodus_context, authority_index);
|
||||
let maybe_roast_session = RoastSessions::<T>::get(&exodus_session, authority_index);
|
||||
assert!(maybe_roast_session.is_none());
|
||||
|
||||
let scalar_exists = SignatureScalars::<T>::contains_key(&exodus_context, &roast_session);
|
||||
let consensus_exists = GroupCommitmentsConsensus::<T>::contains_key(&exodus_context, &roast_session);
|
||||
let scalar_exists = SignatureScalars::<T>::contains_key(&exodus_session, &roast_session);
|
||||
let consensus_exists = GroupCommitmentsConsensus::<T>::contains_key(&exodus_session, &roast_session);
|
||||
let committers_exists = GroupCommitters::<T>::contains_key((
|
||||
&exodus_context,
|
||||
&exodus_session,
|
||||
&roast_session,
|
||||
&dummy_merkle_root,
|
||||
&bounded_group_commitment,
|
||||
@ -862,8 +796,8 @@ mod benchmarks {
|
||||
assert!(!consensus_exists);
|
||||
assert!(!committers_exists);
|
||||
|
||||
assert!(!ExodusRequests::<T>::contains_key((&network_curve, &exodus_context)));
|
||||
assert!(ExodusSignedGovernance::<T>::contains_key(dkg_index, &exodus_context));
|
||||
assert!(!ExodusRequests::<T>::contains_key(&network_curve, &exodus_session));
|
||||
assert!(ExodusSignedGovernance::<T>::contains_key((&exodus_session, network_id), dkg_index));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -874,9 +808,7 @@ mod benchmarks {
|
||||
let (_, network_curve, _, _) = prepare_pallet::<T>(1usize);
|
||||
|
||||
let network_id = NetworkIdOf::<T>::default();
|
||||
let base_amount: BalanceOf<T> = T::BaseEvmAmount::get().unique_saturated_into();
|
||||
let amount = base_amount.saturating_add(T::Currency::minimum_balance());
|
||||
|
||||
let amount: BalanceOf<T> = 10_000u32.into();
|
||||
let bounty = Perbill::from_percent(5);
|
||||
let receiver = EvmAddress::from([69u8; 20]);
|
||||
|
||||
@ -887,19 +819,15 @@ mod benchmarks {
|
||||
}
|
||||
});
|
||||
|
||||
let initial_balance = T::Currency::minimum_balance()
|
||||
let total_existential = T::Currency::minimum_balance();
|
||||
let initial_balance = total_existential
|
||||
.saturating_mul(5u32.into())
|
||||
.saturating_add(amount);
|
||||
|
||||
T::Currency::mint_into(&caller, initial_balance).unwrap();
|
||||
let _ = T::Currency::make_free_balance_be(&caller, initial_balance);
|
||||
let _ = T::NetworkDataHandler::register_incoming(&network_id, amount).unwrap();
|
||||
|
||||
let total_issuance = T::Currency::total_issuance();
|
||||
let all_exodus_sessions = CurrentExodusSessions::<T>::get();
|
||||
let current_exodus_session = all_exodus_sessions
|
||||
.get(&network_id)
|
||||
.copied()
|
||||
.unwrap_or(0);
|
||||
let current_exodus_session = CurrentExodus::<T>::get();
|
||||
|
||||
#[extrinsic_call]
|
||||
_(
|
||||
@ -910,14 +838,9 @@ mod benchmarks {
|
||||
receiver,
|
||||
);
|
||||
|
||||
let all_exodus_sessions = CurrentExodusSessions::<T>::get();
|
||||
let last_exodus_session = all_exodus_sessions.get(&network_id).copied().unwrap();
|
||||
let context = ExodusContext::new(network_id, current_exodus_session);
|
||||
|
||||
assert!(ExodusRequests::<T>::contains_key((&network_curve, &context)));
|
||||
assert_eq!(last_exodus_session, current_exodus_session + 1);
|
||||
assert_eq!(T::Currency::balance(&caller), initial_balance - amount);
|
||||
assert_eq!(T::Currency::total_issuance(), total_issuance - amount);
|
||||
assert!(ExodusRequests::<T>::contains_key(&network_curve, current_exodus_session));
|
||||
assert_eq!(CurrentExodus::<T>::get(), current_exodus_session + 1);
|
||||
assert_eq!(T::Currency::free_balance(&caller), initial_balance - amount);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -43,53 +43,51 @@ pub enum ExodusError {
|
||||
InvalidMerkleProof,
|
||||
InvalidIdentityElement,
|
||||
NoActiveAuthorities,
|
||||
TreeGenerationFailed,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for ExodusError {
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match *self {
|
||||
ExodusError::InvalidParticipantId => write!(fmt, "Participant index could not be parsed as an identifier."),
|
||||
ExodusError::DeserializationError => write!(fmt, "Error while deserializing value."),
|
||||
ExodusError::SerializationError => write!(fmt, "Error while serializing value."),
|
||||
ExodusError::InvalidParticipantId => write!(fmt, "Participant index could not be parsed to identifier."),
|
||||
ExodusError::DeserializationError => write!(fmt, "Error during deserializing value."),
|
||||
ExodusError::SerializationError => write!(fmt, "Error serializing value."),
|
||||
ExodusError::InvalidMinSigners(min, max) => write!(fmt, "Number of min_signers ({min}) must be at least 2 and not larger than max_signers ({max})."),
|
||||
ExodusError::InvalidMaxSigners(max_signers) => write!(fmt, "Number of max_signers must be at least 2, {max_signers} given."),
|
||||
ExodusError::DKGNotSupported(ref curve) => write!(fmt, "The ciphersuite {curve:?} does not support DKG."),
|
||||
ExodusError::IncorrectNumberOfCoefficients => write!(fmt, "Incorrect number of coefficients; should be equal to min signers."),
|
||||
ExodusError::IncorrectNumberOfCommitments => write!(fmt, "Incorrect number of commitments; should be equal to min signers."),
|
||||
ExodusError::InvalidNonceCommitments => write!(fmt, "Hiding nonce commitment indices should match binding nonce commitments."),
|
||||
ExodusError::InvalidProofOfKnowledge => write!(fmt, "Invalid proof of knowledge."),
|
||||
ExodusError::InvalidNonceCommitments => write!(fmt, "Hiding nonce commitments indexes should match binding nonce commitments."),
|
||||
ExodusError::InvalidProofOfKnowledge => write!(fmt, "The proof of knowledge is not valid."),
|
||||
ExodusError::IncorrectNumberOfPackages => write!(fmt, "Incorrect number of packages; should be equal to max signers."),
|
||||
ExodusError::IncorrectPackage => write!(fmt, "An incorrect package was specified."),
|
||||
ExodusError::IncorrectPackage => write!(fmt, "The incorrect package was specified."),
|
||||
ExodusError::PackageNotFound => write!(fmt, "Round 1 package not found for Round 2 participant."),
|
||||
ExodusError::InvalidSecretShare => write!(fmt, "Invalid secret share."),
|
||||
ExodusError::MissingCommitment => write!(fmt, "The signing package must contain the participant's Commitments."),
|
||||
ExodusError::MissingCommitment => write!(fmt, "The Signing Package must contain the participant's Commitments."),
|
||||
ExodusError::IncorrectCommitment => write!(fmt, "The participant's commitment is incorrect."),
|
||||
ExodusError::UnknownIdentifier => write!(fmt, "Unknown identifier provided."),
|
||||
ExodusError::UnknownIdentifier => write!(fmt, "Unknown identifier."),
|
||||
ExodusError::IdentityCommitment => write!(fmt, "Commitment equals the identity."),
|
||||
ExodusError::DuplicatedIdentifier => write!(fmt, "Duplicated identifier."),
|
||||
ExodusError::IncorrectNumberOfIdentifiers => write!(fmt, "Incorrect number of identifiers."),
|
||||
ExodusError::InvalidSignature => write!(fmt, "Invalid signature provided."),
|
||||
ExodusError::InvalidSignatureShare => write!(fmt, "Invalid signature share provided."),
|
||||
ExodusError::InvalidSignature => write!(fmt, "Invalid signature."),
|
||||
ExodusError::InvalidSignatureShare => write!(fmt, "Invalid signature share."),
|
||||
ExodusError::EncryptionFailed => write!(fmt, "Encryption failed."),
|
||||
ExodusError::DecryptionFailed => write!(fmt, "Decryption failed."),
|
||||
ExodusError::HKDFFailed => write!(fmt, "HKDF failed."),
|
||||
ExodusError::InvalidNonceLength => write!(fmt, "Encryption nonce has invalid length."),
|
||||
ExodusError::MalformedSigningKey => write!(fmt, "Malformed signing key encoding."),
|
||||
ExodusError::NoStoredNetworks => write!(fmt, "No stored networks to work on."),
|
||||
ExodusError::NoStoredNetworks => write!(fmt, "No stored networks to be worked on."),
|
||||
ExodusError::OffchainTimeoutPeriod => write!(fmt, "Offchain request should be in-flight."),
|
||||
ExodusError::BadSignature(auth_index) => write!(fmt, "Signature could not be created from {auth_index}."),
|
||||
ExodusError::TransactionSubmissionFailed(auth_index) => write!(fmt, "Could not submit transaction from {auth_index}."),
|
||||
ExodusError::UnknownReceiverIndex(receiver_index) => write!(fmt, "Unknown receiver index {receiver_index} found."),
|
||||
ExodusError::CouldNotConstructMessage(auth_index) => write!(fmt, "Could not construct message during OCW from {auth_index}."),
|
||||
ExodusError::NothingToWrite => write!(fmt, "Nothing to write to local storage."),
|
||||
ExodusError::NothingToWrite => write!(fmt, "Nothing to write into local storage."),
|
||||
ExodusError::UnknownPrefix => write!(fmt, "Unknown prefix used for local storage."),
|
||||
ExodusError::UnexpectedRound => write!(fmt, "Unexpected round provided."),
|
||||
ExodusError::InvalidMerkleProof => write!(fmt, "Invalid Merkle proof provided."),
|
||||
ExodusError::InvalidMerkleProof => write!(fmt, "Invalid merkle proof provided."),
|
||||
ExodusError::InvalidIdentityElement => write!(fmt, "Invalid identity element provided."),
|
||||
ExodusError::NoActiveAuthorities => write!(fmt, "No active authorities for signing EXODUS transactions."),
|
||||
ExodusError::TreeGenerationFailed => write!(fmt, "Tree generation failed because of inconsistent indexation."),
|
||||
ExodusError::NoActiveAuthorities => write!(fmt, "No active authorities for signing exodus transactions."),
|
||||
ExodusError::Unknown => write!(fmt, "Unknown error."),
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ use rand_chacha::rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use ghost_traits::exodus::{
|
||||
DistributedKeyGeneration, IdentifierConverter, MerkleTreeBuilder,
|
||||
CiphersuiteSizes,
|
||||
};
|
||||
|
||||
use crate::{AuthIndex, ExodusError, NetworkCurve};
|
||||
@ -242,8 +241,6 @@ impl DistributedKeyGeneration<AuthIndex, ExodusError> for NetworkCurve {
|
||||
round2_packages_bytes: &Self::RoundPackages,
|
||||
) -> Self::Part3Result {
|
||||
with_ciphersuite!(self, |f| {
|
||||
type InnerGroup = <Ciphersuite as frost_core::Ciphersuite>::Group;
|
||||
|
||||
let round2_secret_package = f::keys::dkg::round2::SecretPackage::deserialize(round2_secret_package_bytes)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
@ -294,24 +291,13 @@ impl DistributedKeyGeneration<AuthIndex, ExodusError> for NetworkCurve {
|
||||
let key_package_bytes = key_package.serialize()
|
||||
.map_err(|_| ExodusError::SerializationError)?;
|
||||
|
||||
let identifier_size = self.scalar_bytes_len();
|
||||
let verifying_share_size = self.element_bytes_len();
|
||||
|
||||
let verifying_shares_merkle_tree =
|
||||
Self::build_merkle_tree(
|
||||
identifier_size + verifying_share_size,
|
||||
pubkey_package.verifying_shares(),
|
||||
|verifying_share, buffer| {
|
||||
let serialized = <InnerGroup as frost_core::Group>::serialize(
|
||||
&verifying_share.to_element()
|
||||
).map_err(|_| ExodusError::SerializationError)?;
|
||||
|
||||
buffer.extend_from_slice(serialized.as_ref());
|
||||
Ok(())
|
||||
}
|
||||
|verifying_share| verifying_share.serialize()
|
||||
.map_err(|_| ExodusError::SerializationError)
|
||||
)?;
|
||||
|
||||
// TODO: make it better
|
||||
let (_, merkle_proof) =
|
||||
Self::generate_merkle_proof_from_tree(
|
||||
pubkey_package.verifying_shares(),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use ghost_traits::exodus::{
|
||||
CiphersuiteSizes, IdentifierConverter, MerkleTreeBuilder,
|
||||
IdentifierConverter, MerkleTreeBuilder,
|
||||
FlexibleRoundOptimizedSchnorrThresholdSignature,
|
||||
};
|
||||
use sp_std::{
|
||||
@ -15,6 +15,29 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
|
||||
type Packages<'a> = BTreeMap<AuthIndex, &'a [u8]>;
|
||||
type NoncePackages<'a> = BTreeMap<AuthIndex, (&'a [u8], &'a [u8])>;
|
||||
|
||||
fn header_bytes_len(&self) -> usize { 5 }
|
||||
|
||||
fn signature_bytes_len(&self) -> usize {
|
||||
match self {
|
||||
NetworkCurve::Secp256k1 => 64,
|
||||
NetworkCurve::Ed25519 => 64,
|
||||
}
|
||||
}
|
||||
|
||||
fn element_bytes_len(&self) -> usize {
|
||||
match self {
|
||||
NetworkCurve::Secp256k1 => 33,
|
||||
NetworkCurve::Ed25519 => 32,
|
||||
}
|
||||
}
|
||||
|
||||
fn scalar_bytes_len(&self) -> usize {
|
||||
match self {
|
||||
NetworkCurve::Secp256k1 => 32,
|
||||
NetworkCurve::Ed25519 => 32,
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_signature_share(
|
||||
&self,
|
||||
index: AuthIndex,
|
||||
@ -163,19 +186,6 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
|
||||
})
|
||||
}
|
||||
|
||||
fn is_nonce_valid_point(&self, nonce_bytes: &[u8]) -> Result<(), ExodusError> {
|
||||
with_ciphersuite!(self, |f| {
|
||||
type InnerGroup = <Ciphersuite as frost_core::Ciphersuite>::Group;
|
||||
|
||||
let serialized_nonce = <InnerGroup as frost_core::Group>::Serialization::try_from(nonce_bytes)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
<InnerGroup as frost_core::Group>::deserialize(&serialized_nonce)
|
||||
.map_err(|_| ExodusError::DeserializationError)
|
||||
.map(|_| ())
|
||||
})
|
||||
}
|
||||
|
||||
fn is_signature_valid(
|
||||
&self,
|
||||
verifying_key_bytes: &[u8],
|
||||
@ -320,16 +330,11 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
|
||||
return Err(ExodusError::InvalidParticipantId);
|
||||
}
|
||||
|
||||
let identifier_size = self.scalar_bytes_len();
|
||||
let binding_factor_size = self.scalar_bytes_len();
|
||||
|
||||
let binding_factor_tree = Self::build_merkle_tree(
|
||||
identifier_size + binding_factor_size,
|
||||
&binding_factors_list,
|
||||
|binding_factor, buffer| {
|
||||
|binding_factor| {
|
||||
let serialized = <InnerField as frost_core::Field>::serialize(binding_factor);
|
||||
buffer.extend_from_slice(serialized.as_ref());
|
||||
Ok(())
|
||||
Ok(serialized.as_ref().to_vec())
|
||||
}
|
||||
)?;
|
||||
|
||||
|
||||
@ -13,16 +13,15 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
||||
type Hash = <SubstrateBlake2Hasher as GhostHasher>::Hash;
|
||||
|
||||
fn build_merkle_tree<C, V, F>(
|
||||
size_hint: usize,
|
||||
values: &BTreeMap<Identifier<C>, V>,
|
||||
update_preimage_buffer: F,
|
||||
serialize_fn: F,
|
||||
) -> Result<Vec<Self::Hash>, ExodusError>
|
||||
where
|
||||
C: frost_core::Ciphersuite,
|
||||
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
||||
F: Fn(&V, &mut Vec<u8>) -> Result<(), ExodusError>
|
||||
F: Fn(&V) -> Result<Vec<u8>, ExodusError>
|
||||
{
|
||||
use ghost_helpers::merkle_tree::{generate_tree, MerkleTreeError};
|
||||
use ghost_helpers::merkle_tree::generate_tree;
|
||||
|
||||
type CField<C> = <<C as Ciphersuite>::Group as Group>::Field;
|
||||
|
||||
@ -35,28 +34,25 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
||||
})
|
||||
.ok_or(ExodusError::IncorrectNumberOfIdentifiers)?;
|
||||
|
||||
let maybe_tree = generate_tree::<SubstrateBlake2Hasher, _, _, _, _>(
|
||||
generate_tree::<SubstrateBlake2Hasher, _, _, _, _>(
|
||||
max_index,
|
||||
size_hint,
|
||||
values.iter(),
|
||||
|(identifier, value), buffer| {
|
||||
|(identifier, value)| {
|
||||
let id_scalar = identifier.to_scalar();
|
||||
let id_bytes = <CField<C> as frost_core::Field>::serialize(&id_scalar);
|
||||
|
||||
let index = Self::convert_identifier_to_index(id_bytes.as_ref())?;
|
||||
let value_bytes = serialize_fn(value).map_err(|_| ExodusError::SerializationError)?;
|
||||
|
||||
buffer.extend_from_slice(id_bytes.as_ref());
|
||||
update_preimage_buffer(value, buffer)?;
|
||||
// NOTE: revisit
|
||||
// Is it possible to use [u8; CONSTANT] where constant is
|
||||
// purely dependant on provided generic.
|
||||
let mut preimage = Vec::<u8>::with_capacity(id_bytes.as_ref().len() + value_bytes.len());
|
||||
preimage.extend_from_slice(id_bytes.as_ref());
|
||||
preimage.extend_from_slice(value_bytes.as_ref());
|
||||
|
||||
Ok(index as usize)
|
||||
});
|
||||
|
||||
match maybe_tree {
|
||||
Ok(tree) => Ok(tree),
|
||||
Err(MerkleTreeError::Generate(exodus_err)) => Err(exodus_err),
|
||||
Err(MerkleTreeError::InvalidIndex) => Err(ExodusError::TreeGenerationFailed),
|
||||
Err(MerkleTreeError::Empty) => Err(ExodusError::IncorrectNumberOfIdentifiers),
|
||||
}
|
||||
Ok((index as usize, preimage))
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_merkle_proof_from_tree<C, V, F>(
|
||||
@ -70,7 +66,7 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
||||
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
||||
F: Fn(&V) -> Result<Vec<u8>, ExodusError>
|
||||
{
|
||||
use ghost_helpers::merkle_tree::{generate_proof, MerkleTreeError};
|
||||
use ghost_helpers::merkle_tree::generate_proof;
|
||||
|
||||
type CField<C> = <<C as Ciphersuite>::Group as Group>::Field;
|
||||
|
||||
@ -79,7 +75,7 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
||||
.map_err(|_| ExodusError::InvalidParticipantId)?;
|
||||
|
||||
let value = values.get(&identifier).ok_or(ExodusError::InvalidParticipantId)?;
|
||||
let value_bytes = serialize_fn(&value)?;
|
||||
let value_bytes = serialize_fn(&value).map_err(|_| ExodusError::SerializationError)?;
|
||||
|
||||
let max_index = values.keys()
|
||||
.next_back()
|
||||
@ -90,15 +86,11 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
||||
})
|
||||
.ok_or(ExodusError::IncorrectNumberOfIdentifiers)?;
|
||||
|
||||
let proof = generate_proof::<SubstrateBlake2Hasher, _, _>(
|
||||
let proof = generate_proof::<SubstrateBlake2Hasher, _>(
|
||||
merkle_tree,
|
||||
max_index,
|
||||
authority_index,
|
||||
).map_err(|err| match err {
|
||||
MerkleTreeError::Generate(exodus_err) => exodus_err,
|
||||
MerkleTreeError::InvalidIndex => ExodusError::TreeGenerationFailed,
|
||||
MerkleTreeError::Empty => ExodusError::IncorrectNumberOfIdentifiers,
|
||||
})?;
|
||||
);
|
||||
|
||||
Ok((value_bytes, proof))
|
||||
}
|
||||
|
||||
@ -72,6 +72,3 @@ mod ecdh;
|
||||
|
||||
#[macro_use]
|
||||
mod frost;
|
||||
|
||||
#[macro_use]
|
||||
mod sizes;
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
use ghost_helpers::networks::NetworkCurve;
|
||||
use ghost_traits::exodus::CiphersuiteSizes;
|
||||
|
||||
use crate::{AuthIndex, ExodusError};
|
||||
|
||||
impl CiphersuiteSizes<AuthIndex, ExodusError> for NetworkCurve {
|
||||
fn header_bytes_len(&self) -> usize { 5 }
|
||||
|
||||
fn signature_bytes_len(&self) -> usize {
|
||||
match self {
|
||||
NetworkCurve::Secp256k1 => 64,
|
||||
NetworkCurve::Ed25519 => 64,
|
||||
}
|
||||
}
|
||||
|
||||
fn element_bytes_len(&self) -> usize {
|
||||
match self {
|
||||
NetworkCurve::Secp256k1 => 33,
|
||||
NetworkCurve::Ed25519 => 32,
|
||||
}
|
||||
}
|
||||
|
||||
fn scalar_bytes_len(&self) -> usize {
|
||||
match self {
|
||||
NetworkCurve::Secp256k1 => 32,
|
||||
NetworkCurve::Ed25519 => 32,
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@
|
||||
use frame_system::EnsureRoot;
|
||||
use frame_support::{
|
||||
derive_impl, parameter_types,
|
||||
traits::{ConstU32, ConstU64, ConstU128},
|
||||
traits::{ConstU32, ConstU64},
|
||||
};
|
||||
use crate as ghost_exodus;
|
||||
|
||||
@ -41,7 +41,7 @@ impl frame_system::Config for Runtime {
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub static FixedAuthorities: Vec<u64> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
pub static FixedAuthorities: Vec<u64> = vec![0, 1, 2, 3];
|
||||
}
|
||||
|
||||
pub struct TestSessionManager;
|
||||
@ -136,15 +136,13 @@ impl ghost_exodus::Config for Runtime {
|
||||
type DisabledValidators = Session;
|
||||
|
||||
type UnsignedPriority = ConstU64<{ 1 << 20 }>;
|
||||
type UnsignedLongevity = ConstU64<5>;
|
||||
type MaxAuthorities = ConstU32<15>;
|
||||
type MaxAuthoritiesChunks = ConstU32<2>;
|
||||
type UnsignedLongevity = ConstU64<1>;
|
||||
type MaxAuthorities = ConstU32<10>;
|
||||
type MaxAuthoritiesChunks = ConstU32<1>;
|
||||
|
||||
type DkgRoundPeriod = ConstU64<1000>;
|
||||
type DkgRoundPeriod = ConstU64<100>;
|
||||
type RemovalLimit = ConstU32<20>;
|
||||
type MaxCursorLen = ConstU32<256>;
|
||||
type BaseEvmAmount = ConstU128<5>;
|
||||
type MaxExodusRequestCount = ConstU32<40>;
|
||||
type MaxCursorLen = ConstU32<20>;
|
||||
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -6,30 +6,6 @@ use frame_support::{BoundedVec, traits::ConstU32};
|
||||
|
||||
use crate::{ExodusHash, ELEMENT_MAX_BYTES};
|
||||
|
||||
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||
pub struct QualifiedConsensusState<Bitmap> {
|
||||
pub state: ConsensusState<Bitmap>,
|
||||
pub members: Bitmap,
|
||||
}
|
||||
|
||||
impl<Bitmap> QualifiedConsensusState<Bitmap> {
|
||||
pub fn new(
|
||||
element_bytes: BoundedVec<u8, ConstU32<ELEMENT_MAX_BYTES>>,
|
||||
participants: Bitmap,
|
||||
merkle_root: ExodusHash,
|
||||
members: Bitmap,
|
||||
) -> Self {
|
||||
Self {
|
||||
members,
|
||||
state: ConsensusState::new(
|
||||
element_bytes,
|
||||
participants,
|
||||
merkle_root,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||
pub struct ConsensusState<Bitmap> {
|
||||
pub element_bytes: BoundedVec<u8, ConstU32<ELEMENT_MAX_BYTES>>,
|
||||
|
||||
@ -1,46 +1,28 @@
|
||||
use sp_runtime::{RuntimeDebug, traits::UniqueSaturatedInto};
|
||||
use codec::{Encode, Decode};
|
||||
use scale_info::TypeInfo;
|
||||
use strum::EnumCount;
|
||||
|
||||
use frame_support::{BoundedVec, traits::ConstU32};
|
||||
|
||||
use ghost_traits::{
|
||||
networks::NetworkDataBasicHandler,
|
||||
bounded_bitmap::{
|
||||
use ghost_helpers::networks::NetworkType;
|
||||
use ghost_traits::bounded_bitmap::{
|
||||
BoundedBitmapGenerator, BoundedBitmapReader, BoundedBitmapWriter,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ELEMENT_MAX_BYTES, Config, NetworkType, NetworkIdOf, ExodusContext,
|
||||
ParticipantsBitmap, BlockNumberFor, DkgIndex,
|
||||
};
|
||||
use crate::{ELEMENT_MAX_BYTES, ExodusSession, DkgIndex};
|
||||
|
||||
type RotationItem<T> = (NetworkType, ExodusContext<NetworkIdOf<T>>);
|
||||
type Rotations<T> = BoundedVec<
|
||||
RotationItem<T>,
|
||||
<<T as Config>::NetworkDataHandler as NetworkDataBasicHandler>::MaxNetworks,
|
||||
>;
|
||||
type RotationSessions = BoundedVec<RotationSession, ConstU32<{ NetworkType::COUNT as u32 }>>;
|
||||
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct ReadyDkgAuthorities<T: Config> {
|
||||
authorities_indexes: ParticipantsBitmap<T>,
|
||||
#[derive(Default, Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||
pub struct ReadyDkgAuthorities<AuthoritiesBitmap> {
|
||||
authorities_indexes: AuthoritiesBitmap,
|
||||
dkg_index: DkgIndex,
|
||||
}
|
||||
|
||||
impl<T: Config> Default for ReadyDkgAuthorities<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
authorities_indexes: Default::default(),
|
||||
dkg_index: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> ReadyDkgAuthorities<T>
|
||||
impl<AuthoritiesBitmap> ReadyDkgAuthorities<AuthoritiesBitmap>
|
||||
where
|
||||
ParticipantsBitmap<T>: BoundedBitmapReader,
|
||||
AuthoritiesBitmap: BoundedBitmapReader,
|
||||
{
|
||||
pub fn contains_index<N>(&self, index: N) -> bool
|
||||
where N: UniqueSaturatedInto<usize>,
|
||||
@ -48,7 +30,7 @@ where
|
||||
self.authorities_indexes.contains(index)
|
||||
}
|
||||
|
||||
pub fn get_indexes(&self) -> &ParticipantsBitmap<T> {
|
||||
pub fn get_indexes(&self) -> &AuthoritiesBitmap {
|
||||
&self.authorities_indexes
|
||||
}
|
||||
|
||||
@ -57,15 +39,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config>
|
||||
From<&PendingDkgAuthorities<T>>
|
||||
for ReadyDkgAuthorities<T>
|
||||
impl<AuthoritiesBitmap, Block>
|
||||
From<&PendingDkgAuthorities<AuthoritiesBitmap, Block>>
|
||||
for ReadyDkgAuthorities<AuthoritiesBitmap>
|
||||
where
|
||||
BlockNumberFor<T>: Copy,
|
||||
ParticipantsBitmap<T>: BoundedBitmapWriter + BoundedBitmapReader + BoundedBitmapGenerator + Clone,
|
||||
for<'a> ParticipantsBitmap<T>: core::ops::BitAndAssign<&'a ParticipantsBitmap<T>>,
|
||||
Block: Copy,
|
||||
AuthoritiesBitmap: BoundedBitmapWriter + BoundedBitmapReader + BoundedBitmapGenerator + Clone,
|
||||
for<'a> AuthoritiesBitmap: core::ops::BitAndAssign<&'a AuthoritiesBitmap>,
|
||||
{
|
||||
fn from(pending: &PendingDkgAuthorities<T>) -> Self {
|
||||
fn from(pending: &PendingDkgAuthorities<AuthoritiesBitmap, Block>) -> Self {
|
||||
Self {
|
||||
authorities_indexes: pending.get_indexes().clone(),
|
||||
dkg_index: pending.get_dkg_index(),
|
||||
@ -73,40 +55,34 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct PendingDkgAuthorities<T: Config> {
|
||||
#[derive(Default, Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||
pub struct RotationSession {
|
||||
pub exodus_session: ExodusSession,
|
||||
pub network_type: NetworkType
|
||||
}
|
||||
|
||||
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||
pub struct PendingDkgAuthorities<AuthoritiesBitmap, Block> {
|
||||
verifying_key: BoundedVec<u8, ConstU32<ELEMENT_MAX_BYTES>>,
|
||||
authorities_indexes: ParticipantsBitmap<T>,
|
||||
rotations: Rotations<T>,
|
||||
dkg_state: DkgState<BlockNumberFor<T>>,
|
||||
authorities_indexes: AuthoritiesBitmap,
|
||||
rotation_sessions: RotationSessions,
|
||||
dkg_state: DkgState<Block>,
|
||||
}
|
||||
|
||||
impl<T: Config> Default for PendingDkgAuthorities<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
verifying_key: Default::default(),
|
||||
authorities_indexes: Default::default(),
|
||||
rotations: Default::default(),
|
||||
dkg_state: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> PendingDkgAuthorities<T>
|
||||
impl<AuthoritiesBitmap, Block> PendingDkgAuthorities<AuthoritiesBitmap, Block>
|
||||
where
|
||||
BlockNumberFor<T>: Copy,
|
||||
ParticipantsBitmap<T>: BoundedBitmapWriter + BoundedBitmapReader + BoundedBitmapGenerator + Clone,
|
||||
for<'a> ParticipantsBitmap<T>: core::ops::BitAndAssign<&'a ParticipantsBitmap<T>>,
|
||||
Block: Copy,
|
||||
AuthoritiesBitmap: BoundedBitmapWriter + BoundedBitmapReader + BoundedBitmapGenerator + Clone,
|
||||
for<'a> AuthoritiesBitmap: core::ops::BitAndAssign<&'a AuthoritiesBitmap>,
|
||||
{
|
||||
pub fn new_dkg(&mut self, authorities_len: usize) {
|
||||
self.authorities_indexes = ParticipantsBitmap::<T>::empty(authorities_len);
|
||||
self.authorities_indexes = AuthoritiesBitmap::empty(authorities_len);
|
||||
self.dkg_state.restart();
|
||||
self.rotations = Default::default();
|
||||
self.rotation_sessions = Default::default();
|
||||
}
|
||||
|
||||
pub fn set_release_block(&mut self, block: BlockNumberFor<T>) {
|
||||
self.dkg_state.set_release_block(block);
|
||||
pub fn set_block(&mut self, block: Block) {
|
||||
self.dkg_state.set_block(block);
|
||||
}
|
||||
|
||||
pub fn set_verifying_key(
|
||||
@ -125,7 +101,7 @@ where
|
||||
self.verifying_key = Default::default();
|
||||
self.authorities_indexes.nullify();
|
||||
self.dkg_state.restart();
|
||||
self.rotations = Default::default();
|
||||
self.rotation_sessions = Default::default();
|
||||
}
|
||||
|
||||
pub fn next_phase(&mut self) {
|
||||
@ -133,7 +109,7 @@ where
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn intersect_indexes(&mut self, mask: &ParticipantsBitmap<T>) {
|
||||
pub fn intersect_indexes(&mut self, mask: &AuthoritiesBitmap) {
|
||||
self.authorities_indexes &= mask;
|
||||
}
|
||||
|
||||
@ -149,8 +125,8 @@ where
|
||||
self.dkg_state.get_dkg_index()
|
||||
}
|
||||
|
||||
pub fn get_release_block(&self) -> BlockNumberFor<T> {
|
||||
self.dkg_state.get_release_block()
|
||||
pub fn get_block(&self) -> Block {
|
||||
self.dkg_state.get_block()
|
||||
}
|
||||
|
||||
pub fn get_phase(&self) -> DkgPhase {
|
||||
@ -207,13 +183,17 @@ where
|
||||
self.authorities_indexes.insert(i)
|
||||
}
|
||||
|
||||
pub fn try_push_rotation(
|
||||
pub fn try_push_rotation_session(
|
||||
&mut self,
|
||||
exodus_session: ExodusSession,
|
||||
network_type: NetworkType,
|
||||
exodus_context: ExodusContext<NetworkIdOf<T>>,
|
||||
) -> Option<()> {
|
||||
let item = (network_type, exodus_context);
|
||||
self.rotations.try_push(item).ok()
|
||||
let rotation_session = RotationSession {
|
||||
exodus_session,
|
||||
network_type,
|
||||
};
|
||||
|
||||
self.rotation_sessions.try_push(rotation_session).ok()
|
||||
}
|
||||
|
||||
pub fn count_ones<N>(&self) -> N
|
||||
@ -228,44 +208,43 @@ where
|
||||
self.authorities_indexes.highest_bit()
|
||||
}
|
||||
|
||||
pub fn get_indexes(&self) -> &ParticipantsBitmap<T> {
|
||||
pub fn get_indexes(&self) -> &AuthoritiesBitmap {
|
||||
&self.authorities_indexes
|
||||
}
|
||||
|
||||
pub fn iter_rotations(
|
||||
&self
|
||||
) -> impl Iterator<Item = &RotationItem<T>> {
|
||||
self.rotations.iter()
|
||||
pub fn iter_rotation_sessions(&self) -> impl Iterator<Item = &RotationSession> {
|
||||
self.rotation_sessions.iter()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Default, Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||
pub struct DkgState<Block> {
|
||||
release_block: Block,
|
||||
dkg_index: DkgIndex,
|
||||
dkg_phase: DkgPhase,
|
||||
block: Block,
|
||||
index: DkgIndex,
|
||||
phase: DkgPhase,
|
||||
}
|
||||
|
||||
impl<Block: Copy> DkgState<Block> {
|
||||
fn is_dkg_pending(&self) -> bool { self.dkg_phase.is_dkg_pending() }
|
||||
fn is_dkg_vacant(&self) -> bool { self.dkg_phase.is_dkg_vacant() }
|
||||
fn is_dkg_pending(&self) -> bool { self.phase.is_dkg_pending() }
|
||||
fn is_dkg_vacant(&self) -> bool { self.phase.is_dkg_vacant() }
|
||||
|
||||
fn get_dkg_index(&self) -> DkgIndex { self.dkg_index }
|
||||
fn get_phase(&self) -> DkgPhase { self.dkg_phase }
|
||||
fn get_release_block(&self) -> Block { self.release_block }
|
||||
fn get_dkg_index(&self) -> DkgIndex { self.index }
|
||||
fn get_phase(&self) -> DkgPhase { self.phase }
|
||||
fn get_block(&self) -> Block { self.block }
|
||||
|
||||
fn restart(&mut self) {
|
||||
self.dkg_phase = Default::default();
|
||||
self.dkg_index = self.dkg_index.checked_add(1)
|
||||
self.phase = Default::default();
|
||||
self.index = self.index.checked_add(1)
|
||||
.unwrap_or_default();
|
||||
}
|
||||
|
||||
fn next_phase(&mut self) {
|
||||
self.dkg_phase.next_phase()
|
||||
self.phase.next_phase()
|
||||
}
|
||||
|
||||
fn set_release_block(&mut self, release_block: Block) {
|
||||
self.release_block = release_block;
|
||||
fn set_block(&mut self, block: Block) {
|
||||
self.block = block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,8 +6,8 @@ use sp_runtime::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
EvmAddress, EvmBytes32, ExodusContext, RoastSession, EvmSessionsBundle,
|
||||
Config, BalanceOf, MAX_MESSAGE_SIZE,
|
||||
EvmAddress, EvmBytes32, ExodusSession, RoastSession,
|
||||
MAX_MESSAGE_SIZE,
|
||||
};
|
||||
|
||||
pub trait EvmAbiEncode {
|
||||
@ -133,7 +133,7 @@ macro_rules! impl_evm_encodable {
|
||||
|
||||
impl_evm_encodable!(numeric: u8, u16, u32, u64, u128);
|
||||
impl_evm_encodable!(bytes_fixed: EvmAddress, EvmBytes32);
|
||||
impl_evm_encodable!(const_array: [u128; 4], [u128; 2], [u32; 2], [u8; 2]);
|
||||
impl_evm_encodable!(const_array: [u128; 3], [u128; 2], [u32; 2], [u8; 2]);
|
||||
impl_evm_encodable!(bytes_slice:);
|
||||
|
||||
macro_rules! abi_encode_evm_message {
|
||||
@ -172,9 +172,8 @@ pub enum GovernanceStatus {
|
||||
RewardManager = 4,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone, Copy, PartialEq, TypeInfo, RuntimeDebug)]
|
||||
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
|
||||
pub enum GovernanceAction {
|
||||
SetRouterRegistryIndex { index: u128 },
|
||||
SetDistributor { distributor: EvmAddress },
|
||||
SetWarmupPeriod { warmup_period: u128 },
|
||||
UpdateGatekeeperAddress { new_gatekeeper: EvmAddress },
|
||||
@ -189,19 +188,16 @@ pub enum GovernanceAction {
|
||||
ForfeitReserves { router: EvmAddress, liquidity: u128, destroyer_mode: bool },
|
||||
RedeemReserves { router: EvmAddress, amount: u128 },
|
||||
Withdraw { token: EvmAddress, amount: u128 },
|
||||
SetBondDepository { address: EvmAddress },
|
||||
AuditReserves,
|
||||
|
||||
Close { id: u128 },
|
||||
Create {
|
||||
market: [u128; 4],
|
||||
market: [u128; 3],
|
||||
terms: [u128; 2],
|
||||
token: EvmAddress,
|
||||
intervals: [u32; 2],
|
||||
booleans: [bool; 2],
|
||||
},
|
||||
|
||||
Approve { spender: EvmAddress, value: u128, },
|
||||
}
|
||||
|
||||
impl GovernanceAction {
|
||||
@ -210,13 +206,6 @@ impl GovernanceAction {
|
||||
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
|
||||
) -> Option<&'a [u8]> {
|
||||
match &self {
|
||||
Self::SetRouterRegistryIndex { index } => {
|
||||
abi_encode_evm_message!(
|
||||
message_buffer,
|
||||
"setRouterRegistryIndex(uint256)",
|
||||
[index]
|
||||
)
|
||||
},
|
||||
Self::SetDistributor { distributor } => {
|
||||
abi_encode_evm_message!(
|
||||
message_buffer,
|
||||
@ -301,13 +290,6 @@ impl GovernanceAction {
|
||||
[token, amount]
|
||||
)
|
||||
},
|
||||
Self::SetBondDepository { address } => {
|
||||
abi_encode_evm_message!(
|
||||
message_buffer,
|
||||
"setBondDepository(address)",
|
||||
[address]
|
||||
)
|
||||
},
|
||||
Self::AuditReserves => {
|
||||
abi_encode_evm_message!(message_buffer, "auditReserves()", [])
|
||||
},
|
||||
@ -318,79 +300,68 @@ impl GovernanceAction {
|
||||
let booleans_u8 = [booleans[0] as u8, booleans[1] as u8];
|
||||
abi_encode_evm_message!(
|
||||
message_buffer,
|
||||
"create(uint256[4],uint256[2],address,uint32[2],bool[2])",
|
||||
"create(uint256[3],uint256[2],address,uint32[2],bool[2])",
|
||||
[market, terms, token, intervals, &booleans_u8]
|
||||
)
|
||||
},
|
||||
Self::Approve { spender, value } => {
|
||||
abi_encode_evm_message!(
|
||||
message_buffer,
|
||||
"approve(address,uint256)",
|
||||
[spender, value]
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct ExodusRequest<T: Config> {
|
||||
pub r#type: ExodusRequestType<T>,
|
||||
pub struct ExodusRequest<NetworkId, Balance> {
|
||||
pub r#type: ExodusRequestType<NetworkId, Balance>,
|
||||
pub next_roast_session: RoastSession,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub enum ExodusRequestType<T: Config> {
|
||||
pub enum ExodusRequestType<NetworkId, Balance> {
|
||||
EvmRotation {
|
||||
exodus_session: ExodusSession,
|
||||
public_key: EvmBytes32,
|
||||
xor_key: u128,
|
||||
bitmask: u128,
|
||||
sessions: EvmSessionsBundle<T>,
|
||||
parity: u8,
|
||||
},
|
||||
UtxoRotation,
|
||||
EvmBridgeOut { amount: BalanceOf<T>, bounty: Perbill, receiver: EvmAddress },
|
||||
EvmGovernance { target: EvmAddress, action: GovernanceAction },
|
||||
UtxoBridgeOut,
|
||||
EvmBridgeOut {
|
||||
exodus_session: ExodusSession,
|
||||
network_id: NetworkId,
|
||||
amount: Balance,
|
||||
bounty: Perbill,
|
||||
receiver: EvmAddress,
|
||||
},
|
||||
EvmGovernance {
|
||||
exodus_session: ExodusSession,
|
||||
network_id: NetworkId,
|
||||
target: EvmAddress,
|
||||
action: GovernanceAction,
|
||||
},
|
||||
UtxoBridgeOut { network_id: NetworkId },
|
||||
}
|
||||
|
||||
impl<T: Config> ExodusRequestType<T>
|
||||
impl<NetworkId, Balance> ExodusRequestType<NetworkId, Balance>
|
||||
where
|
||||
BalanceOf<T>: UniqueSaturatedInto<u128> + Copy,
|
||||
NetworkId: UniqueSaturatedInto<u64> + Copy,
|
||||
Balance: UniqueSaturatedInto<u128> + Copy,
|
||||
{
|
||||
pub fn get_message<'a, NetworkId>(
|
||||
pub fn get_message<'a>(
|
||||
&self,
|
||||
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
) -> Option<&'a [u8]>
|
||||
where
|
||||
NetworkId: UniqueSaturatedInto<u64> + Copy + Default,
|
||||
{
|
||||
) -> Option<&'a [u8]> {
|
||||
match &self {
|
||||
ExodusRequestType::EvmRotation { public_key, xor_key, bitmask, sessions } => {
|
||||
let mut buffer = [0u8; 32];
|
||||
|
||||
buffer[..16].copy_from_slice(&xor_key.to_be_bytes());
|
||||
buffer[16..].copy_from_slice(&bitmask.to_be_bytes());
|
||||
let packed_bits = EvmBytes32::from(&buffer);
|
||||
|
||||
let payload = sessions.as_slice();
|
||||
|
||||
ExodusRequestType::EvmRotation { exodus_session, public_key, parity } => {
|
||||
abi_encode_evm_message!(
|
||||
message_buffer,
|
||||
"rotate(uint256,bytes32,uint256,bytes)",
|
||||
[&exodus_context.session, public_key, &packed_bits, payload]
|
||||
"rotate(uint256,bytes32,uint8)",
|
||||
[exodus_session, public_key, parity]
|
||||
)
|
||||
},
|
||||
ExodusRequestType::EvmGovernance { target, action } => {
|
||||
ExodusRequestType::EvmGovernance { exodus_session, network_id, target, action } => {
|
||||
let mut action_buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
||||
let action_payload = action.get_message(&mut action_buffer)?;
|
||||
|
||||
let mut metadata_buffer = [0u8; 32];
|
||||
let chain_id_u64: u64 = exodus_context.network_id
|
||||
.unique_saturated_into();
|
||||
|
||||
let chain_id_u64: u64 = (*network_id).unique_saturated_into();
|
||||
metadata_buffer[0..8].copy_from_slice(&chain_id_u64.to_be_bytes());
|
||||
metadata_buffer[8..28].copy_from_slice(target.as_ref());
|
||||
|
||||
@ -399,16 +370,14 @@ where
|
||||
abi_encode_evm_message!(
|
||||
message_buffer,
|
||||
"govern(uint256,uint256,bytes)",
|
||||
[&exodus_context.session, &packed_metadata, action_payload]
|
||||
[exodus_session, &packed_metadata, action_payload]
|
||||
)
|
||||
},
|
||||
ExodusRequestType::EvmBridgeOut { amount, bounty, receiver } => {
|
||||
ExodusRequestType::EvmBridgeOut { exodus_session, network_id, amount, bounty, receiver } => {
|
||||
let mut buffer = [0u8; 32];
|
||||
buffer[0..20].copy_from_slice(receiver.as_ref());
|
||||
|
||||
let chain_id_u64: u64 = exodus_context.network_id
|
||||
.unique_saturated_into();
|
||||
|
||||
let chain_id_u64: u64 = (*network_id).unique_saturated_into();
|
||||
buffer[20..28].copy_from_slice(&chain_id_u64.to_be_bytes());
|
||||
|
||||
let scaled_bounty = multiply_by_rational_with_rounding(
|
||||
@ -418,7 +387,7 @@ where
|
||||
sp_runtime::Rounding::Down
|
||||
)?;
|
||||
|
||||
let bounty_uint32 = scaled_bounty.min(u32::MAX as u128) as u32;
|
||||
let bounty_uint32 = scaled_bounty as u32;
|
||||
buffer[28..32].copy_from_slice(&bounty_uint32.to_be_bytes());
|
||||
|
||||
let mut amount_buffer = [0u8; 32];
|
||||
@ -431,78 +400,49 @@ where
|
||||
abi_encode_evm_message!(
|
||||
message_buffer,
|
||||
"recall(uint256,uint256,uint256)",
|
||||
[&exodus_context.session, &amount_u256, &packed_metadata]
|
||||
[exodus_session, &amount_u256, &packed_metadata]
|
||||
)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_evm_rotation(&self) -> bool {
|
||||
match &self {
|
||||
ExodusRequestType::EvmRotation { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_utxo_rotation(&self) -> bool {
|
||||
match &self {
|
||||
ExodusRequestType::UtxoRotation { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_bridge_out(&self) -> bool {
|
||||
match &self {
|
||||
ExodusRequestType::EvmBridgeOut { .. } | ExodusRequestType::UtxoBridgeOut { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_evm_governance(&self) -> bool {
|
||||
match &self {
|
||||
ExodusRequestType::EvmGovernance { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> ExodusRequest<T>
|
||||
impl<NetworkId, Balance> ExodusRequest<NetworkId, Balance>
|
||||
where
|
||||
BalanceOf<T>: UniqueSaturatedInto<u128> + Copy,
|
||||
NetworkId: UniqueSaturatedInto<u64> + Copy,
|
||||
Balance: UniqueSaturatedInto<u128> + Copy,
|
||||
{
|
||||
pub fn get_message<'a, NetworkId>(
|
||||
pub fn get_message<'a>(
|
||||
&self,
|
||||
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
) -> Option<&'a [u8]>
|
||||
where
|
||||
NetworkId: UniqueSaturatedInto<u64> + Copy + Default,
|
||||
{
|
||||
self.r#type.get_message(message_buffer, exodus_context)
|
||||
) -> Option<&'a [u8]> {
|
||||
self.r#type.get_message(message_buffer)
|
||||
}
|
||||
|
||||
pub fn evm_rotation(
|
||||
exodus_session: ExodusSession,
|
||||
public_key: EvmBytes32,
|
||||
xor_key: u128,
|
||||
bitmask: u128,
|
||||
sessions: EvmSessionsBundle<T>,
|
||||
parity: u8,
|
||||
) -> Self {
|
||||
let rotation = ExodusRequestType::EvmRotation {
|
||||
exodus_session,
|
||||
public_key,
|
||||
xor_key,
|
||||
bitmask,
|
||||
sessions,
|
||||
parity,
|
||||
};
|
||||
Self::default_request_for(rotation)
|
||||
}
|
||||
|
||||
pub fn evm_bridge_out(
|
||||
amount: BalanceOf<T>,
|
||||
exodus_session: ExodusSession,
|
||||
network_id: NetworkId,
|
||||
amount: Balance,
|
||||
bounty: Perbill,
|
||||
receiver: EvmAddress
|
||||
receiver: EvmAddress,
|
||||
) -> Self {
|
||||
let evm_bridge_out = ExodusRequestType::EvmBridgeOut {
|
||||
exodus_session,
|
||||
network_id,
|
||||
amount,
|
||||
bounty,
|
||||
receiver,
|
||||
@ -510,93 +450,81 @@ where
|
||||
Self::default_request_for(evm_bridge_out)
|
||||
}
|
||||
|
||||
pub fn evm_governance(target: EvmAddress, action: GovernanceAction) -> Self {
|
||||
pub fn evm_governance(
|
||||
exodus_session: ExodusSession,
|
||||
network_id: NetworkId,
|
||||
target: EvmAddress,
|
||||
action: GovernanceAction,
|
||||
) -> Self {
|
||||
let evm_governance = ExodusRequestType::EvmGovernance {
|
||||
exodus_session,
|
||||
network_id,
|
||||
target,
|
||||
action,
|
||||
};
|
||||
Self::default_request_for(evm_governance)
|
||||
}
|
||||
|
||||
fn default_request_for(request_type: ExodusRequestType<T>) -> Self {
|
||||
Self {
|
||||
r#type: request_type,
|
||||
next_roast_session: Default::default()
|
||||
pub fn is_rotation(&self) -> bool {
|
||||
match &self.r#type {
|
||||
ExodusRequestType::EvmRotation { .. } | ExodusRequestType::UtxoRotation { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn default_request_for(
|
||||
request_type: ExodusRequestType<NetworkId, Balance>,
|
||||
) -> Self {
|
||||
Self { r#type: request_type, next_roast_session: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::*;
|
||||
use sp_io::hashing::keccak_256;
|
||||
|
||||
#[test]
|
||||
fn test_rotation_message_valid() {
|
||||
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
||||
let public_key = EvmBytes32::repeat_byte(0x11);
|
||||
let session = 69;
|
||||
let network_id = 420;
|
||||
let session = 69u64;
|
||||
|
||||
let context = ExodusContext::new(network_id, session);
|
||||
let dummy_xor_key = u128::MAX;
|
||||
let dummy_evm_bitmask = 1337;
|
||||
|
||||
let mut dummy_packed_sessions =
|
||||
EvmSessionsBundle::<Runtime>::with_max_capacity();
|
||||
|
||||
let max_size = EvmSessionsBundle::<Runtime>::bound();
|
||||
dummy_packed_sessions.bounded_resize(max_size, 69);
|
||||
|
||||
let rotation_request = ExodusRequest::<Runtime>::evm_rotation(
|
||||
let rotation_request = ExodusRequest::<u64, u128>::evm_rotation(
|
||||
session,
|
||||
public_key.clone(),
|
||||
dummy_xor_key,
|
||||
dummy_evm_bitmask,
|
||||
dummy_packed_sessions,
|
||||
1,
|
||||
);
|
||||
|
||||
let calldata = rotation_request.get_message(&mut buffer, context).unwrap();
|
||||
// prefix + public_key + packed_bits + pointer + length + bytes array + padding
|
||||
// 4 + 32 + 32 + 32 + 32 + 32 + (8 * 5) + (32 - 40 % 32)
|
||||
assert_eq!(calldata.len(), 228);
|
||||
let calldata = rotation_request.get_message(&mut buffer).unwrap();
|
||||
assert_eq!(calldata.len(), 100);
|
||||
|
||||
let expected_hash = keccak_256("rotate(uint256,bytes32,uint256,bytes)".as_bytes());
|
||||
let expected_hash = keccak_256("rotate(uint256,bytes32,uint8)".as_bytes());
|
||||
|
||||
assert_eq!(calldata[0..4], expected_hash[0..4]);
|
||||
assert_eq!(calldata[35], 0x45);
|
||||
assert_eq!(&calldata[4..35], &[0u8; 31]);
|
||||
assert_eq!(&calldata[36..68], public_key.as_ref());
|
||||
|
||||
assert_eq!(&calldata[68..84], &dummy_xor_key.to_be_bytes());
|
||||
assert_eq!(&calldata[84..100], &dummy_evm_bitmask.to_be_bytes());
|
||||
|
||||
assert_eq!(&calldata[100..131], &[0u8; 31]);
|
||||
assert_eq!(calldata[131], 128);
|
||||
|
||||
assert_eq!(&calldata[132..163], &[0u8; 31]);
|
||||
assert_eq!(calldata[163], 40);
|
||||
|
||||
assert_eq!(calldata[164], 69);
|
||||
assert_eq!(&calldata[204..228], &[0u8; 24]);
|
||||
assert_eq!(calldata[99], 1);
|
||||
assert_eq!(&calldata[68..99], &[0u8; 31]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bridge_out_message_valid() {
|
||||
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
||||
let receiver = EvmAddress::repeat_byte(0xAA);
|
||||
let network_id = 420;
|
||||
let session = 69;
|
||||
let network_id = 420u64;
|
||||
let session = 69u64;
|
||||
|
||||
let context = ExodusContext::new(network_id, session);
|
||||
|
||||
let bridge_request = ExodusRequest::<Runtime>::evm_bridge_out(
|
||||
1_000_000u64,
|
||||
let bridge_request = ExodusRequest::<u64, u128>::evm_bridge_out(
|
||||
session,
|
||||
network_id,
|
||||
1_000_000u128,
|
||||
sp_runtime::Perbill::from_percent(1),
|
||||
receiver.clone()
|
||||
);
|
||||
|
||||
let calldata = bridge_request.get_message(&mut buffer, context).unwrap();
|
||||
let calldata = bridge_request.get_message(&mut buffer).unwrap();
|
||||
assert_eq!(calldata.len(), 100);
|
||||
|
||||
let expected_hash = keccak_256("recall(uint256,uint256,uint256)".as_bytes());
|
||||
@ -621,8 +549,8 @@ mod tests {
|
||||
fn test_governance_message_valid() {
|
||||
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
||||
let target = EvmAddress::repeat_byte(0xAA);
|
||||
let network_id = 420;
|
||||
let session = 69;
|
||||
let network_id = 420u64;
|
||||
let session = 69u64;
|
||||
|
||||
let actions = vec![
|
||||
GovernanceAction::SetDistributor { distributor: EvmAddress::repeat_byte(0x11) },
|
||||
@ -654,7 +582,7 @@ mod tests {
|
||||
|
||||
GovernanceAction::Close { id: 99 },
|
||||
GovernanceAction::Create {
|
||||
market: [69, 420, 1337, 0],
|
||||
market: [69, 420, 1337],
|
||||
terms: [69, 420],
|
||||
token: EvmAddress::repeat_byte(0x99),
|
||||
intervals: [69, 1337],
|
||||
@ -664,16 +592,16 @@ mod tests {
|
||||
|
||||
for (index, action) in actions.into_iter().enumerate() {
|
||||
let action_clone = action.clone();
|
||||
let current_session = session + (index as u64);
|
||||
let context = ExodusContext::new(network_id, current_session);
|
||||
|
||||
let governance_request = ExodusRequest::<Runtime>::evm_governance(
|
||||
let governance_request = ExodusRequest::<u64, u128>::evm_governance(
|
||||
session,
|
||||
network_id,
|
||||
target,
|
||||
action,
|
||||
);
|
||||
|
||||
let message = governance_request
|
||||
.get_message(&mut buffer, context)
|
||||
.get_message(&mut buffer)
|
||||
.get_or_insert(&[])
|
||||
.to_vec();
|
||||
|
||||
@ -682,7 +610,7 @@ mod tests {
|
||||
let expected_master_hash = keccak_256("govern(uint256,uint256,bytes)".as_bytes());
|
||||
assert_eq!(message[0..4], expected_master_hash[0..4]);
|
||||
|
||||
assert_eq!(message[35], current_session as u8);
|
||||
assert_eq!(message[35], 69);
|
||||
assert_eq!(&message[4..35], &[0u8; 31]);
|
||||
|
||||
assert_eq!(message[43], 0xA4);
|
||||
@ -698,12 +626,6 @@ mod tests {
|
||||
assert_eq!((message.len() - 4) % 32, 0);
|
||||
|
||||
match action_clone {
|
||||
GovernanceAction::SetRouterRegistryIndex { index } => {
|
||||
let hash = keccak_256("setRouterRegistryIndex(uint256)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
let decoded_warmup = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||
assert_eq!(decoded_warmup, index as u32);
|
||||
},
|
||||
GovernanceAction::SetDistributor { distributor } => {
|
||||
let hash = keccak_256("setDistributor(address)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
@ -712,8 +634,7 @@ mod tests {
|
||||
GovernanceAction::SetWarmupPeriod { warmup_period } => {
|
||||
let hash = keccak_256("setWarmupPeriod(uint256)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
let decoded_warmup = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||
assert_eq!(decoded_warmup, warmup_period as u32);
|
||||
assert_eq!(inner_payload[inner_payload.len() - 1], warmup_period as u8);
|
||||
},
|
||||
GovernanceAction::UpdateGatekeeperAddress { new_gatekeeper } => {
|
||||
let hash = keccak_256("updateGatekeeperAddress(address)".as_bytes());
|
||||
@ -723,8 +644,7 @@ mod tests {
|
||||
GovernanceAction::SetBounty { bounty } => {
|
||||
let hash = keccak_256("setBounty(uint256)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
let decoded_bounty = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||
assert_eq!(decoded_bounty, bounty as u32);
|
||||
assert_eq!(inner_payload[inner_payload.len() - 1], bounty as u8);
|
||||
},
|
||||
GovernanceAction::AddPool { address } => {
|
||||
let hash = keccak_256("addPool(address)".as_bytes());
|
||||
@ -734,16 +654,13 @@ mod tests {
|
||||
GovernanceAction::RemovePool { index } => {
|
||||
let hash = keccak_256("removePool(uint256)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
let decoded_index = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||
assert_eq!(decoded_index, index as u32);
|
||||
assert_eq!(inner_payload[inner_payload.len() - 1], index as u8);
|
||||
},
|
||||
GovernanceAction::SetAdjustment { rate, target, add } => {
|
||||
let hash = keccak_256("setAdjustment(uint256,uint256,bool)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
let decoded_rate = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||
assert_eq!(decoded_rate, rate as u32);
|
||||
let decoded_target = u32::from_be_bytes(inner_payload[64..68].try_into().unwrap());
|
||||
assert_eq!(decoded_target, target as u32);
|
||||
assert_eq!(inner_payload[35], rate as u8);
|
||||
assert_eq!(inner_payload[67], target as u8);
|
||||
assert_eq!(inner_payload[99], add as u8);
|
||||
},
|
||||
GovernanceAction::Enable { status, address, calculator } => {
|
||||
@ -763,8 +680,7 @@ mod tests {
|
||||
let hash = keccak_256("forfeitReserves(address,uint256,bool)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
assert_eq!(&inner_payload[16..36], router.as_ref());
|
||||
let decoded_liquidity = u32::from_be_bytes(inner_payload[64..68].try_into().unwrap());
|
||||
assert_eq!(decoded_liquidity, liquidity as u32);
|
||||
assert_eq!(inner_payload[67], liquidity as u8);
|
||||
assert_eq!(inner_payload[99], destroyer_mode as u8);
|
||||
},
|
||||
GovernanceAction::RedeemReserves { router, amount } => {
|
||||
@ -777,13 +693,7 @@ mod tests {
|
||||
let hash = keccak_256("withdraw(address,uint256)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
assert_eq!(&inner_payload[16..36], token.as_ref());
|
||||
let decoded_amount = u32::from_be_bytes(inner_payload[64..68].try_into().unwrap());
|
||||
assert_eq!(decoded_amount, amount as u32);
|
||||
},
|
||||
GovernanceAction::SetBondDepository { address } => {
|
||||
let hash = keccak_256("setBondDepository(address)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
assert_eq!(&inner_payload[16..36], address.as_ref());
|
||||
assert_eq!(inner_payload[67], amount as u8);
|
||||
},
|
||||
GovernanceAction::AuditReserves => {
|
||||
let hash = keccak_256("auditReserves()".as_bytes());
|
||||
@ -793,37 +703,28 @@ mod tests {
|
||||
GovernanceAction::Close { id } => {
|
||||
let hash = keccak_256("close(uint256)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
let decoded_id = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||
assert_eq!(decoded_id, id as u32);
|
||||
assert_eq!(inner_payload[inner_payload.len() - 1], id as u8);
|
||||
},
|
||||
GovernanceAction::Create { market, terms, token, intervals, booleans } => {
|
||||
let hash = keccak_256("create(uint256[4],uint256[2],address,uint32[2],bool[2])".as_bytes());
|
||||
let hash = keccak_256("create(uint256[3],uint256[2],address,uint32[2],bool[2])".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
assert_eq!(inner_payload.len(), 356);
|
||||
assert_eq!(inner_payload.len(), 324);
|
||||
assert_eq!(inner_payload[35], 69);
|
||||
|
||||
assert_eq!(u128::from_be_bytes(inner_payload[20..36].try_into().unwrap()), market[0]);
|
||||
assert_eq!(u128::from_be_bytes(inner_payload[52..68].try_into().unwrap()), market[1]);
|
||||
assert_eq!(u128::from_be_bytes(inner_payload[84..100].try_into().unwrap()), market[2]);
|
||||
assert_eq!(u128::from_be_bytes(inner_payload[116..132].try_into().unwrap()), market[3]);
|
||||
|
||||
assert_eq!(u128::from_be_bytes(inner_payload[148..164].try_into().unwrap()), terms[0]);
|
||||
assert_eq!(u128::from_be_bytes(inner_payload[180..196].try_into().unwrap()), terms[1]);
|
||||
assert_eq!(u128::from_be_bytes(inner_payload[116..132].try_into().unwrap()), terms[0]);
|
||||
assert_eq!(u128::from_be_bytes(inner_payload[148..164].try_into().unwrap()), terms[1]);
|
||||
|
||||
assert_eq!(&inner_payload[208..228], token.as_ref());
|
||||
assert_eq!(&inner_payload[176..196], token.as_ref());
|
||||
|
||||
assert_eq!(u32::from_be_bytes(inner_payload[256..260].try_into().unwrap()), intervals[0]);
|
||||
assert_eq!(u32::from_be_bytes(inner_payload[288..292].try_into().unwrap()), intervals[1]);
|
||||
assert_eq!(u32::from_be_bytes(inner_payload[224..228].try_into().unwrap()), intervals[0]);
|
||||
assert_eq!(u32::from_be_bytes(inner_payload[256..260].try_into().unwrap()), intervals[1]);
|
||||
|
||||
assert_eq!(inner_payload[323], booleans[0] as u8);
|
||||
assert_eq!(inner_payload[355], booleans[1] as u8);
|
||||
},
|
||||
GovernanceAction::Approve { spender, value } => {
|
||||
let hash = keccak_256("approve(address,uint256)".as_bytes());
|
||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||
assert_eq!(&inner_payload[16..36], spender.as_ref());
|
||||
let decoded_amount = u32::from_be_bytes(inner_payload[64..68].try_into().unwrap());
|
||||
assert_eq!(decoded_amount, value as u32);
|
||||
assert_eq!(inner_payload[291], booleans[0] as u8);
|
||||
assert_eq!(inner_payload[323], booleans[1] as u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ use sp_runtime::{
|
||||
};
|
||||
|
||||
use super::{DkgPackage, ExodusPackage, ExodusOk, PackageContext};
|
||||
use crate::{AuthIndex, ExodusContext, DkgIndex, ExodusHash, ExodusError};
|
||||
use crate::{AuthIndex, ExodusSession, ExodusHash, ExodusError};
|
||||
|
||||
fn create_storage_key(prefix: &[u8], index: &[u8], network: &[u8]) -> Vec<u8> {
|
||||
let mut key = crate::DB_STORAGE_PREFIX.to_vec();
|
||||
@ -59,10 +59,10 @@ pub struct ExodusShare;
|
||||
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
|
||||
pub struct ExodusExile;
|
||||
|
||||
type ExodusNonces<NetworkId, BlockNumber> = BTreeMap<ExodusContext<NetworkId>, PersistentData<BlockNumber, ExodusNonce>>;
|
||||
type ExodusGroups<NetworkId, BlockNumber> = BTreeMap<ExodusContext<NetworkId>, PersistentData<BlockNumber, ExodusGroup>>;
|
||||
type ExodusShares<NetworkId, BlockNumber> = BTreeMap<ExodusContext<NetworkId>, PersistentData<BlockNumber, ExodusShare>>;
|
||||
type ExodusExiles<NetworkId, BlockNumber> = BTreeMap<ExodusContext<NetworkId>, PersistentData<BlockNumber, ExodusExile>>;
|
||||
type ExodusNonces<BlockNumber> = BTreeMap<ExodusSession, PersistentData<BlockNumber, ExodusNonce>>;
|
||||
type ExodusGroups<BlockNumber> = BTreeMap<ExodusSession, PersistentData<BlockNumber, ExodusGroup>>;
|
||||
type ExodusShares<BlockNumber> = BTreeMap<ExodusSession, PersistentData<BlockNumber, ExodusShare>>;
|
||||
type ExodusExiles<BlockNumber> = BTreeMap<ExodusSession, PersistentData<BlockNumber, ExodusExile>>;
|
||||
|
||||
pub struct ExodusStorageWrapper<ExodusInnerType> {
|
||||
pub inner: ExodusInnerType,
|
||||
@ -75,7 +75,7 @@ impl<ExodusInnerType> ExodusStorageWrapper<ExodusInnerType> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Encode)]
|
||||
#[derive(Default)]
|
||||
pub struct ExodusStorage<BlockNumber, NetworkCurve>
|
||||
where
|
||||
BlockNumber: Default,
|
||||
@ -113,37 +113,34 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn read_local_storage<NI>(&self) -> ExodusRecords<NI, B>
|
||||
where
|
||||
NI: Default + Encode + Decode + AtLeast32BitUnsigned,
|
||||
{
|
||||
pub fn read_local_storage(&self) -> ExodusRecords<B> {
|
||||
let encoded_index = self.authority_index.encode();
|
||||
let encoded_network = self.network_curve.encode();
|
||||
|
||||
let nonces_key = create_storage_key(crate::EXODUS_PREFIX_NONCES, &encoded_index, &encoded_network);
|
||||
let exodus_nonces = StorageValueRef::persistent(&nonces_key)
|
||||
.get::<ExodusNonces<NI, B>>()
|
||||
.get::<ExodusNonces<B>>()
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_default();
|
||||
|
||||
let shares_key = create_storage_key(crate::EXODUS_PREFIX_SHARES, &encoded_index, &encoded_network);
|
||||
let exodus_shares = StorageValueRef::persistent(&shares_key)
|
||||
.get::<ExodusShares<NI, B>>()
|
||||
.get::<ExodusShares<B>>()
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_default();
|
||||
|
||||
let groups_key = create_storage_key(crate::EXODUS_PREFIX_BLENDS, &encoded_index, &encoded_network);
|
||||
let exodus_groups = StorageValueRef::persistent(&groups_key)
|
||||
.get::<ExodusGroups<NI, B>>()
|
||||
.get::<ExodusGroups<B>>()
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_default();
|
||||
|
||||
let exiles_key = create_storage_key(crate::EXODUS_PREFIX_EXILES, &encoded_index, &encoded_network);
|
||||
let exodus_exiles = StorageValueRef::persistent(&exiles_key)
|
||||
.get::<ExodusExiles<NI, B>>()
|
||||
.get::<ExodusExiles<B>>()
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_default();
|
||||
@ -156,11 +153,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_signed_call_with_context<T, A, F1, F2, F3, NI>(
|
||||
pub fn prepare_signed_call_with_context<T, A, F1, F2, F3>(
|
||||
&self,
|
||||
authority_key: &A,
|
||||
current_dkg_index: DkgIndex,
|
||||
exodus_records: &mut ExodusRecords<NI, B>,
|
||||
exodus_records: &mut ExodusRecords<B>,
|
||||
make_data: F1,
|
||||
submit_call: F2,
|
||||
insert_data: F3,
|
||||
@ -168,16 +164,13 @@ where
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
A: RuntimeAppPublic,
|
||||
NI: Default + Encode + Decode + AtLeast32BitUnsigned,
|
||||
F1: FnOnce(PackageContext<NC, B>) -> Result<ExodusPackage<NC, NI, B, T>, ExodusError>,
|
||||
F2: FnOnce(ExodusPackage<NC, NI, B, T>, A::Signature) -> Result<(), ExodusError>,
|
||||
F3: FnOnce(&mut ExodusRecords<NI, B>, B),
|
||||
F1: FnOnce(PackageContext<NC>) -> Result<ExodusPackage<NC, T>, ExodusError>,
|
||||
F2: FnOnce(ExodusPackage<NC, T>, A::Signature) -> Result<(), ExodusError>,
|
||||
F3: FnOnce(&mut ExodusRecords<B>, B),
|
||||
{
|
||||
let context = PackageContext::default()
|
||||
.with_block_number(self.current_block)
|
||||
.with_authority_index(self.authority_index)
|
||||
.with_network_curve(self.network_curve)
|
||||
.with_dkg_index(current_dkg_index);
|
||||
.with_network_curve(self.network_curve);
|
||||
|
||||
let package = make_data(context)?;
|
||||
|
||||
@ -210,10 +203,7 @@ where
|
||||
StorageValueRef::persistent(&exiles_key).clear();
|
||||
}
|
||||
|
||||
pub fn try_write_local_storage<NI: Default>(&self, records: &ExodusRecords<NI, B>)
|
||||
where
|
||||
NI: Encode + Decode + AtLeast32BitUnsigned,
|
||||
{
|
||||
pub fn try_write_local_storage(&self, records: &ExodusRecords<B>) {
|
||||
let encoded_index = self.authority_index.encode();
|
||||
let encoded_network = self.network_curve.encode();
|
||||
|
||||
@ -239,104 +229,99 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExodusRecords<NetworkId, BlockNumber>
|
||||
pub struct ExodusRecords<BlockNumber>
|
||||
where
|
||||
NetworkId: Default,
|
||||
BlockNumber: AtLeast32BitUnsigned,
|
||||
{
|
||||
exodus_nonces: ExodusStorageWrapper<ExodusNonces<NetworkId, BlockNumber>>,
|
||||
exodus_shares: ExodusStorageWrapper<ExodusShares<NetworkId, BlockNumber>>,
|
||||
exodus_groups: ExodusStorageWrapper<ExodusGroups<NetworkId, BlockNumber>>,
|
||||
exodus_exiles: ExodusStorageWrapper<ExodusExiles<NetworkId, BlockNumber>>,
|
||||
exodus_nonces: ExodusStorageWrapper<ExodusNonces<BlockNumber>>,
|
||||
exodus_shares: ExodusStorageWrapper<ExodusShares<BlockNumber>>,
|
||||
exodus_groups: ExodusStorageWrapper<ExodusGroups<BlockNumber>>,
|
||||
exodus_exiles: ExodusStorageWrapper<ExodusExiles<BlockNumber>>,
|
||||
}
|
||||
|
||||
impl<NetworkId, BlockNumber> ExodusRecords<NetworkId, BlockNumber>
|
||||
impl<BlockNumber> ExodusRecords<BlockNumber>
|
||||
where
|
||||
BlockNumber: AtLeast32BitUnsigned + Default,
|
||||
NetworkId: AtLeast32BitUnsigned + Default,
|
||||
{
|
||||
pub fn get_secret_nonce(
|
||||
&self,
|
||||
exodus_context: &ExodusContext<NetworkId>,
|
||||
) -> Option<&[u8]> {
|
||||
pub fn get_secret_nonce(&self, exodus_session: &ExodusSession) -> Option<&[u8]> {
|
||||
self.exodus_nonces.inner
|
||||
.get(exodus_context)
|
||||
.get(exodus_session)
|
||||
.map(|v| v.data.0.as_slice())
|
||||
}
|
||||
|
||||
pub fn get_group_record(
|
||||
&self,
|
||||
exodus_context: &ExodusContext<NetworkId>,
|
||||
exodus_session: &ExodusSession,
|
||||
) -> Option<ExodusGroup> {
|
||||
self.exodus_groups.inner
|
||||
.get(exodus_context)
|
||||
.get(exodus_session)
|
||||
.cloned()
|
||||
.map(|storage| storage.data)
|
||||
}
|
||||
|
||||
pub fn is_exodus_session_banned(
|
||||
&self,
|
||||
exodus_context: &ExodusContext<NetworkId>,
|
||||
exodus_session: &ExodusSession,
|
||||
) -> bool {
|
||||
self.exodus_exiles.inner.contains_key(exodus_context)
|
||||
self.exodus_exiles.inner.contains_key(exodus_session)
|
||||
}
|
||||
|
||||
pub fn is_group_registered(
|
||||
&self,
|
||||
exodus_context: &ExodusContext<NetworkId>,
|
||||
exodus_session: &ExodusSession,
|
||||
) -> bool {
|
||||
self.exodus_groups.inner.contains_key(exodus_context)
|
||||
self.exodus_groups.inner.contains_key(exodus_session)
|
||||
}
|
||||
|
||||
pub fn is_waiting_period_for_nonce(
|
||||
&self,
|
||||
exodus_context: &ExodusContext<NetworkId>,
|
||||
current_block: &BlockNumber,
|
||||
exodus_session: &ExodusSession,
|
||||
current_block: &BlockNumber
|
||||
) -> bool {
|
||||
self.exodus_nonces.inner
|
||||
.get(exodus_context)
|
||||
.get(exodus_session)
|
||||
.map(|data| data.release_block.gt(current_block))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_waiting_period_for_share(
|
||||
&self,
|
||||
exodus_context: &ExodusContext<NetworkId>,
|
||||
exodus_session: &ExodusSession,
|
||||
current_block: &BlockNumber,
|
||||
) -> bool {
|
||||
self.exodus_shares.inner
|
||||
.get(exodus_context)
|
||||
.get(exodus_session)
|
||||
.map(|data| data.release_block.gt(¤t_block))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_waiting_period_for_group(
|
||||
&self,
|
||||
exodus_context: &ExodusContext<NetworkId>,
|
||||
exodus_session: &ExodusSession,
|
||||
current_block: &BlockNumber,
|
||||
) -> bool {
|
||||
self.exodus_groups.inner
|
||||
.get(exodus_context)
|
||||
.get(exodus_session)
|
||||
.map(|data| data.release_block.gt(¤t_block))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn exclude_exodus_session(
|
||||
&mut self,
|
||||
exodus_context: ExodusContext<NetworkId>
|
||||
exodus_session: ExodusSession,
|
||||
) {
|
||||
let exodus_exile = PersistentData {
|
||||
data: ExodusExile,
|
||||
release_block: Default::default(),
|
||||
};
|
||||
|
||||
self.exodus_exiles.inner.insert(exodus_session, exodus_exile);
|
||||
self.exodus_exiles.data_changed = true;
|
||||
self.exodus_exiles.inner.insert(exodus_context, exodus_exile);
|
||||
}
|
||||
|
||||
pub fn insert_exodus_nonce(
|
||||
&mut self,
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
exodus_session: ExodusSession,
|
||||
next_release_block: BlockNumber,
|
||||
nonce_commitment: Vec<u8>,
|
||||
) {
|
||||
@ -345,13 +330,13 @@ where
|
||||
release_block: next_release_block,
|
||||
};
|
||||
|
||||
self.exodus_nonces.inner.insert(exodus_session, exodus_nonce);
|
||||
self.exodus_nonces.data_changed = true;
|
||||
self.exodus_nonces.inner.insert(exodus_context, exodus_nonce);
|
||||
}
|
||||
|
||||
pub fn insert_exodus_share(
|
||||
&mut self,
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
exodus_session: ExodusSession,
|
||||
next_release_block: BlockNumber,
|
||||
) {
|
||||
let exodus_share = PersistentData {
|
||||
@ -359,13 +344,13 @@ where
|
||||
release_block: next_release_block,
|
||||
};
|
||||
|
||||
self.exodus_shares.inner.insert(exodus_session, exodus_share);
|
||||
self.exodus_shares.data_changed = true;
|
||||
self.exodus_shares.inner.insert(exodus_context, exodus_share);
|
||||
}
|
||||
|
||||
pub fn insert_exodus_group(
|
||||
&mut self,
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
exodus_session: ExodusSession,
|
||||
next_release_block: BlockNumber,
|
||||
self_binding_factor: Vec<u8>,
|
||||
binding_factors_proof: Vec<ExodusHash>,
|
||||
@ -375,12 +360,12 @@ where
|
||||
release_block: next_release_block,
|
||||
};
|
||||
|
||||
self.exodus_groups.inner.insert(exodus_session, exodus_group);
|
||||
self.exodus_groups.data_changed = true;
|
||||
self.exodus_groups.inner.insert(exodus_context, exodus_group);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Encode, Clone, Copy)]
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct DkgStorage<BlockNumber, NetworkCurve>
|
||||
where
|
||||
BlockNumber: Copy + Clone,
|
||||
@ -421,10 +406,10 @@ where
|
||||
self.current_block.saturating_add(self.block_longevity)
|
||||
}
|
||||
|
||||
pub fn get_dkg_result<NI>(
|
||||
pub fn get_dkg_result(
|
||||
&self,
|
||||
dkg_record: DkgRecord<B>,
|
||||
) -> Result<ExodusOk<NC, NI>, ExodusError> {
|
||||
) -> Result<ExodusOk<NC>, ExodusError> {
|
||||
match dkg_record.prefix_slice {
|
||||
crate::DKG_ROUND0_PREFIX => return Ok(ExodusOk::DkgRoundRegistered(0u8, self.authority_index, self.network_curve)),
|
||||
crate::DKG_ROUND1_PREFIX => return Ok(ExodusOk::DkgRoundRegistered(1u8, self.authority_index, self.network_curve)),
|
||||
@ -469,7 +454,6 @@ where
|
||||
pub fn prepare_signed_call_with_context<T, A, F1, F2>(
|
||||
&self,
|
||||
authority_key: &A,
|
||||
current_dkg_index: DkgIndex,
|
||||
dkg_record: &mut DkgRecord<B>,
|
||||
make_data: F1,
|
||||
submit_call: F2,
|
||||
@ -477,14 +461,12 @@ where
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
A: RuntimeAppPublic,
|
||||
F1: FnOnce(PackageContext<NC, B>) -> Result<DkgPackage<NC, B, T>, ExodusError>,
|
||||
F2: FnOnce(DkgPackage<NC, B, T>, A::Signature) -> Result<(), ExodusError>,
|
||||
F1: FnOnce(PackageContext<NC>) -> Result<DkgPackage<NC, T>, ExodusError>,
|
||||
F2: FnOnce(DkgPackage<NC, T>, A::Signature) -> Result<(), ExodusError>,
|
||||
{
|
||||
let context = PackageContext::default()
|
||||
.with_block_number(self.current_block)
|
||||
.with_authority_index(self.authority_index)
|
||||
.with_network_curve(self.network_curve)
|
||||
.with_dkg_index(current_dkg_index);
|
||||
.with_network_curve(self.network_curve);
|
||||
|
||||
let package = make_data(context)?;
|
||||
|
||||
|
||||
@ -3,85 +3,37 @@ use scale_info::TypeInfo;
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
use sp_runtime::traits::UniqueSaturatedInto;
|
||||
use frame_support::{BoundedVec, traits::ConstU32};
|
||||
use ghost_traits::bounded_bitmap::BoundedBitmapReader;
|
||||
use crate::{AuthIndex, ExodusSession, ExodusHash, ExodusError};
|
||||
|
||||
use crate::{
|
||||
AuthIndex, DkgIndex, ExodusSession, ExodusHash, ExodusError,
|
||||
ParticipantsBitmap,
|
||||
};
|
||||
|
||||
pub trait IndexedBundle<T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
fn blob(&self) -> &[u8];
|
||||
fn bitmask(&self) -> &ParticipantsBitmap<T>;
|
||||
|
||||
fn get_package_by_index<D: Decode>(&self, index: AuthIndex, size: usize) -> Option<D> {
|
||||
let index_usize = index.unique_saturated_into();
|
||||
let popcount = self.bitmask().count_ones_before::<usize>(index_usize)?;
|
||||
|
||||
popcount.checked_mul(size)
|
||||
.and_then(|start| start.checked_add(size).map(|end| (start, end)))
|
||||
.and_then(|(start, end)| self.blob().get(start..end))
|
||||
.and_then(|raw_slice| D::decode(&mut &raw_slice[..]).ok())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PackageMetadata<NetworkCurve, BlockNumber>
|
||||
pub trait PackageMetadata<NetworkCurve>
|
||||
where
|
||||
NetworkCurve: Copy,
|
||||
BlockNumber: Copy,
|
||||
{
|
||||
fn package_context(&self) -> &PackageContext<NetworkCurve, BlockNumber>;
|
||||
fn context(&self) -> &PackageContext<NetworkCurve>;
|
||||
|
||||
fn get_authority_index(&self) -> AuthIndex {
|
||||
self.package_context().get_authority_index()
|
||||
self.context().get_authority_index()
|
||||
}
|
||||
fn get_network_curve(&self) -> NetworkCurve {
|
||||
self.package_context().get_network_curve()
|
||||
self.context().get_network_curve()
|
||||
}
|
||||
fn get_dkg_index(&self) -> DkgIndex {
|
||||
self.package_context().get_dkg_index()
|
||||
}
|
||||
fn get_block_number(&self) -> BlockNumber {
|
||||
self.package_context().get_block_number()
|
||||
}
|
||||
fn get_metadata(&self) -> (NetworkCurve, AuthIndex, DkgIndex) {
|
||||
let network_curve = self.get_network_curve();
|
||||
let authority_index = self.get_authority_index();
|
||||
let dkg_index = self.get_dkg_index();
|
||||
|
||||
(network_curve, authority_index, dkg_index)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ExodusMetadata<NetworkId>
|
||||
where
|
||||
NetworkId: Default + Copy,
|
||||
{
|
||||
fn get_exodus_context(&self) -> &ExodusContext<NetworkId>;
|
||||
fn copy_exodus_context(&self) -> ExodusContext<NetworkId>;
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone, RuntimeDebug, TypeInfo, PartialEq, Eq)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub enum ExodusPackage<NetworkCurve, NetworkId, BlockNumber, T>
|
||||
pub enum ExodusPackage<NetworkCurve, T>
|
||||
where
|
||||
NetworkId: Default,
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
NonceCommitment(ExodusNonceCommitment<NetworkCurve, NetworkId, BlockNumber>),
|
||||
GroupCommitment(ExodusGroupCommitment<NetworkCurve, NetworkId, BlockNumber>),
|
||||
SignatureShare(ExodusSignatureShare<NetworkCurve, NetworkId, BlockNumber, T>),
|
||||
NonceCommitment(ExodusNonceCommitment<NetworkCurve>),
|
||||
GroupCommitment(ExodusGroupCommitment<NetworkCurve>),
|
||||
SignatureShare(ExodusSignatureShare<NetworkCurve, T>),
|
||||
}
|
||||
|
||||
impl<NC, NI, B, T> ExodusPackage<NC, NI, B, T>
|
||||
impl<NetworkCurve, T> ExodusPackage<NetworkCurve, T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
NI: Default,
|
||||
{
|
||||
pub fn bytes_len(&self) -> u32 {
|
||||
let length = match self {
|
||||
@ -99,24 +51,32 @@ where
|
||||
|
||||
length as u32
|
||||
}
|
||||
|
||||
pub fn get_exodus_session(&self) -> ExodusSession {
|
||||
match &self {
|
||||
Self::SignatureShare(package) => package.session,
|
||||
Self::NonceCommitment(package) => package.session,
|
||||
Self::GroupCommitment(package) => package.session,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Encode, Decode, Clone, TypeInfo, PartialEq, Eq)]
|
||||
#[derive(Encode, Decode, Clone, RuntimeDebug, TypeInfo, PartialEq, Eq)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub enum DkgPackage<NetworkCurve, BlockNumber, T>
|
||||
pub enum DkgPackage<NetworkCurve, T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
Round0(Round0Package<NetworkCurve, BlockNumber>),
|
||||
Round1(Round1Package<NetworkCurve, BlockNumber, T>),
|
||||
Round2(Round2Package<NetworkCurve, BlockNumber, T>),
|
||||
Round3(Round3Package<NetworkCurve, BlockNumber, T>),
|
||||
Round4(Round4Package<NetworkCurve, BlockNumber, T>),
|
||||
Round5(Round5Package<NetworkCurve, BlockNumber, T>),
|
||||
Round6(Round6Package<NetworkCurve, BlockNumber, T>),
|
||||
Round0(Round0Package<NetworkCurve>),
|
||||
Round1(Round1Package<NetworkCurve, T>),
|
||||
Round2(Round2Package<NetworkCurve, T>),
|
||||
Round3(Round3Package<NetworkCurve, T>),
|
||||
Round4(Round4Package<NetworkCurve, T>),
|
||||
Round5(Round5Package<NetworkCurve>),
|
||||
Round6(Round6Package<NetworkCurve, T>),
|
||||
}
|
||||
|
||||
impl<NC, B, T> DkgPackage<NC, B, T>
|
||||
impl<NetworkCurve, T> DkgPackage<NetworkCurve, T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
@ -124,19 +84,12 @@ where
|
||||
let length = match self {
|
||||
Self::Round0(_) => ExodusHash::len_bytes(),
|
||||
Self::Round1(round1) => round1.package.len(),
|
||||
Self::Round2(round2) => round2.bundle.bitmask.count_ones(),
|
||||
Self::Round3(round3) => {
|
||||
round3.indices.highest_bit::<usize>().unwrap_or_default()
|
||||
},
|
||||
Self::Round4(round4) => round4.bundle.bitmask.count_ones(),
|
||||
Self::Round2(round2) => round2.bundle.bitmask.len(),
|
||||
Self::Round3(round3) => round3.indices.len(),
|
||||
Self::Round4(round4) => round4.bundle.bitmask.len(),
|
||||
Self::Round5(round5) => {
|
||||
let key_members_size = round5.key_members
|
||||
.highest_bit::<usize>()
|
||||
.unwrap_or_default();
|
||||
|
||||
round5.verifying_key.len()
|
||||
.saturating_add(ExodusHash::len_bytes())
|
||||
.saturating_add(key_members_size)
|
||||
},
|
||||
Self::Round6(round6) => round6.merkle_proof.len(),
|
||||
};
|
||||
@ -145,18 +98,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct PackageContext<NetworkCurve, BlockNumber> {
|
||||
#[derive(Default, RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
pub struct PackageContext<NetworkCurve> {
|
||||
authority_index: AuthIndex,
|
||||
network_curve: NetworkCurve,
|
||||
block_number: BlockNumber,
|
||||
dkg_index: DkgIndex,
|
||||
network_curve: NetworkCurve
|
||||
}
|
||||
|
||||
impl<NetworkCurve, BlockNumber> PackageContext<NetworkCurve, BlockNumber>
|
||||
impl<NetworkCurve> PackageContext<NetworkCurve>
|
||||
where
|
||||
NetworkCurve: Copy,
|
||||
BlockNumber: Copy,
|
||||
{
|
||||
pub fn get_authority_index(&self) -> AuthIndex {
|
||||
self.authority_index
|
||||
@ -166,14 +116,6 @@ where
|
||||
self.network_curve
|
||||
}
|
||||
|
||||
pub fn get_dkg_index(&self) -> DkgIndex {
|
||||
self.dkg_index
|
||||
}
|
||||
|
||||
pub fn get_block_number(&self) -> BlockNumber {
|
||||
self.block_number
|
||||
}
|
||||
|
||||
pub fn with_network_curve(mut self, network_curve: NetworkCurve) -> Self {
|
||||
self.network_curve = network_curve;
|
||||
self
|
||||
@ -183,265 +125,225 @@ where
|
||||
self.authority_index = authority_index;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_dkg_index(mut self, dkg_index: DkgIndex) -> Self {
|
||||
self.dkg_index = dkg_index;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_block_number(mut self, block_number: BlockNumber) -> Self {
|
||||
self.block_number = block_number;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct BundledPackages<T>
|
||||
where
|
||||
T: crate::pallet::Config
|
||||
{
|
||||
pub bitmask: ParticipantsBitmap<T>,
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
pub struct BundledPackages {
|
||||
pub blob: Vec<u8>,
|
||||
pub bitmask: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<T> IndexedBundle<T> for BundledPackages<T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
fn blob(&self) -> &[u8] { &self.blob }
|
||||
fn bitmask(&self) -> &ParticipantsBitmap<T> { &self.bitmask }
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct EncryptionBundledPackages<T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
pub blob: BoundedVec<u8, crate::EncryptedRound2BlobMaxBytes<T>>,
|
||||
pub bitmask: ParticipantsBitmap<T>,
|
||||
pub bitmask: BoundedVec<u8, crate::MaxAuthoritiesBitmaskSize<T>>
|
||||
}
|
||||
|
||||
impl<T> IndexedBundle<T> for EncryptionBundledPackages<T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
fn blob(&self) -> &[u8] { &self.blob }
|
||||
fn bitmask(&self) -> &ParticipantsBitmap<T> { &self.bitmask }
|
||||
impl<T: crate::pallet::Config> EncryptionBundledPackages<T> {
|
||||
pub fn len(&self) -> usize {
|
||||
let blob_len = self.blob.len();
|
||||
let bitmask_len = self.bitmask.len();
|
||||
|
||||
bitmask_len.saturating_add(blob_len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: crate::pallet::Config> TryFrom<BundledPackages<T>> for EncryptionBundledPackages<T> {
|
||||
impl<T: crate::pallet::Config> TryFrom<BundledPackages> for EncryptionBundledPackages<T> {
|
||||
type Error = ExodusError;
|
||||
|
||||
fn try_from(source: BundledPackages<T>) -> Result<Self, Self::Error> {
|
||||
let blob = BoundedVec::try_from(source.blob)
|
||||
fn try_from(source: BundledPackages) -> Result<Self, Self::Error> {
|
||||
let blob =
|
||||
BoundedVec::<u8, crate::EncryptedRound2BlobMaxBytes<T>>::try_from(source.blob)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(Self { blob, bitmask: source.bitmask })
|
||||
let bitmask = BoundedVec::<u8, crate::MaxAuthoritiesBitmaskSize<T>>::try_from(source.bitmask)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(Self { blob, bitmask })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct JustificationsBundledPackages<T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
pub blob: BoundedVec<u8, crate::Round2BlobMaxBytes<T>>,
|
||||
pub bitmask: ParticipantsBitmap<T>,
|
||||
pub bitmask: BoundedVec<u8, crate::MaxAuthoritiesBitmaskSize<T>>
|
||||
}
|
||||
|
||||
impl<T> IndexedBundle<T> for JustificationsBundledPackages<T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
fn blob(&self) -> &[u8] { &self.blob }
|
||||
fn bitmask(&self) -> &ParticipantsBitmap<T> { &self.bitmask }
|
||||
impl<T: crate::pallet::Config> JustificationsBundledPackages<T> {
|
||||
pub fn len(&self) -> usize {
|
||||
let blob_len = self.blob.len();
|
||||
let bitmask_len = self.bitmask.len();
|
||||
|
||||
bitmask_len.saturating_add(blob_len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: crate::pallet::Config> TryFrom<BundledPackages<T>> for JustificationsBundledPackages<T> {
|
||||
impl<T: crate::pallet::Config> TryFrom<BundledPackages> for JustificationsBundledPackages<T> {
|
||||
type Error = ExodusError;
|
||||
|
||||
fn try_from(source: BundledPackages<T>) -> Result<Self, Self::Error> {
|
||||
let blob = BoundedVec::try_from(source.blob)
|
||||
fn try_from(source: BundledPackages) -> Result<Self, Self::Error> {
|
||||
let blob =
|
||||
BoundedVec::<u8, crate::Round2BlobMaxBytes<T>>::try_from(source.blob)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(Self { blob, bitmask: source.bitmask })
|
||||
let bitmask = BoundedVec::<u8, crate::MaxAuthoritiesBitmaskSize<T>>::try_from(source.bitmask)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(Self { blob, bitmask })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Default, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct ExodusContext<NetworkId: Default> {
|
||||
pub session: ExodusSession,
|
||||
pub network_id: NetworkId,
|
||||
}
|
||||
|
||||
impl<NetworkId: Default + Copy> ExodusContext<NetworkId> {
|
||||
pub fn new(network_id: NetworkId, session: ExodusSession) -> Self {
|
||||
Self { session, network_id }
|
||||
}
|
||||
|
||||
pub fn with_network_id(mut self, network_id: NetworkId) -> Self {
|
||||
self.network_id = network_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_exodus_session(mut self, session: ExodusSession) -> Self {
|
||||
self.session = session;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct ExodusNonceCommitment<NetworkCurve, NetworkId: Default, BlockNumber> {
|
||||
package_context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
pub struct ExodusNonceCommitment<NetworkCurve> {
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub hiding_commitment: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||
pub binding_commitment: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||
pub session: ExodusSession,
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct ExodusGroupCommitment<NetworkCurve, NetworkId: Default, BlockNumber> {
|
||||
package_context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
pub struct ExodusGroupCommitment<NetworkCurve> {
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub group_commitment: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||
pub binding_factors_root: ExodusHash,
|
||||
pub session: ExodusSession,
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct ExodusSignatureShare<NetworkCurve, NetworkId, BlockNumber, T>
|
||||
pub struct ExodusSignatureShare<NetworkCurve, T>
|
||||
where
|
||||
NetworkId: Default,
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
package_context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub binding_factors_proof: BoundedVec<ExodusHash, crate::BindingFactorsProof<T>>,
|
||||
pub signature_share: BoundedVec<u8, ConstU32<{ crate::SCALAR_MAX_BYTES }>>,
|
||||
pub self_binding_factor: BoundedVec<u8, ConstU32<{ crate::SCALAR_MAX_BYTES }>>,
|
||||
pub session: ExodusSession,
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct Round0Package<NetworkCurve, BlockNumber> {
|
||||
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
pub struct Round0Package<NetworkCurve> {
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub package_hash: ExodusHash,
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct Round1Package<NetworkCurve, BlockNumber, T>
|
||||
pub struct Round1Package<NetworkCurve, T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub package: BoundedVec<u8, crate::Round1MaxBytes<T>>,
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct Round2Package<NetworkCurve, BlockNumber, T>
|
||||
pub struct Round2Package<NetworkCurve, T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub bundle: EncryptionBundledPackages<T>,
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct Round3Package<NetworkCurve, BlockNumber, T>
|
||||
pub struct Round3Package<NetworkCurve, T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
pub indices: ParticipantsBitmap<T>,
|
||||
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub indices: BoundedVec<u8, crate::AccusedIndicesMaxBytes<T>>,
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct Round4Package<NetworkCurve, BlockNumber, T>
|
||||
pub struct Round4Package<NetworkCurve, T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub bundle: JustificationsBundledPackages<T>,
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct Round5Package<NetworkCurve, BlockNumber, T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
pub key_members: ParticipantsBitmap<T>,
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
pub struct Round5Package<NetworkCurve> {
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub verifying_key: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||
pub merkle_root: ExodusHash,
|
||||
}
|
||||
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct Round6Package<NetworkCurve, BlockNumber, T>
|
||||
pub struct Round6Package<NetworkCurve, T>
|
||||
where
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||
context: PackageContext<NetworkCurve>,
|
||||
pub verifying_share: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||
pub merkle_proof: BoundedVec<ExodusHash, crate::MerkleProofMaxSize<T>>,
|
||||
}
|
||||
|
||||
impl<NetworkCurve, BlockNumber> PackageContext<NetworkCurve, BlockNumber> {
|
||||
pub fn with_exodus_nonce_commitment<NetworkId: Default>(
|
||||
impl<NetworkCurve> PackageContext<NetworkCurve> {
|
||||
pub fn with_exodus_nonce_commitment(
|
||||
self,
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
session: ExodusSession,
|
||||
hiding_commitment_vec: Vec<u8>,
|
||||
binding_commitment_vec: Vec<u8>,
|
||||
) -> Result<ExodusNonceCommitment<NetworkCurve, NetworkId, BlockNumber>, ExodusError> {
|
||||
let hiding_commitment = BoundedVec::try_from(hiding_commitment_vec)
|
||||
) -> Result<ExodusNonceCommitment<NetworkCurve>, ExodusError> {
|
||||
let hiding_commitment =
|
||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(hiding_commitment_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
let binding_commitment = BoundedVec::try_from(binding_commitment_vec)
|
||||
let binding_commitment =
|
||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(binding_commitment_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(ExodusNonceCommitment {
|
||||
package_context: self,
|
||||
exodus_context,
|
||||
hiding_commitment,
|
||||
binding_commitment,
|
||||
})
|
||||
Ok(ExodusNonceCommitment { context: self, hiding_commitment, binding_commitment, session })
|
||||
}
|
||||
|
||||
pub fn with_exodus_group_commitment<NetworkId: Default>(
|
||||
pub fn with_exodus_group_commitment(
|
||||
self,
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
session: ExodusSession,
|
||||
commitment_vec: Vec<u8>,
|
||||
binding_factors_root: ExodusHash,
|
||||
) -> Result<ExodusGroupCommitment<NetworkCurve, NetworkId, BlockNumber>, ExodusError> {
|
||||
let group_commitment = BoundedVec::try_from(commitment_vec)
|
||||
) -> Result<ExodusGroupCommitment<NetworkCurve>, ExodusError> {
|
||||
let group_commitment =
|
||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(commitment_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(ExodusGroupCommitment {
|
||||
package_context: self,
|
||||
exodus_context,
|
||||
context: self,
|
||||
group_commitment,
|
||||
binding_factors_root,
|
||||
session,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_exodus_signature_share<NetworkId: Default, T: crate::pallet::Config>(
|
||||
pub fn with_exodus_signature_share<T: crate::pallet::Config>(
|
||||
self,
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
session: ExodusSession,
|
||||
signature_share_vec: Vec<u8>,
|
||||
binding_factors_proof_vec: Vec<ExodusHash>,
|
||||
self_binding_factor_vec: Vec<u8>,
|
||||
) -> Result<ExodusSignatureShare<NetworkCurve, NetworkId, BlockNumber, T>, ExodusError> {
|
||||
let signature_share = BoundedVec::try_from(signature_share_vec)
|
||||
) -> Result<ExodusSignatureShare<NetworkCurve, T>, ExodusError> {
|
||||
let signature_share =
|
||||
BoundedVec::<u8, ConstU32<{ crate::SCALAR_MAX_BYTES }>>::try_from(signature_share_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
let binding_factors_proof = BoundedVec::try_from(binding_factors_proof_vec)
|
||||
let binding_factors_proof =
|
||||
BoundedVec::<ExodusHash, crate::BindingFactorsProof<T>>::try_from(binding_factors_proof_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
let self_binding_factor =
|
||||
@ -449,26 +351,27 @@ impl<NetworkCurve, BlockNumber> PackageContext<NetworkCurve, BlockNumber> {
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(ExodusSignatureShare {
|
||||
package_context: self,
|
||||
exodus_context,
|
||||
context: self,
|
||||
binding_factors_proof,
|
||||
self_binding_factor,
|
||||
signature_share,
|
||||
session,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_dkg_round0(
|
||||
self,
|
||||
package_hash: ExodusHash,
|
||||
) -> Round0Package<NetworkCurve, BlockNumber> {
|
||||
) -> Round0Package<NetworkCurve> {
|
||||
Round0Package { context: self, package_hash }
|
||||
}
|
||||
|
||||
pub fn with_dkg_round1<T: crate::pallet::Config>(
|
||||
self,
|
||||
package_vec: Vec<u8>,
|
||||
) -> Result<Round1Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||
let package = BoundedVec::try_from(package_vec)
|
||||
) -> Result<Round1Package<NetworkCurve, T>, ExodusError> {
|
||||
let package =
|
||||
BoundedVec::<u8, crate::Round1MaxBytes<T>>::try_from(package_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(Round1Package { context: self, package })
|
||||
@ -476,99 +379,80 @@ impl<NetworkCurve, BlockNumber> PackageContext<NetworkCurve, BlockNumber> {
|
||||
|
||||
pub fn with_dkg_round2<T: crate::pallet::Config>(
|
||||
self,
|
||||
bundle_raw: BundledPackages<T>,
|
||||
) -> Result<Round2Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||
bundle_raw: BundledPackages,
|
||||
) -> Result<Round2Package<NetworkCurve, T>, ExodusError> {
|
||||
let bundle: EncryptionBundledPackages<T> = bundle_raw.try_into()?;
|
||||
Ok(Round2Package { context: self, bundle })
|
||||
}
|
||||
|
||||
pub fn with_dkg_round3<T: crate::pallet::Config>(
|
||||
self,
|
||||
indices: ParticipantsBitmap<T>,
|
||||
) -> Result<Round3Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||
indices_vec: Vec<u8>
|
||||
) -> Result<Round3Package<NetworkCurve, T>, ExodusError> {
|
||||
let indices =
|
||||
BoundedVec::<u8, crate::AccusedIndicesMaxBytes<T>>::try_from(indices_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(Round3Package { context: self, indices })
|
||||
}
|
||||
|
||||
pub fn with_dkg_round4<T: crate::pallet::Config>(
|
||||
self,
|
||||
bundle_raw: BundledPackages<T>,
|
||||
) -> Result<Round4Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||
bundle_raw: BundledPackages,
|
||||
) -> Result<Round4Package<NetworkCurve, T>, ExodusError> {
|
||||
let bundle: JustificationsBundledPackages<T> = bundle_raw.try_into()?;
|
||||
Ok(Round4Package { context: self, bundle })
|
||||
}
|
||||
|
||||
pub fn with_dkg_round5<T: crate::pallet::Config>(
|
||||
pub fn with_dkg_round5(
|
||||
self,
|
||||
verifying_key_vec: Vec<u8>,
|
||||
key_members: ParticipantsBitmap<T>,
|
||||
merkle_root: ExodusHash,
|
||||
) -> Result<Round5Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||
let verifying_key = BoundedVec::try_from(verifying_key_vec)
|
||||
) -> Result<Round5Package<NetworkCurve>, ExodusError> {
|
||||
let verifying_key =
|
||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(verifying_key_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(Round5Package { context: self, key_members, verifying_key, merkle_root })
|
||||
Ok(Round5Package { context: self, verifying_key, merkle_root })
|
||||
}
|
||||
|
||||
pub fn with_dkg_round6<T: crate::pallet::Config>(
|
||||
self,
|
||||
verifying_share_vec: Vec<u8>,
|
||||
merkle_proof_vec: Vec<ExodusHash>,
|
||||
) -> Result<Round6Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||
let verifying_share = BoundedVec::try_from(verifying_share_vec)
|
||||
) -> Result<Round6Package<NetworkCurve, T>, ExodusError> {
|
||||
let verifying_share =
|
||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(verifying_share_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
let merkle_proof = BoundedVec::try_from(merkle_proof_vec)
|
||||
let merkle_proof =
|
||||
BoundedVec::<ExodusHash, crate::MerkleProofMaxSize<T>>::try_from(merkle_proof_vec)
|
||||
.map_err(|_| ExodusError::DeserializationError)?;
|
||||
|
||||
Ok(Round6Package { context: self, verifying_share, merkle_proof })
|
||||
}
|
||||
}
|
||||
|
||||
impl<NC, NI, B, T> ExodusMetadata<NI> for ExodusPackage<NC, NI, B, T>
|
||||
where
|
||||
NI: Default + Copy,
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
fn copy_exodus_context(&self) -> ExodusContext<NI> {
|
||||
match self {
|
||||
Self::NonceCommitment(package) => (*package).exodus_context,
|
||||
Self::GroupCommitment(package) => (*package).exodus_context,
|
||||
Self::SignatureShare(package) => (*package).exodus_context,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_exodus_context(&self) -> &ExodusContext<NI> {
|
||||
match self {
|
||||
Self::NonceCommitment(package) => &package.exodus_context,
|
||||
Self::GroupCommitment(package) => &package.exodus_context,
|
||||
Self::SignatureShare(package) => &package.exodus_context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NC, NI, B, T> PackageMetadata<NC, B> for ExodusPackage<NC, NI, B, T>
|
||||
where
|
||||
NI: Default,
|
||||
NC: Copy,
|
||||
B: Copy,
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
fn package_context(&self) -> &PackageContext<NC, B> {
|
||||
match self {
|
||||
Self::NonceCommitment(package) => &package.package_context,
|
||||
Self::GroupCommitment(package) => &package.package_context,
|
||||
Self::SignatureShare(package) => &package.package_context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NC, B, T> PackageMetadata<NC, B> for DkgPackage<NC, B, T>
|
||||
impl<NC, T> PackageMetadata<NC> for ExodusPackage<NC, T>
|
||||
where
|
||||
NC: Copy,
|
||||
B: Copy,
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
fn package_context(&self) -> &PackageContext<NC, B> {
|
||||
fn context(&self) -> &PackageContext<NC> {
|
||||
match self {
|
||||
Self::NonceCommitment(package) => &package.context,
|
||||
Self::GroupCommitment(package) => &package.context,
|
||||
Self::SignatureShare(package) => &package.context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NC, T> PackageMetadata<NC> for DkgPackage<NC, T>
|
||||
where
|
||||
NC: Copy,
|
||||
T: crate::pallet::Config,
|
||||
{
|
||||
fn context(&self) -> &PackageContext<NC> {
|
||||
match self {
|
||||
Self::Round0(package) => &package.context,
|
||||
Self::Round1(package) => &package.context,
|
||||
|
||||
@ -1,33 +1,28 @@
|
||||
use scale_info::TypeInfo;
|
||||
use codec::{Encode, Decode};
|
||||
use frame_support::{BoundedVec, traits::ConstU32};
|
||||
use sp_runtime::{
|
||||
RuntimeDebug,
|
||||
traits::{AtLeast32BitUnsigned, UniqueSaturatedInto},
|
||||
};
|
||||
|
||||
use crate::{BalanceOf, Config, ExodusContext};
|
||||
use super::ExodusRequestType;
|
||||
use sp_runtime::{RuntimeDebug, traits::UniqueSaturatedInto};
|
||||
|
||||
type ExodusNonceT = BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>;
|
||||
type ExodusSignatureT = BoundedVec<u8, ConstU32<{ crate::SCALAR_MAX_BYTES }>>;
|
||||
type Type<NetworkId, Balance> = super::ExodusRequestType<NetworkId, Balance>;
|
||||
|
||||
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct ExodusSignedMessage<T: Config> {
|
||||
pub struct ExodusSignedMessage<NetworkId: Default, Balance: Default> {
|
||||
pub nonce: ExodusNonceT,
|
||||
pub signature: ExodusSignatureT,
|
||||
pub r#type: ExodusRequestType<T>,
|
||||
pub r#type: Type<NetworkId, Balance>,
|
||||
}
|
||||
|
||||
impl<T: Config> ExodusSignedMessage<T>
|
||||
impl<NetworkId, Balance> ExodusSignedMessage<NetworkId, Balance>
|
||||
where
|
||||
BalanceOf<T>: UniqueSaturatedInto<u128> + Copy + Default,
|
||||
NetworkId: UniqueSaturatedInto<u64> + Copy + Default,
|
||||
Balance: UniqueSaturatedInto<u128> + Copy + Default,
|
||||
{
|
||||
pub fn new<E, S>(
|
||||
nonce_iter: E,
|
||||
signature_iter: S,
|
||||
r#type: ExodusRequestType<T>,
|
||||
r#type: Type<NetworkId, Balance>
|
||||
) -> Option<Self>
|
||||
where
|
||||
E: Iterator<Item = u8> + ExactSizeIterator,
|
||||
@ -42,24 +37,10 @@ where
|
||||
Some(Self { nonce, signature, r#type })
|
||||
}
|
||||
|
||||
pub fn get_message<'a, NetworkId: Default + Copy + AtLeast32BitUnsigned>(
|
||||
pub fn get_message<'a>(
|
||||
&self,
|
||||
message_buffer: &'a mut [u8; crate::MAX_MESSAGE_SIZE as usize],
|
||||
exodus_context: ExodusContext<NetworkId>,
|
||||
) -> Option<&'a [u8]> {
|
||||
self.r#type.get_message(message_buffer, exodus_context)
|
||||
}
|
||||
|
||||
pub fn is_evm_rotation(&self) -> bool {
|
||||
self.r#type.is_evm_rotation()
|
||||
}
|
||||
pub fn is_utxo_rotation(&self) -> bool {
|
||||
self.r#type.is_utxo_rotation()
|
||||
}
|
||||
pub fn is_bridge_out(&self) -> bool {
|
||||
self.r#type.is_bridge_out()
|
||||
}
|
||||
pub fn is_evm_governance(&self) -> bool {
|
||||
self.r#type.is_evm_governance()
|
||||
self.r#type.get_message(message_buffer)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,16 @@
|
||||
use sp_runtime::traits::UniqueSaturatedInto;
|
||||
use crate::{AuthIndex, ExodusSession, DkgIndex, RoastSession};
|
||||
|
||||
pub enum ExodusOk<NetworkCurve, NetworkId> {
|
||||
ExodusRequestsFinished(AuthIndex, NetworkCurve, u32, u32),
|
||||
pub enum ExodusOk<NetworkCurve> {
|
||||
ExodusEmptyRequests(AuthIndex, NetworkCurve),
|
||||
ExodusWaitingState(AuthIndex, NetworkCurve),
|
||||
ExodusNonceCommitted(ExodusSession, NetworkId, RoastSession, AuthIndex, NetworkCurve),
|
||||
ExodusGroupCommitted(ExodusSession, NetworkId, RoastSession, AuthIndex, NetworkCurve),
|
||||
ExodusSignedPartially(ExodusSession, NetworkId, RoastSession, AuthIndex, NetworkCurve),
|
||||
ExodusNonceCommitted(ExodusSession, RoastSession, AuthIndex, NetworkCurve),
|
||||
ExodusGroupCommitted(ExodusSession, RoastSession, AuthIndex, NetworkCurve),
|
||||
ExodusSignedPartially(ExodusSession, RoastSession, AuthIndex, NetworkCurve),
|
||||
ExodusVerifyingShareMissed(AuthIndex, DkgIndex, NetworkCurve),
|
||||
|
||||
DkgNotPartOfRound(u8, AuthIndex, NetworkCurve),
|
||||
DkgRoundRegistered(u8, AuthIndex, NetworkCurve),
|
||||
DkgPreviousPurged(AuthIndex, NetworkCurve, u32),
|
||||
DkgLocalStoragePurged(AuthIndex, NetworkCurve, DkgIndex),
|
||||
DkgPreviousPurged(AuthIndex, NetworkCurve),
|
||||
DkgRoundsCleared(AuthIndex, NetworkCurve),
|
||||
DkgRoundAlreadyPassed(u8, AuthIndex, NetworkCurve),
|
||||
DkgRoundWaitingPeriod(u8, AuthIndex, NetworkCurve),
|
||||
@ -21,41 +18,27 @@ pub enum ExodusOk<NetworkCurve, NetworkId> {
|
||||
DkgRoundMaxSignersNarrowed(u8, AuthIndex, AuthIndex, AuthIndex, NetworkCurve),
|
||||
}
|
||||
|
||||
impl<NetworkCurve, NetworkId> core::fmt::Debug for ExodusOk<NetworkCurve, NetworkId>
|
||||
impl<NetworkCurve> core::fmt::Display for ExodusOk<NetworkCurve>
|
||||
where
|
||||
NetworkCurve: core::fmt::Display,
|
||||
NetworkId: UniqueSaturatedInto<u64> + Copy,
|
||||
NetworkCurve: core::fmt::Display
|
||||
{
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match self {
|
||||
ExodusOk::ExodusRequestsFinished(auth_index, curve, success_count, failed_count) => {
|
||||
write!(fmt, "EXODUS requests processing round completed by authority #{auth_index} for curve {curve}: {success_count} tasks succeeded, {failed_count} tasks failed.")
|
||||
}
|
||||
ExodusOk::ExodusEmptyRequests(auth_index, curve) => write!(fmt, "No EXODUS requests found for authority #{auth_index} on curve {curve}."),
|
||||
ExodusOk::ExodusWaitingState(auth_index, curve) => write!(fmt, "Waiting for EXODUS requests to be processed by authority #{auth_index} on curve {curve}."),
|
||||
ExodusOk::ExodusNonceCommitted(exodus, network_id, roast, auth_index, curve) => {
|
||||
let network_id_u64: u64 = (*network_id).unique_saturated_into();
|
||||
write!(fmt, "Nonce committed for EXODUS {exodus:?} on ROAST session {roast:?} by authority #{auth_index} for curve {curve} on network #{network_id_u64}.")
|
||||
},
|
||||
ExodusOk::ExodusGroupCommitted(exodus, network_id, roast, auth_index, curve) => {
|
||||
let network_id_u64: u64 = (*network_id).unique_saturated_into();
|
||||
write!(fmt, "Aggregated nonce and binding factor proof committed for EXODUS {exodus:?} on ROAST session {roast:?} by authority #{auth_index} for curve {curve} on network #{network_id_u64}.")
|
||||
},
|
||||
ExodusOk::ExodusSignedPartially(exodus, network_id, roast, auth_index, curve) => {
|
||||
let network_id_u64: u64 = (*network_id).unique_saturated_into();
|
||||
write!(fmt, "Partial signature created for EXODUS {exodus:?} on ROAST session {roast:?} by authority #{auth_index} for curve {curve} on network #{network_id_u64}.")
|
||||
},
|
||||
ExodusOk::ExodusVerifyingShareMissed(auth_index, dkg_index, curve) => write!(fmt, "No verifying share found for authority #{auth_index} in EXODUS round based on DKG session #{dkg_index} for curve {curve}."),
|
||||
ExodusOk::ExodusEmptyRequests(auth_index, curve) => write!(fmt, "No EXODUS requests found by authority #{auth_index} for curve {curve}."),
|
||||
ExodusOk::ExodusWaitingState(auth_index, curve) => write!(fmt, "Waiting for EXODUS requests to be processed by authority #{auth_index} for curve {curve}."),
|
||||
ExodusOk::ExodusNonceCommitted(exodus, roast, auth_index, curve) => write!(fmt, "Nonce committed for EXODUS {exodus:?} on ROAST session {roast:?} by authority #{auth_index} for curve {curve}."),
|
||||
ExodusOk::ExodusGroupCommitted(exodus, roast, auth_index, curve) => write!(fmt, "Aggregated nonce and binding factor proof committed for EXODUS {exodus:?} on ROAST session {roast:?} by authority #{auth_index} for curve {curve}."),
|
||||
ExodusOk::ExodusSignedPartially(exodus, roast, auth_index, curve) => write!(fmt, "Partial signature created for EXODUS {exodus:?} on ROAST session {roast:?} by authority #{auth_index} for curve {curve}."),
|
||||
ExodusOk::ExodusVerifyingShareMissed(auth_index, dkg_index, curve) => write!(fmt, "EXODUS Round no verifying share for authority #{auth_index} based on DKG session #{dkg_index} for curve {curve}."),
|
||||
|
||||
ExodusOk::DkgNotPartOfRound(round, auth_index, curve) => write!(fmt, "DKG authority #{auth_index} is not part of Round {round} for network curve {curve}."),
|
||||
ExodusOk::DkgNotPartOfRound(round, auth_index, curve) => write!(fmt, "DKG authority #{auth_index} for network curve {curve} is not part of Round{round}."),
|
||||
ExodusOk::DkgRoundRegistered(round, auth_index, curve) => write!(fmt, "DKG Round{round} registered by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgPreviousPurged(auth_index, curve, removed_count) => write!(fmt, "Storage prepared for a new DKG session by authority #{auth_index} for network curve {curve}. {removed_count} entries removed."),
|
||||
ExodusOk::DkgLocalStoragePurged(auth_index, curve, dkg_index) => write!(fmt, "Storage for DKG session #{dkg_index} cleared by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgPreviousPurged(auth_index, curve) => write!(fmt, "Storage prepared for new DKG session by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgRoundsCleared(auth_index, curve) => write!(fmt, "DKG Rounds cleared from storage by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgRoundAlreadyPassed(round, auth_index, curve) => write!(fmt, "DKG Round {round} already completed by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgRoundWaitingPeriod(round, auth_index, curve) => write!(fmt, "DKG Round {round} is waiting to be applied by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgRoundNothingStored(round, auth_index, curve) => write!(fmt, "No data stored for DKG Round {round} by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgRoundMaxSignersNarrowed(round, auth_index, prev_max, curr_max, curve) => write!(fmt, "DKG Round {round} narrowed max_signers from {prev_max} to {curr_max} by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgRoundAlreadyPassed(round, auth_index, curve) => write!(fmt, "DKG Round{round} already done by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgRoundWaitingPeriod(round, auth_index, curve) => write!(fmt, "DKG Round{round} waiting to be applied by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgRoundNothingStored(round, auth_index, curve) => write!(fmt, "DKG nothing stored from Round{round} by authority #{auth_index} for network curve {curve}."),
|
||||
ExodusOk::DkgRoundMaxSignersNarrowed(round, auth_index, prev_max, curr_max, curve) => write!(fmt, "DKG Round{round} narrowed max_signers from {prev_max} to {curr_max} by {auth_index} for network curve {curve}."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
//! Autogenerated weights for `ghost_exodus`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2026-09-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||
@ -63,30 +63,34 @@ pub trait WeightInfo {
|
||||
|
||||
/// Weight functions for `ghost_exodus`.
|
||||
impl WeightInfo for () {
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round0Packages` (r:0 w:1)
|
||||
/// Proof: `GhostExodus::Round0Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_round0_package() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `365`
|
||||
// Estimated: `3830`
|
||||
// Minimum execution time: 240_843_000 picoseconds.
|
||||
Weight::from_parts(243_855_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3830))
|
||||
// Measured: `351`
|
||||
// Estimated: `3816`
|
||||
// Minimum execution time: 239_012_000 picoseconds.
|
||||
Weight::from_parts(241_388_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3816))
|
||||
.saturating_add(RocksDbWeight::get().reads(4))
|
||||
.saturating_add(RocksDbWeight::get().writes(2))
|
||||
.saturating_add(RocksDbWeight::get().writes(3))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round0Packages` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::Round0Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round1Packages` (r:1 w:1)
|
||||
@ -94,109 +98,119 @@ impl WeightInfo for () {
|
||||
/// The range of component `c` is `[4, 300]`.
|
||||
fn register_round1_package(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `405 + c * (32 ±0)`
|
||||
// Estimated: `3870 + c * (32 ±0)`
|
||||
// Minimum execution time: 1_349_108_000 picoseconds.
|
||||
Weight::from_parts(1_224_956_354, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3870))
|
||||
// Standard Error: 14_930
|
||||
.saturating_add(Weight::from_parts(33_204_477, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(5))
|
||||
.saturating_add(RocksDbWeight::get().writes(1))
|
||||
// Measured: `391 + c * (32 ±0)`
|
||||
// Estimated: `3856 + c * (32 ±0)`
|
||||
// Minimum execution time: 1_339_828_000 picoseconds.
|
||||
Weight::from_parts(1_212_625_790, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3856))
|
||||
// Standard Error: 11_831
|
||||
.saturating_add(Weight::from_parts(33_120_868, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(6))
|
||||
.saturating_add(RocksDbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round2Packages` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Round2Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[1, 300]`.
|
||||
/// The range of component `c` is `[1, 37]`.
|
||||
fn register_encrypted_round2_packages(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `332 + c * (32 ±0)`
|
||||
// Estimated: `3797 + c * (32 ±0)`
|
||||
// Minimum execution time: 245_305_000 picoseconds.
|
||||
Weight::from_parts(253_863_353, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3797))
|
||||
// Standard Error: 3_527
|
||||
.saturating_add(Weight::from_parts(810_623, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(4))
|
||||
.saturating_add(RocksDbWeight::get().writes(1))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||
// Measured: `317 + c * (257 ±0)`
|
||||
// Estimated: `3783 + c * (257 ±0)`
|
||||
// Minimum execution time: 251_478_000 picoseconds.
|
||||
Weight::from_parts(254_144_621, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3783))
|
||||
// Standard Error: 24_613
|
||||
.saturating_add(Weight::from_parts(6_595_819, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(5))
|
||||
.saturating_add(RocksDbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Complaints` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Complaints` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[1, 300]`.
|
||||
/// The range of component `c` is `[1, 37]`.
|
||||
fn register_round3_complaints(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `332 + c * (32 ±0)`
|
||||
// Estimated: `3797 + c * (32 ±0)`
|
||||
// Minimum execution time: 238_391_000 picoseconds.
|
||||
Weight::from_parts(238_937_380, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3797))
|
||||
// Standard Error: 1_789
|
||||
.saturating_add(Weight::from_parts(39_316, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(4))
|
||||
.saturating_add(RocksDbWeight::get().writes(1))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||
// Measured: `317 + c * (257 ±0)`
|
||||
// Estimated: `3783 + c * (257 ±0)`
|
||||
// Minimum execution time: 236_155_000 picoseconds.
|
||||
Weight::from_parts(242_055_948, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3783))
|
||||
// Standard Error: 15_623
|
||||
.saturating_add(Weight::from_parts(360_411, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(5))
|
||||
.saturating_add(RocksDbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Justifications` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Justifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[1, 300]`.
|
||||
/// The range of component `c` is `[1, 37]`.
|
||||
fn register_round4_justifications(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `332 + c * (32 ±0)`
|
||||
// Estimated: `3797 + c * (32 ±0)`
|
||||
// Minimum execution time: 245_916_000 picoseconds.
|
||||
Weight::from_parts(251_070_206, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3797))
|
||||
// Standard Error: 2_152
|
||||
.saturating_add(Weight::from_parts(508_508, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(4))
|
||||
.saturating_add(RocksDbWeight::get().writes(1))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||
// Measured: `317 + c * (257 ±0)`
|
||||
// Estimated: `3783 + c * (257 ±0)`
|
||||
// Minimum execution time: 249_507_000 picoseconds.
|
||||
Weight::from_parts(248_505_595, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3783))
|
||||
// Standard Error: 20_302
|
||||
.saturating_add(Weight::from_parts(4_191_526, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(5))
|
||||
.saturating_add(RocksDbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Verifications` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Verifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_round5_verifying_package() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `462`
|
||||
// Estimated: `3927`
|
||||
// Minimum execution time: 271_654_000 picoseconds.
|
||||
Weight::from_parts(286_394_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3927))
|
||||
.saturating_add(RocksDbWeight::get().reads(5))
|
||||
.saturating_add(RocksDbWeight::get().writes(2))
|
||||
// Measured: `448`
|
||||
// Estimated: `3913`
|
||||
// Minimum execution time: 264_214_000 picoseconds.
|
||||
Weight::from_parts(266_905_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3913))
|
||||
.saturating_add(RocksDbWeight::get().reads(6))
|
||||
.saturating_add(RocksDbWeight::get().writes(3))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingShares` (r:1 w:1)
|
||||
@ -207,18 +221,18 @@ impl WeightInfo for () {
|
||||
fn register_round6_public_share_package(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0 + c * (770 ±0)`
|
||||
// Estimated: `1698 + c * (1019 ±27)`
|
||||
// Minimum execution time: 283_863_000 picoseconds.
|
||||
Weight::from_parts(286_691_978, 0)
|
||||
.saturating_add(Weight::from_parts(0, 1698))
|
||||
// Standard Error: 85_685
|
||||
.saturating_add(Weight::from_parts(2_854_037, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(6))
|
||||
.saturating_add(RocksDbWeight::get().writes(2))
|
||||
// Estimated: `1551 + c * (1019 ±27)`
|
||||
// Minimum execution time: 281_073_000 picoseconds.
|
||||
Weight::from_parts(280_778_987, 0)
|
||||
.saturating_add(Weight::from_parts(0, 1551))
|
||||
// Standard Error: 92_951
|
||||
.saturating_add(Weight::from_parts(3_489_552, 0).saturating_mul(c.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(7))
|
||||
.saturating_add(RocksDbWeight::get().writes(3))
|
||||
.saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||
@ -229,22 +243,24 @@ impl WeightInfo for () {
|
||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessionStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::NonceCommitments` (r:0 w:1)
|
||||
/// Proof: `GhostExodus::NonceCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_nonce_commitment() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `633`
|
||||
// Estimated: `4098`
|
||||
// Minimum execution time: 369_666_000 picoseconds.
|
||||
Weight::from_parts(373_163_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4098))
|
||||
// Measured: `588`
|
||||
// Estimated: `4053`
|
||||
// Minimum execution time: 291_972_000 picoseconds.
|
||||
Weight::from_parts(295_122_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4053))
|
||||
.saturating_add(RocksDbWeight::get().reads(8))
|
||||
.saturating_add(RocksDbWeight::get().writes(4))
|
||||
.saturating_add(RocksDbWeight::get().writes(5))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||
@ -253,6 +269,8 @@ impl WeightInfo for () {
|
||||
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::GroupCommitters` (r:1 w:1)
|
||||
@ -263,16 +281,16 @@ impl WeightInfo for () {
|
||||
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_group_commitment() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `1032`
|
||||
// Estimated: `4495`
|
||||
// Minimum execution time: 339_569_000 picoseconds.
|
||||
Weight::from_parts(341_788_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4495))
|
||||
.saturating_add(RocksDbWeight::get().reads(9))
|
||||
.saturating_add(RocksDbWeight::get().writes(3))
|
||||
// Measured: `968`
|
||||
// Estimated: `4433`
|
||||
// Minimum execution time: 331_528_000 picoseconds.
|
||||
Weight::from_parts(333_974_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4433))
|
||||
.saturating_add(RocksDbWeight::get().reads(10))
|
||||
.saturating_add(RocksDbWeight::get().writes(4))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||
@ -281,6 +299,8 @@ impl WeightInfo for () {
|
||||
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::GroupCommitmentsConsensus` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||
@ -299,15 +319,13 @@ impl WeightInfo for () {
|
||||
/// Proof: `GhostExodus::SignatureScalars` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::GroupCommitters` (r:0 w:1)
|
||||
/// Proof: `GhostExodus::GroupCommitters` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::CounterForExodusRequests` (r:1 w1)
|
||||
/// Proof: `GhostExodus::CounterForExodusRequests` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
fn register_signature_share() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `11337`
|
||||
// Estimated: `14802`
|
||||
// Minimum execution time: 4_046_065_000 picoseconds.
|
||||
Weight::from_parts(4_059_064_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 14802))
|
||||
// Measured: `11259`
|
||||
// Estimated: `14724`
|
||||
// Minimum execution time: 3_842_259_000 picoseconds.
|
||||
Weight::from_parts(3_985_167_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 14724))
|
||||
.saturating_add(RocksDbWeight::get().reads(14))
|
||||
.saturating_add(RocksDbWeight::get().writes(8))
|
||||
}
|
||||
@ -319,18 +337,18 @@ impl WeightInfo for () {
|
||||
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::CurrentExodusSessions` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::CurrentExodusSessions` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||
/// Storage: `GhostExodus::CurrentExodus` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::CurrentExodus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusRequests` (r:0 w:1)
|
||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_evm_bridge_out_exodus() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `457`
|
||||
// Estimated: `3922`
|
||||
// Minimum execution time: 195_417_000 picoseconds.
|
||||
Weight::from_parts(196_842_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3922))
|
||||
.saturating_add(RocksDbWeight::get().reads(7))
|
||||
.saturating_add(RocksDbWeight::get().writes(5))
|
||||
// Measured: `448`
|
||||
// Estimated: `3913`
|
||||
// Minimum execution time: 137_053_000 picoseconds.
|
||||
Weight::from_parts(138_693_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3913))
|
||||
.saturating_add(RocksDbWeight::get().reads(5))
|
||||
.saturating_add(RocksDbWeight::get().writes(4))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-governance"
|
||||
version = "0.3.11"
|
||||
version = "0.3.7"
|
||||
description = "Full-chain and cross-chain governance pallet with early adopter share claims"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
@ -13,7 +13,6 @@ codec = { workspace = true, features = ["derive"] }
|
||||
scale-info = { workspace = true, features = ["derive"] }
|
||||
serde = { workspace = true }
|
||||
serde_derive = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
rustc-hex = { workspace = true }
|
||||
libsecp256k1 = { workspace = true, default-features = false }
|
||||
|
||||
@ -43,7 +42,6 @@ std = [
|
||||
"serde/std",
|
||||
"codec/std",
|
||||
"scale-info/std",
|
||||
"num-traits/std",
|
||||
"libsecp256k1/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
|
||||
@ -32,7 +32,7 @@ mod benchmarks {
|
||||
let dummy_evm_address = EvmAddress::from(evm_addr_bytes);
|
||||
|
||||
let target_index = max_proof_depth - 1;
|
||||
let claim_package_init = ClaimPackage::<T> {
|
||||
let claim_package_init = ClaimPackage {
|
||||
shares: dummy_shares,
|
||||
merkle_proof: Default::default(),
|
||||
token_id: 0,
|
||||
@ -99,8 +99,7 @@ mod benchmarks {
|
||||
let message_string_bytes = Pallet::<T>::ethereum_signable_message(
|
||||
¤t_account,
|
||||
&network_id,
|
||||
&preimage_hash,
|
||||
0u8,
|
||||
&preimage_hash
|
||||
);
|
||||
|
||||
let message_hash = SubstrateKeccakHasher::hash(&message_string_bytes);
|
||||
@ -125,7 +124,6 @@ mod benchmarks {
|
||||
claim_package,
|
||||
dummy_evm_address,
|
||||
evm_signature,
|
||||
dummy_shares,
|
||||
);
|
||||
|
||||
assert_eq!(dummy_shares, GlobalShares::<T>::get().claimed_shares);
|
||||
|
||||
@ -9,11 +9,7 @@ use frame_system::pallet_prelude::*;
|
||||
use sp_core::U256;
|
||||
use sp_std::vec::Vec;
|
||||
use sp_io::crypto::secp256k1_ecdsa_recover;
|
||||
use sp_runtime::traits::{
|
||||
AtLeast32BitUnsigned, CheckedAdd, Saturating, UniqueSaturatedInto,
|
||||
};
|
||||
|
||||
use num_traits::PrimInt;
|
||||
use sp_runtime::traits::{AtLeast32BitUnsigned, CheckedAdd, UniqueSaturatedInto};
|
||||
|
||||
use ghost_helpers::{
|
||||
SubstrateKeccakHasher, merkle_tree::verify_tree_proof,
|
||||
@ -36,8 +32,9 @@ mod benchmarking;
|
||||
mod mock;
|
||||
mod tests;
|
||||
|
||||
const MAX_POSSIBLE_PROOF_DEPTH: u32 = 256;
|
||||
|
||||
type TokenId = u128;
|
||||
type ClaimNonce = u8;
|
||||
type EvmHash = sp_core::H256;
|
||||
type EvmAddress = sp_core::H160;
|
||||
type EvmSignature = [u8; 65];
|
||||
@ -137,41 +134,25 @@ where
|
||||
}
|
||||
|
||||
pub fn lock_balance(&mut self, extra_balance: Balance) {
|
||||
self.locked_balance = self.locked_balance
|
||||
.saturating_add(extra_balance);
|
||||
self.locked_balance.saturating_add(extra_balance);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, RuntimeDebug, TypeInfo)]
|
||||
#[scale_info(skip_type_params(T))]
|
||||
pub struct ClaimPackage<T: pallet::Config> {
|
||||
#[derive(Encode, Decode, Clone, RuntimeDebug, TypeInfo, PartialEq, Eq)]
|
||||
pub struct ClaimPackage<Balance>
|
||||
where
|
||||
Balance: Default + Copy + Clone,
|
||||
{
|
||||
pub index: u32,
|
||||
pub token_id: TokenId,
|
||||
pub shares: BalanceOf<T>,
|
||||
pub merkle_proof: BoundedVec<EvmHash, T::MaxProofDepth>,
|
||||
pub shares: Balance,
|
||||
pub merkle_proof: BoundedVec<EvmHash, ConstU32<MAX_POSSIBLE_PROOF_DEPTH>>,
|
||||
}
|
||||
|
||||
impl<T: pallet::Config> Clone for ClaimPackage<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
index: self.index,
|
||||
token_id: self.token_id,
|
||||
shares: self.shares,
|
||||
merkle_proof: self.merkle_proof.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: pallet::Config> PartialEq for ClaimPackage<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.index == other.index &&
|
||||
self.token_id == other.token_id &&
|
||||
self.shares == other.shares &&
|
||||
self.merkle_proof == other.merkle_proof
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: pallet::Config> ClaimPackage<T> {
|
||||
impl<Balance> ClaimPackage<Balance>
|
||||
where
|
||||
Balance: Default + Copy + Clone + UniqueSaturatedInto<u128>,
|
||||
{
|
||||
pub fn get_preimage<NetworkId>(
|
||||
&self,
|
||||
evm_address: &EvmAddress,
|
||||
@ -233,9 +214,6 @@ pub mod pallet {
|
||||
#[pallet::constant]
|
||||
type MaxProofDepth: Get<u32>;
|
||||
|
||||
#[pallet::constant]
|
||||
type MaxPartialClaims: Get<ClaimNonce>;
|
||||
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
@ -251,10 +229,9 @@ pub mod pallet {
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
PartialClaimsExhausted,
|
||||
PreimageAlreadyClaimed,
|
||||
BoundedToOtherNetwork,
|
||||
AuthorityNotGovernor,
|
||||
ExceedsAllowedShares,
|
||||
NetworkHasNoGenesis,
|
||||
InvalidMerkleProof,
|
||||
SharesOverflowed,
|
||||
@ -292,16 +269,7 @@ pub mod pallet {
|
||||
pub type ClaimedHashes<T: Config> = StorageMap<
|
||||
_,
|
||||
Blake2_256, EvmHash,
|
||||
ClaimNonce,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn claimed_shares)]
|
||||
pub type ClaimedShares<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat, EvmHash,
|
||||
BalanceOf<T>,
|
||||
bool,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
@ -346,10 +314,9 @@ pub mod pallet {
|
||||
pub fn claim(
|
||||
origin: OriginFor<T>,
|
||||
network_id: NetworkIdOf<T>,
|
||||
claim_package: ClaimPackage<T>,
|
||||
claim_package: ClaimPackage<BalanceOf<T>>,
|
||||
evm_address: EvmAddress,
|
||||
evm_signature: EvmSignature,
|
||||
requested_shares: BalanceOf<T>,
|
||||
) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
|
||||
@ -371,21 +338,12 @@ pub mod pallet {
|
||||
let preimage = claim_package.get_preimage(&evm_address, network_id);
|
||||
let preimage_hash = SubstrateKeccakHasher::hash(&preimage);
|
||||
|
||||
let max_claim_nonces = T::MaxPartialClaims::get();
|
||||
let current_nonce = ClaimedHashes::<T>::get(&preimage_hash);
|
||||
ensure!(
|
||||
!ClaimedHashes::<T>::contains_key(&preimage_hash),
|
||||
Error::<T>::PreimageAlreadyClaimed
|
||||
);
|
||||
|
||||
ensure!(current_nonce < max_claim_nonces, Error::<T>::PartialClaimsExhausted);
|
||||
|
||||
let already_claimed = ClaimedShares::<T>::get(&preimage_hash);
|
||||
let claimed_shares = if current_nonce == max_claim_nonces.saturating_sub(1) {
|
||||
claim_package.shares.saturating_sub(already_claimed)
|
||||
} else {
|
||||
let cumulative_shares = already_claimed.saturating_add(requested_shares);
|
||||
ensure!(cumulative_shares <= claim_package.shares, Error::<T>::ExceedsAllowedShares);
|
||||
requested_shares
|
||||
};
|
||||
|
||||
Self::verify_signature(&who, &network_id, &preimage_hash, &evm_address, &evm_signature, current_nonce)?;
|
||||
Self::verify_signature(&who, &network_id, &preimage_hash, &evm_address, &evm_signature)?;
|
||||
Self::verify_merkle_proof(&network_id, &preimage, &claim_package)?;
|
||||
|
||||
NetworkShares::<T>::try_mutate(&network_id, |state| -> DispatchResult {
|
||||
@ -393,29 +351,25 @@ pub mod pallet {
|
||||
let proof_size_match = package_proof_size == state.proofs_size;
|
||||
ensure!(proof_size_match, Error::<T>::SharesOverflowed);
|
||||
|
||||
let increased = state.try_increase_claimed(claimed_shares);
|
||||
let increased = state.try_increase_claimed(claim_package.shares);
|
||||
ensure!(increased.is_some(), Error::<T>::SharesOverflowed);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
GlobalShares::<T>::try_mutate(|state| -> DispatchResult {
|
||||
let increased = state.try_increase_claimed(claimed_shares);
|
||||
let increased = state.try_increase_claimed(claim_package.shares);
|
||||
ensure!(increased.is_some(), Error::<T>::SharesOverflowed);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
member_share.increase_activated_shares(claimed_shares);
|
||||
member_share.increase_activated_shares(claim_package.shares);
|
||||
member_share.initiate_on_network(network_id);
|
||||
|
||||
MemberShares::<T>::insert(&who, member_share);
|
||||
ClaimedHashes::<T>::insert(&preimage_hash, current_nonce.saturating_add(1));
|
||||
ClaimedShares::<T>::insert(
|
||||
&preimage_hash,
|
||||
already_claimed.saturating_add(claimed_shares),
|
||||
);
|
||||
ClaimedHashes::<T>::insert(&preimage_hash, true);
|
||||
|
||||
Self::deposit_event(Event::<T>::SharesClaimed {
|
||||
shares: claimed_shares,
|
||||
shares: claim_package.shares,
|
||||
network_id,
|
||||
who,
|
||||
});
|
||||
@ -436,73 +390,45 @@ impl<T: Config> Pallet<T> {
|
||||
r
|
||||
}
|
||||
|
||||
fn to_ascii_base10<N: PrimInt + UniqueSaturatedInto<u128>>(num: N) -> Vec<u8> {
|
||||
let zero = N::zero();
|
||||
if num == zero { return sp_std::vec![b'0']; }
|
||||
|
||||
let ten = N::from(10).unwrap_or_else(|| N::zero());
|
||||
let num_u128 = num.unique_saturated_into();
|
||||
let capacity = (num_u128.ilog10() + 1) as usize;
|
||||
|
||||
let mut result = Vec::with_capacity(capacity);
|
||||
let mut n = num;
|
||||
|
||||
while n > zero {
|
||||
result.push(b'0' + (n % ten).to_u8().unwrap_or(0));
|
||||
n = n / ten;
|
||||
}
|
||||
result.reverse();
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn ethereum_signable_message(
|
||||
receiver: &T::AccountId,
|
||||
network_id: &NetworkIdOf<T>,
|
||||
preimage_hash: &EvmHash,
|
||||
nonce: ClaimNonce,
|
||||
) -> Vec<u8> {
|
||||
let prefix = b"GMV Claim:";
|
||||
let network_id_u64: u64 = (*network_id).unique_saturated_into();
|
||||
|
||||
let receiver_ascii_hex = Self::to_ascii_hex(&receiver.encode());
|
||||
let preimage_ascii_hex = Self::to_ascii_hex(preimage_hash.as_ref());
|
||||
let network_ascii = Self::to_ascii_base10(network_id_u64);
|
||||
let nonce_ascii = Self::to_ascii_base10(nonce);
|
||||
let network_ascii_hex = Self::to_ascii_hex(&network_id_u64.to_be_bytes());
|
||||
|
||||
let account_label = b"\naccount:0x";
|
||||
let preimage_label = b"\npreimage:0x";
|
||||
let network_label = b"\nnetwork:";
|
||||
let nonce_label = b"\nnonce:";
|
||||
|
||||
let what_length = prefix.len()
|
||||
.saturating_add(account_label.len()).saturating_add(receiver_ascii_hex.len())
|
||||
.saturating_add(preimage_label.len()).saturating_add(preimage_ascii_hex.len())
|
||||
.saturating_add(network_label.len()).saturating_add(network_ascii.len())
|
||||
.saturating_add(nonce_label.len()).saturating_add(nonce_ascii.len());
|
||||
let what_length = receiver_ascii_hex.len()
|
||||
.saturating_add(preimage_ascii_hex.len())
|
||||
.saturating_add(network_ascii_hex.len())
|
||||
.saturating_add(10 + 11 + 12 + 11); // all 4 prefixes
|
||||
|
||||
let mut what = Vec::with_capacity(what_length);
|
||||
what.extend_from_slice(prefix);
|
||||
|
||||
what.extend_from_slice(account_label);
|
||||
what.extend_from_slice(b"\naccount:0x");
|
||||
what.extend_from_slice(&receiver_ascii_hex);
|
||||
|
||||
what.extend_from_slice(preimage_label);
|
||||
what.extend_from_slice(b"\npreimage:0x");
|
||||
what.extend_from_slice(&preimage_ascii_hex);
|
||||
|
||||
what.extend_from_slice(network_label);
|
||||
what.extend_from_slice(&network_ascii);
|
||||
what.extend_from_slice(b"\nnetwork:0x");
|
||||
what.extend_from_slice(&network_ascii_hex);
|
||||
|
||||
what.extend_from_slice(nonce_label);
|
||||
what.extend_from_slice(&nonce_ascii);
|
||||
let mut l = what.len();
|
||||
let mut rev = Vec::new();
|
||||
while l > 0 {
|
||||
rev.push(b'0' + (l % 10) as u8);
|
||||
l /= 10;
|
||||
}
|
||||
|
||||
let length_ascii = Self::to_ascii_base10(what.len());
|
||||
let message_prefix = b"\x19Ethereum Signed Message:\n";
|
||||
|
||||
let message_capacity = message_prefix.len() + length_ascii.len() + what.len();
|
||||
let mut v = Vec::with_capacity(message_capacity);
|
||||
v.extend_from_slice(message_prefix);
|
||||
v.extend_from_slice(&length_ascii);
|
||||
let mut v = Vec::with_capacity(26 + rev.len() + what.len());
|
||||
v.extend_from_slice(b"\x19Ethereum Signed Message:\n");
|
||||
v.extend(rev.into_iter().rev());
|
||||
v.extend(what);
|
||||
|
||||
v
|
||||
@ -514,9 +440,8 @@ impl<T: Config> Pallet<T> {
|
||||
preimage_hash: &EvmHash,
|
||||
evm_address: &EvmAddress,
|
||||
evm_signature: &EvmSignature,
|
||||
nonce: ClaimNonce,
|
||||
) -> DispatchResult {
|
||||
let message = Self::ethereum_signable_message(who, network_id, preimage_hash, nonce);
|
||||
let message = Self::ethereum_signable_message(who, network_id, preimage_hash);
|
||||
let message_bytes = SubstrateKeccakHasher::hash(&message).to_fixed_bytes();
|
||||
|
||||
let recovered_pubkey = secp256k1_ecdsa_recover(evm_signature, &message_bytes)
|
||||
@ -532,7 +457,7 @@ impl<T: Config> Pallet<T> {
|
||||
fn verify_merkle_proof(
|
||||
network_id: &NetworkIdOf<T>,
|
||||
preimage: &[u8],
|
||||
claim_package: &ClaimPackage<T>,
|
||||
claim_package: &ClaimPackage<BalanceOf<T>>,
|
||||
) -> DispatchResult {
|
||||
let network_state = NetworkShares::<T>::get(network_id);
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ use super::*;
|
||||
pub use crate as ghost_governance;
|
||||
use frame_support::{
|
||||
derive_impl, parameter_types,
|
||||
traits::{ConstU8, ConstU32, ConstU128},
|
||||
traits::{ConstU32, ConstU128},
|
||||
};
|
||||
use frame_system::EnsureRoot;
|
||||
use sp_runtime::BuildStorage;
|
||||
@ -52,8 +52,7 @@ impl Config for Test {
|
||||
type NetworkDataHandler = Networks;
|
||||
|
||||
type MinimumDonation = ConstU128<69>;
|
||||
type MaxProofDepth = ConstU32<7>;
|
||||
type MaxPartialClaims = ConstU8<3>;
|
||||
type MaxProofDepth = ConstU32<5>;
|
||||
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ use hex_literal::hex;
|
||||
|
||||
use sp_runtime::AccountId32;
|
||||
use frame_support::traits::Get;
|
||||
use frame_support::{assert_ok, assert_err};
|
||||
use frame_support::assert_ok;
|
||||
use libsecp256k1::{Message, SecretKey, PublicKey};
|
||||
|
||||
use ghost_helpers::merkle_tree::{generate_tree, generate_proof};
|
||||
@ -79,34 +79,24 @@ fn claim_happy_path() {
|
||||
let users = vec![user_1.clone(), user_2.clone(), user_3.clone()];
|
||||
let max_index = 2u8;
|
||||
|
||||
let tmp_package_probe = ClaimPackage::<Test> {
|
||||
shares: user_1.allowed_shares,
|
||||
merkle_proof: Default::default(),
|
||||
token_id: user_1.token_id,
|
||||
index: 0u32,
|
||||
};
|
||||
let size_hint = tmp_package_probe.get_preimage(&user_1.evm_address, network_id).as_ref().len();
|
||||
|
||||
let raw_values_complex = vec![(0u8, &user_1), (1u8, &user_2), (2u8, &user_3)];
|
||||
let merkle_tree = generate_tree::<SubstrateKeccakHasher, u8, _, _, ()>(
|
||||
let merkle_tree = generate_tree::<SubstrateKeccakHasher, u8, _, _, _>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_values_complex,
|
||||
|
||||
|(index, u), buffer| {
|
||||
let tmp_package = ClaimPackage::<Test> {
|
||||
|item: (u8, &NewTestUser)| -> Result<(usize, Vec<u8>), ()> {
|
||||
let (index, u) = item;
|
||||
|
||||
let tmp_package = ClaimPackage {
|
||||
shares: u.allowed_shares,
|
||||
merkle_proof: Default::default(),
|
||||
token_id: u.token_id,
|
||||
index: index as u32
|
||||
};
|
||||
|
||||
let preimage_bytes = tmp_package.get_preimage(&u.evm_address, network_id);
|
||||
buffer.extend_from_slice(preimage_bytes.as_ref());
|
||||
|
||||
Ok(index as usize)
|
||||
Ok((index as usize, tmp_package.get_preimage(&u.evm_address, network_id).to_vec()))
|
||||
}
|
||||
).ok().unwrap();
|
||||
).unwrap();
|
||||
|
||||
let merkle_root = *merkle_tree.last().unwrap();
|
||||
|
||||
@ -126,11 +116,9 @@ fn claim_happy_path() {
|
||||
activated_shares: 0,
|
||||
});
|
||||
|
||||
let proof = generate_proof::<SubstrateKeccakHasher, u8, ()>(&merkle_tree, max_index, slot_index as u8)
|
||||
.ok()
|
||||
.unwrap();
|
||||
let proof = generate_proof::<SubstrateKeccakHasher, u8>(&merkle_tree, max_index, slot_index as u8);
|
||||
|
||||
let claim_package = ClaimPackage::<Test> {
|
||||
let claim_package = ClaimPackage {
|
||||
shares: current_user.allowed_shares,
|
||||
merkle_proof: BoundedVec::try_from(proof).unwrap(),
|
||||
token_id: current_user.token_id,
|
||||
@ -143,8 +131,7 @@ fn claim_happy_path() {
|
||||
let message_string_bytes = Governance::ethereum_signable_message(
|
||||
¤t_user.substrate_account,
|
||||
&network_id,
|
||||
&preimage_hash,
|
||||
0u8,
|
||||
&preimage_hash
|
||||
);
|
||||
|
||||
let message_hash = SubstrateKeccakHasher::hash(&message_string_bytes);
|
||||
@ -167,8 +154,7 @@ fn claim_happy_path() {
|
||||
network_id,
|
||||
claim_package,
|
||||
current_user.evm_address.clone(),
|
||||
evm_signature,
|
||||
current_user.allowed_shares,
|
||||
evm_signature
|
||||
));
|
||||
|
||||
let updated_share = MemberShares::<Test>::get(¤t_user.substrate_account);
|
||||
@ -186,216 +172,6 @@ fn claim_happy_path() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_claims_happy_path() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let network_id = 69u64;
|
||||
|
||||
let minimum_donation_u128 = <<Test as crate::Config>::MinimumDonation as Get<u128>>::get();
|
||||
let minimum_donation: BalanceOf<Test> = minimum_donation_u128.unique_saturated_into();
|
||||
|
||||
let secret_key = SecretKey::parse(&[7u8; 32]).unwrap();
|
||||
let public_key = PublicKey::from_secret_key(&secret_key);
|
||||
let pubkey_raw = &public_key.serialize()[1..65];
|
||||
let pubkey_hash = SubstrateKeccakHasher::hash(pubkey_raw);
|
||||
|
||||
let mut evm_addr_bytes = [0u8; 20];
|
||||
evm_addr_bytes.copy_from_slice(&pubkey_hash.as_ref()[12..32]);
|
||||
|
||||
let substrate_account_a = AccountId32::new([11u8; 32]);
|
||||
let substrate_account_b = AccountId32::new([22u8; 32]);
|
||||
let substrate_account_c = AccountId32::new([33u8; 32]);
|
||||
|
||||
let current_user = NewTestUser {
|
||||
substrate_account: substrate_account_a.clone(),
|
||||
evm_secret: secret_key,
|
||||
evm_address: EvmAddress::from(evm_addr_bytes),
|
||||
allowed_shares: 1000u128,
|
||||
token_id: 7,
|
||||
};
|
||||
|
||||
let max_index = 0u8;
|
||||
let raw_values_complex = vec![(0u8, ¤t_user)];
|
||||
|
||||
let tmp_package_probe = ClaimPackage::<Test> {
|
||||
shares: current_user.allowed_shares,
|
||||
merkle_proof: Default::default(),
|
||||
token_id: current_user.token_id,
|
||||
index: 0u32,
|
||||
};
|
||||
let size_hint = tmp_package_probe.get_preimage(¤t_user.evm_address, network_id).as_ref().len();
|
||||
|
||||
let merkle_tree = generate_tree::<SubstrateKeccakHasher, u8, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_values_complex,
|
||||
|
||||
|(index, u), buffer| {
|
||||
let tmp_package = ClaimPackage::<Test> {
|
||||
shares: u.allowed_shares,
|
||||
merkle_proof: Default::default(),
|
||||
token_id: u.token_id,
|
||||
index: index as u32
|
||||
};
|
||||
|
||||
let preimage_bytes = tmp_package.get_preimage(&u.evm_address, network_id);
|
||||
buffer.extend_from_slice(preimage_bytes.as_ref());
|
||||
|
||||
Ok(index as usize)
|
||||
}
|
||||
).ok().unwrap();
|
||||
|
||||
let total_shares = 1_000_000;
|
||||
let merkle_root = *merkle_tree.last().unwrap();
|
||||
let network_state = NetworkShare::new(total_shares, merkle_root, 0);
|
||||
let global_state = ShareState::new(total_shares);
|
||||
|
||||
NetworkShares::<Test>::insert(&network_id, network_state);
|
||||
GlobalShares::<Test>::put(global_state);
|
||||
|
||||
let setup_governor = |account: &<Test as frame_system::Config>::AccountId| {
|
||||
MemberShares::<Test>::insert(account, MemberShare {
|
||||
locked_balance: minimum_donation,
|
||||
initiated_network: None,
|
||||
activated_shares: 0,
|
||||
});
|
||||
};
|
||||
setup_governor(&substrate_account_a);
|
||||
setup_governor(&substrate_account_b);
|
||||
setup_governor(&substrate_account_c);
|
||||
|
||||
let proof = generate_proof::<SubstrateKeccakHasher, u8, ()>(&merkle_tree, max_index, 0u8)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let claim_package = ClaimPackage {
|
||||
shares: current_user.allowed_shares,
|
||||
merkle_proof: BoundedVec::try_from(proof).unwrap(),
|
||||
token_id: current_user.token_id,
|
||||
index: 0,
|
||||
};
|
||||
|
||||
let preimage = claim_package.get_preimage(¤t_user.evm_address, network_id);
|
||||
let preimage_hash = SubstrateKeccakHasher::hash(&preimage);
|
||||
|
||||
let generate_test_signature = |target_account: &<Test as frame_system::Config>::AccountId| -> EvmSignature {
|
||||
let active_nonce = ClaimedHashes::<Test>::get(&preimage_hash);
|
||||
let message_string_bytes = Governance::ethereum_signable_message(
|
||||
&target_account,
|
||||
&network_id,
|
||||
&preimage_hash,
|
||||
active_nonce,
|
||||
);
|
||||
|
||||
let message_hash = SubstrateKeccakHasher::hash(&message_string_bytes);
|
||||
let mut message_bytes = [0u8; 32];
|
||||
message_bytes.copy_from_slice(message_hash.as_ref());
|
||||
|
||||
let msg_to_sign = Message::parse(&message_bytes);
|
||||
let (sig, recovery_id) = libsecp256k1::sign(&msg_to_sign, ¤t_user.evm_secret);
|
||||
|
||||
let mut signature_raw = [0u8; 65];
|
||||
signature_raw[0..32].copy_from_slice(&sig.r.b32());
|
||||
signature_raw[32..64].copy_from_slice(&sig.s.b32());
|
||||
signature_raw[64] = recovery_id.serialize();
|
||||
|
||||
EvmSignature::from(signature_raw)
|
||||
};
|
||||
|
||||
let sig_0 = generate_test_signature(&substrate_account_a);
|
||||
assert_ok!(Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_a.clone()),
|
||||
network_id,
|
||||
claim_package.clone(),
|
||||
current_user.evm_address.clone(),
|
||||
sig_0,
|
||||
400,
|
||||
));
|
||||
|
||||
let global_share = GlobalShares::<Test>::get();
|
||||
assert_eq!(global_share.claimed_shares, 400);
|
||||
assert_eq!(global_share.total_shares, total_shares);
|
||||
|
||||
let network_share = NetworkShares::<Test>::get(&network_id);
|
||||
assert_eq!(network_share.claimed_shares(), 400);
|
||||
assert_eq!(network_share.total_shares(), total_shares);
|
||||
|
||||
assert_eq!(MemberShares::<Test>::get(&substrate_account_a).activated_shares, 400);
|
||||
assert_eq!(ClaimedHashes::<Test>::get(&preimage_hash), 1);
|
||||
assert_eq!(ClaimedShares::<Test>::get(&preimage_hash), 400);
|
||||
|
||||
let sig_1_fail = generate_test_signature(&substrate_account_b);
|
||||
assert_err!(
|
||||
Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_b.clone()),
|
||||
network_id,
|
||||
claim_package.clone(),
|
||||
current_user.evm_address.clone(),
|
||||
sig_1_fail,
|
||||
700,
|
||||
),
|
||||
Error::<Test>::ExceedsAllowedShares
|
||||
);
|
||||
|
||||
let sig_1_success = generate_test_signature(&substrate_account_b);
|
||||
assert_ok!(Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_b.clone()),
|
||||
network_id,
|
||||
claim_package.clone(),
|
||||
current_user.evm_address.clone(),
|
||||
sig_1_success,
|
||||
100,
|
||||
));
|
||||
|
||||
let global_share = GlobalShares::<Test>::get();
|
||||
assert_eq!(global_share.claimed_shares, 500);
|
||||
assert_eq!(global_share.total_shares, total_shares);
|
||||
|
||||
let network_share = NetworkShares::<Test>::get(&network_id);
|
||||
assert_eq!(network_share.claimed_shares(), 500);
|
||||
assert_eq!(network_share.total_shares(), total_shares);
|
||||
|
||||
assert_eq!(MemberShares::<Test>::get(&substrate_account_b).activated_shares, 100);
|
||||
assert_eq!(ClaimedHashes::<Test>::get(&preimage_hash), 2);
|
||||
assert_eq!(ClaimedShares::<Test>::get(&preimage_hash), 500);
|
||||
|
||||
let sig_2_final = generate_test_signature(&substrate_account_c);
|
||||
assert_ok!(Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_c.clone()),
|
||||
network_id,
|
||||
claim_package.clone(),
|
||||
current_user.evm_address.clone(),
|
||||
sig_2_final,
|
||||
300,
|
||||
));
|
||||
|
||||
let global_share = GlobalShares::<Test>::get();
|
||||
assert_eq!(global_share.claimed_shares, 1_000);
|
||||
assert_eq!(global_share.total_shares, total_shares);
|
||||
|
||||
let network_share = NetworkShares::<Test>::get(&network_id);
|
||||
assert_eq!(network_share.claimed_shares(), 1_000);
|
||||
assert_eq!(network_share.total_shares(), total_shares);
|
||||
|
||||
assert_eq!(MemberShares::<Test>::get(&substrate_account_c).activated_shares, 500);
|
||||
assert_eq!(ClaimedHashes::<Test>::get(&preimage_hash), 3);
|
||||
assert_eq!(ClaimedShares::<Test>::get(&preimage_hash), 1_000);
|
||||
|
||||
let sig_3_exhausted = generate_test_signature(&substrate_account_a);
|
||||
assert_err!(
|
||||
Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_a),
|
||||
network_id,
|
||||
claim_package,
|
||||
current_user.evm_address.clone(),
|
||||
sig_3_exhausted,
|
||||
100,
|
||||
),
|
||||
Error::<Test>::PartialClaimsExhausted
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_proof_from_python_preclaims_for_sepolia() {
|
||||
new_test_ext().execute_with(|| {
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
//! Autogenerated weights for `ghost_governance`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2026-09-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||
@ -56,23 +56,21 @@ impl WeightInfo for () {
|
||||
/// Proof: `GhostGovernance::MemberShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostGovernance::ClaimedHashes` (r:1 w:1)
|
||||
/// Proof: `GhostGovernance::ClaimedHashes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostGovernance::ClaimedShares` (r:1 w:1)
|
||||
/// Proof: `GhostGovernance::ClaimedShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostGovernance::NetworkShares` (r:1 w:1)
|
||||
/// Proof: `GhostGovernance::NetworkShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostGovernance::GlobalShares` (r:1 w:1)
|
||||
/// Proof: `GhostGovernance::GlobalShares` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `p` is `[1, 18]`.
|
||||
/// The range of component `p` is `[1, 20]`.
|
||||
fn claim(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `283`
|
||||
// Estimated: `3748`
|
||||
// Minimum execution time: 224_852_000 picoseconds.
|
||||
Weight::from_parts(225_347_733, 0)
|
||||
// Minimum execution time: 214_208_000 picoseconds.
|
||||
Weight::from_parts(216_987_870, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3748))
|
||||
// Standard Error: 21_234
|
||||
.saturating_add(Weight::from_parts(1_581_800, 0).saturating_mul(p.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(5))
|
||||
.saturating_add(RocksDbWeight::get().writes(5))
|
||||
// Standard Error: 30_856
|
||||
.saturating_add(Weight::from_parts(1_702_104, 0).saturating_mul(p.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(4))
|
||||
.saturating_add(RocksDbWeight::get().writes(4))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-helpers"
|
||||
version = "0.0.16"
|
||||
version = "0.0.11"
|
||||
description = "Cryptographic utility suite for custom runtimes: optimized Bitmaps, UTXO parsing, Merkle Tree proofs, and Hash Chain components."
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@ -2,8 +2,8 @@ use codec::{Decode, Encode};
|
||||
use num_traits::PrimInt;
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use sp_runtime::traits::UniqueSaturatedInto;
|
||||
use sp_arithmetic::traits::AtLeast8BitUnsigned;
|
||||
use sp_runtime::{traits::UniqueSaturatedInto, RuntimeDebug};
|
||||
use sp_std::{cmp::{min, max}, marker::PhantomData, vec, vec::Vec};
|
||||
|
||||
use ghost_traits::bounded_bitmap as traits;
|
||||
@ -33,7 +33,7 @@ pub fn validate_bitmap_sizes<B: traits::BoundedBitmapMetadata>(authorities: u32)
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
|
||||
#[scale_info(skip_type_params(MaxChunks))]
|
||||
pub struct BoundedBitmap<Inner, MaxChunks>
|
||||
where
|
||||
@ -43,19 +43,6 @@ where
|
||||
active_bits_count: u32,
|
||||
}
|
||||
|
||||
impl<Inner: core::fmt::Debug, MaxChunks> core::fmt::Debug for BoundedBitmap<Inner, MaxChunks>
|
||||
where
|
||||
MaxChunks: frame_support::traits::Get<u32>,
|
||||
{
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let slice: &[Inner] = &self.data;
|
||||
f.debug_struct("BoundedBitmap")
|
||||
.field("data", &slice)
|
||||
.field("active_bits_count", &self.active_bits_count)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, MaxChunks> BoundedBitmap<Inner, MaxChunks>
|
||||
where
|
||||
MaxChunks: Get<u32>,
|
||||
@ -67,15 +54,6 @@ where
|
||||
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
||||
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
||||
{
|
||||
pub fn inner_as_ref(&self) -> &[u8] {
|
||||
let slice: &[Inner] = self.data.as_ref();
|
||||
let byte_len = slice.len() * core::mem::size_of::<Inner>();
|
||||
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(slice.as_ptr() as *const u8, byte_len)
|
||||
}
|
||||
}
|
||||
|
||||
fn combine<F>(&self, rhs: &Self, op: F) -> Self
|
||||
where
|
||||
Inner: Copy,
|
||||
@ -168,6 +146,41 @@ where
|
||||
new_bitmap
|
||||
}
|
||||
|
||||
fn from_bitmask<Outer>(values: &Vec<Outer>) -> Self
|
||||
where
|
||||
Outer: AtLeast8BitUnsigned + PrimInt,
|
||||
{
|
||||
let value_bits = inner_bits::<Outer>();
|
||||
let n = values.iter().enumerate().rev()
|
||||
.find(|(_, &val)| val != Outer::zero())
|
||||
.map(|(idx, &val)| {
|
||||
let active_bits = value_bits - (val.leading_zeros() as usize);
|
||||
idx.saturating_mul(value_bits).saturating_add(active_bits)
|
||||
})
|
||||
.unwrap_or(0);
|
||||
|
||||
let mut new_bitmap = Self::empty(n);
|
||||
|
||||
for (value_index, value) in values.iter().enumerate() {
|
||||
for bit_index in 0..value_bits {
|
||||
let bit_mask = Outer::one() << bit_index;
|
||||
if (*value & bit_mask) == Outer::zero() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let index = value_index
|
||||
.saturating_mul(value_bits)
|
||||
.saturating_add(bit_index);
|
||||
|
||||
if let None = new_bitmap.insert(index as u32) {
|
||||
return new_bitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_bitmap
|
||||
}
|
||||
|
||||
fn all_ones<N>(n: N) -> Self
|
||||
where
|
||||
N: UniqueSaturatedInto<usize>,
|
||||
@ -294,35 +307,6 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn count_ones_before<N>(&self, index: N) -> Option<N>
|
||||
where
|
||||
usize: UniqueSaturatedInto<N>,
|
||||
N: UniqueSaturatedInto<usize>,
|
||||
{
|
||||
let index: usize = index.unique_saturated_into();
|
||||
|
||||
if index >= self.active_bits_count as usize { return None; }
|
||||
|
||||
let shift = inner_shift::<Inner>();
|
||||
let element_index = index >> shift;
|
||||
|
||||
let bit_index = index & ((1 << shift) - 1);
|
||||
|
||||
let current_element = self.data.get(element_index)?;
|
||||
let lower_bits_mask = (Inner::one() << bit_index) - Inner::one();
|
||||
let bits_before = *current_element & lower_bits_mask;
|
||||
|
||||
self.data.get(0..element_index)?
|
||||
.iter()
|
||||
.try_fold(0usize, |acc, &element| {
|
||||
acc.checked_add(element.count_ones() as usize)
|
||||
})
|
||||
.and_then(|popcount| {
|
||||
popcount.checked_add(bits_before.count_ones() as usize)
|
||||
})
|
||||
.map(|total| total.unique_saturated_into())
|
||||
}
|
||||
|
||||
fn count_ones<N>(&self) -> N
|
||||
where
|
||||
u32: UniqueSaturatedInto<N>,
|
||||
@ -441,14 +425,6 @@ where
|
||||
self.highest_bit()
|
||||
}
|
||||
|
||||
fn count_ones_before<N>(&self, index: N) -> Option<N>
|
||||
where
|
||||
usize: UniqueSaturatedInto<N>,
|
||||
N: UniqueSaturatedInto<usize>,
|
||||
{
|
||||
self.count_ones_before(index)
|
||||
}
|
||||
|
||||
fn count_ones<N>(&self) -> N
|
||||
where
|
||||
u32: UniqueSaturatedInto<N>,
|
||||
@ -500,6 +476,13 @@ where
|
||||
Self::empty_from(bitmap_ref)
|
||||
}
|
||||
|
||||
fn from_bitmask<Outer>(values_ref: &Vec<Outer>) -> Self
|
||||
where
|
||||
Outer: AtLeast8BitUnsigned + PrimInt,
|
||||
{
|
||||
Self::from_bitmask(values_ref)
|
||||
}
|
||||
|
||||
fn from_vec<Outer>(values_ref: &Vec<Outer>) -> Self
|
||||
where
|
||||
Outer: AtLeast8BitUnsigned + TryInto<usize> + PartialEq + Copy,
|
||||
@ -1116,72 +1099,50 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_ones_before_basic() {
|
||||
let w = <$inner_type>::BITS as usize;
|
||||
let idx = |x: usize| -> $inner_type {
|
||||
x.try_into().ok().expect("bit index fits inner type")
|
||||
};
|
||||
fn test_from_bitmask_where_each_u8_is_a_bit() {
|
||||
let byte1 = 77u8;
|
||||
let byte2 = 42u8;
|
||||
let byte3 = 69u8;
|
||||
|
||||
let mut indices: Vec<$inner_type> = vec![
|
||||
0u8.into(),
|
||||
1u8.into(),
|
||||
3u8.into()
|
||||
];
|
||||
let raw_bits: Vec<u8> = vec![byte1, byte2, byte3];
|
||||
let bitmap = TestBitmap::from_bitmask(&raw_bits);
|
||||
|
||||
indices.extend([idx(w), idx(w + 1), idx(w + 3)] as [$inner_type; 3]);
|
||||
let bitmap = TestBitmap::from_vec(&indices);
|
||||
let count_ones = raw_bits.iter().map(|b| b.count_ones()).sum::<u32>();
|
||||
let filled_bits = (raw_bits.len() as u32 - 1) * 8;
|
||||
let expected_bits = filled_bits + (8 - byte3.leading_zeros());
|
||||
|
||||
assert_eq!(bitmap.count_ones_before(0), Some(0));
|
||||
assert_eq!(bitmap.count_ones_before(1), Some(1));
|
||||
assert_eq!(bitmap.count_ones_before(2), Some(2));
|
||||
assert_eq!(bitmap.count_ones_before(3), Some(2));
|
||||
assert_eq!(bitmap.count_ones_before(4), Some(3));
|
||||
assert_eq!(bitmap.count_ones_before(w), Some(3));
|
||||
assert_eq!(bitmap.active_bits_count(), expected_bits);
|
||||
assert_eq!(bitmap.count_ones::<u32>(), count_ones);
|
||||
|
||||
assert_eq!(bitmap.count_ones_before(w + 1), Some(4));
|
||||
assert_eq!(bitmap.count_ones_before(w + 4), Some(6));
|
||||
assert_eq!(bitmap.count_ones_before(2 * w), Some(6));
|
||||
}
|
||||
// 77 - 10110010
|
||||
assert!(bitmap.contains(0u32));
|
||||
assert!(!bitmap.contains(1u32));
|
||||
assert!(bitmap.contains(2u32));
|
||||
assert!(bitmap.contains(3u32));
|
||||
assert!(!bitmap.contains(4u32));
|
||||
assert!(!bitmap.contains(5u32));
|
||||
assert!(bitmap.contains(6u32));
|
||||
assert!(!bitmap.contains(7u32));
|
||||
|
||||
#[test]
|
||||
fn test_count_ones_before_crossing_elements() {
|
||||
let w = <$inner_type>::BITS as usize;
|
||||
let idx = |x: usize| -> $inner_type {
|
||||
x.try_into().ok().expect("bit index fits inner type")
|
||||
};
|
||||
// 42 - 01010100
|
||||
assert!(!bitmap.contains(8u32));
|
||||
assert!(bitmap.contains(9u32));
|
||||
assert!(!bitmap.contains(10u32));
|
||||
assert!(bitmap.contains(11u32));
|
||||
assert!(!bitmap.contains(12u32));
|
||||
assert!(bitmap.contains(13u32));
|
||||
assert!(!bitmap.contains(14u32));
|
||||
assert!(!bitmap.contains(15u32));
|
||||
|
||||
let mut bitmap = TestBitmap::empty(2 * w + 1);
|
||||
for i in [0usize, 1, w, w + 1, w + 2] {
|
||||
bitmap.insert(idx(i));
|
||||
}
|
||||
|
||||
let bits_per_element = core::mem::size_of::<$inner_type>() * 8;
|
||||
|
||||
assert_eq!(bitmap.count_ones_before(bits_per_element), Some(2));
|
||||
assert_eq!(bitmap.count_ones_before(bits_per_element + 1), Some(3));
|
||||
assert_eq!(bitmap.count_ones_before(bits_per_element + 3), Some(5));
|
||||
assert_eq!(bitmap.count_ones_before(2 * bits_per_element), Some(5));
|
||||
|
||||
assert_eq!(bitmap.count_ones_before(2 * bits_per_element + 1), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_ones_before_bounds_and_overflow() {
|
||||
let w = <$inner_type>::BITS as usize;
|
||||
let idx = |x: usize| -> $inner_type {
|
||||
x.try_into().ok().expect("bit index fits inner type")
|
||||
};
|
||||
|
||||
let mut bitmap = TestBitmap::empty(w);
|
||||
for i in 0..w {
|
||||
bitmap.insert(idx(i));
|
||||
}
|
||||
|
||||
let bits_per_element = (core::mem::size_of::<$inner_type>() * 8) as u32;
|
||||
|
||||
assert_eq!(bitmap.count_ones_before(bits_per_element - 1), Some(bits_per_element - 1));
|
||||
assert_eq!(bitmap.count_ones_before(bits_per_element), None);
|
||||
assert_eq!(bitmap.count_ones_before(10000u32), None);
|
||||
// 69 - 10100010
|
||||
assert!(bitmap.contains(16u32));
|
||||
assert!(!bitmap.contains(17u32));
|
||||
assert!(bitmap.contains(18u32));
|
||||
assert!(!bitmap.contains(19u32));
|
||||
assert!(!bitmap.contains(20u32));
|
||||
assert!(!bitmap.contains(21u32));
|
||||
assert!(bitmap.contains(22u32));
|
||||
assert!(!bitmap.contains(23u32));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,5 +1,19 @@
|
||||
use ghost_traits::hashing::GhostHasher;
|
||||
|
||||
fn combine_values<H, V>(left: V, right: V) -> H::Hash
|
||||
where
|
||||
H: GhostHasher,
|
||||
V: AsRef<[u8]>,
|
||||
{
|
||||
let hash_len = H::hash_len();
|
||||
let mut combined = sp_std::vec![0u8; hash_len * 2];
|
||||
|
||||
combined[..hash_len].copy_from_slice(left.as_ref());
|
||||
combined[hash_len..].copy_from_slice(right.as_ref());
|
||||
|
||||
H::hash(&combined)
|
||||
}
|
||||
|
||||
pub fn cumulative_hash<H, S>(raw_values: S) -> H::Hash
|
||||
where
|
||||
H: GhostHasher,
|
||||
@ -10,7 +24,7 @@ where
|
||||
.into_iter()
|
||||
.fold(H::empty(), |acc_hash, raw_value| {
|
||||
let hashed_value = H::hash(raw_value.as_ref());
|
||||
H::combine_hashes(acc_hash, hashed_value)
|
||||
combine_values::<H, _>(acc_hash, hashed_value)
|
||||
})
|
||||
}
|
||||
|
||||
@ -33,7 +47,7 @@ where
|
||||
|
||||
iter.fold(current_hash, |acc_hash, raw_value| {
|
||||
let next_hash = H::from_slice(raw_value.as_ref());
|
||||
H::combine_hashes(acc_hash, next_hash)
|
||||
combine_values::<H, _>(acc_hash, next_hash)
|
||||
})
|
||||
}
|
||||
|
||||
@ -80,14 +94,45 @@ where
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sp_core::H256;
|
||||
use sp_io::hashing::{blake2_256, sha2_256};
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
use crate::{
|
||||
SubstrateBlake2Hasher, SubstrateKeccakHasher, UtxoSha2Hasher,
|
||||
};
|
||||
pub struct TestBlake2Hasher;
|
||||
impl GhostHasher for TestBlake2Hasher {
|
||||
type Hash = H256;
|
||||
type HashBytes = [u8; 32];
|
||||
|
||||
fn hash(data: &[u8]) -> Self::Hash {
|
||||
H256::from(blake2_256(data))
|
||||
}
|
||||
fn empty() -> Self::Hash {
|
||||
H256::zero()
|
||||
}
|
||||
fn hash_len() -> usize {
|
||||
H256::len_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestSha2Hasher;
|
||||
impl GhostHasher for TestSha2Hasher {
|
||||
type Hash = H256;
|
||||
type HashBytes = [u8; 32];
|
||||
fn hash(data: &[u8]) -> Self::Hash {
|
||||
let first_pass: [u8; 32] = sha2_256(data);
|
||||
let second_pass: [u8; 32] = sha2_256(&first_pass);
|
||||
|
||||
H256::from(second_pass)
|
||||
}
|
||||
fn hash_len() -> usize {
|
||||
H256::len_bytes()
|
||||
}
|
||||
fn empty() -> Self::Hash {
|
||||
H256::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn mock_sequential_hash(header: &[u8; 80]) -> H256 {
|
||||
sequential_hash::<UtxoSha2Hasher, _>(core::iter::once(header))
|
||||
sequential_hash::<TestSha2Hasher, _>(core::iter::once(header))
|
||||
}
|
||||
|
||||
fn create_header(prev_hash: [u8; 32]) -> [u8; 80] {
|
||||
@ -96,15 +141,10 @@ mod tests {
|
||||
header
|
||||
}
|
||||
|
||||
macro_rules! run_hasher_tests {
|
||||
($hasher_type:ty, $mod_name:ident) => {
|
||||
mod $mod_name {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_generate_empty_values() {
|
||||
let empty_list: Vec<Vec<u8>> = sp_std::vec![];
|
||||
let result = cumulative_hash::<$hasher_type, _>(empty_list);
|
||||
let result = cumulative_hash::<TestBlake2Hasher, _>(empty_list);
|
||||
assert_eq!(H256::zero(), result);
|
||||
}
|
||||
|
||||
@ -114,9 +154,9 @@ mod tests {
|
||||
let dataset_2 = sp_std::vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
|
||||
let dataset_3 = sp_std::vec![vec![9, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
|
||||
|
||||
let hash_1 = cumulative_hash::<$hasher_type, _>(dataset_1);
|
||||
let hash_2 = cumulative_hash::<$hasher_type, _>(dataset_2);
|
||||
let hash_3 = cumulative_hash::<$hasher_type, _>(dataset_3);
|
||||
let hash_1 = cumulative_hash::<TestBlake2Hasher, _>(dataset_1);
|
||||
let hash_2 = cumulative_hash::<TestBlake2Hasher, _>(dataset_2);
|
||||
let hash_3 = cumulative_hash::<TestBlake2Hasher, _>(dataset_3);
|
||||
|
||||
assert_eq!(hash_1, hash_2);
|
||||
assert_ne!(hash_1, hash_3);
|
||||
@ -128,8 +168,8 @@ mod tests {
|
||||
let dataset_forward = sp_std::vec![sp_std::vec![1, 1, 1], sp_std::vec![2, 2, 2]];
|
||||
let dataset_reversed = sp_std::vec![sp_std::vec![2, 2, 2], sp_std::vec![1, 1, 1]];
|
||||
|
||||
let hash_forward = cumulative_hash::<$hasher_type, _>(dataset_forward);
|
||||
let hash_reversed = cumulative_hash::<$hasher_type, _>(dataset_reversed);
|
||||
let hash_forward = cumulative_hash::<TestBlake2Hasher, _>(dataset_forward);
|
||||
let hash_reversed = cumulative_hash::<TestBlake2Hasher, _>(dataset_reversed);
|
||||
|
||||
assert_ne!(hash_forward, hash_reversed);
|
||||
}
|
||||
@ -137,22 +177,22 @@ mod tests {
|
||||
#[test]
|
||||
fn test_cumulative_hash_with_slices() {
|
||||
let slice_data: &[&[u8]] = &[&[1, 2, 3], &[4, 5, 6]];
|
||||
let hash_from_slice = cumulative_hash::<$hasher_type, _>(slice_data.iter());
|
||||
let hash_from_slice = cumulative_hash::<TestBlake2Hasher, _>(slice_data.iter());
|
||||
assert_ne!(hash_from_slice, H256::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequential_hash_empty() {
|
||||
let empty_list: Vec<Vec<u8>> = sp_std::vec![];
|
||||
let result = sequential_hash::<$hasher_type, _>(empty_list);
|
||||
let result = sequential_hash::<TestBlake2Hasher, _>(empty_list);
|
||||
assert_eq!(H256::zero(), result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequential_hash_single_element() {
|
||||
let single_item = sp_std::vec![sp_std::vec![1, 2, 3]];
|
||||
let result = sequential_hash::<$hasher_type, _>(single_item);
|
||||
let expected = <$hasher_type>::hash(&[1, 2, 3]);
|
||||
let result = sequential_hash::<TestBlake2Hasher, _>(single_item);
|
||||
let expected = TestBlake2Hasher::hash(&[1, 2, 3]);
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
||||
@ -162,9 +202,9 @@ mod tests {
|
||||
let data_2 = sp_std::vec![sp_std::vec![1], sp_std::vec![2], sp_std::vec![3]];
|
||||
let data_reversed = sp_std::vec![sp_std::vec![3], sp_std::vec![2], sp_std::vec![1]];
|
||||
|
||||
let hash_1 = sequential_hash::<$hasher_type, _>(data_1);
|
||||
let hash_2 = sequential_hash::<$hasher_type, _>(data_2);
|
||||
let hash_reversed = sequential_hash::<$hasher_type, _>(data_reversed);
|
||||
let hash_1 = sequential_hash::<TestBlake2Hasher, _>(data_1);
|
||||
let hash_2 = sequential_hash::<TestBlake2Hasher, _>(data_2);
|
||||
let hash_reversed = sequential_hash::<TestBlake2Hasher, _>(data_reversed);
|
||||
|
||||
assert_eq!(hash_1, hash_2);
|
||||
assert_ne!(hash_1, hash_reversed);
|
||||
@ -173,24 +213,17 @@ mod tests {
|
||||
#[test]
|
||||
fn test_sequential_vs_cumulative_hash() {
|
||||
let dataset = sp_std::vec![sp_std::vec![1, 2, 3], sp_std::vec![4, 5, 6]];
|
||||
let seq_hash = sequential_hash::<$hasher_type, _>(dataset.clone());
|
||||
let cum_hash = cumulative_hash::<$hasher_type, _>(dataset);
|
||||
let seq_hash = sequential_hash::<TestBlake2Hasher, _>(dataset.clone());
|
||||
let cum_hash = cumulative_hash::<TestBlake2Hasher, _>(dataset);
|
||||
assert_ne!(seq_hash, cum_hash);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequential_hash_with_slices() {
|
||||
let slice_data: &[&[u8]] = &[&[10, 20], &[30, 40]];
|
||||
let result = sequential_hash::<$hasher_type, _>(slice_data.iter());
|
||||
let result = sequential_hash::<TestBlake2Hasher, _>(slice_data.iter());
|
||||
assert_ne!(result, H256::zero());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run_hasher_tests!(SubstrateBlake2Hasher, blake2_hashing_tests);
|
||||
run_hasher_tests!(SubstrateKeccakHasher, keccak_hashing_tests);
|
||||
run_hasher_tests!(UtxoSha2Hasher, sha2_hashing_tests);
|
||||
|
||||
#[test]
|
||||
fn test_verify_in_current_block_with_empty_ancestry() {
|
||||
@ -201,7 +234,7 @@ mod tests {
|
||||
trusted_bytes.reverse();
|
||||
let trusted_top_block_hash = H256::from(trusted_bytes);
|
||||
|
||||
let result = verify_hash_ancestry::<UtxoSha2Hasher, &[[u8; 80]]>(
|
||||
let result = verify_hash_ancestry::<TestSha2Hasher, &[[u8; 80]]>(
|
||||
&tx_header,
|
||||
&[],
|
||||
trusted_top_block_hash,
|
||||
@ -223,7 +256,7 @@ mod tests {
|
||||
let trusted_top_block_hash = H256::from(trusted_bytes);
|
||||
|
||||
let ancestry = [header_101];
|
||||
let result = verify_hash_ancestry::<UtxoSha2Hasher, &[[u8; 80]]>(
|
||||
let result = verify_hash_ancestry::<TestSha2Hasher, &[[u8; 80]]>(
|
||||
&tx_header_100,
|
||||
&ancestry,
|
||||
trusted_top_block_hash,
|
||||
@ -251,7 +284,7 @@ mod tests {
|
||||
let trusted_top_block_hash = H256::from(trusted_bytes);
|
||||
|
||||
let ancestry = [header_101, header_102, header_103];
|
||||
let result = verify_hash_ancestry::<UtxoSha2Hasher, &[[u8; 80]]>(
|
||||
let result = verify_hash_ancestry::<TestSha2Hasher, &[[u8; 80]]>(
|
||||
&header_100,
|
||||
&ancestry,
|
||||
trusted_top_block_hash,
|
||||
@ -272,7 +305,7 @@ mod tests {
|
||||
let trusted_top_block_hash = H256::from(trusted_bytes);
|
||||
|
||||
let ancestry = [broken_header_101];
|
||||
let result = verify_hash_ancestry::<UtxoSha2Hasher, &[[u8; 80]]>(
|
||||
let result = verify_hash_ancestry::<TestSha2Hasher, &[[u8; 80]]>(
|
||||
&header_100,
|
||||
&ancestry,
|
||||
trusted_top_block_hash,
|
||||
|
||||
@ -1,452 +0,0 @@
|
||||
use sp_runtime::traits::UniqueSaturatedInto;
|
||||
|
||||
macro_rules! generate_perfect_slot_mapper {
|
||||
(
|
||||
struct_name: $struct_name:ident,
|
||||
inner_type: $inner_type:ty,
|
||||
init_rng: $init_rng:expr,
|
||||
golden_ratio: $golden_ratio:expr,
|
||||
lcg_multiplier: $lcg_multiplier:expr,
|
||||
lcg_increment: $lcg_increment:expr,
|
||||
) => {
|
||||
pub struct $struct_name;
|
||||
|
||||
impl $struct_name {
|
||||
const TOTAL_BITS: usize = core::mem::size_of::<$inner_type>() * 8;
|
||||
|
||||
fn get_exact_iterations(items_count: usize) -> Option<usize> {
|
||||
let table_size = Self::TOTAL_BITS;
|
||||
|
||||
if items_count <= 1 { return Some(1); }
|
||||
if items_count > table_size { return None; }
|
||||
|
||||
let density_pct = (items_count * 100) / table_size;
|
||||
|
||||
match table_size {
|
||||
16 => match density_pct {
|
||||
0 => Some(1),
|
||||
1..=5 => Some(1), // max 0 items
|
||||
6..=10 => Some(1), // max 1 items
|
||||
11..=15 => Some(2), // max 2 items
|
||||
16..=20 => Some(2), // max 3 items
|
||||
21..=25 => Some(3), // max 4 items
|
||||
26..=30 => Some(3), // max 4 items
|
||||
31..=35 => Some(5), // max 5 items
|
||||
36..=40 => Some(8), // max 6 items
|
||||
41..=45 => Some(13), // max 7 items
|
||||
46..=50 => Some(24), // max 8 items
|
||||
51..=55 => Some(24), // max 8 items
|
||||
56..=60 => Some(49), // max 9 items
|
||||
61..=65 => Some(112), // max 10 items
|
||||
66..=70 => Some(301), // max 11 items
|
||||
71..=75 => Some(966), // max 12 items
|
||||
76..=80 => Some(966), // max 12 items
|
||||
81..=85 => Some(3868), // max 13 items
|
||||
86..=90 => Some(20633), // max 14 items
|
||||
91..=95 => Some(165075), // max 15 items
|
||||
_ => None,
|
||||
},
|
||||
32 => match density_pct {
|
||||
0 => Some(1),
|
||||
1..=5 => Some(1), // max 1 items
|
||||
6..=10 => Some(2), // max 3 items
|
||||
11..=15 => Some(2), // max 4 items
|
||||
16..=20 => Some(4), // max 6 items
|
||||
21..=25 => Some(7), // max 8 items
|
||||
26..=30 => Some(9), // max 9 items
|
||||
31..=35 => Some(20), // max 11 items
|
||||
36..=40 => Some(31), // max 12 items
|
||||
41..=45 => Some(85), // max 14 items
|
||||
46..=50 => Some(287), // max 16 items
|
||||
51..=55 => Some(575), // max 17 items
|
||||
56..=60 => Some(2807), // max 19 items
|
||||
61..=65 => Some(6912), // max 20 items
|
||||
66..=70 => Some(53627), // max 22 items
|
||||
71..=75 => Some(610170), // max 24 items
|
||||
_ => None,
|
||||
},
|
||||
64 => match density_pct {
|
||||
0 => Some(1),
|
||||
1..=5 => Some(1), // max 3 items
|
||||
6..=10 => Some(2), // max 6 items
|
||||
11..=15 => Some(4), // max 9 items
|
||||
16..=20 => Some(8), // max 12 items
|
||||
21..=25 => Some(22), // max 16 items
|
||||
26..=30 => Some(58), // max 19 items
|
||||
31..=35 => Some(180), // max 22 items
|
||||
36..=40 => Some(686), // max 25 items
|
||||
41..=45 => Some(3285), // max 28 items
|
||||
46..=50 => Some(38995), // max 32 items
|
||||
51..=55 => Some(343497), // max 35 items
|
||||
_ => None,
|
||||
},
|
||||
128 => match density_pct {
|
||||
0 => Some(1),
|
||||
1..=5 => Some(2), // max 6 items
|
||||
6..=10 => Some(4), // max 12 items
|
||||
11..=15 => Some(11), // max 19 items
|
||||
16..=20 => Some(36), // max 25 items
|
||||
21..=25 => Some(207), // max 32 items
|
||||
26..=30 => Some(1368), // max 38 items
|
||||
31..=35 => Some(13426), // max 44 items
|
||||
36..=40 => Some(331105), // max 51 items
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_bits_metadata() -> Option<($inner_type, $inner_type)> {
|
||||
let table_size = Self::TOTAL_BITS;
|
||||
let bits_needed = table_size.trailing_zeros() as usize;
|
||||
|
||||
let bit_shift_usize = table_size.checked_sub(bits_needed)?;
|
||||
let bit_shift = bit_shift_usize as $inner_type;
|
||||
let bit_mask = (table_size - 1) as $inner_type;
|
||||
|
||||
Some((bit_shift, bit_mask))
|
||||
}
|
||||
|
||||
pub fn get_lcg_xor_mask<V>(values: &[V]) -> Option<$inner_type>
|
||||
where
|
||||
V: UniqueSaturatedInto<$inner_type> + Copy,
|
||||
{
|
||||
let table_size = Self::TOTAL_BITS;
|
||||
|
||||
if values.len() > table_size { return None; }
|
||||
|
||||
let max_iterations = Self::get_exact_iterations(values.len())?;
|
||||
let (bit_shift, bit_mask) = Self::get_bits_metadata()?;
|
||||
|
||||
let mut lcg_rng_state: $inner_type = $init_rng;
|
||||
let mut xor_key: $inner_type = lcg_rng_state;
|
||||
let mut slots_taken = [false; Self::TOTAL_BITS];
|
||||
|
||||
for _ in 0..max_iterations {
|
||||
slots_taken.fill(false);
|
||||
let mut collision_found = false;
|
||||
|
||||
for value in values {
|
||||
let slot_index = Self::get_lcg_based_slot_index(
|
||||
bit_mask,
|
||||
bit_shift,
|
||||
xor_key,
|
||||
value
|
||||
);
|
||||
|
||||
if slot_index >= table_size || slots_taken[slot_index] {
|
||||
collision_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
slots_taken[slot_index] = true;
|
||||
}
|
||||
|
||||
if !collision_found { return Some(xor_key); }
|
||||
|
||||
lcg_rng_state = lcg_rng_state
|
||||
.wrapping_mul($lcg_multiplier)
|
||||
.wrapping_add($lcg_increment);
|
||||
|
||||
xor_key = lcg_rng_state;
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_lcg_based_slot_index<V>(
|
||||
bit_mask: $inner_type,
|
||||
bit_shift: $inner_type,
|
||||
xor_key: $inner_type,
|
||||
value: &V
|
||||
) -> usize
|
||||
where
|
||||
V: UniqueSaturatedInto<$inner_type> + Copy,
|
||||
{
|
||||
let converted_value: $inner_type = (*value).unique_saturated_into();
|
||||
let knuth_hash = (converted_value ^ xor_key).wrapping_mul($golden_ratio);
|
||||
|
||||
let shifted_hash = knuth_hash.checked_shr(bit_shift as u32).unwrap_or(knuth_hash);
|
||||
let slot_index_converted = shifted_hash & bit_mask;
|
||||
|
||||
slot_index_converted as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generate_perfect_slot_mapper!(
|
||||
struct_name: PerfectSlotMapperU16,
|
||||
inner_type: u16,
|
||||
|
||||
init_rng: 0x1234,
|
||||
golden_ratio: 0x9E37, // Computed with: 2^16 * ( (sqrt(5) - 1) / 2)
|
||||
lcg_multiplier: 25173, // Reference: Peter Grogono, Programming in Pascal, Section 4.5.
|
||||
lcg_increment: 13849, // http://engr.case.edu/merat_francis/eeap282f97/labs/Random_Lab.pdf
|
||||
);
|
||||
|
||||
generate_perfect_slot_mapper!(
|
||||
struct_name: PerfectSlotMapperU32,
|
||||
inner_type: u32,
|
||||
|
||||
init_rng: 0x12345678,
|
||||
golden_ratio: 0x9E3779B9, // Computd with: 2^32 * ( (sqrt(5) - 1) / 2)
|
||||
lcg_multiplier: 1664525, // Numerical Recipes `ranqd1`, Chapter 7.1,
|
||||
lcg_increment: 1013904223, // An Even Quicker Generator, Eq. 7.1.6
|
||||
);
|
||||
|
||||
generate_perfect_slot_mapper!(
|
||||
struct_name: PerfectSlotMapperU64,
|
||||
inner_type: u64,
|
||||
|
||||
init_rng: 0x123456789ABCDEF,
|
||||
golden_ratio: 0x9E3779B97F4A7C15, // Taken from `splitmix64`, this generator is specifically used in PostgreSQL
|
||||
lcg_multiplier: 6364136223846793005, // Newlib / Musl libc 64-bit LCG multiplier
|
||||
lcg_increment: 1, // https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/stdlib/rand.c
|
||||
);
|
||||
|
||||
generate_perfect_slot_mapper!(
|
||||
struct_name: PerfectSlotMapperU128,
|
||||
inner_type: u128,
|
||||
|
||||
init_rng: 0x123456789ABCDEF0123456789ABCDEF0,
|
||||
golden_ratio: 0x9E3779B97F4A7C15F39CC0605CEDC834, // Computd with: 2^128 * ( (sqrt(5) - 1) / 2) with python
|
||||
lcg_multiplier: 0x2360ED051FC65DA44385DF649FCCF645, // 2549297995355413924ULL,4865540595714422341ULL
|
||||
lcg_increment: 0x5851F42D4C957F2D14057B7EF767814F, // 6364136223846793005ULL,1442695040888963407ULL
|
||||
// https://github.com/imneme/pcg-cpp/blob/master/include/pcg_random.hpp
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
mod perfect_mapper_tests {
|
||||
use super::*;
|
||||
|
||||
macro_rules! generate_mapper_test {
|
||||
($mod_name:ident, $struct_name:ident, $init_rng:expr, $inner_type:ty) => {
|
||||
mod $mod_name {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_standard_pack_20_percentages() {
|
||||
const TABLE_SIZE: usize = $struct_name::TOTAL_BITS;
|
||||
const ITEMS_COUNT: usize = (TABLE_SIZE * 20) / 100;
|
||||
|
||||
let mut values = [0 as $inner_type; TABLE_SIZE];
|
||||
for i in 0..ITEMS_COUNT {
|
||||
values[i] = ((i as $inner_type).wrapping_mul(999)) ^ 0xABC;
|
||||
}
|
||||
|
||||
let filled_values = &values[0..ITEMS_COUNT];
|
||||
let mask = $struct_name::get_lcg_xor_mask(filled_values);
|
||||
|
||||
assert!(mask.is_some());
|
||||
let xor_key = mask.unwrap();
|
||||
|
||||
let bits_needed = TABLE_SIZE.trailing_zeros() as $inner_type;
|
||||
let bit_mask = (TABLE_SIZE - 1) as $inner_type;
|
||||
let bit_shift = (TABLE_SIZE as $inner_type) - bits_needed;
|
||||
|
||||
let mut slots = vec![false; TABLE_SIZE];
|
||||
|
||||
for val in filled_values {
|
||||
let idx = $struct_name::get_lcg_based_slot_index(
|
||||
bit_mask,
|
||||
bit_shift,
|
||||
xor_key,
|
||||
val
|
||||
);
|
||||
assert!(idx < TABLE_SIZE);
|
||||
assert!(!slots[idx]);
|
||||
slots[idx] = true;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_heavy_math() {
|
||||
const TABLE_SIZE: usize = $struct_name::TOTAL_BITS;
|
||||
|
||||
let max_val = <$inner_type>::MAX;
|
||||
let one_val = 1 as $inner_type;
|
||||
|
||||
let mut block_pattern = 0 as $inner_type;
|
||||
let mut noise_pattern = 0 as $inner_type;
|
||||
|
||||
let total_bytes = core::mem::size_of::<$inner_type>();
|
||||
let mut i = 0;
|
||||
while i < total_bytes {
|
||||
let byte_val = if i % 2 == 0 { 0x55 } else { 0xAA };
|
||||
noise_pattern = (noise_pattern << 8) | (byte_val as $inner_type);
|
||||
|
||||
let block_val = if i < total_bytes / 3 {
|
||||
0xEE
|
||||
} else if i < (total_bytes * 2) / 3 {
|
||||
0xFF
|
||||
} else {
|
||||
0xAA
|
||||
};
|
||||
block_pattern = (block_pattern << 8) | (block_val as $inner_type);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let center_bit_shift = (TABLE_SIZE / 2) as u32;
|
||||
let center_bit_pattern = (1 as $inner_type)
|
||||
.checked_shl(center_bit_shift)
|
||||
.unwrap_or(1);
|
||||
|
||||
let values: [$inner_type; 6] = [
|
||||
$init_rng,
|
||||
noise_pattern,
|
||||
max_val,
|
||||
one_val,
|
||||
center_bit_pattern,
|
||||
block_pattern
|
||||
];
|
||||
|
||||
let mask = $struct_name::get_lcg_xor_mask(&values);
|
||||
assert!(mask.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_element() {
|
||||
const TABLE_SIZE: usize = $struct_name::TOTAL_BITS;
|
||||
|
||||
let single_value = [420 as $inner_type];
|
||||
let mask = $struct_name::get_lcg_xor_mask(&single_value);
|
||||
assert!(mask.is_some());
|
||||
|
||||
let xor_key = mask.unwrap();
|
||||
|
||||
let bits_needed = TABLE_SIZE.trailing_zeros() as $inner_type;
|
||||
let bit_mask = (TABLE_SIZE - 1) as $inner_type;
|
||||
let bit_shift = (TABLE_SIZE as $inner_type) - bits_needed;
|
||||
|
||||
let idx = $struct_name::get_lcg_based_slot_index(
|
||||
bit_mask,
|
||||
bit_shift,
|
||||
xor_key,
|
||||
&single_value[0]
|
||||
);
|
||||
|
||||
assert!(idx < TABLE_SIZE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_bounds_returns_none() {
|
||||
const TABLE_SIZE: usize = $struct_name::TOTAL_BITS;
|
||||
let oversized_values = [1 as $inner_type; TABLE_SIZE];
|
||||
let mask = $struct_name::get_lcg_xor_mask(&oversized_values);
|
||||
assert!(mask.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_top_25_evm_chains_by_tvl() {
|
||||
const TABLE_SIZE: usize = $struct_name::TOTAL_BITS;
|
||||
|
||||
let evm_network_ids: [u64; 25] = [
|
||||
1, // Ethereum Mainnet
|
||||
8453, // Base
|
||||
56, // BNB Smart Chain
|
||||
42161, // Arbitrum One
|
||||
10143, // Monad
|
||||
137, // Polygon PoS
|
||||
43114, // Avalanche C-Chain
|
||||
10, // OP Mainnet
|
||||
57073, // Ink
|
||||
14, // Flare Network
|
||||
196, // X Layer
|
||||
25, // Cronos
|
||||
5000, // Mantle
|
||||
100, // Gnosis Chain
|
||||
59144, // Linea
|
||||
534352, // Scroll
|
||||
324, // zkSync Era
|
||||
146, // Sonic (Fantom)
|
||||
1116, // Core
|
||||
42220, // Celo
|
||||
1088, // Metis
|
||||
592, // Astar
|
||||
1284, // Moonbeam
|
||||
98865, // Plume Network
|
||||
60808, // BOB (Build on Bitcoin)
|
||||
];
|
||||
|
||||
let mask = $struct_name::get_lcg_xor_mask(&evm_network_ids);
|
||||
|
||||
if let Some(xor_key) = mask {
|
||||
let mut slots_check = [false; TABLE_SIZE];
|
||||
|
||||
let bits_needed = TABLE_SIZE.trailing_zeros() as $inner_type;
|
||||
let bit_mask = (TABLE_SIZE - 1) as $inner_type;
|
||||
let bit_shift = (TABLE_SIZE as $inner_type) - bits_needed;
|
||||
|
||||
for chain_id in &evm_network_ids {
|
||||
let slot_idx = $struct_name::get_lcg_based_slot_index(
|
||||
bit_mask,
|
||||
bit_shift,
|
||||
xor_key,
|
||||
chain_id
|
||||
);
|
||||
|
||||
assert!(slot_idx < TABLE_SIZE);
|
||||
assert!(!slots_check[slot_idx]);
|
||||
|
||||
slots_check[slot_idx] = true;
|
||||
}
|
||||
} else {
|
||||
assert!(TABLE_SIZE <= 32);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_top_25_evm_testnet_chains() {
|
||||
const TABLE_SIZE: usize = $struct_name::TOTAL_BITS;
|
||||
|
||||
let evm_network_ids: [u64; 10] = [
|
||||
63, // Mordor (Ethereum Classic Testnet)
|
||||
11155111, // Ethereum Sepolia
|
||||
80002, // Polygon Amoy
|
||||
421614, // Arbitrum Sepolia
|
||||
84532, // Base Sepolia
|
||||
11155420, // Optimism Sepolia
|
||||
59141, // Linea Sepolia
|
||||
534351, // Scroll Sepolia
|
||||
80084, // Berachain Bartio
|
||||
98864, // Plume Testnet
|
||||
];
|
||||
|
||||
let mask = $struct_name::get_lcg_xor_mask(&evm_network_ids);
|
||||
|
||||
if let Some(xor_key) = mask {
|
||||
let mut slots_check = [false; TABLE_SIZE];
|
||||
|
||||
let bits_needed = TABLE_SIZE.trailing_zeros() as $inner_type;
|
||||
let bit_mask = (TABLE_SIZE - 1) as $inner_type;
|
||||
let bit_shift = (TABLE_SIZE as $inner_type) - bits_needed;
|
||||
|
||||
for chain_id in &evm_network_ids {
|
||||
let slot_idx = $struct_name::get_lcg_based_slot_index(
|
||||
bit_mask,
|
||||
bit_shift,
|
||||
xor_key,
|
||||
chain_id
|
||||
);
|
||||
|
||||
assert!(slot_idx < TABLE_SIZE);
|
||||
assert!(!slots_check[slot_idx]);
|
||||
|
||||
slots_check[slot_idx] = true;
|
||||
}
|
||||
} else {
|
||||
assert!(TABLE_SIZE == 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generate_mapper_test!(u16_mapper, PerfectSlotMapperU16, 0x1234, u16);
|
||||
generate_mapper_test!(u32_mapper, PerfectSlotMapperU32, 0x12345678, u32);
|
||||
generate_mapper_test!(u64_mapper, PerfectSlotMapperU64, 0x123456789ABCDEF, u64);
|
||||
generate_mapper_test!(u128_mapper, PerfectSlotMapperU128, 0x123456789ABCDEF0123456789ABCDEF0, u128);
|
||||
}
|
||||
@ -3,14 +3,12 @@
|
||||
use ghost_traits::hashing::GhostHasher;
|
||||
use sp_core::H256;
|
||||
use sp_io::hashing::{blake2_256, keccak_256, sha2_256};
|
||||
use sp_runtime::{Perbill, traits::{Saturating, UniqueSaturatedInto}};
|
||||
|
||||
pub mod bounded_bitmap;
|
||||
pub mod hash_chain;
|
||||
pub mod merkle_tree;
|
||||
pub mod networks;
|
||||
pub mod utxo;
|
||||
pub mod lcg;
|
||||
|
||||
pub type AuthIndexU8 = u8;
|
||||
pub type AuthIndexU16 = u16;
|
||||
@ -50,101 +48,53 @@ where
|
||||
value - f
|
||||
}
|
||||
|
||||
pub fn get_submission_probability<B>(
|
||||
participants_count: usize,
|
||||
values_count: usize,
|
||||
blocks_left: B
|
||||
) -> Perbill
|
||||
where
|
||||
B: UniqueSaturatedInto<u32>,
|
||||
{
|
||||
// y = min(1, (1/6) + (A-C)/2x)
|
||||
let a: u32 = participants_count.unique_saturated_into();
|
||||
let c: u32 = values_count.unique_saturated_into();
|
||||
let x: u32 = blocks_left.unique_saturated_into();
|
||||
|
||||
if a == 0 { return Perbill::zero(); }
|
||||
|
||||
let part_1 = Perbill::from_percent(6);
|
||||
let part_2 = if x > 0 {
|
||||
let numerator = a.saturating_sub(c);
|
||||
let denominator = x.saturating_mul(2);
|
||||
Perbill::from_rational(numerator, denominator)
|
||||
} else {
|
||||
if c < a { Perbill::one() }
|
||||
else { Perbill::zero() }
|
||||
};
|
||||
|
||||
part_1.saturating_add(part_2)
|
||||
pub struct SubstrateBlake2Hasher;
|
||||
impl GhostHasher for SubstrateBlake2Hasher {
|
||||
type Hash = H256;
|
||||
type HashBytes = [u8; 32];
|
||||
fn hash(data: &[u8]) -> Self::Hash {
|
||||
H256::from(blake2_256(data))
|
||||
}
|
||||
|
||||
macro_rules! impl_ghost_hasher {
|
||||
(
|
||||
struct $name:ident;
|
||||
hash_type: $hash_type:ty;
|
||||
hash_bytes_len: $hash_bytes_len:expr;
|
||||
fn hash($data:ident) -> $hash_res:expr
|
||||
) => {
|
||||
pub struct $name;
|
||||
|
||||
impl GhostHasher for $name {
|
||||
type Hash = $hash_type;
|
||||
type HashBytes = [u8; $hash_bytes_len];
|
||||
|
||||
fn hash($data: &[u8]) -> Self::Hash {
|
||||
$hash_res
|
||||
}
|
||||
|
||||
fn hash_len() -> usize {
|
||||
$hash_bytes_len
|
||||
H256::len_bytes()
|
||||
}
|
||||
|
||||
fn empty() -> Self::Hash {
|
||||
<$hash_type>::zero()
|
||||
}
|
||||
|
||||
fn combine_hashes(left: Self::Hash, right: Self::Hash) -> Self::Hash {
|
||||
let mut combined = [0u8; $hash_bytes_len * 2];
|
||||
combined[..$hash_bytes_len].copy_from_slice(left.as_ref());
|
||||
combined[$hash_bytes_len..].copy_from_slice(right.as_ref());
|
||||
Self::hash(&combined)
|
||||
}
|
||||
|
||||
fn combine_hashes_prefixed(p: u8, l: Self::Hash, r: Self::Hash) -> Self::Hash {
|
||||
let mut combined = [p; $hash_bytes_len * 2 + 1];
|
||||
combined[1..1 + $hash_bytes_len].copy_from_slice(l.as_ref());
|
||||
combined[1 + $hash_bytes_len..].copy_from_slice(r.as_ref());
|
||||
Self::hash(&combined)
|
||||
H256::zero()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub struct SubstrateKeccakHasher;
|
||||
impl GhostHasher for SubstrateKeccakHasher {
|
||||
type Hash = H256;
|
||||
type HashBytes = [u8; 32];
|
||||
fn hash(data: &[u8]) -> Self::Hash {
|
||||
H256::from(keccak_256(data))
|
||||
}
|
||||
fn hash_len() -> usize {
|
||||
H256::len_bytes()
|
||||
}
|
||||
fn empty() -> Self::Hash {
|
||||
H256::zero()
|
||||
}
|
||||
}
|
||||
|
||||
impl_ghost_hasher!(
|
||||
struct SubstrateBlake2Hasher;
|
||||
hash_type: H256;
|
||||
hash_bytes_len: 32;
|
||||
fn hash(data) -> H256::from(blake2_256(data))
|
||||
);
|
||||
|
||||
impl_ghost_hasher!(
|
||||
struct SubstrateKeccakHasher;
|
||||
hash_type: H256;
|
||||
hash_bytes_len: 32;
|
||||
fn hash(data) -> H256::from(keccak_256(data))
|
||||
);
|
||||
|
||||
impl_ghost_hasher!(
|
||||
struct UtxoSha2Hasher;
|
||||
hash_type: H256;
|
||||
hash_bytes_len: 32;
|
||||
fn hash(data) -> {
|
||||
pub struct UtxoSha2Hasher;
|
||||
impl GhostHasher for UtxoSha2Hasher {
|
||||
type Hash = H256;
|
||||
type HashBytes = [u8; 32];
|
||||
fn hash(data: &[u8]) -> Self::Hash {
|
||||
let first_pass: [u8; 32] = sha2_256(data);
|
||||
let second_pass: [u8; 32] = sha2_256(&first_pass);
|
||||
|
||||
H256::from(second_pass)
|
||||
}
|
||||
);
|
||||
fn hash_len() -> usize {
|
||||
H256::len_bytes()
|
||||
}
|
||||
fn empty() -> Self::Hash {
|
||||
H256::zero()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@ -184,38 +134,4 @@ mod tests {
|
||||
assert_eq!(get_byzantium_quorum_threshold(4u64), 3u64);
|
||||
assert_eq!(get_byzantium_quorum_threshold(4usize), 3usize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_base_probability_when_plenty_of_time() {
|
||||
let prob = get_submission_probability(100, 0, 10000u32);
|
||||
assert!(prob > Perbill::from_percent(6));
|
||||
assert!(prob < Perbill::from_percent(7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_urgency_increases_as_blocks_shrink() {
|
||||
let prob_far = get_submission_probability(20, 10, 10u32);
|
||||
assert_eq!(prob_far, Perbill::from_percent(56));
|
||||
|
||||
let prob_close = get_submission_probability(20, 10, 2u32);
|
||||
assert_eq!(prob_close, Perbill::one());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deadline_reached_but_votes_missing() {
|
||||
let prob = get_submission_probability(10, 5, 0u32);
|
||||
assert_eq!(prob, Perbill::one());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_votes_collected() {
|
||||
let prob = get_submission_probability(10, 10, 5u32);
|
||||
assert_eq!(prob, Perbill::from_percent(6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_participants_edge_case() {
|
||||
let prob = get_submission_probability(0, 0, 5u32);
|
||||
assert_eq!(prob, Perbill::zero());
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,57 +6,49 @@ use sp_std::vec::Vec;
|
||||
const LEAF_PREFIX: u8 = 0;
|
||||
const NODE_PREFIX: u8 = 1;
|
||||
|
||||
pub enum MerkleTreeError<E> {
|
||||
Generate(E),
|
||||
InvalidIndex,
|
||||
Empty,
|
||||
}
|
||||
|
||||
fn leaf_prefixed<H>(preimage: &[u8]) -> H::Hash
|
||||
where
|
||||
H: GhostHasher,
|
||||
{
|
||||
let mut buffer = Vec::with_capacity(preimage.len() + 1);
|
||||
buffer.push(LEAF_PREFIX);
|
||||
buffer.extend_from_slice(preimage);
|
||||
let mut prefixed_data = sp_std::vec![LEAF_PREFIX; 1 + preimage.len()];
|
||||
prefixed_data[1..].copy_from_slice(preimage);
|
||||
H::hash(&prefixed_data)
|
||||
}
|
||||
|
||||
H::hash(&buffer)
|
||||
fn node_prefixed<H>(preimage1: &[u8], preimage2: &[u8]) -> H::Hash
|
||||
where
|
||||
H: GhostHasher,
|
||||
{
|
||||
let total_len = preimage1.len() + preimage2.len();
|
||||
let mut prefixed_data = sp_std::vec![NODE_PREFIX; 1 + total_len];
|
||||
prefixed_data[1..1 + preimage1.len()].copy_from_slice(preimage1);
|
||||
prefixed_data[1 + preimage1.len()..].copy_from_slice(preimage2);
|
||||
H::hash(&prefixed_data)
|
||||
}
|
||||
|
||||
pub fn generate_tree<H, I, S, F, E>(
|
||||
max_index: I,
|
||||
size_hint: usize,
|
||||
raw_values: S,
|
||||
update_preimage_buffer: F,
|
||||
) -> Result<Vec<H::Hash>, MerkleTreeError<E>>
|
||||
generate_preimage: F,
|
||||
) -> Result<Vec<H::Hash>, E>
|
||||
where
|
||||
H: GhostHasher,
|
||||
S: IntoIterator,
|
||||
I: AtLeast8BitUnsigned + UniqueSaturatedInto<usize>,
|
||||
F: Fn(S::Item, &mut Vec<u8>) -> Result<usize, E>,
|
||||
F: Fn(S::Item) -> Result<(usize, Vec<u8>), E>,
|
||||
{
|
||||
let num_of_leaves: usize = (max_index + I::one()).unique_saturated_into();
|
||||
let padded_leaves = num_of_leaves.next_power_of_two();
|
||||
let total_capacity = (2 * padded_leaves) - 1;
|
||||
|
||||
if total_capacity == 0 { return Err(MerkleTreeError::Empty); }
|
||||
|
||||
let empty_hash = H::empty();
|
||||
let empty_leaf_hash = leaf_prefixed::<H>(empty_hash.as_ref());
|
||||
let mut merkle_tree = sp_std::vec![empty_leaf_hash; total_capacity];
|
||||
|
||||
let mut buffer = Vec::with_capacity(size_hint + 1);
|
||||
|
||||
for item in raw_values.into_iter() {
|
||||
buffer.clear();
|
||||
buffer.push(LEAF_PREFIX);
|
||||
|
||||
let index = update_preimage_buffer(item, &mut buffer)
|
||||
.map_err(|err| MerkleTreeError::Generate(err))?;
|
||||
|
||||
if index >= padded_leaves { return Err(MerkleTreeError::InvalidIndex); }
|
||||
|
||||
merkle_tree[index] = H::hash(&buffer);
|
||||
let (index, preimage) = generate_preimage(item)?;
|
||||
if index >= padded_leaves { return Ok(sp_std::vec![]); }
|
||||
merkle_tree[index] = leaf_prefixed::<H>(&preimage)
|
||||
}
|
||||
|
||||
let mut layer_start = 0;
|
||||
@ -66,15 +58,10 @@ where
|
||||
while current_layer_len > 1 {
|
||||
for i in (0..current_layer_len).step_by(2) {
|
||||
let layer_index = layer_start + i;
|
||||
let left_bytes = merkle_tree[layer_index];
|
||||
let right_bytes = merkle_tree[layer_index | 1];
|
||||
let left_bytes = merkle_tree[layer_index].as_ref();
|
||||
let right_bytes = merkle_tree[layer_index | 1].as_ref();
|
||||
|
||||
let combined_hash = H::combine_hashes_prefixed(
|
||||
NODE_PREFIX,
|
||||
left_bytes,
|
||||
right_bytes,
|
||||
);
|
||||
merkle_tree[write_ptr] = combined_hash;
|
||||
merkle_tree[write_ptr] = node_prefixed::<H>(left_bytes, right_bytes);
|
||||
write_ptr += 1;
|
||||
}
|
||||
layer_start += current_layer_len;
|
||||
@ -84,16 +71,16 @@ where
|
||||
Ok(merkle_tree)
|
||||
}
|
||||
|
||||
pub fn generate_proof<H, I, E>(
|
||||
pub fn generate_proof<H, I>(
|
||||
merkle_tree: &[H::Hash],
|
||||
max_index: I,
|
||||
index: I,
|
||||
) -> Result<Vec<H::Hash>, MerkleTreeError<E>>
|
||||
) -> Vec<H::Hash>
|
||||
where
|
||||
H: GhostHasher,
|
||||
I: AtLeast8BitUnsigned + UniqueSaturatedInto<usize>,
|
||||
{
|
||||
if index > max_index { return Err(MerkleTreeError::InvalidIndex); }
|
||||
if index > max_index { return sp_std::vec![]; }
|
||||
|
||||
let num_of_leaves: usize = (max_index + I::one()).unique_saturated_into();
|
||||
let mut current_index: usize = index.unique_saturated_into();
|
||||
@ -114,7 +101,7 @@ where
|
||||
current_index >>= 1;
|
||||
}
|
||||
|
||||
Ok(proof)
|
||||
proof
|
||||
}
|
||||
|
||||
pub fn verify_tree_proof<H, I>(
|
||||
@ -133,11 +120,14 @@ where
|
||||
let mut current_hash = leaf_prefixed::<H>(preimage);
|
||||
|
||||
for sibling in merkle_proof.iter() {
|
||||
current_hash = if current_index % 2 == 0 {
|
||||
H::combine_hashes_prefixed(NODE_PREFIX, current_hash, *sibling)
|
||||
let sibling_bytes = sibling.as_ref();
|
||||
let hash_bytes = current_hash.as_ref();
|
||||
|
||||
if current_index % 2 == 0 {
|
||||
current_hash = node_prefixed::<H>(hash_bytes, sibling_bytes);
|
||||
} else {
|
||||
H::combine_hashes_prefixed(NODE_PREFIX, *sibling, current_hash)
|
||||
};
|
||||
current_hash = node_prefixed::<H>(sibling_bytes, hash_bytes);
|
||||
}
|
||||
|
||||
current_index >>= 1;
|
||||
}
|
||||
@ -148,64 +138,66 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sp_core::H256;
|
||||
use sp_io::hashing::blake2_256;
|
||||
|
||||
use crate::{
|
||||
SubstrateBlake2Hasher, SubstrateKeccakHasher, UtxoSha2Hasher,
|
||||
};
|
||||
pub struct TestBlake2Hasher;
|
||||
impl GhostHasher for TestBlake2Hasher {
|
||||
type Hash = H256;
|
||||
type HashBytes = [u8; 32];
|
||||
|
||||
macro_rules! run_merkle_tree_tests {
|
||||
($hasher_type:ty, $mod_name:ident) => {
|
||||
mod $mod_name {
|
||||
use super::*;
|
||||
fn hash(data: &[u8]) -> Self::Hash {
|
||||
H256::from(blake2_256(data))
|
||||
}
|
||||
fn empty() -> Self::Hash {
|
||||
H256::zero()
|
||||
}
|
||||
fn hash_len() -> usize {
|
||||
H256::len_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_tree_perfect_power_of_two() {
|
||||
let max_index = 3u32;
|
||||
let size_hint = 69;
|
||||
|
||||
let raw_data = sp_std::vec![
|
||||
(0, sp_std::vec![1; 69]),
|
||||
(1, sp_std::vec![2; 69]),
|
||||
(2, sp_std::vec![3; 69]),
|
||||
(3, sp_std::vec![4; 69]),
|
||||
(0, sp_std::vec![1]),
|
||||
(1, sp_std::vec![2]),
|
||||
(2, sp_std::vec![3]),
|
||||
(3, sp_std::vec![4]),
|
||||
];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_data,
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(tree.len(), 7);
|
||||
|
||||
let h0 = <$hasher_type>::hash(&[ &[0u8], [1; 69].as_slice() ].concat());
|
||||
let h1 = <$hasher_type>::hash(&[ &[0u8], [2; 69].as_slice() ].concat());
|
||||
let h2 = <$hasher_type>::hash(&[ &[0u8], [3; 69].as_slice() ].concat());
|
||||
let h3 = <$hasher_type>::hash(&[ &[0u8], [4; 69].as_slice() ].concat());
|
||||
let h0 = TestBlake2Hasher::hash(&[ &[0u8], [1].as_slice() ].concat());
|
||||
let h1 = TestBlake2Hasher::hash(&[ &[0u8], [2].as_slice() ].concat());
|
||||
let h2 = TestBlake2Hasher::hash(&[ &[0u8], [3].as_slice() ].concat());
|
||||
let h3 = TestBlake2Hasher::hash(&[ &[0u8], [4].as_slice() ].concat());
|
||||
|
||||
let mut c1 = [0u8; 65];
|
||||
c1[0] = NODE_PREFIX;
|
||||
c1[1..33].copy_from_slice(h0.as_ref());
|
||||
c1[33..].copy_from_slice(h1.as_ref());
|
||||
let parent_left = <$hasher_type>::hash(&c1);
|
||||
let parent_left = TestBlake2Hasher::hash(&c1);
|
||||
|
||||
let mut c2 = [0u8; 65];
|
||||
c2[0] = NODE_PREFIX;
|
||||
c2[1..33].copy_from_slice(h2.as_ref());
|
||||
c2[33..].copy_from_slice(h3.as_ref());
|
||||
let parent_right = <$hasher_type>::hash(&c2);
|
||||
let parent_right = TestBlake2Hasher::hash(&c2);
|
||||
|
||||
let mut c_root = [0u8; 65];
|
||||
c_root[0] = NODE_PREFIX;
|
||||
c_root[1..33].copy_from_slice(parent_left.as_ref());
|
||||
c_root[33..].copy_from_slice(parent_right.as_ref());
|
||||
let expected_root = <$hasher_type>::hash(&c_root);
|
||||
let expected_root = TestBlake2Hasher::hash(&c_root);
|
||||
|
||||
assert_eq!(tree.last().unwrap(), &expected_root);
|
||||
}
|
||||
@ -213,44 +205,36 @@ mod tests {
|
||||
#[test]
|
||||
fn test_generate_tree_with_padding_hashing() {
|
||||
let max_index = 2u32;
|
||||
let size_hint = 420;
|
||||
|
||||
let raw_data = sp_std::vec![
|
||||
(0, sp_std::vec![1; size_hint]),
|
||||
(1, sp_std::vec![2; size_hint]),
|
||||
(2, sp_std::vec![3; size_hint]),
|
||||
(0, sp_std::vec![1]),
|
||||
(1, sp_std::vec![2]),
|
||||
(2, sp_std::vec![3]),
|
||||
];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let mut empty_data = sp_std::vec![LEAF_PREFIX];
|
||||
empty_data.extend_from_slice(&<$hasher_type>::empty().to_fixed_bytes());
|
||||
let empty_hash = <$hasher_type>::hash(&empty_data);
|
||||
empty_data.extend_from_slice(&H256::zero().to_fixed_bytes());
|
||||
let empty_hash = TestBlake2Hasher::hash(&empty_data);
|
||||
|
||||
assert_eq!(tree.len(), 7);
|
||||
assert_eq!(tree[3], empty_hash);
|
||||
|
||||
let mut leaf2_data = sp_std::vec![LEAF_PREFIX];
|
||||
leaf2_data.extend_from_slice(&sp_std::vec![3; size_hint]);
|
||||
let h2 = <$hasher_type>::hash(&leaf2_data);
|
||||
leaf2_data.extend_from_slice(&[3]);
|
||||
let h2 = TestBlake2Hasher::hash(&leaf2_data);
|
||||
|
||||
let mut combined_right = [0u8; 65];
|
||||
combined_right[0] = NODE_PREFIX;
|
||||
combined_right[1..33].copy_from_slice(h2.as_ref());
|
||||
combined_right[33..].copy_from_slice(empty_hash.as_ref());
|
||||
|
||||
let expected_parent_right = <$hasher_type>::hash(&combined_right);
|
||||
let expected_parent_right = TestBlake2Hasher::hash(&combined_right);
|
||||
assert_eq!(tree[5], expected_parent_right);
|
||||
}
|
||||
|
||||
@ -262,43 +246,20 @@ mod tests {
|
||||
let data_2 = sp_std::vec![(0, sp_std::vec![100]), (1, sp_std::vec![200])];
|
||||
let data_3 = sp_std::vec![(0, sp_std::vec![101]), (1, sp_std::vec![200])];
|
||||
|
||||
let tree_1 = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
max_index,
|
||||
1,
|
||||
data_1,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
)
|
||||
.ok()
|
||||
let tree_1 =
|
||||
generate_tree::<TestBlake2Hasher, u32, _, _, ()>(max_index, data_1, |(i, b)| {
|
||||
Ok((i, b))
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let tree_2 = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
max_index,
|
||||
1,
|
||||
data_2,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
)
|
||||
.ok()
|
||||
let tree_2 =
|
||||
generate_tree::<TestBlake2Hasher, u32, _, _, ()>(max_index, data_2, |(i, b)| {
|
||||
Ok((i, b))
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let tree_3 = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
max_index,
|
||||
1,
|
||||
data_3,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
)
|
||||
.ok()
|
||||
let tree_3 =
|
||||
generate_tree::<TestBlake2Hasher, u32, _, _, ()>(max_index, data_3, |(i, b)| {
|
||||
Ok((i, b))
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(tree_1.last().unwrap(), tree_2.last().unwrap());
|
||||
@ -308,132 +269,96 @@ mod tests {
|
||||
#[test]
|
||||
fn test_generate_tree_single_element() {
|
||||
let max_index = 0u32;
|
||||
let size_hint = 1337;
|
||||
let raw_data = sp_std::vec![(0, sp_std::vec![42; size_hint])];
|
||||
let raw_data = sp_std::vec![(0, sp_std::vec![42])];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let expected_leaf_data = [
|
||||
&[LEAF_PREFIX][..],
|
||||
sp_std::vec![42; size_hint].as_slice()
|
||||
].concat();
|
||||
let expected_hash = <$hasher_type>::hash(&expected_leaf_data);
|
||||
|
||||
assert_eq!(tree.len(), 1);
|
||||
assert_eq!(tree[0], expected_hash);
|
||||
assert_eq!(tree[0], TestBlake2Hasher::hash(&vec![LEAF_PREFIX, 42]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proof_and_verification_end_to_end() {
|
||||
let max_index = 3u32;
|
||||
let size_hint = 420;
|
||||
|
||||
let raw_data = sp_std::vec![
|
||||
(0, sp_std::vec![1; size_hint]),
|
||||
(1, sp_std::vec![2; size_hint]),
|
||||
(2, sp_std::vec![3; size_hint]),
|
||||
(3, sp_std::vec![4; size_hint]),
|
||||
(0, sp_std::vec![1]),
|
||||
(1, sp_std::vec![2]),
|
||||
(2, sp_std::vec![3]),
|
||||
(3, sp_std::vec![4]),
|
||||
];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let root = *tree.last().unwrap();
|
||||
|
||||
let target_index = 2u32;
|
||||
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, target_index)
|
||||
.ok()
|
||||
.unwrap();
|
||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, target_index);
|
||||
|
||||
assert_eq!(proof.len(), 2);
|
||||
|
||||
let preimage = sp_std::vec![3; size_hint];
|
||||
assert!(verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||
let preimage = sp_std::vec![3];
|
||||
let is_valid =
|
||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index);
|
||||
|
||||
assert!(is_valid);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proof_index_out_of_bounds() {
|
||||
let max_index = 3u32;
|
||||
let size_hint = 420;
|
||||
|
||||
let raw_data = sp_std::vec![
|
||||
(0, sp_std::vec![1; size_hint]),
|
||||
(1, sp_std::vec![2; size_hint]),
|
||||
(2, sp_std::vec![3; size_hint]),
|
||||
(3, sp_std::vec![4; size_hint]),
|
||||
(0, sp_std::vec![1]),
|
||||
(1, sp_std::vec![2]),
|
||||
(2, sp_std::vec![3]),
|
||||
(3, sp_std::vec![4]),
|
||||
];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let root = *tree.last().unwrap();
|
||||
|
||||
let target_index = 2u32;
|
||||
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, target_index)
|
||||
.ok()
|
||||
.unwrap();
|
||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, target_index);
|
||||
|
||||
assert_eq!(proof.len(), 2);
|
||||
|
||||
let preimage = sp_std::vec![3; size_hint];
|
||||
assert!(verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||
assert!(!verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, 4));
|
||||
let preimage = sp_std::vec![3];
|
||||
let is_valid =
|
||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index + 1);
|
||||
|
||||
assert!(!is_valid);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proof_contains_correct_siblings() {
|
||||
let max_index = 3u32;
|
||||
let size_hint = 1337;
|
||||
|
||||
let raw_data = sp_std::vec![
|
||||
(0, sp_std::vec![10; size_hint]),
|
||||
(1, sp_std::vec![20; size_hint]),
|
||||
(2, sp_std::vec![30; size_hint]),
|
||||
(3, sp_std::vec![40; size_hint]),
|
||||
(0, sp_std::vec![10]),
|
||||
(1, sp_std::vec![20]),
|
||||
(2, sp_std::vec![30]),
|
||||
(3, sp_std::vec![40]),
|
||||
];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let h0 = tree[0];
|
||||
@ -444,31 +369,19 @@ mod tests {
|
||||
let parent_left = tree[4]; // hash(h0 + h1)
|
||||
let parent_right = tree[5]; // hash(h2 + h3)
|
||||
|
||||
let proof_for_0 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 0)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let proof_for_0 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 0);
|
||||
assert_eq!(proof_for_0[0], h1);
|
||||
assert_eq!(proof_for_0[1], parent_right);
|
||||
|
||||
let proof_for_1 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 1)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let proof_for_1 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 1);
|
||||
assert_eq!(proof_for_1[0], h0);
|
||||
assert_eq!(proof_for_1[1], parent_right);
|
||||
|
||||
let proof_for_2 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 2)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let proof_for_2 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 2);
|
||||
assert_eq!(proof_for_2[0], h3);
|
||||
assert_eq!(proof_for_2[1], parent_left);
|
||||
|
||||
let proof_for_3 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 3)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let proof_for_3 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 3);
|
||||
assert_eq!(proof_for_3[0], h2);
|
||||
assert_eq!(proof_for_3[1], parent_left);
|
||||
}
|
||||
@ -476,38 +389,30 @@ mod tests {
|
||||
#[test]
|
||||
fn test_proof_for_padded_tree_leaf() {
|
||||
let max_index = 2u32;
|
||||
let size_hint = 69;
|
||||
|
||||
let raw_data = sp_std::vec![
|
||||
(0, sp_std::vec![1; size_hint]),
|
||||
(1, sp_std::vec![2; size_hint]),
|
||||
(2, sp_std::vec![3; size_hint]),
|
||||
(0, sp_std::vec![1]),
|
||||
(1, sp_std::vec![2]),
|
||||
(2, sp_std::vec![3]),
|
||||
];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 2)
|
||||
.ok()
|
||||
.unwrap();
|
||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 2);
|
||||
|
||||
let mut empty_data = sp_std::vec![LEAF_PREFIX];
|
||||
empty_data.extend_from_slice(&<$hasher_type>::empty().to_fixed_bytes());
|
||||
let empty_hash = <$hasher_type>::hash(&empty_data);
|
||||
empty_data.extend_from_slice(&H256::zero().to_fixed_bytes());
|
||||
let empty_hash = TestBlake2Hasher::hash(&empty_data);
|
||||
assert_eq!(proof[0], empty_hash);
|
||||
|
||||
let root = *tree.last().unwrap();
|
||||
assert!(verify_tree_proof::<$hasher_type, u32>(&sp_std::vec![3; size_hint], &proof, root, 2));
|
||||
let is_valid =
|
||||
verify_tree_proof::<TestBlake2Hasher, u32>(&sp_std::vec![3], &proof, root, 2);
|
||||
assert!(is_valid);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -515,39 +420,24 @@ mod tests {
|
||||
let max_index = 0u32;
|
||||
let raw_data = sp_std::vec![(0, sp_std::vec![99])];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
1,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let proof = generate_proof::<$hasher_type, u32, ()>(
|
||||
&tree,
|
||||
max_index,
|
||||
0
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 0);
|
||||
assert!(proof.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_tree_proof_with_h0_h3_and_random_values() {
|
||||
let max_index = 3u32;
|
||||
let size_hint = 69;
|
||||
|
||||
let leaf_0 = sp_std::vec![10u8; 69];
|
||||
let leaf_1 = sp_std::vec![20u8; 69];
|
||||
let leaf_2 = sp_std::vec![30u8; 69];
|
||||
let leaf_3 = sp_std::vec![40u8; 69];
|
||||
let leaf_0 = sp_std::vec![10u8];
|
||||
let leaf_1 = sp_std::vec![20u8];
|
||||
let leaf_2 = sp_std::vec![30u8];
|
||||
let leaf_3 = sp_std::vec![40u8];
|
||||
|
||||
let raw_data = sp_std::vec![
|
||||
(0, leaf_0.clone()),
|
||||
@ -556,17 +446,11 @@ mod tests {
|
||||
(3, leaf_3.clone())
|
||||
];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let root = *tree.last().unwrap();
|
||||
@ -576,35 +460,45 @@ mod tests {
|
||||
let h2 = tree[2];
|
||||
let h3 = tree[3];
|
||||
|
||||
let proof_for_1 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 1).ok().unwrap();
|
||||
let proof_for_1 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 1);
|
||||
assert_eq!(proof_for_1[0], h0);
|
||||
|
||||
let is_valid_1 = verify_tree_proof::<$hasher_type, u32>(&leaf_1, &proof_for_1, root, 1);
|
||||
let is_valid_1 = verify_tree_proof::<TestBlake2Hasher, u32>(&leaf_1, &proof_for_1, root, 1);
|
||||
assert!(is_valid_1);
|
||||
|
||||
let proof_for_2 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 2).ok().unwrap();
|
||||
let proof_for_2 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 2);
|
||||
assert_eq!(proof_for_2[0], h3);
|
||||
|
||||
let is_valid_2 = verify_tree_proof::<$hasher_type, u32>(&leaf_2, &proof_for_2, root, 2);
|
||||
let is_valid_2 = verify_tree_proof::<TestBlake2Hasher, u32>(&leaf_2, &proof_for_2, root, 2);
|
||||
assert!(is_valid_2);
|
||||
|
||||
let proof_for_0 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 0).ok().unwrap();
|
||||
let proof_for_0 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 0);
|
||||
assert_eq!(proof_for_0[0], h1);
|
||||
assert!(verify_tree_proof::<$hasher_type, u32>(&leaf_0, &proof_for_0, root, 0));
|
||||
assert!(verify_tree_proof::<TestBlake2Hasher, u32>(
|
||||
&leaf_0,
|
||||
&proof_for_0,
|
||||
root,
|
||||
0
|
||||
));
|
||||
|
||||
let proof_for_3 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 3).ok().unwrap();
|
||||
let proof_for_3 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 3);
|
||||
assert_eq!(proof_for_3[0], h2);
|
||||
assert!(verify_tree_proof::<$hasher_type, u32>(&leaf_3, &proof_for_3, root, 3));
|
||||
assert!(verify_tree_proof::<TestBlake2Hasher, u32>(
|
||||
&leaf_3,
|
||||
&proof_for_3,
|
||||
root,
|
||||
3
|
||||
));
|
||||
|
||||
let mut bad_proof = proof_for_1.clone();
|
||||
bad_proof[0] = <$hasher_type>::empty();
|
||||
bad_proof[0] = H256::random();
|
||||
let is_valid_bad_proof =
|
||||
verify_tree_proof::<$hasher_type, u32>(&leaf_1, &bad_proof, root, 1);
|
||||
verify_tree_proof::<TestBlake2Hasher, u32>(&leaf_1, &bad_proof, root, 1);
|
||||
assert!(!is_valid_bad_proof);
|
||||
|
||||
let bad_preimage = vec![99u8];
|
||||
let is_valid_bad_preimage =
|
||||
verify_tree_proof::<$hasher_type, u32>(&bad_preimage, &proof_for_1, root, 1);
|
||||
verify_tree_proof::<TestBlake2Hasher, u32>(&bad_preimage, &proof_for_1, root, 1);
|
||||
assert!(!is_valid_bad_preimage);
|
||||
}
|
||||
|
||||
@ -617,17 +511,11 @@ mod tests {
|
||||
raw_data.push((i, sp_std::vec![i as u8]));
|
||||
}
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
1,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let root = *tree.last().unwrap();
|
||||
@ -637,55 +525,50 @@ mod tests {
|
||||
let target_index = 11u32;
|
||||
let preimage = vec![target_index as u8];
|
||||
|
||||
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, target_index)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, target_index);
|
||||
assert_eq!(proof.len(), 4);
|
||||
|
||||
let h10 = tree[10];
|
||||
assert_eq!(proof[0], h10);
|
||||
|
||||
assert!(verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||
assert!(!verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, 4));
|
||||
let is_valid =
|
||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index);
|
||||
assert!(is_valid);
|
||||
|
||||
let is_valid_wrong_index =
|
||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, 4);
|
||||
assert!(!is_valid_wrong_index);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verification_index_at_upper_bound() {
|
||||
let max_index = 3u32;
|
||||
let size_hint = 420;
|
||||
|
||||
let raw_data = sp_std::vec![
|
||||
(0, sp_std::vec![1; size_hint]),
|
||||
(1, sp_std::vec![2; size_hint]),
|
||||
(2, sp_std::vec![3; size_hint]),
|
||||
(3, sp_std::vec![4; size_hint]),
|
||||
(0, sp_std::vec![1]),
|
||||
(1, sp_std::vec![2]),
|
||||
(2, sp_std::vec![3]),
|
||||
(3, sp_std::vec![4]),
|
||||
];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
size_hint,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let root = *tree.last().unwrap();
|
||||
|
||||
let target_index = 3u32;
|
||||
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, target_index)
|
||||
.ok()
|
||||
.unwrap();
|
||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, target_index);
|
||||
|
||||
assert_eq!(proof.len(), 2);
|
||||
|
||||
let preimage = sp_std::vec![4; size_hint];
|
||||
assert!(verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||
let preimage = sp_std::vec![4];
|
||||
let is_valid =
|
||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index);
|
||||
|
||||
assert!(is_valid);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -698,32 +581,23 @@ mod tests {
|
||||
(3, sp_std::vec![4]),
|
||||
];
|
||||
|
||||
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
||||
max_index,
|
||||
1,
|
||||
raw_data,
|
||||
|
||||
|(index, bytes), buffer| {
|
||||
buffer.extend_from_slice(&bytes);
|
||||
Ok(index as usize)
|
||||
}
|
||||
|(index, bytes)| Ok((index, bytes)),
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let root = *tree.last().unwrap();
|
||||
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 3u32).ok().unwrap();
|
||||
|
||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 3u32);
|
||||
|
||||
let target_index = 4u32;
|
||||
let preimage = sp_std::vec![4];
|
||||
|
||||
assert!(!verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let is_valid =
|
||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index);
|
||||
|
||||
run_merkle_tree_tests!(SubstrateBlake2Hasher, blake2_merkle_tree_tests);
|
||||
run_merkle_tree_tests!(SubstrateKeccakHasher, keccak_merkle_tree_tests);
|
||||
run_merkle_tree_tests!(UtxoSha2Hasher, sha2_merkle_tree_tests);
|
||||
assert!(!is_valid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,6 @@ use sp_std::vec::Vec;
|
||||
|
||||
const MAX_INPUTS: usize = 3;
|
||||
const MAX_OUTPUTS: usize = 4;
|
||||
const MAX_FLAGS_LEN: usize = 8;
|
||||
const MAX_HASHES_LEN: usize = 16;
|
||||
const MAX_SCRIPT_LEN: usize = 512;
|
||||
pub const MAX_TX_LEN: usize = 4096;
|
||||
|
||||
@ -29,17 +27,20 @@ pub struct Transaction<H: GhostHasher> {
|
||||
lock_time: u32,
|
||||
}
|
||||
|
||||
pub struct Header<H: GhostHasher>(sp_std::marker::PhantomData<H>);
|
||||
pub struct Header<H: GhostHasher> {
|
||||
pub merkle_root: H::Hash,
|
||||
pub tx_count: u32,
|
||||
pub tree_hashes: Vec<H::Hash>,
|
||||
pub flags: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<H: GhostHasher> Header<H> {
|
||||
fn calc_tree_width(tx_count: u32, h: u32) -> u32 {
|
||||
(tx_count + (1 << h) - 1) >> h
|
||||
fn calc_tree_width(&self, h: u32) -> u32 {
|
||||
(self.tx_count + (1 << h) - 1) >> h
|
||||
}
|
||||
|
||||
fn traverse(
|
||||
tx_count: u32,
|
||||
flags: &[u8],
|
||||
tree_hashes: &[H::Hash],
|
||||
&self,
|
||||
height: u32,
|
||||
pos: u32,
|
||||
bits_used: &mut u32,
|
||||
@ -50,19 +51,19 @@ impl<H: GhostHasher> Header<H> {
|
||||
let byte_idx = (*bits_used / 8) as usize;
|
||||
let bit_idx = (*bits_used % 8) as u8;
|
||||
|
||||
if byte_idx >= flags.len() {
|
||||
if byte_idx >= self.flags.len() {
|
||||
return Err(ParseError::InvalidVarint(VarintError::BufferTooShort));
|
||||
}
|
||||
|
||||
let parent_of_match = ((flags[byte_idx] >> bit_idx) & 1) == 1;
|
||||
let parent_of_match = ((self.flags[byte_idx] >> bit_idx) & 1) == 1;
|
||||
*bits_used += 1;
|
||||
|
||||
if height == 0 || !parent_of_match {
|
||||
if *hash_used as usize >= tree_hashes.len() {
|
||||
if *hash_used as usize >= self.tree_hashes.len() {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
let curr_hash = tree_hashes[*hash_used as usize];
|
||||
let curr_hash = self.tree_hashes[*hash_used as usize];
|
||||
*hash_used += 1;
|
||||
|
||||
if height == 0 && parent_of_match && curr_hash == target_txid {
|
||||
@ -72,10 +73,7 @@ impl<H: GhostHasher> Header<H> {
|
||||
return Ok(curr_hash);
|
||||
}
|
||||
|
||||
let left = Self::traverse(
|
||||
tx_count,
|
||||
flags,
|
||||
tree_hashes,
|
||||
let left = self.traverse(
|
||||
height - 1,
|
||||
pos * 2,
|
||||
bits_used,
|
||||
@ -84,11 +82,8 @@ impl<H: GhostHasher> Header<H> {
|
||||
target_txid,
|
||||
)?;
|
||||
|
||||
let right = if pos * 2 + 1 < Self::calc_tree_width(tx_count, height - 1) {
|
||||
let right = Self::traverse(
|
||||
tx_count,
|
||||
flags,
|
||||
tree_hashes,
|
||||
let right = if pos * 2 + 1 < self.calc_tree_width(height - 1) {
|
||||
let right = self.traverse(
|
||||
height - 1,
|
||||
pos * 2 + 1,
|
||||
bits_used,
|
||||
@ -114,83 +109,17 @@ impl<H: GhostHasher> Header<H> {
|
||||
Ok(current_node_hash)
|
||||
}
|
||||
|
||||
pub fn verify_utxo_merkle_proof(
|
||||
txproof_bytes: &[u8],
|
||||
target_txid: H::Hash,
|
||||
) -> Result<(), ParseError> {
|
||||
if txproof_bytes.len() < 85 {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
let header_bytes = &txproof_bytes[..80];
|
||||
let mut bytes = &txproof_bytes[80..];
|
||||
|
||||
let mut merkle_root = [0u8; 32];
|
||||
merkle_root.copy_from_slice(&header_bytes[36..68]);
|
||||
|
||||
if bytes.len() < 4 {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
let tx_count = u32::from_le_bytes(
|
||||
bytes[..4]
|
||||
.try_into()
|
||||
.map_err(|_| ParseError::TypeConversionFailed)?,
|
||||
);
|
||||
bytes = &bytes[4..];
|
||||
let hash_count = read_varint(&mut bytes)?;
|
||||
|
||||
if hash_count > MAX_HASHES_LEN {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
let hash_count_bytes = hash_count
|
||||
.checked_mul(32)
|
||||
.ok_or(ParseError::TypeConversionFailed)?;
|
||||
|
||||
if bytes.len() < hash_count_bytes {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
let tree_hashes_bytes = &bytes[..hash_count_bytes];
|
||||
bytes = &bytes[hash_count_bytes..];
|
||||
|
||||
let tree_hashes: Vec<H::Hash> = tree_hashes_bytes
|
||||
.chunks_exact(32)
|
||||
.map(|chunk| H::from_slice(chunk))
|
||||
.collect();
|
||||
|
||||
let flags_count = read_varint(&mut bytes)?;
|
||||
|
||||
if flags_count > MAX_FLAGS_LEN {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
if bytes.len() < flags_count {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
let flags = bytes[..flags_count].to_vec();
|
||||
bytes = &bytes[flags_count..];
|
||||
|
||||
if !bytes.is_empty() {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
pub fn extract_proof(&self, target_txid: H::Hash) -> Result<H::Hash, ParseError> {
|
||||
let mut bits_used = 0u32;
|
||||
let mut hash_used = 0u32;
|
||||
|
||||
let mut matched_index = None;
|
||||
let mut max_height = 0;
|
||||
|
||||
while (1 << max_height) < tx_count {
|
||||
while (1 << max_height) < self.tx_count {
|
||||
max_height += 1;
|
||||
}
|
||||
|
||||
let computed_root = Self::traverse(
|
||||
tx_count,
|
||||
&flags,
|
||||
&tree_hashes,
|
||||
let computed_root = self.traverse(
|
||||
max_height,
|
||||
0,
|
||||
&mut bits_used,
|
||||
@ -199,23 +128,19 @@ impl<H: GhostHasher> Header<H> {
|
||||
target_txid,
|
||||
)?;
|
||||
|
||||
if hash_used as usize != tree_hashes.len() {
|
||||
if hash_used as usize != self.tree_hashes.len() {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
if (bits_used + 7) / 8 != flags.len() as u32 {
|
||||
if (bits_used + 7) / 8 != self.flags.len() as u32 {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
if matched_index.is_none() {
|
||||
return Err(ParseError::TransactionNotFoundInProof);
|
||||
if matched_index.is_some() {
|
||||
Ok(computed_root)
|
||||
} else {
|
||||
Err(ParseError::TransactionNotFoundInProof)
|
||||
}
|
||||
|
||||
if computed_root != H::from_slice(&merkle_root) {
|
||||
return Err(ParseError::InvalidMerkleRoot);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -432,9 +357,6 @@ fn read_varint(bytes: &mut &[u8]) -> Result<usize, VarintError> {
|
||||
.try_into()
|
||||
.map_err(|_| VarintError::TypeConversionFailed)?,
|
||||
);
|
||||
if val < 0xfd {
|
||||
return Err(VarintError::TypeConversionFailed);
|
||||
}
|
||||
*bytes = &bytes[2..];
|
||||
Ok(val as usize)
|
||||
}
|
||||
@ -447,9 +369,6 @@ fn read_varint(bytes: &mut &[u8]) -> Result<usize, VarintError> {
|
||||
.try_into()
|
||||
.map_err(|_| VarintError::TypeConversionFailed)?,
|
||||
);
|
||||
if val < 0x10000 {
|
||||
return Err(VarintError::TypeConversionFailed);
|
||||
}
|
||||
*bytes = &bytes[4..];
|
||||
Ok(val as usize)
|
||||
}
|
||||
@ -462,9 +381,6 @@ fn read_varint(bytes: &mut &[u8]) -> Result<usize, VarintError> {
|
||||
.try_into()
|
||||
.map_err(|_| VarintError::TypeConversionFailed)?,
|
||||
);
|
||||
if val < 0x100000000 {
|
||||
return Err(VarintError::TypeConversionFailed);
|
||||
}
|
||||
*bytes = &bytes[8..];
|
||||
Ok(val as usize)
|
||||
}
|
||||
@ -476,7 +392,6 @@ fn read_varint(bytes: &mut &[u8]) -> Result<usize, VarintError> {
|
||||
pub enum ParseError {
|
||||
InvalidLength,
|
||||
ExceededMaxLimits,
|
||||
InvalidMerkleRoot,
|
||||
TypeConversionFailed,
|
||||
TransactionNotFoundInProof,
|
||||
InvalidVarint(VarintError),
|
||||
@ -610,3 +525,60 @@ impl<'a, H: GhostHasher> TryFrom<&'a [u8]> for Transaction<H> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, H: GhostHasher> TryFrom<&'a [u8]> for Header<H> {
|
||||
type Error = ParseError;
|
||||
|
||||
fn try_from(mut bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
if bytes.len() < 85 {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
let header_bytes = &bytes[..80];
|
||||
bytes = &bytes[80..];
|
||||
|
||||
let mut merkle_root = [0u8; 32];
|
||||
merkle_root.copy_from_slice(&header_bytes[36..68]);
|
||||
|
||||
if bytes.len() < 4 {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
let tx_count = u32::from_le_bytes(
|
||||
bytes[..4]
|
||||
.try_into()
|
||||
.map_err(|_| ParseError::TypeConversionFailed)?,
|
||||
);
|
||||
bytes = &bytes[4..];
|
||||
|
||||
let hash_count = read_varint(&mut bytes)?;
|
||||
if bytes.len() < hash_count * 32 {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
let tree_hashes_bytes = &bytes[..hash_count * 32];
|
||||
bytes = &bytes[hash_count * 32..];
|
||||
|
||||
let tree_hashes: Vec<H::Hash> = tree_hashes_bytes
|
||||
.chunks_exact(32)
|
||||
.map(|chunk| H::from_slice(chunk))
|
||||
.collect();
|
||||
|
||||
let flags_count = read_varint(&mut bytes)?;
|
||||
if bytes.len() < flags_count {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
let flags = bytes[..flags_count].to_vec();
|
||||
bytes = &bytes[flags_count..];
|
||||
|
||||
if !bytes.is_empty() {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
merkle_root: H::from_slice(&merkle_root),
|
||||
tx_count,
|
||||
tree_hashes,
|
||||
flags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-networks"
|
||||
version = "0.2.12"
|
||||
version = "0.2.10"
|
||||
description = "Registry and lifecycle management for external network metadata and cryptographic profiles."
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@ -197,21 +197,17 @@ pub mod module {
|
||||
StorageValue<_, BoundedVec<T::NetworkId, T::MaxNetworks>, ValueQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn network_types)]
|
||||
pub type NetworkTypes<T: Config> = StorageMap<
|
||||
#[pallet::getter(fn network_curves)]
|
||||
pub type NetworkCurves<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat, NetworkCurve,
|
||||
BoundedBTreeMap<
|
||||
NetworkType,
|
||||
BoundedVec<T::NetworkId, T::MaxNetworks>,
|
||||
T::MaxNetworks,
|
||||
>,
|
||||
BoundedBTreeMap<NetworkType, u32, T::MaxNetworks>,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn network_curves)]
|
||||
pub type NetworkCurves<T: Config> =
|
||||
#[pallet::getter(fn network_curves_vec)]
|
||||
pub type NetworkCurvesVec<T: Config> =
|
||||
StorageValue<_, BoundedVec<NetworkCurve, T::MaxNetworks>, ValueQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
@ -433,26 +429,24 @@ impl<T: Config> Pallet<T> {
|
||||
modified_indexes.try_push(chain_id.clone())
|
||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
|
||||
let mut modified_types = NetworkTypes::<T>::get(network_curve);
|
||||
if let Some(chain_ids) = modified_types.get_mut(&network_type) {
|
||||
chain_ids.try_push(chain_id).map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
let mut modified_curves_map = NetworkCurves::<T>::get(network_curve);
|
||||
if let Some(counter) = modified_curves_map.get_mut(&network_type) {
|
||||
*counter = counter.saturating_add(1);
|
||||
} else {
|
||||
let mut new_ids_vec = BoundedVec::<T::NetworkId, T::MaxNetworks>::default();
|
||||
new_ids_vec.try_push(chain_id).map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
modified_types.try_insert(network_type, new_ids_vec)
|
||||
modified_curves_map.try_insert(network_type, 1u32)
|
||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
}
|
||||
|
||||
let mut modified_curves = NetworkCurves::<T>::get();
|
||||
if !modified_curves.contains(&network_curve) {
|
||||
modified_curves.try_push(network_curve)
|
||||
let mut modified_curves_vec = NetworkCurvesVec::<T>::get();
|
||||
if !modified_curves_vec.contains(&network_curve) {
|
||||
modified_curves_vec.try_push(network_curve)
|
||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
}
|
||||
|
||||
Networks::<T>::insert(&chain_id, network);
|
||||
NetworkIndexes::<T>::put(modified_indexes);
|
||||
NetworkTypes::<T>::insert(network_curve, modified_types);
|
||||
NetworkCurves::<T>::put(modified_curves);
|
||||
NetworkCurves::<T>::insert(network_curve, modified_curves_map);
|
||||
NetworkCurvesVec::<T>::put(modified_curves_vec);
|
||||
|
||||
Self::deposit_event(Event::<T>::NetworkRegistered { chain_id });
|
||||
Ok(())
|
||||
@ -466,38 +460,38 @@ impl<T: Config> Pallet<T> {
|
||||
let network_curve = network.curve;
|
||||
let network_type = network.r#type;
|
||||
|
||||
let mut modified_types = NetworkTypes::<T>::get(network_curve);
|
||||
let mut modified_curves_map = NetworkCurves::<T>::get(network_curve);
|
||||
|
||||
let chain_ids = modified_types
|
||||
let counter = modified_curves_map
|
||||
.get_mut(&network_type)
|
||||
.ok_or(Error::<T>::NetworkTypeDoesNotExist)?;
|
||||
|
||||
chain_ids.retain(|id| id != &chain_id);
|
||||
*counter = counter.saturating_sub(1);
|
||||
|
||||
let mut should_remove_curve = false;
|
||||
if chain_ids.is_empty() {
|
||||
modified_types.remove(&network_type);
|
||||
if modified_types.is_empty() {
|
||||
should_remove_curve = true;
|
||||
let mut should_remove_curve_from_vec = false;
|
||||
if *counter == 0 {
|
||||
modified_curves_map.remove(&network_type);
|
||||
if modified_curves_map.is_empty() {
|
||||
should_remove_curve_from_vec = true;
|
||||
}
|
||||
}
|
||||
|
||||
let mut modified_indexes = NetworkIndexes::<T>::get();
|
||||
modified_indexes.retain(|id| id != &chain_id);
|
||||
|
||||
let mut modified_curves = NetworkCurves::<T>::get();
|
||||
if should_remove_curve {
|
||||
modified_curves.retain(|curve| curve != &network_curve);
|
||||
let mut modified_curves_vec = NetworkCurvesVec::<T>::get();
|
||||
if should_remove_curve_from_vec {
|
||||
modified_curves_vec.retain(|curve| curve != &network_curve);
|
||||
}
|
||||
|
||||
Networks::<T>::remove(&chain_id);
|
||||
NetworkIndexes::<T>::put(modified_indexes);
|
||||
NetworkCurves::<T>::put(modified_curves);
|
||||
NetworkCurvesVec::<T>::put(modified_curves_vec);
|
||||
|
||||
if modified_types.is_empty() {
|
||||
NetworkTypes::<T>::remove(network_curve);
|
||||
if modified_curves_map.is_empty() {
|
||||
NetworkCurves::<T>::remove(network_curve);
|
||||
} else {
|
||||
NetworkTypes::<T>::insert(network_curve, modified_types);
|
||||
NetworkCurves::<T>::insert(network_curve, modified_curves_map);
|
||||
}
|
||||
|
||||
Self::deposit_event(Event::<T>::NetworkRemoved { chain_id });
|
||||
@ -631,46 +625,15 @@ impl<T: Config> Pallet<T> {
|
||||
chain_id: T::NetworkId,
|
||||
network_type: NetworkType,
|
||||
) -> DispatchResult {
|
||||
let mut network = Networks::<T>::get(&chain_id)
|
||||
.ok_or(Error::<T>::NetworkDoesNotExist)?;
|
||||
|
||||
let network_curve = network.curve;
|
||||
let prev_type = network.r#type;
|
||||
|
||||
if prev_type == network_type {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut modified_types = NetworkTypes::<T>::get(network_curve);
|
||||
let prev_chain_ids = modified_types
|
||||
.get_mut(&prev_type)
|
||||
.ok_or(Error::<T>::NetworkTypeDoesNotExist)?;
|
||||
|
||||
prev_chain_ids.retain(|id| id != &chain_id);
|
||||
|
||||
if prev_chain_ids.is_empty() {
|
||||
modified_types.remove(&prev_type);
|
||||
}
|
||||
|
||||
if let Some(chain_ids) = modified_types.get_mut(&network_type) {
|
||||
chain_ids.try_push(chain_id).map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
} else {
|
||||
let mut new_ids_vec = BoundedVec::<T::NetworkId, T::MaxNetworks>::default();
|
||||
new_ids_vec.try_push(chain_id).map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
modified_types.try_insert(network_type, new_ids_vec)
|
||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
}
|
||||
|
||||
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
||||
let network = maybe_network.as_mut().ok_or(Error::<T>::NetworkDoesNotExist)?;
|
||||
network.r#type = network_type;
|
||||
|
||||
Networks::<T>::insert(&chain_id, network);
|
||||
NetworkTypes::<T>::insert(network_curve, modified_types);
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
Self::deposit_event(Event::<T>::NetworkTypeUpdated {
|
||||
chain_id,
|
||||
network_type,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -689,53 +652,50 @@ impl<T: Config> Pallet<T> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut modified_prev_types = NetworkTypes::<T>::get(prev_curve);
|
||||
let prev_chain_ids = modified_prev_types
|
||||
let mut modified_prev_map = NetworkCurves::<T>::get(prev_curve);
|
||||
let counter = modified_prev_map
|
||||
.get_mut(&network_type)
|
||||
.ok_or(Error::<T>::NetworkTypeDoesNotExist)?;
|
||||
|
||||
prev_chain_ids.retain(|id| id != &chain_id);
|
||||
*counter = counter.saturating_sub(1);
|
||||
|
||||
let mut should_remove_prev_curve = false;
|
||||
if prev_chain_ids.is_empty() {
|
||||
modified_prev_types.remove(&network_type);
|
||||
if modified_prev_types.is_empty() {
|
||||
should_remove_prev_curve = true;
|
||||
let mut should_remove_prev_from_vec = false;
|
||||
if *counter == 0 {
|
||||
modified_prev_map.remove(&network_type);
|
||||
if modified_prev_map.is_empty() {
|
||||
should_remove_prev_from_vec = true;
|
||||
}
|
||||
}
|
||||
|
||||
let mut modified_curr_types = NetworkTypes::<T>::get(network_curve);
|
||||
if let Some(chain_ids) = modified_curr_types.get_mut(&network_type) {
|
||||
chain_ids.try_push(chain_id)
|
||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
let mut modified_curr_map = NetworkCurves::<T>::get(network_curve);
|
||||
if let Some(counter) = modified_curr_map.get_mut(&network_type) {
|
||||
*counter = counter.saturating_add(1);
|
||||
} else {
|
||||
let mut new_ids_vec = BoundedVec::<T::NetworkId, T::MaxNetworks>::default();
|
||||
new_ids_vec.try_push(chain_id).map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
modified_curr_types.try_insert(network_type, new_ids_vec)
|
||||
modified_curr_map.try_insert(network_type, 1u32)
|
||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
}
|
||||
|
||||
let mut modified_curves = NetworkCurves::<T>::get();
|
||||
let mut modified_curves_vec = NetworkCurvesVec::<T>::get();
|
||||
|
||||
if should_remove_prev_curve {
|
||||
modified_curves.retain(|curve| curve != &prev_curve);
|
||||
if should_remove_prev_from_vec {
|
||||
modified_curves_vec.retain(|curve| curve != &prev_curve);
|
||||
}
|
||||
|
||||
if !modified_curves.contains(&network_curve) {
|
||||
modified_curves.try_push(network_curve)
|
||||
if !modified_curves_vec.contains(&network_curve) {
|
||||
modified_curves_vec.try_push(network_curve)
|
||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||
}
|
||||
|
||||
network.curve = network_curve;
|
||||
|
||||
Networks::<T>::insert(&chain_id, network);
|
||||
NetworkTypes::<T>::insert(network_curve, modified_curr_types);
|
||||
NetworkCurves::<T>::put(modified_curves);
|
||||
NetworkCurves::<T>::insert(network_curve, modified_curr_map);
|
||||
NetworkCurvesVec::<T>::put(modified_curves_vec);
|
||||
|
||||
if modified_prev_types.is_empty() {
|
||||
NetworkTypes::<T>::remove(prev_curve);
|
||||
if modified_prev_map.is_empty() {
|
||||
NetworkCurves::<T>::remove(prev_curve);
|
||||
} else {
|
||||
NetworkTypes::<T>::insert(prev_curve, modified_prev_types);
|
||||
NetworkCurves::<T>::insert(prev_curve, modified_prev_map);
|
||||
}
|
||||
|
||||
Self::deposit_event(Event::<T>::NetworkCurveUpdated {
|
||||
@ -801,12 +761,9 @@ impl<T: Config> NetworkDataBasicHandler for Pallet<T> {
|
||||
type NetworkId = T::NetworkId;
|
||||
type NetworkType = NetworkType;
|
||||
type NetworkCurve = NetworkCurve;
|
||||
type MaxNetworks = T::MaxNetworks;
|
||||
}
|
||||
|
||||
impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
||||
type TypesItem = BoundedVec<T::NetworkId, T::MaxNetworks>;
|
||||
|
||||
fn count() -> u32 {
|
||||
NetworkIndexes::<T>::decode_len()
|
||||
.map(|len| len as u32)
|
||||
@ -818,7 +775,7 @@ impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
||||
}
|
||||
|
||||
fn curve_exists(curve: &Self::NetworkCurve) -> bool {
|
||||
NetworkTypes::<T>::contains_key(curve)
|
||||
NetworkCurves::<T>::contains_key(curve)
|
||||
}
|
||||
|
||||
fn get(n: &Self::NetworkId) -> Option<NetworkData> {
|
||||
@ -847,17 +804,15 @@ impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
||||
}
|
||||
|
||||
fn iter_curves() -> impl Iterator<Item = Self::NetworkCurve> {
|
||||
NetworkCurves::<T>::get().into_iter()
|
||||
NetworkCurvesVec::<T>::get().into_iter()
|
||||
}
|
||||
|
||||
fn iter_types_by_curve(
|
||||
curve: &Self::NetworkCurve
|
||||
) -> impl Iterator<Item = (Self::NetworkType, Self::TypesItem)> {
|
||||
let network_types = NetworkTypes::<T>::get(curve);
|
||||
|
||||
network_types.into_iter().map(|(network_type, network_ids)| {
|
||||
(network_type, network_ids)
|
||||
})
|
||||
) -> impl Iterator<Item = Self::NetworkType> {
|
||||
NetworkCurves::<T>::get(curve)
|
||||
.into_iter()
|
||||
.map(|(network_type, _)| network_type)
|
||||
}
|
||||
}
|
||||
|
||||
@ -878,25 +833,23 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
|
||||
.map(|network| network.incoming_share)
|
||||
.ok_or(())?;
|
||||
|
||||
let increased_gatekeeper_amount = GatekeeperAmounts::<T>::get(network_id)
|
||||
.checked_add(&amount)
|
||||
.ok_or(())?;
|
||||
GatekeeperAmounts::<T>::try_mutate(network_id, |gatekeeper_amount| -> Result<(), ()> {
|
||||
*gatekeeper_amount = gatekeeper_amount.checked_add(&amount).ok_or(())?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let curve_share = Perbill::from_parts(incoming_share).mul_ceil(amount);
|
||||
let final_amount = amount.saturating_sub(curve_share);
|
||||
|
||||
let mut imbalance_state = NetworkImbalance::<T>::get();
|
||||
|
||||
NetworkImbalance::<T>::try_mutate(|imbalance_state| -> Result<(), ()> {
|
||||
imbalance_state.incoming = imbalance_state.incoming
|
||||
.checked_add(&final_amount)
|
||||
.ok_or(())?;
|
||||
|
||||
imbalance_state.curve_share = imbalance_state.curve_share
|
||||
.checked_add(&curve_share)
|
||||
.ok_or(())?;
|
||||
|
||||
GatekeeperAmounts::<T>::insert(network_id, increased_gatekeeper_amount);
|
||||
NetworkImbalance::<T>::put(imbalance_state);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(final_amount)
|
||||
}
|
||||
@ -909,25 +862,23 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
|
||||
.map(|network| network.outgoing_share)
|
||||
.ok_or(())?;
|
||||
|
||||
let decreased_gatekeeper_amount = GatekeeperAmounts::<T>::get(network_id)
|
||||
.checked_sub(&amount)
|
||||
.ok_or(())?;
|
||||
GatekeeperAmounts::<T>::try_mutate(network_id, |gatekeeper_amount| -> Result<(), ()> {
|
||||
*gatekeeper_amount = gatekeeper_amount.checked_sub(&amount).ok_or(())?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let curve_share = Perbill::from_parts(outgoing_share).mul_ceil(amount);
|
||||
let final_amount = amount.saturating_sub(curve_share);
|
||||
|
||||
let mut imbalance_state = NetworkImbalance::<T>::get();
|
||||
|
||||
NetworkImbalance::<T>::try_mutate(|imbalance_state| -> Result<(), ()> {
|
||||
imbalance_state.outgoing = imbalance_state.outgoing
|
||||
.checked_add(&final_amount)
|
||||
.ok_or(())?;
|
||||
|
||||
imbalance_state.curve_share = imbalance_state.curve_share
|
||||
.checked_add(&curve_share)
|
||||
.ok_or(())?;
|
||||
|
||||
GatekeeperAmounts::<T>::insert(network_id, decreased_gatekeeper_amount);
|
||||
NetworkImbalance::<T>::put(imbalance_state);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(final_amount)
|
||||
}
|
||||
|
||||
@ -45,8 +45,8 @@ fn register_and_check_network(chain_id: u32, network: NetworkData) {
|
||||
));
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network));
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
||||
assert!(NetworkTypes::<Test>::contains_key(&network_curve));
|
||||
assert!(NetworkCurves::<Test>::get().contains(&network_curve));
|
||||
assert!(NetworkCurves::<Test>::contains_key(&network_curve));
|
||||
assert!(NetworkCurvesVec::<Test>::get().contains(&network_curve));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -55,8 +55,8 @@ fn could_add_network_from_authority() {
|
||||
let (chain_id, network) = prepare_network_data(None, None);
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
||||
|
||||
assert_ok!(GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||
@ -68,8 +68,8 @@ fn could_add_network_from_authority() {
|
||||
));
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network));
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
||||
assert!(NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||
assert!(NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
||||
});
|
||||
}
|
||||
|
||||
@ -79,8 +79,8 @@ fn could_not_add_network_from_random_account() {
|
||||
let (chain_id, network) = prepare_network_data(None, None);
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
||||
|
||||
assert_err!(
|
||||
GhostNetworks::register_network(
|
||||
@ -108,8 +108,8 @@ fn could_not_add_network_from_random_account() {
|
||||
);
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
||||
});
|
||||
}
|
||||
|
||||
@ -351,10 +351,10 @@ fn could_update_network_curve_from_authority_account() {
|
||||
let (chain_id, network) = prepare_network_data(None, None);
|
||||
register_and_check_network(chain_id, network.clone());
|
||||
|
||||
assert!(!NetworkTypes::<Test>::contains_key(&new_curve));
|
||||
assert!(NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::get().contains(&new_curve));
|
||||
assert!(NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::contains_key(&new_curve));
|
||||
assert!(NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&new_curve));
|
||||
assert!(NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
||||
|
||||
assert_ok!(GhostNetworks::update_network_curve(
|
||||
RuntimeOrigin::signed(UpdaterAccount::get()),
|
||||
@ -370,10 +370,10 @@ fn could_update_network_curve_from_authority_account() {
|
||||
let mut final_network = network.clone();
|
||||
final_network.r#curve = new_curve;
|
||||
|
||||
assert!(NetworkTypes::<Test>::contains_key(&new_curve));
|
||||
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(NetworkCurves::<Test>::get().contains(&new_curve));
|
||||
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||
assert!(NetworkCurves::<Test>::contains_key(&new_curve));
|
||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(NetworkCurvesVec::<Test>::get().contains(&new_curve));
|
||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
||||
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(final_network.clone()));
|
||||
assert_ne!(network, final_network);
|
||||
@ -1050,8 +1050,8 @@ fn could_remove_network_from_authority_account() {
|
||||
));
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
||||
});
|
||||
}
|
||||
|
||||
@ -1077,8 +1077,8 @@ fn could_not_remove_network_from_random_account() {
|
||||
);
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network));
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
||||
assert!(NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||
assert!(NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
||||
});
|
||||
}
|
||||
|
||||
@ -1093,8 +1093,8 @@ fn could_not_remove_non_existent_network() {
|
||||
);
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -41,7 +41,6 @@ use ghost_networks::{
|
||||
NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler,
|
||||
NetworkType,
|
||||
};
|
||||
use ghost_traits::evictor::StakingEvictor;
|
||||
use ghost_traits::exposure::ExposureListener;
|
||||
|
||||
pub mod migrations;
|
||||
@ -310,7 +309,6 @@ pub mod pallet {
|
||||
>;
|
||||
type DisabledValidators: DisabledValidators;
|
||||
type ExposureListener: ExposureListener<BalanceOf<Self>, Self::AccountId>;
|
||||
type StakingEvictor: StakingEvictor<Self::AccountId>;
|
||||
|
||||
#[pallet::constant]
|
||||
type MaxAuthorities: Get<u32>;
|
||||
@ -1457,15 +1455,7 @@ impl<T: Config> Pallet<T> {
|
||||
let authority_index = index as AuthIndex;
|
||||
|
||||
if offence_bitmap.exists(&authority_index) {
|
||||
weight.saturating_accrue(T::DbWeight::get().reads(2));
|
||||
|
||||
if let Some(account_id) = T::ExposureListener::get_account_by_index(index) {
|
||||
weight.saturating_accrue(T::DbWeight::get().reads(1));
|
||||
if T::StakingEvictor::try_evict_validator(&account_id) {
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(2));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(full_id) = <T::ValidatorSet as ValidatorSetWithIdentification<
|
||||
T::AccountId,
|
||||
>>::IdentificationOf::convert(id.clone())
|
||||
@ -1647,7 +1637,7 @@ impl<Offender: Clone> Offence<Offender> for SlowClapOffence<Offender> {
|
||||
missed_percent.saturating_mul(Perbill::from_rational(1, offenders_count))
|
||||
}
|
||||
OffenceType::CommitmentOffence => offenders_count
|
||||
.checked_sub(Perbill::from_percent(9).mul_floor(self.validator_set_count))
|
||||
.checked_sub(Perbill::from_percent(9).mul_ceil(self.validator_set_count))
|
||||
.map(|threshold| {
|
||||
Perbill::from_rational(threshold.saturating_mul(4), self.validator_set_count)
|
||||
.square()
|
||||
|
||||
@ -5,7 +5,6 @@ use frame_support::{
|
||||
traits::{ConstU32, ConstU64},
|
||||
};
|
||||
use frame_system::EnsureRoot;
|
||||
use ghost_traits::evictor::StakingEvictor;
|
||||
use pallet_session::historical as pallet_session_historical;
|
||||
use sp_runtime::{
|
||||
curve::PiecewiseLinear,
|
||||
@ -37,7 +36,6 @@ frame_support::construct_runtime!(
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub static EvicatedValidators: Vec<u64> = vec![];
|
||||
pub static FixedValidators: Vec<u64> = vec![0, 1, 2, 3];
|
||||
}
|
||||
|
||||
@ -174,25 +172,6 @@ impl pallet_balances::Config for Runtime {
|
||||
|
||||
type Balance = u64;
|
||||
|
||||
pub struct TestStakingEvictor;
|
||||
impl StakingEvictor<u64> for TestStakingEvictor {
|
||||
fn try_evict_validator(who: &u64) -> bool {
|
||||
if !FixedValidators::get().contains(who) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut evicted_validators = EvicatedValidators::get();
|
||||
match evicted_validators.iter().position(|x| x == who) {
|
||||
Some(_) => false,
|
||||
None => {
|
||||
evicted_validators.push(*who);
|
||||
EvicatedValidators::set(evicted_validators);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestExposureListener;
|
||||
impl ExposureListener<Balance, u64> for TestExposureListener
|
||||
where
|
||||
@ -238,7 +217,6 @@ impl Config for Runtime {
|
||||
type ReportUnresponsiveness = OffenceHandler;
|
||||
type DisabledValidators = Session;
|
||||
type ExposureListener = TestExposureListener;
|
||||
type StakingEvictor = TestStakingEvictor;
|
||||
|
||||
type MaxAuthorities = ConstU32<5>;
|
||||
type ApplauseThreshold = ConstU32<500_000_000>;
|
||||
|
||||
@ -1691,40 +1691,6 @@ fn migration_from_v2_to_v3_works_fine() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validators_are_evicted_during_offence() {
|
||||
let (network_id, _, _) = generate_unique_hash(None, None, None, None, None);
|
||||
|
||||
new_test_ext().execute_with(|| {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
System::set_block_number(5 * EpochDuration::get() / 2);
|
||||
let last_stored_block = 69;
|
||||
|
||||
for i in 0..3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
last_stored_block,
|
||||
));
|
||||
}
|
||||
|
||||
assert_eq!(EvicatedValidators::get().len(), 0);
|
||||
let current_block = SlowClap::current_block_number();
|
||||
|
||||
SlowClap::on_initialize(current_block);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
crate::Event::SomeAuthoritiesDelayed {
|
||||
delayed: vec![(3, 3)],
|
||||
},
|
||||
));
|
||||
assert_eq!(EvicatedValidators::get().len(), 1);
|
||||
});
|
||||
}
|
||||
|
||||
fn assert_clapped_amount(
|
||||
session_index: &SessionIndex,
|
||||
unique_hash: &H256,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-traits"
|
||||
version = "0.4.10"
|
||||
version = "0.4.6"
|
||||
description = "Shared traits including `GhostHasher`, `NetworkDataBasicHandler`, `BoundedBTreeMap`, `MerkleTree` and more."
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@ -20,10 +20,6 @@ pub trait BoundedBitmapReader {
|
||||
fn highest_bit<N>(&self) -> Option<N>
|
||||
where
|
||||
usize: UniqueSaturatedInto<N>;
|
||||
fn count_ones_before<N>(&self, index: N) -> Option<N>
|
||||
where
|
||||
N: UniqueSaturatedInto<usize>,
|
||||
usize: UniqueSaturatedInto<N>;
|
||||
fn count_ones<N>(&self) -> N
|
||||
where
|
||||
u32: UniqueSaturatedInto<N>;
|
||||
@ -44,6 +40,9 @@ pub trait BoundedBitmapGenerator {
|
||||
where
|
||||
N: UniqueSaturatedInto<usize>;
|
||||
fn empty_from(bitmap: &Self) -> Self;
|
||||
fn from_bitmask<Outer>(values: &Vec<Outer>) -> Self
|
||||
where
|
||||
Outer: AtLeast8BitUnsigned + num_traits::PrimInt;
|
||||
fn from_vec<Outer>(values: &Vec<Outer>) -> Self
|
||||
where
|
||||
Outer: AtLeast8BitUnsigned + TryInto<usize> + PartialEq + Copy;
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
pub trait StakingEvictor<AccountId> {
|
||||
fn try_evict_validator(who: &AccountId) -> bool;
|
||||
}
|
||||
@ -6,14 +6,7 @@ use sp_std::{
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
pub trait CiphersuiteSizes<A, E> {
|
||||
fn header_bytes_len(&self) -> usize;
|
||||
fn element_bytes_len(&self) -> usize;
|
||||
fn signature_bytes_len(&self) -> usize;
|
||||
fn scalar_bytes_len(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait IdentifierConverter<A, E>: CiphersuiteSizes<A, E> {
|
||||
pub trait IdentifierConverter<A, E> {
|
||||
fn non_zero_index(index: A) -> Result<A, E>;
|
||||
fn convert_identifier_to_index(bytes: &[u8]) -> Result<A, E>;
|
||||
}
|
||||
@ -22,6 +15,11 @@ pub trait FlexibleRoundOptimizedSchnorrThresholdSignature<A, E>: MerkleTreeBuild
|
||||
type Packages<'a>;
|
||||
type NoncePackages<'a>;
|
||||
|
||||
fn header_bytes_len(&self) -> usize;
|
||||
fn element_bytes_len(&self) -> usize;
|
||||
fn signature_bytes_len(&self) -> usize;
|
||||
fn scalar_bytes_len(&self) -> usize;
|
||||
|
||||
fn verify_signature_share(
|
||||
&self,
|
||||
i: A,
|
||||
@ -35,7 +33,6 @@ pub trait FlexibleRoundOptimizedSchnorrThresholdSignature<A, E>: MerkleTreeBuild
|
||||
vk: &[u8],
|
||||
m: &[u8],
|
||||
) -> Result<(), E>;
|
||||
fn is_nonce_valid_point(&self, b: &[u8]) -> Result<(), E>;
|
||||
fn is_signature_valid(&self, vk: &[u8], r: &[u8], z: &[u8], m: &[u8]) -> Result<(), E>;
|
||||
fn accumulate_signature_scalar(&self, ss: &[u8], sh: &[u8]) -> Result<Vec<u8>, E>;
|
||||
|
||||
@ -94,14 +91,13 @@ pub trait MerkleTreeBuilder<A, E>: IdentifierConverter<A, E> {
|
||||
type Hash;
|
||||
|
||||
fn build_merkle_tree<C, V, F>(
|
||||
size_hint: usize,
|
||||
verifying_shares: &BTreeMap<Identifier<C>, V>,
|
||||
serialize_fn: F,
|
||||
) -> Result<Vec<Self::Hash>, E>
|
||||
where
|
||||
C: frost_core::Ciphersuite,
|
||||
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
||||
F: Fn(&V, &mut Vec<u8>) -> Result<(), E>;
|
||||
F: Fn(&V) -> Result<Vec<u8>, E>;
|
||||
|
||||
fn generate_merkle_proof_from_tree<C, V, F>(
|
||||
verifying_shares: &BTreeMap<Identifier<C>, V>,
|
||||
|
||||
@ -21,13 +21,6 @@ pub trait GhostHasher {
|
||||
bytes
|
||||
}
|
||||
|
||||
fn combine_hashes(left: Self::Hash, right: Self::Hash) -> Self::Hash;
|
||||
fn combine_hashes_prefixed(
|
||||
prefix: u8,
|
||||
left: Self::Hash,
|
||||
right: Self::Hash,
|
||||
) -> Self::Hash;
|
||||
|
||||
fn hash(data: &[u8]) -> Self::Hash;
|
||||
fn empty() -> Self::Hash;
|
||||
fn hash_len() -> usize;
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
use frame_support::{
|
||||
pallet_prelude::*,
|
||||
storage::PrefixIterator,
|
||||
};
|
||||
use frame_support::{pallet_prelude::*, storage::PrefixIterator};
|
||||
use sp_std::vec::Vec;
|
||||
use sp_runtime::{
|
||||
offchain::http::PendingRequest,
|
||||
@ -32,12 +29,9 @@ pub trait NetworkDataBasicHandler {
|
||||
+ TypeInfo
|
||||
+ MaybeSerializeDeserialize
|
||||
+ MaxEncodedLen;
|
||||
type MaxNetworks: Get<u32>;
|
||||
}
|
||||
|
||||
pub trait NetworkDataInspectHandler<Network>: NetworkDataBasicHandler {
|
||||
type TypesItem: AsRef<[Self::NetworkId]>;
|
||||
|
||||
fn count() -> u32;
|
||||
fn contains_key(n: &Self::NetworkId) -> bool;
|
||||
fn curve_exists(c: &Self::NetworkCurve) -> bool;
|
||||
@ -46,9 +40,7 @@ pub trait NetworkDataInspectHandler<Network>: NetworkDataBasicHandler {
|
||||
fn iter() -> PrefixIterator<(Self::NetworkId, Network)>;
|
||||
fn iter_indexes() -> impl Iterator<Item = Self::NetworkId>;
|
||||
fn iter_curves() -> impl Iterator<Item = Self::NetworkCurve>;
|
||||
fn iter_types_by_curve(
|
||||
c: &Self::NetworkCurve
|
||||
) -> impl Iterator<Item = (Self::NetworkType, Self::TypesItem)>;
|
||||
fn iter_types_by_curve(n: &Self::NetworkCurve) -> impl Iterator<Item = Self::NetworkType>;
|
||||
}
|
||||
|
||||
pub trait NetworkDataMutateHandler<Network, Balance>: NetworkDataInspectHandler<Network> {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-weaver"
|
||||
version = "0.0.26"
|
||||
version = "0.0.8"
|
||||
description = "Weaving a secure cryptographic tapestry across different external chains."
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@ -3,14 +3,12 @@
|
||||
use super::*;
|
||||
use frame_benchmarking::v2::*;
|
||||
use frame_system::RawOrigin;
|
||||
use sp_runtime::traits::Saturating;
|
||||
use sp_std::vec;
|
||||
|
||||
use ghost_helpers::networks::NetworkDataBuilder;
|
||||
|
||||
fn prepare_pallet<T: Config>(
|
||||
authorities_len: u32,
|
||||
maybe_network_id: Option<u64>,
|
||||
authorities_len: u32
|
||||
) -> (NetworkIdOf<T>, T::AuthorityId, AuthIndex) {
|
||||
let authority = T::AuthorityId::generate_pair(None);
|
||||
let authorities = vec![authority.clone(); authorities_len as usize];
|
||||
@ -20,9 +18,7 @@ fn prepare_pallet<T: Config>(
|
||||
|
||||
Authorities::<T>::put(bounded_authorities);
|
||||
|
||||
let network_id_u64 = maybe_network_id.unwrap_or_default();
|
||||
let network_id: NetworkIdOf<T> = network_id_u64.unique_saturated_into();
|
||||
|
||||
let network_id = NetworkIdOf::<T>::default();
|
||||
let network_data = NetworkDataBuilder::default()
|
||||
.with_network_type(NetworkType::Utxo)
|
||||
.with_gatekeeper(
|
||||
@ -35,9 +31,6 @@ fn prepare_pallet<T: Config>(
|
||||
T::NetworkDataHandler::register(network_id, network_data)
|
||||
.expect("network should be valid for insertion");
|
||||
|
||||
let current_block = T::BlockNumberProvider::current_block_number();
|
||||
Pallet::<T>::on_initialize(current_block);
|
||||
|
||||
(network_id, authority, 0)
|
||||
}
|
||||
|
||||
@ -49,14 +42,13 @@ mod benchmarks {
|
||||
fn extend_warp(
|
||||
a: Linear<1, { T::MaxAuthorities::get() as u32 }>,
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let (network_id, authority, authority_index) = prepare_pallet::<T>(a, None);
|
||||
let (network_id, authority, authority_index) = prepare_pallet::<T>(a);
|
||||
|
||||
TapestryDrafts::<T>::remove(&network_id);
|
||||
|
||||
let block_attestation = AttestationContext::default()
|
||||
.with_network_id(network_id)
|
||||
.with_authority_index(authority_index)
|
||||
.with_current_block(1337u16.into())
|
||||
.build_block_attestation(420);
|
||||
|
||||
let signature = authority
|
||||
@ -81,7 +73,7 @@ mod benchmarks {
|
||||
let next_session = weaving_session + 1;
|
||||
let root_hash = H256::repeat_byte(0x69);
|
||||
|
||||
let (network_id, authority, authority_index) = prepare_pallet::<T>(a, None);
|
||||
let (network_id, authority, authority_index) = prepare_pallet::<T>(a);
|
||||
|
||||
let tapestry_key = (network_id, weaving_session, next_session, root_hash);
|
||||
TapestryStrands::<T>::mutate(&tapestry_key, |tapestry| {
|
||||
@ -105,7 +97,6 @@ mod benchmarks {
|
||||
.with_network_id(network_id)
|
||||
.with_weaving_session(weaving_session)
|
||||
.with_authority_index(authority_index)
|
||||
.with_current_block(1337u16.into())
|
||||
.build_hash_attestation(root_hash, next_session);
|
||||
|
||||
let signature = authority
|
||||
@ -148,18 +139,7 @@ mod benchmarks {
|
||||
) -> Result<(), BenchmarkError> {
|
||||
let session = 69;
|
||||
let max_history_depth = a as usize;
|
||||
let (network_id, _, _) = prepare_pallet::<T>(1, None);
|
||||
|
||||
let expected_receiver_bytes = hex::decode("1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e").unwrap();
|
||||
let mut receiver_raw = [0u8; 32];
|
||||
receiver_raw.copy_from_slice(&expected_receiver_bytes);
|
||||
|
||||
let transfer_amount: u64 = 153348847;
|
||||
let receiver = T::AccountId::decode(&mut &receiver_raw[..])
|
||||
.expect("32-byte array must cleanly decode into T::AccountId");
|
||||
|
||||
let existential_deposit = <T as Config>::Currency::minimum_balance();
|
||||
<T as Config>::Currency::set_balance(&receiver, existential_deposit);
|
||||
let (network_id, _, _) = prepare_pallet::<T>(1);
|
||||
|
||||
// Real world tx at block #481838
|
||||
// Block https://blockstream.info/block/0000000000000000011bdccb39e19e942a60edffdccd9779653c5b46b337904a
|
||||
@ -325,12 +305,9 @@ mod benchmarks {
|
||||
let first_sha = sp_io::hashing::sha2_256(&last_header[..80]);
|
||||
let mut native_le = sp_io::hashing::sha2_256(&first_sha);
|
||||
native_le.reverse();
|
||||
|
||||
let at_block = 420;
|
||||
let dynamic_trusted_root = H256::from(native_le);
|
||||
let loom_state = LoomState { at_block, root_hash: dynamic_trusted_root };
|
||||
|
||||
LoomStates::<T>::insert(&network_id, &session, loom_state);
|
||||
LoomStates::<T>::insert(&network_id, &session, dynamic_trusted_root);
|
||||
|
||||
let utxo_thread_proof = UtxoThreadProof::new(
|
||||
gettxproof_bytes,
|
||||
@ -339,40 +316,31 @@ mod benchmarks {
|
||||
);
|
||||
|
||||
let thread_proof = ThreadProof::UtxoThreadProof(utxo_thread_proof);
|
||||
let pulled_thread_key = thread_proof.get_unique_key(session, network_id);
|
||||
let pulled_thread_key = thread_proof.get_unique_key(session);
|
||||
|
||||
assert!(!PulledThreads::<T>::contains_key(&pulled_thread_key));
|
||||
assert_eq!(T::Currency::balance(&receiver), existential_deposit);
|
||||
|
||||
#[extrinsic_call]
|
||||
pull_thread(RawOrigin::None, network_id, session, thread_proof);
|
||||
|
||||
let final_amount = existential_deposit.saturating_add(
|
||||
transfer_amount.unique_saturated_into()
|
||||
);
|
||||
assert!(PulledThreads::<T>::contains_key(&pulled_thread_key));
|
||||
assert_eq!(T::Currency::balance(&receiver), final_amount);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn pull_evm_thread() -> Result<(), BenchmarkError> {
|
||||
let session = 0;
|
||||
let sepolia_network_id = 11155111;
|
||||
let (network_id, _, _) = prepare_pallet::<T>(1, Some(sepolia_network_id));
|
||||
let session = 69;
|
||||
let (network_id, _, _) = prepare_pallet::<T>(1);
|
||||
|
||||
// https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract
|
||||
// getRoot: session 0, atBlock 11716130
|
||||
// https://sepolia.etherscan.io/address/0x81acdf2da6b50d806c96aecd9a498a5359e373c0#readContract
|
||||
// getRoot: session 0, atBlock 11660400
|
||||
|
||||
let root_string =
|
||||
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129")
|
||||
hex::decode("28d1e6b476b03a464f74d531d532572db29d6b57349e4f17f84e92843f6c4ee7")
|
||||
.expect("EVM Root hex should be valid");
|
||||
|
||||
let at_block = 420;
|
||||
let expected_root = H256::from_slice(&root_string);
|
||||
let loom_state = LoomState { at_block, root_hash: expected_root };
|
||||
LoomStates::<T>::insert(&network_id, &session, loom_state);
|
||||
LoomStates::<T>::insert(&network_id, &session, expected_root);
|
||||
|
||||
let receiver_32: [u8; 32] =
|
||||
hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e")
|
||||
@ -380,17 +348,12 @@ mod benchmarks {
|
||||
.try_into()
|
||||
.expect("Hex string must be exactly 32 bytes long");
|
||||
|
||||
let transfer_amount: BalanceOf<T> = 420u64.unique_saturated_into();
|
||||
let receiver_account = sp_runtime::AccountId32::from(receiver_32);
|
||||
let receiver_account_t = T::AccountId::decode(&mut &receiver_32[..])
|
||||
.expect("32-byte array must cleanly decode into T::AccountId");
|
||||
|
||||
let existential_deposit = <T as Config>::Currency::minimum_balance();
|
||||
<T as Config>::Currency::set_balance(&receiver_account_t, existential_deposit);
|
||||
let transfer_amount: BalanceOf<T> = 420u64.unique_saturated_into();
|
||||
|
||||
let proof = vec![
|
||||
H256::from_slice(&hex::decode("7d831a4be9e37572687117870c3f96669a66bf07971e4fd705a36a0a4d6365b0").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("9f00b99751b7ccea1903949210408edb3ce50343985708c36a0b1d44e0a7628c").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("c5354289f0397c916949373043eb1d5ea99447f67fe014324d96c58ef02a2d11").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("da1fbdfefa1e9aedfedcfc48fb17cb0e731529f7a3695114e0a9caa1989dd420").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")),
|
||||
@ -399,14 +362,14 @@ mod benchmarks {
|
||||
H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")),
|
||||
];
|
||||
let slots = vec![H256::from_slice(
|
||||
&hex::decode("f6182b8c276793f53d1820ad0405665177516e46e40af45e0dfea73c39a2306e")
|
||||
&hex::decode("2e474dabf492786b3505d7b7cf0bf07c9dbce92c91982fa7344c77e24fd4310d")
|
||||
.expect("Slot should be valid hex"),
|
||||
)];
|
||||
|
||||
let evm_thread_proof = EvmThreadProof::new(0, 1, receiver_account.into(), transfer_amount, proof, slots);
|
||||
let evm_thread_proof = EvmThreadProof::new(0, 1, receiver_account, transfer_amount, proof, slots);
|
||||
|
||||
let thread_proof = ThreadProof::EvmThreadProof(evm_thread_proof);
|
||||
let pulled_thread_key = thread_proof.get_unique_key(session, network_id);
|
||||
let pulled_thread_key = thread_proof.get_unique_key(session);
|
||||
|
||||
assert!(!PulledThreads::<T>::contains_key(&pulled_thread_key));
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ pub enum WeavingError<NetworkId> {
|
||||
impl<NetworkId: core::fmt::Debug> core::fmt::Debug for WeavingError<NetworkId> {
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::NoStoredNetworks => write!(fmt, "No stored networks to work on."),
|
||||
Self::NoStoredNetworks => write!(fmt, "No stored networks to be watch on."),
|
||||
Self::UnparsableRequestBody => {
|
||||
write!(fmt, "HTTP request body contains invalid UTF-8 sequences.")
|
||||
}
|
||||
@ -22,25 +22,25 @@ impl<NetworkId: core::fmt::Debug> core::fmt::Debug for WeavingError<NetworkId> {
|
||||
write!(fmt, "The request deadline or network timeout was hit.")
|
||||
}
|
||||
Self::UnknownWeavingPhase(network_id) => {
|
||||
write!(fmt, "Unknown weaving phase for network #{:?}.", network_id)
|
||||
write!(fmt, "Unknown weaving phase for network: {:?}.", network_id)
|
||||
}
|
||||
Self::OffchainLockPeriod(network_id) => write!(
|
||||
fmt,
|
||||
"Storage lock is still held for network #{:?}.",
|
||||
"Storage lock is still held for network: {:?}.",
|
||||
network_id
|
||||
),
|
||||
Self::NoEndpointsAvailable(network_id) => write!(
|
||||
fmt,
|
||||
"No RPC URLs configured for network #{:?}.",
|
||||
"Zero RPC URLs configured for network: {:?}.",
|
||||
network_id
|
||||
),
|
||||
Self::ContradictoryHashes(network_id) => write!(
|
||||
fmt,
|
||||
"Divergence among reported hashes for network #{:?}.",
|
||||
"Divergence among reported hashes for network: {:?}.",
|
||||
network_id
|
||||
),
|
||||
Self::ContradictoryBlocks(len, deviation, network_id) => {
|
||||
write!(fmt, "Divergence among {len} reported blocks exceeds the maximum allowed deviation of {deviation} for network #{:?}.", network_id)
|
||||
write!(fmt, "Divergence among {len} reported blocks exceeds the maximum threshold of {deviation} provided for network: {:?}.", network_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,7 +73,7 @@ impl core::fmt::Debug for RpcResolverError {
|
||||
"The 'result' field in the JSON-RPC response is missing or null."
|
||||
),
|
||||
Self::UnknownNetworkType => {
|
||||
write!(fmt, "The provided network type identifier is not supported.")
|
||||
write!(fmt, "he provided network type identifier is not supported.")
|
||||
}
|
||||
Self::RpcProtocolError => write!(
|
||||
fmt,
|
||||
|
||||
@ -68,14 +68,13 @@ fn parse_pending_requests<'a, R: Copy + Into<RequestId> + 'static>(
|
||||
) -> impl Iterator<Item = NetworkResponseType> + 'a {
|
||||
PendingRequest::try_wait_all(pending_requests, Some(deadline))
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.filter_map(move |(idx, wait_result)| {
|
||||
.filter_map(move |wait_result| {
|
||||
let http_result = wait_result
|
||||
.inspect_err(|_| {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"🕸️ Weaver: RPC request [index {}] timed out (deadline reached).",
|
||||
idx
|
||||
"🕸️ Error during request preparation: {:?}",
|
||||
WeavingError::<u32>::DeadlineReached,
|
||||
)
|
||||
})
|
||||
.ok()?;
|
||||
@ -84,8 +83,7 @@ fn parse_pending_requests<'a, R: Copy + Into<RequestId> + 'static>(
|
||||
.inspect_err(|err| {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"🕸️ Weaver: RPC request [index {}] failed with HTTP error: {:?}",
|
||||
idx,
|
||||
"🕸️ Error during response parsing: {:?}",
|
||||
err,
|
||||
)
|
||||
})
|
||||
|
||||
@ -3,10 +3,7 @@
|
||||
|
||||
use frame_support::{
|
||||
pallet_prelude::*,
|
||||
traits::{
|
||||
Get, OneSessionHandler,
|
||||
tokens::fungible::{Inspect, Mutate},
|
||||
},
|
||||
traits::{Currency, Get, OneSessionHandler},
|
||||
};
|
||||
use frame_system::{
|
||||
pallet_prelude::*,
|
||||
@ -22,16 +19,13 @@ use sp_runtime::{
|
||||
storage::StorageValueRef,
|
||||
storage_lock::{StorageLock, Time},
|
||||
},
|
||||
traits::{
|
||||
TrailingZeroInput, BlockNumberProvider, Saturating,
|
||||
UniqueSaturatedInto,
|
||||
},
|
||||
RuntimeAppPublic, Perbill, PerThing,
|
||||
traits::{BlockNumberProvider, UniqueSaturatedInto},
|
||||
RuntimeAppPublic,
|
||||
};
|
||||
|
||||
use ghost_helpers::{
|
||||
bounded_bitmap::{validate_bitmap_sizes, BoundedBitmap},
|
||||
get_byzantium_quorum_threshold, get_submission_probability,
|
||||
get_byzantium_quorum_threshold,
|
||||
networks::{NetworkData, NetworkType},
|
||||
};
|
||||
use ghost_traits::{
|
||||
@ -42,7 +36,6 @@ use ghost_traits::{
|
||||
},
|
||||
};
|
||||
|
||||
pub mod migrations;
|
||||
mod errors;
|
||||
mod impls;
|
||||
mod types;
|
||||
@ -66,7 +59,7 @@ pub use pallet::*;
|
||||
pub mod sr25519 {
|
||||
mod app_sr25519 {
|
||||
use sp_application_crypto::{app_crypto, sr25519, KeyTypeId};
|
||||
const WEAVER: KeyTypeId = KeyTypeId(*b"wevr");
|
||||
const WEAVER: KeyTypeId = KeyTypeId(*b"weav");
|
||||
app_crypto!(sr25519, WEAVER);
|
||||
}
|
||||
|
||||
@ -82,8 +75,8 @@ const LOG_TARGET: &str = "runtime::ghost-weaver";
|
||||
const DB_PREFIX: &[u8] = b"ghost-weaver::";
|
||||
|
||||
const LOCK_BLOCK_EXPIRATION: u64 = 20;
|
||||
const MIN_LOCK_GUARD_PERIOD: u64 = 60_000;
|
||||
const FETCH_TIMEOUT_PERIOD: u64 = 5_000;
|
||||
const MIN_LOCK_GUARD_PERIOD: u64 = 15_000;
|
||||
const FETCH_TIMEOUT_PERIOD: u64 = 3_000;
|
||||
|
||||
type AuthIndex = ghost_helpers::AuthIndexU16;
|
||||
type BitmapChunk = ghost_helpers::BitmapChunkU32;
|
||||
@ -93,17 +86,20 @@ type ThreadId = u64;
|
||||
type WeavingSession = u64;
|
||||
type ExternalBlockNumber = u64;
|
||||
|
||||
type BalanceOf<T> = <<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
|
||||
type NetworkIdOf<T> = <<T as Config>::NetworkDataHandler as NetworkDataBasicHandler>::NetworkId;
|
||||
type BalanceOf<T> =
|
||||
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
|
||||
|
||||
pub type NetworkIdOf<T> = <<T as Config>::NetworkDataHandler as NetworkDataBasicHandler>::NetworkId;
|
||||
|
||||
type WeavingResult<T, O> = Result<O, WeavingError<NetworkIdOf<T>>>;
|
||||
|
||||
type WeaversBitmap<T> = BoundedBitmap<BitmapChunk, <T as Config>::MaxAuthoritiesChunks>;
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
@ -121,7 +117,7 @@ pub mod pallet {
|
||||
+ MaybeSerializeDeserialize
|
||||
+ MaxEncodedLen;
|
||||
|
||||
type Currency: Inspect<Self::AccountId> + Mutate<Self::AccountId>;
|
||||
type Currency: Currency<Self::AccountId>;
|
||||
|
||||
type NetworkDataHandler: NetworkDataBasicHandler
|
||||
+ NetworkDataInspectHandler<NetworkData>
|
||||
@ -186,16 +182,6 @@ pub mod pallet {
|
||||
CouldNotRegisterIncoming,
|
||||
}
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn network_attested_blocks)]
|
||||
pub(super) type NetworkAttestedBlocks<T: Config> = StorageDoubleMap<
|
||||
_,
|
||||
Twox64Concat, NetworkIdOf<T>,
|
||||
Twox64Concat, AuthIndex,
|
||||
BlockNumberFor<T>,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn current_weaving_session)]
|
||||
pub(super) type CurrentWeavingSession<T: Config> =
|
||||
@ -216,7 +202,7 @@ pub mod pallet {
|
||||
_,
|
||||
Twox64Concat, NetworkIdOf<T>,
|
||||
Twox64Concat, WeavingSession,
|
||||
LoomState,
|
||||
H256,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
@ -302,12 +288,7 @@ pub mod pallet {
|
||||
);
|
||||
return;
|
||||
}
|
||||
let initial_loom_state = LoomState {
|
||||
at_block: 0u16.into(),
|
||||
root_hash: data.2,
|
||||
};
|
||||
|
||||
LoomStates::<T>::insert(&data.0, data.1, initial_loom_state);
|
||||
LoomStates::<T>::insert(&data.0, data.1, data.2);
|
||||
});
|
||||
|
||||
if !self.authorities.is_empty() {
|
||||
@ -349,23 +330,26 @@ pub mod pallet {
|
||||
|
||||
let external_block = block_attestation.external_block;
|
||||
|
||||
let current_authorities_count = Authorities::<T>::decode_len().
|
||||
unwrap_or_default();
|
||||
|
||||
NetworkAttestations::<T>::try_mutate(
|
||||
&network_id,
|
||||
|attestations| -> DispatchResult {
|
||||
let index = authority_index as usize;
|
||||
if attestations.is_empty() {
|
||||
attestations.bounded_resize(current_authorities_count, None);
|
||||
}
|
||||
|
||||
ensure!(index < attestations.len(), Error::<T>::TooManyAttestations);
|
||||
attestations[index] = Some(external_block);
|
||||
ensure!(
|
||||
(authority_index as usize) < attestations.len(),
|
||||
Error::<T>::TooManyAttestations,
|
||||
);
|
||||
|
||||
attestations[authority_index as usize] = Some(external_block);
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let current_block = T::BlockNumberProvider::current_block_number();
|
||||
NetworkAttestedBlocks::<T>::insert(
|
||||
&network_id, &authority_index,
|
||||
current_block
|
||||
);
|
||||
|
||||
Self::deposit_event(Event::<T>::BlockAttestated {
|
||||
network_id,
|
||||
authority_index,
|
||||
@ -418,20 +402,10 @@ pub mod pallet {
|
||||
|
||||
WeavingStates::<T>::mutate(&network_id, |weaving_state| {
|
||||
if weaving_state.count < weavers_count {
|
||||
*weaving_state = WeavingState::new(
|
||||
root_hash,
|
||||
next_session,
|
||||
weavers_count
|
||||
);
|
||||
*weaving_state = WeavingState::new(root_hash, next_session, weavers_count);
|
||||
}
|
||||
});
|
||||
|
||||
let current_block = T::BlockNumberProvider::current_block_number();
|
||||
NetworkAttestedBlocks::<T>::insert(
|
||||
&network_id, &authority_index,
|
||||
current_block
|
||||
);
|
||||
|
||||
Self::deposit_event(Event::<T>::HashAttestated {
|
||||
authority_index,
|
||||
next_session,
|
||||
@ -464,8 +438,8 @@ pub mod pallet {
|
||||
let network_data = T::NetworkDataHandler::get(&network_id)
|
||||
.ok_or(Error::<T>::NonExistentNetworkId)?;
|
||||
|
||||
let state = LoomStates::<T>::get(&network_id, &session);
|
||||
let pulled_thread_key = thread_proof.get_unique_key(session, network_id);
|
||||
let root_hash = LoomStates::<T>::get(&network_id, &session);
|
||||
let pulled_thread_key = thread_proof.get_unique_key(session);
|
||||
|
||||
ensure!(
|
||||
!PulledThreads::<T>::contains_key(&pulled_thread_key),
|
||||
@ -473,7 +447,7 @@ pub mod pallet {
|
||||
);
|
||||
|
||||
let (receiver_account, amount) = thread_proof
|
||||
.verify_thread_proof(state.root_hash, network_id, &network_data.gatekeeper)
|
||||
.verify_thread_proof(root_hash, &network_data.gatekeeper)
|
||||
.ok_or(Error::<T>::InvalidMerkleProof)?;
|
||||
|
||||
let receiver_bytes: &[u8; 32] = receiver_account.as_ref();
|
||||
@ -484,7 +458,7 @@ pub mod pallet {
|
||||
T::NetworkDataHandler::register_incoming(&network_id, amount)
|
||||
.map_err(|_| Error::<T>::CouldNotRegisterIncoming)?;
|
||||
|
||||
T::Currency::mint_into(&receiver, pure_amount)?;
|
||||
let _ = T::Currency::deposit_creating(&receiver, pure_amount);
|
||||
PulledThreads::<T>::insert(pulled_thread_key, ());
|
||||
|
||||
Self::deposit_event(Event::<T>::ThreadPulled {
|
||||
@ -530,13 +504,11 @@ pub mod pallet {
|
||||
let current_session = CurrentWeavingSession::<T>::get(&network_id);
|
||||
let loom_state_changed =
|
||||
LoomStates::<T>::mutate(&network_id, ¤t_session, |loom_state| {
|
||||
if !threshold_reached { return false; }
|
||||
|
||||
let hash_changed = loom_state.root_hash != weaving_state.hash;
|
||||
loom_state.at_block = tapestry_draft.median;
|
||||
if hash_changed { loom_state.root_hash = weaving_state.hash; }
|
||||
|
||||
hash_changed
|
||||
if *loom_state != weaving_state.hash && threshold_reached {
|
||||
*loom_state = weaving_state.hash;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
});
|
||||
|
||||
if loom_state_changed && weaving_state.next_session != current_session {
|
||||
@ -546,10 +518,8 @@ pub mod pallet {
|
||||
CurrentWeavingSession::<T>::insert(&network_id, next_session);
|
||||
}
|
||||
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(3));
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
||||
TapestryDrafts::<T>::remove(&network_id);
|
||||
WeavingStates::<T>::remove(&network_id);
|
||||
NetworkAttestations::<T>::remove(&network_id);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
@ -562,11 +532,9 @@ pub mod pallet {
|
||||
weight.saturating_accrue(T::DbWeight::get().reads(1));
|
||||
let attestation_len = NetworkAttestations::<T>::decode_len(&network_id);
|
||||
|
||||
if attestation_len.unwrap_or(0) != len {
|
||||
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
|
||||
NetworkAttestations::<T>::mutate(&network_id, |attestations| {
|
||||
attestations.bounded_resize(len, None);
|
||||
});
|
||||
if attestation_len.unwrap_or(0) > len {
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
||||
NetworkAttestations::<T>::remove(&network_id);
|
||||
return weight;
|
||||
}
|
||||
|
||||
@ -607,7 +575,7 @@ pub mod pallet {
|
||||
if sp_io::offchain::is_validator() {
|
||||
log::warn!(target: LOG_TARGET, "🕸️ Weaver started at block #{:?}", now);
|
||||
match Self::start_weaving(now) {
|
||||
Ok(msg) => log::warn!(target: LOG_TARGET, "🕸️ Weaver finished gracefully at block #{:?}: {:?}", now, msg),
|
||||
Ok(_) => log::warn!(target: LOG_TARGET, "🕸️ Weaver finished gracefully at block #{:?}", now),
|
||||
Err(e) => log::warn!(target: LOG_TARGET, "🕸️ Weaver failed at block #{:?}: {:?}", now, e),
|
||||
}
|
||||
}
|
||||
@ -648,21 +616,6 @@ pub mod pallet {
|
||||
.propagate(true)
|
||||
.build()
|
||||
}
|
||||
Call::pull_thread {
|
||||
network_id,
|
||||
session,
|
||||
thread_proof,
|
||||
} => {
|
||||
let thread_context =
|
||||
Self::validate_thread(network_id, session, thread_proof)?;
|
||||
|
||||
ValidTransaction::with_tag_prefix("WeaverThread")
|
||||
.priority(T::UnsignedPriority::get())
|
||||
.and_provides(thread_context.to_fixed_bytes())
|
||||
.longevity(LOCK_BLOCK_EXPIRATION)
|
||||
.propagate(true)
|
||||
.build()
|
||||
}
|
||||
_ => InvalidTransaction::Call.into(),
|
||||
}
|
||||
}
|
||||
@ -670,31 +623,6 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
fn validate_thread(
|
||||
network_id: &NetworkIdOf<T>,
|
||||
session: &WeavingSession,
|
||||
thread_proof: &ThreadProof<BalanceOf<T>>,
|
||||
) -> Result<H256, InvalidTransaction> {
|
||||
let network_data = T::NetworkDataHandler::get(&network_id)
|
||||
.ok_or(InvalidTransaction::BadProof)?;
|
||||
|
||||
let root_hash = LoomStates::<T>::get(&network_id, &session).root_hash;
|
||||
if root_hash == Default::default() {
|
||||
return Err(InvalidTransaction::BadProof);
|
||||
}
|
||||
|
||||
thread_proof
|
||||
.verify_thread_proof(root_hash, *network_id, &network_data.gatekeeper)
|
||||
.ok_or(InvalidTransaction::BadProof)?;
|
||||
|
||||
let pulled_thread_key = thread_proof.get_unique_key(*session, *network_id);
|
||||
if PulledThreads::<T>::contains_key(&pulled_thread_key) {
|
||||
return Err(InvalidTransaction::Stale);
|
||||
}
|
||||
|
||||
Ok(pulled_thread_key)
|
||||
}
|
||||
|
||||
fn validate_attestation_signature<A>(
|
||||
attestation: &A,
|
||||
signature: &<T::AuthorityId as RuntimeAppPublic>::Signature,
|
||||
@ -704,40 +632,15 @@ impl<T: Config> Pallet<T> {
|
||||
A: Encode,
|
||||
{
|
||||
let authority_index = attestation.authority_index();
|
||||
let attestation_block = attestation.block();
|
||||
let network_id = attestation.network_id();
|
||||
|
||||
if !T::NetworkDataHandler::contains_key(&network_id) {
|
||||
return Err(InvalidTransaction::BadProof);
|
||||
}
|
||||
|
||||
let current_attestation_len =
|
||||
NetworkAttestations::<T>::decode_len(&network_id).unwrap_or(0);
|
||||
|
||||
if authority_index as usize >= current_attestation_len {
|
||||
return Err(InvalidTransaction::BadSigner.into());
|
||||
}
|
||||
|
||||
if DisabledAuthorities::<T>::get().contains(authority_index) {
|
||||
return Err(InvalidTransaction::BadSigner);
|
||||
}
|
||||
|
||||
let attestation_block = attestation.block();
|
||||
let current_block = T::BlockNumberProvider::current_block_number();
|
||||
let lock: BlockNumberFor<T> = LOCK_BLOCK_EXPIRATION.unique_saturated_into();
|
||||
let block_expiration = attestation_block.saturating_add(lock);
|
||||
|
||||
if current_block >= block_expiration {
|
||||
return Err(InvalidTransaction::Stale);
|
||||
}
|
||||
|
||||
let last_attested = NetworkAttestedBlocks::<T>::get(
|
||||
&network_id,
|
||||
&authority_index
|
||||
);
|
||||
let cooling_off_until = last_attested.saturating_add(lock);
|
||||
|
||||
if attestation_block < cooling_off_until {
|
||||
return Err(InvalidTransaction::Stale);
|
||||
if T::BlockNumberProvider::current_block_number() <= attestation_block {
|
||||
return Err(InvalidTransaction::BadProof);
|
||||
}
|
||||
|
||||
Authorities::<T>::get()
|
||||
@ -750,6 +653,10 @@ impl<T: Config> Pallet<T> {
|
||||
.ok_or(InvalidTransaction::BadSigner)
|
||||
})?;
|
||||
|
||||
if !T::NetworkDataHandler::contains_key(&network_id) {
|
||||
return Err(InvalidTransaction::BadProof);
|
||||
}
|
||||
|
||||
Ok((authority_index, network_id))
|
||||
}
|
||||
|
||||
@ -764,7 +671,7 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
let lock_period_key = Self::create_storage_key(b"network-period", &network_id_encoded);
|
||||
let lock_period = Self::read_offchain_storage(&lock_period_key, &MIN_LOCK_GUARD_PERIOD);
|
||||
let lock_until = rt_offchain::Duration::from_millis(lock_period.max(MIN_LOCK_GUARD_PERIOD));
|
||||
let lock_until = rt_offchain::Duration::from_millis(lock_period);
|
||||
|
||||
let network_lock_key = Self::create_storage_key(b"network-lock-", &network_id_encoded);
|
||||
let mut network_lock = StorageLock::<Time>::with_deadline(&network_lock_key, lock_until);
|
||||
@ -802,31 +709,14 @@ impl<T: Config> Pallet<T> {
|
||||
return Err(WeavingError::NoEndpointsAvailable(network_id));
|
||||
}
|
||||
|
||||
let check_probability = |values_count: usize, blocks_left: BlockNumberFor<T>| -> bool {
|
||||
let total_authorities = Authorities::<T>::decode_len().unwrap_or(1);
|
||||
let submission_probability = get_submission_probability(
|
||||
total_authorities,
|
||||
values_count,
|
||||
blocks_left,
|
||||
);
|
||||
|
||||
let seed = sp_io::offchain::random_seed();
|
||||
let randomness = <u32>::decode(&mut TrailingZeroInput::new(seed.as_ref()))
|
||||
.expect("input is padded with zeroes; qed");
|
||||
let random_roll = Perbill::from_parts(randomness % Perbill::ACCURACY);
|
||||
|
||||
random_roll > submission_probability
|
||||
};
|
||||
|
||||
match TapestryDrafts::<T>::get(&network_id) {
|
||||
Some(tapestry_draft) => Self::try_request_and_submit_hash(
|
||||
network_id,
|
||||
current_block,
|
||||
tapestry_draft,
|
||||
tapestry_draft.median,
|
||||
deadline,
|
||||
&network_data,
|
||||
&rpc_endpoints,
|
||||
check_probability,
|
||||
),
|
||||
None => Self::try_request_and_submit_block(
|
||||
network_id,
|
||||
@ -834,7 +724,6 @@ impl<T: Config> Pallet<T> {
|
||||
deadline,
|
||||
&network_data,
|
||||
&rpc_endpoints,
|
||||
check_probability,
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -842,22 +731,13 @@ impl<T: Config> Pallet<T> {
|
||||
fn try_request_and_submit_hash(
|
||||
network_id: NetworkIdOf<T>,
|
||||
current_block: BlockNumberFor<T>,
|
||||
tapestry_draft: TapestryDraft<BlockNumberFor<T>>,
|
||||
target_block: ExternalBlockNumber,
|
||||
deadline: rt_offchain::Timestamp,
|
||||
network_data: &NetworkData,
|
||||
rpc_endpoints: &Vec<Vec<u8>>,
|
||||
check_probability: impl Fn(usize, BlockNumberFor<T>) -> bool,
|
||||
) -> WeavingResult<T, WeavingOk<NetworkIdOf<T>>> {
|
||||
let weaving_session = CurrentWeavingSession::<T>::get(&network_id);
|
||||
|
||||
let block_until = tapestry_draft.until.saturating_sub(current_block);
|
||||
let weaving_count = WeavingStates::<T>::get(&network_id).count as usize;
|
||||
|
||||
if check_probability(weaving_count, block_until) {
|
||||
return Ok(WeavingOk::Skipped(network_id));
|
||||
}
|
||||
|
||||
let target_block = tapestry_draft.median;
|
||||
let request_id = current_block.unique_saturated_into();
|
||||
|
||||
let request_body = network_data.r#type.get_hash_request_body(
|
||||
@ -951,20 +831,7 @@ impl<T: Config> Pallet<T> {
|
||||
deadline: rt_offchain::Timestamp,
|
||||
network_data: &NetworkData,
|
||||
rpc_endpoints: &Vec<Vec<u8>>,
|
||||
check_probability: impl Fn(usize, BlockNumberFor<T>) -> bool,
|
||||
) -> WeavingResult<T, WeavingOk<NetworkIdOf<T>>> {
|
||||
let next_attempt_block = NextConsensusAttemptBlocks::<T>::get(&network_id);
|
||||
let block_until = next_attempt_block.saturating_sub(current_block);
|
||||
|
||||
let attestations_count = NetworkAttestations::<T>::get(&network_id)
|
||||
.iter()
|
||||
.flatten()
|
||||
.count();
|
||||
|
||||
if check_probability(attestations_count, block_until) {
|
||||
return Ok(WeavingOk::Skipped(network_id));
|
||||
}
|
||||
|
||||
let network_id_encoded = network_id.encode();
|
||||
let distance_key = Self::create_storage_key(b"distance-", &network_id_encoded);
|
||||
let block_deviation =
|
||||
@ -983,7 +850,6 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
let total_blocks = block_numbers.len();
|
||||
let weaving_threshold = get_byzantium_quorum_threshold(total_blocks);
|
||||
let parsed_blocks_count = total_blocks.unique_saturated_into();
|
||||
|
||||
let median_block = Self::validate_block_numbers_consensus(
|
||||
&mut block_numbers,
|
||||
@ -1032,7 +898,7 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
});
|
||||
|
||||
Ok(WeavingOk::Block(finalized_block, parsed_blocks_count, network_id))
|
||||
Ok(WeavingOk::Block(finalized_block, network_id))
|
||||
}
|
||||
|
||||
fn prepare_pending_requests(
|
||||
@ -1176,7 +1042,12 @@ impl<T: Config> Pallet<T> {
|
||||
local_authorities
|
||||
.binary_search(&authority)
|
||||
.ok()
|
||||
.map(|_| (index as AuthIndex, authority))
|
||||
.map(|location| {
|
||||
(
|
||||
index.unique_saturated_into(),
|
||||
local_authorities[location].clone(),
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
pub mod v1;
|
||||
|
||||
pub type MigrateV0ToV1<T> = frame_support::migrations::VersionedMigration<
|
||||
0,
|
||||
1,
|
||||
v1::RemoveAttestedBlocksStorage<T>,
|
||||
crate::Pallet::<T>,
|
||||
<T as frame_system::Config>::DbWeight,
|
||||
>;
|
||||
@ -1,33 +0,0 @@
|
||||
use frame_support::{
|
||||
traits::{Get, UncheckedOnRuntimeUpgrade},
|
||||
weights::Weight,
|
||||
};
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use crate::{Config, LOG_TARGET};
|
||||
|
||||
pub struct RemoveAttestedBlocksStorage<T>(PhantomData<T>);
|
||||
impl<T: Config> UncheckedOnRuntimeUpgrade for RemoveAttestedBlocksStorage<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let clear_key = frame_support::storage::storage_prefix(
|
||||
b"GhostWeaver",
|
||||
b"AttestedBlocks"
|
||||
);
|
||||
|
||||
let removal_results = frame_support::storage::unhashed::clear_prefix(
|
||||
&clear_key,
|
||||
None,
|
||||
None
|
||||
);
|
||||
|
||||
let killed_keys = removal_results.unique;
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"🧹 Success: Purged deprecated AttestedBlocks storage. Wiped {} keys from Trie.",
|
||||
killed_keys
|
||||
);
|
||||
|
||||
T::DbWeight::get().reads_writes(1, killed_keys as u64)
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::{LOCK_BLOCK_EXPIRATION, sr25519::AuthorityPair};
|
||||
use crate::sr25519::AuthorityPair;
|
||||
|
||||
use crate::mock::*;
|
||||
use crate::pallet::*;
|
||||
@ -76,11 +76,10 @@ fn should_successfully_compute_median_and_start_weaving_round() {
|
||||
let networks = vec![(network_id, network_data, Default::default())];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2);
|
||||
System::set_block_number(2);
|
||||
|
||||
let context = AttestationContext::default()
|
||||
.with_current_block(LOCK_BLOCK_EXPIRATION + 1)
|
||||
.with_current_block(1)
|
||||
.with_network_id(network_id);
|
||||
|
||||
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
||||
@ -97,12 +96,12 @@ fn should_successfully_compute_median_and_start_weaving_round() {
|
||||
|
||||
assert!(GhostWeaver::tapestry_drafts(network_id).is_none());
|
||||
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 3);
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3);
|
||||
System::set_block_number(3);
|
||||
GhostWeaver::on_initialize(3);
|
||||
|
||||
let round = GhostWeaver::tapestry_drafts(network_id);
|
||||
assert!(round.is_some());
|
||||
assert_eq!(round.unwrap().until, LOCK_BLOCK_EXPIRATION + 3 + WeavingDelay::get());
|
||||
assert_eq!(round.unwrap().until, 3 + WeavingDelay::get());
|
||||
});
|
||||
}
|
||||
|
||||
@ -121,11 +120,10 @@ fn should_apply_cooldown_delay_on_consensus_failure() {
|
||||
let networks = vec![(network_id, network_data, Default::default())];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 9);
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 10);
|
||||
System::set_block_number(10);
|
||||
|
||||
let context = AttestationContext::default()
|
||||
.with_current_block(LOCK_BLOCK_EXPIRATION + 9)
|
||||
.with_current_block(9)
|
||||
.with_network_id(network_id);
|
||||
|
||||
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
||||
@ -140,20 +138,20 @@ fn should_apply_cooldown_delay_on_consensus_failure() {
|
||||
assert!(GhostWeaver::extend_warp(RuntimeOrigin::none(), att2, sig2).is_ok());
|
||||
assert!(GhostWeaver::extend_warp(RuntimeOrigin::none(), att3, sig3).is_ok());
|
||||
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 11);
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 11);
|
||||
System::set_block_number(11);
|
||||
GhostWeaver::on_initialize(11);
|
||||
|
||||
let cooldown_block = GhostWeaver::next_consensus_attempt_blocks(network_id);
|
||||
assert_eq!(cooldown_block, LOCK_BLOCK_EXPIRATION + 14);
|
||||
assert_eq!(cooldown_block, 14);
|
||||
|
||||
TapestryDrafts::<TestRuntime>::remove(network_id);
|
||||
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 12);
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION+ 12);
|
||||
System::set_block_number(12);
|
||||
GhostWeaver::on_initialize(12);
|
||||
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_none());
|
||||
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 14);
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 14);
|
||||
System::set_block_number(14);
|
||||
GhostWeaver::on_initialize(14);
|
||||
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_some());
|
||||
});
|
||||
}
|
||||
@ -170,11 +168,10 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
||||
let networks = vec![(network_id, network_data, Default::default())];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2);
|
||||
System::set_block_number(2);
|
||||
|
||||
let att = AttestationContext::default()
|
||||
.with_current_block(LOCK_BLOCK_EXPIRATION + 1)
|
||||
.with_current_block(1)
|
||||
.with_network_id(network_id)
|
||||
.with_authority_index(0)
|
||||
.build_block_attestation(100);
|
||||
@ -187,9 +184,7 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
||||
signature: valid_sig,
|
||||
};
|
||||
|
||||
let validity =
|
||||
GhostWeaver::validate_unsigned(TransactionSource::External, &call);
|
||||
|
||||
let validity = GhostWeaver::validate_unsigned(TransactionSource::External, &call);
|
||||
assert!(validity.is_ok());
|
||||
let valid_info = validity.unwrap();
|
||||
|
||||
@ -204,9 +199,7 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
||||
signature: invalid_sig,
|
||||
};
|
||||
|
||||
let spam_validity =
|
||||
GhostWeaver::validate_unsigned(TransactionSource::External, &spam_call);
|
||||
|
||||
let spam_validity = GhostWeaver::validate_unsigned(TransactionSource::External, &spam_call);
|
||||
assert_eq!(
|
||||
spam_validity,
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner).into())
|
||||
@ -247,9 +240,6 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
ext.register_extension(TransactionPoolExt::new(pool));
|
||||
|
||||
ext.execute_with(|| {
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 2);
|
||||
|
||||
let network_id_encoded = evm_network_id.encode();
|
||||
|
||||
let mut endpoint_key = b"ghost-weaver::".to_vec();
|
||||
@ -262,7 +252,6 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
|
||||
let target_endpoint = b"http://localhost:8545".to_vec();
|
||||
let rpc_endpoints: Vec<Vec<u8>> = vec![target_endpoint.clone()];
|
||||
|
||||
sp_io::offchain::local_storage_set(
|
||||
sp_core::offchain::StorageKind::PERSISTENT,
|
||||
&endpoint_key,
|
||||
@ -284,7 +273,7 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
);
|
||||
|
||||
sp_io::crypto::sr25519_generate(
|
||||
sp_core::crypto::KeyTypeId(*b"wevr"),
|
||||
sp_core::crypto::KeyTypeId(*b"weav"),
|
||||
Some(b"//Alice".to_vec()),
|
||||
);
|
||||
});
|
||||
@ -299,8 +288,8 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
("Accept".into(), "application/json".into()),
|
||||
("Content-Type".into(), "application/json".into()),
|
||||
],
|
||||
body: b"{\"id\":21,\"jsonrpc\":\"2.0\",\"method\":\"getblockcount\"}".to_vec(),
|
||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":21,\"result\":960127}".to_vec()),
|
||||
body: b"{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"getblockcount\"}".to_vec(),
|
||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":960127}".to_vec()),
|
||||
sent: true,
|
||||
..Default::default()
|
||||
});
|
||||
@ -314,16 +303,17 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
("X-Custom-Provider".into(), "GhostWeaverNode".into()),
|
||||
("Authorization".into(), "Bearer new-api-token-123".into()),
|
||||
],
|
||||
body: b"{\"id\":22,\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\"}".to_vec(),
|
||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":22,\"result\":\"0x1873a84\"}".to_vec()),
|
||||
body: b"{\"id\":2,\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\"}".to_vec(),
|
||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":\"0x1873a84\"}".to_vec()),
|
||||
sent: true,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||
System::set_block_number(1u64);
|
||||
GhostWeaver::offchain_worker(1u64);
|
||||
System::set_block_number(2u64);
|
||||
|
||||
let state = pool_state.read();
|
||||
assert_eq!(state.transactions.len(), 1);
|
||||
@ -344,13 +334,14 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
assert_eq!(curr_utxo_block, 960127);
|
||||
|
||||
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_none());
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3u64);
|
||||
GhostWeaver::on_initialize(3u64);
|
||||
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_some());
|
||||
});
|
||||
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||
System::set_block_number(2u64);
|
||||
GhostWeaver::offchain_worker(2u64);
|
||||
System::set_block_number(3u64);
|
||||
|
||||
let state = pool_state.read();
|
||||
assert_eq!(state.transactions.len(), 2);
|
||||
@ -371,8 +362,7 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
assert_eq!(curr_evm_block, 25639556);
|
||||
|
||||
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_none());
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3u64);
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 4u64);
|
||||
GhostWeaver::on_initialize(4u64);
|
||||
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_some());
|
||||
});
|
||||
}
|
||||
@ -382,9 +372,6 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
let evm_network_id = 1u32;
|
||||
let utxo_network_id = 69u32;
|
||||
|
||||
let median_utxo_block = 960129;
|
||||
let median_evm_block = 25639556;
|
||||
|
||||
let pair = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
||||
|
||||
let new_evm_network_data = NetworkDataBuilder::default()
|
||||
@ -419,12 +406,11 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
ext.register_extension(TransactionPoolExt::new(pool));
|
||||
|
||||
ext.execute_with(|| {
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 2);
|
||||
|
||||
let tapestry_draft = TapestryDraftBuilder::<crate::ExternalBlockNumber, u32>::default();
|
||||
let evm_tapestry_draft = tapestry_draft.with_median_external(median_evm_block).build();
|
||||
let utxo_tapestry_draft = tapestry_draft.with_median_external(median_utxo_block).build();
|
||||
|
||||
let evm_tapestry_draft = tapestry_draft.with_median_external(25639556).build();
|
||||
|
||||
let utxo_tapestry_draft = tapestry_draft.with_median_external(960129).build();
|
||||
|
||||
CurrentWeavingSession::<TestRuntime>::insert(&evm_network_id, evm_session);
|
||||
CurrentWeavingSession::<TestRuntime>::insert(&utxo_network_id, utxo_session);
|
||||
@ -465,7 +451,7 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
);
|
||||
|
||||
sp_io::crypto::sr25519_generate(
|
||||
sp_core::crypto::KeyTypeId(*b"wevr"),
|
||||
sp_core::crypto::KeyTypeId(*b"weav"),
|
||||
Some(b"//Alice".to_vec()),
|
||||
);
|
||||
});
|
||||
@ -480,8 +466,8 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
("Accept".into(), "application/json".into()),
|
||||
("Content-Type".into(), "application/json".into()),
|
||||
],
|
||||
body: b"{\"id\":21,\"jsonrpc\":\"2.0\",\"method\":\"getblockhash\",\"params\":[960129]}".to_vec(),
|
||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":21,\"result\":\"0000000000000000000091c72779c83d76dfa8149e950f3a5287377a9708d5c1\"}".to_vec()),
|
||||
body: b"{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"getblockhash\",\"params\":[960129]}".to_vec(),
|
||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0000000000000000000091c72779c83d76dfa8149e950f3a5287377a9708d5c1\"}".to_vec()),
|
||||
sent: true,
|
||||
..Default::default()
|
||||
});
|
||||
@ -496,16 +482,17 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
("Authorization".into(), "Bearer new-api-token-123".into()),
|
||||
],
|
||||
// Match the EXACT field order: data first, then to
|
||||
body: b"{\"id\":22,\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{\"data\":\"0x00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000001873a84\",\"to\":\"0x02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9\"},\"latest\"]}".to_vec(),
|
||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":22,\"result\":\"0xf72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d0000000000000000000000000000000000000000000000000000000000000046\"}".to_vec()),
|
||||
body: b"{\"id\":2,\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{\"data\":\"0x00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000001873a84\",\"to\":\"0x02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9\"},\"latest\"]}".to_vec(),
|
||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":\"0xf72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d0000000000000000000000000000000000000000000000000000000000000046\"}".to_vec()),
|
||||
sent: true,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||
System::set_block_number(1u64);
|
||||
GhostWeaver::offchain_worker(1u64);
|
||||
System::set_block_number(2u64);
|
||||
|
||||
let state = pool_state.read();
|
||||
assert_eq!(state.transactions.len(), 1);
|
||||
@ -531,15 +518,14 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
GhostWeaver::on_initialize(3u64);
|
||||
let curr_state = LoomStates::<TestRuntime>::get(&utxo_network_id, &utxo_session);
|
||||
|
||||
assert_eq!(prev_state.root_hash, H256::default());
|
||||
assert_eq!(curr_state.root_hash, block_hash);
|
||||
assert_eq!(prev_state.at_block, 0);
|
||||
assert_eq!(curr_state.at_block, median_utxo_block);
|
||||
assert_eq!(prev_state, H256::default());
|
||||
assert_eq!(curr_state, block_hash);
|
||||
});
|
||||
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||
System::set_block_number(2u64);
|
||||
GhostWeaver::offchain_worker(2u64);
|
||||
System::set_block_number(3u64);
|
||||
|
||||
let state = pool_state.read();
|
||||
assert_eq!(state.transactions.len(), 2);
|
||||
@ -556,20 +542,17 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
assert_eq!(curr_weaving_state.next_session, evm_session + 1);
|
||||
|
||||
let bytes = hex::decode("f72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d")
|
||||
.expect("EVM block hash should be valid");
|
||||
.expect("UTXO block hash should be valid");
|
||||
let block_hash = H256::from_slice(&bytes);
|
||||
|
||||
assert_eq!(curr_weaving_state.hash, block_hash);
|
||||
|
||||
let prev_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3u64);
|
||||
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 4u64);
|
||||
GhostWeaver::on_initialize(4u64);
|
||||
let curr_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
||||
|
||||
assert_eq!(prev_state.root_hash, H256::default());
|
||||
assert_eq!(curr_state.root_hash, block_hash);
|
||||
assert_eq!(prev_state.at_block, 0);
|
||||
assert_eq!(curr_state.at_block, median_evm_block);
|
||||
assert_eq!(prev_state, H256::default());
|
||||
assert_eq!(curr_state, block_hash);
|
||||
});
|
||||
}
|
||||
|
||||
@ -577,7 +560,7 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
fn should_successfully_pull_evm_thread_and_mint_currency() {
|
||||
let pair = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
||||
|
||||
let network_id = 11155111;
|
||||
let network_id = 1;
|
||||
let network_data = NetworkDataBuilder::default()
|
||||
.with_network_type(NetworkType::Evm)
|
||||
.build();
|
||||
@ -585,87 +568,207 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
|
||||
let authorities = vec![pair.clone()];
|
||||
let networks = vec![(network_id, network_data, Default::default())];
|
||||
|
||||
// Contract address: 0x7fec11e652f4d54e8cf11c4b52c360380332f2bd
|
||||
// Contract address: 0x9a52C28dA655b69d8ddc430d6ebD04630BA0e845
|
||||
//
|
||||
// three inserts
|
||||
// 69 sfJ9hc4A7r578XM35nd48B3FWcd33XjpVnAbGC5tvtwthMWdU - 0xc477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e
|
||||
// 420 sfDxNicCEPts6CVttVMPCs2eoymDpQahu1GUVyGPWu6dhwADJ - 0x0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e
|
||||
// 1337 sfH6zJ63fcxrFAZ1RmiHbxgy2t3sEufY26WdsBSS359AzJd4w - 0x962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b
|
||||
|
||||
// https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract
|
||||
// getRoot: atBlock 11716130, globalIndexes from 0 to 2
|
||||
// https://sepolia.etherscan.io/address/0x81acdf2da6b50d806c96aecd9a498a5359e373c0#readContract
|
||||
// getRoot: atBlock 11660400, globalIndexes from 0 to 2
|
||||
let inserts = vec![
|
||||
(
|
||||
0,
|
||||
hex::decode("c477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e").expect("Bytes32 from EVM should be valid"),
|
||||
hex::decode("c477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e")
|
||||
.expect("Bytes32 from EVM should be valid"),
|
||||
69u64,
|
||||
vec![
|
||||
H256::from_slice(&hex::decode("2d931b11b1652669a04e7b5b50418f5e1e2fabb6791dabc9a196e719ad5cf9c6").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("9f00b99751b7ccea1903949210408edb3ce50343985708c36a0b1d44e0a7628c").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"675a2e7b05b8b3932cd0faf88f1bc29767b7462667f56d051b8d5325bda0ee73",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"da1fbdfefa1e9aedfedcfc48fb17cb0e731529f7a3695114e0a9caa1989dd420",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
],
|
||||
vec![H256::from_slice(
|
||||
&hex::decode("f494b2065ca61f2af007a3dd5f1f3d228a3ad09f4f7b7c5ef3eeb3aee6718ee2").expect("Slot should be valid hex"),
|
||||
&hex::decode("350a78f78c810898b7c60ddba671543bfbe683ffb0ac393df0e132f607b5f738")
|
||||
.expect("Slot should be valid hex"),
|
||||
)],
|
||||
),
|
||||
(
|
||||
1,
|
||||
hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e").expect("Bytes32 from EVM should be valid"),
|
||||
hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e")
|
||||
.expect("Bytes32 from EVM should be valid"),
|
||||
420u64,
|
||||
vec![
|
||||
H256::from_slice(&hex::decode("7d831a4be9e37572687117870c3f96669a66bf07971e4fd705a36a0a4d6365b0").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("9f00b99751b7ccea1903949210408edb3ce50343985708c36a0b1d44e0a7628c").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"c5354289f0397c916949373043eb1d5ea99447f67fe014324d96c58ef02a2d11",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"da1fbdfefa1e9aedfedcfc48fb17cb0e731529f7a3695114e0a9caa1989dd420",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
],
|
||||
vec![H256::from_slice(
|
||||
&hex::decode("f6182b8c276793f53d1820ad0405665177516e46e40af45e0dfea73c39a2306e").expect("Slot should be valid hex"),
|
||||
&hex::decode("2e474dabf492786b3505d7b7cf0bf07c9dbce92c91982fa7344c77e24fd4310d")
|
||||
.expect("Slot should be valid hex"),
|
||||
)],
|
||||
),
|
||||
(
|
||||
2,
|
||||
hex::decode("962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b").expect("Bytes32 from EVM should be valid"),
|
||||
hex::decode("962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b")
|
||||
.expect("Bytes32 from EVM should be valid"),
|
||||
1337u64,
|
||||
vec![
|
||||
H256::from_slice(&hex::decode("f39a869f62e75cf5f0bf914688a6b289caf2049435d8e68c5c5e6d05e44913f3").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("385de173dc8295d4153b2de3bd705dd96556c8c316a996b3e56adce0970ffa36").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")),
|
||||
H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"f39a869f62e75cf5f0bf914688a6b289caf2049435d8e68c5c5e6d05e44913f3",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"e0090094ce1d7af8a81ba78bef4b137c1ab32d20d5487224a9f8df95b516c1e4",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
H256::from_slice(
|
||||
&hex::decode(
|
||||
"de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040",
|
||||
)
|
||||
.expect("Proof should be valid"),
|
||||
),
|
||||
],
|
||||
vec![H256::from_slice(
|
||||
&hex::decode("2f52c7d2d3f4167c436f3b6cc0a7d944a45846ba87f74998100b83122d5eb0ad").expect("Slot should be valid hex"),
|
||||
&hex::decode("bde870fce92d701a7a5d6f63003e1cd2cb61c3266fc1be256844b8ca61d9c9ab")
|
||||
.expect("Slot should be valid hex"),
|
||||
)],
|
||||
),
|
||||
];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
GhostWeaver::on_initialize(1);
|
||||
|
||||
// https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract
|
||||
// getRoot: session 0, atBlock 11716130
|
||||
// https://sepolia.etherscan.io/address/0x81acdf2da6b50d806c96aecd9a498a5359e373c0#readContract
|
||||
// getRoot: session 0, atBlock 11660400
|
||||
let session = 0;
|
||||
let root_string =
|
||||
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129")
|
||||
hex::decode("28d1e6b476b03a464f74d531d532572db29d6b57349e4f17f84e92843f6c4ee7")
|
||||
.expect("Root hex should be valid");
|
||||
|
||||
let expected_root = H256::from_slice(&root_string);
|
||||
let expected_loom_state = LoomState { at_block: 420, root_hash: expected_root };
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_loom_state);
|
||||
|
||||
let mut total_issuance = 0;
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root);
|
||||
|
||||
for insert in inserts.into_iter() {
|
||||
let index_usize = insert.0 as crate::ThreadId;
|
||||
@ -692,9 +795,8 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
|
||||
);
|
||||
|
||||
let thread_info = ThreadProof::EvmThreadProof(evm_thread_proof);
|
||||
let pulled_thread_key = thread_info.get_unique_key(session, network_id);
|
||||
let pulled_thread_key = thread_info.get_unique_key(session);
|
||||
|
||||
assert_eq!(Balances::total_issuance(), total_issuance);
|
||||
assert_eq!(Balances::free_balance(&receiver_account), 0);
|
||||
assert!(!PulledThreads::<TestRuntime>::contains_key(
|
||||
&pulled_thread_key
|
||||
@ -704,7 +806,8 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
|
||||
network_id,
|
||||
session,
|
||||
thread_info
|
||||
).is_ok());
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
assert!(PulledThreads::<TestRuntime>::contains_key(
|
||||
&pulled_thread_key
|
||||
@ -712,15 +815,12 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
|
||||
|
||||
let expected_commission = 0u64;
|
||||
let expected_pure_amount = transfer_amount - expected_commission;
|
||||
total_issuance = total_issuance.saturating_add(expected_pure_amount);
|
||||
|
||||
assert_eq!(Balances::total_issuance(), total_issuance);
|
||||
assert_eq!(
|
||||
Balances::free_balance(&receiver_account),
|
||||
expected_pure_amount
|
||||
);
|
||||
|
||||
|
||||
System::assert_last_event(RuntimeEvent::GhostWeaver(Event::ThreadPulled {
|
||||
pulled_thread_key,
|
||||
network_id,
|
||||
@ -776,8 +876,7 @@ fn should_successfully_pull_utxo_thread_and_mint_currency() {
|
||||
.expect("Bitcoin Root hex should be valid");
|
||||
|
||||
let expected_root = H256::from_slice(&block_hash);
|
||||
let expected_loom_state = LoomState { at_block: 420, root_hash: expected_root };
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_loom_state);
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root);
|
||||
|
||||
let expected_receiver_bytes = hex::decode("1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e").unwrap();
|
||||
let mut receiver_raw = [0u8; 32];
|
||||
@ -788,7 +887,7 @@ fn should_successfully_pull_utxo_thread_and_mint_currency() {
|
||||
|
||||
let utxo_thread_proof = UtxoThreadProof::new(payload.0, payload.1, payload.2);
|
||||
let thread_info = ThreadProof::UtxoThreadProof(utxo_thread_proof);
|
||||
let pulled_thread_key = thread_info.get_unique_key(session, network_id);
|
||||
let pulled_thread_key = thread_info.get_unique_key(session);
|
||||
|
||||
assert_eq!(Balances::free_balance(&receiver_account), 0);
|
||||
assert!(!PulledThreads::<TestRuntime>::contains_key(
|
||||
@ -823,117 +922,6 @@ fn should_successfully_pull_utxo_thread_and_mint_currency() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_successfully_pull_utxo_thread_and_reject_nominal_varint_encoding() {
|
||||
let pair = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
||||
let incoming_share = 0;
|
||||
|
||||
let network_id = 69;
|
||||
let network_data = NetworkDataBuilder::default()
|
||||
.with_network_type(NetworkType::Utxo)
|
||||
.with_incoming_share(incoming_share)
|
||||
.with_gatekeeper(
|
||||
// Transaction: https://blockstream.info/tx/4a3fdd9ebb30b9c6df05d4199f8474b2f0c795d1f40a58d0d73342fc666b4a2e
|
||||
hex::decode("4635b1794a22bfbe6c5c5eba17b693f4aaf0e348")
|
||||
.expect("Bytes32 from UTXO should be valid"),
|
||||
)
|
||||
.build();
|
||||
|
||||
let authorities = vec![pair.clone()];
|
||||
let networks = vec![(network_id, network_data, Default::default())];
|
||||
|
||||
// Real world tx at block #481838
|
||||
// Block https://blockstream.info/block/0000000000000000011bdccb39e19e942a60edffdccd9779653c5b46b337904a
|
||||
// Transaction: https://blockstream.info/tx/4a3fdd9ebb30b9c6df05d4199f8474b2f0c795d1f40a58d0d73342fc666b4a2e
|
||||
|
||||
let payload = (
|
||||
// curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "gettxoutproof", "params": [["4a3fdd9ebb30b9c6df05d4199f8474b2f0c795d1f40a58d0d73342fc666b4a2e"], "0000000000000000011bdccb39e19e942a60edffdccd9779653c5b46b337904a"]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
|
||||
hex::decode("00000020375a14cfcf5730daa8ff8d7a5bd2cf59fba797e289c2e0000000000000000000529cd017146361b57e6b7353b16d8d38d32f92ee842039dd779d35bfbfa2f3e53f649e59e93c01187900ea9fb40600000cfbd7b718845d123b1ae1a7fd3bce9c97acba097dc912c4ac67a920395db07ba4eef685960869ba70e0ca38890565c97dc11f1d7ae538e7b509069f81e38eff1a2e4a6b66fc4233d7d0580af4d195c7f0b274849f19d405dfc6b930bb9edd3f4a4c1f1e9fa3a336c50e8ea16039e4db4bef7ff5946e3a019937bdf626c2336d0e3926a83a575218f84e6dc55ffb9d0997a41e4b4d5425a85f22160c9f52362a95021a573ff96bb429bd80a8ec9dcb899971553efe91b6a0fe57c4694c3e8da8dc7f1babd514f2746da1ed06f08664baed853c334e0a3917d0c859b19ee14f448f77e624822070db3b606d5092027ca9ecf7e0243e6c151081021ebb3ddcdd28c1b8f9fdcffebd1962590477675f3d29d52602a1e7e941f772a3bbff42cf2eb6e74a1124bf424f767e294ae6253a21602c7c6b0381743dd6dcd57b025983e0e34375b24f67ac8beb00713d2f70594bbf797d5d94c061cb9965e6458f2f017f983d7ce37361fa13fda372f595dc1f22895ab93339457c72c480fed1c4d1164a242303ff3600").expect("Bytes32 from UTXO should be valid"),
|
||||
// curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "getrawtransaction", "params": ["4a3fdd9ebb30b9c6df05d4199f8474b2f0c795d1f40a58d0d73342fc666b4a2e", false]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
|
||||
hex::decode("010000000299a43fae581f80baf44e021ddf7b11995f184db282d6e48c22248b9fe79c43bb010000008b483045022100e9db01784dcd879c65d66127c2d52a4f9244321d15796893d6dccadaa1146e3d02203d9bb80f8df8b66692d3d9517f7cbb898d7cc40a30b175432322e1956c9b973a0141048097e4f8bb8ee104d5c2ece11d42f7e4719df8ddba459ecadecaba87d233c81a3c14830371392dd8ed030ef970450c0b7af48d9db4ba20c046896481602eb9dbffffffffb3fd05bc6000a5a0384e9a613d452e9307568df0a964907068e00403a0a0e09e020000006a47304402205bb1cbad4b29421648c1e22cac32a56aa06c933fe655559823fffb71ffebbc0b022021648d970560aa5b2031560b52a0fd06305995a58a457663324c18c1a9b0bd0b8121020d6e50b2660af27933c42bc1395fe93df90ffac5e2a989f6a134919fb8cf8075ffffffff030000000000000000296a2769642b5bb666ac1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e7c150000000000001976a914c1c69d91a5719a23ba2094d89a4df3eadfa4aef788acefea2309000000001976a9144635b1794a22bfbe6c5c5eba17b693f4aaf0e34888ac00000000").expect("Bytes32 from UTXO should be valid"),
|
||||
vec![
|
||||
// curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "getblockheader", "params": ["000000000000000000e7da64065cc23d5c5a5aa402f088aaaf37c5fe1c3b6b92", false]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
|
||||
hex::decode("000000204a9037b3465b3c657997cddcffed602a949ee139cbdc1b010000000000000000669c3e2472384bc95993f154aada38d6b2113d8d32069e32e2724ba40915a1802a669e59e93c011801c8c735").expect("Bytes32 from UTXO should be valid"),
|
||||
// curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "getblockheader", "params": ["00000000000000000063da6d9362c0ac3b87877d1c5ad7afd5bd706571d5b393", false]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
|
||||
hex::decode("02000020926b3b1cfec537afaa88f002a45a5a5c3dc25c0664dae7000000000000000000af0f270bf3f868d47089f395197809c360f1506636c960d96afed68bbd72d0b4496d9e59e93c01183ac94b67").expect("Bytes32 from UTXO should be valid"),
|
||||
// curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "getblockheader", "params": ["000000000000000000ec6063eb743366264368be7ff5021727682cb518963026", false]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
|
||||
hex::decode("0000002093b3d5716570bdd5afd75a1c7d87873bacc062936dda630000000000000000009ab437e7c66b10a59b67127f290d24f381aba4e03d5e16c062a356eea4d608dea56d9e59e93c0118264f310e").expect("Bytes32 from UTXO should be valid"),
|
||||
],
|
||||
);
|
||||
|
||||
let encodings = vec![
|
||||
vec![0x02], // canonical
|
||||
vec![0xFD, 0x02, 0x00], // non-minimal 3 bytes
|
||||
vec![0xFE, 0x02, 0x00, 0x00, 0x00], // non-minimal 5 bytes
|
||||
vec![0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // non-minimal 9 bytes
|
||||
];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
let session = 0;
|
||||
let block_hash =
|
||||
hex::decode("000000000000000000ec6063eb743366264368be7ff5021727682cb518963026")
|
||||
.expect("Bitcoin Root hex should be valid");
|
||||
|
||||
let expected_root = H256::from_slice(&block_hash);
|
||||
let expected_loom_state = LoomState { at_block: 420, root_hash: expected_root };
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_loom_state);
|
||||
|
||||
let expected_receiver_bytes = hex::decode("1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e").unwrap();
|
||||
let mut receiver_raw = [0u8; 32];
|
||||
receiver_raw.copy_from_slice(&expected_receiver_bytes);
|
||||
|
||||
let receiver_account = sp_runtime::AccountId32::from(receiver_raw);
|
||||
let transfer_amount: u64 = 153348847;
|
||||
let mut expected_pure_amount: u64 = 0;
|
||||
|
||||
for (idx, enc) in encodings.iter().enumerate() {
|
||||
let mut variant = Vec::with_capacity(payload.1.len() + enc.len() - 1);
|
||||
variant.extend_from_slice(&payload.1[0..4]);
|
||||
variant.extend_from_slice(&enc);
|
||||
variant.extend_from_slice(&payload.1[5..]);
|
||||
|
||||
let utxo_thread_proof = UtxoThreadProof::new(payload.0.clone(), variant, payload.2.clone());
|
||||
let thread_info = ThreadProof::UtxoThreadProof(utxo_thread_proof);
|
||||
let pulled_thread_key = thread_info.get_unique_key(session, network_id);
|
||||
|
||||
assert_eq!(Balances::free_balance(&receiver_account), expected_pure_amount);
|
||||
assert!(!PulledThreads::<TestRuntime>::contains_key(
|
||||
&pulled_thread_key
|
||||
));
|
||||
|
||||
let pull_result = GhostWeaver::pull_thread(
|
||||
RuntimeOrigin::none(),
|
||||
network_id,
|
||||
session,
|
||||
thread_info
|
||||
);
|
||||
|
||||
if idx == 0 {
|
||||
assert!(pull_result.is_ok());
|
||||
assert!(PulledThreads::<TestRuntime>::contains_key(&pulled_thread_key));
|
||||
|
||||
let curve_share = Perbill::from_parts(incoming_share).mul_ceil(transfer_amount);
|
||||
expected_pure_amount += transfer_amount.saturating_sub(curve_share);
|
||||
|
||||
assert_eq!(Balances::free_balance(&receiver_account), expected_pure_amount);
|
||||
|
||||
System::assert_last_event(RuntimeEvent::GhostWeaver(Event::ThreadPulled {
|
||||
pulled_thread_key,
|
||||
network_id,
|
||||
receiver: receiver_account.clone(),
|
||||
amount: transfer_amount,
|
||||
}));
|
||||
} else {
|
||||
assert!(pull_result.is_err());
|
||||
assert!(!PulledThreads::<TestRuntime>::contains_key(&pulled_thread_key));
|
||||
assert_eq!(Balances::free_balance(&receiver_account), expected_pure_amount);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(Balances::free_balance(&receiver_account), transfer_amount);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
||||
let pair1 = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
||||
@ -950,9 +938,7 @@ fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
||||
let networks = vec![(network_id, new_network_data, 0u64)];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
let current_substrate_block = LOCK_BLOCK_EXPIRATION + 10;
|
||||
|
||||
GhostWeaver::on_initialize(current_substrate_block);
|
||||
let current_substrate_block = 10;
|
||||
System::set_block_number(current_substrate_block + 1);
|
||||
|
||||
let tapestry_draft = TapestryDraftBuilder::default()
|
||||
@ -1000,96 +986,8 @@ fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
||||
GhostWeaver::on_initialize(current_substrate_block);
|
||||
|
||||
let saved_loom = LoomStates::<TestRuntime>::get(&network_id, current_session);
|
||||
assert_ne!(saved_loom.root_hash, target_hash);
|
||||
assert_eq!(saved_loom.at_block, 0);
|
||||
|
||||
let updated_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
||||
assert_eq!(updated_session, current_session);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn on_initialize_should_update_at_block_when_threshold_reached_with_same_hash() {
|
||||
let pair1 = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
||||
let pair2 = AuthorityPair::from_string("//Bob", None).expect("Should be valid seed");
|
||||
let pair3 = AuthorityPair::from_string("//Charlie", None).expect("Should be valid seed");
|
||||
|
||||
let network_id = 1;
|
||||
|
||||
let new_network_data = NetworkDataBuilder::default()
|
||||
.with_network_type(NetworkType::Evm)
|
||||
.build();
|
||||
|
||||
let authorities = vec![pair1.clone(), pair2.clone(), pair3.clone()];
|
||||
let networks = vec![(network_id, new_network_data, 0u64)];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
let current_substrate_block = LOCK_BLOCK_EXPIRATION + 10;
|
||||
let current_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
||||
|
||||
let target_hash = H256::repeat_byte(0xAA);
|
||||
LoomStates::<TestRuntime>::insert(&network_id, ¤t_session, crate::LoomState {
|
||||
root_hash: target_hash,
|
||||
at_block: 0,
|
||||
});
|
||||
|
||||
System::set_block_number(current_substrate_block);
|
||||
GhostWeaver::on_initialize(current_substrate_block);
|
||||
|
||||
let tapestry_draft = TapestryDraftBuilder::default()
|
||||
.with_current_block(current_substrate_block)
|
||||
.with_block_delay(5u32)
|
||||
.with_median_external(100)
|
||||
.build();
|
||||
|
||||
TapestryDrafts::<TestRuntime>::insert(&network_id, tapestry_draft);
|
||||
|
||||
let attestation = AttestationContext::default()
|
||||
.with_current_block(current_substrate_block)
|
||||
.with_network_id(network_id)
|
||||
.with_weaving_session(current_session);
|
||||
|
||||
let hash_att1 = attestation
|
||||
.with_authority_index(0)
|
||||
.build_hash_attestation(target_hash, current_session);
|
||||
|
||||
let hash_att2 = attestation
|
||||
.with_authority_index(1)
|
||||
.build_hash_attestation(target_hash, current_session);
|
||||
|
||||
let hash_att3 = attestation
|
||||
.with_authority_index(2)
|
||||
.build_hash_attestation(target_hash, current_session);
|
||||
|
||||
assert!(GhostWeaver::weave_weft(
|
||||
RuntimeOrigin::none(),
|
||||
hash_att1,
|
||||
pair1.sign(&hash_att1.encode())
|
||||
)
|
||||
.is_ok());
|
||||
assert!(GhostWeaver::weave_weft(
|
||||
RuntimeOrigin::none(),
|
||||
hash_att2,
|
||||
pair2.sign(&hash_att2.encode())
|
||||
)
|
||||
.is_ok());
|
||||
assert!(GhostWeaver::weave_weft(
|
||||
RuntimeOrigin::none(),
|
||||
hash_att3,
|
||||
pair3.sign(&hash_att3.encode())
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
let state_before = WeavingStates::<TestRuntime>::get(&network_id);
|
||||
assert_eq!(state_before.count, 3);
|
||||
assert_eq!(state_before.hash, target_hash);
|
||||
|
||||
GhostWeaver::on_initialize(current_substrate_block);
|
||||
|
||||
let saved_loom = LoomStates::<TestRuntime>::get(&network_id, current_session);
|
||||
|
||||
assert_eq!(saved_loom.root_hash, target_hash);
|
||||
assert_eq!(saved_loom.at_block, 100);
|
||||
assert_ne!(saved_loom, target_hash);
|
||||
assert_eq!(saved_loom, saved_loom);
|
||||
|
||||
let updated_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
||||
assert_eq!(updated_session, current_session);
|
||||
|
||||
@ -14,6 +14,7 @@ use ghost_helpers::{
|
||||
merkle_tree::verify_tree_proof,
|
||||
SubstrateBlake2Hasher, SubstrateKeccakHasher, UtxoSha2Hasher,
|
||||
};
|
||||
use ghost_traits::hashing::GhostHasher;
|
||||
|
||||
use crate::{ExternalBlockNumber, ThreadId, WeavingSession};
|
||||
|
||||
@ -36,43 +37,22 @@ const PROTOCOL_PREFIX: [u8; 7] = [0x69, 0x64, 0x2b, 0x5b, 0xb6, 0x66, 0xac];
|
||||
const PROTOCOL_PREFIX: [u8; 7] = [0x47, 0x48, 0x53, 0x54, 0x74, 0x6F, 0x3A];
|
||||
|
||||
pub enum WeavingOk<NetworkId> {
|
||||
Skipped(NetworkId),
|
||||
Block(ExternalBlockNumber, u32, NetworkId),
|
||||
Block(ExternalBlockNumber, NetworkId),
|
||||
Hash(ExternalBlockNumber, H256, WeavingSession, NetworkId),
|
||||
}
|
||||
|
||||
impl<NetworkId> core::fmt::Debug for WeavingOk<NetworkId>
|
||||
impl<NetworkId> core::fmt::Display for WeavingOk<NetworkId>
|
||||
where
|
||||
NetworkId: core::fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::Skipped(network_id) => write!(fmt, "Submission step skipped for network: {:?} based on probability distribution.", network_id),
|
||||
Self::Block(block, count, network_id) => write!(fmt, "Verified block height #{:?} for network: {:?} based on {} parsed requests.", block, network_id, count),
|
||||
Self::Hash(block, hash, next_session, network_id) => write!(fmt, "Extracted Merkle Root {:?} (next session is {:?}) from block #{:?} for network: {:?}.", hash, next_session, block, network_id),
|
||||
Self::Block(block, network_id) => write!(fmt, "Verified block height #{:?} found for network: {:?}.", block, network_id),
|
||||
Self::Hash(block, hash, next_session, network_id) => write!(fmt, "Extracted Merkle Root {:?} where next session is {:?}; from block #{:?} for network: {:?}.", hash, next_session, block, network_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default,
|
||||
RuntimeDebug,
|
||||
Clone,
|
||||
Copy,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Encode,
|
||||
Decode,
|
||||
TypeInfo,
|
||||
MaxEncodedLen,
|
||||
)]
|
||||
pub struct LoomState {
|
||||
pub at_block: ExternalBlockNumber,
|
||||
pub root_hash: H256,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default,
|
||||
RuntimeDebug,
|
||||
@ -308,40 +288,31 @@ where
|
||||
Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>,
|
||||
u64: UniqueSaturatedInto<Balance>,
|
||||
{
|
||||
pub fn verify_thread_proof<NetworkId>(
|
||||
&self,
|
||||
root_hash: H256,
|
||||
network_id: NetworkId,
|
||||
gatekeeper: &[u8]
|
||||
) -> Option<(AccountId32, Balance)>
|
||||
where
|
||||
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
||||
{
|
||||
pub fn is_evm_proof_correct(&self) -> bool {
|
||||
match self {
|
||||
Self::UtxoThreadProof(utxo_thread) => {
|
||||
utxo_thread.verify_thread_proof(root_hash, gatekeeper)
|
||||
},
|
||||
Self::EvmThreadProof(evm_thread) => {
|
||||
evm_thread.verify_thread_proof(root_hash, network_id)
|
||||
},
|
||||
Self::EvmThreadProof(_) => true,
|
||||
Self::UtxoThreadProof(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_unique_key<NetworkId>(
|
||||
&self,
|
||||
session: WeavingSession,
|
||||
network_id: NetworkId,
|
||||
) -> H256
|
||||
where
|
||||
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
||||
{
|
||||
pub fn is_utxo_proof_correct(&self) -> bool {
|
||||
match self {
|
||||
Self::EvmThreadProof(thread_info) => {
|
||||
thread_info.get_unique_key(session, network_id)
|
||||
},
|
||||
Self::UtxoThreadProof(utxo_thread) => {
|
||||
utxo_thread.get_unique_key(network_id)
|
||||
},
|
||||
Self::UtxoThreadProof(_) => true,
|
||||
Self::EvmThreadProof(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_thread_proof(&self, root_hash: H256, gatekeeper: &[u8]) -> Option<(AccountId32, Balance)> {
|
||||
match self {
|
||||
Self::UtxoThreadProof(utxo_thread) => utxo_thread.verify_thread_proof(root_hash, gatekeeper),
|
||||
Self::EvmThreadProof(evm_thread) => evm_thread.verify_thread_proof(root_hash),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_unique_key(&self, session: WeavingSession) -> H256 {
|
||||
match self {
|
||||
Self::EvmThreadProof(thread_info) => thread_info.get_unique_key(session),
|
||||
Self::UtxoThreadProof(utxo_thread) => utxo_thread.get_unique_key(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -360,20 +331,11 @@ impl<Balance> EvmThreadProof<Balance>
|
||||
where
|
||||
Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>,
|
||||
{
|
||||
pub fn verify_thread_proof<NetworkId>(
|
||||
&self,
|
||||
root_hash: H256,
|
||||
network_id: NetworkId,
|
||||
) -> Option<(AccountId32, Balance)>
|
||||
where
|
||||
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
||||
{
|
||||
pub fn verify_thread_proof(&self, root_hash: H256) -> Option<(AccountId32, Balance)> {
|
||||
if EVM_MERKLE_DEPTH as usize != self.proof.len() { return None; }
|
||||
|
||||
let preimage_hash = self.get_preimage_hash(network_id)?;
|
||||
|
||||
let proof_valid = verify_tree_proof::<SubstrateKeccakHasher, _>(
|
||||
&preimage_hash.to_fixed_bytes(),
|
||||
&self.get_preimage_slice().to_fixed_bytes(),
|
||||
self.proof.as_ref(),
|
||||
root_hash,
|
||||
self.proof_index,
|
||||
@ -384,80 +346,41 @@ where
|
||||
Some((self.receiver.clone(), self.amount))
|
||||
}
|
||||
|
||||
fn get_preimage_hash<NetworkId>(&self, network_id: NetworkId) -> Option<H256>
|
||||
where
|
||||
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
||||
{
|
||||
fn get_preimage_slice(&self) -> H256 {
|
||||
let slot_index_usize: usize = self.slot_index.unique_saturated_into();
|
||||
|
||||
self.slots.get(slot_index_usize)
|
||||
.filter(|&&provided_hash| {
|
||||
provided_hash == self.compute_arguments_hash(network_id)
|
||||
(slot_index_usize < self.slots.len())
|
||||
.then(|| {
|
||||
self.slots
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, &preimage)| {
|
||||
if index == slot_index_usize {
|
||||
self.compute_arguments_hash()
|
||||
} else {
|
||||
preimage
|
||||
}
|
||||
})
|
||||
.map(|_| cumulative_hash::<SubstrateKeccakHasher, _>(self.slots.iter()))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.map(|slots| cumulative_hash::<SubstrateKeccakHasher, _>(slots))
|
||||
.unwrap_or(SubstrateKeccakHasher::empty())
|
||||
}
|
||||
|
||||
pub fn get_unique_key<NetworkId>(
|
||||
&self,
|
||||
session: WeavingSession,
|
||||
network_id: NetworkId,
|
||||
) -> H256
|
||||
where
|
||||
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
||||
{
|
||||
pub fn get_unique_key(&self, session: WeavingSession) -> H256 {
|
||||
let session_bytes = (session as u64).to_be_bytes();
|
||||
let slot_index_bytes = (self.slot_index as u64).to_be_bytes();
|
||||
let proof_index_bytes = (self.proof_index as u64).to_be_bytes();
|
||||
|
||||
let network_id_u64: u64 = network_id.unique_saturated_into();
|
||||
let network_id_bytes = network_id_u64.to_be_bytes();
|
||||
let slot_bytes = (self.slot_index as u64).to_be_bytes();
|
||||
let proof_bytes = (self.proof_index as u64).to_be_bytes();
|
||||
|
||||
let mut h1 = [0u8; 32]; h1[24..32].copy_from_slice(&session_bytes);
|
||||
let mut h2 = [0u8; 32]; h2[24..32].copy_from_slice(&slot_index_bytes);
|
||||
let mut h3 = [0u8; 32]; h3[24..32].copy_from_slice(&proof_index_bytes);
|
||||
let mut h4 = [0u8; 32]; h4[24..32].copy_from_slice(&network_id_bytes);
|
||||
let mut h2 = [0u8; 32]; h2[24..32].copy_from_slice(&slot_bytes);
|
||||
let mut h3 = [0u8; 32]; h3[24..32].copy_from_slice(&proof_bytes);
|
||||
|
||||
let metadata: [H256; 4] = [
|
||||
H256::from(h1),
|
||||
H256::from(h2),
|
||||
H256::from(h3),
|
||||
H256::from(h4),
|
||||
];
|
||||
let metadata: [H256; 3] = [H256::from(h1), H256::from(h2), H256::from(h3)];
|
||||
|
||||
sequential_hash::<SubstrateBlake2Hasher, _>(metadata)
|
||||
}
|
||||
|
||||
fn compute_arguments_hash<NetworkId>(&self, network_id: NetworkId) -> H256
|
||||
where
|
||||
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
||||
{
|
||||
let amount_u128: u128 = self.amount.unique_saturated_into();
|
||||
let slot_index_u64: u64 = self.slot_index.unique_saturated_into();
|
||||
let network_id_u64: u64 = network_id.unique_saturated_into();
|
||||
|
||||
let amount_u256 = U256::from(amount_u128);
|
||||
let slot_index_u256 = U256::from(slot_index_u64);
|
||||
let network_id_u256 = U256::from(network_id_u64);
|
||||
|
||||
let mut padded_amount = [0u8; 32];
|
||||
amount_u256.to_big_endian(&mut padded_amount);
|
||||
|
||||
let mut padded_slot_index = [0u8; 32];
|
||||
slot_index_u256.to_big_endian(&mut padded_slot_index);
|
||||
|
||||
let mut padded_network_id = [0u8; 32];
|
||||
network_id_u256.to_big_endian(&mut padded_network_id);
|
||||
|
||||
let inputs: [&[u8]; 4] = [
|
||||
padded_amount.as_ref(),
|
||||
self.receiver.as_ref(),
|
||||
padded_slot_index.as_ref(),
|
||||
padded_network_id.as_ref(),
|
||||
];
|
||||
|
||||
sequential_hash::<SubstrateKeccakHasher, _>(inputs)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
slot_index: ThreadId,
|
||||
proof_index: ThreadId,
|
||||
@ -481,6 +404,27 @@ where
|
||||
slots,
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_arguments_hash(&self) -> H256 {
|
||||
let amount_u128: u128 = self.amount.unique_saturated_into();
|
||||
let amount_u256 = U256::from(amount_u128);
|
||||
|
||||
let slot_index_u64: u64 = self.slot_index.unique_saturated_into();
|
||||
let slot_index_u256 = U256::from(slot_index_u64);
|
||||
|
||||
let mut padded_amount = [0u8; 32];
|
||||
amount_u256.to_big_endian(&mut padded_amount);
|
||||
|
||||
let mut padded_slot_index = [0u8; 32];
|
||||
slot_index_u256.to_big_endian(&mut padded_slot_index);
|
||||
|
||||
let inputs: [&[u8]; 3] = [
|
||||
padded_amount.as_ref(),
|
||||
self.receiver.as_ref(),
|
||||
padded_slot_index.as_ref(),
|
||||
];
|
||||
sequential_hash::<SubstrateKeccakHasher, _>(inputs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
|
||||
@ -500,7 +444,7 @@ impl UtxoThreadProof {
|
||||
|
||||
pub fn verify_thread_proof<Balance>(
|
||||
&self,
|
||||
block_hash: H256,
|
||||
root_hash: H256,
|
||||
gatekeeper_ref: &[u8],
|
||||
) -> Option<(AccountId32, Balance)>
|
||||
where
|
||||
@ -515,7 +459,7 @@ impl UtxoThreadProof {
|
||||
let is_chain_valid = verify_hash_ancestry::<UtxoSha2Hasher, _>(
|
||||
header_bytes,
|
||||
self.ancestry_headers.iter(),
|
||||
block_hash,
|
||||
root_hash,
|
||||
);
|
||||
|
||||
if !is_chain_valid { return None; }
|
||||
@ -524,12 +468,14 @@ impl UtxoThreadProof {
|
||||
self.getrawtransaction_bytes.as_ref()
|
||||
).ok()?;
|
||||
|
||||
let txid_preimage = transaction.compute_txid()?;
|
||||
Header::<UtxoSha2Hasher>::verify_utxo_merkle_proof(
|
||||
let header = Header::<UtxoSha2Hasher>::try_from(
|
||||
self.gettxproof_bytes.as_ref(),
|
||||
txid_preimage,
|
||||
).ok()?;
|
||||
|
||||
let txid_preimage = transaction.compute_txid()?;
|
||||
let root_hash = header.extract_proof(txid_preimage).ok()?;
|
||||
if root_hash != header.merkle_root { return None; }
|
||||
|
||||
#[cfg(not(any(test, feature = "runtime-benchmarks")))]
|
||||
let destination_script = Transaction::<UtxoSha2Hasher>::convert_into_p2tr(gatekeeper_ref)?;
|
||||
#[cfg(any(test, feature = "runtime-benchmarks"))]
|
||||
@ -542,17 +488,10 @@ impl UtxoThreadProof {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn get_unique_key<NetworkId>(&self, network_id: NetworkId) -> H256
|
||||
where
|
||||
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
||||
{
|
||||
let network_id_u64: u64 = network_id.unique_saturated_into();
|
||||
let network_id_bytes = network_id_u64.to_be_bytes();
|
||||
|
||||
pub fn get_unique_key(&self) -> H256 {
|
||||
let metadata: &[&[u8]] = &[
|
||||
self.gettxproof_bytes.as_ref(),
|
||||
self.getrawtransaction_bytes.as_ref(),
|
||||
network_id_bytes.as_ref(),
|
||||
];
|
||||
|
||||
sequential_hash::<SubstrateBlake2Hasher, _>(metadata)
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
//! Autogenerated weights for `ghost_weaver`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2026-09-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||
@ -67,16 +67,16 @@ impl WeightInfo for () {
|
||||
/// The range of component `a` is `[1, 300]`.
|
||||
fn extend_warp(a: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `274 + a * (33 ±0)`
|
||||
// Estimated: `3736 + a * (33 ±0)`
|
||||
// Minimum execution time: 229_711_000 picoseconds.
|
||||
Weight::from_parts(233_206_680, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3736))
|
||||
// Standard Error: 1_554
|
||||
.saturating_add(Weight::from_parts(66_095, 0).saturating_mul(a.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(6))
|
||||
.saturating_add(RocksDbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 33).saturating_mul(a.into()))
|
||||
// Measured: `223 + a * (32 ±0)`
|
||||
// Estimated: `3687 + a * (32 ±0)`
|
||||
// Minimum execution time: 210_105_000 picoseconds.
|
||||
Weight::from_parts(214_589_101, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3687))
|
||||
// Standard Error: 1_420
|
||||
.saturating_add(Weight::from_parts(50_124, 0).saturating_mul(a.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(5))
|
||||
.saturating_add(RocksDbWeight::get().writes(1))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
|
||||
}
|
||||
/// Storage: `GhostWeaver::DisabledAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostWeaver::DisabledAuthorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
@ -93,16 +93,16 @@ impl WeightInfo for () {
|
||||
/// The range of component `a` is `[1, 300]`.
|
||||
fn weave_weft(a: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `569 + a * (33 ±0)`
|
||||
// Estimated: `4031 + a * (33 ±0)`
|
||||
// Minimum execution time: 262_809_000 picoseconds.
|
||||
Weight::from_parts(267_769_707, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4031))
|
||||
// Standard Error: 1_865
|
||||
.saturating_add(Weight::from_parts(39_109, 0).saturating_mul(a.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(8))
|
||||
.saturating_add(RocksDbWeight::get().writes(3))
|
||||
.saturating_add(Weight::from_parts(0, 33).saturating_mul(a.into()))
|
||||
// Measured: `518 + a * (32 ±0)`
|
||||
// Estimated: `3982 + a * (32 ±0)`
|
||||
// Minimum execution time: 241_676_000 picoseconds.
|
||||
Weight::from_parts(246_243_389, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3982))
|
||||
// Standard Error: 1_686
|
||||
.saturating_add(Weight::from_parts(32_125, 0).saturating_mul(a.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(6))
|
||||
.saturating_add(RocksDbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
@ -114,19 +114,19 @@ impl WeightInfo for () {
|
||||
/// Proof: `GhostNetworks::GatekeeperAmounts` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkImbalance` (r:1 w:1)
|
||||
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Storage: `System::Account` (r:1 w:0)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// The range of component `a` is `[1, 144]`.
|
||||
fn pull_utxo_thread(a: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `500`
|
||||
// Estimated: `3965`
|
||||
// Minimum execution time: 217_481_000 picoseconds.
|
||||
Weight::from_parts(216_492_234, 0)
|
||||
// Standard Error: 4_414
|
||||
.saturating_add(Weight::from_parts(3_376_569, 0).saturating_mul(a.into()))
|
||||
// Measured: `346`
|
||||
// Estimated: `3811`
|
||||
// Minimum execution time: 170_554_000 picoseconds.
|
||||
Weight::from_parts(170_660_694, 0)
|
||||
// Standard Error: 4_207
|
||||
.saturating_add(Weight::from_parts(3_450_120, 0).saturating_mul(a.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(6))
|
||||
.saturating_add(RocksDbWeight::get().writes(4))
|
||||
.saturating_add(RocksDbWeight::get().writes(3))
|
||||
}
|
||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
@ -138,16 +138,16 @@ impl WeightInfo for () {
|
||||
/// Proof: `GhostNetworks::GatekeeperAmounts` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkImbalance` (r:1 w:1)
|
||||
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Storage: `System::Account` (r:1 w:0)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn pull_evm_thread() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `500`
|
||||
// Estimated: `3965`
|
||||
// Minimum execution time: 176_861_000 picoseconds.
|
||||
Weight::from_parts(177_861_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3965))
|
||||
// Measured: `3446`
|
||||
// Estimated: `3811`
|
||||
// Minimum execution time: 136_258_000 picoseconds.
|
||||
Weight::from_parts(137_856_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3811))
|
||||
.saturating_add(RocksDbWeight::get().reads(6))
|
||||
.saturating_add(RocksDbWeight::get().writes(4))
|
||||
.saturating_add(RocksDbWeight::get().writes(3))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "casper-runtime"
|
||||
version = "4.0.18"
|
||||
version = "4.0.10"
|
||||
build = "build.rs"
|
||||
description = "Runtime of the Casper Network"
|
||||
edition.workspace = true
|
||||
@ -75,7 +75,6 @@ ghost-networks = { workspace = true }
|
||||
ghost-governance = { workspace = true }
|
||||
ghost-weaver = { workspace = true }
|
||||
ghost-exodus = { workspace = true }
|
||||
ghost-exodus-runtime-api = { workspace = true }
|
||||
ghost-sudo = { workspace = true }
|
||||
ghost-traits = { workspace = true }
|
||||
ghost-helpers = { workspace = true }
|
||||
@ -189,7 +188,6 @@ std = [
|
||||
"ghost-governance/std",
|
||||
"ghost-weaver/std",
|
||||
"ghost-exodus/std",
|
||||
"ghost-exodus-runtime-api/std",
|
||||
"ghost-sudo/std",
|
||||
"casper-runtime-constants/std",
|
||||
"runtime-common/std",
|
||||
|
||||
@ -15,7 +15,7 @@ use frame_support::{
|
||||
traits::{
|
||||
fungible::HoldConsideration,
|
||||
tokens::{imbalance::ResolveTo, UnityAssetBalanceConversion},
|
||||
ConstU128, ConstU32, ConstU8, InstanceFilter, KeyOwnerProofSystem,
|
||||
ConstU128, ConstU32, InstanceFilter, KeyOwnerProofSystem,
|
||||
LinearStoragePrice,
|
||||
},
|
||||
};
|
||||
@ -69,7 +69,6 @@ pub use frame_system::Call as SystemCall;
|
||||
pub use pallet_balances::Call as BalancesCall;
|
||||
pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase};
|
||||
|
||||
use ghost_helpers::networks::{NetworkCurve, NetworkType};
|
||||
use ghost_weaver::sr25519::AuthorityId as GhostWeaverId;
|
||||
use ghost_exodus::sr25519::AuthorityId as GhostExodusId;
|
||||
|
||||
@ -124,8 +123,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: create_runtime_str!("casper"),
|
||||
impl_name: create_runtime_str!("casper-svengali"),
|
||||
authoring_version: 0,
|
||||
spec_version: 12,
|
||||
impl_version: 0,
|
||||
spec_version: 6,
|
||||
impl_version: 4,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 1,
|
||||
state_version: 1,
|
||||
@ -888,8 +887,7 @@ impl ghost_governance::Config for Runtime {
|
||||
type Currency = Balances;
|
||||
type NetworkDataHandler = GhostNetworks;
|
||||
type MinimumDonation = ConstU128<{ 6_900 * STRH }>;
|
||||
type MaxProofDepth = ConstU32<18>;
|
||||
type MaxPartialClaims = ConstU8<20>;
|
||||
type MaxProofDepth = ConstU32<20>;
|
||||
|
||||
type WeightInfo = weights::ghost_governance::WeightInfo<Runtime>;
|
||||
}
|
||||
@ -907,7 +905,6 @@ parameter_types! {
|
||||
pub ExodusUnsignedPriority: TransactionPriority =
|
||||
Perbill::from_percent(90) * TransactionPriority::MAX;
|
||||
|
||||
pub MaxExodusRequestCount: u32 = 32;
|
||||
pub MaxAuthoritiesChunks: u32 = 32;
|
||||
pub WeavingDelay: u64 = 50;
|
||||
pub AttestationDelay: u64 = 25;
|
||||
@ -916,7 +913,6 @@ parameter_types! {
|
||||
pub ExodusDkgRoundPeriod: u64 = 50;
|
||||
pub ExodusRemovalLimit: u32 = 64;
|
||||
pub ExodusMaxCursorLen: u32 = 100;
|
||||
pub MinBridgeOut: u128 = 500 * STRH;
|
||||
}
|
||||
|
||||
impl ghost_weaver::Config for Runtime {
|
||||
@ -951,12 +947,10 @@ impl ghost_exodus::Config for Runtime {
|
||||
type UnsignedPriority = ExodusUnsignedPriority;
|
||||
type MaxAuthorities = MaxActiveValidators;
|
||||
type MaxAuthoritiesChunks = MaxAuthoritiesChunks;
|
||||
type MaxExodusRequestCount = MaxExodusRequestCount;
|
||||
|
||||
type DkgRoundPeriod = ExodusDkgRoundPeriod;
|
||||
type RemovalLimit = ExodusRemovalLimit;
|
||||
type MaxCursorLen = ExodusMaxCursorLen;
|
||||
type BaseEvmAmount = MinBridgeOut;
|
||||
|
||||
type WeightInfo = weights::ghost_exodus::WeightInfo<Runtime>;
|
||||
}
|
||||
@ -1035,9 +1029,7 @@ pub type SignedExtra = (
|
||||
|
||||
/// All migrations that will run on the next runtime upgrade.
|
||||
/// Should be cleared after release.
|
||||
pub type Migrations = (
|
||||
ghost_weaver::migrations::MigrateV0ToV1<Runtime>,
|
||||
);
|
||||
pub type Migrations = ();
|
||||
|
||||
/// Unchecked extrinsic type as expected by this runtime.
|
||||
pub type UncheckedExtrinsic =
|
||||
@ -1161,39 +1153,6 @@ sp_api::impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl ghost_exodus_runtime_api::ExodusApi<Block> for Runtime {
|
||||
fn get_evm_rotation_metadata(
|
||||
dkg_index: u64,
|
||||
network_type: NetworkType,
|
||||
) -> ghost_exodus_runtime_api::PreparedEvmMessage {
|
||||
GhostExodus::api_get_evm_rotation(dkg_index, network_type)
|
||||
}
|
||||
|
||||
fn get_evm_bridge_metadata(
|
||||
dkg_index: u64,
|
||||
network_id: u64,
|
||||
session: u64,
|
||||
) -> ghost_exodus_runtime_api::PreparedEvmMessage {
|
||||
GhostExodus::api_get_evm_bridge(dkg_index, network_id, session)
|
||||
}
|
||||
|
||||
fn get_evm_governance_metadata(
|
||||
dkg_index: u64,
|
||||
network_id: u64,
|
||||
session: u64,
|
||||
) -> ghost_exodus_runtime_api::PreparedEvmMessage {
|
||||
GhostExodus::api_get_evm_governance(dkg_index, network_id, session)
|
||||
}
|
||||
|
||||
fn pending_exodus_request_count() -> u32 {
|
||||
GhostExodus::api_pending_exodus_request_count()
|
||||
}
|
||||
|
||||
fn is_qualification_ongoing(network_curve: NetworkCurve) -> bool {
|
||||
GhostExodus::api_is_qualification_ongoing(network_curve)
|
||||
}
|
||||
}
|
||||
|
||||
impl pallet_staking_runtime_api::StakingApi<Block, Balance, AccountId> for Runtime {
|
||||
fn nominations_quota(balance: Balance) -> u32 {
|
||||
Staking::api_nominations_quota(balance)
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
//! Autogenerated weights for `ghost_exodus`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2026-09-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||
@ -46,232 +46,252 @@ use core::marker::PhantomData;
|
||||
/// Weight functions for `ghost_exodus`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round0Packages` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Round0Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round0Packages` (r:0 w:1)
|
||||
/// Proof: `GhostExodus::Round0Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_round0_package() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `365`
|
||||
// Estimated: `3830`
|
||||
// Minimum execution time: 240_843_000 picoseconds.
|
||||
Weight::from_parts(243_855_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3830))
|
||||
// Measured: `351`
|
||||
// Estimated: `3816`
|
||||
// Minimum execution time: 239_012_000 picoseconds.
|
||||
Weight::from_parts(241_388_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3816))
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round1Packages` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Round1Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round0Packages` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::Round0Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round1Packages` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Round1Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[4, 300]`.
|
||||
fn register_round1_package(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `405 + c * (32 ±0)`
|
||||
// Estimated: `3870 + c * (32 ±0)`
|
||||
// Minimum execution time: 1_349_108_000 picoseconds.
|
||||
Weight::from_parts(1_224_956_354, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3870))
|
||||
// Standard Error: 14_930
|
||||
.saturating_add(Weight::from_parts(33_204_477, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
// Measured: `391 + c * (32 ±0)`
|
||||
// Estimated: `3856 + c * (32 ±0)`
|
||||
// Minimum execution time: 1_339_828_000 picoseconds.
|
||||
Weight::from_parts(1_212_625_790, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3856))
|
||||
// Standard Error: 11_831
|
||||
.saturating_add(Weight::from_parts(33_120_868, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Round2Packages` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Round2Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[1, 300]`.
|
||||
/// The range of component `c` is `[1, 37]`.
|
||||
fn register_encrypted_round2_packages(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `332 + c * (32 ±0)`
|
||||
// Estimated: `3797 + c * (32 ±0)`
|
||||
// Minimum execution time: 245_305_000 picoseconds.
|
||||
Weight::from_parts(253_863_353, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3797))
|
||||
// Standard Error: 3_527
|
||||
.saturating_add(Weight::from_parts(810_623, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Complaints` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Complaints` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[1, 300]`.
|
||||
fn register_round3_complaints(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `332 + c * (32 ±0)`
|
||||
// Estimated: `3797 + c * (32 ±0)`
|
||||
// Minimum execution time: 238_391_000 picoseconds.
|
||||
Weight::from_parts(242_937_380, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3797))
|
||||
// Standard Error: 1_789
|
||||
.saturating_add(Weight::from_parts(39_316, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Justifications` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Justifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[1, 300]`.
|
||||
fn register_round4_justifications(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `332 + c * (32 ±0)`
|
||||
// Estimated: `3797 + c * (32 ±0)`
|
||||
// Minimum execution time: 245_916_000 picoseconds.
|
||||
Weight::from_parts(251_070_206, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3797))
|
||||
// Standard Error: 2_152
|
||||
.saturating_add(Weight::from_parts(508_508, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Verifications` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Verifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_round5_verifying_package() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `462`
|
||||
// Estimated: `3927`
|
||||
// Minimum execution time: 271_654_000 picoseconds.
|
||||
Weight::from_parts(286_394_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3927))
|
||||
// Measured: `317 + c * (257 ±0)`
|
||||
// Estimated: `3783 + c * (257 ±0)`
|
||||
// Minimum execution time: 251_478_000 picoseconds.
|
||||
Weight::from_parts(254_144_621, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3783))
|
||||
// Standard Error: 24_613
|
||||
.saturating_add(Weight::from_parts(6_595_819, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingSharesParticipants` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::VerifyingSharesParticipants` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Complaints` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Complaints` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[1, 37]`.
|
||||
fn register_round3_complaints(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `317 + c * (257 ±0)`
|
||||
// Estimated: `3783 + c * (257 ±0)`
|
||||
// Minimum execution time: 236_155_000 picoseconds.
|
||||
Weight::from_parts(242_055_898, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3783))
|
||||
// Standard Error: 15_623
|
||||
.saturating_add(Weight::from_parts(360_411, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Justifications` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Justifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[1, 37]`.
|
||||
fn register_round4_justifications(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `317 + c * (257 ±0)`
|
||||
// Estimated: `3783 + c * (257 ±0)`
|
||||
// Minimum execution time: 249_507_000 picoseconds.
|
||||
Weight::from_parts(248_505_595, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3783))
|
||||
// Standard Error: 20_302
|
||||
.saturating_add(Weight::from_parts(4_191_526, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::Verifications` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::Verifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_round5_verifying_package() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `448`
|
||||
// Estimated: `3913`
|
||||
// Minimum execution time: 264_214_000 picoseconds.
|
||||
Weight::from_parts(266_905_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3913))
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingShares` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::VerifyingShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingSharesParticipants` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::VerifyingSharesParticipants` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `c` is `[1, 9]`.
|
||||
fn register_round6_public_share_package(c: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0 + c * (770 ±0)`
|
||||
// Estimated: `1698 + c * (1019 ±27)`
|
||||
// Minimum execution time: 283_863_000 picoseconds.
|
||||
Weight::from_parts(286_691_978, 0)
|
||||
.saturating_add(Weight::from_parts(0, 1698))
|
||||
// Standard Error: 85_685
|
||||
.saturating_add(Weight::from_parts(2_854_037, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
// Estimated: `1551 + c * (1019 ±27)`
|
||||
// Minimum execution time: 281_073_000 picoseconds.
|
||||
Weight::from_parts(280_778_987, 0)
|
||||
.saturating_add(Weight::from_parts(0, 1551))
|
||||
// Standard Error: 79_426
|
||||
.saturating_add(Weight::from_parts(3_449_552, 0).saturating_mul(c.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(7))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
.saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::ActiveDkgAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::NonceCommitments` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::NonceCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessionStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::NonceCommitments` (r:0 w:1)
|
||||
/// Proof: `GhostExodus::NonceCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_nonce_commitment() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `633`
|
||||
// Estimated: `4098`
|
||||
// Minimum execution time: 369_666_000 picoseconds.
|
||||
Weight::from_parts(373_163_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4098))
|
||||
// Measured: `588`
|
||||
// Estimated: `4053`
|
||||
// Minimum execution time: 291_972_000 picoseconds.
|
||||
Weight::from_parts(295_122_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4053))
|
||||
.saturating_add(T::DbWeight::get().reads(8))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::ActiveDkgAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessionStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::GroupCommitters` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::GroupCommitters` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessionStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::GroupCommitmentsConsensus` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_group_commitment() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `1030`
|
||||
// Estimated: `4495`
|
||||
// Minimum execution time: 339_569_000 picoseconds.
|
||||
Weight::from_parts(341_788_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4495))
|
||||
.saturating_add(T::DbWeight::get().reads(9))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
// Measured: `968`
|
||||
// Estimated: `4433`
|
||||
// Minimum execution time: 331_528_000 picoseconds.
|
||||
Weight::from_parts(333_974_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4433))
|
||||
.saturating_add(T::DbWeight::get().reads(10))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::ActiveDkgAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessionStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ActiveAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::GroupCommitmentsConsensus` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusSignedGovernance` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::ExodusSignedGovernance` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::RoastSessionStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::NonceCommitments` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::NonceCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::VerifyingShares` (r:1 w:0)
|
||||
@ -280,22 +300,18 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
|
||||
/// Proof: `GhostExodus::ActiveVerifyingKey` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::SignatureScalars` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::SignatureScalars` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::CounterForExodusRequests` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::CounterForExodusRequests` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::GroupCommitters` (r:0 w:1)
|
||||
/// Proof: `GhostExodus::GroupCommitters` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_signature_share() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `11337`
|
||||
// Estimated: `14802`
|
||||
// Minimum execution time: 4_046_065_000 picoseconds.
|
||||
Weight::from_parts(4_059_064_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 14802))
|
||||
// Measured: `11259`
|
||||
// Estimated: `14724`
|
||||
// Minimum execution time: 3_980_585_000 picoseconds.
|
||||
Weight::from_parts(3_985_167_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 14724))
|
||||
.saturating_add(T::DbWeight::get().reads(14))
|
||||
.saturating_add(T::DbWeight::get().writes(8))
|
||||
}
|
||||
/// Storage: `GhostExodus::CounterForExodusRequests` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::CounterForExodusRequests` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::GatekeeperAmounts` (r:1 w:1)
|
||||
@ -304,18 +320,18 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
|
||||
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::CurrentExodusSessions` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::CurrentExodusSessions` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||
/// Storage: `GhostExodus::CurrentExodus` (r:1 w:1)
|
||||
/// Proof: `GhostExodus::CurrentExodus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostExodus::ExodusRequests` (r:0 w:1)
|
||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
fn register_evm_bridge_out_exodus() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `457`
|
||||
// Estimated: `3922`
|
||||
// Minimum execution time: 195_417_000 picoseconds.
|
||||
Weight::from_parts(196_842_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3922))
|
||||
.saturating_add(T::DbWeight::get().reads(7))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
// Measured: `448`
|
||||
// Estimated: `3913`
|
||||
// Minimum execution time: 137_053_000 picoseconds.
|
||||
Weight::from_parts(138_693_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3913))
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
//! Autogenerated weights for `ghost_governance`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2026-09-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||
@ -50,23 +50,21 @@ impl<T: frame_system::Config> ghost_governance::WeightInfo for WeightInfo<T> {
|
||||
/// Proof: `GhostGovernance::MemberShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostGovernance::ClaimedHashes` (r:1 w:1)
|
||||
/// Proof: `GhostGovernance::ClaimedHashes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostGovernance::ClaimedShares` (r:1 w:1)
|
||||
/// Proof: `GhostGovernance::ClaimedShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostGovernance::NetworkShares` (r:1 w:1)
|
||||
/// Proof: `GhostGovernance::NetworkShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostGovernance::GlobalShares` (r:1 w:1)
|
||||
/// Proof: `GhostGovernance::GlobalShares` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `p` is `[1, 18]`.
|
||||
/// The range of component `p` is `[1, 20]`.
|
||||
fn claim(p: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `283`
|
||||
// Estimated: `3748`
|
||||
// Minimum execution time: 224_852_000 picoseconds.
|
||||
Weight::from_parts(225_347_733, 0)
|
||||
// Minimum execution time: 214_208_000 picoseconds.
|
||||
Weight::from_parts(216_987_870, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3748))
|
||||
// Standard Error: 21_234
|
||||
.saturating_add(Weight::from_parts(1_581_800, 0).saturating_mul(p.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().writes(5))
|
||||
// Standard Error: 30_856
|
||||
.saturating_add(Weight::from_parts(1_702_104, 0).saturating_mul(p.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(4))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
//! Autogenerated weights for `ghost_weaver`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2026-09-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||
@ -46,40 +46,34 @@ use core::marker::PhantomData;
|
||||
/// Weight functions for `ghost_weaver`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
|
||||
/// Storage: `GhostWeaver::Authorities` (r:1 w:0)
|
||||
/// Proof: `GhostWeaver::Authorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::AttestedBlocks` (r:1 w:1)
|
||||
/// Proof: `GhostWeaver::AttestedBlocks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::NetworkAttestations` (r:1 w:1)
|
||||
/// Proof: `GhostWeaver::NetworkAttestations` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::DisabledAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostWeaver::DisabledAuthorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::Authorities` (r:1 w:0)
|
||||
/// Proof: `GhostWeaver::Authorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::TapestryDrafts` (r:1 w:0)
|
||||
/// Proof: `GhostWeaver::TapestryDrafts` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::NetworkAttestations` (r:1 w:1)
|
||||
/// Proof: `GhostWeaver::NetworkAttestations` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `a` is `[1, 300]`.
|
||||
fn extend_warp(a: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `274 + a * (33 ±0)`
|
||||
// Estimated: `3736 + a * (33 ±0)`
|
||||
// Minimum execution time: 229_711_000 picoseconds.
|
||||
Weight::from_parts(235_206_680, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3736))
|
||||
// Standard Error: 1_554
|
||||
.saturating_add(Weight::from_parts(66_905, 0).saturating_mul(a.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 33).saturating_mul(a.into()))
|
||||
// Measured: `223 + a * (32 ±0)`
|
||||
// Estimated: `3687 + a * (32 ±0)`
|
||||
// Minimum execution time: 210_105_000 picoseconds.
|
||||
Weight::from_parts(214_589_101, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3687))
|
||||
// Standard Error: 1_420
|
||||
.saturating_add(Weight::from_parts(50_124, 0).saturating_mul(a.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(5))
|
||||
.saturating_add(T::DbWeight::get().writes(1))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
|
||||
}
|
||||
/// Storage: `GhostWeaver::Authorities` (r:1 w:0)
|
||||
/// Proof: `GhostWeaver::Authorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::AttestedBlocks` (r:1 w:1)
|
||||
/// Proof: `GhostWeaver::AttestedBlocks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::NetworkAttestations` (r:1 w:0)
|
||||
/// Proof: `GhostWeaver::NetworkAttestations` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::DisabledAuthorities` (r:1 w:0)
|
||||
/// Proof: `GhostWeaver::DisabledAuthorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::Authorities` (r:1 w:0)
|
||||
/// Proof: `GhostWeaver::Authorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostWeaver::TapestryDrafts` (r:1 w:0)
|
||||
@ -91,16 +85,16 @@ impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
|
||||
/// The range of component `a` is `[1, 300]`.
|
||||
fn weave_weft(a: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `569 + a * (33 ±0)`
|
||||
// Estimated: `4031 + a * (33 ±0)`
|
||||
// Minimum execution time: 262_809_000 picoseconds.
|
||||
Weight::from_parts(267_769_707, 0)
|
||||
.saturating_add(Weight::from_parts(0, 4031))
|
||||
// Standard Error: 2_375
|
||||
.saturating_add(Weight::from_parts(39_109, 0).saturating_mul(a.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(8))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
.saturating_add(Weight::from_parts(0, 33).saturating_mul(a.into()))
|
||||
// Measured: `518 + a * (32 ±0)`
|
||||
// Estimated: `3982 + a * (32 ±0)`
|
||||
// Minimum execution time: 241_676_000 picoseconds.
|
||||
Weight::from_parts(246_243_389, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3982))
|
||||
// Standard Error: 1_686
|
||||
.saturating_add(Weight::from_parts(32_125, 0).saturating_mul(a.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(2))
|
||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
|
||||
}
|
||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
@ -112,20 +106,20 @@ impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
|
||||
/// Proof: `GhostNetworks::GatekeeperAmounts` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkImbalance` (r:1 w:1)
|
||||
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Storage: `System::Account` (r:1 w:0)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
/// The range of component `a` is `[1, 144]`.
|
||||
fn pull_utxo_thread(a: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `500`
|
||||
// Estimated: `3965`
|
||||
// Minimum execution time: 217_481_000 picoseconds.
|
||||
Weight::from_parts(216_492_234, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3965))
|
||||
// Standard Error: 4_414
|
||||
.saturating_add(Weight::from_parts(3_376_569, 0).saturating_mul(a.into()))
|
||||
// Measured: `346`
|
||||
// Estimated: `3811`
|
||||
// Minimum execution time: 170_554_000 picoseconds.
|
||||
Weight::from_parts(170_660_694, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3811))
|
||||
// Standard Error: 4_207
|
||||
.saturating_add(Weight::from_parts(3_450_120, 0).saturating_mul(a.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
}
|
||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
@ -137,16 +131,16 @@ impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
|
||||
/// Proof: `GhostNetworks::GatekeeperAmounts` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `GhostNetworks::NetworkImbalance` (r:1 w:1)
|
||||
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||
/// Storage: `System::Account` (r:1 w:1)
|
||||
/// Storage: `System::Account` (r:1 w:0)
|
||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||
fn pull_evm_thread() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `500`
|
||||
// Estimated: `3965`
|
||||
// Minimum execution time: 176_861_000 picoseconds.
|
||||
Weight::from_parts(177_918_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3965))
|
||||
// Measured: `346`
|
||||
// Estimated: `3811`
|
||||
// Minimum execution time: 136_258_000 picoseconds.
|
||||
Weight::from_parts(137_856_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 3811))
|
||||
.saturating_add(T::DbWeight::get().reads(6))
|
||||
.saturating_add(T::DbWeight::get().writes(4))
|
||||
.saturating_add(T::DbWeight::get().writes(3))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
[toolchain]
|
||||
channel = "1.93.1"
|
||||
components = ["rustfmt", "clippy", "rust-src"]
|
||||
targets = ["wasm32-unknown-unknown"]
|
||||
@ -17,22 +17,15 @@ MORDOR_RPC=(
|
||||
"https://rpc.mordor.etccooperative.org"
|
||||
)
|
||||
|
||||
HOODI_RPC=(
|
||||
"https://rpc.hoodi.ethpandaops.io"
|
||||
"https://0xrpc.io/hoodi"
|
||||
"https://rpc.sentio.xyz/hoodi"
|
||||
)
|
||||
|
||||
HOODI_GATEKEEPER="0xc9D5f50e17eeEAF39E0D0cDbbcF4B04FA4A4Bbd6"
|
||||
|
||||
show_help() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") [OPTIONS]
|
||||
|
||||
Options:
|
||||
--chain <name> Specify network: 'sepolia', 'hoodi' or 'mordor'. If omitted, checks all.
|
||||
--chain <name> Specify network: 'sepolia' or 'mordor'. If omitted, checks both.
|
||||
--output <dir> Base directory to save results. Creates a subfolder with Unix Timestamp.
|
||||
--rpcs <urls> Comma-separated list of custom RPC endpoints. Disables default networks lists.
|
||||
--rpcs <urls> Comma-separated list of custom RPC endpoints.
|
||||
Disables default Sepolia/Mordor lists.
|
||||
--help Show this help message.
|
||||
|
||||
Example:
|
||||
@ -59,66 +52,20 @@ spinner() {
|
||||
tput cnorm
|
||||
}
|
||||
|
||||
pad32() {
|
||||
local h="$1"
|
||||
h="${h#0x}"
|
||||
printf "%064s" "$h" | tr ' ' '0'
|
||||
}
|
||||
|
||||
build_calldata() {
|
||||
local selector="$1"
|
||||
local at_block="$2"
|
||||
local s_hex
|
||||
local b_hex
|
||||
|
||||
s_hex=$(printf "%x" 0)
|
||||
b_hex=$(printf "%x" "$at_block")
|
||||
|
||||
echo "0x${selector#0x}$(pad32 "$s_hex")$(pad32 "$b_hex")"
|
||||
}
|
||||
|
||||
decode_get_root() {
|
||||
local res_json="$1"
|
||||
local hex
|
||||
|
||||
hex=$(echo "$res_json" | grep -o '"result":"[^"]*' | cut -d'"' -f4)
|
||||
if [[ -z "$hex" || "$hex" == "null" ]]; then
|
||||
echo "ERROR"
|
||||
return
|
||||
fi
|
||||
|
||||
hex="${hex#0x}"
|
||||
if (( ${#hex} < 128 )); then
|
||||
echo "ERROR"
|
||||
return
|
||||
fi
|
||||
|
||||
local word1="${hex:0:64}"
|
||||
local word2="${hex:64:64}"
|
||||
local num
|
||||
|
||||
num=$(printf "%d" "0x$word2" 2>/dev/null)
|
||||
[[ -z "$num" ]] && num="$word2"
|
||||
echo "0x${word1} ${num}"
|
||||
}
|
||||
|
||||
check_network() {
|
||||
local name=$1
|
||||
local gatekeeper=$2
|
||||
shift 2
|
||||
shift
|
||||
local rpcs=("$@")
|
||||
local target_dir="${OUT_DIR:-/tmp}"
|
||||
local tmp_file="${target_dir}/$(date +%s)_${name,,}"
|
||||
|
||||
local root_width=66
|
||||
local sess_width=6
|
||||
local max_len=0
|
||||
for e in "${rpcs[@]}"; do (( ${#e} > max_len )) && max_len=${#e}; done
|
||||
[[ $max_len -lt 20 ]] && max_len=20
|
||||
|
||||
local total_width=$(( max_len + 95 ))
|
||||
local total_width=$(( max_len + 32 ))
|
||||
local line=$(printf "%.0s-" $(seq 1 $total_width))
|
||||
local header_fmt="| %-${max_len}s | %-10s | %-${root_width}s | %-${sess_width}s |\n"
|
||||
local header_fmt="| %-${max_len}s | %-12s | %-10s |\n"
|
||||
|
||||
(
|
||||
for endpoint in "${rpcs[@]}"; do
|
||||
@ -127,15 +74,11 @@ check_network() {
|
||||
hex=$(echo "$res_b" | grep -o '"result":"[^"]*' | cut -d'"' -f4)
|
||||
[[ -n "$hex" && "$hex" != "null" ]] && blk=$(printf "%d" "$hex") || blk="ERROR"
|
||||
|
||||
root="N/A"
|
||||
if [[ -n "$blk" && "$blk" != "ERROR" ]]; then
|
||||
calldata=$(build_calldata "$SELECTOR" "$blk")
|
||||
payload=$(printf '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"%s","data":"%s"},"latest"],"id":1}' "$gatekeeper" "$calldata")
|
||||
res_c=$(curl -s -X POST -H "Content-Type: application/json" --max-time 10 --data "$payload" "$endpoint")
|
||||
root=$(decode_get_root "$res_c")
|
||||
fi
|
||||
res_l=$(curl -s -X POST -H "Content-Type: application/json" --max-time 10 \
|
||||
--data '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x1","toBlock":"0x2"}],"id":1}' "$endpoint")
|
||||
echo "$res_l" | grep -q '"result"' && ev="YES" || ev="NO"
|
||||
|
||||
echo "$endpoint|$blk|$root"
|
||||
echo "$endpoint|$blk|$ev"
|
||||
done
|
||||
) > "$tmp_file" &
|
||||
|
||||
@ -145,17 +88,10 @@ check_network() {
|
||||
spinner $worker_pid "$name"
|
||||
|
||||
local table_output="$line\n"
|
||||
table_output+=$(printf "$header_fmt" "Endpoint" "Block" "Merkle Root" "Session")"\n"
|
||||
table_output+=$(printf "$header_fmt" "Endpoint" "Block" "Events")"\n"
|
||||
table_output+="$line\n"
|
||||
while IFS="|" read -r url blk root; do
|
||||
if [[ "$root" == *" "* ]]; then
|
||||
hash="${root%% *}"
|
||||
sess="${root##* }"
|
||||
else
|
||||
hash="$root"
|
||||
sess="-"
|
||||
fi
|
||||
table_output+=$(printf "$header_fmt" "$url" "$blk" "$hash" "$sess")"\n"
|
||||
while IFS="|" read -r url blk ev; do
|
||||
table_output+=$(printf "$header_fmt" "$url" "$blk" "$ev")"\n"
|
||||
done < "$tmp_file"
|
||||
table_output+="$line"
|
||||
|
||||
@ -169,7 +105,6 @@ check_network() {
|
||||
CHOSEN_CHAIN=""
|
||||
BASE_OUT_DIR=""
|
||||
CUSTOM_RPCS=""
|
||||
SELECTOR="d4be7935"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@ -191,14 +126,11 @@ if [[ -n "$CUSTOM_RPCS" ]]; then
|
||||
check_network "Custom" "${USER_RPC_ARRAY[@]}"
|
||||
else
|
||||
if [ "$CHOSEN_CHAIN" == "sepolia" ]; then
|
||||
check_network "Sepolia" "$SEPOLIA_GATEKEEPER" "${HOODI_RPC[@]}"
|
||||
check_network "Sepolia" "${SEPOLIA_RPC[@]}"
|
||||
elif [ "$CHOSEN_CHAIN" == "mordor" ]; then
|
||||
check_network "Mordor" "$MORDOR_GATEKEEPER" "${HOODI_RPC[@]}"
|
||||
elif [ "$CHOSEN_CHAIN" == "hoodi" ]; then
|
||||
check_network "Hoodi" "$HOODI_GATEKEEPER" "${HOODI_RPC[@]}"
|
||||
check_network "Mordor" "${MORDOR_RPC[@]}"
|
||||
else
|
||||
check_network "Sepolia" "$SEPOLIA_GATEKEEPER" "${SEPOLIA_RPC[@]}"
|
||||
check_network "Mordor" "$MORDOR_GATEKEEPER" "${MORDOR_RPC[@]}"
|
||||
check_network "Hoodi" "$HOODI_GATEKEEPER" "${HOODI_RPC[@]}"
|
||||
check_network "Sepolia" "${SEPOLIA_RPC[@]}"
|
||||
check_network "Mordor" "${MORDOR_RPC[@]}"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -9,7 +9,6 @@ UNIT_FILE=false
|
||||
SKIP_BUILD=false
|
||||
SET_ENVIRONMENT=false
|
||||
VALIDATE=false
|
||||
FIX_WEAVER_KEYSTORE=false
|
||||
EXECUTABLE_PATH="/usr/bin/"
|
||||
SPECIFICATION_PATH="/etc/ghost/"
|
||||
BASE_PATH="/var/lib/ghost"
|
||||
@ -86,16 +85,30 @@ extract_seed() {
|
||||
echo $seed
|
||||
}
|
||||
|
||||
apply_patches_if_needed() {
|
||||
local PATCH_STATUS=0
|
||||
upgrade_compiler_if_needed() {
|
||||
UPDATE_STATUS=$(rustup check 2>&1)
|
||||
"$SCRIPT_FOLDER"/patch.sh || PATCH_STATUS=$?
|
||||
|
||||
if [ "$PATCH_STATUS" -eq 2 ]; then
|
||||
if echo "$UPDATE_STATUS" | grep -q "Update available" || [ $PATCH_STATUS -eq 2 ]; then
|
||||
echo "[+] clean all cache on the current system"
|
||||
cargo clean
|
||||
cargo install cargo-cache
|
||||
cargo clean
|
||||
cargo cache --remove-dir all
|
||||
|
||||
echo "[+] upgrading rustc compiler version to latest"
|
||||
rustup update
|
||||
toolchain_name=$(rustup show | grep default | head -n 1 | cut -d' ' -f1)
|
||||
|
||||
if ! rustup target list --installed | grep -q "wasm32-unknown-unknown"; then
|
||||
echo "[+] installing wasm32-unknown-unknown target"
|
||||
rustup target add wasm32-unknown-unknown
|
||||
fi
|
||||
|
||||
if ! rustup component list --installed | grep -q "rust-src"; then
|
||||
echo "[+] installing rust-src component"
|
||||
rustup component add rust-src
|
||||
fi
|
||||
|
||||
echo "[+] fetching all dependencies"
|
||||
cargo fetch
|
||||
|
||||
@ -121,8 +134,7 @@ help() {
|
||||
echo -e "-s, --base-path\n\tPath to the folder with chain database ('/var/lib/ghost' is default)."
|
||||
echo -e "-c, --specification-path\n\tPath to specification ('/etc/ghost' is default)."
|
||||
echo -e "-n, --specification-name\n\tSpecification name to be used ('casper' is default)."
|
||||
echo -e "--generate-genesis\n\tGenerate keys to participate in the genesis file."
|
||||
echo -e "--fix-weaver-keystore\n\tFix keystore prefixes (weav -> wevr) to ensure the offchain worker can find the key."
|
||||
echo -e "-g, --generate-genesis\n\tGenerate keys to participate in the genesis file."
|
||||
echo -e "--hard-reset-i-know-what-im-doing\n\tWill completely remove ledger along with associated session keys."
|
||||
echo -e "-h, --help\n\tPrints help information."
|
||||
}
|
||||
@ -194,12 +206,9 @@ while [ $# -gt 0 ]; do
|
||||
--hard-reset-i-know-what-im-doing)
|
||||
HARD_RESET=true
|
||||
;;
|
||||
--generate-genesis)
|
||||
--generate-genesis|-g)
|
||||
GENERATE_GENESIS=true
|
||||
;;
|
||||
--fix-weaver-keystore)
|
||||
FIX_WEAVER_KEYSTORE=true
|
||||
;;
|
||||
--help|-h)
|
||||
help
|
||||
exit 0
|
||||
@ -231,7 +240,7 @@ if [[ $HARD_RESET = true ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
apply_patches_if_needed
|
||||
upgrade_compiler_if_needed
|
||||
|
||||
echo "[+] trying to stop current ghost-node"
|
||||
sudo systemctl stop ghost-node
|
||||
@ -340,12 +349,12 @@ if [[ $SET_ENVIRONMENT = true ]]; then
|
||||
|
||||
if prompt "[?] setup the rust environment (e.g. WASM support)?"; then
|
||||
rustup default stable
|
||||
apply_patches_if_needed
|
||||
upgrade_compiler_if_needed
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ! -z $RELEASE ]]; then
|
||||
apply_patches_if_needed
|
||||
upgrade_compiler_if_needed
|
||||
if prompt "[?] 'cargo build $RELEASE $FEATURES' is what you want?"; then
|
||||
cd $PROJECT_FOLDER
|
||||
echo "[+] starting build in 3 seconds..."
|
||||
@ -533,51 +542,6 @@ if [ $UNIT_FILE = true ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $FIX_WEAVER_KEYSTORE = true ]; then
|
||||
echo "[+] Starting keystore prefix fix (weav -> wevr)..."
|
||||
|
||||
KEYSTORE_DIR="${BASE_PATH%/}/chains/${SPECIFICATION_NAME}_staging_testnet/keystore"
|
||||
|
||||
echo "[+] Requesting sudo privileges to modify keystore files..."
|
||||
sudo -v
|
||||
|
||||
if ! sudo test -d "$KEYSTORE_DIR"; then
|
||||
echo "[-] Keystore directory not found at: $KEYSTORE_DIR"
|
||||
echo "[-] Please check your --base-path and --specification-name settings."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
WRONG_PREFIX="77656176" # "weav"
|
||||
CORRECT_PREFIX="77657672" # "wevr"
|
||||
CHANGES_MADE=0
|
||||
|
||||
while IFS= read -r file; do
|
||||
if sudo test -f "$file"; then
|
||||
filename=$(basename "$file")
|
||||
if [[ "$filename" == "$WRONG_PREFIX"* ]]; then
|
||||
new_filename="${CORRECT_PREFIX}${filename#$WRONG_PREFIX}"
|
||||
new_file_path="$KEYSTORE_DIR/$new_filename"
|
||||
|
||||
if sudo test -f "$new_file_path"; then
|
||||
echo "[!] WARNING: File with correct prefix already exists: $new_filename. Skipping."
|
||||
else
|
||||
sudo mv "$file" "$new_file_path"
|
||||
echo "[+] Renamed: $filename -> $new_filename"
|
||||
CHANGES_MADE=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done < <(sudo find "$KEYSTORE_DIR" -maxdepth 1 -type f)
|
||||
|
||||
if [ $CHANGES_MADE -eq 1 ]; then
|
||||
echo "[+] Keystore fix applied successfully."
|
||||
echo "[+] IMPORTANT: You must restart the ghost-node service for changes to take effect."
|
||||
echo "[+] Run: sudo systemctl restart ghost-node"
|
||||
else
|
||||
echo "[+] No files with the wrong 'weav' prefix were found. Everything is fine."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$GENERATE_GENESIS" = true ]; then
|
||||
echo "[+] Generating keys for genesis configuration..."
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user