Compare commits
45 Commits
pen_i12072
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| cc7721e389 | |||
| 5622336d3f | |||
| 07cf35d08c | |||
| 8dfc37e97e | |||
| d973b096d9 | |||
| 4842fc5108 | |||
| d43c616749 | |||
| 52a1aa0fab | |||
| c25c3edd30 | |||
| 2ade4c9637 | |||
| 014ed7d5dc | |||
| a7d3a3fee8 | |||
| 844fc81680 | |||
| 8e44a7f5d2 | |||
| 5380ac0b36 | |||
| 9610423617 | |||
| d0db73170d | |||
| d18b8ba11f | |||
| c22925d758 | |||
| 6df2088756 | |||
| 6ae8fd9ed4 | |||
| ba575d0ab8 | |||
| ab7f978ccc | |||
| 66ca7545ce | |||
| bdbf7bd20f | |||
| f72387c9cb | |||
| d940ede8ac | |||
| 653bf08486 | |||
| 1dc61fb17d | |||
| d488bf9a43 | |||
| 74d74f4037 | |||
| 7ad0159517 | |||
| c884ec7b77 | |||
| e3a81e3902 | |||
| d7ac7885b6 | |||
| f3e7122d43 | |||
| 84b6dfad9f | |||
| b6759bac6f | |||
| 5f39a7d9b1 | |||
| 8abd114a5b | |||
| 6b0033425c | |||
| f77ca05d3f | |||
| 339ea52864 | |||
| d8bfe2a2ac | |||
| 77bf4419e0 |
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -1195,7 +1195,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "casper-runtime"
|
name = "casper-runtime"
|
||||||
version = "4.0.14"
|
version = "4.0.20"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"casper-runtime-constants",
|
"casper-runtime-constants",
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
@ -1209,6 +1209,7 @@ dependencies = [
|
|||||||
"frame-try-runtime",
|
"frame-try-runtime",
|
||||||
"ghost-core-primitives",
|
"ghost-core-primitives",
|
||||||
"ghost-exodus",
|
"ghost-exodus",
|
||||||
|
"ghost-exodus-runtime-api",
|
||||||
"ghost-governance",
|
"ghost-governance",
|
||||||
"ghost-helpers",
|
"ghost-helpers",
|
||||||
"ghost-networks",
|
"ghost-networks",
|
||||||
@ -3684,7 +3685,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghost-exodus"
|
name = "ghost-exodus"
|
||||||
version = "0.0.17"
|
version = "0.1.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
@ -3694,6 +3695,7 @@ dependencies = [
|
|||||||
"frost-core",
|
"frost-core",
|
||||||
"frost-ed25519",
|
"frost-ed25519",
|
||||||
"frost-secp256k1-tr",
|
"frost-secp256k1-tr",
|
||||||
|
"ghost-exodus-runtime-api",
|
||||||
"ghost-helpers",
|
"ghost-helpers",
|
||||||
"ghost-networks",
|
"ghost-networks",
|
||||||
"ghost-traits",
|
"ghost-traits",
|
||||||
@ -3725,15 +3727,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghost-exodus-runtime-api"
|
name = "ghost-exodus-runtime-api"
|
||||||
version = "0.0.0"
|
version = "0.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ghost-helpers",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"sp-api",
|
"sp-api",
|
||||||
|
"sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.12.0)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghost-governance"
|
name = "ghost-governance"
|
||||||
version = "0.3.10"
|
version = "0.3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
@ -3758,7 +3762,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghost-helpers"
|
name = "ghost-helpers"
|
||||||
version = "0.0.11"
|
version = "0.0.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"ghost-traits",
|
"ghost-traits",
|
||||||
@ -3840,7 +3844,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghost-networks"
|
name = "ghost-networks"
|
||||||
version = "0.2.10"
|
version = "0.2.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
@ -4086,7 +4090,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghost-traits"
|
name = "ghost-traits"
|
||||||
version = "0.4.6"
|
version = "0.4.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frost-core",
|
"frost-core",
|
||||||
@ -4110,7 +4114,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghost-weaver"
|
name = "ghost-weaver"
|
||||||
version = "0.0.14"
|
version = "0.0.27"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
|
|||||||
@ -239,6 +239,7 @@ ghost-networks = { path = "pallets/networks", default-features = false }
|
|||||||
ghost-governance = { path = "pallets/governance", default-features = false }
|
ghost-governance = { path = "pallets/governance", default-features = false }
|
||||||
ghost-weaver = { path = "pallets/weaver", default-features = false }
|
ghost-weaver = { path = "pallets/weaver", default-features = false }
|
||||||
ghost-exodus = { path = "pallets/exodus", 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-sudo = { path = "pallets/sudo", default-features = false }
|
||||||
ghost-nomination-pools = { path = "pallets/pools", 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 }
|
ghost-nomination-pools-runtime-api = { path = "pallets/pools/runtime-api", default-features = false }
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ghost-exodus"
|
name = "ghost-exodus"
|
||||||
version = "0.0.17"
|
version = "0.1.7"
|
||||||
description = "Threshold signature generation with DKG included"
|
description = "Threshold signature generation with DKG included"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
@ -40,6 +40,7 @@ parking_lot = { workspace = true }
|
|||||||
|
|
||||||
ghost-traits = { workspace = true }
|
ghost-traits = { workspace = true }
|
||||||
ghost-helpers = { workspace = true }
|
ghost-helpers = { workspace = true }
|
||||||
|
ghost-exodus-runtime-api = { workspace = true }
|
||||||
|
|
||||||
pallet-balances = { workspace = true }
|
pallet-balances = { workspace = true }
|
||||||
pallet-session = { workspace = true }
|
pallet-session = { workspace = true }
|
||||||
@ -80,6 +81,7 @@ std = [
|
|||||||
"frost-core/std",
|
"frost-core/std",
|
||||||
"ghost-traits/std",
|
"ghost-traits/std",
|
||||||
"ghost-helpers/std",
|
"ghost-helpers/std",
|
||||||
|
"ghost-exodus-runtime-api/std",
|
||||||
"pallet-balances/std",
|
"pallet-balances/std",
|
||||||
"pallet-session/std",
|
"pallet-session/std",
|
||||||
"pallet-staking/std",
|
"pallet-staking/std",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ghost-exodus-runtime-api"
|
name = "ghost-exodus-runtime-api"
|
||||||
version = "0.0.0"
|
version = "0.0.2"
|
||||||
description = "RPC runtime API for ghost EXODUS pallet"
|
description = "RPC runtime API for ghost EXODUS pallet"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
@ -14,7 +14,14 @@ targets = ["x86_64-unknown-linux-gnu"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
codec = { workspace = true, features = ["derive"] }
|
codec = { workspace = true, features = ["derive"] }
|
||||||
sp-api = { workspace = true }
|
sp-api = { workspace = true }
|
||||||
|
sp-std = { workspace = true }
|
||||||
|
ghost-helpers = { workspace = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["codec/std", "sp-api/std"]
|
std = [
|
||||||
|
"codec/std",
|
||||||
|
"sp-api/std",
|
||||||
|
"sp-std/std",
|
||||||
|
"ghost-helpers/std",
|
||||||
|
]
|
||||||
|
|||||||
@ -1,7 +1,17 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![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! {
|
sp_api::decl_runtime_apis! {
|
||||||
pub trait ExodusApi<NetworkId> {
|
pub trait ExodusApi {
|
||||||
fn verifying_key(network_id: NetworkId) -> Vec<u8>;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use frame_system::RawOrigin;
|
|||||||
use ghost_helpers::networks::NetworkDataBuilder;
|
use ghost_helpers::networks::NetworkDataBuilder;
|
||||||
|
|
||||||
fn prepare_pallet<T: Config>(authorities_len: usize) -> (
|
fn prepare_pallet<T: Config>(authorities_len: usize) -> (
|
||||||
PendingDkgAuthorities<ParticipantsBitmap<T>, BlockNumberFor<T>>,
|
PendingDkgAuthorities<T>,
|
||||||
NetworkCurve,
|
NetworkCurve,
|
||||||
T::AuthorityId,
|
T::AuthorityId,
|
||||||
AuthIndex
|
AuthIndex
|
||||||
@ -47,11 +47,13 @@ mod benchmarks {
|
|||||||
prepare_pallet::<T>(1);
|
prepare_pallet::<T>(1);
|
||||||
|
|
||||||
dkg_state.next_phase();
|
dkg_state.next_phase();
|
||||||
|
let dkg_index = dkg_state.get_dkg_index();
|
||||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||||
|
|
||||||
let round0_package = PackageContext::default()
|
let round0_package = PackageContext::default()
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(0)
|
.with_authority_index(0)
|
||||||
|
.with_dkg_index(dkg_index)
|
||||||
.with_dkg_round0(dummy_hash);
|
.with_dkg_round0(dummy_hash);
|
||||||
|
|
||||||
let dkg_package = DkgPackage::Round0(round0_package);
|
let dkg_package = DkgPackage::Round0(round0_package);
|
||||||
@ -83,10 +85,10 @@ mod benchmarks {
|
|||||||
dkg_state.next_phase();
|
dkg_state.next_phase();
|
||||||
|
|
||||||
dkg_state.insert_index(authority_index);
|
dkg_state.insert_index(authority_index);
|
||||||
|
let dkg_index = dkg_state.get_dkg_index();
|
||||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||||
|
|
||||||
let mut rng = Pallet::<T>::get_offchain_rng(authority_index);
|
let mut rng = ChaCha20Rng::seed_from_u64(694201337);
|
||||||
|
|
||||||
let (_, public_package) = network_curve.dkg_part1(
|
let (_, public_package) = network_curve.dkg_part1(
|
||||||
authority_index,
|
authority_index,
|
||||||
max_signers,
|
max_signers,
|
||||||
@ -97,9 +99,12 @@ mod benchmarks {
|
|||||||
let package_hash = ExodusHash::from(blake2_256(&public_package));
|
let package_hash = ExodusHash::from(blake2_256(&public_package));
|
||||||
Round0Packages::<T>::insert(network_curve, authority_index, package_hash);
|
Round0Packages::<T>::insert(network_curve, authority_index, package_hash);
|
||||||
|
|
||||||
|
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||||
let round1_package = PackageContext::default()
|
let round1_package = PackageContext::default()
|
||||||
|
.with_block_number(current_block)
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(0)
|
.with_authority_index(0)
|
||||||
|
.with_dkg_index(dkg_index)
|
||||||
.with_dkg_round1(public_package)
|
.with_dkg_round1(public_package)
|
||||||
.expect("Round1 package should be valid");
|
.expect("Round1 package should be valid");
|
||||||
|
|
||||||
@ -120,9 +125,9 @@ mod benchmarks {
|
|||||||
|
|
||||||
#[benchmark]
|
#[benchmark]
|
||||||
fn register_encrypted_round2_packages(
|
fn register_encrypted_round2_packages(
|
||||||
c: Linear<1, { T::MaxAuthorities::get() / 8 }>
|
c: Linear<1, { T::MaxAuthorities::get() }>
|
||||||
) -> Result<(), BenchmarkError> {
|
) -> Result<(), BenchmarkError> {
|
||||||
let max_signers = (c * 8) as AuthIndex;
|
let max_signers = c as AuthIndex;
|
||||||
|
|
||||||
let (mut dkg_state, network_curve, authority, authority_index) =
|
let (mut dkg_state, network_curve, authority, authority_index) =
|
||||||
prepare_pallet::<T>(max_signers as usize);
|
prepare_pallet::<T>(max_signers as usize);
|
||||||
@ -131,6 +136,8 @@ mod benchmarks {
|
|||||||
dkg_state.next_phase();
|
dkg_state.next_phase();
|
||||||
dkg_state.next_phase();
|
dkg_state.next_phase();
|
||||||
|
|
||||||
|
let dkg_index = dkg_state.get_dkg_index();
|
||||||
|
|
||||||
(0..max_signers).for_each(|i| {
|
(0..max_signers).for_each(|i| {
|
||||||
dkg_state.insert_index(i);
|
dkg_state.insert_index(i);
|
||||||
});
|
});
|
||||||
@ -142,29 +149,29 @@ mod benchmarks {
|
|||||||
|
|
||||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||||
|
|
||||||
let bitmask_len = padded_participants.div_ceil(8);
|
|
||||||
let blob_len = round2_encrypted_package_size(
|
let blob_len = round2_encrypted_package_size(
|
||||||
padded_participants,
|
padded_participants - 1,
|
||||||
network_curve.scalar_bytes_len(),
|
network_curve.scalar_bytes_len(),
|
||||||
network_curve.header_bytes_len(),
|
network_curve.header_bytes_len(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut bitmask = vec![0u8; bitmask_len];
|
let mut bitmask = ParticipantsBitmap::<T>::empty(padded_participants);
|
||||||
let blob = vec![0u8; blob_len];
|
let blob = vec![0u8; blob_len];
|
||||||
|
|
||||||
(0..max_signers).for_each(|i| {
|
(0..max_signers).for_each(|i| {
|
||||||
if i != authority_index {
|
if i != authority_index {
|
||||||
let byte_index = (i / 8) as usize;
|
bitmask.insert(i);
|
||||||
let bit_index = (i % 8) as u8;
|
|
||||||
bitmask[byte_index] |= 1 << bit_index;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let encryption_bundle = BundledPackages { bitmask, blob };
|
let encryption_bundle = BundledPackages { bitmask, blob };
|
||||||
|
|
||||||
|
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||||
let round2_package = PackageContext::default()
|
let round2_package = PackageContext::default()
|
||||||
|
.with_block_number(current_block)
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
|
.with_dkg_index(dkg_index)
|
||||||
.with_dkg_round2(encryption_bundle)
|
.with_dkg_round2(encryption_bundle)
|
||||||
.expect("Round2 package should be valid");
|
.expect("Round2 package should be valid");
|
||||||
|
|
||||||
@ -185,9 +192,9 @@ mod benchmarks {
|
|||||||
|
|
||||||
#[benchmark]
|
#[benchmark]
|
||||||
fn register_round3_complaints(
|
fn register_round3_complaints(
|
||||||
c: Linear<1, { T::MaxAuthorities::get() / 8 }>
|
c: Linear<1, { T::MaxAuthorities::get() }>
|
||||||
) -> Result<(), BenchmarkError> {
|
) -> Result<(), BenchmarkError> {
|
||||||
let max_signers = (c * 8) as AuthIndex;
|
let max_signers = c as AuthIndex;
|
||||||
|
|
||||||
let (mut dkg_state, network_curve, authority, authority_index) =
|
let (mut dkg_state, network_curve, authority, authority_index) =
|
||||||
prepare_pallet::<T>(max_signers as usize);
|
prepare_pallet::<T>(max_signers as usize);
|
||||||
@ -197,26 +204,28 @@ mod benchmarks {
|
|||||||
dkg_state.next_phase();
|
dkg_state.next_phase();
|
||||||
dkg_state.next_phase();
|
dkg_state.next_phase();
|
||||||
|
|
||||||
|
let dkg_index = dkg_state.get_dkg_index();
|
||||||
|
|
||||||
(0..max_signers).for_each(|i| {
|
(0..max_signers).for_each(|i| {
|
||||||
dkg_state.insert_index(i);
|
dkg_state.insert_index(i);
|
||||||
});
|
});
|
||||||
|
|
||||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||||
|
|
||||||
let bitvec_len = (max_signers + 7) / 8;
|
let mut accused_indexes = ParticipantsBitmap::<T>::empty(max_signers);
|
||||||
let mut accused_indexes = vec![0u8; bitvec_len as usize];
|
|
||||||
|
|
||||||
(0..max_signers).for_each(|i| {
|
(0..max_signers).for_each(|i| {
|
||||||
if i != authority_index {
|
if i != authority_index {
|
||||||
let byte_index = (i / 8) as usize;
|
accused_indexes.insert(i);
|
||||||
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()
|
let round3_package = PackageContext::default()
|
||||||
|
.with_block_number(current_block)
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
|
.with_dkg_index(dkg_index)
|
||||||
.with_dkg_round3(accused_indexes)
|
.with_dkg_round3(accused_indexes)
|
||||||
.expect("Round3 package should be valid");
|
.expect("Round3 package should be valid");
|
||||||
|
|
||||||
@ -240,9 +249,9 @@ mod benchmarks {
|
|||||||
|
|
||||||
#[benchmark]
|
#[benchmark]
|
||||||
fn register_round4_justifications(
|
fn register_round4_justifications(
|
||||||
c: Linear<1, { T::MaxAuthorities::get() / 8 }>
|
c: Linear<1, { T::MaxAuthorities::get() }>
|
||||||
) -> Result<(), BenchmarkError> {
|
) -> Result<(), BenchmarkError> {
|
||||||
let max_signers = (c * 8) as AuthIndex;
|
let max_signers = c as AuthIndex;
|
||||||
|
|
||||||
let (mut dkg_state, network_curve, authority, authority_index) =
|
let (mut dkg_state, network_curve, authority, authority_index) =
|
||||||
prepare_pallet::<T>(max_signers as usize);
|
prepare_pallet::<T>(max_signers as usize);
|
||||||
@ -253,6 +262,8 @@ mod benchmarks {
|
|||||||
dkg_state.next_phase();
|
dkg_state.next_phase();
|
||||||
dkg_state.next_phase();
|
dkg_state.next_phase();
|
||||||
|
|
||||||
|
let dkg_index = dkg_state.get_dkg_index();
|
||||||
|
|
||||||
(0..max_signers).for_each(|i| {
|
(0..max_signers).for_each(|i| {
|
||||||
dkg_state.insert_index(i);
|
dkg_state.insert_index(i);
|
||||||
});
|
});
|
||||||
@ -264,29 +275,29 @@ mod benchmarks {
|
|||||||
|
|
||||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||||
|
|
||||||
let bitmask_len = padded_participants.div_ceil(8);
|
|
||||||
let blob_len = round2_package_size(
|
let blob_len = round2_package_size(
|
||||||
padded_participants,
|
padded_participants - 1,
|
||||||
network_curve.scalar_bytes_len(),
|
network_curve.scalar_bytes_len(),
|
||||||
network_curve.header_bytes_len(),
|
network_curve.header_bytes_len(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut bitmask = vec![0u8; bitmask_len];
|
let mut bitmask = ParticipantsBitmap::<T>::empty(padded_participants);
|
||||||
let blob = vec![0u8; blob_len];
|
let blob = vec![0u8; blob_len];
|
||||||
|
|
||||||
(0..max_signers).for_each(|i| {
|
(0..max_signers).for_each(|i| {
|
||||||
if i != authority_index {
|
if i != authority_index {
|
||||||
let byte_index = (i / 8) as usize;
|
bitmask.insert(i);
|
||||||
let bit_index = (i % 8) as u8;
|
|
||||||
bitmask[byte_index] |= 1 << bit_index;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let justification_bundle = BundledPackages { bitmask, blob };
|
let justification_bundle = BundledPackages { bitmask, blob };
|
||||||
|
|
||||||
|
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||||
let round4_package = PackageContext::default()
|
let round4_package = PackageContext::default()
|
||||||
|
.with_block_number(current_block)
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
|
.with_dkg_index(dkg_index)
|
||||||
.with_dkg_round4(justification_bundle)
|
.with_dkg_round4(justification_bundle)
|
||||||
.expect("Round4 package should be valid");
|
.expect("Round4 package should be valid");
|
||||||
|
|
||||||
@ -332,11 +343,19 @@ mod benchmarks {
|
|||||||
|
|
||||||
let dummy_merkle_root = ExodusHash::repeat_byte(69);
|
let dummy_merkle_root = ExodusHash::repeat_byte(69);
|
||||||
let dummy_verifying_key = vec![69u8; network_curve.element_bytes_len()];
|
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()
|
let round5_package = PackageContext::default()
|
||||||
|
.with_block_number(current_block)
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
.with_dkg_round5(dummy_verifying_key.clone(), dummy_merkle_root)
|
.with_dkg_index(dkg_index)
|
||||||
|
.with_dkg_round5(
|
||||||
|
dummy_verifying_key.clone(),
|
||||||
|
dummy_key_members.clone(),
|
||||||
|
dummy_merkle_root,
|
||||||
|
)
|
||||||
.expect("Round5 package should be valid");
|
.expect("Round5 package should be valid");
|
||||||
|
|
||||||
let dkg_package = DkgPackage::Round5(round5_package);
|
let dkg_package = DkgPackage::Round5(round5_package);
|
||||||
@ -354,20 +373,22 @@ mod benchmarks {
|
|||||||
).expect("Bounded verifying key should be correct");
|
).expect("Bounded verifying key should be correct");
|
||||||
|
|
||||||
let metadata_hashes = [
|
let metadata_hashes = [
|
||||||
SubstrateBlake2Hasher::hash(dummy_merkle_root.as_ref()),
|
dummy_merkle_root.as_ref(),
|
||||||
SubstrateBlake2Hasher::hash(bounded_verifying_key.as_ref()),
|
bounded_verifying_key.as_ref(),
|
||||||
|
dummy_key_members.inner_as_ref(),
|
||||||
];
|
];
|
||||||
let verifying_hash = sequential_hash::<SubstrateBlake2Hasher, _>(metadata_hashes);
|
let verifying_hash = cumulative_hash::<SubstrateBlake2Hasher, _>(metadata_hashes);
|
||||||
|
|
||||||
let verification_key = (network_curve, dkg_index, verifying_hash);
|
let verification_key = (network_curve, dkg_index, verifying_hash);
|
||||||
let participants = Verifications::<T>::get(verification_key);
|
let participants = Verifications::<T>::get(verification_key);
|
||||||
assert!(participants.contains(authority_index));
|
assert!(participants.contains(authority_index));
|
||||||
|
|
||||||
let consensus = VerifyingKeyConsensus::<T>::get(&network_curve, dkg_index);
|
let consensus = VerifyingKeyConsensus::<T>::get(&network_curve, dkg_index);
|
||||||
assert!(consensus.participants.contains(authority_index));
|
assert!(consensus.state.participants.contains(authority_index));
|
||||||
assert_eq!(consensus.participants.count_ones::<AuthIndex>(), 1);
|
assert_eq!(consensus.state.participants.count_ones::<AuthIndex>(), 1);
|
||||||
assert_eq!(consensus.merkle_root, dummy_merkle_root);
|
assert_eq!(consensus.state.merkle_root, dummy_merkle_root);
|
||||||
assert_eq!(consensus.element_bytes, bounded_verifying_key);
|
assert_eq!(consensus.state.element_bytes, bounded_verifying_key);
|
||||||
|
assert_eq!(consensus.members, dummy_key_members);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -415,10 +436,16 @@ mod benchmarks {
|
|||||||
dummy_values.insert(identifier, dummy_value.clone());
|
dummy_values.insert(identifier, dummy_value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let identifier_size = network_curve.scalar_bytes_len();
|
||||||
|
|
||||||
let merkle_tree =
|
let merkle_tree =
|
||||||
NetworkCurve::build_merkle_tree(
|
NetworkCurve::build_merkle_tree(
|
||||||
|
identifier_size + dummy_value.len(),
|
||||||
&dummy_values,
|
&dummy_values,
|
||||||
|value: &Vec<u8>| Ok(value.clone()),
|
|value, buffer| {
|
||||||
|
buffer.extend_from_slice(value.as_ref());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
).expect("Merkle tree for verifying shares should be valid");
|
).expect("Merkle tree for verifying shares should be valid");
|
||||||
|
|
||||||
let merkle_root = merkle_tree.last().copied().unwrap();
|
let merkle_root = merkle_tree.last().copied().unwrap();
|
||||||
@ -434,13 +461,16 @@ mod benchmarks {
|
|||||||
});
|
});
|
||||||
|
|
||||||
VerifyingKeyConsensus::<T>::mutate(&network_curve, &dkg_index, |consensus| {
|
VerifyingKeyConsensus::<T>::mutate(&network_curve, &dkg_index, |consensus| {
|
||||||
consensus.participants.insert(authority_index);
|
consensus.state.participants.insert(authority_index);
|
||||||
consensus.merkle_root = dummy_merkle_root;
|
consensus.state.merkle_root = dummy_merkle_root;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||||
let round6_package = PackageContext::default()
|
let round6_package = PackageContext::default()
|
||||||
|
.with_block_number(current_block)
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
|
.with_dkg_index(dkg_index)
|
||||||
.with_dkg_round6(dummy_verifying_share.clone(), dummy_merkle_proof)
|
.with_dkg_round6(dummy_verifying_share.clone(), dummy_merkle_proof)
|
||||||
.expect("Round6 package should be valid");
|
.expect("Round6 package should be valid");
|
||||||
|
|
||||||
@ -482,10 +512,22 @@ mod benchmarks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dkg_state.insert_index(authority_index);
|
dkg_state.insert_index(authority_index);
|
||||||
let exodus_session = CurrentExodus::<T>::get();
|
let all_exodus_sessions = CurrentExodusSessions::<T>::get();
|
||||||
|
let exodus_session = all_exodus_sessions
|
||||||
|
.get(&network_id)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let dummy_context = ExodusContext::new(network_id, exodus_session);
|
||||||
let dummy_address = EvmAddress::repeat_byte(69);
|
let dummy_address = EvmAddress::repeat_byte(69);
|
||||||
let dummy_nonce = vec![0u8; network_curve.element_bytes_len()];
|
|
||||||
|
// 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 create_bond = GovernanceAction::Create {
|
let create_bond = GovernanceAction::Create {
|
||||||
market: [69, 420, 1337, 0],
|
market: [69, 420, 1337, 0],
|
||||||
@ -494,27 +536,30 @@ mod benchmarks {
|
|||||||
intervals: [34, 35],
|
intervals: [34, 35],
|
||||||
booleans: [true, true],
|
booleans: [true, true],
|
||||||
};
|
};
|
||||||
let request = ExodusRequest::<NetworkIdOf<T>, BalanceOf<T>>::evm_governance(
|
let request = ExodusRequest::<T>::evm_governance(
|
||||||
exodus_session,
|
|
||||||
network_id,
|
|
||||||
dummy_address,
|
dummy_address,
|
||||||
create_bond,
|
create_bond,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||||
let authorities = QualificationAuthorities::<T>::get(&network_curve);
|
let authorities = QualificationAuthorities::<T>::get(&network_curve);
|
||||||
let active_dkg: ActivatedState<T> = (&dkg_state).into();
|
let active_dkg: ReadyDkgAuthorities<T> = (&dkg_state).into();
|
||||||
|
let active_dkg_index = active_dkg.get_dkg_index();
|
||||||
|
|
||||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||||
ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
|
ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
|
||||||
ActiveAuthorities::<T>::insert(&network_curve, authorities);
|
ActiveAuthorities::<T>::insert(&network_curve, authorities);
|
||||||
ExodusRequests::<T>::insert((network_curve, exodus_session), request);
|
ExodusRequests::<T>::insert((&network_curve, &dummy_context), request);
|
||||||
|
|
||||||
let nonce_package = PackageContext::default()
|
let nonce_package = PackageContext::default()
|
||||||
|
.with_block_number(current_block)
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
|
.with_dkg_index(active_dkg_index)
|
||||||
.with_exodus_nonce_commitment(
|
.with_exodus_nonce_commitment(
|
||||||
exodus_session,
|
dummy_context,
|
||||||
dummy_nonce.clone(),
|
dummy_nonce.to_vec(),
|
||||||
dummy_nonce.clone(),
|
dummy_nonce.to_vec(),
|
||||||
)
|
)
|
||||||
.expect("Nonce commitment package should be valid");
|
.expect("Nonce commitment package should be valid");
|
||||||
|
|
||||||
@ -527,21 +572,21 @@ mod benchmarks {
|
|||||||
#[extrinsic_call]
|
#[extrinsic_call]
|
||||||
_(RawOrigin::None, exodus_package, signature);
|
_(RawOrigin::None, exodus_package, signature);
|
||||||
|
|
||||||
let roast_session = RoastSessions::<T>::get(&exodus_session, authority_index)
|
let roast_session = RoastSessions::<T>::get(&dummy_context, authority_index)
|
||||||
.expect("ROAST session should exist after nonce commitment");
|
.expect("ROAST session should exist after nonce commitment");
|
||||||
|
|
||||||
let roast_state = RoastSessionStates::<T>::get(&exodus_session, roast_session);
|
let roast_state = RoastSessionStates::<T>::get(&dummy_context, roast_session);
|
||||||
assert!(roast_state.nonce_committers.contains(authority_index));
|
assert!(roast_state.nonce_committers.contains(authority_index));
|
||||||
assert!(!roast_state.group_committers.contains(authority_index));
|
assert!(!roast_state.group_committers.contains(authority_index));
|
||||||
assert!(!roast_state.partial_signers.contains(authority_index));
|
assert!(!roast_state.partial_signers.contains(authority_index));
|
||||||
|
|
||||||
let registered_nonces = NonceCommitments::<T>::get(
|
let registered_nonces = NonceCommitments::<T>::get(
|
||||||
(exodus_session, roast_session),
|
(dummy_context, roast_session),
|
||||||
authority_index,
|
authority_index,
|
||||||
).expect("Nonces should be registered during nonce commitment");
|
).expect("Nonces should be registered during nonce commitment");
|
||||||
|
|
||||||
assert_eq!(registered_nonces.hiding, dummy_nonce.clone());
|
assert_eq!(registered_nonces.hiding.as_ref(), dummy_nonce);
|
||||||
assert_eq!(registered_nonces.binding, dummy_nonce);
|
assert_eq!(registered_nonces.binding.as_ref(), dummy_nonce);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -558,8 +603,13 @@ mod benchmarks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dkg_state.insert_index(authority_index);
|
dkg_state.insert_index(authority_index);
|
||||||
let exodus_session = CurrentExodus::<T>::get();
|
let all_exodus_sessions = CurrentExodusSessions::<T>::get();
|
||||||
|
let exodus_session = all_exodus_sessions
|
||||||
|
.get(&network_id)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let dummy_context = ExodusContext::new(network_id, exodus_session);
|
||||||
let dummy_bytes = EvmBytes32::repeat_byte(69);
|
let dummy_bytes = EvmBytes32::repeat_byte(69);
|
||||||
let dummy_address = EvmAddress::repeat_byte(69);
|
let dummy_address = EvmAddress::repeat_byte(69);
|
||||||
let dummy_merkle_root = ExodusHash::repeat_byte(69);
|
let dummy_merkle_root = ExodusHash::repeat_byte(69);
|
||||||
@ -572,33 +622,36 @@ mod benchmarks {
|
|||||||
intervals: [34, 35],
|
intervals: [34, 35],
|
||||||
booleans: [true, true],
|
booleans: [true, true],
|
||||||
};
|
};
|
||||||
let request = ExodusRequest::<NetworkIdOf<T>, BalanceOf<T>>::evm_governance(
|
let request = ExodusRequest::<T>::evm_governance(
|
||||||
exodus_session,
|
|
||||||
network_id,
|
|
||||||
dummy_address,
|
dummy_address,
|
||||||
create_bond,
|
create_bond,
|
||||||
);
|
);
|
||||||
|
|
||||||
let authorities = QualificationAuthorities::<T>::get(&network_curve);
|
let authorities = QualificationAuthorities::<T>::get(&network_curve);
|
||||||
let active_dkg: ActivatedState<T> = (&dkg_state).into();
|
let active_dkg: ReadyDkgAuthorities<T> = (&dkg_state).into();
|
||||||
|
let active_dkg_index = active_dkg.get_dkg_index();
|
||||||
|
|
||||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||||
ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
|
ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
|
||||||
ActiveAuthorities::<T>::insert(&network_curve, authorities);
|
ActiveAuthorities::<T>::insert(&network_curve, authorities);
|
||||||
ExodusRequests::<T>::insert((network_curve, exodus_session), request);
|
ExodusRequests::<T>::insert((network_curve, dummy_context), request);
|
||||||
|
|
||||||
let mut roast_state = RoastSessionState::<ParticipantsBitmap::<T>>::default();
|
let mut roast_state = RoastSessionState::<ParticipantsBitmap::<T>>::default();
|
||||||
roast_state.status = RoastStatus::GroupCommitments;
|
roast_state.status = RoastStatus::GroupCommitments;
|
||||||
roast_state.nonce_committers.insert(authority_index);
|
roast_state.nonce_committers.insert(authority_index);
|
||||||
|
|
||||||
let roast_session = 3;
|
let roast_session = 3;
|
||||||
RoastSessions::<T>::insert(&exodus_session, authority_index, roast_session);
|
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||||
RoastSessionStates::<T>::insert(exodus_session, roast_session, roast_state);
|
RoastSessions::<T>::insert(&dummy_context, authority_index, roast_session);
|
||||||
|
RoastSessionStates::<T>::insert(dummy_context, roast_session, roast_state);
|
||||||
|
|
||||||
let group_package = PackageContext::default()
|
let group_package = PackageContext::default()
|
||||||
|
.with_block_number(current_block)
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
|
.with_dkg_index(active_dkg_index)
|
||||||
.with_exodus_group_commitment(
|
.with_exodus_group_commitment(
|
||||||
exodus_session,
|
dummy_context,
|
||||||
dummy_group_commitment.clone(),
|
dummy_group_commitment.clone(),
|
||||||
dummy_bytes,
|
dummy_bytes,
|
||||||
)
|
)
|
||||||
@ -618,16 +671,16 @@ mod benchmarks {
|
|||||||
dummy_group_commitment,
|
dummy_group_commitment,
|
||||||
).expect("Group commtiment should be valid");
|
).expect("Group commtiment should be valid");
|
||||||
|
|
||||||
let roast_state = RoastSessionStates::<T>::get(&exodus_session, roast_session);
|
let roast_state = RoastSessionStates::<T>::get(&dummy_context, roast_session);
|
||||||
assert!(roast_state.nonce_committers.contains(authority_index));
|
assert!(roast_state.nonce_committers.contains(authority_index));
|
||||||
assert!(roast_state.group_committers.contains(authority_index));
|
assert!(roast_state.group_committers.contains(authority_index));
|
||||||
|
|
||||||
let consensus = GroupCommitmentsConsensus::<T>::get(exodus_session, roast_session);
|
let consensus = GroupCommitmentsConsensus::<T>::get(dummy_context, roast_session);
|
||||||
assert!(consensus.participants.contains(authority_index));
|
assert!(consensus.participants.contains(authority_index));
|
||||||
assert_eq!(&consensus.element_bytes, &bounded_group_commitment);
|
assert_eq!(&consensus.element_bytes, &bounded_group_commitment);
|
||||||
assert_eq!(consensus.merkle_root, dummy_merkle_root);
|
assert_eq!(consensus.merkle_root, dummy_merkle_root);
|
||||||
|
|
||||||
let group_commitment_key = (exodus_session, roast_session, dummy_merkle_root, bounded_group_commitment);
|
let group_commitment_key = (dummy_context, roast_session, dummy_merkle_root, bounded_group_commitment);
|
||||||
let participants = GroupCommitters::<T>::get(group_commitment_key);
|
let participants = GroupCommitters::<T>::get(group_commitment_key);
|
||||||
assert!(participants.contains(authority_index));
|
assert!(participants.contains(authority_index));
|
||||||
|
|
||||||
@ -650,7 +703,13 @@ mod benchmarks {
|
|||||||
|
|
||||||
dkg_state.insert_index(authority_index);
|
dkg_state.insert_index(authority_index);
|
||||||
let dkg_index = dkg_state.get_dkg_index();
|
let dkg_index = dkg_state.get_dkg_index();
|
||||||
let exodus_session = CurrentExodus::<T>::get();
|
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 mut dummy_element = vec![0u8; network_curve.element_bytes_len()];
|
let mut dummy_element = vec![0u8; network_curve.element_bytes_len()];
|
||||||
dummy_element[0] = 0x02;
|
dummy_element[0] = 0x02;
|
||||||
@ -670,9 +729,7 @@ mod benchmarks {
|
|||||||
intervals: [34, 35],
|
intervals: [34, 35],
|
||||||
booleans: [true, true],
|
booleans: [true, true],
|
||||||
};
|
};
|
||||||
let request = ExodusRequest::<NetworkIdOf<T>, BalanceOf<T>>::evm_governance(
|
let request = ExodusRequest::<T>::evm_governance(
|
||||||
exodus_session,
|
|
||||||
network_id,
|
|
||||||
dummy_address,
|
dummy_address,
|
||||||
create_bond,
|
create_bond,
|
||||||
);
|
);
|
||||||
@ -697,10 +754,16 @@ mod benchmarks {
|
|||||||
dummy_values.insert(identifier, dummy_binding_factor.clone());
|
dummy_values.insert(identifier, dummy_binding_factor.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let identifier_size = network_curve.scalar_bytes_len();
|
||||||
|
|
||||||
let merkle_tree =
|
let merkle_tree =
|
||||||
NetworkCurve::build_merkle_tree(
|
NetworkCurve::build_merkle_tree(
|
||||||
|
identifier_size + dummy_scalar.len(),
|
||||||
&dummy_values,
|
&dummy_values,
|
||||||
|value: &Vec<u8>| Ok(value.clone()),
|
|value, buffer| {
|
||||||
|
buffer.extend_from_slice(value.as_ref());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
).expect("Merkle tree for binding factor should be valid");
|
).expect("Merkle tree for binding factor should be valid");
|
||||||
|
|
||||||
let merkle_root = merkle_tree.last().copied().unwrap();
|
let merkle_root = merkle_tree.last().copied().unwrap();
|
||||||
@ -717,13 +780,13 @@ mod benchmarks {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let authorities = QualificationAuthorities::<T>::get(&network_curve);
|
let authorities = QualificationAuthorities::<T>::get(&network_curve);
|
||||||
let active_dkg: ActivatedState<T> = (&dkg_state).into();
|
let active_dkg: ReadyDkgAuthorities<T> = (&dkg_state).into();
|
||||||
let active_dkg_index = active_dkg.get_dkg_index();
|
let active_dkg_index = active_dkg.get_dkg_index();
|
||||||
|
|
||||||
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
QualificationDkgState::<T>::insert(&network_curve, dkg_state);
|
||||||
ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
|
ActiveDkgAuthorities::<T>::insert(&network_curve, active_dkg);
|
||||||
ActiveAuthorities::<T>::insert(&network_curve, authorities);
|
ActiveAuthorities::<T>::insert(&network_curve, authorities);
|
||||||
ExodusRequests::<T>::insert((network_curve, exodus_session), request);
|
ExodusRequests::<T>::insert((network_curve, exodus_context), request);
|
||||||
|
|
||||||
let mut roast_state = RoastSessionState::<ParticipantsBitmap::<T>>::default();
|
let mut roast_state = RoastSessionState::<ParticipantsBitmap::<T>>::default();
|
||||||
roast_state.status = RoastStatus::PartialSignatures;
|
roast_state.status = RoastStatus::PartialSignatures;
|
||||||
@ -736,8 +799,8 @@ mod benchmarks {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let roast_session = 3;
|
let roast_session = 3;
|
||||||
RoastSessions::<T>::insert(&exodus_session, authority_index, roast_session);
|
RoastSessions::<T>::insert(&exodus_context, authority_index, roast_session);
|
||||||
RoastSessionStates::<T>::insert(exodus_session, roast_session, roast_state);
|
RoastSessionStates::<T>::insert(exodus_context, roast_session, roast_state);
|
||||||
|
|
||||||
let bounded_group_commitment = BoundedVec::try_from(dummy_group_commitment).unwrap();
|
let bounded_group_commitment = BoundedVec::try_from(dummy_group_commitment).unwrap();
|
||||||
let dummy_verifying_key = BoundedVec::try_from(dummy_element.clone()).unwrap();
|
let dummy_verifying_key = BoundedVec::try_from(dummy_element.clone()).unwrap();
|
||||||
@ -750,9 +813,9 @@ mod benchmarks {
|
|||||||
|
|
||||||
ActiveVerifyingKey::<T>::insert(&network_curve, dummy_verifying_key);
|
ActiveVerifyingKey::<T>::insert(&network_curve, dummy_verifying_key);
|
||||||
VerifyingShares::<T>::insert((&network_curve, active_dkg_index, authority_index), dummy_verifying_share);
|
VerifyingShares::<T>::insert((&network_curve, active_dkg_index, authority_index), dummy_verifying_share);
|
||||||
NonceCommitments::<T>::insert((&exodus_session, &roast_session), authority_index, dummy_nonce);
|
NonceCommitments::<T>::insert((&exodus_context, &roast_session), authority_index, dummy_nonce);
|
||||||
|
|
||||||
GroupCommitmentsConsensus::<T>::mutate(&exodus_session, &roast_session, |consensus| {
|
GroupCommitmentsConsensus::<T>::mutate(&exodus_context, &roast_session, |consensus| {
|
||||||
consensus.element_bytes = bounded_group_commitment.clone();
|
consensus.element_bytes = bounded_group_commitment.clone();
|
||||||
consensus.merkle_root = dummy_merkle_root;
|
consensus.merkle_root = dummy_merkle_root;
|
||||||
(0..threshold).for_each(|i| {
|
(0..threshold).for_each(|i| {
|
||||||
@ -760,11 +823,14 @@ mod benchmarks {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let current_block = <T as Config>::BlockNumberProvider::current_block_number();
|
||||||
let share_package = PackageContext::default()
|
let share_package = PackageContext::default()
|
||||||
|
.with_block_number(current_block)
|
||||||
.with_network_curve(NetworkCurve::Secp256k1)
|
.with_network_curve(NetworkCurve::Secp256k1)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
|
.with_dkg_index(active_dkg_index)
|
||||||
.with_exodus_signature_share(
|
.with_exodus_signature_share(
|
||||||
exodus_session,
|
exodus_context,
|
||||||
dummy_signature_share.clone(),
|
dummy_signature_share.clone(),
|
||||||
dummy_merkle_proof,
|
dummy_merkle_proof,
|
||||||
dummy_binding_factor
|
dummy_binding_factor
|
||||||
@ -780,13 +846,13 @@ mod benchmarks {
|
|||||||
#[extrinsic_call]
|
#[extrinsic_call]
|
||||||
_(RawOrigin::None, exodus_package, signature);
|
_(RawOrigin::None, exodus_package, signature);
|
||||||
|
|
||||||
let maybe_roast_session = RoastSessions::<T>::get(&exodus_session, authority_index);
|
let maybe_roast_session = RoastSessions::<T>::get(&exodus_context, authority_index);
|
||||||
assert!(maybe_roast_session.is_none());
|
assert!(maybe_roast_session.is_none());
|
||||||
|
|
||||||
let scalar_exists = SignatureScalars::<T>::contains_key(&exodus_session, &roast_session);
|
let scalar_exists = SignatureScalars::<T>::contains_key(&exodus_context, &roast_session);
|
||||||
let consensus_exists = GroupCommitmentsConsensus::<T>::contains_key(&exodus_session, &roast_session);
|
let consensus_exists = GroupCommitmentsConsensus::<T>::contains_key(&exodus_context, &roast_session);
|
||||||
let committers_exists = GroupCommitters::<T>::contains_key((
|
let committers_exists = GroupCommitters::<T>::contains_key((
|
||||||
&exodus_session,
|
&exodus_context,
|
||||||
&roast_session,
|
&roast_session,
|
||||||
&dummy_merkle_root,
|
&dummy_merkle_root,
|
||||||
&bounded_group_commitment,
|
&bounded_group_commitment,
|
||||||
@ -796,8 +862,8 @@ mod benchmarks {
|
|||||||
assert!(!consensus_exists);
|
assert!(!consensus_exists);
|
||||||
assert!(!committers_exists);
|
assert!(!committers_exists);
|
||||||
|
|
||||||
assert!(!ExodusRequests::<T>::contains_key((&network_curve, &exodus_session)));
|
assert!(!ExodusRequests::<T>::contains_key((&network_curve, &exodus_context)));
|
||||||
assert!(ExodusSignedGovernance::<T>::contains_key((&exodus_session, network_id), dkg_index));
|
assert!(ExodusSignedGovernance::<T>::contains_key(dkg_index, &exodus_context));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -829,7 +895,11 @@ mod benchmarks {
|
|||||||
let _ = T::NetworkDataHandler::register_incoming(&network_id, amount).unwrap();
|
let _ = T::NetworkDataHandler::register_incoming(&network_id, amount).unwrap();
|
||||||
|
|
||||||
let total_issuance = T::Currency::total_issuance();
|
let total_issuance = T::Currency::total_issuance();
|
||||||
let current_exodus_session = CurrentExodus::<T>::get();
|
let all_exodus_sessions = CurrentExodusSessions::<T>::get();
|
||||||
|
let current_exodus_session = all_exodus_sessions
|
||||||
|
.get(&network_id)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
#[extrinsic_call]
|
#[extrinsic_call]
|
||||||
_(
|
_(
|
||||||
@ -840,8 +910,12 @@ mod benchmarks {
|
|||||||
receiver,
|
receiver,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(ExodusRequests::<T>::contains_key((&network_curve, current_exodus_session)));
|
let all_exodus_sessions = CurrentExodusSessions::<T>::get();
|
||||||
assert_eq!(CurrentExodus::<T>::get(), current_exodus_session + 1);
|
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::balance(&caller), initial_balance - amount);
|
||||||
assert_eq!(T::Currency::total_issuance(), total_issuance - amount);
|
assert_eq!(T::Currency::total_issuance(), total_issuance - amount);
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,7 @@ pub enum ExodusError {
|
|||||||
InvalidMerkleProof,
|
InvalidMerkleProof,
|
||||||
InvalidIdentityElement,
|
InvalidIdentityElement,
|
||||||
NoActiveAuthorities,
|
NoActiveAuthorities,
|
||||||
|
TreeGenerationFailed,
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ impl core::fmt::Debug for ExodusError {
|
|||||||
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::InvalidIdentityElement => write!(fmt, "Invalid identity element provided."),
|
||||||
ExodusError::NoActiveAuthorities => write!(fmt, "No active authorities for signing EXODUS transactions."),
|
ExodusError::NoActiveAuthorities => write!(fmt, "No active authorities for signing EXODUS transactions."),
|
||||||
|
ExodusError::TreeGenerationFailed => write!(fmt, "Tree generation failed because of inconsistent indexation."),
|
||||||
ExodusError::Unknown => write!(fmt, "Unknown error."),
|
ExodusError::Unknown => write!(fmt, "Unknown error."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use rand_chacha::rand_core::{CryptoRng, RngCore};
|
|||||||
|
|
||||||
use ghost_traits::exodus::{
|
use ghost_traits::exodus::{
|
||||||
DistributedKeyGeneration, IdentifierConverter, MerkleTreeBuilder,
|
DistributedKeyGeneration, IdentifierConverter, MerkleTreeBuilder,
|
||||||
|
CiphersuiteSizes,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{AuthIndex, ExodusError, NetworkCurve};
|
use crate::{AuthIndex, ExodusError, NetworkCurve};
|
||||||
@ -241,6 +242,8 @@ impl DistributedKeyGeneration<AuthIndex, ExodusError> for NetworkCurve {
|
|||||||
round2_packages_bytes: &Self::RoundPackages,
|
round2_packages_bytes: &Self::RoundPackages,
|
||||||
) -> Self::Part3Result {
|
) -> Self::Part3Result {
|
||||||
with_ciphersuite!(self, |f| {
|
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)
|
let round2_secret_package = f::keys::dkg::round2::SecretPackage::deserialize(round2_secret_package_bytes)
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
@ -291,13 +294,24 @@ impl DistributedKeyGeneration<AuthIndex, ExodusError> for NetworkCurve {
|
|||||||
let key_package_bytes = key_package.serialize()
|
let key_package_bytes = key_package.serialize()
|
||||||
.map_err(|_| ExodusError::SerializationError)?;
|
.map_err(|_| ExodusError::SerializationError)?;
|
||||||
|
|
||||||
|
let identifier_size = self.scalar_bytes_len();
|
||||||
|
let verifying_share_size = self.element_bytes_len();
|
||||||
|
|
||||||
let verifying_shares_merkle_tree =
|
let verifying_shares_merkle_tree =
|
||||||
Self::build_merkle_tree(
|
Self::build_merkle_tree(
|
||||||
|
identifier_size + verifying_share_size,
|
||||||
pubkey_package.verifying_shares(),
|
pubkey_package.verifying_shares(),
|
||||||
|verifying_share| verifying_share.serialize()
|
|verifying_share, buffer| {
|
||||||
.map_err(|_| ExodusError::SerializationError)
|
let serialized = <InnerGroup as frost_core::Group>::serialize(
|
||||||
|
&verifying_share.to_element()
|
||||||
|
).map_err(|_| ExodusError::SerializationError)?;
|
||||||
|
|
||||||
|
buffer.extend_from_slice(serialized.as_ref());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// TODO: make it better
|
||||||
let (_, merkle_proof) =
|
let (_, merkle_proof) =
|
||||||
Self::generate_merkle_proof_from_tree(
|
Self::generate_merkle_proof_from_tree(
|
||||||
pubkey_package.verifying_shares(),
|
pubkey_package.verifying_shares(),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use ghost_traits::exodus::{
|
use ghost_traits::exodus::{
|
||||||
IdentifierConverter, MerkleTreeBuilder,
|
CiphersuiteSizes, IdentifierConverter, MerkleTreeBuilder,
|
||||||
FlexibleRoundOptimizedSchnorrThresholdSignature,
|
FlexibleRoundOptimizedSchnorrThresholdSignature,
|
||||||
};
|
};
|
||||||
use sp_std::{
|
use sp_std::{
|
||||||
@ -15,29 +15,6 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
|
|||||||
type Packages<'a> = BTreeMap<AuthIndex, &'a [u8]>;
|
type Packages<'a> = BTreeMap<AuthIndex, &'a [u8]>;
|
||||||
type NoncePackages<'a> = BTreeMap<AuthIndex, (&'a [u8], &'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(
|
fn verify_signature_share(
|
||||||
&self,
|
&self,
|
||||||
index: AuthIndex,
|
index: AuthIndex,
|
||||||
@ -186,6 +163,19 @@ 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(
|
fn is_signature_valid(
|
||||||
&self,
|
&self,
|
||||||
verifying_key_bytes: &[u8],
|
verifying_key_bytes: &[u8],
|
||||||
@ -330,11 +320,16 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
|
|||||||
return Err(ExodusError::InvalidParticipantId);
|
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(
|
let binding_factor_tree = Self::build_merkle_tree(
|
||||||
|
identifier_size + binding_factor_size,
|
||||||
&binding_factors_list,
|
&binding_factors_list,
|
||||||
|binding_factor| {
|
|binding_factor, buffer| {
|
||||||
let serialized = <InnerField as frost_core::Field>::serialize(binding_factor);
|
let serialized = <InnerField as frost_core::Field>::serialize(binding_factor);
|
||||||
Ok(serialized.as_ref().to_vec())
|
buffer.extend_from_slice(serialized.as_ref());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|||||||
@ -13,15 +13,16 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
|||||||
type Hash = <SubstrateBlake2Hasher as GhostHasher>::Hash;
|
type Hash = <SubstrateBlake2Hasher as GhostHasher>::Hash;
|
||||||
|
|
||||||
fn build_merkle_tree<C, V, F>(
|
fn build_merkle_tree<C, V, F>(
|
||||||
|
size_hint: usize,
|
||||||
values: &BTreeMap<Identifier<C>, V>,
|
values: &BTreeMap<Identifier<C>, V>,
|
||||||
serialize_fn: F,
|
update_preimage_buffer: F,
|
||||||
) -> Result<Vec<Self::Hash>, ExodusError>
|
) -> Result<Vec<Self::Hash>, ExodusError>
|
||||||
where
|
where
|
||||||
C: frost_core::Ciphersuite,
|
C: frost_core::Ciphersuite,
|
||||||
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
||||||
F: Fn(&V) -> Result<Vec<u8>, ExodusError>
|
F: Fn(&V, &mut Vec<u8>) -> Result<(), ExodusError>
|
||||||
{
|
{
|
||||||
use ghost_helpers::merkle_tree::generate_tree;
|
use ghost_helpers::merkle_tree::{generate_tree, MerkleTreeError};
|
||||||
|
|
||||||
type CField<C> = <<C as Ciphersuite>::Group as Group>::Field;
|
type CField<C> = <<C as Ciphersuite>::Group as Group>::Field;
|
||||||
|
|
||||||
@ -34,25 +35,28 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
|||||||
})
|
})
|
||||||
.ok_or(ExodusError::IncorrectNumberOfIdentifiers)?;
|
.ok_or(ExodusError::IncorrectNumberOfIdentifiers)?;
|
||||||
|
|
||||||
generate_tree::<SubstrateBlake2Hasher, _, _, _, _>(
|
let maybe_tree = generate_tree::<SubstrateBlake2Hasher, _, _, _, _>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
values.iter(),
|
values.iter(),
|
||||||
|(identifier, value)| {
|
|(identifier, value), buffer| {
|
||||||
let id_scalar = identifier.to_scalar();
|
let id_scalar = identifier.to_scalar();
|
||||||
let id_bytes = <CField<C> as frost_core::Field>::serialize(&id_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 index = Self::convert_identifier_to_index(id_bytes.as_ref())?;
|
||||||
let value_bytes = serialize_fn(value).map_err(|_| ExodusError::SerializationError)?;
|
|
||||||
|
|
||||||
// NOTE: revisit
|
buffer.extend_from_slice(id_bytes.as_ref());
|
||||||
// Is it possible to use [u8; CONSTANT] where constant is
|
update_preimage_buffer(value, buffer)?;
|
||||||
// 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, preimage))
|
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),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_merkle_proof_from_tree<C, V, F>(
|
fn generate_merkle_proof_from_tree<C, V, F>(
|
||||||
@ -66,7 +70,7 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
|||||||
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
||||||
F: Fn(&V) -> Result<Vec<u8>, ExodusError>
|
F: Fn(&V) -> Result<Vec<u8>, ExodusError>
|
||||||
{
|
{
|
||||||
use ghost_helpers::merkle_tree::generate_proof;
|
use ghost_helpers::merkle_tree::{generate_proof, MerkleTreeError};
|
||||||
|
|
||||||
type CField<C> = <<C as Ciphersuite>::Group as Group>::Field;
|
type CField<C> = <<C as Ciphersuite>::Group as Group>::Field;
|
||||||
|
|
||||||
@ -75,7 +79,7 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
|||||||
.map_err(|_| ExodusError::InvalidParticipantId)?;
|
.map_err(|_| ExodusError::InvalidParticipantId)?;
|
||||||
|
|
||||||
let value = values.get(&identifier).ok_or(ExodusError::InvalidParticipantId)?;
|
let value = values.get(&identifier).ok_or(ExodusError::InvalidParticipantId)?;
|
||||||
let value_bytes = serialize_fn(&value).map_err(|_| ExodusError::SerializationError)?;
|
let value_bytes = serialize_fn(&value)?;
|
||||||
|
|
||||||
let max_index = values.keys()
|
let max_index = values.keys()
|
||||||
.next_back()
|
.next_back()
|
||||||
@ -86,11 +90,15 @@ impl MerkleTreeBuilder<AuthIndex, ExodusError> for NetworkCurve {
|
|||||||
})
|
})
|
||||||
.ok_or(ExodusError::IncorrectNumberOfIdentifiers)?;
|
.ok_or(ExodusError::IncorrectNumberOfIdentifiers)?;
|
||||||
|
|
||||||
let proof = generate_proof::<SubstrateBlake2Hasher, _>(
|
let proof = generate_proof::<SubstrateBlake2Hasher, _, _>(
|
||||||
merkle_tree,
|
merkle_tree,
|
||||||
max_index,
|
max_index,
|
||||||
authority_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))
|
Ok((value_bytes, proof))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,3 +72,6 @@ mod ecdh;
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod frost;
|
mod frost;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod sizes;
|
||||||
|
|||||||
29
pallets/exodus/src/impls/sizes.rs
Normal file
29
pallets/exodus/src/impls/sizes.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
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
@ -41,7 +41,7 @@ impl frame_system::Config for Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub static FixedAuthorities: Vec<u64> = vec![0, 1, 2, 3];
|
pub static FixedAuthorities: Vec<u64> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestSessionManager;
|
pub struct TestSessionManager;
|
||||||
@ -136,14 +136,15 @@ impl ghost_exodus::Config for Runtime {
|
|||||||
type DisabledValidators = Session;
|
type DisabledValidators = Session;
|
||||||
|
|
||||||
type UnsignedPriority = ConstU64<{ 1 << 20 }>;
|
type UnsignedPriority = ConstU64<{ 1 << 20 }>;
|
||||||
type UnsignedLongevity = ConstU64<1>;
|
type UnsignedLongevity = ConstU64<5>;
|
||||||
type MaxAuthorities = ConstU32<10>;
|
type MaxAuthorities = ConstU32<15>;
|
||||||
type MaxAuthoritiesChunks = ConstU32<1>;
|
type MaxAuthoritiesChunks = ConstU32<2>;
|
||||||
|
|
||||||
type DkgRoundPeriod = ConstU64<100>;
|
type DkgRoundPeriod = ConstU64<1000>;
|
||||||
type RemovalLimit = ConstU32<20>;
|
type RemovalLimit = ConstU32<20>;
|
||||||
type MaxCursorLen = ConstU32<20>;
|
type MaxCursorLen = ConstU32<256>;
|
||||||
type BaseEvmAmount = ConstU128<5>;
|
type BaseEvmAmount = ConstU128<5>;
|
||||||
|
type MaxExodusRequestCount = ConstU32<40>;
|
||||||
|
|
||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,30 @@ use frame_support::{BoundedVec, traits::ConstU32};
|
|||||||
|
|
||||||
use crate::{ExodusHash, ELEMENT_MAX_BYTES};
|
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)]
|
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||||
pub struct ConsensusState<Bitmap> {
|
pub struct ConsensusState<Bitmap> {
|
||||||
pub element_bytes: BoundedVec<u8, ConstU32<ELEMENT_MAX_BYTES>>,
|
pub element_bytes: BoundedVec<u8, ConstU32<ELEMENT_MAX_BYTES>>,
|
||||||
|
|||||||
@ -1,28 +1,46 @@
|
|||||||
use sp_runtime::{RuntimeDebug, traits::UniqueSaturatedInto};
|
use sp_runtime::{RuntimeDebug, traits::UniqueSaturatedInto};
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
use strum::EnumCount;
|
|
||||||
|
|
||||||
use frame_support::{BoundedVec, traits::ConstU32};
|
use frame_support::{BoundedVec, traits::ConstU32};
|
||||||
|
|
||||||
use ghost_helpers::networks::NetworkType;
|
use ghost_traits::{
|
||||||
use ghost_traits::bounded_bitmap::{
|
networks::NetworkDataBasicHandler,
|
||||||
|
bounded_bitmap::{
|
||||||
BoundedBitmapGenerator, BoundedBitmapReader, BoundedBitmapWriter,
|
BoundedBitmapGenerator, BoundedBitmapReader, BoundedBitmapWriter,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{ELEMENT_MAX_BYTES, ExodusSession, DkgIndex};
|
use crate::{
|
||||||
|
ELEMENT_MAX_BYTES, Config, NetworkType, NetworkIdOf, ExodusContext,
|
||||||
|
ParticipantsBitmap, BlockNumberFor, DkgIndex,
|
||||||
|
};
|
||||||
|
|
||||||
type RotationSessions = BoundedVec<RotationSession, ConstU32<{ NetworkType::COUNT as u32 }>>;
|
type RotationItem<T> = (NetworkType, ExodusContext<NetworkIdOf<T>>);
|
||||||
|
type Rotations<T> = BoundedVec<
|
||||||
|
RotationItem<T>,
|
||||||
|
<<T as Config>::NetworkDataHandler as NetworkDataBasicHandler>::MaxNetworks,
|
||||||
|
>;
|
||||||
|
|
||||||
#[derive(Default, Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
|
||||||
pub struct ReadyDkgAuthorities<AuthoritiesBitmap> {
|
#[scale_info(skip_type_params(T))]
|
||||||
authorities_indexes: AuthoritiesBitmap,
|
pub struct ReadyDkgAuthorities<T: Config> {
|
||||||
|
authorities_indexes: ParticipantsBitmap<T>,
|
||||||
dkg_index: DkgIndex,
|
dkg_index: DkgIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AuthoritiesBitmap> ReadyDkgAuthorities<AuthoritiesBitmap>
|
impl<T: Config> Default for ReadyDkgAuthorities<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
authorities_indexes: Default::default(),
|
||||||
|
dkg_index: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Config> ReadyDkgAuthorities<T>
|
||||||
where
|
where
|
||||||
AuthoritiesBitmap: BoundedBitmapReader,
|
ParticipantsBitmap<T>: BoundedBitmapReader,
|
||||||
{
|
{
|
||||||
pub fn contains_index<N>(&self, index: N) -> bool
|
pub fn contains_index<N>(&self, index: N) -> bool
|
||||||
where N: UniqueSaturatedInto<usize>,
|
where N: UniqueSaturatedInto<usize>,
|
||||||
@ -30,7 +48,7 @@ where
|
|||||||
self.authorities_indexes.contains(index)
|
self.authorities_indexes.contains(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_indexes(&self) -> &AuthoritiesBitmap {
|
pub fn get_indexes(&self) -> &ParticipantsBitmap<T> {
|
||||||
&self.authorities_indexes
|
&self.authorities_indexes
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,15 +57,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AuthoritiesBitmap, Block>
|
impl<T: Config>
|
||||||
From<&PendingDkgAuthorities<AuthoritiesBitmap, Block>>
|
From<&PendingDkgAuthorities<T>>
|
||||||
for ReadyDkgAuthorities<AuthoritiesBitmap>
|
for ReadyDkgAuthorities<T>
|
||||||
where
|
where
|
||||||
Block: Copy,
|
BlockNumberFor<T>: Copy,
|
||||||
AuthoritiesBitmap: BoundedBitmapWriter + BoundedBitmapReader + BoundedBitmapGenerator + Clone,
|
ParticipantsBitmap<T>: BoundedBitmapWriter + BoundedBitmapReader + BoundedBitmapGenerator + Clone,
|
||||||
for<'a> AuthoritiesBitmap: core::ops::BitAndAssign<&'a AuthoritiesBitmap>,
|
for<'a> ParticipantsBitmap<T>: core::ops::BitAndAssign<&'a ParticipantsBitmap<T>>,
|
||||||
{
|
{
|
||||||
fn from(pending: &PendingDkgAuthorities<AuthoritiesBitmap, Block>) -> Self {
|
fn from(pending: &PendingDkgAuthorities<T>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
authorities_indexes: pending.get_indexes().clone(),
|
authorities_indexes: pending.get_indexes().clone(),
|
||||||
dkg_index: pending.get_dkg_index(),
|
dkg_index: pending.get_dkg_index(),
|
||||||
@ -55,34 +73,40 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
|
||||||
pub struct RotationSession {
|
#[scale_info(skip_type_params(T))]
|
||||||
pub exodus_session: ExodusSession,
|
pub struct PendingDkgAuthorities<T: Config> {
|
||||||
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>>,
|
verifying_key: BoundedVec<u8, ConstU32<ELEMENT_MAX_BYTES>>,
|
||||||
authorities_indexes: AuthoritiesBitmap,
|
authorities_indexes: ParticipantsBitmap<T>,
|
||||||
rotation_sessions: RotationSessions,
|
rotations: Rotations<T>,
|
||||||
dkg_state: DkgState<Block>,
|
dkg_state: DkgState<BlockNumberFor<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AuthoritiesBitmap, Block> PendingDkgAuthorities<AuthoritiesBitmap, 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>
|
||||||
where
|
where
|
||||||
Block: Copy,
|
BlockNumberFor<T>: Copy,
|
||||||
AuthoritiesBitmap: BoundedBitmapWriter + BoundedBitmapReader + BoundedBitmapGenerator + Clone,
|
ParticipantsBitmap<T>: BoundedBitmapWriter + BoundedBitmapReader + BoundedBitmapGenerator + Clone,
|
||||||
for<'a> AuthoritiesBitmap: core::ops::BitAndAssign<&'a AuthoritiesBitmap>,
|
for<'a> ParticipantsBitmap<T>: core::ops::BitAndAssign<&'a ParticipantsBitmap<T>>,
|
||||||
{
|
{
|
||||||
pub fn new_dkg(&mut self, authorities_len: usize) {
|
pub fn new_dkg(&mut self, authorities_len: usize) {
|
||||||
self.authorities_indexes = AuthoritiesBitmap::empty(authorities_len);
|
self.authorities_indexes = ParticipantsBitmap::<T>::empty(authorities_len);
|
||||||
self.dkg_state.restart();
|
self.dkg_state.restart();
|
||||||
self.rotation_sessions = Default::default();
|
self.rotations = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_block(&mut self, block: Block) {
|
pub fn set_release_block(&mut self, block: BlockNumberFor<T>) {
|
||||||
self.dkg_state.set_block(block);
|
self.dkg_state.set_release_block(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_verifying_key(
|
pub fn set_verifying_key(
|
||||||
@ -101,7 +125,7 @@ where
|
|||||||
self.verifying_key = Default::default();
|
self.verifying_key = Default::default();
|
||||||
self.authorities_indexes.nullify();
|
self.authorities_indexes.nullify();
|
||||||
self.dkg_state.restart();
|
self.dkg_state.restart();
|
||||||
self.rotation_sessions = Default::default();
|
self.rotations = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_phase(&mut self) {
|
pub fn next_phase(&mut self) {
|
||||||
@ -109,7 +133,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn intersect_indexes(&mut self, mask: &AuthoritiesBitmap) {
|
pub fn intersect_indexes(&mut self, mask: &ParticipantsBitmap<T>) {
|
||||||
self.authorities_indexes &= mask;
|
self.authorities_indexes &= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,8 +149,8 @@ where
|
|||||||
self.dkg_state.get_dkg_index()
|
self.dkg_state.get_dkg_index()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block(&self) -> Block {
|
pub fn get_release_block(&self) -> BlockNumberFor<T> {
|
||||||
self.dkg_state.get_block()
|
self.dkg_state.get_release_block()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_phase(&self) -> DkgPhase {
|
pub fn get_phase(&self) -> DkgPhase {
|
||||||
@ -183,17 +207,13 @@ where
|
|||||||
self.authorities_indexes.insert(i)
|
self.authorities_indexes.insert(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_push_rotation_session(
|
pub fn try_push_rotation(
|
||||||
&mut self,
|
&mut self,
|
||||||
exodus_session: ExodusSession,
|
|
||||||
network_type: NetworkType,
|
network_type: NetworkType,
|
||||||
|
exodus_context: ExodusContext<NetworkIdOf<T>>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let rotation_session = RotationSession {
|
let item = (network_type, exodus_context);
|
||||||
exodus_session,
|
self.rotations.try_push(item).ok()
|
||||||
network_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.rotation_sessions.try_push(rotation_session).ok()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count_ones<N>(&self) -> N
|
pub fn count_ones<N>(&self) -> N
|
||||||
@ -208,43 +228,44 @@ where
|
|||||||
self.authorities_indexes.highest_bit()
|
self.authorities_indexes.highest_bit()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_indexes(&self) -> &AuthoritiesBitmap {
|
pub fn get_indexes(&self) -> &ParticipantsBitmap<T> {
|
||||||
&self.authorities_indexes
|
&self.authorities_indexes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_rotation_sessions(&self) -> impl Iterator<Item = &RotationSession> {
|
pub fn iter_rotations(
|
||||||
self.rotation_sessions.iter()
|
&self
|
||||||
|
) -> impl Iterator<Item = &RotationItem<T>> {
|
||||||
|
self.rotations.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
#[derive(Default, Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||||
pub struct DkgState<Block> {
|
pub struct DkgState<Block> {
|
||||||
block: Block,
|
release_block: Block,
|
||||||
index: DkgIndex,
|
dkg_index: DkgIndex,
|
||||||
phase: DkgPhase,
|
dkg_phase: DkgPhase,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: Copy> DkgState<Block> {
|
impl<Block: Copy> DkgState<Block> {
|
||||||
fn is_dkg_pending(&self) -> bool { self.phase.is_dkg_pending() }
|
fn is_dkg_pending(&self) -> bool { self.dkg_phase.is_dkg_pending() }
|
||||||
fn is_dkg_vacant(&self) -> bool { self.phase.is_dkg_vacant() }
|
fn is_dkg_vacant(&self) -> bool { self.dkg_phase.is_dkg_vacant() }
|
||||||
|
|
||||||
fn get_dkg_index(&self) -> DkgIndex { self.index }
|
fn get_dkg_index(&self) -> DkgIndex { self.dkg_index }
|
||||||
fn get_phase(&self) -> DkgPhase { self.phase }
|
fn get_phase(&self) -> DkgPhase { self.dkg_phase }
|
||||||
fn get_block(&self) -> Block { self.block }
|
fn get_release_block(&self) -> Block { self.release_block }
|
||||||
|
|
||||||
fn restart(&mut self) {
|
fn restart(&mut self) {
|
||||||
self.phase = Default::default();
|
self.dkg_phase = Default::default();
|
||||||
self.index = self.index.checked_add(1)
|
self.dkg_index = self.dkg_index.checked_add(1)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_phase(&mut self) {
|
fn next_phase(&mut self) {
|
||||||
self.phase.next_phase()
|
self.dkg_phase.next_phase()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_block(&mut self, block: Block) {
|
fn set_release_block(&mut self, release_block: Block) {
|
||||||
self.block = block;
|
self.release_block = release_block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,8 @@ use sp_runtime::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
EvmAddress, EvmBytes32, ExodusSession, RoastSession,
|
EvmAddress, EvmBytes32, ExodusContext, RoastSession, EvmSessionsBundle,
|
||||||
MAX_MESSAGE_SIZE,
|
Config, BalanceOf, MAX_MESSAGE_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait EvmAbiEncode {
|
pub trait EvmAbiEncode {
|
||||||
@ -172,8 +172,9 @@ pub enum GovernanceStatus {
|
|||||||
RewardManager = 4,
|
RewardManager = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
|
#[derive(Encode, Decode, Clone, Copy, PartialEq, TypeInfo, RuntimeDebug)]
|
||||||
pub enum GovernanceAction {
|
pub enum GovernanceAction {
|
||||||
|
SetRouterRegistryIndex { index: u128 },
|
||||||
SetDistributor { distributor: EvmAddress },
|
SetDistributor { distributor: EvmAddress },
|
||||||
SetWarmupPeriod { warmup_period: u128 },
|
SetWarmupPeriod { warmup_period: u128 },
|
||||||
UpdateGatekeeperAddress { new_gatekeeper: EvmAddress },
|
UpdateGatekeeperAddress { new_gatekeeper: EvmAddress },
|
||||||
@ -188,6 +189,7 @@ pub enum GovernanceAction {
|
|||||||
ForfeitReserves { router: EvmAddress, liquidity: u128, destroyer_mode: bool },
|
ForfeitReserves { router: EvmAddress, liquidity: u128, destroyer_mode: bool },
|
||||||
RedeemReserves { router: EvmAddress, amount: u128 },
|
RedeemReserves { router: EvmAddress, amount: u128 },
|
||||||
Withdraw { token: EvmAddress, amount: u128 },
|
Withdraw { token: EvmAddress, amount: u128 },
|
||||||
|
SetBondDepository { address: EvmAddress },
|
||||||
AuditReserves,
|
AuditReserves,
|
||||||
|
|
||||||
Close { id: u128 },
|
Close { id: u128 },
|
||||||
@ -198,6 +200,8 @@ pub enum GovernanceAction {
|
|||||||
intervals: [u32; 2],
|
intervals: [u32; 2],
|
||||||
booleans: [bool; 2],
|
booleans: [bool; 2],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Approve { spender: EvmAddress, value: u128, },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GovernanceAction {
|
impl GovernanceAction {
|
||||||
@ -206,6 +210,13 @@ impl GovernanceAction {
|
|||||||
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
|
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
|
||||||
) -> Option<&'a [u8]> {
|
) -> Option<&'a [u8]> {
|
||||||
match &self {
|
match &self {
|
||||||
|
Self::SetRouterRegistryIndex { index } => {
|
||||||
|
abi_encode_evm_message!(
|
||||||
|
message_buffer,
|
||||||
|
"setRouterRegistryIndex(uint256)",
|
||||||
|
[index]
|
||||||
|
)
|
||||||
|
},
|
||||||
Self::SetDistributor { distributor } => {
|
Self::SetDistributor { distributor } => {
|
||||||
abi_encode_evm_message!(
|
abi_encode_evm_message!(
|
||||||
message_buffer,
|
message_buffer,
|
||||||
@ -290,6 +301,13 @@ impl GovernanceAction {
|
|||||||
[token, amount]
|
[token, amount]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
Self::SetBondDepository { address } => {
|
||||||
|
abi_encode_evm_message!(
|
||||||
|
message_buffer,
|
||||||
|
"setBondDepository(address)",
|
||||||
|
[address]
|
||||||
|
)
|
||||||
|
},
|
||||||
Self::AuditReserves => {
|
Self::AuditReserves => {
|
||||||
abi_encode_evm_message!(message_buffer, "auditReserves()", [])
|
abi_encode_evm_message!(message_buffer, "auditReserves()", [])
|
||||||
},
|
},
|
||||||
@ -304,64 +322,75 @@ impl GovernanceAction {
|
|||||||
[market, terms, token, intervals, &booleans_u8]
|
[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)]
|
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
|
||||||
pub struct ExodusRequest<NetworkId, Balance> {
|
#[scale_info(skip_type_params(T))]
|
||||||
pub r#type: ExodusRequestType<NetworkId, Balance>,
|
pub struct ExodusRequest<T: Config> {
|
||||||
|
pub r#type: ExodusRequestType<T>,
|
||||||
pub next_roast_session: RoastSession,
|
pub next_roast_session: RoastSession,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
|
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
|
||||||
pub enum ExodusRequestType<NetworkId, Balance> {
|
#[scale_info(skip_type_params(T))]
|
||||||
|
pub enum ExodusRequestType<T: Config> {
|
||||||
EvmRotation {
|
EvmRotation {
|
||||||
exodus_session: ExodusSession,
|
|
||||||
public_key: EvmBytes32,
|
public_key: EvmBytes32,
|
||||||
parity: u8,
|
xor_key: u128,
|
||||||
|
bitmask: u128,
|
||||||
|
sessions: EvmSessionsBundle<T>,
|
||||||
},
|
},
|
||||||
UtxoRotation,
|
UtxoRotation,
|
||||||
EvmBridgeOut {
|
EvmBridgeOut { amount: BalanceOf<T>, bounty: Perbill, receiver: EvmAddress },
|
||||||
exodus_session: ExodusSession,
|
EvmGovernance { target: EvmAddress, action: GovernanceAction },
|
||||||
network_id: NetworkId,
|
UtxoBridgeOut,
|
||||||
amount: Balance,
|
|
||||||
bounty: Perbill,
|
|
||||||
receiver: EvmAddress,
|
|
||||||
},
|
|
||||||
EvmGovernance {
|
|
||||||
exodus_session: ExodusSession,
|
|
||||||
network_id: NetworkId,
|
|
||||||
target: EvmAddress,
|
|
||||||
action: GovernanceAction,
|
|
||||||
},
|
|
||||||
UtxoBridgeOut { network_id: NetworkId },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NetworkId, Balance> ExodusRequestType<NetworkId, Balance>
|
impl<T: Config> ExodusRequestType<T>
|
||||||
where
|
where
|
||||||
NetworkId: UniqueSaturatedInto<u64> + Copy,
|
BalanceOf<T>: UniqueSaturatedInto<u128> + Copy,
|
||||||
Balance: UniqueSaturatedInto<u128> + Copy,
|
|
||||||
{
|
{
|
||||||
pub fn get_message<'a>(
|
pub fn get_message<'a, NetworkId>(
|
||||||
&self,
|
&self,
|
||||||
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
|
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
|
||||||
) -> Option<&'a [u8]> {
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
|
) -> Option<&'a [u8]>
|
||||||
|
where
|
||||||
|
NetworkId: UniqueSaturatedInto<u64> + Copy + Default,
|
||||||
|
{
|
||||||
match &self {
|
match &self {
|
||||||
ExodusRequestType::EvmRotation { exodus_session, public_key, parity } => {
|
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();
|
||||||
|
|
||||||
abi_encode_evm_message!(
|
abi_encode_evm_message!(
|
||||||
message_buffer,
|
message_buffer,
|
||||||
"rotate(uint256,bytes32,uint8)",
|
"rotate(uint256,bytes32,uint256,bytes)",
|
||||||
[exodus_session, public_key, parity]
|
[&exodus_context.session, public_key, &packed_bits, payload]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
ExodusRequestType::EvmGovernance { exodus_session, network_id, target, action } => {
|
ExodusRequestType::EvmGovernance { target, action } => {
|
||||||
let mut action_buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
let mut action_buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
||||||
let action_payload = action.get_message(&mut action_buffer)?;
|
let action_payload = action.get_message(&mut action_buffer)?;
|
||||||
|
|
||||||
let mut metadata_buffer = [0u8; 32];
|
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[0..8].copy_from_slice(&chain_id_u64.to_be_bytes());
|
||||||
metadata_buffer[8..28].copy_from_slice(target.as_ref());
|
metadata_buffer[8..28].copy_from_slice(target.as_ref());
|
||||||
|
|
||||||
@ -370,14 +399,16 @@ where
|
|||||||
abi_encode_evm_message!(
|
abi_encode_evm_message!(
|
||||||
message_buffer,
|
message_buffer,
|
||||||
"govern(uint256,uint256,bytes)",
|
"govern(uint256,uint256,bytes)",
|
||||||
[exodus_session, &packed_metadata, action_payload]
|
[&exodus_context.session, &packed_metadata, action_payload]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
ExodusRequestType::EvmBridgeOut { exodus_session, network_id, amount, bounty, receiver } => {
|
ExodusRequestType::EvmBridgeOut { amount, bounty, receiver } => {
|
||||||
let mut buffer = [0u8; 32];
|
let mut buffer = [0u8; 32];
|
||||||
buffer[0..20].copy_from_slice(receiver.as_ref());
|
buffer[0..20].copy_from_slice(receiver.as_ref());
|
||||||
|
|
||||||
let chain_id_u64: u64 = (*network_id).unique_saturated_into();
|
let chain_id_u64: u64 = exodus_context.network_id
|
||||||
|
.unique_saturated_into();
|
||||||
|
|
||||||
buffer[20..28].copy_from_slice(&chain_id_u64.to_be_bytes());
|
buffer[20..28].copy_from_slice(&chain_id_u64.to_be_bytes());
|
||||||
|
|
||||||
let scaled_bounty = multiply_by_rational_with_rounding(
|
let scaled_bounty = multiply_by_rational_with_rounding(
|
||||||
@ -387,7 +418,7 @@ where
|
|||||||
sp_runtime::Rounding::Down
|
sp_runtime::Rounding::Down
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let bounty_uint32 = scaled_bounty as u32;
|
let bounty_uint32 = scaled_bounty.min(u32::MAX as u128) as u32;
|
||||||
buffer[28..32].copy_from_slice(&bounty_uint32.to_be_bytes());
|
buffer[28..32].copy_from_slice(&bounty_uint32.to_be_bytes());
|
||||||
|
|
||||||
let mut amount_buffer = [0u8; 32];
|
let mut amount_buffer = [0u8; 32];
|
||||||
@ -400,49 +431,78 @@ where
|
|||||||
abi_encode_evm_message!(
|
abi_encode_evm_message!(
|
||||||
message_buffer,
|
message_buffer,
|
||||||
"recall(uint256,uint256,uint256)",
|
"recall(uint256,uint256,uint256)",
|
||||||
[exodus_session, &amount_u256, &packed_metadata]
|
[&exodus_context.session, &amount_u256, &packed_metadata]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => None
|
_ => 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<NetworkId, Balance> ExodusRequest<NetworkId, Balance>
|
impl<T: Config> ExodusRequest<T>
|
||||||
where
|
where
|
||||||
NetworkId: UniqueSaturatedInto<u64> + Copy,
|
BalanceOf<T>: UniqueSaturatedInto<u128> + Copy,
|
||||||
Balance: UniqueSaturatedInto<u128> + Copy,
|
|
||||||
{
|
{
|
||||||
pub fn get_message<'a>(
|
pub fn get_message<'a, NetworkId>(
|
||||||
&self,
|
&self,
|
||||||
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
|
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
|
||||||
) -> Option<&'a [u8]> {
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
self.r#type.get_message(message_buffer)
|
) -> Option<&'a [u8]>
|
||||||
|
where
|
||||||
|
NetworkId: UniqueSaturatedInto<u64> + Copy + Default,
|
||||||
|
{
|
||||||
|
self.r#type.get_message(message_buffer, exodus_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evm_rotation(
|
pub fn evm_rotation(
|
||||||
exodus_session: ExodusSession,
|
|
||||||
public_key: EvmBytes32,
|
public_key: EvmBytes32,
|
||||||
parity: u8,
|
xor_key: u128,
|
||||||
|
bitmask: u128,
|
||||||
|
sessions: EvmSessionsBundle<T>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let rotation = ExodusRequestType::EvmRotation {
|
let rotation = ExodusRequestType::EvmRotation {
|
||||||
exodus_session,
|
|
||||||
public_key,
|
public_key,
|
||||||
parity,
|
xor_key,
|
||||||
|
bitmask,
|
||||||
|
sessions,
|
||||||
};
|
};
|
||||||
Self::default_request_for(rotation)
|
Self::default_request_for(rotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evm_bridge_out(
|
pub fn evm_bridge_out(
|
||||||
exodus_session: ExodusSession,
|
amount: BalanceOf<T>,
|
||||||
network_id: NetworkId,
|
|
||||||
amount: Balance,
|
|
||||||
bounty: Perbill,
|
bounty: Perbill,
|
||||||
receiver: EvmAddress,
|
receiver: EvmAddress
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let evm_bridge_out = ExodusRequestType::EvmBridgeOut {
|
let evm_bridge_out = ExodusRequestType::EvmBridgeOut {
|
||||||
exodus_session,
|
|
||||||
network_id,
|
|
||||||
amount,
|
amount,
|
||||||
bounty,
|
bounty,
|
||||||
receiver,
|
receiver,
|
||||||
@ -450,81 +510,93 @@ where
|
|||||||
Self::default_request_for(evm_bridge_out)
|
Self::default_request_for(evm_bridge_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evm_governance(
|
pub fn evm_governance(target: EvmAddress, action: GovernanceAction) -> Self {
|
||||||
exodus_session: ExodusSession,
|
|
||||||
network_id: NetworkId,
|
|
||||||
target: EvmAddress,
|
|
||||||
action: GovernanceAction,
|
|
||||||
) -> Self {
|
|
||||||
let evm_governance = ExodusRequestType::EvmGovernance {
|
let evm_governance = ExodusRequestType::EvmGovernance {
|
||||||
exodus_session,
|
|
||||||
network_id,
|
|
||||||
target,
|
target,
|
||||||
action,
|
action,
|
||||||
};
|
};
|
||||||
Self::default_request_for(evm_governance)
|
Self::default_request_for(evm_governance)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_rotation(&self) -> bool {
|
fn default_request_for(request_type: ExodusRequestType<T>) -> Self {
|
||||||
match &self.r#type {
|
Self {
|
||||||
ExodusRequestType::EvmRotation { .. } | ExodusRequestType::UtxoRotation { .. } => true,
|
r#type: request_type,
|
||||||
_ => false,
|
next_roast_session: Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_request_for(
|
|
||||||
request_type: ExodusRequestType<NetworkId, Balance>,
|
|
||||||
) -> Self {
|
|
||||||
Self { r#type: request_type, next_roast_session: Default::default() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::mock::*;
|
||||||
use sp_io::hashing::keccak_256;
|
use sp_io::hashing::keccak_256;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rotation_message_valid() {
|
fn test_rotation_message_valid() {
|
||||||
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
||||||
let public_key = EvmBytes32::repeat_byte(0x11);
|
let public_key = EvmBytes32::repeat_byte(0x11);
|
||||||
let session = 69u64;
|
let session = 69;
|
||||||
|
let network_id = 420;
|
||||||
|
|
||||||
let rotation_request = ExodusRequest::<u64, u128>::evm_rotation(
|
let context = ExodusContext::new(network_id, session);
|
||||||
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(
|
||||||
public_key.clone(),
|
public_key.clone(),
|
||||||
1,
|
dummy_xor_key,
|
||||||
|
dummy_evm_bitmask,
|
||||||
|
dummy_packed_sessions,
|
||||||
);
|
);
|
||||||
|
|
||||||
let calldata = rotation_request.get_message(&mut buffer).unwrap();
|
let calldata = rotation_request.get_message(&mut buffer, context).unwrap();
|
||||||
assert_eq!(calldata.len(), 100);
|
// 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 expected_hash = keccak_256("rotate(uint256,bytes32,uint8)".as_bytes());
|
let expected_hash = keccak_256("rotate(uint256,bytes32,uint256,bytes)".as_bytes());
|
||||||
|
|
||||||
assert_eq!(calldata[0..4], expected_hash[0..4]);
|
assert_eq!(calldata[0..4], expected_hash[0..4]);
|
||||||
assert_eq!(calldata[35], 0x45);
|
assert_eq!(calldata[35], 0x45);
|
||||||
assert_eq!(&calldata[4..35], &[0u8; 31]);
|
assert_eq!(&calldata[4..35], &[0u8; 31]);
|
||||||
assert_eq!(&calldata[36..68], public_key.as_ref());
|
assert_eq!(&calldata[36..68], public_key.as_ref());
|
||||||
assert_eq!(calldata[99], 1);
|
|
||||||
assert_eq!(&calldata[68..99], &[0u8; 31]);
|
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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bridge_out_message_valid() {
|
fn test_bridge_out_message_valid() {
|
||||||
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
||||||
let receiver = EvmAddress::repeat_byte(0xAA);
|
let receiver = EvmAddress::repeat_byte(0xAA);
|
||||||
let network_id = 420u64;
|
let network_id = 420;
|
||||||
let session = 69u64;
|
let session = 69;
|
||||||
|
|
||||||
let bridge_request = ExodusRequest::<u64, u128>::evm_bridge_out(
|
let context = ExodusContext::new(network_id, session);
|
||||||
session,
|
|
||||||
network_id,
|
let bridge_request = ExodusRequest::<Runtime>::evm_bridge_out(
|
||||||
1_000_000u128,
|
1_000_000u64,
|
||||||
sp_runtime::Perbill::from_percent(1),
|
sp_runtime::Perbill::from_percent(1),
|
||||||
receiver.clone()
|
receiver.clone()
|
||||||
);
|
);
|
||||||
|
|
||||||
let calldata = bridge_request.get_message(&mut buffer).unwrap();
|
let calldata = bridge_request.get_message(&mut buffer, context).unwrap();
|
||||||
assert_eq!(calldata.len(), 100);
|
assert_eq!(calldata.len(), 100);
|
||||||
|
|
||||||
let expected_hash = keccak_256("recall(uint256,uint256,uint256)".as_bytes());
|
let expected_hash = keccak_256("recall(uint256,uint256,uint256)".as_bytes());
|
||||||
@ -549,8 +621,8 @@ mod tests {
|
|||||||
fn test_governance_message_valid() {
|
fn test_governance_message_valid() {
|
||||||
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
|
||||||
let target = EvmAddress::repeat_byte(0xAA);
|
let target = EvmAddress::repeat_byte(0xAA);
|
||||||
let network_id = 420u64;
|
let network_id = 420;
|
||||||
let session = 69u64;
|
let session = 69;
|
||||||
|
|
||||||
let actions = vec![
|
let actions = vec![
|
||||||
GovernanceAction::SetDistributor { distributor: EvmAddress::repeat_byte(0x11) },
|
GovernanceAction::SetDistributor { distributor: EvmAddress::repeat_byte(0x11) },
|
||||||
@ -592,16 +664,16 @@ mod tests {
|
|||||||
|
|
||||||
for (index, action) in actions.into_iter().enumerate() {
|
for (index, action) in actions.into_iter().enumerate() {
|
||||||
let action_clone = action.clone();
|
let action_clone = action.clone();
|
||||||
|
let current_session = session + (index as u64);
|
||||||
|
let context = ExodusContext::new(network_id, current_session);
|
||||||
|
|
||||||
let governance_request = ExodusRequest::<u64, u128>::evm_governance(
|
let governance_request = ExodusRequest::<Runtime>::evm_governance(
|
||||||
session,
|
|
||||||
network_id,
|
|
||||||
target,
|
target,
|
||||||
action,
|
action,
|
||||||
);
|
);
|
||||||
|
|
||||||
let message = governance_request
|
let message = governance_request
|
||||||
.get_message(&mut buffer)
|
.get_message(&mut buffer, context)
|
||||||
.get_or_insert(&[])
|
.get_or_insert(&[])
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
|
||||||
@ -610,7 +682,7 @@ mod tests {
|
|||||||
let expected_master_hash = keccak_256("govern(uint256,uint256,bytes)".as_bytes());
|
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[0..4], expected_master_hash[0..4]);
|
||||||
|
|
||||||
assert_eq!(message[35], 69);
|
assert_eq!(message[35], current_session as u8);
|
||||||
assert_eq!(&message[4..35], &[0u8; 31]);
|
assert_eq!(&message[4..35], &[0u8; 31]);
|
||||||
|
|
||||||
assert_eq!(message[43], 0xA4);
|
assert_eq!(message[43], 0xA4);
|
||||||
@ -626,6 +698,12 @@ mod tests {
|
|||||||
assert_eq!((message.len() - 4) % 32, 0);
|
assert_eq!((message.len() - 4) % 32, 0);
|
||||||
|
|
||||||
match action_clone {
|
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 } => {
|
GovernanceAction::SetDistributor { distributor } => {
|
||||||
let hash = keccak_256("setDistributor(address)".as_bytes());
|
let hash = keccak_256("setDistributor(address)".as_bytes());
|
||||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||||
@ -634,7 +712,8 @@ mod tests {
|
|||||||
GovernanceAction::SetWarmupPeriod { warmup_period } => {
|
GovernanceAction::SetWarmupPeriod { warmup_period } => {
|
||||||
let hash = keccak_256("setWarmupPeriod(uint256)".as_bytes());
|
let hash = keccak_256("setWarmupPeriod(uint256)".as_bytes());
|
||||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||||
assert_eq!(inner_payload[inner_payload.len() - 1], warmup_period as u8);
|
let decoded_warmup = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||||
|
assert_eq!(decoded_warmup, warmup_period as u32);
|
||||||
},
|
},
|
||||||
GovernanceAction::UpdateGatekeeperAddress { new_gatekeeper } => {
|
GovernanceAction::UpdateGatekeeperAddress { new_gatekeeper } => {
|
||||||
let hash = keccak_256("updateGatekeeperAddress(address)".as_bytes());
|
let hash = keccak_256("updateGatekeeperAddress(address)".as_bytes());
|
||||||
@ -644,7 +723,8 @@ mod tests {
|
|||||||
GovernanceAction::SetBounty { bounty } => {
|
GovernanceAction::SetBounty { bounty } => {
|
||||||
let hash = keccak_256("setBounty(uint256)".as_bytes());
|
let hash = keccak_256("setBounty(uint256)".as_bytes());
|
||||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||||
assert_eq!(inner_payload[inner_payload.len() - 1], bounty as u8);
|
let decoded_bounty = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||||
|
assert_eq!(decoded_bounty, bounty as u32);
|
||||||
},
|
},
|
||||||
GovernanceAction::AddPool { address } => {
|
GovernanceAction::AddPool { address } => {
|
||||||
let hash = keccak_256("addPool(address)".as_bytes());
|
let hash = keccak_256("addPool(address)".as_bytes());
|
||||||
@ -654,13 +734,16 @@ mod tests {
|
|||||||
GovernanceAction::RemovePool { index } => {
|
GovernanceAction::RemovePool { index } => {
|
||||||
let hash = keccak_256("removePool(uint256)".as_bytes());
|
let hash = keccak_256("removePool(uint256)".as_bytes());
|
||||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||||
assert_eq!(inner_payload[inner_payload.len() - 1], index as u8);
|
let decoded_index = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||||
|
assert_eq!(decoded_index, index as u32);
|
||||||
},
|
},
|
||||||
GovernanceAction::SetAdjustment { rate, target, add } => {
|
GovernanceAction::SetAdjustment { rate, target, add } => {
|
||||||
let hash = keccak_256("setAdjustment(uint256,uint256,bool)".as_bytes());
|
let hash = keccak_256("setAdjustment(uint256,uint256,bool)".as_bytes());
|
||||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||||
assert_eq!(inner_payload[35], rate as u8);
|
let decoded_rate = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||||
assert_eq!(inner_payload[67], target as u8);
|
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[99], add as u8);
|
assert_eq!(inner_payload[99], add as u8);
|
||||||
},
|
},
|
||||||
GovernanceAction::Enable { status, address, calculator } => {
|
GovernanceAction::Enable { status, address, calculator } => {
|
||||||
@ -680,7 +763,8 @@ mod tests {
|
|||||||
let hash = keccak_256("forfeitReserves(address,uint256,bool)".as_bytes());
|
let hash = keccak_256("forfeitReserves(address,uint256,bool)".as_bytes());
|
||||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||||
assert_eq!(&inner_payload[16..36], router.as_ref());
|
assert_eq!(&inner_payload[16..36], router.as_ref());
|
||||||
assert_eq!(inner_payload[67], liquidity as u8);
|
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[99], destroyer_mode as u8);
|
assert_eq!(inner_payload[99], destroyer_mode as u8);
|
||||||
},
|
},
|
||||||
GovernanceAction::RedeemReserves { router, amount } => {
|
GovernanceAction::RedeemReserves { router, amount } => {
|
||||||
@ -693,7 +777,13 @@ mod tests {
|
|||||||
let hash = keccak_256("withdraw(address,uint256)".as_bytes());
|
let hash = keccak_256("withdraw(address,uint256)".as_bytes());
|
||||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||||
assert_eq!(&inner_payload[16..36], token.as_ref());
|
assert_eq!(&inner_payload[16..36], token.as_ref());
|
||||||
assert_eq!(inner_payload[67], amount as u8);
|
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());
|
||||||
},
|
},
|
||||||
GovernanceAction::AuditReserves => {
|
GovernanceAction::AuditReserves => {
|
||||||
let hash = keccak_256("auditReserves()".as_bytes());
|
let hash = keccak_256("auditReserves()".as_bytes());
|
||||||
@ -703,7 +793,8 @@ mod tests {
|
|||||||
GovernanceAction::Close { id } => {
|
GovernanceAction::Close { id } => {
|
||||||
let hash = keccak_256("close(uint256)".as_bytes());
|
let hash = keccak_256("close(uint256)".as_bytes());
|
||||||
assert_eq!(inner_payload[0..4], hash[0..4]);
|
assert_eq!(inner_payload[0..4], hash[0..4]);
|
||||||
assert_eq!(inner_payload[inner_payload.len() - 1], id as u8);
|
let decoded_id = u32::from_be_bytes(inner_payload[32..36].try_into().unwrap());
|
||||||
|
assert_eq!(decoded_id, id as u32);
|
||||||
},
|
},
|
||||||
GovernanceAction::Create { market, terms, token, intervals, booleans } => {
|
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[4],uint256[2],address,uint32[2],bool[2])".as_bytes());
|
||||||
@ -726,6 +817,13 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(inner_payload[323], booleans[0] as u8);
|
assert_eq!(inner_payload[323], booleans[0] as u8);
|
||||||
assert_eq!(inner_payload[355], booleans[1] 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use sp_runtime::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{DkgPackage, ExodusPackage, ExodusOk, PackageContext};
|
use super::{DkgPackage, ExodusPackage, ExodusOk, PackageContext};
|
||||||
use crate::{AuthIndex, ExodusSession, ExodusHash, ExodusError};
|
use crate::{AuthIndex, ExodusContext, DkgIndex, ExodusHash, ExodusError};
|
||||||
|
|
||||||
fn create_storage_key(prefix: &[u8], index: &[u8], network: &[u8]) -> Vec<u8> {
|
fn create_storage_key(prefix: &[u8], index: &[u8], network: &[u8]) -> Vec<u8> {
|
||||||
let mut key = crate::DB_STORAGE_PREFIX.to_vec();
|
let mut key = crate::DB_STORAGE_PREFIX.to_vec();
|
||||||
@ -59,10 +59,10 @@ pub struct ExodusShare;
|
|||||||
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
|
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
|
||||||
pub struct ExodusExile;
|
pub struct ExodusExile;
|
||||||
|
|
||||||
type ExodusNonces<BlockNumber> = BTreeMap<ExodusSession, PersistentData<BlockNumber, ExodusNonce>>;
|
type ExodusNonces<NetworkId, BlockNumber> = BTreeMap<ExodusContext<NetworkId>, PersistentData<BlockNumber, ExodusNonce>>;
|
||||||
type ExodusGroups<BlockNumber> = BTreeMap<ExodusSession, PersistentData<BlockNumber, ExodusGroup>>;
|
type ExodusGroups<NetworkId, BlockNumber> = BTreeMap<ExodusContext<NetworkId>, PersistentData<BlockNumber, ExodusGroup>>;
|
||||||
type ExodusShares<BlockNumber> = BTreeMap<ExodusSession, PersistentData<BlockNumber, ExodusShare>>;
|
type ExodusShares<NetworkId, BlockNumber> = BTreeMap<ExodusContext<NetworkId>, PersistentData<BlockNumber, ExodusShare>>;
|
||||||
type ExodusExiles<BlockNumber> = BTreeMap<ExodusSession, PersistentData<BlockNumber, ExodusExile>>;
|
type ExodusExiles<NetworkId, BlockNumber> = BTreeMap<ExodusContext<NetworkId>, PersistentData<BlockNumber, ExodusExile>>;
|
||||||
|
|
||||||
pub struct ExodusStorageWrapper<ExodusInnerType> {
|
pub struct ExodusStorageWrapper<ExodusInnerType> {
|
||||||
pub inner: ExodusInnerType,
|
pub inner: ExodusInnerType,
|
||||||
@ -75,7 +75,7 @@ impl<ExodusInnerType> ExodusStorageWrapper<ExodusInnerType> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, Encode)]
|
||||||
pub struct ExodusStorage<BlockNumber, NetworkCurve>
|
pub struct ExodusStorage<BlockNumber, NetworkCurve>
|
||||||
where
|
where
|
||||||
BlockNumber: Default,
|
BlockNumber: Default,
|
||||||
@ -113,34 +113,37 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_local_storage(&self) -> ExodusRecords<B> {
|
pub fn read_local_storage<NI>(&self) -> ExodusRecords<NI, B>
|
||||||
|
where
|
||||||
|
NI: Default + Encode + Decode + AtLeast32BitUnsigned,
|
||||||
|
{
|
||||||
let encoded_index = self.authority_index.encode();
|
let encoded_index = self.authority_index.encode();
|
||||||
let encoded_network = self.network_curve.encode();
|
let encoded_network = self.network_curve.encode();
|
||||||
|
|
||||||
let nonces_key = create_storage_key(crate::EXODUS_PREFIX_NONCES, &encoded_index, &encoded_network);
|
let nonces_key = create_storage_key(crate::EXODUS_PREFIX_NONCES, &encoded_index, &encoded_network);
|
||||||
let exodus_nonces = StorageValueRef::persistent(&nonces_key)
|
let exodus_nonces = StorageValueRef::persistent(&nonces_key)
|
||||||
.get::<ExodusNonces<B>>()
|
.get::<ExodusNonces<NI, B>>()
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let shares_key = create_storage_key(crate::EXODUS_PREFIX_SHARES, &encoded_index, &encoded_network);
|
let shares_key = create_storage_key(crate::EXODUS_PREFIX_SHARES, &encoded_index, &encoded_network);
|
||||||
let exodus_shares = StorageValueRef::persistent(&shares_key)
|
let exodus_shares = StorageValueRef::persistent(&shares_key)
|
||||||
.get::<ExodusShares<B>>()
|
.get::<ExodusShares<NI, B>>()
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let groups_key = create_storage_key(crate::EXODUS_PREFIX_BLENDS, &encoded_index, &encoded_network);
|
let groups_key = create_storage_key(crate::EXODUS_PREFIX_BLENDS, &encoded_index, &encoded_network);
|
||||||
let exodus_groups = StorageValueRef::persistent(&groups_key)
|
let exodus_groups = StorageValueRef::persistent(&groups_key)
|
||||||
.get::<ExodusGroups<B>>()
|
.get::<ExodusGroups<NI, B>>()
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let exiles_key = create_storage_key(crate::EXODUS_PREFIX_EXILES, &encoded_index, &encoded_network);
|
let exiles_key = create_storage_key(crate::EXODUS_PREFIX_EXILES, &encoded_index, &encoded_network);
|
||||||
let exodus_exiles = StorageValueRef::persistent(&exiles_key)
|
let exodus_exiles = StorageValueRef::persistent(&exiles_key)
|
||||||
.get::<ExodusExiles<B>>()
|
.get::<ExodusExiles<NI, B>>()
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
@ -153,10 +156,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_signed_call_with_context<T, A, F1, F2, F3>(
|
pub fn prepare_signed_call_with_context<T, A, F1, F2, F3, NI>(
|
||||||
&self,
|
&self,
|
||||||
authority_key: &A,
|
authority_key: &A,
|
||||||
exodus_records: &mut ExodusRecords<B>,
|
current_dkg_index: DkgIndex,
|
||||||
|
exodus_records: &mut ExodusRecords<NI, B>,
|
||||||
make_data: F1,
|
make_data: F1,
|
||||||
submit_call: F2,
|
submit_call: F2,
|
||||||
insert_data: F3,
|
insert_data: F3,
|
||||||
@ -164,13 +168,16 @@ where
|
|||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
A: RuntimeAppPublic,
|
A: RuntimeAppPublic,
|
||||||
F1: FnOnce(PackageContext<NC>) -> Result<ExodusPackage<NC, T>, ExodusError>,
|
NI: Default + Encode + Decode + AtLeast32BitUnsigned,
|
||||||
F2: FnOnce(ExodusPackage<NC, T>, A::Signature) -> Result<(), ExodusError>,
|
F1: FnOnce(PackageContext<NC, B>) -> Result<ExodusPackage<NC, NI, B, T>, ExodusError>,
|
||||||
F3: FnOnce(&mut ExodusRecords<B>, B),
|
F2: FnOnce(ExodusPackage<NC, NI, B, T>, A::Signature) -> Result<(), ExodusError>,
|
||||||
|
F3: FnOnce(&mut ExodusRecords<NI, B>, B),
|
||||||
{
|
{
|
||||||
let context = PackageContext::default()
|
let context = PackageContext::default()
|
||||||
|
.with_block_number(self.current_block)
|
||||||
.with_authority_index(self.authority_index)
|
.with_authority_index(self.authority_index)
|
||||||
.with_network_curve(self.network_curve);
|
.with_network_curve(self.network_curve)
|
||||||
|
.with_dkg_index(current_dkg_index);
|
||||||
|
|
||||||
let package = make_data(context)?;
|
let package = make_data(context)?;
|
||||||
|
|
||||||
@ -203,7 +210,10 @@ where
|
|||||||
StorageValueRef::persistent(&exiles_key).clear();
|
StorageValueRef::persistent(&exiles_key).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_write_local_storage(&self, records: &ExodusRecords<B>) {
|
pub fn try_write_local_storage<NI: Default>(&self, records: &ExodusRecords<NI, B>)
|
||||||
|
where
|
||||||
|
NI: Encode + Decode + AtLeast32BitUnsigned,
|
||||||
|
{
|
||||||
let encoded_index = self.authority_index.encode();
|
let encoded_index = self.authority_index.encode();
|
||||||
let encoded_network = self.network_curve.encode();
|
let encoded_network = self.network_curve.encode();
|
||||||
|
|
||||||
@ -229,99 +239,104 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExodusRecords<BlockNumber>
|
pub struct ExodusRecords<NetworkId, BlockNumber>
|
||||||
where
|
where
|
||||||
|
NetworkId: Default,
|
||||||
BlockNumber: AtLeast32BitUnsigned,
|
BlockNumber: AtLeast32BitUnsigned,
|
||||||
{
|
{
|
||||||
exodus_nonces: ExodusStorageWrapper<ExodusNonces<BlockNumber>>,
|
exodus_nonces: ExodusStorageWrapper<ExodusNonces<NetworkId, BlockNumber>>,
|
||||||
exodus_shares: ExodusStorageWrapper<ExodusShares<BlockNumber>>,
|
exodus_shares: ExodusStorageWrapper<ExodusShares<NetworkId, BlockNumber>>,
|
||||||
exodus_groups: ExodusStorageWrapper<ExodusGroups<BlockNumber>>,
|
exodus_groups: ExodusStorageWrapper<ExodusGroups<NetworkId, BlockNumber>>,
|
||||||
exodus_exiles: ExodusStorageWrapper<ExodusExiles<BlockNumber>>,
|
exodus_exiles: ExodusStorageWrapper<ExodusExiles<NetworkId, BlockNumber>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<BlockNumber> ExodusRecords<BlockNumber>
|
impl<NetworkId, BlockNumber> ExodusRecords<NetworkId, BlockNumber>
|
||||||
where
|
where
|
||||||
BlockNumber: AtLeast32BitUnsigned + Default,
|
BlockNumber: AtLeast32BitUnsigned + Default,
|
||||||
|
NetworkId: AtLeast32BitUnsigned + Default,
|
||||||
{
|
{
|
||||||
pub fn get_secret_nonce(&self, exodus_session: &ExodusSession) -> Option<&[u8]> {
|
pub fn get_secret_nonce(
|
||||||
|
&self,
|
||||||
|
exodus_context: &ExodusContext<NetworkId>,
|
||||||
|
) -> Option<&[u8]> {
|
||||||
self.exodus_nonces.inner
|
self.exodus_nonces.inner
|
||||||
.get(exodus_session)
|
.get(exodus_context)
|
||||||
.map(|v| v.data.0.as_slice())
|
.map(|v| v.data.0.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_group_record(
|
pub fn get_group_record(
|
||||||
&self,
|
&self,
|
||||||
exodus_session: &ExodusSession,
|
exodus_context: &ExodusContext<NetworkId>,
|
||||||
) -> Option<ExodusGroup> {
|
) -> Option<ExodusGroup> {
|
||||||
self.exodus_groups.inner
|
self.exodus_groups.inner
|
||||||
.get(exodus_session)
|
.get(exodus_context)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|storage| storage.data)
|
.map(|storage| storage.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_exodus_session_banned(
|
pub fn is_exodus_session_banned(
|
||||||
&self,
|
&self,
|
||||||
exodus_session: &ExodusSession,
|
exodus_context: &ExodusContext<NetworkId>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.exodus_exiles.inner.contains_key(exodus_session)
|
self.exodus_exiles.inner.contains_key(exodus_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_group_registered(
|
pub fn is_group_registered(
|
||||||
&self,
|
&self,
|
||||||
exodus_session: &ExodusSession,
|
exodus_context: &ExodusContext<NetworkId>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.exodus_groups.inner.contains_key(exodus_session)
|
self.exodus_groups.inner.contains_key(exodus_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_waiting_period_for_nonce(
|
pub fn is_waiting_period_for_nonce(
|
||||||
&self,
|
&self,
|
||||||
exodus_session: &ExodusSession,
|
exodus_context: &ExodusContext<NetworkId>,
|
||||||
current_block: &BlockNumber
|
current_block: &BlockNumber,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.exodus_nonces.inner
|
self.exodus_nonces.inner
|
||||||
.get(exodus_session)
|
.get(exodus_context)
|
||||||
.map(|data| data.release_block.gt(current_block))
|
.map(|data| data.release_block.gt(current_block))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_waiting_period_for_share(
|
pub fn is_waiting_period_for_share(
|
||||||
&self,
|
&self,
|
||||||
exodus_session: &ExodusSession,
|
exodus_context: &ExodusContext<NetworkId>,
|
||||||
current_block: &BlockNumber,
|
current_block: &BlockNumber,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.exodus_shares.inner
|
self.exodus_shares.inner
|
||||||
.get(exodus_session)
|
.get(exodus_context)
|
||||||
.map(|data| data.release_block.gt(¤t_block))
|
.map(|data| data.release_block.gt(¤t_block))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_waiting_period_for_group(
|
pub fn is_waiting_period_for_group(
|
||||||
&self,
|
&self,
|
||||||
exodus_session: &ExodusSession,
|
exodus_context: &ExodusContext<NetworkId>,
|
||||||
current_block: &BlockNumber,
|
current_block: &BlockNumber,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.exodus_groups.inner
|
self.exodus_groups.inner
|
||||||
.get(exodus_session)
|
.get(exodus_context)
|
||||||
.map(|data| data.release_block.gt(¤t_block))
|
.map(|data| data.release_block.gt(¤t_block))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exclude_exodus_session(
|
pub fn exclude_exodus_session(
|
||||||
&mut self,
|
&mut self,
|
||||||
exodus_session: ExodusSession,
|
exodus_context: ExodusContext<NetworkId>
|
||||||
) {
|
) {
|
||||||
let exodus_exile = PersistentData {
|
let exodus_exile = PersistentData {
|
||||||
data: ExodusExile,
|
data: ExodusExile,
|
||||||
release_block: Default::default(),
|
release_block: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.exodus_exiles.inner.insert(exodus_session, exodus_exile);
|
|
||||||
self.exodus_exiles.data_changed = true;
|
self.exodus_exiles.data_changed = true;
|
||||||
|
self.exodus_exiles.inner.insert(exodus_context, exodus_exile);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_exodus_nonce(
|
pub fn insert_exodus_nonce(
|
||||||
&mut self,
|
&mut self,
|
||||||
exodus_session: ExodusSession,
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
next_release_block: BlockNumber,
|
next_release_block: BlockNumber,
|
||||||
nonce_commitment: Vec<u8>,
|
nonce_commitment: Vec<u8>,
|
||||||
) {
|
) {
|
||||||
@ -330,13 +345,13 @@ where
|
|||||||
release_block: next_release_block,
|
release_block: next_release_block,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.exodus_nonces.inner.insert(exodus_session, exodus_nonce);
|
|
||||||
self.exodus_nonces.data_changed = true;
|
self.exodus_nonces.data_changed = true;
|
||||||
|
self.exodus_nonces.inner.insert(exodus_context, exodus_nonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_exodus_share(
|
pub fn insert_exodus_share(
|
||||||
&mut self,
|
&mut self,
|
||||||
exodus_session: ExodusSession,
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
next_release_block: BlockNumber,
|
next_release_block: BlockNumber,
|
||||||
) {
|
) {
|
||||||
let exodus_share = PersistentData {
|
let exodus_share = PersistentData {
|
||||||
@ -344,13 +359,13 @@ where
|
|||||||
release_block: next_release_block,
|
release_block: next_release_block,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.exodus_shares.inner.insert(exodus_session, exodus_share);
|
|
||||||
self.exodus_shares.data_changed = true;
|
self.exodus_shares.data_changed = true;
|
||||||
|
self.exodus_shares.inner.insert(exodus_context, exodus_share);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_exodus_group(
|
pub fn insert_exodus_group(
|
||||||
&mut self,
|
&mut self,
|
||||||
exodus_session: ExodusSession,
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
next_release_block: BlockNumber,
|
next_release_block: BlockNumber,
|
||||||
self_binding_factor: Vec<u8>,
|
self_binding_factor: Vec<u8>,
|
||||||
binding_factors_proof: Vec<ExodusHash>,
|
binding_factors_proof: Vec<ExodusHash>,
|
||||||
@ -360,12 +375,12 @@ where
|
|||||||
release_block: next_release_block,
|
release_block: next_release_block,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.exodus_groups.inner.insert(exodus_session, exodus_group);
|
|
||||||
self.exodus_groups.data_changed = true;
|
self.exodus_groups.data_changed = true;
|
||||||
|
self.exodus_groups.inner.insert(exodus_context, exodus_group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Default, Encode, Clone, Copy)]
|
||||||
pub struct DkgStorage<BlockNumber, NetworkCurve>
|
pub struct DkgStorage<BlockNumber, NetworkCurve>
|
||||||
where
|
where
|
||||||
BlockNumber: Copy + Clone,
|
BlockNumber: Copy + Clone,
|
||||||
@ -406,10 +421,10 @@ where
|
|||||||
self.current_block.saturating_add(self.block_longevity)
|
self.current_block.saturating_add(self.block_longevity)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_dkg_result(
|
pub fn get_dkg_result<NI>(
|
||||||
&self,
|
&self,
|
||||||
dkg_record: DkgRecord<B>,
|
dkg_record: DkgRecord<B>,
|
||||||
) -> Result<ExodusOk<NC>, ExodusError> {
|
) -> Result<ExodusOk<NC, NI>, ExodusError> {
|
||||||
match dkg_record.prefix_slice {
|
match dkg_record.prefix_slice {
|
||||||
crate::DKG_ROUND0_PREFIX => return Ok(ExodusOk::DkgRoundRegistered(0u8, self.authority_index, self.network_curve)),
|
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)),
|
crate::DKG_ROUND1_PREFIX => return Ok(ExodusOk::DkgRoundRegistered(1u8, self.authority_index, self.network_curve)),
|
||||||
@ -454,6 +469,7 @@ where
|
|||||||
pub fn prepare_signed_call_with_context<T, A, F1, F2>(
|
pub fn prepare_signed_call_with_context<T, A, F1, F2>(
|
||||||
&self,
|
&self,
|
||||||
authority_key: &A,
|
authority_key: &A,
|
||||||
|
current_dkg_index: DkgIndex,
|
||||||
dkg_record: &mut DkgRecord<B>,
|
dkg_record: &mut DkgRecord<B>,
|
||||||
make_data: F1,
|
make_data: F1,
|
||||||
submit_call: F2,
|
submit_call: F2,
|
||||||
@ -461,12 +477,14 @@ where
|
|||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
A: RuntimeAppPublic,
|
A: RuntimeAppPublic,
|
||||||
F1: FnOnce(PackageContext<NC>) -> Result<DkgPackage<NC, T>, ExodusError>,
|
F1: FnOnce(PackageContext<NC, B>) -> Result<DkgPackage<NC, B, T>, ExodusError>,
|
||||||
F2: FnOnce(DkgPackage<NC, T>, A::Signature) -> Result<(), ExodusError>,
|
F2: FnOnce(DkgPackage<NC, B, T>, A::Signature) -> Result<(), ExodusError>,
|
||||||
{
|
{
|
||||||
let context = PackageContext::default()
|
let context = PackageContext::default()
|
||||||
|
.with_block_number(self.current_block)
|
||||||
.with_authority_index(self.authority_index)
|
.with_authority_index(self.authority_index)
|
||||||
.with_network_curve(self.network_curve);
|
.with_network_curve(self.network_curve)
|
||||||
|
.with_dkg_index(current_dkg_index);
|
||||||
|
|
||||||
let package = make_data(context)?;
|
let package = make_data(context)?;
|
||||||
|
|
||||||
|
|||||||
@ -3,37 +3,85 @@ use scale_info::TypeInfo;
|
|||||||
use sp_runtime::RuntimeDebug;
|
use sp_runtime::RuntimeDebug;
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
|
|
||||||
|
use sp_runtime::traits::UniqueSaturatedInto;
|
||||||
use frame_support::{BoundedVec, traits::ConstU32};
|
use frame_support::{BoundedVec, traits::ConstU32};
|
||||||
use crate::{AuthIndex, ExodusSession, ExodusHash, ExodusError};
|
use ghost_traits::bounded_bitmap::BoundedBitmapReader;
|
||||||
|
|
||||||
pub trait PackageMetadata<NetworkCurve>
|
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>
|
||||||
where
|
where
|
||||||
NetworkCurve: Copy,
|
NetworkCurve: Copy,
|
||||||
|
BlockNumber: Copy,
|
||||||
{
|
{
|
||||||
fn context(&self) -> &PackageContext<NetworkCurve>;
|
fn package_context(&self) -> &PackageContext<NetworkCurve, BlockNumber>;
|
||||||
|
|
||||||
fn get_authority_index(&self) -> AuthIndex {
|
fn get_authority_index(&self) -> AuthIndex {
|
||||||
self.context().get_authority_index()
|
self.package_context().get_authority_index()
|
||||||
}
|
}
|
||||||
fn get_network_curve(&self) -> NetworkCurve {
|
fn get_network_curve(&self) -> NetworkCurve {
|
||||||
self.context().get_network_curve()
|
self.package_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)]
|
#[derive(Encode, Decode, Clone, RuntimeDebug, TypeInfo, PartialEq, Eq)]
|
||||||
#[scale_info(skip_type_params(T))]
|
#[scale_info(skip_type_params(T))]
|
||||||
pub enum ExodusPackage<NetworkCurve, T>
|
pub enum ExodusPackage<NetworkCurve, NetworkId, BlockNumber, T>
|
||||||
where
|
where
|
||||||
|
NetworkId: Default,
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
NonceCommitment(ExodusNonceCommitment<NetworkCurve>),
|
NonceCommitment(ExodusNonceCommitment<NetworkCurve, NetworkId, BlockNumber>),
|
||||||
GroupCommitment(ExodusGroupCommitment<NetworkCurve>),
|
GroupCommitment(ExodusGroupCommitment<NetworkCurve, NetworkId, BlockNumber>),
|
||||||
SignatureShare(ExodusSignatureShare<NetworkCurve, T>),
|
SignatureShare(ExodusSignatureShare<NetworkCurve, NetworkId, BlockNumber, T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NetworkCurve, T> ExodusPackage<NetworkCurve, T>
|
impl<NC, NI, B, T> ExodusPackage<NC, NI, B, T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
|
NI: Default,
|
||||||
{
|
{
|
||||||
pub fn bytes_len(&self) -> u32 {
|
pub fn bytes_len(&self) -> u32 {
|
||||||
let length = match self {
|
let length = match self {
|
||||||
@ -51,32 +99,24 @@ where
|
|||||||
|
|
||||||
length as u32
|
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(Encode, Decode, Clone, RuntimeDebug, TypeInfo, PartialEq, Eq)]
|
#[derive(RuntimeDebug, Encode, Decode, Clone, TypeInfo, PartialEq, Eq)]
|
||||||
#[scale_info(skip_type_params(T))]
|
#[scale_info(skip_type_params(T))]
|
||||||
pub enum DkgPackage<NetworkCurve, T>
|
pub enum DkgPackage<NetworkCurve, BlockNumber, T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
Round0(Round0Package<NetworkCurve>),
|
Round0(Round0Package<NetworkCurve, BlockNumber>),
|
||||||
Round1(Round1Package<NetworkCurve, T>),
|
Round1(Round1Package<NetworkCurve, BlockNumber, T>),
|
||||||
Round2(Round2Package<NetworkCurve, T>),
|
Round2(Round2Package<NetworkCurve, BlockNumber, T>),
|
||||||
Round3(Round3Package<NetworkCurve, T>),
|
Round3(Round3Package<NetworkCurve, BlockNumber, T>),
|
||||||
Round4(Round4Package<NetworkCurve, T>),
|
Round4(Round4Package<NetworkCurve, BlockNumber, T>),
|
||||||
Round5(Round5Package<NetworkCurve>),
|
Round5(Round5Package<NetworkCurve, BlockNumber, T>),
|
||||||
Round6(Round6Package<NetworkCurve, T>),
|
Round6(Round6Package<NetworkCurve, BlockNumber, T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NetworkCurve, T> DkgPackage<NetworkCurve, T>
|
impl<NC, B, T> DkgPackage<NC, B, T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
@ -84,12 +124,19 @@ where
|
|||||||
let length = match self {
|
let length = match self {
|
||||||
Self::Round0(_) => ExodusHash::len_bytes(),
|
Self::Round0(_) => ExodusHash::len_bytes(),
|
||||||
Self::Round1(round1) => round1.package.len(),
|
Self::Round1(round1) => round1.package.len(),
|
||||||
Self::Round2(round2) => round2.bundle.bitmask.len(),
|
Self::Round2(round2) => round2.bundle.bitmask.count_ones(),
|
||||||
Self::Round3(round3) => round3.indices.len(),
|
Self::Round3(round3) => {
|
||||||
Self::Round4(round4) => round4.bundle.bitmask.len(),
|
round3.indices.highest_bit::<usize>().unwrap_or_default()
|
||||||
|
},
|
||||||
|
Self::Round4(round4) => round4.bundle.bitmask.count_ones(),
|
||||||
Self::Round5(round5) => {
|
Self::Round5(round5) => {
|
||||||
|
let key_members_size = round5.key_members
|
||||||
|
.highest_bit::<usize>()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
round5.verifying_key.len()
|
round5.verifying_key.len()
|
||||||
.saturating_add(ExodusHash::len_bytes())
|
.saturating_add(ExodusHash::len_bytes())
|
||||||
|
.saturating_add(key_members_size)
|
||||||
},
|
},
|
||||||
Self::Round6(round6) => round6.merkle_proof.len(),
|
Self::Round6(round6) => round6.merkle_proof.len(),
|
||||||
};
|
};
|
||||||
@ -98,15 +145,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(Default, RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
pub struct PackageContext<NetworkCurve> {
|
pub struct PackageContext<NetworkCurve, BlockNumber> {
|
||||||
authority_index: AuthIndex,
|
authority_index: AuthIndex,
|
||||||
network_curve: NetworkCurve
|
network_curve: NetworkCurve,
|
||||||
|
block_number: BlockNumber,
|
||||||
|
dkg_index: DkgIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NetworkCurve> PackageContext<NetworkCurve>
|
impl<NetworkCurve, BlockNumber> PackageContext<NetworkCurve, BlockNumber>
|
||||||
where
|
where
|
||||||
NetworkCurve: Copy,
|
NetworkCurve: Copy,
|
||||||
|
BlockNumber: Copy,
|
||||||
{
|
{
|
||||||
pub fn get_authority_index(&self) -> AuthIndex {
|
pub fn get_authority_index(&self) -> AuthIndex {
|
||||||
self.authority_index
|
self.authority_index
|
||||||
@ -116,6 +166,14 @@ where
|
|||||||
self.network_curve
|
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 {
|
pub fn with_network_curve(mut self, network_curve: NetworkCurve) -> Self {
|
||||||
self.network_curve = network_curve;
|
self.network_curve = network_curve;
|
||||||
self
|
self
|
||||||
@ -125,225 +183,265 @@ where
|
|||||||
self.authority_index = authority_index;
|
self.authority_index = authority_index;
|
||||||
self
|
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, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
pub struct BundledPackages {
|
#[scale_info(skip_type_params(T))]
|
||||||
|
pub struct BundledPackages<T>
|
||||||
|
where
|
||||||
|
T: crate::pallet::Config
|
||||||
|
{
|
||||||
|
pub bitmask: ParticipantsBitmap<T>,
|
||||||
pub blob: Vec<u8>,
|
pub blob: Vec<u8>,
|
||||||
pub bitmask: Vec<u8>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
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)]
|
||||||
#[scale_info(skip_type_params(T))]
|
#[scale_info(skip_type_params(T))]
|
||||||
pub struct EncryptionBundledPackages<T>
|
pub struct EncryptionBundledPackages<T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
pub blob: BoundedVec<u8, crate::EncryptedRound2BlobMaxBytes<T>>,
|
pub blob: BoundedVec<u8, crate::EncryptedRound2BlobMaxBytes<T>>,
|
||||||
pub bitmask: BoundedVec<u8, crate::MaxAuthoritiesBitmaskSize<T>>
|
pub bitmask: ParticipantsBitmap<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: crate::pallet::Config> EncryptionBundledPackages<T> {
|
impl<T> IndexedBundle<T> for EncryptionBundledPackages<T>
|
||||||
pub fn len(&self) -> usize {
|
where
|
||||||
let blob_len = self.blob.len();
|
T: crate::pallet::Config,
|
||||||
let bitmask_len = self.bitmask.len();
|
{
|
||||||
|
fn blob(&self) -> &[u8] { &self.blob }
|
||||||
bitmask_len.saturating_add(blob_len)
|
fn bitmask(&self) -> &ParticipantsBitmap<T> { &self.bitmask }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: crate::pallet::Config> TryFrom<BundledPackages> for EncryptionBundledPackages<T> {
|
impl<T: crate::pallet::Config> TryFrom<BundledPackages<T>> for EncryptionBundledPackages<T> {
|
||||||
type Error = ExodusError;
|
type Error = ExodusError;
|
||||||
|
|
||||||
fn try_from(source: BundledPackages) -> Result<Self, Self::Error> {
|
fn try_from(source: BundledPackages<T>) -> Result<Self, Self::Error> {
|
||||||
let blob =
|
let blob = BoundedVec::try_from(source.blob)
|
||||||
BoundedVec::<u8, crate::EncryptedRound2BlobMaxBytes<T>>::try_from(source.blob)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
let bitmask = BoundedVec::<u8, crate::MaxAuthoritiesBitmaskSize<T>>::try_from(source.bitmask)
|
Ok(Self { blob, bitmask: source.bitmask })
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
|
||||||
|
|
||||||
Ok(Self { blob, bitmask })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
#[scale_info(skip_type_params(T))]
|
#[scale_info(skip_type_params(T))]
|
||||||
pub struct JustificationsBundledPackages<T>
|
pub struct JustificationsBundledPackages<T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
pub blob: BoundedVec<u8, crate::Round2BlobMaxBytes<T>>,
|
pub blob: BoundedVec<u8, crate::Round2BlobMaxBytes<T>>,
|
||||||
pub bitmask: BoundedVec<u8, crate::MaxAuthoritiesBitmaskSize<T>>
|
pub bitmask: ParticipantsBitmap<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: crate::pallet::Config> JustificationsBundledPackages<T> {
|
impl<T> IndexedBundle<T> for 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> for JustificationsBundledPackages<T> {
|
|
||||||
type Error = ExodusError;
|
|
||||||
|
|
||||||
fn try_from(source: BundledPackages) -> Result<Self, Self::Error> {
|
|
||||||
let blob =
|
|
||||||
BoundedVec::<u8, crate::Round2BlobMaxBytes<T>>::try_from(source.blob)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
|
||||||
|
|
||||||
let bitmask = BoundedVec::<u8, crate::MaxAuthoritiesBitmaskSize<T>>::try_from(source.bitmask)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
|
||||||
|
|
||||||
Ok(Self { blob, bitmask })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
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, 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, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
pub struct ExodusSignatureShare<NetworkCurve, T>
|
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
context: PackageContext<NetworkCurve>,
|
fn blob(&self) -> &[u8] { &self.blob }
|
||||||
|
fn bitmask(&self) -> &ParticipantsBitmap<T> { &self.bitmask }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: crate::pallet::Config> TryFrom<BundledPackages<T>> for JustificationsBundledPackages<T> {
|
||||||
|
type Error = ExodusError;
|
||||||
|
|
||||||
|
fn try_from(source: BundledPackages<T>) -> Result<Self, Self::Error> {
|
||||||
|
let blob = BoundedVec::try_from(source.blob)
|
||||||
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
|
Ok(Self { blob, bitmask: source.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)]
|
||||||
|
#[scale_info(skip_type_params(T))]
|
||||||
|
pub struct ExodusNonceCommitment<NetworkCurve, NetworkId: Default, BlockNumber> {
|
||||||
|
package_context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
|
pub hiding_commitment: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||||
|
pub binding_commitment: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
|
pub struct ExodusGroupCommitment<NetworkCurve, NetworkId: Default, BlockNumber> {
|
||||||
|
package_context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
|
pub group_commitment: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||||
|
pub binding_factors_root: ExodusHash,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
|
#[scale_info(skip_type_params(T))]
|
||||||
|
pub struct ExodusSignatureShare<NetworkCurve, NetworkId, BlockNumber, T>
|
||||||
|
where
|
||||||
|
NetworkId: Default,
|
||||||
|
T: crate::pallet::Config,
|
||||||
|
{
|
||||||
|
package_context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
pub binding_factors_proof: BoundedVec<ExodusHash, crate::BindingFactorsProof<T>>,
|
pub binding_factors_proof: BoundedVec<ExodusHash, crate::BindingFactorsProof<T>>,
|
||||||
pub signature_share: BoundedVec<u8, ConstU32<{ crate::SCALAR_MAX_BYTES }>>,
|
pub signature_share: BoundedVec<u8, ConstU32<{ crate::SCALAR_MAX_BYTES }>>,
|
||||||
pub self_binding_factor: 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, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
pub struct Round0Package<NetworkCurve> {
|
pub struct Round0Package<NetworkCurve, BlockNumber> {
|
||||||
context: PackageContext<NetworkCurve>,
|
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
pub package_hash: ExodusHash,
|
pub package_hash: ExodusHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
#[scale_info(skip_type_params(T))]
|
#[scale_info(skip_type_params(T))]
|
||||||
pub struct Round1Package<NetworkCurve, T>
|
pub struct Round1Package<NetworkCurve, BlockNumber, T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
context: PackageContext<NetworkCurve>,
|
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
pub package: BoundedVec<u8, crate::Round1MaxBytes<T>>,
|
pub package: BoundedVec<u8, crate::Round1MaxBytes<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
#[scale_info(skip_type_params(T))]
|
#[scale_info(skip_type_params(T))]
|
||||||
pub struct Round2Package<NetworkCurve, T>
|
pub struct Round2Package<NetworkCurve, BlockNumber, T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
context: PackageContext<NetworkCurve>,
|
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
pub bundle: EncryptionBundledPackages<T>,
|
pub bundle: EncryptionBundledPackages<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
#[scale_info(skip_type_params(T))]
|
#[scale_info(skip_type_params(T))]
|
||||||
pub struct Round3Package<NetworkCurve, T>
|
pub struct Round3Package<NetworkCurve, BlockNumber, T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
context: PackageContext<NetworkCurve>,
|
pub indices: ParticipantsBitmap<T>,
|
||||||
pub indices: BoundedVec<u8, crate::AccusedIndicesMaxBytes<T>>,
|
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
#[scale_info(skip_type_params(T))]
|
#[scale_info(skip_type_params(T))]
|
||||||
pub struct Round4Package<NetworkCurve, T>
|
pub struct Round4Package<NetworkCurve, BlockNumber, T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
context: PackageContext<NetworkCurve>,
|
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
pub bundle: JustificationsBundledPackages<T>,
|
pub bundle: JustificationsBundledPackages<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
pub struct Round5Package<NetworkCurve> {
|
#[scale_info(skip_type_params(T))]
|
||||||
context: PackageContext<NetworkCurve>,
|
pub struct Round5Package<NetworkCurve, BlockNumber, T>
|
||||||
|
where
|
||||||
|
T: crate::pallet::Config,
|
||||||
|
{
|
||||||
|
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
|
pub key_members: ParticipantsBitmap<T>,
|
||||||
pub verifying_key: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
pub verifying_key: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||||
pub merkle_root: ExodusHash,
|
pub merkle_root: ExodusHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)]
|
#[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
|
||||||
#[scale_info(skip_type_params(T))]
|
#[scale_info(skip_type_params(T))]
|
||||||
pub struct Round6Package<NetworkCurve, T>
|
pub struct Round6Package<NetworkCurve, BlockNumber, T>
|
||||||
where
|
where
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
context: PackageContext<NetworkCurve>,
|
context: PackageContext<NetworkCurve, BlockNumber>,
|
||||||
pub verifying_share: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
pub verifying_share: BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>,
|
||||||
pub merkle_proof: BoundedVec<ExodusHash, crate::MerkleProofMaxSize<T>>,
|
pub merkle_proof: BoundedVec<ExodusHash, crate::MerkleProofMaxSize<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NetworkCurve> PackageContext<NetworkCurve> {
|
impl<NetworkCurve, BlockNumber> PackageContext<NetworkCurve, BlockNumber> {
|
||||||
pub fn with_exodus_nonce_commitment(
|
pub fn with_exodus_nonce_commitment<NetworkId: Default>(
|
||||||
self,
|
self,
|
||||||
session: ExodusSession,
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
hiding_commitment_vec: Vec<u8>,
|
hiding_commitment_vec: Vec<u8>,
|
||||||
binding_commitment_vec: Vec<u8>,
|
binding_commitment_vec: Vec<u8>,
|
||||||
) -> Result<ExodusNonceCommitment<NetworkCurve>, ExodusError> {
|
) -> Result<ExodusNonceCommitment<NetworkCurve, NetworkId, BlockNumber>, ExodusError> {
|
||||||
let hiding_commitment =
|
let hiding_commitment = BoundedVec::try_from(hiding_commitment_vec)
|
||||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(hiding_commitment_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
let binding_commitment =
|
let binding_commitment = BoundedVec::try_from(binding_commitment_vec)
|
||||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(binding_commitment_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
Ok(ExodusNonceCommitment { context: self, hiding_commitment, binding_commitment, session })
|
Ok(ExodusNonceCommitment {
|
||||||
}
|
package_context: self,
|
||||||
|
exodus_context,
|
||||||
pub fn with_exodus_group_commitment(
|
hiding_commitment,
|
||||||
self,
|
binding_commitment,
|
||||||
session: ExodusSession,
|
|
||||||
commitment_vec: Vec<u8>,
|
|
||||||
binding_factors_root: ExodusHash,
|
|
||||||
) -> Result<ExodusGroupCommitment<NetworkCurve>, ExodusError> {
|
|
||||||
let group_commitment =
|
|
||||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(commitment_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
|
||||||
|
|
||||||
Ok(ExodusGroupCommitment {
|
|
||||||
context: self,
|
|
||||||
group_commitment,
|
|
||||||
binding_factors_root,
|
|
||||||
session,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_exodus_signature_share<T: crate::pallet::Config>(
|
pub fn with_exodus_group_commitment<NetworkId: Default>(
|
||||||
self,
|
self,
|
||||||
session: ExodusSession,
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
|
commitment_vec: Vec<u8>,
|
||||||
|
binding_factors_root: ExodusHash,
|
||||||
|
) -> Result<ExodusGroupCommitment<NetworkCurve, NetworkId, BlockNumber>, ExodusError> {
|
||||||
|
let group_commitment = BoundedVec::try_from(commitment_vec)
|
||||||
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
|
Ok(ExodusGroupCommitment {
|
||||||
|
package_context: self,
|
||||||
|
exodus_context,
|
||||||
|
group_commitment,
|
||||||
|
binding_factors_root,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_exodus_signature_share<NetworkId: Default, T: crate::pallet::Config>(
|
||||||
|
self,
|
||||||
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
signature_share_vec: Vec<u8>,
|
signature_share_vec: Vec<u8>,
|
||||||
binding_factors_proof_vec: Vec<ExodusHash>,
|
binding_factors_proof_vec: Vec<ExodusHash>,
|
||||||
self_binding_factor_vec: Vec<u8>,
|
self_binding_factor_vec: Vec<u8>,
|
||||||
) -> Result<ExodusSignatureShare<NetworkCurve, T>, ExodusError> {
|
) -> Result<ExodusSignatureShare<NetworkCurve, NetworkId, BlockNumber, T>, ExodusError> {
|
||||||
let signature_share =
|
let signature_share = BoundedVec::try_from(signature_share_vec)
|
||||||
BoundedVec::<u8, ConstU32<{ crate::SCALAR_MAX_BYTES }>>::try_from(signature_share_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
let binding_factors_proof =
|
let binding_factors_proof = BoundedVec::try_from(binding_factors_proof_vec)
|
||||||
BoundedVec::<ExodusHash, crate::BindingFactorsProof<T>>::try_from(binding_factors_proof_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
let self_binding_factor =
|
let self_binding_factor =
|
||||||
@ -351,27 +449,26 @@ impl<NetworkCurve> PackageContext<NetworkCurve> {
|
|||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
Ok(ExodusSignatureShare {
|
Ok(ExodusSignatureShare {
|
||||||
context: self,
|
package_context: self,
|
||||||
|
exodus_context,
|
||||||
binding_factors_proof,
|
binding_factors_proof,
|
||||||
self_binding_factor,
|
self_binding_factor,
|
||||||
signature_share,
|
signature_share,
|
||||||
session,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_dkg_round0(
|
pub fn with_dkg_round0(
|
||||||
self,
|
self,
|
||||||
package_hash: ExodusHash,
|
package_hash: ExodusHash,
|
||||||
) -> Round0Package<NetworkCurve> {
|
) -> Round0Package<NetworkCurve, BlockNumber> {
|
||||||
Round0Package { context: self, package_hash }
|
Round0Package { context: self, package_hash }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_dkg_round1<T: crate::pallet::Config>(
|
pub fn with_dkg_round1<T: crate::pallet::Config>(
|
||||||
self,
|
self,
|
||||||
package_vec: Vec<u8>,
|
package_vec: Vec<u8>,
|
||||||
) -> Result<Round1Package<NetworkCurve, T>, ExodusError> {
|
) -> Result<Round1Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||||
let package =
|
let package = BoundedVec::try_from(package_vec)
|
||||||
BoundedVec::<u8, crate::Round1MaxBytes<T>>::try_from(package_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
Ok(Round1Package { context: self, package })
|
Ok(Round1Package { context: self, package })
|
||||||
@ -379,80 +476,99 @@ impl<NetworkCurve> PackageContext<NetworkCurve> {
|
|||||||
|
|
||||||
pub fn with_dkg_round2<T: crate::pallet::Config>(
|
pub fn with_dkg_round2<T: crate::pallet::Config>(
|
||||||
self,
|
self,
|
||||||
bundle_raw: BundledPackages,
|
bundle_raw: BundledPackages<T>,
|
||||||
) -> Result<Round2Package<NetworkCurve, T>, ExodusError> {
|
) -> Result<Round2Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||||
let bundle: EncryptionBundledPackages<T> = bundle_raw.try_into()?;
|
let bundle: EncryptionBundledPackages<T> = bundle_raw.try_into()?;
|
||||||
Ok(Round2Package { context: self, bundle })
|
Ok(Round2Package { context: self, bundle })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_dkg_round3<T: crate::pallet::Config>(
|
pub fn with_dkg_round3<T: crate::pallet::Config>(
|
||||||
self,
|
self,
|
||||||
indices_vec: Vec<u8>
|
indices: ParticipantsBitmap<T>,
|
||||||
) -> Result<Round3Package<NetworkCurve, T>, ExodusError> {
|
) -> Result<Round3Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||||
let indices =
|
|
||||||
BoundedVec::<u8, crate::AccusedIndicesMaxBytes<T>>::try_from(indices_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
|
||||||
|
|
||||||
Ok(Round3Package { context: self, indices })
|
Ok(Round3Package { context: self, indices })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_dkg_round4<T: crate::pallet::Config>(
|
pub fn with_dkg_round4<T: crate::pallet::Config>(
|
||||||
self,
|
self,
|
||||||
bundle_raw: BundledPackages,
|
bundle_raw: BundledPackages<T>,
|
||||||
) -> Result<Round4Package<NetworkCurve, T>, ExodusError> {
|
) -> Result<Round4Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||||
let bundle: JustificationsBundledPackages<T> = bundle_raw.try_into()?;
|
let bundle: JustificationsBundledPackages<T> = bundle_raw.try_into()?;
|
||||||
Ok(Round4Package { context: self, bundle })
|
Ok(Round4Package { context: self, bundle })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_dkg_round5(
|
pub fn with_dkg_round5<T: crate::pallet::Config>(
|
||||||
self,
|
self,
|
||||||
verifying_key_vec: Vec<u8>,
|
verifying_key_vec: Vec<u8>,
|
||||||
|
key_members: ParticipantsBitmap<T>,
|
||||||
merkle_root: ExodusHash,
|
merkle_root: ExodusHash,
|
||||||
) -> Result<Round5Package<NetworkCurve>, ExodusError> {
|
) -> Result<Round5Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||||
let verifying_key =
|
let verifying_key = BoundedVec::try_from(verifying_key_vec)
|
||||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(verifying_key_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
Ok(Round5Package { context: self, verifying_key, merkle_root })
|
Ok(Round5Package { context: self, key_members, verifying_key, merkle_root })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_dkg_round6<T: crate::pallet::Config>(
|
pub fn with_dkg_round6<T: crate::pallet::Config>(
|
||||||
self,
|
self,
|
||||||
verifying_share_vec: Vec<u8>,
|
verifying_share_vec: Vec<u8>,
|
||||||
merkle_proof_vec: Vec<ExodusHash>,
|
merkle_proof_vec: Vec<ExodusHash>,
|
||||||
) -> Result<Round6Package<NetworkCurve, T>, ExodusError> {
|
) -> Result<Round6Package<NetworkCurve, BlockNumber, T>, ExodusError> {
|
||||||
let verifying_share =
|
let verifying_share = BoundedVec::try_from(verifying_share_vec)
|
||||||
BoundedVec::<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>::try_from(verifying_share_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
let merkle_proof =
|
let merkle_proof = BoundedVec::try_from(merkle_proof_vec)
|
||||||
BoundedVec::<ExodusHash, crate::MerkleProofMaxSize<T>>::try_from(merkle_proof_vec)
|
|
||||||
.map_err(|_| ExodusError::DeserializationError)?;
|
.map_err(|_| ExodusError::DeserializationError)?;
|
||||||
|
|
||||||
Ok(Round6Package { context: self, verifying_share, merkle_proof })
|
Ok(Round6Package { context: self, verifying_share, merkle_proof })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NC, T> PackageMetadata<NC> for ExodusPackage<NC, T>
|
impl<NC, NI, B, T> ExodusMetadata<NI> for ExodusPackage<NC, NI, B, T>
|
||||||
where
|
where
|
||||||
NC: Copy,
|
NI: Default + Copy,
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
fn context(&self) -> &PackageContext<NC> {
|
fn copy_exodus_context(&self) -> ExodusContext<NI> {
|
||||||
match self {
|
match self {
|
||||||
Self::NonceCommitment(package) => &package.context,
|
Self::NonceCommitment(package) => (*package).exodus_context,
|
||||||
Self::GroupCommitment(package) => &package.context,
|
Self::GroupCommitment(package) => (*package).exodus_context,
|
||||||
Self::SignatureShare(package) => &package.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, T> PackageMetadata<NC> for DkgPackage<NC, T>
|
impl<NC, NI, B, T> PackageMetadata<NC, B> for ExodusPackage<NC, NI, B, T>
|
||||||
where
|
where
|
||||||
|
NI: Default,
|
||||||
NC: Copy,
|
NC: Copy,
|
||||||
|
B: Copy,
|
||||||
T: crate::pallet::Config,
|
T: crate::pallet::Config,
|
||||||
{
|
{
|
||||||
fn context(&self) -> &PackageContext<NC> {
|
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>
|
||||||
|
where
|
||||||
|
NC: Copy,
|
||||||
|
B: Copy,
|
||||||
|
T: crate::pallet::Config,
|
||||||
|
{
|
||||||
|
fn package_context(&self) -> &PackageContext<NC, B> {
|
||||||
match self {
|
match self {
|
||||||
Self::Round0(package) => &package.context,
|
Self::Round0(package) => &package.context,
|
||||||
Self::Round1(package) => &package.context,
|
Self::Round1(package) => &package.context,
|
||||||
|
|||||||
@ -1,28 +1,33 @@
|
|||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use frame_support::{BoundedVec, traits::ConstU32};
|
use frame_support::{BoundedVec, traits::ConstU32};
|
||||||
use sp_runtime::{RuntimeDebug, traits::UniqueSaturatedInto};
|
use sp_runtime::{
|
||||||
|
RuntimeDebug,
|
||||||
|
traits::{AtLeast32BitUnsigned, UniqueSaturatedInto},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{BalanceOf, Config, ExodusContext};
|
||||||
|
use super::ExodusRequestType;
|
||||||
|
|
||||||
type ExodusNonceT = BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>;
|
type ExodusNonceT = BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>;
|
||||||
type ExodusSignatureT = BoundedVec<u8, ConstU32<{ crate::SCALAR_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)]
|
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
|
||||||
pub struct ExodusSignedMessage<NetworkId: Default, Balance: Default> {
|
#[scale_info(skip_type_params(T))]
|
||||||
|
pub struct ExodusSignedMessage<T: Config> {
|
||||||
pub nonce: ExodusNonceT,
|
pub nonce: ExodusNonceT,
|
||||||
pub signature: ExodusSignatureT,
|
pub signature: ExodusSignatureT,
|
||||||
pub r#type: Type<NetworkId, Balance>,
|
pub r#type: ExodusRequestType<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NetworkId, Balance> ExodusSignedMessage<NetworkId, Balance>
|
impl<T: Config> ExodusSignedMessage<T>
|
||||||
where
|
where
|
||||||
NetworkId: UniqueSaturatedInto<u64> + Copy + Default,
|
BalanceOf<T>: UniqueSaturatedInto<u128> + Copy + Default,
|
||||||
Balance: UniqueSaturatedInto<u128> + Copy + Default,
|
|
||||||
{
|
{
|
||||||
pub fn new<E, S>(
|
pub fn new<E, S>(
|
||||||
nonce_iter: E,
|
nonce_iter: E,
|
||||||
signature_iter: S,
|
signature_iter: S,
|
||||||
r#type: Type<NetworkId, Balance>
|
r#type: ExodusRequestType<T>,
|
||||||
) -> Option<Self>
|
) -> Option<Self>
|
||||||
where
|
where
|
||||||
E: Iterator<Item = u8> + ExactSizeIterator,
|
E: Iterator<Item = u8> + ExactSizeIterator,
|
||||||
@ -37,10 +42,24 @@ where
|
|||||||
Some(Self { nonce, signature, r#type })
|
Some(Self { nonce, signature, r#type })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_message<'a>(
|
pub fn get_message<'a, NetworkId: Default + Copy + AtLeast32BitUnsigned>(
|
||||||
&self,
|
&self,
|
||||||
message_buffer: &'a mut [u8; crate::MAX_MESSAGE_SIZE as usize],
|
message_buffer: &'a mut [u8; crate::MAX_MESSAGE_SIZE as usize],
|
||||||
|
exodus_context: ExodusContext<NetworkId>,
|
||||||
) -> Option<&'a [u8]> {
|
) -> Option<&'a [u8]> {
|
||||||
self.r#type.get_message(message_buffer)
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
|
use sp_runtime::traits::UniqueSaturatedInto;
|
||||||
use crate::{AuthIndex, ExodusSession, DkgIndex, RoastSession};
|
use crate::{AuthIndex, ExodusSession, DkgIndex, RoastSession};
|
||||||
|
|
||||||
pub enum ExodusOk<NetworkCurve> {
|
pub enum ExodusOk<NetworkCurve, NetworkId> {
|
||||||
|
ExodusRequestsFinished(AuthIndex, NetworkCurve, u32, u32),
|
||||||
ExodusEmptyRequests(AuthIndex, NetworkCurve),
|
ExodusEmptyRequests(AuthIndex, NetworkCurve),
|
||||||
ExodusWaitingState(AuthIndex, NetworkCurve),
|
ExodusWaitingState(AuthIndex, NetworkCurve),
|
||||||
ExodusNonceCommitted(ExodusSession, RoastSession, AuthIndex, NetworkCurve),
|
ExodusNonceCommitted(ExodusSession, NetworkId, RoastSession, AuthIndex, NetworkCurve),
|
||||||
ExodusGroupCommitted(ExodusSession, RoastSession, AuthIndex, NetworkCurve),
|
ExodusGroupCommitted(ExodusSession, NetworkId, RoastSession, AuthIndex, NetworkCurve),
|
||||||
ExodusSignedPartially(ExodusSession, RoastSession, AuthIndex, NetworkCurve),
|
ExodusSignedPartially(ExodusSession, NetworkId, RoastSession, AuthIndex, NetworkCurve),
|
||||||
ExodusVerifyingShareMissed(AuthIndex, DkgIndex, NetworkCurve),
|
ExodusVerifyingShareMissed(AuthIndex, DkgIndex, NetworkCurve),
|
||||||
|
|
||||||
DkgNotPartOfRound(u8, AuthIndex, NetworkCurve),
|
DkgNotPartOfRound(u8, AuthIndex, NetworkCurve),
|
||||||
DkgRoundRegistered(u8, AuthIndex, NetworkCurve),
|
DkgRoundRegistered(u8, AuthIndex, NetworkCurve),
|
||||||
DkgPreviousPurged(AuthIndex, NetworkCurve),
|
DkgPreviousPurged(AuthIndex, NetworkCurve, u32),
|
||||||
|
DkgLocalStoragePurged(AuthIndex, NetworkCurve, DkgIndex),
|
||||||
DkgRoundsCleared(AuthIndex, NetworkCurve),
|
DkgRoundsCleared(AuthIndex, NetworkCurve),
|
||||||
DkgRoundAlreadyPassed(u8, AuthIndex, NetworkCurve),
|
DkgRoundAlreadyPassed(u8, AuthIndex, NetworkCurve),
|
||||||
DkgRoundWaitingPeriod(u8, AuthIndex, NetworkCurve),
|
DkgRoundWaitingPeriod(u8, AuthIndex, NetworkCurve),
|
||||||
@ -18,27 +21,41 @@ pub enum ExodusOk<NetworkCurve> {
|
|||||||
DkgRoundMaxSignersNarrowed(u8, AuthIndex, AuthIndex, AuthIndex, NetworkCurve),
|
DkgRoundMaxSignersNarrowed(u8, AuthIndex, AuthIndex, AuthIndex, NetworkCurve),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NetworkCurve> core::fmt::Display for ExodusOk<NetworkCurve>
|
impl<NetworkCurve, NetworkId> core::fmt::Debug for ExodusOk<NetworkCurve, NetworkId>
|
||||||
where
|
where
|
||||||
NetworkCurve: core::fmt::Display
|
NetworkCurve: core::fmt::Display,
|
||||||
|
NetworkId: UniqueSaturatedInto<u64> + Copy,
|
||||||
{
|
{
|
||||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ExodusOk::ExodusEmptyRequests(auth_index, curve) => write!(fmt, "No EXODUS requests found by authority #{auth_index} for curve {curve}."),
|
ExodusOk::ExodusRequestsFinished(auth_index, curve, success_count, failed_count) => {
|
||||||
ExodusOk::ExodusWaitingState(auth_index, curve) => write!(fmt, "Waiting for EXODUS requests to be processed by authority #{auth_index} for curve {curve}."),
|
write!(fmt, "EXODUS requests processing round completed by authority #{auth_index} for curve {curve}: {success_count} tasks succeeded, {failed_count} tasks failed.")
|
||||||
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::ExodusEmptyRequests(auth_index, curve) => write!(fmt, "No EXODUS requests found for authority #{auth_index} on 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::ExodusWaitingState(auth_index, curve) => write!(fmt, "Waiting for EXODUS requests to be processed by authority #{auth_index} on 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::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::DkgNotPartOfRound(round, auth_index, curve) => write!(fmt, "DKG authority #{auth_index} for network curve {curve} is not part of Round{round}."),
|
ExodusOk::DkgNotPartOfRound(round, auth_index, curve) => write!(fmt, "DKG authority #{auth_index} is not part of Round {round} for network curve {curve}."),
|
||||||
ExodusOk::DkgRoundRegistered(round, auth_index, curve) => write!(fmt, "DKG Round{round} registered by authority #{auth_index} for network curve {curve}."),
|
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) => write!(fmt, "Storage prepared for new DKG session 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::DkgRoundsCleared(auth_index, curve) => write!(fmt, "DKG Rounds cleared from storage 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 done 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} waiting to be applied 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, "DKG nothing stored from Round{round} 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 {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}."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
//! Autogenerated weights for `ghost_exodus`
|
//! Autogenerated weights for `ghost_exodus`
|
||||||
//!
|
//!
|
||||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||||
//! DATE: 2026-09-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||||
//! WORST CASE MAP SIZE: `1000000`
|
//! WORST CASE MAP SIZE: `1000000`
|
||||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||||
@ -63,34 +63,30 @@ pub trait WeightInfo {
|
|||||||
|
|
||||||
/// Weight functions for `ghost_exodus`.
|
/// Weight functions for `ghost_exodus`.
|
||||||
impl WeightInfo for () {
|
impl WeightInfo for () {
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:1)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Round0Packages` (r:0 w:1)
|
||||||
/// Proof: `GhostExodus::Round0Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Round0Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
fn register_round0_package() -> Weight {
|
fn register_round0_package() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `351`
|
// Measured: `365`
|
||||||
// Estimated: `3816`
|
// Estimated: `3830`
|
||||||
// Minimum execution time: 240_813_000 picoseconds.
|
// Minimum execution time: 240_843_000 picoseconds.
|
||||||
Weight::from_parts(243_523_000, 0)
|
Weight::from_parts(243_855_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3816))
|
.saturating_add(Weight::from_parts(0, 3830))
|
||||||
.saturating_add(RocksDbWeight::get().reads(4))
|
.saturating_add(RocksDbWeight::get().reads(4))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3))
|
.saturating_add(RocksDbWeight::get().writes(2))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Round0Packages` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::Round0Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Round0Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::Round1Packages` (r:1 w:1)
|
/// Storage: `GhostExodus::Round1Packages` (r:1 w:1)
|
||||||
@ -98,119 +94,109 @@ impl WeightInfo for () {
|
|||||||
/// The range of component `c` is `[4, 300]`.
|
/// The range of component `c` is `[4, 300]`.
|
||||||
fn register_round1_package(c: u32, ) -> Weight {
|
fn register_round1_package(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `391 + c * (32 ±0)`
|
// Measured: `405 + c * (32 ±0)`
|
||||||
// Estimated: `3856 + c * (32 ±0)`
|
// Estimated: `3870 + c * (32 ±0)`
|
||||||
// Minimum execution time: 1_356_791_000 picoseconds.
|
// Minimum execution time: 1_349_108_000 picoseconds.
|
||||||
Weight::from_parts(1_221_760_215, 0)
|
Weight::from_parts(1_224_956_354, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3856))
|
.saturating_add(Weight::from_parts(0, 3870))
|
||||||
// Standard Error: 16_481
|
// Standard Error: 14_930
|
||||||
.saturating_add(Weight::from_parts(33_163_393, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(33_204_477, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(RocksDbWeight::get().reads(6))
|
.saturating_add(RocksDbWeight::get().reads(5))
|
||||||
.saturating_add(RocksDbWeight::get().writes(2))
|
.saturating_add(RocksDbWeight::get().writes(1))
|
||||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Round2Packages` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::Round2Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Round2Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// The range of component `c` is `[1, 37]`.
|
/// The range of component `c` is `[1, 300]`.
|
||||||
fn register_encrypted_round2_packages(c: u32, ) -> Weight {
|
fn register_encrypted_round2_packages(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `317 + c * (257 ±0)`
|
// Measured: `332 + c * (32 ±0)`
|
||||||
// Estimated: `3783 + c * (257 ±0)`
|
// Estimated: `3797 + c * (32 ±0)`
|
||||||
// Minimum execution time: 254_590_000 picoseconds.
|
// Minimum execution time: 245_305_000 picoseconds.
|
||||||
Weight::from_parts(258_091_105, 0)
|
Weight::from_parts(253_863_353, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3783))
|
.saturating_add(Weight::from_parts(0, 3797))
|
||||||
// Standard Error: 25_082
|
// Standard Error: 3_527
|
||||||
.saturating_add(Weight::from_parts(6_595_878, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(810_623, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(RocksDbWeight::get().reads(5))
|
.saturating_add(RocksDbWeight::get().reads(4))
|
||||||
.saturating_add(RocksDbWeight::get().writes(2))
|
.saturating_add(RocksDbWeight::get().writes(1))
|
||||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Complaints` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::Complaints` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Complaints` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// The range of component `c` is `[1, 37]`.
|
/// The range of component `c` is `[1, 300]`.
|
||||||
fn register_round3_complaints(c: u32, ) -> Weight {
|
fn register_round3_complaints(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `317 + c * (257 ±0)`
|
// Measured: `332 + c * (32 ±0)`
|
||||||
// Estimated: `3783 + c * (257 ±0)`
|
// Estimated: `3797 + c * (32 ±0)`
|
||||||
// Minimum execution time: 240_888_000 picoseconds.
|
// Minimum execution time: 238_391_000 picoseconds.
|
||||||
Weight::from_parts(245_480_975, 0)
|
Weight::from_parts(238_937_380, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3783))
|
.saturating_add(Weight::from_parts(0, 3797))
|
||||||
// Standard Error: 13_733
|
// Standard Error: 1_789
|
||||||
.saturating_add(Weight::from_parts(371_161, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(39_316, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(RocksDbWeight::get().reads(5))
|
.saturating_add(RocksDbWeight::get().reads(4))
|
||||||
.saturating_add(RocksDbWeight::get().writes(2))
|
.saturating_add(RocksDbWeight::get().writes(1))
|
||||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Justifications` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::Justifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Justifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// The range of component `c` is `[1, 37]`.
|
/// The range of component `c` is `[1, 300]`.
|
||||||
fn register_round4_justifications(c: u32, ) -> Weight {
|
fn register_round4_justifications(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `317 + c * (257 ±0)`
|
// Measured: `332 + c * (32 ±0)`
|
||||||
// Estimated: `3783 + c * (257 ±0)`
|
// Estimated: `3797 + c * (32 ±0)`
|
||||||
// Minimum execution time: 251_521_000 picoseconds.
|
// Minimum execution time: 245_916_000 picoseconds.
|
||||||
Weight::from_parts(253_053_636, 0)
|
Weight::from_parts(251_070_206, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3783))
|
.saturating_add(Weight::from_parts(0, 3797))
|
||||||
// Standard Error: 14_691
|
// Standard Error: 2_152
|
||||||
.saturating_add(Weight::from_parts(4_101_872, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(508_508, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(RocksDbWeight::get().reads(5))
|
.saturating_add(RocksDbWeight::get().reads(4))
|
||||||
.saturating_add(RocksDbWeight::get().writes(2))
|
.saturating_add(RocksDbWeight::get().writes(1))
|
||||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Verifications` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::Verifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Verifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:1)
|
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
fn register_round5_verifying_package() -> Weight {
|
fn register_round5_verifying_package() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `448`
|
// Measured: `462`
|
||||||
// Estimated: `3913`
|
// Estimated: `3927`
|
||||||
// Minimum execution time: 265_187_000 picoseconds.
|
// Minimum execution time: 271_654_000 picoseconds.
|
||||||
Weight::from_parts(269_124_000, 0)
|
Weight::from_parts(286_394_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3913))
|
.saturating_add(Weight::from_parts(0, 3927))
|
||||||
.saturating_add(RocksDbWeight::get().reads(6))
|
.saturating_add(RocksDbWeight::get().reads(5))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3))
|
.saturating_add(RocksDbWeight::get().writes(2))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::VerifyingShares` (r:1 w:1)
|
/// Storage: `GhostExodus::VerifyingShares` (r:1 w:1)
|
||||||
@ -221,18 +207,18 @@ impl WeightInfo for () {
|
|||||||
fn register_round6_public_share_package(c: u32, ) -> Weight {
|
fn register_round6_public_share_package(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `0 + c * (770 ±0)`
|
// Measured: `0 + c * (770 ±0)`
|
||||||
// Estimated: `1551 + c * (1019 ±27)`
|
// Estimated: `1698 + c * (1019 ±27)`
|
||||||
// Minimum execution time: 284_558_000 picoseconds.
|
// Minimum execution time: 283_863_000 picoseconds.
|
||||||
Weight::from_parts(284_117_484, 0)
|
Weight::from_parts(286_691_978, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 1551))
|
.saturating_add(Weight::from_parts(0, 1698))
|
||||||
// Standard Error: 74_361
|
// Standard Error: 85_685
|
||||||
.saturating_add(Weight::from_parts(3_551_271, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(2_854_037, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(RocksDbWeight::get().reads(7))
|
.saturating_add(RocksDbWeight::get().reads(6))
|
||||||
.saturating_add(RocksDbWeight::get().writes(3))
|
.saturating_add(RocksDbWeight::get().writes(2))
|
||||||
.saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||||
@ -243,24 +229,22 @@ impl WeightInfo for () {
|
|||||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::RoastSessionStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::RoastSessionStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::NonceCommitments` (r:0 w:1)
|
/// Storage: `GhostExodus::NonceCommitments` (r:0 w:1)
|
||||||
/// Proof: `GhostExodus::NonceCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::NonceCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
fn register_nonce_commitment() -> Weight {
|
fn register_nonce_commitment() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `627`
|
// Measured: `633`
|
||||||
// Estimated: `4092`
|
// Estimated: `4098`
|
||||||
// Minimum execution time: 315_066_000 picoseconds.
|
// Minimum execution time: 369_666_000 picoseconds.
|
||||||
Weight::from_parts(318_561_000, 0)
|
Weight::from_parts(373_163_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 4092))
|
.saturating_add(Weight::from_parts(0, 4098))
|
||||||
.saturating_add(RocksDbWeight::get().reads(8))
|
.saturating_add(RocksDbWeight::get().reads(8))
|
||||||
.saturating_add(RocksDbWeight::get().writes(5))
|
.saturating_add(RocksDbWeight::get().writes(4))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||||
@ -269,8 +253,6 @@ impl WeightInfo for () {
|
|||||||
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:0)
|
/// Storage: `GhostExodus::RoastSessions` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::GroupCommitters` (r:1 w:1)
|
/// Storage: `GhostExodus::GroupCommitters` (r:1 w:1)
|
||||||
@ -281,16 +263,16 @@ impl WeightInfo for () {
|
|||||||
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
fn register_group_commitment() -> Weight {
|
fn register_group_commitment() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `992`
|
// Measured: `1032`
|
||||||
// Estimated: `4457`
|
// Estimated: `4495`
|
||||||
// Minimum execution time: 338_644_000 picoseconds.
|
// Minimum execution time: 339_569_000 picoseconds.
|
||||||
Weight::from_parts(343_954_000, 0)
|
Weight::from_parts(341_788_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 4457))
|
.saturating_add(Weight::from_parts(0, 4495))
|
||||||
.saturating_add(RocksDbWeight::get().reads(10))
|
.saturating_add(RocksDbWeight::get().reads(9))
|
||||||
.saturating_add(RocksDbWeight::get().writes(4))
|
.saturating_add(RocksDbWeight::get().writes(3))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||||
@ -299,8 +281,6 @@ impl WeightInfo for () {
|
|||||||
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::ActiveAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::GroupCommitmentsConsensus` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||||
@ -323,13 +303,13 @@ impl WeightInfo for () {
|
|||||||
/// Proof: `GhostExodus::CounterForExodusRequests` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::CounterForExodusRequests` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||||
fn register_signature_share() -> Weight {
|
fn register_signature_share() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `11299`
|
// Measured: `11337`
|
||||||
// Estimated: `14764`
|
// Estimated: `14802`
|
||||||
// Minimum execution time: 3_968_938_000 picoseconds.
|
// Minimum execution time: 4_046_065_000 picoseconds.
|
||||||
Weight::from_parts(3_975_088_000, 0)
|
Weight::from_parts(4_059_064_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 14764))
|
.saturating_add(Weight::from_parts(0, 14802))
|
||||||
.saturating_add(RocksDbWeight::get().reads(15))
|
.saturating_add(RocksDbWeight::get().reads(14))
|
||||||
.saturating_add(RocksDbWeight::get().writes(9))
|
.saturating_add(RocksDbWeight::get().writes(8))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
@ -339,17 +319,17 @@ impl WeightInfo for () {
|
|||||||
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::CurrentExodus` (r:1 w:1)
|
/// Storage: `GhostExodus::CurrentExodusSessions` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::CurrentExodus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::CurrentExodusSessions` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
fn register_evm_bridge_out_exodus() -> Weight {
|
fn register_evm_bridge_out_exodus() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `448`
|
// Measured: `457`
|
||||||
// Estimated: `3913`
|
// Estimated: `3922`
|
||||||
// Minimum execution time: 191_374_000 picoseconds.
|
// Minimum execution time: 195_417_000 picoseconds.
|
||||||
Weight::from_parts(192_991_000, 0)
|
Weight::from_parts(196_842_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3913))
|
.saturating_add(Weight::from_parts(0, 3922))
|
||||||
.saturating_add(RocksDbWeight::get().reads(7))
|
.saturating_add(RocksDbWeight::get().reads(7))
|
||||||
.saturating_add(RocksDbWeight::get().writes(5))
|
.saturating_add(RocksDbWeight::get().writes(5))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ghost-governance"
|
name = "ghost-governance"
|
||||||
version = "0.3.10"
|
version = "0.3.11"
|
||||||
description = "Full-chain and cross-chain governance pallet with early adopter share claims"
|
description = "Full-chain and cross-chain governance pallet with early adopter share claims"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|||||||
@ -79,14 +79,21 @@ fn claim_happy_path() {
|
|||||||
let users = vec![user_1.clone(), user_2.clone(), user_3.clone()];
|
let users = vec![user_1.clone(), user_2.clone(), user_3.clone()];
|
||||||
let max_index = 2u8;
|
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 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,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_values_complex,
|
raw_values_complex,
|
||||||
|
|
||||||
|item: (u8, &NewTestUser)| -> Result<(usize, Vec<u8>), ()> {
|
|(index, u), buffer| {
|
||||||
let (index, u) = item;
|
|
||||||
|
|
||||||
let tmp_package = ClaimPackage::<Test> {
|
let tmp_package = ClaimPackage::<Test> {
|
||||||
shares: u.allowed_shares,
|
shares: u.allowed_shares,
|
||||||
merkle_proof: Default::default(),
|
merkle_proof: Default::default(),
|
||||||
@ -94,9 +101,12 @@ fn claim_happy_path() {
|
|||||||
index: index as u32
|
index: index as u32
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((index as usize, tmp_package.get_preimage(&u.evm_address, network_id).to_vec()))
|
let preimage_bytes = tmp_package.get_preimage(&u.evm_address, network_id);
|
||||||
|
buffer.extend_from_slice(preimage_bytes.as_ref());
|
||||||
|
|
||||||
|
Ok(index as usize)
|
||||||
}
|
}
|
||||||
).unwrap();
|
).ok().unwrap();
|
||||||
|
|
||||||
let merkle_root = *merkle_tree.last().unwrap();
|
let merkle_root = *merkle_tree.last().unwrap();
|
||||||
|
|
||||||
@ -116,7 +126,9 @@ fn claim_happy_path() {
|
|||||||
activated_shares: 0,
|
activated_shares: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
let proof = generate_proof::<SubstrateKeccakHasher, u8>(&merkle_tree, max_index, slot_index as u8);
|
let proof = generate_proof::<SubstrateKeccakHasher, u8, ()>(&merkle_tree, max_index, slot_index as u8)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let claim_package = ClaimPackage::<Test> {
|
let claim_package = ClaimPackage::<Test> {
|
||||||
shares: current_user.allowed_shares,
|
shares: current_user.allowed_shares,
|
||||||
@ -205,21 +217,33 @@ fn partial_claims_happy_path() {
|
|||||||
let max_index = 0u8;
|
let max_index = 0u8;
|
||||||
let raw_values_complex = vec![(0u8, ¤t_user)];
|
let raw_values_complex = vec![(0u8, ¤t_user)];
|
||||||
|
|
||||||
let merkle_tree = generate_tree::<SubstrateKeccakHasher, u8, _, _, _>(
|
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,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_values_complex,
|
raw_values_complex,
|
||||||
|
|
||||||
|item: (u8, &NewTestUser)| -> Result<(usize, Vec<u8>), ()> {
|
|(index, u), buffer| {
|
||||||
let (index, u) = item;
|
|
||||||
let tmp_package = ClaimPackage::<Test> {
|
let tmp_package = ClaimPackage::<Test> {
|
||||||
shares: u.allowed_shares,
|
shares: u.allowed_shares,
|
||||||
merkle_proof: Default::default(),
|
merkle_proof: Default::default(),
|
||||||
token_id: u.token_id,
|
token_id: u.token_id,
|
||||||
index: index as u32
|
index: index as u32
|
||||||
};
|
};
|
||||||
Ok((index as usize, tmp_package.get_preimage(&u.evm_address, network_id).to_vec()))
|
|
||||||
|
let preimage_bytes = tmp_package.get_preimage(&u.evm_address, network_id);
|
||||||
|
buffer.extend_from_slice(preimage_bytes.as_ref());
|
||||||
|
|
||||||
|
Ok(index as usize)
|
||||||
}
|
}
|
||||||
).unwrap();
|
).ok().unwrap();
|
||||||
|
|
||||||
let total_shares = 1_000_000;
|
let total_shares = 1_000_000;
|
||||||
let merkle_root = *merkle_tree.last().unwrap();
|
let merkle_root = *merkle_tree.last().unwrap();
|
||||||
@ -240,7 +264,10 @@ fn partial_claims_happy_path() {
|
|||||||
setup_governor(&substrate_account_b);
|
setup_governor(&substrate_account_b);
|
||||||
setup_governor(&substrate_account_c);
|
setup_governor(&substrate_account_c);
|
||||||
|
|
||||||
let proof = generate_proof::<SubstrateKeccakHasher, u8>(&merkle_tree, max_index, 0u8);
|
let proof = generate_proof::<SubstrateKeccakHasher, u8, ()>(&merkle_tree, max_index, 0u8)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let claim_package = ClaimPackage {
|
let claim_package = ClaimPackage {
|
||||||
shares: current_user.allowed_shares,
|
shares: current_user.allowed_shares,
|
||||||
merkle_proof: BoundedVec::try_from(proof).unwrap(),
|
merkle_proof: BoundedVec::try_from(proof).unwrap(),
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
//! Autogenerated weights for `ghost_governance`
|
//! Autogenerated weights for `ghost_governance`
|
||||||
//!
|
//!
|
||||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||||
//! DATE: 2026-09-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||||
//! WORST CASE MAP SIZE: `1000000`
|
//! WORST CASE MAP SIZE: `1000000`
|
||||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||||
@ -67,11 +67,11 @@ impl WeightInfo for () {
|
|||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `283`
|
// Measured: `283`
|
||||||
// Estimated: `3748`
|
// Estimated: `3748`
|
||||||
// Minimum execution time: 229_254_000 picoseconds.
|
// Minimum execution time: 224_852_000 picoseconds.
|
||||||
Weight::from_parts(229_992_093, 0)
|
Weight::from_parts(225_347_733, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3748))
|
.saturating_add(Weight::from_parts(0, 3748))
|
||||||
// Standard Error: 25_680
|
// Standard Error: 21_234
|
||||||
.saturating_add(Weight::from_parts(1_874_433, 0).saturating_mul(p.into()))
|
.saturating_add(Weight::from_parts(1_581_800, 0).saturating_mul(p.into()))
|
||||||
.saturating_add(RocksDbWeight::get().reads(5))
|
.saturating_add(RocksDbWeight::get().reads(5))
|
||||||
.saturating_add(RocksDbWeight::get().writes(5))
|
.saturating_add(RocksDbWeight::get().writes(5))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ghost-helpers"
|
name = "ghost-helpers"
|
||||||
version = "0.0.11"
|
version = "0.0.16"
|
||||||
description = "Cryptographic utility suite for custom runtimes: optimized Bitmaps, UTXO parsing, Merkle Tree proofs, and Hash Chain components."
|
description = "Cryptographic utility suite for custom runtimes: optimized Bitmaps, UTXO parsing, Merkle Tree proofs, and Hash Chain components."
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|||||||
@ -2,8 +2,8 @@ use codec::{Decode, Encode};
|
|||||||
use num_traits::PrimInt;
|
use num_traits::PrimInt;
|
||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
|
|
||||||
|
use sp_runtime::traits::UniqueSaturatedInto;
|
||||||
use sp_arithmetic::traits::AtLeast8BitUnsigned;
|
use sp_arithmetic::traits::AtLeast8BitUnsigned;
|
||||||
use sp_runtime::{traits::UniqueSaturatedInto, RuntimeDebug};
|
|
||||||
use sp_std::{cmp::{min, max}, marker::PhantomData, vec, vec::Vec};
|
use sp_std::{cmp::{min, max}, marker::PhantomData, vec, vec::Vec};
|
||||||
|
|
||||||
use ghost_traits::bounded_bitmap as traits;
|
use ghost_traits::bounded_bitmap as traits;
|
||||||
@ -33,7 +33,7 @@ pub fn validate_bitmap_sizes<B: traits::BoundedBitmapMetadata>(authorities: u32)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
|
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||||
#[scale_info(skip_type_params(MaxChunks))]
|
#[scale_info(skip_type_params(MaxChunks))]
|
||||||
pub struct BoundedBitmap<Inner, MaxChunks>
|
pub struct BoundedBitmap<Inner, MaxChunks>
|
||||||
where
|
where
|
||||||
@ -43,6 +43,19 @@ where
|
|||||||
active_bits_count: u32,
|
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>
|
impl<Inner, MaxChunks> BoundedBitmap<Inner, MaxChunks>
|
||||||
where
|
where
|
||||||
MaxChunks: Get<u32>,
|
MaxChunks: Get<u32>,
|
||||||
@ -54,6 +67,15 @@ where
|
|||||||
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
||||||
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
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
|
fn combine<F>(&self, rhs: &Self, op: F) -> Self
|
||||||
where
|
where
|
||||||
Inner: Copy,
|
Inner: Copy,
|
||||||
@ -146,41 +168,6 @@ where
|
|||||||
new_bitmap
|
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
|
fn all_ones<N>(n: N) -> Self
|
||||||
where
|
where
|
||||||
N: UniqueSaturatedInto<usize>,
|
N: UniqueSaturatedInto<usize>,
|
||||||
@ -307,6 +294,35 @@ 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
|
fn count_ones<N>(&self) -> N
|
||||||
where
|
where
|
||||||
u32: UniqueSaturatedInto<N>,
|
u32: UniqueSaturatedInto<N>,
|
||||||
@ -425,6 +441,14 @@ where
|
|||||||
self.highest_bit()
|
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
|
fn count_ones<N>(&self) -> N
|
||||||
where
|
where
|
||||||
u32: UniqueSaturatedInto<N>,
|
u32: UniqueSaturatedInto<N>,
|
||||||
@ -476,13 +500,6 @@ where
|
|||||||
Self::empty_from(bitmap_ref)
|
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
|
fn from_vec<Outer>(values_ref: &Vec<Outer>) -> Self
|
||||||
where
|
where
|
||||||
Outer: AtLeast8BitUnsigned + TryInto<usize> + PartialEq + Copy,
|
Outer: AtLeast8BitUnsigned + TryInto<usize> + PartialEq + Copy,
|
||||||
@ -1099,50 +1116,72 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_bitmask_where_each_u8_is_a_bit() {
|
fn test_count_ones_before_basic() {
|
||||||
let byte1 = 77u8;
|
let w = <$inner_type>::BITS as usize;
|
||||||
let byte2 = 42u8;
|
let idx = |x: usize| -> $inner_type {
|
||||||
let byte3 = 69u8;
|
x.try_into().ok().expect("bit index fits inner type")
|
||||||
|
};
|
||||||
|
|
||||||
let raw_bits: Vec<u8> = vec![byte1, byte2, byte3];
|
let mut indices: Vec<$inner_type> = vec![
|
||||||
let bitmap = TestBitmap::from_bitmask(&raw_bits);
|
0u8.into(),
|
||||||
|
1u8.into(),
|
||||||
|
3u8.into()
|
||||||
|
];
|
||||||
|
|
||||||
let count_ones = raw_bits.iter().map(|b| b.count_ones()).sum::<u32>();
|
indices.extend([idx(w), idx(w + 1), idx(w + 3)] as [$inner_type; 3]);
|
||||||
let filled_bits = (raw_bits.len() as u32 - 1) * 8;
|
let bitmap = TestBitmap::from_vec(&indices);
|
||||||
let expected_bits = filled_bits + (8 - byte3.leading_zeros());
|
|
||||||
|
|
||||||
assert_eq!(bitmap.active_bits_count(), expected_bits);
|
assert_eq!(bitmap.count_ones_before(0), Some(0));
|
||||||
assert_eq!(bitmap.count_ones::<u32>(), count_ones);
|
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));
|
||||||
|
|
||||||
// 77 - 10110010
|
assert_eq!(bitmap.count_ones_before(w + 1), Some(4));
|
||||||
assert!(bitmap.contains(0u32));
|
assert_eq!(bitmap.count_ones_before(w + 4), Some(6));
|
||||||
assert!(!bitmap.contains(1u32));
|
assert_eq!(bitmap.count_ones_before(2 * w), Some(6));
|
||||||
assert!(bitmap.contains(2u32));
|
}
|
||||||
assert!(bitmap.contains(3u32));
|
|
||||||
assert!(!bitmap.contains(4u32));
|
|
||||||
assert!(!bitmap.contains(5u32));
|
|
||||||
assert!(bitmap.contains(6u32));
|
|
||||||
assert!(!bitmap.contains(7u32));
|
|
||||||
|
|
||||||
// 42 - 01010100
|
#[test]
|
||||||
assert!(!bitmap.contains(8u32));
|
fn test_count_ones_before_crossing_elements() {
|
||||||
assert!(bitmap.contains(9u32));
|
let w = <$inner_type>::BITS as usize;
|
||||||
assert!(!bitmap.contains(10u32));
|
let idx = |x: usize| -> $inner_type {
|
||||||
assert!(bitmap.contains(11u32));
|
x.try_into().ok().expect("bit index fits inner type")
|
||||||
assert!(!bitmap.contains(12u32));
|
};
|
||||||
assert!(bitmap.contains(13u32));
|
|
||||||
assert!(!bitmap.contains(14u32));
|
|
||||||
assert!(!bitmap.contains(15u32));
|
|
||||||
|
|
||||||
// 69 - 10100010
|
let mut bitmap = TestBitmap::empty(2 * w + 1);
|
||||||
assert!(bitmap.contains(16u32));
|
for i in [0usize, 1, w, w + 1, w + 2] {
|
||||||
assert!(!bitmap.contains(17u32));
|
bitmap.insert(idx(i));
|
||||||
assert!(bitmap.contains(18u32));
|
}
|
||||||
assert!(!bitmap.contains(19u32));
|
|
||||||
assert!(!bitmap.contains(20u32));
|
let bits_per_element = core::mem::size_of::<$inner_type>() * 8;
|
||||||
assert!(!bitmap.contains(21u32));
|
|
||||||
assert!(bitmap.contains(22u32));
|
assert_eq!(bitmap.count_ones_before(bits_per_element), Some(2));
|
||||||
assert!(!bitmap.contains(23u32));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,19 +1,5 @@
|
|||||||
use ghost_traits::hashing::GhostHasher;
|
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
|
pub fn cumulative_hash<H, S>(raw_values: S) -> H::Hash
|
||||||
where
|
where
|
||||||
H: GhostHasher,
|
H: GhostHasher,
|
||||||
@ -24,7 +10,7 @@ where
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(H::empty(), |acc_hash, raw_value| {
|
.fold(H::empty(), |acc_hash, raw_value| {
|
||||||
let hashed_value = H::hash(raw_value.as_ref());
|
let hashed_value = H::hash(raw_value.as_ref());
|
||||||
combine_values::<H, _>(acc_hash, hashed_value)
|
H::combine_hashes(acc_hash, hashed_value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +33,7 @@ where
|
|||||||
|
|
||||||
iter.fold(current_hash, |acc_hash, raw_value| {
|
iter.fold(current_hash, |acc_hash, raw_value| {
|
||||||
let next_hash = H::from_slice(raw_value.as_ref());
|
let next_hash = H::from_slice(raw_value.as_ref());
|
||||||
combine_values::<H, _>(acc_hash, next_hash)
|
H::combine_hashes(acc_hash, next_hash)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,45 +80,14 @@ where
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use sp_core::H256;
|
use sp_core::H256;
|
||||||
use sp_io::hashing::{blake2_256, sha2_256};
|
|
||||||
use sp_std::vec::Vec;
|
use sp_std::vec::Vec;
|
||||||
|
|
||||||
pub struct TestBlake2Hasher;
|
use crate::{
|
||||||
impl GhostHasher for TestBlake2Hasher {
|
SubstrateBlake2Hasher, SubstrateKeccakHasher, UtxoSha2Hasher,
|
||||||
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 {
|
fn mock_sequential_hash(header: &[u8; 80]) -> H256 {
|
||||||
sequential_hash::<TestSha2Hasher, _>(core::iter::once(header))
|
sequential_hash::<UtxoSha2Hasher, _>(core::iter::once(header))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_header(prev_hash: [u8; 32]) -> [u8; 80] {
|
fn create_header(prev_hash: [u8; 32]) -> [u8; 80] {
|
||||||
@ -141,10 +96,15 @@ mod tests {
|
|||||||
header
|
header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! run_hasher_tests {
|
||||||
|
($hasher_type:ty, $mod_name:ident) => {
|
||||||
|
mod $mod_name {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_generate_empty_values() {
|
fn test_generate_empty_values() {
|
||||||
let empty_list: Vec<Vec<u8>> = sp_std::vec![];
|
let empty_list: Vec<Vec<u8>> = sp_std::vec![];
|
||||||
let result = cumulative_hash::<TestBlake2Hasher, _>(empty_list);
|
let result = cumulative_hash::<$hasher_type, _>(empty_list);
|
||||||
assert_eq!(H256::zero(), result);
|
assert_eq!(H256::zero(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,9 +114,9 @@ mod tests {
|
|||||||
let dataset_2 = sp_std::vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
|
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 dataset_3 = sp_std::vec![vec![9, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
|
||||||
|
|
||||||
let hash_1 = cumulative_hash::<TestBlake2Hasher, _>(dataset_1);
|
let hash_1 = cumulative_hash::<$hasher_type, _>(dataset_1);
|
||||||
let hash_2 = cumulative_hash::<TestBlake2Hasher, _>(dataset_2);
|
let hash_2 = cumulative_hash::<$hasher_type, _>(dataset_2);
|
||||||
let hash_3 = cumulative_hash::<TestBlake2Hasher, _>(dataset_3);
|
let hash_3 = cumulative_hash::<$hasher_type, _>(dataset_3);
|
||||||
|
|
||||||
assert_eq!(hash_1, hash_2);
|
assert_eq!(hash_1, hash_2);
|
||||||
assert_ne!(hash_1, hash_3);
|
assert_ne!(hash_1, hash_3);
|
||||||
@ -168,8 +128,8 @@ mod tests {
|
|||||||
let dataset_forward = sp_std::vec![sp_std::vec![1, 1, 1], sp_std::vec![2, 2, 2]];
|
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 dataset_reversed = sp_std::vec![sp_std::vec![2, 2, 2], sp_std::vec![1, 1, 1]];
|
||||||
|
|
||||||
let hash_forward = cumulative_hash::<TestBlake2Hasher, _>(dataset_forward);
|
let hash_forward = cumulative_hash::<$hasher_type, _>(dataset_forward);
|
||||||
let hash_reversed = cumulative_hash::<TestBlake2Hasher, _>(dataset_reversed);
|
let hash_reversed = cumulative_hash::<$hasher_type, _>(dataset_reversed);
|
||||||
|
|
||||||
assert_ne!(hash_forward, hash_reversed);
|
assert_ne!(hash_forward, hash_reversed);
|
||||||
}
|
}
|
||||||
@ -177,22 +137,22 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_cumulative_hash_with_slices() {
|
fn test_cumulative_hash_with_slices() {
|
||||||
let slice_data: &[&[u8]] = &[&[1, 2, 3], &[4, 5, 6]];
|
let slice_data: &[&[u8]] = &[&[1, 2, 3], &[4, 5, 6]];
|
||||||
let hash_from_slice = cumulative_hash::<TestBlake2Hasher, _>(slice_data.iter());
|
let hash_from_slice = cumulative_hash::<$hasher_type, _>(slice_data.iter());
|
||||||
assert_ne!(hash_from_slice, H256::zero());
|
assert_ne!(hash_from_slice, H256::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sequential_hash_empty() {
|
fn test_sequential_hash_empty() {
|
||||||
let empty_list: Vec<Vec<u8>> = sp_std::vec![];
|
let empty_list: Vec<Vec<u8>> = sp_std::vec![];
|
||||||
let result = sequential_hash::<TestBlake2Hasher, _>(empty_list);
|
let result = sequential_hash::<$hasher_type, _>(empty_list);
|
||||||
assert_eq!(H256::zero(), result);
|
assert_eq!(H256::zero(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sequential_hash_single_element() {
|
fn test_sequential_hash_single_element() {
|
||||||
let single_item = sp_std::vec![sp_std::vec![1, 2, 3]];
|
let single_item = sp_std::vec![sp_std::vec![1, 2, 3]];
|
||||||
let result = sequential_hash::<TestBlake2Hasher, _>(single_item);
|
let result = sequential_hash::<$hasher_type, _>(single_item);
|
||||||
let expected = TestBlake2Hasher::hash(&[1, 2, 3]);
|
let expected = <$hasher_type>::hash(&[1, 2, 3]);
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,9 +162,9 @@ mod tests {
|
|||||||
let data_2 = sp_std::vec![sp_std::vec![1], sp_std::vec![2], sp_std::vec![3]];
|
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 data_reversed = sp_std::vec![sp_std::vec![3], sp_std::vec![2], sp_std::vec![1]];
|
||||||
|
|
||||||
let hash_1 = sequential_hash::<TestBlake2Hasher, _>(data_1);
|
let hash_1 = sequential_hash::<$hasher_type, _>(data_1);
|
||||||
let hash_2 = sequential_hash::<TestBlake2Hasher, _>(data_2);
|
let hash_2 = sequential_hash::<$hasher_type, _>(data_2);
|
||||||
let hash_reversed = sequential_hash::<TestBlake2Hasher, _>(data_reversed);
|
let hash_reversed = sequential_hash::<$hasher_type, _>(data_reversed);
|
||||||
|
|
||||||
assert_eq!(hash_1, hash_2);
|
assert_eq!(hash_1, hash_2);
|
||||||
assert_ne!(hash_1, hash_reversed);
|
assert_ne!(hash_1, hash_reversed);
|
||||||
@ -213,17 +173,24 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_sequential_vs_cumulative_hash() {
|
fn test_sequential_vs_cumulative_hash() {
|
||||||
let dataset = sp_std::vec![sp_std::vec![1, 2, 3], sp_std::vec![4, 5, 6]];
|
let dataset = sp_std::vec![sp_std::vec![1, 2, 3], sp_std::vec![4, 5, 6]];
|
||||||
let seq_hash = sequential_hash::<TestBlake2Hasher, _>(dataset.clone());
|
let seq_hash = sequential_hash::<$hasher_type, _>(dataset.clone());
|
||||||
let cum_hash = cumulative_hash::<TestBlake2Hasher, _>(dataset);
|
let cum_hash = cumulative_hash::<$hasher_type, _>(dataset);
|
||||||
assert_ne!(seq_hash, cum_hash);
|
assert_ne!(seq_hash, cum_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sequential_hash_with_slices() {
|
fn test_sequential_hash_with_slices() {
|
||||||
let slice_data: &[&[u8]] = &[&[10, 20], &[30, 40]];
|
let slice_data: &[&[u8]] = &[&[10, 20], &[30, 40]];
|
||||||
let result = sequential_hash::<TestBlake2Hasher, _>(slice_data.iter());
|
let result = sequential_hash::<$hasher_type, _>(slice_data.iter());
|
||||||
assert_ne!(result, H256::zero());
|
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]
|
#[test]
|
||||||
fn test_verify_in_current_block_with_empty_ancestry() {
|
fn test_verify_in_current_block_with_empty_ancestry() {
|
||||||
@ -234,7 +201,7 @@ mod tests {
|
|||||||
trusted_bytes.reverse();
|
trusted_bytes.reverse();
|
||||||
let trusted_top_block_hash = H256::from(trusted_bytes);
|
let trusted_top_block_hash = H256::from(trusted_bytes);
|
||||||
|
|
||||||
let result = verify_hash_ancestry::<TestSha2Hasher, &[[u8; 80]]>(
|
let result = verify_hash_ancestry::<UtxoSha2Hasher, &[[u8; 80]]>(
|
||||||
&tx_header,
|
&tx_header,
|
||||||
&[],
|
&[],
|
||||||
trusted_top_block_hash,
|
trusted_top_block_hash,
|
||||||
@ -256,7 +223,7 @@ mod tests {
|
|||||||
let trusted_top_block_hash = H256::from(trusted_bytes);
|
let trusted_top_block_hash = H256::from(trusted_bytes);
|
||||||
|
|
||||||
let ancestry = [header_101];
|
let ancestry = [header_101];
|
||||||
let result = verify_hash_ancestry::<TestSha2Hasher, &[[u8; 80]]>(
|
let result = verify_hash_ancestry::<UtxoSha2Hasher, &[[u8; 80]]>(
|
||||||
&tx_header_100,
|
&tx_header_100,
|
||||||
&ancestry,
|
&ancestry,
|
||||||
trusted_top_block_hash,
|
trusted_top_block_hash,
|
||||||
@ -284,7 +251,7 @@ mod tests {
|
|||||||
let trusted_top_block_hash = H256::from(trusted_bytes);
|
let trusted_top_block_hash = H256::from(trusted_bytes);
|
||||||
|
|
||||||
let ancestry = [header_101, header_102, header_103];
|
let ancestry = [header_101, header_102, header_103];
|
||||||
let result = verify_hash_ancestry::<TestSha2Hasher, &[[u8; 80]]>(
|
let result = verify_hash_ancestry::<UtxoSha2Hasher, &[[u8; 80]]>(
|
||||||
&header_100,
|
&header_100,
|
||||||
&ancestry,
|
&ancestry,
|
||||||
trusted_top_block_hash,
|
trusted_top_block_hash,
|
||||||
@ -305,7 +272,7 @@ mod tests {
|
|||||||
let trusted_top_block_hash = H256::from(trusted_bytes);
|
let trusted_top_block_hash = H256::from(trusted_bytes);
|
||||||
|
|
||||||
let ancestry = [broken_header_101];
|
let ancestry = [broken_header_101];
|
||||||
let result = verify_hash_ancestry::<TestSha2Hasher, &[[u8; 80]]>(
|
let result = verify_hash_ancestry::<UtxoSha2Hasher, &[[u8; 80]]>(
|
||||||
&header_100,
|
&header_100,
|
||||||
&ancestry,
|
&ancestry,
|
||||||
trusted_top_block_hash,
|
trusted_top_block_hash,
|
||||||
|
|||||||
452
pallets/helpers/src/lcg.rs
Normal file
452
pallets/helpers/src/lcg.rs
Normal file
@ -0,0 +1,452 @@
|
|||||||
|
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,12 +3,14 @@
|
|||||||
use ghost_traits::hashing::GhostHasher;
|
use ghost_traits::hashing::GhostHasher;
|
||||||
use sp_core::H256;
|
use sp_core::H256;
|
||||||
use sp_io::hashing::{blake2_256, keccak_256, sha2_256};
|
use sp_io::hashing::{blake2_256, keccak_256, sha2_256};
|
||||||
|
use sp_runtime::{Perbill, traits::{Saturating, UniqueSaturatedInto}};
|
||||||
|
|
||||||
pub mod bounded_bitmap;
|
pub mod bounded_bitmap;
|
||||||
pub mod hash_chain;
|
pub mod hash_chain;
|
||||||
pub mod merkle_tree;
|
pub mod merkle_tree;
|
||||||
pub mod networks;
|
pub mod networks;
|
||||||
pub mod utxo;
|
pub mod utxo;
|
||||||
|
pub mod lcg;
|
||||||
|
|
||||||
pub type AuthIndexU8 = u8;
|
pub type AuthIndexU8 = u8;
|
||||||
pub type AuthIndexU16 = u16;
|
pub type AuthIndexU16 = u16;
|
||||||
@ -48,53 +50,101 @@ where
|
|||||||
value - f
|
value - f
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubstrateBlake2Hasher;
|
pub fn get_submission_probability<B>(
|
||||||
impl GhostHasher for SubstrateBlake2Hasher {
|
participants_count: usize,
|
||||||
type Hash = H256;
|
values_count: usize,
|
||||||
type HashBytes = [u8; 32];
|
blocks_left: B
|
||||||
fn hash(data: &[u8]) -> Self::Hash {
|
) -> Perbill
|
||||||
H256::from(blake2_256(data))
|
where
|
||||||
}
|
B: UniqueSaturatedInto<u32>,
|
||||||
fn hash_len() -> usize {
|
{
|
||||||
H256::len_bytes()
|
// y = min(1, (1/6) + (A-C)/2x)
|
||||||
}
|
let a: u32 = participants_count.unique_saturated_into();
|
||||||
fn empty() -> Self::Hash {
|
let c: u32 = values_count.unique_saturated_into();
|
||||||
H256::zero()
|
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 SubstrateKeccakHasher;
|
macro_rules! impl_ghost_hasher {
|
||||||
impl GhostHasher for SubstrateKeccakHasher {
|
(
|
||||||
type Hash = H256;
|
struct $name:ident;
|
||||||
type HashBytes = [u8; 32];
|
hash_type: $hash_type:ty;
|
||||||
fn hash(data: &[u8]) -> Self::Hash {
|
hash_bytes_len: $hash_bytes_len:expr;
|
||||||
H256::from(keccak_256(data))
|
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 {
|
fn hash_len() -> usize {
|
||||||
H256::len_bytes()
|
$hash_bytes_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty() -> Self::Hash {
|
fn empty() -> Self::Hash {
|
||||||
H256::zero()
|
<$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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UtxoSha2Hasher;
|
impl_ghost_hasher!(
|
||||||
impl GhostHasher for UtxoSha2Hasher {
|
struct SubstrateBlake2Hasher;
|
||||||
type Hash = H256;
|
hash_type: H256;
|
||||||
type HashBytes = [u8; 32];
|
hash_bytes_len: 32;
|
||||||
fn hash(data: &[u8]) -> Self::Hash {
|
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) -> {
|
||||||
let first_pass: [u8; 32] = sha2_256(data);
|
let first_pass: [u8; 32] = sha2_256(data);
|
||||||
let second_pass: [u8; 32] = sha2_256(&first_pass);
|
let second_pass: [u8; 32] = sha2_256(&first_pass);
|
||||||
|
|
||||||
H256::from(second_pass)
|
H256::from(second_pass)
|
||||||
}
|
}
|
||||||
fn hash_len() -> usize {
|
);
|
||||||
H256::len_bytes()
|
|
||||||
}
|
|
||||||
fn empty() -> Self::Hash {
|
|
||||||
H256::zero()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@ -134,4 +184,38 @@ mod tests {
|
|||||||
assert_eq!(get_byzantium_quorum_threshold(4u64), 3u64);
|
assert_eq!(get_byzantium_quorum_threshold(4u64), 3u64);
|
||||||
assert_eq!(get_byzantium_quorum_threshold(4usize), 3usize);
|
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,49 +6,57 @@ use sp_std::vec::Vec;
|
|||||||
const LEAF_PREFIX: u8 = 0;
|
const LEAF_PREFIX: u8 = 0;
|
||||||
const NODE_PREFIX: u8 = 1;
|
const NODE_PREFIX: u8 = 1;
|
||||||
|
|
||||||
|
pub enum MerkleTreeError<E> {
|
||||||
|
Generate(E),
|
||||||
|
InvalidIndex,
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
fn leaf_prefixed<H>(preimage: &[u8]) -> H::Hash
|
fn leaf_prefixed<H>(preimage: &[u8]) -> H::Hash
|
||||||
where
|
where
|
||||||
H: GhostHasher,
|
H: GhostHasher,
|
||||||
{
|
{
|
||||||
let mut prefixed_data = sp_std::vec![LEAF_PREFIX; 1 + preimage.len()];
|
let mut buffer = Vec::with_capacity(preimage.len() + 1);
|
||||||
prefixed_data[1..].copy_from_slice(preimage);
|
buffer.push(LEAF_PREFIX);
|
||||||
H::hash(&prefixed_data)
|
buffer.extend_from_slice(preimage);
|
||||||
}
|
|
||||||
|
|
||||||
fn node_prefixed<H>(preimage1: &[u8], preimage2: &[u8]) -> H::Hash
|
H::hash(&buffer)
|
||||||
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>(
|
pub fn generate_tree<H, I, S, F, E>(
|
||||||
max_index: I,
|
max_index: I,
|
||||||
|
size_hint: usize,
|
||||||
raw_values: S,
|
raw_values: S,
|
||||||
generate_preimage: F,
|
update_preimage_buffer: F,
|
||||||
) -> Result<Vec<H::Hash>, E>
|
) -> Result<Vec<H::Hash>, MerkleTreeError<E>>
|
||||||
where
|
where
|
||||||
H: GhostHasher,
|
H: GhostHasher,
|
||||||
S: IntoIterator,
|
S: IntoIterator,
|
||||||
I: AtLeast8BitUnsigned + UniqueSaturatedInto<usize>,
|
I: AtLeast8BitUnsigned + UniqueSaturatedInto<usize>,
|
||||||
F: Fn(S::Item) -> Result<(usize, Vec<u8>), E>,
|
F: Fn(S::Item, &mut Vec<u8>) -> Result<usize, E>,
|
||||||
{
|
{
|
||||||
let num_of_leaves: usize = (max_index + I::one()).unique_saturated_into();
|
let num_of_leaves: usize = (max_index + I::one()).unique_saturated_into();
|
||||||
let padded_leaves = num_of_leaves.next_power_of_two();
|
let padded_leaves = num_of_leaves.next_power_of_two();
|
||||||
let total_capacity = (2 * padded_leaves) - 1;
|
let total_capacity = (2 * padded_leaves) - 1;
|
||||||
|
|
||||||
|
if total_capacity == 0 { return Err(MerkleTreeError::Empty); }
|
||||||
|
|
||||||
let empty_hash = H::empty();
|
let empty_hash = H::empty();
|
||||||
let empty_leaf_hash = leaf_prefixed::<H>(empty_hash.as_ref());
|
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 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() {
|
for item in raw_values.into_iter() {
|
||||||
let (index, preimage) = generate_preimage(item)?;
|
buffer.clear();
|
||||||
if index >= padded_leaves { return Ok(sp_std::vec![]); }
|
buffer.push(LEAF_PREFIX);
|
||||||
merkle_tree[index] = leaf_prefixed::<H>(&preimage)
|
|
||||||
|
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 mut layer_start = 0;
|
let mut layer_start = 0;
|
||||||
@ -58,10 +66,15 @@ where
|
|||||||
while current_layer_len > 1 {
|
while current_layer_len > 1 {
|
||||||
for i in (0..current_layer_len).step_by(2) {
|
for i in (0..current_layer_len).step_by(2) {
|
||||||
let layer_index = layer_start + i;
|
let layer_index = layer_start + i;
|
||||||
let left_bytes = merkle_tree[layer_index].as_ref();
|
let left_bytes = merkle_tree[layer_index];
|
||||||
let right_bytes = merkle_tree[layer_index | 1].as_ref();
|
let right_bytes = merkle_tree[layer_index | 1];
|
||||||
|
|
||||||
merkle_tree[write_ptr] = node_prefixed::<H>(left_bytes, right_bytes);
|
let combined_hash = H::combine_hashes_prefixed(
|
||||||
|
NODE_PREFIX,
|
||||||
|
left_bytes,
|
||||||
|
right_bytes,
|
||||||
|
);
|
||||||
|
merkle_tree[write_ptr] = combined_hash;
|
||||||
write_ptr += 1;
|
write_ptr += 1;
|
||||||
}
|
}
|
||||||
layer_start += current_layer_len;
|
layer_start += current_layer_len;
|
||||||
@ -71,16 +84,16 @@ where
|
|||||||
Ok(merkle_tree)
|
Ok(merkle_tree)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_proof<H, I>(
|
pub fn generate_proof<H, I, E>(
|
||||||
merkle_tree: &[H::Hash],
|
merkle_tree: &[H::Hash],
|
||||||
max_index: I,
|
max_index: I,
|
||||||
index: I,
|
index: I,
|
||||||
) -> Vec<H::Hash>
|
) -> Result<Vec<H::Hash>, MerkleTreeError<E>>
|
||||||
where
|
where
|
||||||
H: GhostHasher,
|
H: GhostHasher,
|
||||||
I: AtLeast8BitUnsigned + UniqueSaturatedInto<usize>,
|
I: AtLeast8BitUnsigned + UniqueSaturatedInto<usize>,
|
||||||
{
|
{
|
||||||
if index > max_index { return sp_std::vec![]; }
|
if index > max_index { return Err(MerkleTreeError::InvalidIndex); }
|
||||||
|
|
||||||
let num_of_leaves: usize = (max_index + I::one()).unique_saturated_into();
|
let num_of_leaves: usize = (max_index + I::one()).unique_saturated_into();
|
||||||
let mut current_index: usize = index.unique_saturated_into();
|
let mut current_index: usize = index.unique_saturated_into();
|
||||||
@ -101,7 +114,7 @@ where
|
|||||||
current_index >>= 1;
|
current_index >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
proof
|
Ok(proof)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_tree_proof<H, I>(
|
pub fn verify_tree_proof<H, I>(
|
||||||
@ -120,14 +133,11 @@ where
|
|||||||
let mut current_hash = leaf_prefixed::<H>(preimage);
|
let mut current_hash = leaf_prefixed::<H>(preimage);
|
||||||
|
|
||||||
for sibling in merkle_proof.iter() {
|
for sibling in merkle_proof.iter() {
|
||||||
let sibling_bytes = sibling.as_ref();
|
current_hash = if current_index % 2 == 0 {
|
||||||
let hash_bytes = current_hash.as_ref();
|
H::combine_hashes_prefixed(NODE_PREFIX, current_hash, *sibling)
|
||||||
|
|
||||||
if current_index % 2 == 0 {
|
|
||||||
current_hash = node_prefixed::<H>(hash_bytes, sibling_bytes);
|
|
||||||
} else {
|
} else {
|
||||||
current_hash = node_prefixed::<H>(sibling_bytes, hash_bytes);
|
H::combine_hashes_prefixed(NODE_PREFIX, *sibling, current_hash)
|
||||||
}
|
};
|
||||||
|
|
||||||
current_index >>= 1;
|
current_index >>= 1;
|
||||||
}
|
}
|
||||||
@ -138,66 +148,64 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use sp_core::H256;
|
|
||||||
use sp_io::hashing::blake2_256;
|
|
||||||
|
|
||||||
pub struct TestBlake2Hasher;
|
use crate::{
|
||||||
impl GhostHasher for TestBlake2Hasher {
|
SubstrateBlake2Hasher, SubstrateKeccakHasher, UtxoSha2Hasher,
|
||||||
type Hash = H256;
|
};
|
||||||
type HashBytes = [u8; 32];
|
|
||||||
|
|
||||||
fn hash(data: &[u8]) -> Self::Hash {
|
macro_rules! run_merkle_tree_tests {
|
||||||
H256::from(blake2_256(data))
|
($hasher_type:ty, $mod_name:ident) => {
|
||||||
}
|
mod $mod_name {
|
||||||
fn empty() -> Self::Hash {
|
use super::*;
|
||||||
H256::zero()
|
|
||||||
}
|
|
||||||
fn hash_len() -> usize {
|
|
||||||
H256::len_bytes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_generate_tree_perfect_power_of_two() {
|
fn test_generate_tree_perfect_power_of_two() {
|
||||||
let max_index = 3u32;
|
let max_index = 3u32;
|
||||||
|
let size_hint = 69;
|
||||||
|
|
||||||
let raw_data = sp_std::vec![
|
let raw_data = sp_std::vec![
|
||||||
(0, sp_std::vec![1]),
|
(0, sp_std::vec![1; 69]),
|
||||||
(1, sp_std::vec![2]),
|
(1, sp_std::vec![2; 69]),
|
||||||
(2, sp_std::vec![3]),
|
(2, sp_std::vec![3; 69]),
|
||||||
(3, sp_std::vec![4]),
|
(3, sp_std::vec![4; 69]),
|
||||||
];
|
];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(tree.len(), 7);
|
assert_eq!(tree.len(), 7);
|
||||||
|
|
||||||
let h0 = TestBlake2Hasher::hash(&[ &[0u8], [1].as_slice() ].concat());
|
let h0 = <$hasher_type>::hash(&[ &[0u8], [1; 69].as_slice() ].concat());
|
||||||
let h1 = TestBlake2Hasher::hash(&[ &[0u8], [2].as_slice() ].concat());
|
let h1 = <$hasher_type>::hash(&[ &[0u8], [2; 69].as_slice() ].concat());
|
||||||
let h2 = TestBlake2Hasher::hash(&[ &[0u8], [3].as_slice() ].concat());
|
let h2 = <$hasher_type>::hash(&[ &[0u8], [3; 69].as_slice() ].concat());
|
||||||
let h3 = TestBlake2Hasher::hash(&[ &[0u8], [4].as_slice() ].concat());
|
let h3 = <$hasher_type>::hash(&[ &[0u8], [4; 69].as_slice() ].concat());
|
||||||
|
|
||||||
let mut c1 = [0u8; 65];
|
let mut c1 = [0u8; 65];
|
||||||
c1[0] = NODE_PREFIX;
|
c1[0] = NODE_PREFIX;
|
||||||
c1[1..33].copy_from_slice(h0.as_ref());
|
c1[1..33].copy_from_slice(h0.as_ref());
|
||||||
c1[33..].copy_from_slice(h1.as_ref());
|
c1[33..].copy_from_slice(h1.as_ref());
|
||||||
let parent_left = TestBlake2Hasher::hash(&c1);
|
let parent_left = <$hasher_type>::hash(&c1);
|
||||||
|
|
||||||
let mut c2 = [0u8; 65];
|
let mut c2 = [0u8; 65];
|
||||||
c2[0] = NODE_PREFIX;
|
c2[0] = NODE_PREFIX;
|
||||||
c2[1..33].copy_from_slice(h2.as_ref());
|
c2[1..33].copy_from_slice(h2.as_ref());
|
||||||
c2[33..].copy_from_slice(h3.as_ref());
|
c2[33..].copy_from_slice(h3.as_ref());
|
||||||
let parent_right = TestBlake2Hasher::hash(&c2);
|
let parent_right = <$hasher_type>::hash(&c2);
|
||||||
|
|
||||||
let mut c_root = [0u8; 65];
|
let mut c_root = [0u8; 65];
|
||||||
c_root[0] = NODE_PREFIX;
|
c_root[0] = NODE_PREFIX;
|
||||||
c_root[1..33].copy_from_slice(parent_left.as_ref());
|
c_root[1..33].copy_from_slice(parent_left.as_ref());
|
||||||
c_root[33..].copy_from_slice(parent_right.as_ref());
|
c_root[33..].copy_from_slice(parent_right.as_ref());
|
||||||
let expected_root = TestBlake2Hasher::hash(&c_root);
|
let expected_root = <$hasher_type>::hash(&c_root);
|
||||||
|
|
||||||
assert_eq!(tree.last().unwrap(), &expected_root);
|
assert_eq!(tree.last().unwrap(), &expected_root);
|
||||||
}
|
}
|
||||||
@ -205,36 +213,44 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_generate_tree_with_padding_hashing() {
|
fn test_generate_tree_with_padding_hashing() {
|
||||||
let max_index = 2u32;
|
let max_index = 2u32;
|
||||||
|
let size_hint = 420;
|
||||||
|
|
||||||
let raw_data = sp_std::vec![
|
let raw_data = sp_std::vec![
|
||||||
(0, sp_std::vec![1]),
|
(0, sp_std::vec![1; size_hint]),
|
||||||
(1, sp_std::vec![2]),
|
(1, sp_std::vec![2; size_hint]),
|
||||||
(2, sp_std::vec![3]),
|
(2, sp_std::vec![3; size_hint]),
|
||||||
];
|
];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut empty_data = sp_std::vec![LEAF_PREFIX];
|
let mut empty_data = sp_std::vec![LEAF_PREFIX];
|
||||||
empty_data.extend_from_slice(&H256::zero().to_fixed_bytes());
|
empty_data.extend_from_slice(&<$hasher_type>::empty().to_fixed_bytes());
|
||||||
let empty_hash = TestBlake2Hasher::hash(&empty_data);
|
let empty_hash = <$hasher_type>::hash(&empty_data);
|
||||||
|
|
||||||
assert_eq!(tree.len(), 7);
|
assert_eq!(tree.len(), 7);
|
||||||
assert_eq!(tree[3], empty_hash);
|
assert_eq!(tree[3], empty_hash);
|
||||||
|
|
||||||
let mut leaf2_data = sp_std::vec![LEAF_PREFIX];
|
let mut leaf2_data = sp_std::vec![LEAF_PREFIX];
|
||||||
leaf2_data.extend_from_slice(&[3]);
|
leaf2_data.extend_from_slice(&sp_std::vec![3; size_hint]);
|
||||||
let h2 = TestBlake2Hasher::hash(&leaf2_data);
|
let h2 = <$hasher_type>::hash(&leaf2_data);
|
||||||
|
|
||||||
let mut combined_right = [0u8; 65];
|
let mut combined_right = [0u8; 65];
|
||||||
combined_right[0] = NODE_PREFIX;
|
combined_right[0] = NODE_PREFIX;
|
||||||
combined_right[1..33].copy_from_slice(h2.as_ref());
|
combined_right[1..33].copy_from_slice(h2.as_ref());
|
||||||
combined_right[33..].copy_from_slice(empty_hash.as_ref());
|
combined_right[33..].copy_from_slice(empty_hash.as_ref());
|
||||||
|
|
||||||
let expected_parent_right = TestBlake2Hasher::hash(&combined_right);
|
let expected_parent_right = <$hasher_type>::hash(&combined_right);
|
||||||
assert_eq!(tree[5], expected_parent_right);
|
assert_eq!(tree[5], expected_parent_right);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,20 +262,43 @@ mod tests {
|
|||||||
let data_2 = sp_std::vec![(0, sp_std::vec![100]), (1, sp_std::vec![200])];
|
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 data_3 = sp_std::vec![(0, sp_std::vec![101]), (1, sp_std::vec![200])];
|
||||||
|
|
||||||
let tree_1 =
|
let tree_1 = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
generate_tree::<TestBlake2Hasher, u32, _, _, ()>(max_index, data_1, |(i, b)| {
|
max_index,
|
||||||
Ok((i, b))
|
1,
|
||||||
})
|
data_1,
|
||||||
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let tree_2 =
|
|
||||||
generate_tree::<TestBlake2Hasher, u32, _, _, ()>(max_index, data_2, |(i, b)| {
|
let tree_2 = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
Ok((i, b))
|
max_index,
|
||||||
})
|
1,
|
||||||
|
data_2,
|
||||||
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let tree_3 =
|
|
||||||
generate_tree::<TestBlake2Hasher, u32, _, _, ()>(max_index, data_3, |(i, b)| {
|
let tree_3 = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
Ok((i, b))
|
max_index,
|
||||||
})
|
1,
|
||||||
|
data_3,
|
||||||
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(tree_1.last().unwrap(), tree_2.last().unwrap());
|
assert_eq!(tree_1.last().unwrap(), tree_2.last().unwrap());
|
||||||
@ -269,96 +308,132 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_generate_tree_single_element() {
|
fn test_generate_tree_single_element() {
|
||||||
let max_index = 0u32;
|
let max_index = 0u32;
|
||||||
let raw_data = sp_std::vec![(0, sp_std::vec![42])];
|
let size_hint = 1337;
|
||||||
|
let raw_data = sp_std::vec![(0, sp_std::vec![42; size_hint])];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.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.len(), 1);
|
||||||
assert_eq!(tree[0], TestBlake2Hasher::hash(&vec![LEAF_PREFIX, 42]));
|
assert_eq!(tree[0], expected_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_proof_and_verification_end_to_end() {
|
fn test_proof_and_verification_end_to_end() {
|
||||||
let max_index = 3u32;
|
let max_index = 3u32;
|
||||||
|
let size_hint = 420;
|
||||||
|
|
||||||
let raw_data = sp_std::vec![
|
let raw_data = sp_std::vec![
|
||||||
(0, sp_std::vec![1]),
|
(0, sp_std::vec![1; size_hint]),
|
||||||
(1, sp_std::vec![2]),
|
(1, sp_std::vec![2; size_hint]),
|
||||||
(2, sp_std::vec![3]),
|
(2, sp_std::vec![3; size_hint]),
|
||||||
(3, sp_std::vec![4]),
|
(3, sp_std::vec![4; size_hint]),
|
||||||
];
|
];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let root = *tree.last().unwrap();
|
let root = *tree.last().unwrap();
|
||||||
|
|
||||||
let target_index = 2u32;
|
let target_index = 2u32;
|
||||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, target_index);
|
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, target_index)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(proof.len(), 2);
|
assert_eq!(proof.len(), 2);
|
||||||
|
|
||||||
let preimage = sp_std::vec![3];
|
let preimage = sp_std::vec![3; size_hint];
|
||||||
let is_valid =
|
assert!(verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index);
|
|
||||||
|
|
||||||
assert!(is_valid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_proof_index_out_of_bounds() {
|
fn test_proof_index_out_of_bounds() {
|
||||||
let max_index = 3u32;
|
let max_index = 3u32;
|
||||||
|
let size_hint = 420;
|
||||||
|
|
||||||
let raw_data = sp_std::vec![
|
let raw_data = sp_std::vec![
|
||||||
(0, sp_std::vec![1]),
|
(0, sp_std::vec![1; size_hint]),
|
||||||
(1, sp_std::vec![2]),
|
(1, sp_std::vec![2; size_hint]),
|
||||||
(2, sp_std::vec![3]),
|
(2, sp_std::vec![3; size_hint]),
|
||||||
(3, sp_std::vec![4]),
|
(3, sp_std::vec![4; size_hint]),
|
||||||
];
|
];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let root = *tree.last().unwrap();
|
let root = *tree.last().unwrap();
|
||||||
|
|
||||||
let target_index = 2u32;
|
let target_index = 2u32;
|
||||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, target_index);
|
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, target_index)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(proof.len(), 2);
|
assert_eq!(proof.len(), 2);
|
||||||
|
|
||||||
let preimage = sp_std::vec![3];
|
let preimage = sp_std::vec![3; size_hint];
|
||||||
let is_valid =
|
assert!(verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index + 1);
|
assert!(!verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, 4));
|
||||||
|
|
||||||
assert!(!is_valid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_proof_contains_correct_siblings() {
|
fn test_proof_contains_correct_siblings() {
|
||||||
let max_index = 3u32;
|
let max_index = 3u32;
|
||||||
|
let size_hint = 1337;
|
||||||
|
|
||||||
let raw_data = sp_std::vec![
|
let raw_data = sp_std::vec![
|
||||||
(0, sp_std::vec![10]),
|
(0, sp_std::vec![10; size_hint]),
|
||||||
(1, sp_std::vec![20]),
|
(1, sp_std::vec![20; size_hint]),
|
||||||
(2, sp_std::vec![30]),
|
(2, sp_std::vec![30; size_hint]),
|
||||||
(3, sp_std::vec![40]),
|
(3, sp_std::vec![40; size_hint]),
|
||||||
];
|
];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let h0 = tree[0];
|
let h0 = tree[0];
|
||||||
@ -369,19 +444,31 @@ mod tests {
|
|||||||
let parent_left = tree[4]; // hash(h0 + h1)
|
let parent_left = tree[4]; // hash(h0 + h1)
|
||||||
let parent_right = tree[5]; // hash(h2 + h3)
|
let parent_right = tree[5]; // hash(h2 + h3)
|
||||||
|
|
||||||
let proof_for_0 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 0);
|
let proof_for_0 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 0)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(proof_for_0[0], h1);
|
assert_eq!(proof_for_0[0], h1);
|
||||||
assert_eq!(proof_for_0[1], parent_right);
|
assert_eq!(proof_for_0[1], parent_right);
|
||||||
|
|
||||||
let proof_for_1 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 1);
|
let proof_for_1 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 1)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(proof_for_1[0], h0);
|
assert_eq!(proof_for_1[0], h0);
|
||||||
assert_eq!(proof_for_1[1], parent_right);
|
assert_eq!(proof_for_1[1], parent_right);
|
||||||
|
|
||||||
let proof_for_2 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 2);
|
let proof_for_2 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 2)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(proof_for_2[0], h3);
|
assert_eq!(proof_for_2[0], h3);
|
||||||
assert_eq!(proof_for_2[1], parent_left);
|
assert_eq!(proof_for_2[1], parent_left);
|
||||||
|
|
||||||
let proof_for_3 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 3);
|
let proof_for_3 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 3)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(proof_for_3[0], h2);
|
assert_eq!(proof_for_3[0], h2);
|
||||||
assert_eq!(proof_for_3[1], parent_left);
|
assert_eq!(proof_for_3[1], parent_left);
|
||||||
}
|
}
|
||||||
@ -389,30 +476,38 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_proof_for_padded_tree_leaf() {
|
fn test_proof_for_padded_tree_leaf() {
|
||||||
let max_index = 2u32;
|
let max_index = 2u32;
|
||||||
|
let size_hint = 69;
|
||||||
|
|
||||||
let raw_data = sp_std::vec![
|
let raw_data = sp_std::vec![
|
||||||
(0, sp_std::vec![1]),
|
(0, sp_std::vec![1; size_hint]),
|
||||||
(1, sp_std::vec![2]),
|
(1, sp_std::vec![2; size_hint]),
|
||||||
(2, sp_std::vec![3]),
|
(2, sp_std::vec![3; size_hint]),
|
||||||
];
|
];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 2);
|
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 2)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut empty_data = sp_std::vec![LEAF_PREFIX];
|
let mut empty_data = sp_std::vec![LEAF_PREFIX];
|
||||||
empty_data.extend_from_slice(&H256::zero().to_fixed_bytes());
|
empty_data.extend_from_slice(&<$hasher_type>::empty().to_fixed_bytes());
|
||||||
let empty_hash = TestBlake2Hasher::hash(&empty_data);
|
let empty_hash = <$hasher_type>::hash(&empty_data);
|
||||||
assert_eq!(proof[0], empty_hash);
|
assert_eq!(proof[0], empty_hash);
|
||||||
|
|
||||||
let root = *tree.last().unwrap();
|
let root = *tree.last().unwrap();
|
||||||
let is_valid =
|
assert!(verify_tree_proof::<$hasher_type, u32>(&sp_std::vec![3; size_hint], &proof, root, 2));
|
||||||
verify_tree_proof::<TestBlake2Hasher, u32>(&sp_std::vec![3], &proof, root, 2);
|
|
||||||
assert!(is_valid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -420,24 +515,39 @@ mod tests {
|
|||||||
let max_index = 0u32;
|
let max_index = 0u32;
|
||||||
let raw_data = sp_std::vec![(0, sp_std::vec![99])];
|
let raw_data = sp_std::vec![(0, sp_std::vec![99])];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
1,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let proof = generate_proof::<$hasher_type, u32, ()>(
|
||||||
|
&tree,
|
||||||
|
max_index,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 0);
|
|
||||||
assert!(proof.is_empty());
|
assert!(proof.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_verify_tree_proof_with_h0_h3_and_random_values() {
|
fn test_verify_tree_proof_with_h0_h3_and_random_values() {
|
||||||
let max_index = 3u32;
|
let max_index = 3u32;
|
||||||
let leaf_0 = sp_std::vec![10u8];
|
let size_hint = 69;
|
||||||
let leaf_1 = sp_std::vec![20u8];
|
|
||||||
let leaf_2 = sp_std::vec![30u8];
|
let leaf_0 = sp_std::vec![10u8; 69];
|
||||||
let leaf_3 = sp_std::vec![40u8];
|
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 raw_data = sp_std::vec![
|
let raw_data = sp_std::vec![
|
||||||
(0, leaf_0.clone()),
|
(0, leaf_0.clone()),
|
||||||
@ -446,11 +556,17 @@ mod tests {
|
|||||||
(3, leaf_3.clone())
|
(3, leaf_3.clone())
|
||||||
];
|
];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let root = *tree.last().unwrap();
|
let root = *tree.last().unwrap();
|
||||||
@ -460,45 +576,35 @@ mod tests {
|
|||||||
let h2 = tree[2];
|
let h2 = tree[2];
|
||||||
let h3 = tree[3];
|
let h3 = tree[3];
|
||||||
|
|
||||||
let proof_for_1 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 1);
|
let proof_for_1 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 1).ok().unwrap();
|
||||||
assert_eq!(proof_for_1[0], h0);
|
assert_eq!(proof_for_1[0], h0);
|
||||||
|
|
||||||
let is_valid_1 = verify_tree_proof::<TestBlake2Hasher, u32>(&leaf_1, &proof_for_1, root, 1);
|
let is_valid_1 = verify_tree_proof::<$hasher_type, u32>(&leaf_1, &proof_for_1, root, 1);
|
||||||
assert!(is_valid_1);
|
assert!(is_valid_1);
|
||||||
|
|
||||||
let proof_for_2 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 2);
|
let proof_for_2 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 2).ok().unwrap();
|
||||||
assert_eq!(proof_for_2[0], h3);
|
assert_eq!(proof_for_2[0], h3);
|
||||||
|
|
||||||
let is_valid_2 = verify_tree_proof::<TestBlake2Hasher, u32>(&leaf_2, &proof_for_2, root, 2);
|
let is_valid_2 = verify_tree_proof::<$hasher_type, u32>(&leaf_2, &proof_for_2, root, 2);
|
||||||
assert!(is_valid_2);
|
assert!(is_valid_2);
|
||||||
|
|
||||||
let proof_for_0 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 0);
|
let proof_for_0 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 0).ok().unwrap();
|
||||||
assert_eq!(proof_for_0[0], h1);
|
assert_eq!(proof_for_0[0], h1);
|
||||||
assert!(verify_tree_proof::<TestBlake2Hasher, u32>(
|
assert!(verify_tree_proof::<$hasher_type, u32>(&leaf_0, &proof_for_0, root, 0));
|
||||||
&leaf_0,
|
|
||||||
&proof_for_0,
|
|
||||||
root,
|
|
||||||
0
|
|
||||||
));
|
|
||||||
|
|
||||||
let proof_for_3 = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 3);
|
let proof_for_3 = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, 3).ok().unwrap();
|
||||||
assert_eq!(proof_for_3[0], h2);
|
assert_eq!(proof_for_3[0], h2);
|
||||||
assert!(verify_tree_proof::<TestBlake2Hasher, u32>(
|
assert!(verify_tree_proof::<$hasher_type, u32>(&leaf_3, &proof_for_3, root, 3));
|
||||||
&leaf_3,
|
|
||||||
&proof_for_3,
|
|
||||||
root,
|
|
||||||
3
|
|
||||||
));
|
|
||||||
|
|
||||||
let mut bad_proof = proof_for_1.clone();
|
let mut bad_proof = proof_for_1.clone();
|
||||||
bad_proof[0] = H256::random();
|
bad_proof[0] = <$hasher_type>::empty();
|
||||||
let is_valid_bad_proof =
|
let is_valid_bad_proof =
|
||||||
verify_tree_proof::<TestBlake2Hasher, u32>(&leaf_1, &bad_proof, root, 1);
|
verify_tree_proof::<$hasher_type, u32>(&leaf_1, &bad_proof, root, 1);
|
||||||
assert!(!is_valid_bad_proof);
|
assert!(!is_valid_bad_proof);
|
||||||
|
|
||||||
let bad_preimage = vec![99u8];
|
let bad_preimage = vec![99u8];
|
||||||
let is_valid_bad_preimage =
|
let is_valid_bad_preimage =
|
||||||
verify_tree_proof::<TestBlake2Hasher, u32>(&bad_preimage, &proof_for_1, root, 1);
|
verify_tree_proof::<$hasher_type, u32>(&bad_preimage, &proof_for_1, root, 1);
|
||||||
assert!(!is_valid_bad_preimage);
|
assert!(!is_valid_bad_preimage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,11 +617,17 @@ mod tests {
|
|||||||
raw_data.push((i, sp_std::vec![i as u8]));
|
raw_data.push((i, sp_std::vec![i as u8]));
|
||||||
}
|
}
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
1,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let root = *tree.last().unwrap();
|
let root = *tree.last().unwrap();
|
||||||
@ -525,50 +637,55 @@ mod tests {
|
|||||||
let target_index = 11u32;
|
let target_index = 11u32;
|
||||||
let preimage = vec![target_index as u8];
|
let preimage = vec![target_index as u8];
|
||||||
|
|
||||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, target_index);
|
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, target_index)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(proof.len(), 4);
|
assert_eq!(proof.len(), 4);
|
||||||
|
|
||||||
let h10 = tree[10];
|
let h10 = tree[10];
|
||||||
assert_eq!(proof[0], h10);
|
assert_eq!(proof[0], h10);
|
||||||
|
|
||||||
let is_valid =
|
assert!(verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index);
|
assert!(!verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, 4));
|
||||||
assert!(is_valid);
|
|
||||||
|
|
||||||
let is_valid_wrong_index =
|
|
||||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, 4);
|
|
||||||
assert!(!is_valid_wrong_index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_verification_index_at_upper_bound() {
|
fn test_verification_index_at_upper_bound() {
|
||||||
let max_index = 3u32;
|
let max_index = 3u32;
|
||||||
|
let size_hint = 420;
|
||||||
|
|
||||||
let raw_data = sp_std::vec![
|
let raw_data = sp_std::vec![
|
||||||
(0, sp_std::vec![1]),
|
(0, sp_std::vec![1; size_hint]),
|
||||||
(1, sp_std::vec![2]),
|
(1, sp_std::vec![2; size_hint]),
|
||||||
(2, sp_std::vec![3]),
|
(2, sp_std::vec![3; size_hint]),
|
||||||
(3, sp_std::vec![4]),
|
(3, sp_std::vec![4; size_hint]),
|
||||||
];
|
];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
size_hint,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let root = *tree.last().unwrap();
|
let root = *tree.last().unwrap();
|
||||||
|
|
||||||
let target_index = 3u32;
|
let target_index = 3u32;
|
||||||
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, target_index);
|
let proof = generate_proof::<$hasher_type, u32, ()>(&tree, max_index, target_index)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(proof.len(), 2);
|
assert_eq!(proof.len(), 2);
|
||||||
|
|
||||||
let preimage = sp_std::vec![4];
|
let preimage = sp_std::vec![4; size_hint];
|
||||||
let is_valid =
|
assert!(verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index);
|
|
||||||
|
|
||||||
assert!(is_valid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -581,23 +698,32 @@ mod tests {
|
|||||||
(3, sp_std::vec![4]),
|
(3, sp_std::vec![4]),
|
||||||
];
|
];
|
||||||
|
|
||||||
let tree = generate_tree::<TestBlake2Hasher, u32, _, _, ()>(
|
let tree = generate_tree::<$hasher_type, u32, _, _, ()>(
|
||||||
max_index,
|
max_index,
|
||||||
|
1,
|
||||||
raw_data,
|
raw_data,
|
||||||
|(index, bytes)| Ok((index, bytes)),
|
|
||||||
|
|(index, bytes), buffer| {
|
||||||
|
buffer.extend_from_slice(&bytes);
|
||||||
|
Ok(index as usize)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let root = *tree.last().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 target_index = 4u32;
|
||||||
let preimage = sp_std::vec![4];
|
let preimage = sp_std::vec![4];
|
||||||
|
|
||||||
let is_valid =
|
assert!(!verify_tree_proof::<$hasher_type, u32>(&preimage, &proof, root, target_index));
|
||||||
verify_tree_proof::<TestBlake2Hasher, u32>(&preimage, &proof, root, target_index);
|
|
||||||
|
|
||||||
assert!(!is_valid);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ use sp_std::vec::Vec;
|
|||||||
|
|
||||||
const MAX_INPUTS: usize = 3;
|
const MAX_INPUTS: usize = 3;
|
||||||
const MAX_OUTPUTS: usize = 4;
|
const MAX_OUTPUTS: usize = 4;
|
||||||
|
const MAX_FLAGS_LEN: usize = 8;
|
||||||
|
const MAX_HASHES_LEN: usize = 16;
|
||||||
const MAX_SCRIPT_LEN: usize = 512;
|
const MAX_SCRIPT_LEN: usize = 512;
|
||||||
pub const MAX_TX_LEN: usize = 4096;
|
pub const MAX_TX_LEN: usize = 4096;
|
||||||
|
|
||||||
@ -27,20 +29,17 @@ pub struct Transaction<H: GhostHasher> {
|
|||||||
lock_time: u32,
|
lock_time: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Header<H: GhostHasher> {
|
pub struct Header<H: GhostHasher>(sp_std::marker::PhantomData<H>);
|
||||||
pub merkle_root: H::Hash,
|
|
||||||
pub tx_count: u32,
|
|
||||||
pub tree_hashes: Vec<H::Hash>,
|
|
||||||
pub flags: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: GhostHasher> Header<H> {
|
impl<H: GhostHasher> Header<H> {
|
||||||
fn calc_tree_width(&self, h: u32) -> u32 {
|
fn calc_tree_width(tx_count: u32, h: u32) -> u32 {
|
||||||
(self.tx_count + (1 << h) - 1) >> h
|
(tx_count + (1 << h) - 1) >> h
|
||||||
}
|
}
|
||||||
|
|
||||||
fn traverse(
|
fn traverse(
|
||||||
&self,
|
tx_count: u32,
|
||||||
|
flags: &[u8],
|
||||||
|
tree_hashes: &[H::Hash],
|
||||||
height: u32,
|
height: u32,
|
||||||
pos: u32,
|
pos: u32,
|
||||||
bits_used: &mut u32,
|
bits_used: &mut u32,
|
||||||
@ -51,19 +50,19 @@ impl<H: GhostHasher> Header<H> {
|
|||||||
let byte_idx = (*bits_used / 8) as usize;
|
let byte_idx = (*bits_used / 8) as usize;
|
||||||
let bit_idx = (*bits_used % 8) as u8;
|
let bit_idx = (*bits_used % 8) as u8;
|
||||||
|
|
||||||
if byte_idx >= self.flags.len() {
|
if byte_idx >= flags.len() {
|
||||||
return Err(ParseError::InvalidVarint(VarintError::BufferTooShort));
|
return Err(ParseError::InvalidVarint(VarintError::BufferTooShort));
|
||||||
}
|
}
|
||||||
|
|
||||||
let parent_of_match = ((self.flags[byte_idx] >> bit_idx) & 1) == 1;
|
let parent_of_match = ((flags[byte_idx] >> bit_idx) & 1) == 1;
|
||||||
*bits_used += 1;
|
*bits_used += 1;
|
||||||
|
|
||||||
if height == 0 || !parent_of_match {
|
if height == 0 || !parent_of_match {
|
||||||
if *hash_used as usize >= self.tree_hashes.len() {
|
if *hash_used as usize >= tree_hashes.len() {
|
||||||
return Err(ParseError::InvalidLength);
|
return Err(ParseError::InvalidLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
let curr_hash = self.tree_hashes[*hash_used as usize];
|
let curr_hash = tree_hashes[*hash_used as usize];
|
||||||
*hash_used += 1;
|
*hash_used += 1;
|
||||||
|
|
||||||
if height == 0 && parent_of_match && curr_hash == target_txid {
|
if height == 0 && parent_of_match && curr_hash == target_txid {
|
||||||
@ -73,7 +72,10 @@ impl<H: GhostHasher> Header<H> {
|
|||||||
return Ok(curr_hash);
|
return Ok(curr_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
let left = self.traverse(
|
let left = Self::traverse(
|
||||||
|
tx_count,
|
||||||
|
flags,
|
||||||
|
tree_hashes,
|
||||||
height - 1,
|
height - 1,
|
||||||
pos * 2,
|
pos * 2,
|
||||||
bits_used,
|
bits_used,
|
||||||
@ -82,8 +84,11 @@ impl<H: GhostHasher> Header<H> {
|
|||||||
target_txid,
|
target_txid,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let right = if pos * 2 + 1 < self.calc_tree_width(height - 1) {
|
let right = if pos * 2 + 1 < Self::calc_tree_width(tx_count, height - 1) {
|
||||||
let right = self.traverse(
|
let right = Self::traverse(
|
||||||
|
tx_count,
|
||||||
|
flags,
|
||||||
|
tree_hashes,
|
||||||
height - 1,
|
height - 1,
|
||||||
pos * 2 + 1,
|
pos * 2 + 1,
|
||||||
bits_used,
|
bits_used,
|
||||||
@ -109,17 +114,83 @@ impl<H: GhostHasher> Header<H> {
|
|||||||
Ok(current_node_hash)
|
Ok(current_node_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_proof(&self, target_txid: H::Hash) -> Result<H::Hash, ParseError> {
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
let mut bits_used = 0u32;
|
let mut bits_used = 0u32;
|
||||||
let mut hash_used = 0u32;
|
let mut hash_used = 0u32;
|
||||||
|
|
||||||
let mut matched_index = None;
|
let mut matched_index = None;
|
||||||
let mut max_height = 0;
|
let mut max_height = 0;
|
||||||
while (1 << max_height) < self.tx_count {
|
|
||||||
|
while (1 << max_height) < tx_count {
|
||||||
max_height += 1;
|
max_height += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let computed_root = self.traverse(
|
let computed_root = Self::traverse(
|
||||||
|
tx_count,
|
||||||
|
&flags,
|
||||||
|
&tree_hashes,
|
||||||
max_height,
|
max_height,
|
||||||
0,
|
0,
|
||||||
&mut bits_used,
|
&mut bits_used,
|
||||||
@ -128,19 +199,23 @@ impl<H: GhostHasher> Header<H> {
|
|||||||
target_txid,
|
target_txid,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if hash_used as usize != self.tree_hashes.len() {
|
if hash_used as usize != tree_hashes.len() {
|
||||||
return Err(ParseError::InvalidLength);
|
return Err(ParseError::InvalidLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bits_used + 7) / 8 != self.flags.len() as u32 {
|
if (bits_used + 7) / 8 != flags.len() as u32 {
|
||||||
return Err(ParseError::InvalidLength);
|
return Err(ParseError::InvalidLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
if matched_index.is_some() {
|
if matched_index.is_none() {
|
||||||
Ok(computed_root)
|
return Err(ParseError::TransactionNotFoundInProof);
|
||||||
} else {
|
|
||||||
Err(ParseError::TransactionNotFoundInProof)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if computed_root != H::from_slice(&merkle_root) {
|
||||||
|
return Err(ParseError::InvalidMerkleRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,6 +432,9 @@ fn read_varint(bytes: &mut &[u8]) -> Result<usize, VarintError> {
|
|||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| VarintError::TypeConversionFailed)?,
|
.map_err(|_| VarintError::TypeConversionFailed)?,
|
||||||
);
|
);
|
||||||
|
if val < 0xfd {
|
||||||
|
return Err(VarintError::TypeConversionFailed);
|
||||||
|
}
|
||||||
*bytes = &bytes[2..];
|
*bytes = &bytes[2..];
|
||||||
Ok(val as usize)
|
Ok(val as usize)
|
||||||
}
|
}
|
||||||
@ -369,6 +447,9 @@ fn read_varint(bytes: &mut &[u8]) -> Result<usize, VarintError> {
|
|||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| VarintError::TypeConversionFailed)?,
|
.map_err(|_| VarintError::TypeConversionFailed)?,
|
||||||
);
|
);
|
||||||
|
if val < 0x10000 {
|
||||||
|
return Err(VarintError::TypeConversionFailed);
|
||||||
|
}
|
||||||
*bytes = &bytes[4..];
|
*bytes = &bytes[4..];
|
||||||
Ok(val as usize)
|
Ok(val as usize)
|
||||||
}
|
}
|
||||||
@ -381,6 +462,9 @@ fn read_varint(bytes: &mut &[u8]) -> Result<usize, VarintError> {
|
|||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| VarintError::TypeConversionFailed)?,
|
.map_err(|_| VarintError::TypeConversionFailed)?,
|
||||||
);
|
);
|
||||||
|
if val < 0x100000000 {
|
||||||
|
return Err(VarintError::TypeConversionFailed);
|
||||||
|
}
|
||||||
*bytes = &bytes[8..];
|
*bytes = &bytes[8..];
|
||||||
Ok(val as usize)
|
Ok(val as usize)
|
||||||
}
|
}
|
||||||
@ -392,6 +476,7 @@ fn read_varint(bytes: &mut &[u8]) -> Result<usize, VarintError> {
|
|||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
InvalidLength,
|
InvalidLength,
|
||||||
ExceededMaxLimits,
|
ExceededMaxLimits,
|
||||||
|
InvalidMerkleRoot,
|
||||||
TypeConversionFailed,
|
TypeConversionFailed,
|
||||||
TransactionNotFoundInProof,
|
TransactionNotFoundInProof,
|
||||||
InvalidVarint(VarintError),
|
InvalidVarint(VarintError),
|
||||||
@ -525,60 +610,3 @@ 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]
|
[package]
|
||||||
name = "ghost-networks"
|
name = "ghost-networks"
|
||||||
version = "0.2.10"
|
version = "0.2.12"
|
||||||
description = "Registry and lifecycle management for external network metadata and cryptographic profiles."
|
description = "Registry and lifecycle management for external network metadata and cryptographic profiles."
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|||||||
@ -197,17 +197,21 @@ pub mod module {
|
|||||||
StorageValue<_, BoundedVec<T::NetworkId, T::MaxNetworks>, ValueQuery>;
|
StorageValue<_, BoundedVec<T::NetworkId, T::MaxNetworks>, ValueQuery>;
|
||||||
|
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
#[pallet::getter(fn network_curves)]
|
#[pallet::getter(fn network_types)]
|
||||||
pub type NetworkCurves<T: Config> = StorageMap<
|
pub type NetworkTypes<T: Config> = StorageMap<
|
||||||
_,
|
_,
|
||||||
Twox64Concat, NetworkCurve,
|
Twox64Concat, NetworkCurve,
|
||||||
BoundedBTreeMap<NetworkType, u32, T::MaxNetworks>,
|
BoundedBTreeMap<
|
||||||
|
NetworkType,
|
||||||
|
BoundedVec<T::NetworkId, T::MaxNetworks>,
|
||||||
|
T::MaxNetworks,
|
||||||
|
>,
|
||||||
ValueQuery,
|
ValueQuery,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
#[pallet::getter(fn network_curves_vec)]
|
#[pallet::getter(fn network_curves)]
|
||||||
pub type NetworkCurvesVec<T: Config> =
|
pub type NetworkCurves<T: Config> =
|
||||||
StorageValue<_, BoundedVec<NetworkCurve, T::MaxNetworks>, ValueQuery>;
|
StorageValue<_, BoundedVec<NetworkCurve, T::MaxNetworks>, ValueQuery>;
|
||||||
|
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
@ -429,24 +433,26 @@ impl<T: Config> Pallet<T> {
|
|||||||
modified_indexes.try_push(chain_id.clone())
|
modified_indexes.try_push(chain_id.clone())
|
||||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||||
|
|
||||||
let mut modified_curves_map = NetworkCurves::<T>::get(network_curve);
|
let mut modified_types = NetworkTypes::<T>::get(network_curve);
|
||||||
if let Some(counter) = modified_curves_map.get_mut(&network_type) {
|
if let Some(chain_ids) = modified_types.get_mut(&network_type) {
|
||||||
*counter = counter.saturating_add(1);
|
chain_ids.try_push(chain_id).map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||||
} else {
|
} else {
|
||||||
modified_curves_map.try_insert(network_type, 1u32)
|
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)?;
|
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut modified_curves_vec = NetworkCurvesVec::<T>::get();
|
let mut modified_curves = NetworkCurves::<T>::get();
|
||||||
if !modified_curves_vec.contains(&network_curve) {
|
if !modified_curves.contains(&network_curve) {
|
||||||
modified_curves_vec.try_push(network_curve)
|
modified_curves.try_push(network_curve)
|
||||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Networks::<T>::insert(&chain_id, network);
|
Networks::<T>::insert(&chain_id, network);
|
||||||
NetworkIndexes::<T>::put(modified_indexes);
|
NetworkIndexes::<T>::put(modified_indexes);
|
||||||
NetworkCurves::<T>::insert(network_curve, modified_curves_map);
|
NetworkTypes::<T>::insert(network_curve, modified_types);
|
||||||
NetworkCurvesVec::<T>::put(modified_curves_vec);
|
NetworkCurves::<T>::put(modified_curves);
|
||||||
|
|
||||||
Self::deposit_event(Event::<T>::NetworkRegistered { chain_id });
|
Self::deposit_event(Event::<T>::NetworkRegistered { chain_id });
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -460,38 +466,38 @@ impl<T: Config> Pallet<T> {
|
|||||||
let network_curve = network.curve;
|
let network_curve = network.curve;
|
||||||
let network_type = network.r#type;
|
let network_type = network.r#type;
|
||||||
|
|
||||||
let mut modified_curves_map = NetworkCurves::<T>::get(network_curve);
|
let mut modified_types = NetworkTypes::<T>::get(network_curve);
|
||||||
|
|
||||||
let counter = modified_curves_map
|
let chain_ids = modified_types
|
||||||
.get_mut(&network_type)
|
.get_mut(&network_type)
|
||||||
.ok_or(Error::<T>::NetworkTypeDoesNotExist)?;
|
.ok_or(Error::<T>::NetworkTypeDoesNotExist)?;
|
||||||
|
|
||||||
*counter = counter.saturating_sub(1);
|
chain_ids.retain(|id| id != &chain_id);
|
||||||
|
|
||||||
let mut should_remove_curve_from_vec = false;
|
let mut should_remove_curve = false;
|
||||||
if *counter == 0 {
|
if chain_ids.is_empty() {
|
||||||
modified_curves_map.remove(&network_type);
|
modified_types.remove(&network_type);
|
||||||
if modified_curves_map.is_empty() {
|
if modified_types.is_empty() {
|
||||||
should_remove_curve_from_vec = true;
|
should_remove_curve = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut modified_indexes = NetworkIndexes::<T>::get();
|
let mut modified_indexes = NetworkIndexes::<T>::get();
|
||||||
modified_indexes.retain(|id| id != &chain_id);
|
modified_indexes.retain(|id| id != &chain_id);
|
||||||
|
|
||||||
let mut modified_curves_vec = NetworkCurvesVec::<T>::get();
|
let mut modified_curves = NetworkCurves::<T>::get();
|
||||||
if should_remove_curve_from_vec {
|
if should_remove_curve {
|
||||||
modified_curves_vec.retain(|curve| curve != &network_curve);
|
modified_curves.retain(|curve| curve != &network_curve);
|
||||||
}
|
}
|
||||||
|
|
||||||
Networks::<T>::remove(&chain_id);
|
Networks::<T>::remove(&chain_id);
|
||||||
NetworkIndexes::<T>::put(modified_indexes);
|
NetworkIndexes::<T>::put(modified_indexes);
|
||||||
NetworkCurvesVec::<T>::put(modified_curves_vec);
|
NetworkCurves::<T>::put(modified_curves);
|
||||||
|
|
||||||
if modified_curves_map.is_empty() {
|
if modified_types.is_empty() {
|
||||||
NetworkCurves::<T>::remove(network_curve);
|
NetworkTypes::<T>::remove(network_curve);
|
||||||
} else {
|
} else {
|
||||||
NetworkCurves::<T>::insert(network_curve, modified_curves_map);
|
NetworkTypes::<T>::insert(network_curve, modified_types);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::deposit_event(Event::<T>::NetworkRemoved { chain_id });
|
Self::deposit_event(Event::<T>::NetworkRemoved { chain_id });
|
||||||
@ -625,15 +631,46 @@ impl<T: Config> Pallet<T> {
|
|||||||
chain_id: T::NetworkId,
|
chain_id: T::NetworkId,
|
||||||
network_type: NetworkType,
|
network_type: NetworkType,
|
||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
|
let mut network = Networks::<T>::get(&chain_id)
|
||||||
let network = maybe_network.as_mut().ok_or(Error::<T>::NetworkDoesNotExist)?;
|
.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)?;
|
||||||
|
}
|
||||||
|
|
||||||
network.r#type = network_type;
|
network.r#type = network_type;
|
||||||
Ok(())
|
|
||||||
})?;
|
Networks::<T>::insert(&chain_id, network);
|
||||||
|
NetworkTypes::<T>::insert(network_curve, modified_types);
|
||||||
|
|
||||||
Self::deposit_event(Event::<T>::NetworkTypeUpdated {
|
Self::deposit_event(Event::<T>::NetworkTypeUpdated {
|
||||||
chain_id,
|
chain_id,
|
||||||
network_type,
|
network_type,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,50 +689,53 @@ impl<T: Config> Pallet<T> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut modified_prev_map = NetworkCurves::<T>::get(prev_curve);
|
let mut modified_prev_types = NetworkTypes::<T>::get(prev_curve);
|
||||||
let counter = modified_prev_map
|
let prev_chain_ids = modified_prev_types
|
||||||
.get_mut(&network_type)
|
.get_mut(&network_type)
|
||||||
.ok_or(Error::<T>::NetworkTypeDoesNotExist)?;
|
.ok_or(Error::<T>::NetworkTypeDoesNotExist)?;
|
||||||
|
|
||||||
*counter = counter.saturating_sub(1);
|
prev_chain_ids.retain(|id| id != &chain_id);
|
||||||
|
|
||||||
let mut should_remove_prev_from_vec = false;
|
let mut should_remove_prev_curve = false;
|
||||||
if *counter == 0 {
|
if prev_chain_ids.is_empty() {
|
||||||
modified_prev_map.remove(&network_type);
|
modified_prev_types.remove(&network_type);
|
||||||
if modified_prev_map.is_empty() {
|
if modified_prev_types.is_empty() {
|
||||||
should_remove_prev_from_vec = true;
|
should_remove_prev_curve = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut modified_curr_map = NetworkCurves::<T>::get(network_curve);
|
let mut modified_curr_types = NetworkTypes::<T>::get(network_curve);
|
||||||
if let Some(counter) = modified_curr_map.get_mut(&network_type) {
|
if let Some(chain_ids) = modified_curr_types.get_mut(&network_type) {
|
||||||
*counter = counter.saturating_add(1);
|
chain_ids.try_push(chain_id)
|
||||||
|
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||||
} else {
|
} else {
|
||||||
modified_curr_map.try_insert(network_type, 1u32)
|
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)
|
||||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut modified_curves_vec = NetworkCurvesVec::<T>::get();
|
let mut modified_curves = NetworkCurves::<T>::get();
|
||||||
|
|
||||||
if should_remove_prev_from_vec {
|
if should_remove_prev_curve {
|
||||||
modified_curves_vec.retain(|curve| curve != &prev_curve);
|
modified_curves.retain(|curve| curve != &prev_curve);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !modified_curves_vec.contains(&network_curve) {
|
if !modified_curves.contains(&network_curve) {
|
||||||
modified_curves_vec.try_push(network_curve)
|
modified_curves.try_push(network_curve)
|
||||||
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
.map_err(|_| Error::<T>::TooManyNetworks)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
network.curve = network_curve;
|
network.curve = network_curve;
|
||||||
|
|
||||||
Networks::<T>::insert(&chain_id, network);
|
Networks::<T>::insert(&chain_id, network);
|
||||||
NetworkCurves::<T>::insert(network_curve, modified_curr_map);
|
NetworkTypes::<T>::insert(network_curve, modified_curr_types);
|
||||||
NetworkCurvesVec::<T>::put(modified_curves_vec);
|
NetworkCurves::<T>::put(modified_curves);
|
||||||
|
|
||||||
if modified_prev_map.is_empty() {
|
if modified_prev_types.is_empty() {
|
||||||
NetworkCurves::<T>::remove(prev_curve);
|
NetworkTypes::<T>::remove(prev_curve);
|
||||||
} else {
|
} else {
|
||||||
NetworkCurves::<T>::insert(prev_curve, modified_prev_map);
|
NetworkTypes::<T>::insert(prev_curve, modified_prev_types);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::deposit_event(Event::<T>::NetworkCurveUpdated {
|
Self::deposit_event(Event::<T>::NetworkCurveUpdated {
|
||||||
@ -761,9 +801,12 @@ impl<T: Config> NetworkDataBasicHandler for Pallet<T> {
|
|||||||
type NetworkId = T::NetworkId;
|
type NetworkId = T::NetworkId;
|
||||||
type NetworkType = NetworkType;
|
type NetworkType = NetworkType;
|
||||||
type NetworkCurve = NetworkCurve;
|
type NetworkCurve = NetworkCurve;
|
||||||
|
type MaxNetworks = T::MaxNetworks;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
||||||
|
type TypesItem = BoundedVec<T::NetworkId, T::MaxNetworks>;
|
||||||
|
|
||||||
fn count() -> u32 {
|
fn count() -> u32 {
|
||||||
NetworkIndexes::<T>::decode_len()
|
NetworkIndexes::<T>::decode_len()
|
||||||
.map(|len| len as u32)
|
.map(|len| len as u32)
|
||||||
@ -775,7 +818,7 @@ impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn curve_exists(curve: &Self::NetworkCurve) -> bool {
|
fn curve_exists(curve: &Self::NetworkCurve) -> bool {
|
||||||
NetworkCurves::<T>::contains_key(curve)
|
NetworkTypes::<T>::contains_key(curve)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(n: &Self::NetworkId) -> Option<NetworkData> {
|
fn get(n: &Self::NetworkId) -> Option<NetworkData> {
|
||||||
@ -804,15 +847,17 @@ impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn iter_curves() -> impl Iterator<Item = Self::NetworkCurve> {
|
fn iter_curves() -> impl Iterator<Item = Self::NetworkCurve> {
|
||||||
NetworkCurvesVec::<T>::get().into_iter()
|
NetworkCurves::<T>::get().into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_types_by_curve(
|
fn iter_types_by_curve(
|
||||||
curve: &Self::NetworkCurve
|
curve: &Self::NetworkCurve
|
||||||
) -> impl Iterator<Item = Self::NetworkType> {
|
) -> impl Iterator<Item = (Self::NetworkType, Self::TypesItem)> {
|
||||||
NetworkCurves::<T>::get(curve)
|
let network_types = NetworkTypes::<T>::get(curve);
|
||||||
.into_iter()
|
|
||||||
.map(|(network_type, _)| network_type)
|
network_types.into_iter().map(|(network_type, network_ids)| {
|
||||||
|
(network_type, network_ids)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -833,23 +878,25 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
|
|||||||
.map(|network| network.incoming_share)
|
.map(|network| network.incoming_share)
|
||||||
.ok_or(())?;
|
.ok_or(())?;
|
||||||
|
|
||||||
GatekeeperAmounts::<T>::try_mutate(network_id, |gatekeeper_amount| -> Result<(), ()> {
|
let increased_gatekeeper_amount = GatekeeperAmounts::<T>::get(network_id)
|
||||||
*gatekeeper_amount = gatekeeper_amount.checked_add(&amount).ok_or(())?;
|
.checked_add(&amount)
|
||||||
Ok(())
|
.ok_or(())?;
|
||||||
})?;
|
|
||||||
|
|
||||||
let curve_share = Perbill::from_parts(incoming_share).mul_ceil(amount);
|
let curve_share = Perbill::from_parts(incoming_share).mul_ceil(amount);
|
||||||
let final_amount = amount.saturating_sub(curve_share);
|
let final_amount = amount.saturating_sub(curve_share);
|
||||||
|
|
||||||
NetworkImbalance::<T>::try_mutate(|imbalance_state| -> Result<(), ()> {
|
let mut imbalance_state = NetworkImbalance::<T>::get();
|
||||||
|
|
||||||
imbalance_state.incoming = imbalance_state.incoming
|
imbalance_state.incoming = imbalance_state.incoming
|
||||||
.checked_add(&final_amount)
|
.checked_add(&final_amount)
|
||||||
.ok_or(())?;
|
.ok_or(())?;
|
||||||
|
|
||||||
imbalance_state.curve_share = imbalance_state.curve_share
|
imbalance_state.curve_share = imbalance_state.curve_share
|
||||||
.checked_add(&curve_share)
|
.checked_add(&curve_share)
|
||||||
.ok_or(())?;
|
.ok_or(())?;
|
||||||
Ok(())
|
|
||||||
})?;
|
GatekeeperAmounts::<T>::insert(network_id, increased_gatekeeper_amount);
|
||||||
|
NetworkImbalance::<T>::put(imbalance_state);
|
||||||
|
|
||||||
Ok(final_amount)
|
Ok(final_amount)
|
||||||
}
|
}
|
||||||
@ -862,23 +909,25 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
|
|||||||
.map(|network| network.outgoing_share)
|
.map(|network| network.outgoing_share)
|
||||||
.ok_or(())?;
|
.ok_or(())?;
|
||||||
|
|
||||||
GatekeeperAmounts::<T>::try_mutate(network_id, |gatekeeper_amount| -> Result<(), ()> {
|
let decreased_gatekeeper_amount = GatekeeperAmounts::<T>::get(network_id)
|
||||||
*gatekeeper_amount = gatekeeper_amount.checked_sub(&amount).ok_or(())?;
|
.checked_sub(&amount)
|
||||||
Ok(())
|
.ok_or(())?;
|
||||||
})?;
|
|
||||||
|
|
||||||
let curve_share = Perbill::from_parts(outgoing_share).mul_ceil(amount);
|
let curve_share = Perbill::from_parts(outgoing_share).mul_ceil(amount);
|
||||||
let final_amount = amount.saturating_sub(curve_share);
|
let final_amount = amount.saturating_sub(curve_share);
|
||||||
|
|
||||||
NetworkImbalance::<T>::try_mutate(|imbalance_state| -> Result<(), ()> {
|
let mut imbalance_state = NetworkImbalance::<T>::get();
|
||||||
|
|
||||||
imbalance_state.outgoing = imbalance_state.outgoing
|
imbalance_state.outgoing = imbalance_state.outgoing
|
||||||
.checked_add(&final_amount)
|
.checked_add(&final_amount)
|
||||||
.ok_or(())?;
|
.ok_or(())?;
|
||||||
|
|
||||||
imbalance_state.curve_share = imbalance_state.curve_share
|
imbalance_state.curve_share = imbalance_state.curve_share
|
||||||
.checked_add(&curve_share)
|
.checked_add(&curve_share)
|
||||||
.ok_or(())?;
|
.ok_or(())?;
|
||||||
Ok(())
|
|
||||||
})?;
|
GatekeeperAmounts::<T>::insert(network_id, decreased_gatekeeper_amount);
|
||||||
|
NetworkImbalance::<T>::put(imbalance_state);
|
||||||
|
|
||||||
Ok(final_amount)
|
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!(Networks::<Test>::get(chain_id), Some(network));
|
||||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
||||||
assert!(NetworkCurves::<Test>::contains_key(&network_curve));
|
assert!(NetworkTypes::<Test>::contains_key(&network_curve));
|
||||||
assert!(NetworkCurvesVec::<Test>::get().contains(&network_curve));
|
assert!(NetworkCurves::<Test>::get().contains(&network_curve));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -55,8 +55,8 @@ fn could_add_network_from_authority() {
|
|||||||
let (chain_id, network) = prepare_network_data(None, None);
|
let (chain_id, network) = prepare_network_data(None, None);
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||||
|
|
||||||
assert_ok!(GhostNetworks::register_network(
|
assert_ok!(GhostNetworks::register_network(
|
||||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
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!(Networks::<Test>::get(chain_id), Some(network));
|
||||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
||||||
assert!(NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
assert!(NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||||
assert!(NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
assert!(NetworkCurves::<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);
|
let (chain_id, network) = prepare_network_data(None, None);
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||||
|
|
||||||
assert_err!(
|
assert_err!(
|
||||||
GhostNetworks::register_network(
|
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!(Networks::<Test>::get(chain_id), None);
|
||||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
assert!(!NetworkCurves::<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);
|
let (chain_id, network) = prepare_network_data(None, None);
|
||||||
register_and_check_network(chain_id, network.clone());
|
register_and_check_network(chain_id, network.clone());
|
||||||
|
|
||||||
assert!(!NetworkCurves::<Test>::contains_key(&new_curve));
|
assert!(!NetworkTypes::<Test>::contains_key(&new_curve));
|
||||||
assert!(NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
assert!(NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&new_curve));
|
assert!(!NetworkCurves::<Test>::get().contains(&new_curve));
|
||||||
assert!(NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
assert!(NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||||
|
|
||||||
assert_ok!(GhostNetworks::update_network_curve(
|
assert_ok!(GhostNetworks::update_network_curve(
|
||||||
RuntimeOrigin::signed(UpdaterAccount::get()),
|
RuntimeOrigin::signed(UpdaterAccount::get()),
|
||||||
@ -370,10 +370,10 @@ fn could_update_network_curve_from_authority_account() {
|
|||||||
let mut final_network = network.clone();
|
let mut final_network = network.clone();
|
||||||
final_network.r#curve = new_curve;
|
final_network.r#curve = new_curve;
|
||||||
|
|
||||||
assert!(NetworkCurves::<Test>::contains_key(&new_curve));
|
assert!(NetworkTypes::<Test>::contains_key(&new_curve));
|
||||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||||
assert!(NetworkCurvesVec::<Test>::get().contains(&new_curve));
|
assert!(NetworkCurves::<Test>::get().contains(&new_curve));
|
||||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||||
|
|
||||||
assert_eq!(Networks::<Test>::get(chain_id), Some(final_network.clone()));
|
assert_eq!(Networks::<Test>::get(chain_id), Some(final_network.clone()));
|
||||||
assert_ne!(network, final_network);
|
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!(Networks::<Test>::get(chain_id), None);
|
||||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
assert!(!NetworkCurves::<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!(Networks::<Test>::get(chain_id), Some(network));
|
||||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![chain_id]);
|
||||||
assert!(NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
assert!(NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||||
assert!(NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
assert!(NetworkCurves::<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!(Networks::<Test>::get(chain_id), None);
|
||||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||||
assert!(!NetworkCurves::<Test>::contains_key(&CURRENT_CURVE));
|
assert!(!NetworkTypes::<Test>::contains_key(&CURRENT_CURVE));
|
||||||
assert!(!NetworkCurvesVec::<Test>::get().contains(&CURRENT_CURVE));
|
assert!(!NetworkCurves::<Test>::get().contains(&CURRENT_CURVE));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ghost-traits"
|
name = "ghost-traits"
|
||||||
version = "0.4.6"
|
version = "0.4.10"
|
||||||
description = "Shared traits including `GhostHasher`, `NetworkDataBasicHandler`, `BoundedBTreeMap`, `MerkleTree` and more."
|
description = "Shared traits including `GhostHasher`, `NetworkDataBasicHandler`, `BoundedBTreeMap`, `MerkleTree` and more."
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|||||||
@ -20,6 +20,10 @@ pub trait BoundedBitmapReader {
|
|||||||
fn highest_bit<N>(&self) -> Option<N>
|
fn highest_bit<N>(&self) -> Option<N>
|
||||||
where
|
where
|
||||||
usize: UniqueSaturatedInto<N>;
|
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
|
fn count_ones<N>(&self) -> N
|
||||||
where
|
where
|
||||||
u32: UniqueSaturatedInto<N>;
|
u32: UniqueSaturatedInto<N>;
|
||||||
@ -40,9 +44,6 @@ pub trait BoundedBitmapGenerator {
|
|||||||
where
|
where
|
||||||
N: UniqueSaturatedInto<usize>;
|
N: UniqueSaturatedInto<usize>;
|
||||||
fn empty_from(bitmap: &Self) -> Self;
|
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
|
fn from_vec<Outer>(values: &Vec<Outer>) -> Self
|
||||||
where
|
where
|
||||||
Outer: AtLeast8BitUnsigned + TryInto<usize> + PartialEq + Copy;
|
Outer: AtLeast8BitUnsigned + TryInto<usize> + PartialEq + Copy;
|
||||||
|
|||||||
@ -6,7 +6,14 @@ use sp_std::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait IdentifierConverter<A, E> {
|
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> {
|
||||||
fn non_zero_index(index: A) -> Result<A, E>;
|
fn non_zero_index(index: A) -> Result<A, E>;
|
||||||
fn convert_identifier_to_index(bytes: &[u8]) -> Result<A, E>;
|
fn convert_identifier_to_index(bytes: &[u8]) -> Result<A, E>;
|
||||||
}
|
}
|
||||||
@ -15,11 +22,6 @@ pub trait FlexibleRoundOptimizedSchnorrThresholdSignature<A, E>: MerkleTreeBuild
|
|||||||
type Packages<'a>;
|
type Packages<'a>;
|
||||||
type NoncePackages<'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(
|
fn verify_signature_share(
|
||||||
&self,
|
&self,
|
||||||
i: A,
|
i: A,
|
||||||
@ -33,6 +35,7 @@ pub trait FlexibleRoundOptimizedSchnorrThresholdSignature<A, E>: MerkleTreeBuild
|
|||||||
vk: &[u8],
|
vk: &[u8],
|
||||||
m: &[u8],
|
m: &[u8],
|
||||||
) -> Result<(), E>;
|
) -> 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 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>;
|
fn accumulate_signature_scalar(&self, ss: &[u8], sh: &[u8]) -> Result<Vec<u8>, E>;
|
||||||
|
|
||||||
@ -91,13 +94,14 @@ pub trait MerkleTreeBuilder<A, E>: IdentifierConverter<A, E> {
|
|||||||
type Hash;
|
type Hash;
|
||||||
|
|
||||||
fn build_merkle_tree<C, V, F>(
|
fn build_merkle_tree<C, V, F>(
|
||||||
|
size_hint: usize,
|
||||||
verifying_shares: &BTreeMap<Identifier<C>, V>,
|
verifying_shares: &BTreeMap<Identifier<C>, V>,
|
||||||
serialize_fn: F,
|
serialize_fn: F,
|
||||||
) -> Result<Vec<Self::Hash>, E>
|
) -> Result<Vec<Self::Hash>, E>
|
||||||
where
|
where
|
||||||
C: frost_core::Ciphersuite,
|
C: frost_core::Ciphersuite,
|
||||||
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
||||||
F: Fn(&V) -> Result<Vec<u8>, E>;
|
F: Fn(&V, &mut Vec<u8>) -> Result<(), E>;
|
||||||
|
|
||||||
fn generate_merkle_proof_from_tree<C, V, F>(
|
fn generate_merkle_proof_from_tree<C, V, F>(
|
||||||
verifying_shares: &BTreeMap<Identifier<C>, V>,
|
verifying_shares: &BTreeMap<Identifier<C>, V>,
|
||||||
|
|||||||
@ -21,6 +21,13 @@ pub trait GhostHasher {
|
|||||||
bytes
|
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 hash(data: &[u8]) -> Self::Hash;
|
||||||
fn empty() -> Self::Hash;
|
fn empty() -> Self::Hash;
|
||||||
fn hash_len() -> usize;
|
fn hash_len() -> usize;
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
use frame_support::{pallet_prelude::*, storage::PrefixIterator};
|
use frame_support::{
|
||||||
|
pallet_prelude::*,
|
||||||
|
storage::PrefixIterator,
|
||||||
|
};
|
||||||
use sp_std::vec::Vec;
|
use sp_std::vec::Vec;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
offchain::http::PendingRequest,
|
offchain::http::PendingRequest,
|
||||||
@ -29,9 +32,12 @@ pub trait NetworkDataBasicHandler {
|
|||||||
+ TypeInfo
|
+ TypeInfo
|
||||||
+ MaybeSerializeDeserialize
|
+ MaybeSerializeDeserialize
|
||||||
+ MaxEncodedLen;
|
+ MaxEncodedLen;
|
||||||
|
type MaxNetworks: Get<u32>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait NetworkDataInspectHandler<Network>: NetworkDataBasicHandler {
|
pub trait NetworkDataInspectHandler<Network>: NetworkDataBasicHandler {
|
||||||
|
type TypesItem: AsRef<[Self::NetworkId]>;
|
||||||
|
|
||||||
fn count() -> u32;
|
fn count() -> u32;
|
||||||
fn contains_key(n: &Self::NetworkId) -> bool;
|
fn contains_key(n: &Self::NetworkId) -> bool;
|
||||||
fn curve_exists(c: &Self::NetworkCurve) -> bool;
|
fn curve_exists(c: &Self::NetworkCurve) -> bool;
|
||||||
@ -40,7 +46,9 @@ pub trait NetworkDataInspectHandler<Network>: NetworkDataBasicHandler {
|
|||||||
fn iter() -> PrefixIterator<(Self::NetworkId, Network)>;
|
fn iter() -> PrefixIterator<(Self::NetworkId, Network)>;
|
||||||
fn iter_indexes() -> impl Iterator<Item = Self::NetworkId>;
|
fn iter_indexes() -> impl Iterator<Item = Self::NetworkId>;
|
||||||
fn iter_curves() -> impl Iterator<Item = Self::NetworkCurve>;
|
fn iter_curves() -> impl Iterator<Item = Self::NetworkCurve>;
|
||||||
fn iter_types_by_curve(n: &Self::NetworkCurve) -> impl Iterator<Item = Self::NetworkType>;
|
fn iter_types_by_curve(
|
||||||
|
c: &Self::NetworkCurve
|
||||||
|
) -> impl Iterator<Item = (Self::NetworkType, Self::TypesItem)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait NetworkDataMutateHandler<Network, Balance>: NetworkDataInspectHandler<Network> {
|
pub trait NetworkDataMutateHandler<Network, Balance>: NetworkDataInspectHandler<Network> {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ghost-weaver"
|
name = "ghost-weaver"
|
||||||
version = "0.0.14"
|
version = "0.0.27"
|
||||||
description = "Weaving a secure cryptographic tapestry across different external chains."
|
description = "Weaving a secure cryptographic tapestry across different external chains."
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|||||||
@ -35,6 +35,9 @@ fn prepare_pallet<T: Config>(
|
|||||||
T::NetworkDataHandler::register(network_id, network_data)
|
T::NetworkDataHandler::register(network_id, network_data)
|
||||||
.expect("network should be valid for insertion");
|
.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)
|
(network_id, authority, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +56,7 @@ mod benchmarks {
|
|||||||
let block_attestation = AttestationContext::default()
|
let block_attestation = AttestationContext::default()
|
||||||
.with_network_id(network_id)
|
.with_network_id(network_id)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
|
.with_current_block(1337u16.into())
|
||||||
.build_block_attestation(420);
|
.build_block_attestation(420);
|
||||||
|
|
||||||
let signature = authority
|
let signature = authority
|
||||||
@ -73,21 +77,38 @@ mod benchmarks {
|
|||||||
fn weave_weft(
|
fn weave_weft(
|
||||||
a: Linear<1, { T::MaxAuthorities::get() as u32 }>
|
a: Linear<1, { T::MaxAuthorities::get() as u32 }>
|
||||||
) -> Result<(), BenchmarkError> {
|
) -> Result<(), BenchmarkError> {
|
||||||
let weaving_session = 420;
|
let weaving_session: WeavingSession = 420;
|
||||||
let next_session = weaving_session + 1;
|
let next_session: WeavingSession = weaving_session + 1;
|
||||||
let root_hash = H256::repeat_byte(0x69);
|
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, None);
|
||||||
|
|
||||||
let tapestry_key = (network_id, weaving_session, next_session, root_hash);
|
let next_session_bytes = next_session.to_be_bytes();
|
||||||
TapestryStrands::<T>::mutate(&tapestry_key, |tapestry| {
|
let weaving_session_bytes = weaving_session.to_be_bytes();
|
||||||
|
|
||||||
|
let metadata: &[&[u8]] = &[
|
||||||
|
root_hash.as_ref(),
|
||||||
|
next_session_bytes.as_ref(),
|
||||||
|
weaving_session_bytes.as_ref(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let tapestry_strand_key =
|
||||||
|
sequential_hash::<SubstrateBlake2Hasher, _>(metadata);
|
||||||
|
|
||||||
|
let mut bitmap = WeaversBitmap::<T>::empty(a);
|
||||||
(0..a).for_each(|i| {
|
(0..a).for_each(|i| {
|
||||||
let index = i as AuthIndex;
|
let index = i as AuthIndex;
|
||||||
if index == authority_index { return; }
|
if index == authority_index { return; }
|
||||||
tapestry.insert(index);
|
bitmap.insert(index);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mut tapestry_map = BoundedBTreeMap::<_, _, T::MaxAuthorities>::default();
|
||||||
|
tapestry_map
|
||||||
|
.try_insert(tapestry_strand_key.clone(), bitmap)
|
||||||
|
.map_err(|_| BenchmarkError::Stop("Failed to insert bitmap into benchmark map"))?;
|
||||||
|
|
||||||
|
TapestryStrands::<T>::insert(&network_id, tapestry_map);
|
||||||
|
|
||||||
let current_block = T::BlockNumberProvider::current_block_number();
|
let current_block = T::BlockNumberProvider::current_block_number();
|
||||||
let dummy_draft = TapestryDraftBuilder::default()
|
let dummy_draft = TapestryDraftBuilder::default()
|
||||||
.with_current_block(current_block)
|
.with_current_block(current_block)
|
||||||
@ -101,24 +122,31 @@ mod benchmarks {
|
|||||||
.with_network_id(network_id)
|
.with_network_id(network_id)
|
||||||
.with_weaving_session(weaving_session)
|
.with_weaving_session(weaving_session)
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
|
.with_current_block(1337u16.into())
|
||||||
.build_hash_attestation(root_hash, next_session);
|
.build_hash_attestation(root_hash, next_session);
|
||||||
|
|
||||||
let signature = authority
|
let signature = authority
|
||||||
.sign(&hash_attestation.encode())
|
.sign(&hash_attestation.encode())
|
||||||
.expect("Signature should be created");
|
.expect("Signature should be created");
|
||||||
|
|
||||||
let tapestry_strand_key = (network_id, weaving_session, next_session, root_hash);
|
|
||||||
|
|
||||||
let weaving_state = WeavingStates::<T>::get(&network_id);
|
let weaving_state = WeavingStates::<T>::get(&network_id);
|
||||||
assert_eq!(weaving_state.hash, H256::default());
|
assert_eq!(weaving_state.hash, H256::default());
|
||||||
assert_eq!(weaving_state.next_session, 0);
|
assert_eq!(weaving_state.next_session, 0);
|
||||||
assert_eq!(weaving_state.count, 0);
|
assert_eq!(weaving_state.count, 0);
|
||||||
|
|
||||||
assert!(!TapestryStrands::<T>::get(&tapestry_strand_key).contains(authority_index));
|
let tapestry_strand = TapestryStrands::<T>::get(&network_id);
|
||||||
assert_eq!(
|
let maybe_tapestry_bitmap = tapestry_strand.get(&tapestry_strand_key);
|
||||||
TapestryStrands::<T>::get(&tapestry_strand_key).count_ones::<u32>(),
|
|
||||||
a - 1
|
let authority_does_not_exists = maybe_tapestry_bitmap
|
||||||
);
|
.map(|bitmap| !bitmap.contains(authority_index))
|
||||||
|
.ok_or(BenchmarkError::Stop("NetworkId should be registered"))?;
|
||||||
|
|
||||||
|
let tapestry_participants = maybe_tapestry_bitmap
|
||||||
|
.map(|bitmap| bitmap.count_ones::<u32>())
|
||||||
|
.ok_or(BenchmarkError::Stop("NetworkId should be registered"))?;
|
||||||
|
|
||||||
|
assert!(authority_does_not_exists);
|
||||||
|
assert_eq!(tapestry_participants, a - 1);
|
||||||
|
|
||||||
#[extrinsic_call]
|
#[extrinsic_call]
|
||||||
_(RawOrigin::None, hash_attestation, signature);
|
_(RawOrigin::None, hash_attestation, signature);
|
||||||
@ -128,11 +156,19 @@ mod benchmarks {
|
|||||||
assert_eq!(new_weaving_state.next_session, next_session);
|
assert_eq!(new_weaving_state.next_session, next_session);
|
||||||
assert_eq!(new_weaving_state.count, a as AuthIndex);
|
assert_eq!(new_weaving_state.count, a as AuthIndex);
|
||||||
|
|
||||||
assert!(TapestryStrands::<T>::get(&tapestry_strand_key).contains(authority_index));
|
let tapestry_strand = TapestryStrands::<T>::get(&network_id);
|
||||||
assert_eq!(
|
let maybe_tapestry_bitmap = tapestry_strand.get(&tapestry_strand_key);
|
||||||
TapestryStrands::<T>::get(&tapestry_strand_key).count_ones::<u32>(),
|
|
||||||
a
|
let authority_exists = maybe_tapestry_bitmap
|
||||||
);
|
.map(|bitmap| bitmap.contains(authority_index))
|
||||||
|
.ok_or(BenchmarkError::Stop("NetworkId should be registered"))?;
|
||||||
|
|
||||||
|
let tapestry_participants = maybe_tapestry_bitmap
|
||||||
|
.map(|bitmap| bitmap.count_ones::<u32>())
|
||||||
|
.ok_or(BenchmarkError::Stop("NetworkId should be registered"))?;
|
||||||
|
|
||||||
|
assert!(authority_exists);
|
||||||
|
assert_eq!(tapestry_participants, a);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -320,9 +356,12 @@ mod benchmarks {
|
|||||||
let first_sha = sp_io::hashing::sha2_256(&last_header[..80]);
|
let first_sha = sp_io::hashing::sha2_256(&last_header[..80]);
|
||||||
let mut native_le = sp_io::hashing::sha2_256(&first_sha);
|
let mut native_le = sp_io::hashing::sha2_256(&first_sha);
|
||||||
native_le.reverse();
|
native_le.reverse();
|
||||||
let dynamic_trusted_root = H256::from(native_le);
|
|
||||||
|
|
||||||
LoomStates::<T>::insert(&network_id, &session, dynamic_trusted_root);
|
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);
|
||||||
|
|
||||||
let utxo_thread_proof = UtxoThreadProof::new(
|
let utxo_thread_proof = UtxoThreadProof::new(
|
||||||
gettxproof_bytes,
|
gettxproof_bytes,
|
||||||
@ -360,8 +399,11 @@ mod benchmarks {
|
|||||||
let root_string =
|
let root_string =
|
||||||
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129")
|
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129")
|
||||||
.expect("EVM Root hex should be valid");
|
.expect("EVM Root hex should be valid");
|
||||||
|
|
||||||
|
let at_block = 420;
|
||||||
let expected_root = H256::from_slice(&root_string);
|
let expected_root = H256::from_slice(&root_string);
|
||||||
LoomStates::<T>::insert(&network_id, &session, expected_root);
|
let loom_state = LoomState { at_block, root_hash: expected_root };
|
||||||
|
LoomStates::<T>::insert(&network_id, &session, loom_state);
|
||||||
|
|
||||||
let receiver_32: [u8; 32] =
|
let receiver_32: [u8; 32] =
|
||||||
hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e")
|
hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e")
|
||||||
|
|||||||
@ -68,13 +68,14 @@ fn parse_pending_requests<'a, R: Copy + Into<RequestId> + 'static>(
|
|||||||
) -> impl Iterator<Item = NetworkResponseType> + 'a {
|
) -> impl Iterator<Item = NetworkResponseType> + 'a {
|
||||||
PendingRequest::try_wait_all(pending_requests, Some(deadline))
|
PendingRequest::try_wait_all(pending_requests, Some(deadline))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(move |wait_result| {
|
.enumerate()
|
||||||
|
.filter_map(move |(idx, wait_result)| {
|
||||||
let http_result = wait_result
|
let http_result = wait_result
|
||||||
.inspect_err(|_| {
|
.inspect_err(|_| {
|
||||||
log::error!(
|
log::error!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
"🕸️ Error during request preparation: {:?}",
|
"🕸️ Weaver: RPC request [index {}] timed out (deadline reached).",
|
||||||
WeavingError::<u32>::DeadlineReached,
|
idx
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.ok()?;
|
.ok()?;
|
||||||
@ -83,7 +84,8 @@ fn parse_pending_requests<'a, R: Copy + Into<RequestId> + 'static>(
|
|||||||
.inspect_err(|err| {
|
.inspect_err(|err| {
|
||||||
log::error!(
|
log::error!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
"🕸️ Error during response parsing: {:?}",
|
"🕸️ Weaver: RPC request [index {}] failed with HTTP error: {:?}",
|
||||||
|
idx,
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -22,23 +22,32 @@ use sp_runtime::{
|
|||||||
storage::StorageValueRef,
|
storage::StorageValueRef,
|
||||||
storage_lock::{StorageLock, Time},
|
storage_lock::{StorageLock, Time},
|
||||||
},
|
},
|
||||||
traits::{BlockNumberProvider, UniqueSaturatedInto},
|
traits::{
|
||||||
RuntimeAppPublic,
|
TrailingZeroInput, BlockNumberProvider, Saturating,
|
||||||
|
UniqueSaturatedInto,
|
||||||
|
},
|
||||||
|
RuntimeAppPublic, Perbill, PerThing,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ghost_helpers::{
|
use ghost_helpers::{
|
||||||
bounded_bitmap::{validate_bitmap_sizes, BoundedBitmap},
|
bounded_bitmap::{validate_bitmap_sizes, BoundedBitmap},
|
||||||
get_byzantium_quorum_threshold,
|
|
||||||
networks::{NetworkData, NetworkType},
|
networks::{NetworkData, NetworkType},
|
||||||
|
hash_chain::sequential_hash,
|
||||||
|
get_byzantium_quorum_threshold, get_submission_probability,
|
||||||
|
SubstrateBlake2Hasher,
|
||||||
};
|
};
|
||||||
use ghost_traits::{
|
use ghost_traits::{
|
||||||
bounded_bitmap::{BoundedBitmapReader, BoundedBitmapWriter},
|
bounded_bitmap::{
|
||||||
|
BoundedBitmapReader, BoundedBitmapWriter,
|
||||||
|
BoundedBitmapGenerator,
|
||||||
|
},
|
||||||
networks::{
|
networks::{
|
||||||
NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler,
|
NetworkDataBasicHandler, NetworkDataInspectHandler,
|
||||||
NetworkRpcResolver,
|
NetworkDataMutateHandler, NetworkRpcResolver,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod migrations;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod impls;
|
mod impls;
|
||||||
mod types;
|
mod types;
|
||||||
@ -78,8 +87,8 @@ const LOG_TARGET: &str = "runtime::ghost-weaver";
|
|||||||
const DB_PREFIX: &[u8] = b"ghost-weaver::";
|
const DB_PREFIX: &[u8] = b"ghost-weaver::";
|
||||||
|
|
||||||
const LOCK_BLOCK_EXPIRATION: u64 = 20;
|
const LOCK_BLOCK_EXPIRATION: u64 = 20;
|
||||||
const MIN_LOCK_GUARD_PERIOD: u64 = 15_000;
|
const MIN_LOCK_GUARD_PERIOD: u64 = 60_000;
|
||||||
const FETCH_TIMEOUT_PERIOD: u64 = 3_000;
|
const FETCH_TIMEOUT_PERIOD: u64 = 5_000;
|
||||||
|
|
||||||
type AuthIndex = ghost_helpers::AuthIndexU16;
|
type AuthIndex = ghost_helpers::AuthIndexU16;
|
||||||
type BitmapChunk = ghost_helpers::BitmapChunkU32;
|
type BitmapChunk = ghost_helpers::BitmapChunkU32;
|
||||||
@ -99,7 +108,7 @@ type WeaversBitmap<T> = BoundedBitmap<BitmapChunk, <T as Config>::MaxAuthorities
|
|||||||
pub mod pallet {
|
pub mod pallet {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
#[pallet::storage_version(STORAGE_VERSION)]
|
#[pallet::storage_version(STORAGE_VERSION)]
|
||||||
@ -170,6 +179,7 @@ pub mod pallet {
|
|||||||
InvalidParticipantAttestation,
|
InvalidParticipantAttestation,
|
||||||
NonExistentNetworkId,
|
NonExistentNetworkId,
|
||||||
TooManyAttestations,
|
TooManyAttestations,
|
||||||
|
TooManyTapestries,
|
||||||
TimeWentBackwards,
|
TimeWentBackwards,
|
||||||
WeavingIsActive,
|
WeavingIsActive,
|
||||||
WeavingIsInactive,
|
WeavingIsInactive,
|
||||||
@ -182,6 +192,16 @@ pub mod pallet {
|
|||||||
CouldNotRegisterIncoming,
|
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::storage]
|
||||||
#[pallet::getter(fn current_weaving_session)]
|
#[pallet::getter(fn current_weaving_session)]
|
||||||
pub(super) type CurrentWeavingSession<T: Config> =
|
pub(super) type CurrentWeavingSession<T: Config> =
|
||||||
@ -202,21 +222,16 @@ pub mod pallet {
|
|||||||
_,
|
_,
|
||||||
Twox64Concat, NetworkIdOf<T>,
|
Twox64Concat, NetworkIdOf<T>,
|
||||||
Twox64Concat, WeavingSession,
|
Twox64Concat, WeavingSession,
|
||||||
H256,
|
LoomState,
|
||||||
ValueQuery,
|
ValueQuery,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
#[pallet::getter(fn tapestry_strands)]
|
#[pallet::getter(fn tapestry_strands)]
|
||||||
pub(super) type TapestryStrands<T: Config> = StorageNMap<
|
pub(super) type TapestryStrands<T: Config> = StorageMap<
|
||||||
_,
|
_,
|
||||||
(
|
Twox64Concat, NetworkIdOf<T>,
|
||||||
NMapKey<Twox64Concat, NetworkIdOf<T>>,
|
BoundedBTreeMap<H256, WeaversBitmap<T>, T::MaxAuthorities>,
|
||||||
NMapKey<Twox64Concat, WeavingSession>,
|
|
||||||
NMapKey<Twox64Concat, WeavingSession>,
|
|
||||||
NMapKey<Twox64Concat, H256>,
|
|
||||||
),
|
|
||||||
WeaversBitmap<T>,
|
|
||||||
ValueQuery,
|
ValueQuery,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@ -288,7 +303,12 @@ pub mod pallet {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LoomStates::<T>::insert(&data.0, data.1, data.2);
|
let initial_loom_state = LoomState {
|
||||||
|
at_block: 0u16.into(),
|
||||||
|
root_hash: data.2,
|
||||||
|
};
|
||||||
|
|
||||||
|
LoomStates::<T>::insert(&data.0, data.1, initial_loom_state);
|
||||||
});
|
});
|
||||||
|
|
||||||
if !self.authorities.is_empty() {
|
if !self.authorities.is_empty() {
|
||||||
@ -330,26 +350,23 @@ pub mod pallet {
|
|||||||
|
|
||||||
let external_block = block_attestation.external_block;
|
let external_block = block_attestation.external_block;
|
||||||
|
|
||||||
let current_authorities_count = Authorities::<T>::decode_len().
|
|
||||||
unwrap_or_default();
|
|
||||||
|
|
||||||
NetworkAttestations::<T>::try_mutate(
|
NetworkAttestations::<T>::try_mutate(
|
||||||
&network_id,
|
&network_id,
|
||||||
|attestations| -> DispatchResult {
|
|attestations| -> DispatchResult {
|
||||||
if attestations.is_empty() {
|
let index = authority_index as usize;
|
||||||
attestations.bounded_resize(current_authorities_count, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure!(
|
ensure!(index < attestations.len(), Error::<T>::TooManyAttestations);
|
||||||
(authority_index as usize) < attestations.len(),
|
attestations[index] = Some(external_block);
|
||||||
Error::<T>::TooManyAttestations,
|
|
||||||
);
|
|
||||||
|
|
||||||
attestations[authority_index as usize] = Some(external_block);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let current_block = T::BlockNumberProvider::current_block_number();
|
||||||
|
NetworkAttestedBlocks::<T>::insert(
|
||||||
|
&network_id, &authority_index,
|
||||||
|
current_block
|
||||||
|
);
|
||||||
|
|
||||||
Self::deposit_event(Event::<T>::BlockAttestated {
|
Self::deposit_event(Event::<T>::BlockAttestated {
|
||||||
network_id,
|
network_id,
|
||||||
authority_index,
|
authority_index,
|
||||||
@ -383,29 +400,65 @@ pub mod pallet {
|
|||||||
Error::<T>::WeavingIsInactive,
|
Error::<T>::WeavingIsInactive,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let authorities_len = Authorities::<T>::decode_len()
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
let root_hash = hash_attestation.root_hash;
|
let root_hash = hash_attestation.root_hash;
|
||||||
let next_session = hash_attestation.next_session;
|
let next_session = hash_attestation.next_session;
|
||||||
let weaving_session = hash_attestation.weaving_session();
|
let weaving_session = hash_attestation.weaving_session();
|
||||||
|
|
||||||
|
let next_session_bytes = next_session.to_be_bytes();
|
||||||
|
let weaving_session_bytes = weaving_session.to_be_bytes();
|
||||||
|
|
||||||
|
let metadata: &[&[u8]] = &[
|
||||||
|
root_hash.as_ref(),
|
||||||
|
next_session_bytes.as_ref(),
|
||||||
|
weaving_session_bytes.as_ref(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let tapestry_strand_key =
|
||||||
|
sequential_hash::<SubstrateBlake2Hasher, _>(metadata);
|
||||||
|
|
||||||
let weavers_count = TapestryStrands::<T>::try_mutate(
|
let weavers_count = TapestryStrands::<T>::try_mutate(
|
||||||
&(network_id, weaving_session, next_session, root_hash),
|
&network_id,
|
||||||
|tapestry_strand| -> Result<AuthIndex, DispatchError> {
|
|tapestry_strand| -> Result<AuthIndex, DispatchError> {
|
||||||
|
if !tapestry_strand.contains_key(&tapestry_strand_key) {
|
||||||
|
let empty_bitmap = WeaversBitmap::<T>::empty(authorities_len);
|
||||||
|
tapestry_strand
|
||||||
|
.try_insert(tapestry_strand_key, empty_bitmap)
|
||||||
|
.map_err(|_| Error::<T>::TooManyTapestries)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tapestry_bitmap = tapestry_strand
|
||||||
|
.get_mut(&tapestry_strand_key)
|
||||||
|
.ok_or(Error::<T>::TooManyTapestries)?;
|
||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
!tapestry_strand.contains(authority_index),
|
!tapestry_bitmap.contains(authority_index),
|
||||||
Error::<T>::AuthorityPartOfTrapestry,
|
Error::<T>::AuthorityPartOfTrapestry,
|
||||||
);
|
);
|
||||||
|
|
||||||
tapestry_strand.insert(authority_index);
|
tapestry_bitmap.insert(authority_index);
|
||||||
Ok(tapestry_strand.count_ones::<AuthIndex>())
|
Ok(tapestry_bitmap.count_ones::<AuthIndex>())
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
WeavingStates::<T>::mutate(&network_id, |weaving_state| {
|
WeavingStates::<T>::mutate(&network_id, |weaving_state| {
|
||||||
if weaving_state.count < weavers_count {
|
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 {
|
Self::deposit_event(Event::<T>::HashAttestated {
|
||||||
authority_index,
|
authority_index,
|
||||||
next_session,
|
next_session,
|
||||||
@ -438,7 +491,7 @@ pub mod pallet {
|
|||||||
let network_data = T::NetworkDataHandler::get(&network_id)
|
let network_data = T::NetworkDataHandler::get(&network_id)
|
||||||
.ok_or(Error::<T>::NonExistentNetworkId)?;
|
.ok_or(Error::<T>::NonExistentNetworkId)?;
|
||||||
|
|
||||||
let root_hash = LoomStates::<T>::get(&network_id, &session);
|
let state = LoomStates::<T>::get(&network_id, &session);
|
||||||
let pulled_thread_key = thread_proof.get_unique_key(session, network_id);
|
let pulled_thread_key = thread_proof.get_unique_key(session, network_id);
|
||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
@ -447,7 +500,7 @@ pub mod pallet {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let (receiver_account, amount) = thread_proof
|
let (receiver_account, amount) = thread_proof
|
||||||
.verify_thread_proof(root_hash, network_id, &network_data.gatekeeper)
|
.verify_thread_proof(state.root_hash, network_id, &network_data.gatekeeper)
|
||||||
.ok_or(Error::<T>::InvalidMerkleProof)?;
|
.ok_or(Error::<T>::InvalidMerkleProof)?;
|
||||||
|
|
||||||
let receiver_bytes: &[u8; 32] = receiver_account.as_ref();
|
let receiver_bytes: &[u8; 32] = receiver_account.as_ref();
|
||||||
@ -504,11 +557,13 @@ pub mod pallet {
|
|||||||
let current_session = CurrentWeavingSession::<T>::get(&network_id);
|
let current_session = CurrentWeavingSession::<T>::get(&network_id);
|
||||||
let loom_state_changed =
|
let loom_state_changed =
|
||||||
LoomStates::<T>::mutate(&network_id, ¤t_session, |loom_state| {
|
LoomStates::<T>::mutate(&network_id, ¤t_session, |loom_state| {
|
||||||
if *loom_state != weaving_state.hash && threshold_reached {
|
if !threshold_reached { return false; }
|
||||||
*loom_state = weaving_state.hash;
|
|
||||||
return true;
|
let hash_changed = loom_state.root_hash != weaving_state.hash;
|
||||||
}
|
loom_state.at_block = tapestry_draft.median;
|
||||||
false
|
if hash_changed { loom_state.root_hash = weaving_state.hash; }
|
||||||
|
|
||||||
|
hash_changed
|
||||||
});
|
});
|
||||||
|
|
||||||
if loom_state_changed && weaving_state.next_session != current_session {
|
if loom_state_changed && weaving_state.next_session != current_session {
|
||||||
@ -518,8 +573,10 @@ pub mod pallet {
|
|||||||
CurrentWeavingSession::<T>::insert(&network_id, next_session);
|
CurrentWeavingSession::<T>::insert(&network_id, next_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
weight.saturating_accrue(T::DbWeight::get().writes(3));
|
||||||
TapestryDrafts::<T>::remove(&network_id);
|
TapestryDrafts::<T>::remove(&network_id);
|
||||||
|
WeavingStates::<T>::remove(&network_id);
|
||||||
|
NetworkAttestations::<T>::remove(&network_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -532,9 +589,11 @@ pub mod pallet {
|
|||||||
weight.saturating_accrue(T::DbWeight::get().reads(1));
|
weight.saturating_accrue(T::DbWeight::get().reads(1));
|
||||||
let attestation_len = NetworkAttestations::<T>::decode_len(&network_id);
|
let attestation_len = NetworkAttestations::<T>::decode_len(&network_id);
|
||||||
|
|
||||||
if attestation_len.unwrap_or(0) > len {
|
if attestation_len.unwrap_or(0) != len {
|
||||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
|
||||||
NetworkAttestations::<T>::remove(&network_id);
|
NetworkAttestations::<T>::mutate(&network_id, |attestations| {
|
||||||
|
attestations.bounded_resize(len, None);
|
||||||
|
});
|
||||||
return weight;
|
return weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,8 +621,9 @@ pub mod pallet {
|
|||||||
.with_median_external(median_block)
|
.with_median_external(median_block)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
TapestryStrands::<T>::remove(&network_id);
|
||||||
TapestryDrafts::<T>::insert(&network_id, tapestry_draft);
|
TapestryDrafts::<T>::insert(&network_id, tapestry_draft);
|
||||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
weight.saturating_accrue(T::DbWeight::get().writes(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -575,7 +635,7 @@ pub mod pallet {
|
|||||||
if sp_io::offchain::is_validator() {
|
if sp_io::offchain::is_validator() {
|
||||||
log::warn!(target: LOG_TARGET, "🕸️ Weaver started at block #{:?}", now);
|
log::warn!(target: LOG_TARGET, "🕸️ Weaver started at block #{:?}", now);
|
||||||
match Self::start_weaving(now) {
|
match Self::start_weaving(now) {
|
||||||
Ok(_) => log::warn!(target: LOG_TARGET, "🕸️ Weaver finished gracefully at block #{:?}", now),
|
Ok(msg) => log::warn!(target: LOG_TARGET, "🕸️ Weaver finished gracefully at block #{:?}: {:?}", now, msg),
|
||||||
Err(e) => log::warn!(target: LOG_TARGET, "🕸️ Weaver failed at block #{:?}: {:?}", now, e),
|
Err(e) => log::warn!(target: LOG_TARGET, "🕸️ Weaver failed at block #{:?}: {:?}", now, e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -616,6 +676,21 @@ pub mod pallet {
|
|||||||
.propagate(true)
|
.propagate(true)
|
||||||
.build()
|
.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(),
|
_ => InvalidTransaction::Call.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -623,6 +698,31 @@ pub mod pallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config> Pallet<T> {
|
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>(
|
fn validate_attestation_signature<A>(
|
||||||
attestation: &A,
|
attestation: &A,
|
||||||
signature: &<T::AuthorityId as RuntimeAppPublic>::Signature,
|
signature: &<T::AuthorityId as RuntimeAppPublic>::Signature,
|
||||||
@ -632,15 +732,40 @@ impl<T: Config> Pallet<T> {
|
|||||||
A: Encode,
|
A: Encode,
|
||||||
{
|
{
|
||||||
let authority_index = attestation.authority_index();
|
let authority_index = attestation.authority_index();
|
||||||
let attestation_block = attestation.block();
|
|
||||||
let network_id = attestation.network_id();
|
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) {
|
if DisabledAuthorities::<T>::get().contains(authority_index) {
|
||||||
return Err(InvalidTransaction::BadSigner);
|
return Err(InvalidTransaction::BadSigner);
|
||||||
}
|
}
|
||||||
|
|
||||||
if T::BlockNumberProvider::current_block_number() <= attestation_block {
|
let attestation_block = attestation.block();
|
||||||
return Err(InvalidTransaction::BadProof);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
Authorities::<T>::get()
|
Authorities::<T>::get()
|
||||||
@ -653,10 +778,6 @@ impl<T: Config> Pallet<T> {
|
|||||||
.ok_or(InvalidTransaction::BadSigner)
|
.ok_or(InvalidTransaction::BadSigner)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if !T::NetworkDataHandler::contains_key(&network_id) {
|
|
||||||
return Err(InvalidTransaction::BadProof);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((authority_index, network_id))
|
Ok((authority_index, network_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,7 +792,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
|
|
||||||
let lock_period_key = Self::create_storage_key(b"network-period", &network_id_encoded);
|
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_period = Self::read_offchain_storage(&lock_period_key, &MIN_LOCK_GUARD_PERIOD);
|
||||||
let lock_until = rt_offchain::Duration::from_millis(lock_period);
|
let lock_until = rt_offchain::Duration::from_millis(lock_period.max(MIN_LOCK_GUARD_PERIOD));
|
||||||
|
|
||||||
let network_lock_key = Self::create_storage_key(b"network-lock-", &network_id_encoded);
|
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);
|
let mut network_lock = StorageLock::<Time>::with_deadline(&network_lock_key, lock_until);
|
||||||
@ -709,14 +830,31 @@ impl<T: Config> Pallet<T> {
|
|||||||
return Err(WeavingError::NoEndpointsAvailable(network_id));
|
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) {
|
match TapestryDrafts::<T>::get(&network_id) {
|
||||||
Some(tapestry_draft) => Self::try_request_and_submit_hash(
|
Some(tapestry_draft) => Self::try_request_and_submit_hash(
|
||||||
network_id,
|
network_id,
|
||||||
current_block,
|
current_block,
|
||||||
tapestry_draft.median,
|
tapestry_draft,
|
||||||
deadline,
|
deadline,
|
||||||
&network_data,
|
&network_data,
|
||||||
&rpc_endpoints,
|
&rpc_endpoints,
|
||||||
|
check_probability,
|
||||||
),
|
),
|
||||||
None => Self::try_request_and_submit_block(
|
None => Self::try_request_and_submit_block(
|
||||||
network_id,
|
network_id,
|
||||||
@ -724,6 +862,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
deadline,
|
deadline,
|
||||||
&network_data,
|
&network_data,
|
||||||
&rpc_endpoints,
|
&rpc_endpoints,
|
||||||
|
check_probability,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -731,13 +870,22 @@ impl<T: Config> Pallet<T> {
|
|||||||
fn try_request_and_submit_hash(
|
fn try_request_and_submit_hash(
|
||||||
network_id: NetworkIdOf<T>,
|
network_id: NetworkIdOf<T>,
|
||||||
current_block: BlockNumberFor<T>,
|
current_block: BlockNumberFor<T>,
|
||||||
target_block: ExternalBlockNumber,
|
tapestry_draft: TapestryDraft<BlockNumberFor<T>>,
|
||||||
deadline: rt_offchain::Timestamp,
|
deadline: rt_offchain::Timestamp,
|
||||||
network_data: &NetworkData,
|
network_data: &NetworkData,
|
||||||
rpc_endpoints: &Vec<Vec<u8>>,
|
rpc_endpoints: &Vec<Vec<u8>>,
|
||||||
|
check_probability: impl Fn(usize, BlockNumberFor<T>) -> bool,
|
||||||
) -> WeavingResult<T, WeavingOk<NetworkIdOf<T>>> {
|
) -> WeavingResult<T, WeavingOk<NetworkIdOf<T>>> {
|
||||||
let weaving_session = CurrentWeavingSession::<T>::get(&network_id);
|
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_id = current_block.unique_saturated_into();
|
||||||
|
|
||||||
let request_body = network_data.r#type.get_hash_request_body(
|
let request_body = network_data.r#type.get_hash_request_body(
|
||||||
@ -770,8 +918,19 @@ impl<T: Config> Pallet<T> {
|
|||||||
network_id,
|
network_id,
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let tapestry_key = (network_id, weaving_session, first_next_session, first_hash);
|
let next_session_bytes = first_next_session.to_be_bytes();
|
||||||
let tapestry_strand = TapestryStrands::<T>::get(&tapestry_key);
|
let weaving_session_bytes = weaving_session.to_be_bytes();
|
||||||
|
|
||||||
|
let metadata: &[&[u8]] = &[
|
||||||
|
first_hash.as_ref(),
|
||||||
|
next_session_bytes.as_ref(),
|
||||||
|
weaving_session_bytes.as_ref(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let tapestry_strand_key =
|
||||||
|
sequential_hash::<SubstrateBlake2Hasher, _>(metadata);
|
||||||
|
|
||||||
|
let tapestry_strand = TapestryStrands::<T>::get(&network_id);
|
||||||
|
|
||||||
let context = AttestationContext::default()
|
let context = AttestationContext::default()
|
||||||
.with_weaving_session(weaving_session)
|
.with_weaving_session(weaving_session)
|
||||||
@ -779,7 +938,12 @@ impl<T: Config> Pallet<T> {
|
|||||||
.with_network_id(network_id);
|
.with_network_id(network_id);
|
||||||
|
|
||||||
Self::local_authorities().for_each(|(authority_index, authority_key)| {
|
Self::local_authorities().for_each(|(authority_index, authority_key)| {
|
||||||
if tapestry_strand.contains(authority_index) {
|
let already_part_of_tapestry_strand = tapestry_strand
|
||||||
|
.get(&tapestry_strand_key)
|
||||||
|
.map(|bitmap| bitmap.contains(authority_index))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if already_part_of_tapestry_strand {
|
||||||
log::error!(
|
log::error!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
"🕸️ Weft already weaved from authority #{:?} for network #{:?}.",
|
"🕸️ Weft already weaved from authority #{:?} for network #{:?}.",
|
||||||
@ -789,6 +953,23 @@ impl<T: Config> Pallet<T> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let last_attested =
|
||||||
|
NetworkAttestedBlocks::<T>::get(&network_id, &authority_index);
|
||||||
|
|
||||||
|
let lock: BlockNumberFor<T> = LOCK_BLOCK_EXPIRATION.unique_saturated_into();
|
||||||
|
let cooling_off_until = last_attested.saturating_add(lock);
|
||||||
|
|
||||||
|
if current_block < cooling_off_until {
|
||||||
|
log::error!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
"🕸️ Weft is cooling for authority #{:?} for network #{:?} blocks left {:?}.",
|
||||||
|
authority_index,
|
||||||
|
network_id,
|
||||||
|
cooling_off_until.saturating_sub(current_block)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let hash_attestation = context
|
let hash_attestation = context
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
.build_hash_attestation(first_hash, first_next_session);
|
.build_hash_attestation(first_hash, first_next_session);
|
||||||
@ -831,7 +1012,20 @@ impl<T: Config> Pallet<T> {
|
|||||||
deadline: rt_offchain::Timestamp,
|
deadline: rt_offchain::Timestamp,
|
||||||
network_data: &NetworkData,
|
network_data: &NetworkData,
|
||||||
rpc_endpoints: &Vec<Vec<u8>>,
|
rpc_endpoints: &Vec<Vec<u8>>,
|
||||||
|
check_probability: impl Fn(usize, BlockNumberFor<T>) -> bool,
|
||||||
) -> WeavingResult<T, WeavingOk<NetworkIdOf<T>>> {
|
) -> 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 network_id_encoded = network_id.encode();
|
||||||
let distance_key = Self::create_storage_key(b"distance-", &network_id_encoded);
|
let distance_key = Self::create_storage_key(b"distance-", &network_id_encoded);
|
||||||
let block_deviation =
|
let block_deviation =
|
||||||
@ -850,6 +1044,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
|
|
||||||
let total_blocks = block_numbers.len();
|
let total_blocks = block_numbers.len();
|
||||||
let weaving_threshold = get_byzantium_quorum_threshold(total_blocks);
|
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(
|
let median_block = Self::validate_block_numbers_consensus(
|
||||||
&mut block_numbers,
|
&mut block_numbers,
|
||||||
@ -870,6 +1065,23 @@ impl<T: Config> Pallet<T> {
|
|||||||
.with_network_id(network_id);
|
.with_network_id(network_id);
|
||||||
|
|
||||||
Self::local_authorities().for_each(|(authority_index, authority_key)| {
|
Self::local_authorities().for_each(|(authority_index, authority_key)| {
|
||||||
|
let last_attested =
|
||||||
|
NetworkAttestedBlocks::<T>::get(&network_id, &authority_index);
|
||||||
|
|
||||||
|
let lock: BlockNumberFor<T> = LOCK_BLOCK_EXPIRATION.unique_saturated_into();
|
||||||
|
let cooling_off_until = last_attested.saturating_add(lock);
|
||||||
|
|
||||||
|
if current_block < cooling_off_until {
|
||||||
|
log::error!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
"🕸️ Attestation is cooling for authority #{:?} for network #{:?} blocks left {:?}.",
|
||||||
|
authority_index,
|
||||||
|
network_id,
|
||||||
|
cooling_off_until.saturating_sub(current_block)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let block_attestation = context
|
let block_attestation = context
|
||||||
.with_authority_index(authority_index)
|
.with_authority_index(authority_index)
|
||||||
.build_block_attestation(finalized_block);
|
.build_block_attestation(finalized_block);
|
||||||
@ -898,7 +1110,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(WeavingOk::Block(finalized_block, network_id))
|
Ok(WeavingOk::Block(finalized_block, parsed_blocks_count, network_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_pending_requests(
|
fn prepare_pending_requests(
|
||||||
@ -1042,12 +1254,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
local_authorities
|
local_authorities
|
||||||
.binary_search(&authority)
|
.binary_search(&authority)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|location| {
|
.map(|_| (index as AuthIndex, authority))
|
||||||
(
|
|
||||||
index.unique_saturated_into(),
|
|
||||||
local_authorities[location].clone(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
pallets/weaver/src/migrations/mod.rs
Normal file
18
pallets/weaver/src/migrations/mod.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
pub mod v1;
|
||||||
|
pub mod v2;
|
||||||
|
|
||||||
|
pub type MigrateV0ToV1<T> = frame_support::migrations::VersionedMigration<
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
v1::RemoveAttestedBlocksStorage<T>,
|
||||||
|
crate::Pallet::<T>,
|
||||||
|
<T as frame_system::Config>::DbWeight,
|
||||||
|
>;
|
||||||
|
|
||||||
|
pub type MigrateV1ToV2<T> = frame_support::migrations::VersionedMigration<
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
v2::UpdateTapestryStrandsStorageLayout<T>,
|
||||||
|
crate::Pallet::<T>,
|
||||||
|
<T as frame_system::Config>::DbWeight,
|
||||||
|
>;
|
||||||
33
pallets/weaver/src/migrations/v1.rs
Normal file
33
pallets/weaver/src/migrations/v1.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
33
pallets/weaver/src/migrations/v2.rs
Normal file
33
pallets/weaver/src/migrations/v2.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use frame_support::{
|
||||||
|
traits::{Get, UncheckedOnRuntimeUpgrade},
|
||||||
|
weights::Weight,
|
||||||
|
};
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use crate::{Config, LOG_TARGET};
|
||||||
|
|
||||||
|
pub struct UpdateTapestryStrandsStorageLayout<T>(PhantomData<T>);
|
||||||
|
impl<T: Config> UncheckedOnRuntimeUpgrade for UpdateTapestryStrandsStorageLayout<T> {
|
||||||
|
fn on_runtime_upgrade() -> Weight {
|
||||||
|
let clear_key = frame_support::storage::storage_prefix(
|
||||||
|
b"GhostWeaver",
|
||||||
|
b"TapestryStrands"
|
||||||
|
);
|
||||||
|
|
||||||
|
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: Old StorageNMap for TapestryStrands wiped. Wiped {} keys from Trie.",
|
||||||
|
killed_keys
|
||||||
|
);
|
||||||
|
|
||||||
|
T::DbWeight::get().reads_writes(1, killed_keys as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#![cfg(test)]
|
#![cfg(test)]
|
||||||
|
|
||||||
use crate::sr25519::AuthorityPair;
|
use crate::{LOCK_BLOCK_EXPIRATION, sr25519::AuthorityPair};
|
||||||
|
|
||||||
use crate::mock::*;
|
use crate::mock::*;
|
||||||
use crate::pallet::*;
|
use crate::pallet::*;
|
||||||
@ -76,10 +76,11 @@ fn should_successfully_compute_median_and_start_weaving_round() {
|
|||||||
let networks = vec![(network_id, network_data, Default::default())];
|
let networks = vec![(network_id, network_data, Default::default())];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
System::set_block_number(2);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||||
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2);
|
||||||
|
|
||||||
let context = AttestationContext::default()
|
let context = AttestationContext::default()
|
||||||
.with_current_block(1)
|
.with_current_block(LOCK_BLOCK_EXPIRATION + 1)
|
||||||
.with_network_id(network_id);
|
.with_network_id(network_id);
|
||||||
|
|
||||||
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
||||||
@ -96,12 +97,12 @@ fn should_successfully_compute_median_and_start_weaving_round() {
|
|||||||
|
|
||||||
assert!(GhostWeaver::tapestry_drafts(network_id).is_none());
|
assert!(GhostWeaver::tapestry_drafts(network_id).is_none());
|
||||||
|
|
||||||
System::set_block_number(3);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 3);
|
||||||
GhostWeaver::on_initialize(3);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3);
|
||||||
|
|
||||||
let round = GhostWeaver::tapestry_drafts(network_id);
|
let round = GhostWeaver::tapestry_drafts(network_id);
|
||||||
assert!(round.is_some());
|
assert!(round.is_some());
|
||||||
assert_eq!(round.unwrap().until, 3 + WeavingDelay::get());
|
assert_eq!(round.unwrap().until, LOCK_BLOCK_EXPIRATION + 3 + WeavingDelay::get());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,10 +121,11 @@ fn should_apply_cooldown_delay_on_consensus_failure() {
|
|||||||
let networks = vec![(network_id, network_data, Default::default())];
|
let networks = vec![(network_id, network_data, Default::default())];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
System::set_block_number(10);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 9);
|
||||||
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 10);
|
||||||
|
|
||||||
let context = AttestationContext::default()
|
let context = AttestationContext::default()
|
||||||
.with_current_block(9)
|
.with_current_block(LOCK_BLOCK_EXPIRATION + 9)
|
||||||
.with_network_id(network_id);
|
.with_network_id(network_id);
|
||||||
|
|
||||||
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
||||||
@ -138,20 +140,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(), att2, sig2).is_ok());
|
||||||
assert!(GhostWeaver::extend_warp(RuntimeOrigin::none(), att3, sig3).is_ok());
|
assert!(GhostWeaver::extend_warp(RuntimeOrigin::none(), att3, sig3).is_ok());
|
||||||
|
|
||||||
System::set_block_number(11);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 11);
|
||||||
GhostWeaver::on_initialize(11);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 11);
|
||||||
|
|
||||||
let cooldown_block = GhostWeaver::next_consensus_attempt_blocks(network_id);
|
let cooldown_block = GhostWeaver::next_consensus_attempt_blocks(network_id);
|
||||||
assert_eq!(cooldown_block, 14);
|
assert_eq!(cooldown_block, LOCK_BLOCK_EXPIRATION + 14);
|
||||||
|
|
||||||
TapestryDrafts::<TestRuntime>::remove(network_id);
|
TapestryDrafts::<TestRuntime>::remove(network_id);
|
||||||
|
|
||||||
System::set_block_number(12);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 12);
|
||||||
GhostWeaver::on_initialize(12);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION+ 12);
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_none());
|
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_none());
|
||||||
|
|
||||||
System::set_block_number(14);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 14);
|
||||||
GhostWeaver::on_initialize(14);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 14);
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_some());
|
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_some());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -168,10 +170,11 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
|||||||
let networks = vec![(network_id, network_data, Default::default())];
|
let networks = vec![(network_id, network_data, Default::default())];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
System::set_block_number(2);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||||
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2);
|
||||||
|
|
||||||
let att = AttestationContext::default()
|
let att = AttestationContext::default()
|
||||||
.with_current_block(1)
|
.with_current_block(LOCK_BLOCK_EXPIRATION + 1)
|
||||||
.with_network_id(network_id)
|
.with_network_id(network_id)
|
||||||
.with_authority_index(0)
|
.with_authority_index(0)
|
||||||
.build_block_attestation(100);
|
.build_block_attestation(100);
|
||||||
@ -184,7 +187,9 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
|||||||
signature: valid_sig,
|
signature: valid_sig,
|
||||||
};
|
};
|
||||||
|
|
||||||
let validity = GhostWeaver::validate_unsigned(TransactionSource::External, &call);
|
let validity =
|
||||||
|
GhostWeaver::validate_unsigned(TransactionSource::External, &call);
|
||||||
|
|
||||||
assert!(validity.is_ok());
|
assert!(validity.is_ok());
|
||||||
let valid_info = validity.unwrap();
|
let valid_info = validity.unwrap();
|
||||||
|
|
||||||
@ -199,7 +204,9 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
|||||||
signature: invalid_sig,
|
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!(
|
assert_eq!(
|
||||||
spam_validity,
|
spam_validity,
|
||||||
Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner).into())
|
Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner).into())
|
||||||
@ -240,6 +247,9 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
ext.register_extension(TransactionPoolExt::new(pool));
|
ext.register_extension(TransactionPoolExt::new(pool));
|
||||||
|
|
||||||
ext.execute_with(|| {
|
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 network_id_encoded = evm_network_id.encode();
|
||||||
|
|
||||||
let mut endpoint_key = b"ghost-weaver::".to_vec();
|
let mut endpoint_key = b"ghost-weaver::".to_vec();
|
||||||
@ -252,6 +262,7 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
|
|
||||||
let target_endpoint = b"http://localhost:8545".to_vec();
|
let target_endpoint = b"http://localhost:8545".to_vec();
|
||||||
let rpc_endpoints: Vec<Vec<u8>> = vec![target_endpoint.clone()];
|
let rpc_endpoints: Vec<Vec<u8>> = vec![target_endpoint.clone()];
|
||||||
|
|
||||||
sp_io::offchain::local_storage_set(
|
sp_io::offchain::local_storage_set(
|
||||||
sp_core::offchain::StorageKind::PERSISTENT,
|
sp_core::offchain::StorageKind::PERSISTENT,
|
||||||
&endpoint_key,
|
&endpoint_key,
|
||||||
@ -288,8 +299,8 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
("Accept".into(), "application/json".into()),
|
("Accept".into(), "application/json".into()),
|
||||||
("Content-Type".into(), "application/json".into()),
|
("Content-Type".into(), "application/json".into()),
|
||||||
],
|
],
|
||||||
body: b"{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"getblockcount\"}".to_vec(),
|
body: b"{\"id\":21,\"jsonrpc\":\"2.0\",\"method\":\"getblockcount\"}".to_vec(),
|
||||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":960127}".to_vec()),
|
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":21,\"result\":960127}".to_vec()),
|
||||||
sent: true,
|
sent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
@ -303,17 +314,16 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
("X-Custom-Provider".into(), "GhostWeaverNode".into()),
|
("X-Custom-Provider".into(), "GhostWeaverNode".into()),
|
||||||
("Authorization".into(), "Bearer new-api-token-123".into()),
|
("Authorization".into(), "Bearer new-api-token-123".into()),
|
||||||
],
|
],
|
||||||
body: b"{\"id\":2,\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\"}".to_vec(),
|
body: b"{\"id\":22,\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\"}".to_vec(),
|
||||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":\"0x1873a84\"}".to_vec()),
|
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":22,\"result\":\"0x1873a84\"}".to_vec()),
|
||||||
sent: true,
|
sent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
System::set_block_number(1u64);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||||
GhostWeaver::offchain_worker(1u64);
|
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||||
System::set_block_number(2u64);
|
|
||||||
|
|
||||||
let state = pool_state.read();
|
let state = pool_state.read();
|
||||||
assert_eq!(state.transactions.len(), 1);
|
assert_eq!(state.transactions.len(), 1);
|
||||||
@ -334,14 +344,13 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
assert_eq!(curr_utxo_block, 960127);
|
assert_eq!(curr_utxo_block, 960127);
|
||||||
|
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_none());
|
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_none());
|
||||||
GhostWeaver::on_initialize(3u64);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3u64);
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_some());
|
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_some());
|
||||||
});
|
});
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
System::set_block_number(2u64);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||||
GhostWeaver::offchain_worker(2u64);
|
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||||
System::set_block_number(3u64);
|
|
||||||
|
|
||||||
let state = pool_state.read();
|
let state = pool_state.read();
|
||||||
assert_eq!(state.transactions.len(), 2);
|
assert_eq!(state.transactions.len(), 2);
|
||||||
@ -362,7 +371,8 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
assert_eq!(curr_evm_block, 25639556);
|
assert_eq!(curr_evm_block, 25639556);
|
||||||
|
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_none());
|
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_none());
|
||||||
GhostWeaver::on_initialize(4u64);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3u64);
|
||||||
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 4u64);
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_some());
|
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_some());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -372,6 +382,9 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
let evm_network_id = 1u32;
|
let evm_network_id = 1u32;
|
||||||
let utxo_network_id = 69u32;
|
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 pair = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
||||||
|
|
||||||
let new_evm_network_data = NetworkDataBuilder::default()
|
let new_evm_network_data = NetworkDataBuilder::default()
|
||||||
@ -406,11 +419,12 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
ext.register_extension(TransactionPoolExt::new(pool));
|
ext.register_extension(TransactionPoolExt::new(pool));
|
||||||
|
|
||||||
ext.execute_with(|| {
|
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 tapestry_draft = TapestryDraftBuilder::<crate::ExternalBlockNumber, u32>::default();
|
||||||
|
let evm_tapestry_draft = tapestry_draft.with_median_external(median_evm_block).build();
|
||||||
let evm_tapestry_draft = tapestry_draft.with_median_external(25639556).build();
|
let utxo_tapestry_draft = tapestry_draft.with_median_external(median_utxo_block).build();
|
||||||
|
|
||||||
let utxo_tapestry_draft = tapestry_draft.with_median_external(960129).build();
|
|
||||||
|
|
||||||
CurrentWeavingSession::<TestRuntime>::insert(&evm_network_id, evm_session);
|
CurrentWeavingSession::<TestRuntime>::insert(&evm_network_id, evm_session);
|
||||||
CurrentWeavingSession::<TestRuntime>::insert(&utxo_network_id, utxo_session);
|
CurrentWeavingSession::<TestRuntime>::insert(&utxo_network_id, utxo_session);
|
||||||
@ -466,8 +480,8 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
("Accept".into(), "application/json".into()),
|
("Accept".into(), "application/json".into()),
|
||||||
("Content-Type".into(), "application/json".into()),
|
("Content-Type".into(), "application/json".into()),
|
||||||
],
|
],
|
||||||
body: b"{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"getblockhash\",\"params\":[960129]}".to_vec(),
|
body: b"{\"id\":21,\"jsonrpc\":\"2.0\",\"method\":\"getblockhash\",\"params\":[960129]}".to_vec(),
|
||||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0000000000000000000091c72779c83d76dfa8149e950f3a5287377a9708d5c1\"}".to_vec()),
|
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":21,\"result\":\"0000000000000000000091c72779c83d76dfa8149e950f3a5287377a9708d5c1\"}".to_vec()),
|
||||||
sent: true,
|
sent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
@ -482,17 +496,16 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
("Authorization".into(), "Bearer new-api-token-123".into()),
|
("Authorization".into(), "Bearer new-api-token-123".into()),
|
||||||
],
|
],
|
||||||
// Match the EXACT field order: data first, then to
|
// Match the EXACT field order: data first, then to
|
||||||
body: b"{\"id\":2,\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{\"data\":\"0x00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000001873a84\",\"to\":\"0x02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9\"},\"latest\"]}".to_vec(),
|
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\":2,\"result\":\"0xf72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d0000000000000000000000000000000000000000000000000000000000000046\"}".to_vec()),
|
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":22,\"result\":\"0xf72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d0000000000000000000000000000000000000000000000000000000000000046\"}".to_vec()),
|
||||||
sent: true,
|
sent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
System::set_block_number(1u64);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||||
GhostWeaver::offchain_worker(1u64);
|
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||||
System::set_block_number(2u64);
|
|
||||||
|
|
||||||
let state = pool_state.read();
|
let state = pool_state.read();
|
||||||
assert_eq!(state.transactions.len(), 1);
|
assert_eq!(state.transactions.len(), 1);
|
||||||
@ -518,14 +531,15 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
GhostWeaver::on_initialize(3u64);
|
GhostWeaver::on_initialize(3u64);
|
||||||
let curr_state = LoomStates::<TestRuntime>::get(&utxo_network_id, &utxo_session);
|
let curr_state = LoomStates::<TestRuntime>::get(&utxo_network_id, &utxo_session);
|
||||||
|
|
||||||
assert_eq!(prev_state, H256::default());
|
assert_eq!(prev_state.root_hash, H256::default());
|
||||||
assert_eq!(curr_state, block_hash);
|
assert_eq!(curr_state.root_hash, block_hash);
|
||||||
|
assert_eq!(prev_state.at_block, 0);
|
||||||
|
assert_eq!(curr_state.at_block, median_utxo_block);
|
||||||
});
|
});
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
System::set_block_number(2u64);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||||
GhostWeaver::offchain_worker(2u64);
|
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||||
System::set_block_number(3u64);
|
|
||||||
|
|
||||||
let state = pool_state.read();
|
let state = pool_state.read();
|
||||||
assert_eq!(state.transactions.len(), 2);
|
assert_eq!(state.transactions.len(), 2);
|
||||||
@ -542,17 +556,20 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
assert_eq!(curr_weaving_state.next_session, evm_session + 1);
|
assert_eq!(curr_weaving_state.next_session, evm_session + 1);
|
||||||
|
|
||||||
let bytes = hex::decode("f72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d")
|
let bytes = hex::decode("f72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d")
|
||||||
.expect("UTXO block hash should be valid");
|
.expect("EVM block hash should be valid");
|
||||||
let block_hash = H256::from_slice(&bytes);
|
let block_hash = H256::from_slice(&bytes);
|
||||||
|
|
||||||
assert_eq!(curr_weaving_state.hash, block_hash);
|
assert_eq!(curr_weaving_state.hash, block_hash);
|
||||||
|
|
||||||
let prev_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
let prev_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
||||||
GhostWeaver::on_initialize(4u64);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3u64);
|
||||||
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 4u64);
|
||||||
let curr_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
let curr_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
||||||
|
|
||||||
assert_eq!(prev_state, H256::default());
|
assert_eq!(prev_state.root_hash, H256::default());
|
||||||
assert_eq!(curr_state, block_hash);
|
assert_eq!(curr_state.root_hash, block_hash);
|
||||||
|
assert_eq!(prev_state.at_block, 0);
|
||||||
|
assert_eq!(curr_state.at_block, median_evm_block);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,14 +652,18 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
|
GhostWeaver::on_initialize(1);
|
||||||
|
|
||||||
// https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract
|
// https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract
|
||||||
// getRoot: session 0, atBlock 11716130
|
// getRoot: session 0, atBlock 11716130
|
||||||
let session = 0;
|
let session = 0;
|
||||||
let root_string =
|
let root_string =
|
||||||
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129")
|
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129")
|
||||||
.expect("Root hex should be valid");
|
.expect("Root hex should be valid");
|
||||||
|
|
||||||
let expected_root = H256::from_slice(&root_string);
|
let expected_root = H256::from_slice(&root_string);
|
||||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root);
|
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;
|
let mut total_issuance = 0;
|
||||||
|
|
||||||
@ -755,7 +776,8 @@ fn should_successfully_pull_utxo_thread_and_mint_currency() {
|
|||||||
.expect("Bitcoin Root hex should be valid");
|
.expect("Bitcoin Root hex should be valid");
|
||||||
|
|
||||||
let expected_root = H256::from_slice(&block_hash);
|
let expected_root = H256::from_slice(&block_hash);
|
||||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root);
|
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 expected_receiver_bytes = hex::decode("1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e").unwrap();
|
||||||
let mut receiver_raw = [0u8; 32];
|
let mut receiver_raw = [0u8; 32];
|
||||||
@ -801,6 +823,117 @@ 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]
|
#[test]
|
||||||
fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
||||||
let pair1 = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
let pair1 = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
||||||
@ -817,7 +950,9 @@ fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
|||||||
let networks = vec![(network_id, new_network_data, 0u64)];
|
let networks = vec![(network_id, new_network_data, 0u64)];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
let current_substrate_block = 10;
|
let current_substrate_block = LOCK_BLOCK_EXPIRATION + 10;
|
||||||
|
|
||||||
|
GhostWeaver::on_initialize(current_substrate_block);
|
||||||
System::set_block_number(current_substrate_block + 1);
|
System::set_block_number(current_substrate_block + 1);
|
||||||
|
|
||||||
let tapestry_draft = TapestryDraftBuilder::default()
|
let tapestry_draft = TapestryDraftBuilder::default()
|
||||||
@ -865,8 +1000,96 @@ fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
|||||||
GhostWeaver::on_initialize(current_substrate_block);
|
GhostWeaver::on_initialize(current_substrate_block);
|
||||||
|
|
||||||
let saved_loom = LoomStates::<TestRuntime>::get(&network_id, current_session);
|
let saved_loom = LoomStates::<TestRuntime>::get(&network_id, current_session);
|
||||||
assert_ne!(saved_loom, target_hash);
|
assert_ne!(saved_loom.root_hash, target_hash);
|
||||||
assert_eq!(saved_loom, saved_loom);
|
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);
|
||||||
|
|
||||||
let updated_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
let updated_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
||||||
assert_eq!(updated_session, current_session);
|
assert_eq!(updated_session, current_session);
|
||||||
|
|||||||
@ -14,7 +14,6 @@ use ghost_helpers::{
|
|||||||
merkle_tree::verify_tree_proof,
|
merkle_tree::verify_tree_proof,
|
||||||
SubstrateBlake2Hasher, SubstrateKeccakHasher, UtxoSha2Hasher,
|
SubstrateBlake2Hasher, SubstrateKeccakHasher, UtxoSha2Hasher,
|
||||||
};
|
};
|
||||||
use ghost_traits::hashing::GhostHasher;
|
|
||||||
|
|
||||||
use crate::{ExternalBlockNumber, ThreadId, WeavingSession};
|
use crate::{ExternalBlockNumber, ThreadId, WeavingSession};
|
||||||
|
|
||||||
@ -37,22 +36,43 @@ const PROTOCOL_PREFIX: [u8; 7] = [0x69, 0x64, 0x2b, 0x5b, 0xb6, 0x66, 0xac];
|
|||||||
const PROTOCOL_PREFIX: [u8; 7] = [0x47, 0x48, 0x53, 0x54, 0x74, 0x6F, 0x3A];
|
const PROTOCOL_PREFIX: [u8; 7] = [0x47, 0x48, 0x53, 0x54, 0x74, 0x6F, 0x3A];
|
||||||
|
|
||||||
pub enum WeavingOk<NetworkId> {
|
pub enum WeavingOk<NetworkId> {
|
||||||
Block(ExternalBlockNumber, NetworkId),
|
Skipped(NetworkId),
|
||||||
|
Block(ExternalBlockNumber, u32, NetworkId),
|
||||||
Hash(ExternalBlockNumber, H256, WeavingSession, NetworkId),
|
Hash(ExternalBlockNumber, H256, WeavingSession, NetworkId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NetworkId> core::fmt::Display for WeavingOk<NetworkId>
|
impl<NetworkId> core::fmt::Debug for WeavingOk<NetworkId>
|
||||||
where
|
where
|
||||||
NetworkId: core::fmt::Debug,
|
NetworkId: core::fmt::Debug,
|
||||||
{
|
{
|
||||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Block(block, network_id) => write!(fmt, "Verified block height #{:?} found for network: {:?}.", block, network_id),
|
Self::Skipped(network_id) => write!(fmt, "Submission step skipped for network: {:?} based on probability distribution.", 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),
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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(
|
#[derive(
|
||||||
Default,
|
Default,
|
||||||
RuntimeDebug,
|
RuntimeDebug,
|
||||||
@ -350,8 +370,10 @@ where
|
|||||||
{
|
{
|
||||||
if EVM_MERKLE_DEPTH as usize != self.proof.len() { return None; }
|
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, _>(
|
let proof_valid = verify_tree_proof::<SubstrateKeccakHasher, _>(
|
||||||
&self.get_preimage_slice(network_id).to_fixed_bytes(),
|
&preimage_hash.to_fixed_bytes(),
|
||||||
self.proof.as_ref(),
|
self.proof.as_ref(),
|
||||||
root_hash,
|
root_hash,
|
||||||
self.proof_index,
|
self.proof_index,
|
||||||
@ -362,22 +384,17 @@ where
|
|||||||
Some((self.receiver.clone(), self.amount))
|
Some((self.receiver.clone(), self.amount))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_preimage_slice<NetworkId>(&self, network_id: NetworkId) -> H256
|
fn get_preimage_hash<NetworkId>(&self, network_id: NetworkId) -> Option<H256>
|
||||||
where
|
where
|
||||||
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
||||||
{
|
{
|
||||||
let slot_index_usize: usize = self.slot_index.unique_saturated_into();
|
let slot_index_usize: usize = self.slot_index.unique_saturated_into();
|
||||||
let mut slot_values: Vec<H256> = self.slots.to_vec();
|
|
||||||
|
|
||||||
match slot_values.get_mut(slot_index_usize) {
|
self.slots.get(slot_index_usize)
|
||||||
Some(slot) => {
|
.filter(|&&provided_hash| {
|
||||||
*slot = self.compute_arguments_hash(network_id);
|
provided_hash == self.compute_arguments_hash(network_id)
|
||||||
cumulative_hash::<SubstrateKeccakHasher, _>(slot_values)
|
})
|
||||||
}
|
.map(|_| cumulative_hash::<SubstrateKeccakHasher, _>(self.slots.iter()))
|
||||||
None => {
|
|
||||||
SubstrateKeccakHasher::empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_unique_key<NetworkId>(
|
pub fn get_unique_key<NetworkId>(
|
||||||
@ -483,7 +500,7 @@ impl UtxoThreadProof {
|
|||||||
|
|
||||||
pub fn verify_thread_proof<Balance>(
|
pub fn verify_thread_proof<Balance>(
|
||||||
&self,
|
&self,
|
||||||
root_hash: H256,
|
block_hash: H256,
|
||||||
gatekeeper_ref: &[u8],
|
gatekeeper_ref: &[u8],
|
||||||
) -> Option<(AccountId32, Balance)>
|
) -> Option<(AccountId32, Balance)>
|
||||||
where
|
where
|
||||||
@ -498,7 +515,7 @@ impl UtxoThreadProof {
|
|||||||
let is_chain_valid = verify_hash_ancestry::<UtxoSha2Hasher, _>(
|
let is_chain_valid = verify_hash_ancestry::<UtxoSha2Hasher, _>(
|
||||||
header_bytes,
|
header_bytes,
|
||||||
self.ancestry_headers.iter(),
|
self.ancestry_headers.iter(),
|
||||||
root_hash,
|
block_hash,
|
||||||
);
|
);
|
||||||
|
|
||||||
if !is_chain_valid { return None; }
|
if !is_chain_valid { return None; }
|
||||||
@ -507,13 +524,11 @@ impl UtxoThreadProof {
|
|||||||
self.getrawtransaction_bytes.as_ref()
|
self.getrawtransaction_bytes.as_ref()
|
||||||
).ok()?;
|
).ok()?;
|
||||||
|
|
||||||
let header = Header::<UtxoSha2Hasher>::try_from(
|
|
||||||
self.gettxproof_bytes.as_ref(),
|
|
||||||
).ok()?;
|
|
||||||
|
|
||||||
let txid_preimage = transaction.compute_txid()?;
|
let txid_preimage = transaction.compute_txid()?;
|
||||||
let root_hash = header.extract_proof(txid_preimage).ok()?;
|
Header::<UtxoSha2Hasher>::verify_utxo_merkle_proof(
|
||||||
if root_hash != header.merkle_root { return None; }
|
self.gettxproof_bytes.as_ref(),
|
||||||
|
txid_preimage,
|
||||||
|
).ok()?;
|
||||||
|
|
||||||
#[cfg(not(any(test, feature = "runtime-benchmarks")))]
|
#[cfg(not(any(test, feature = "runtime-benchmarks")))]
|
||||||
let destination_script = Transaction::<UtxoSha2Hasher>::convert_into_p2tr(gatekeeper_ref)?;
|
let destination_script = Transaction::<UtxoSha2Hasher>::convert_into_p2tr(gatekeeper_ref)?;
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
//! Autogenerated weights for `ghost_weaver`
|
//! Autogenerated weights for `ghost_weaver`
|
||||||
//!
|
//!
|
||||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||||
//! DATE: 2026-09-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||||
//! WORST CASE MAP SIZE: `1000000`
|
//! WORST CASE MAP SIZE: `1000000`
|
||||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
//! 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]`.
|
/// The range of component `a` is `[1, 300]`.
|
||||||
fn extend_warp(a: u32, ) -> Weight {
|
fn extend_warp(a: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `223 + a * (32 ±0)`
|
// Measured: `274 + a * (33 ±0)`
|
||||||
// Estimated: `3687 + a * (32 ±0)`
|
// Estimated: `3736 + a * (33 ±0)`
|
||||||
// Minimum execution time: 212_751_000 picoseconds.
|
// Minimum execution time: 229_711_000 picoseconds.
|
||||||
Weight::from_parts(215_022_916, 0)
|
Weight::from_parts(233_206_680, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3687))
|
.saturating_add(Weight::from_parts(0, 3736))
|
||||||
// Standard Error: 1_319
|
// Standard Error: 1_554
|
||||||
.saturating_add(Weight::from_parts(53_379, 0).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(66_095, 0).saturating_mul(a.into()))
|
||||||
.saturating_add(RocksDbWeight::get().reads(5))
|
.saturating_add(RocksDbWeight::get().reads(6))
|
||||||
.saturating_add(RocksDbWeight::get().writes(1))
|
.saturating_add(RocksDbWeight::get().writes(2))
|
||||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(0, 33).saturating_mul(a.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostWeaver::DisabledAuthorities` (r:1 w:0)
|
/// Storage: `GhostWeaver::DisabledAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostWeaver::DisabledAuthorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// 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]`.
|
/// The range of component `a` is `[1, 300]`.
|
||||||
fn weave_weft(a: u32, ) -> Weight {
|
fn weave_weft(a: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `518 + a * (32 ±0)`
|
// Measured: `569 + a * (33 ±0)`
|
||||||
// Estimated: `3982 + a * (32 ±0)`
|
// Estimated: `4031 + a * (33 ±0)`
|
||||||
// Minimum execution time: 212_751_000 picoseconds.
|
// Minimum execution time: 262_809_000 picoseconds.
|
||||||
Weight::from_parts(246_374_350, 0)
|
Weight::from_parts(267_769_707, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3982))
|
.saturating_add(Weight::from_parts(0, 4031))
|
||||||
// Standard Error: 1_865
|
// Standard Error: 1_865
|
||||||
.saturating_add(Weight::from_parts(38_601, 0).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(39_109, 0).saturating_mul(a.into()))
|
||||||
.saturating_add(RocksDbWeight::get().reads(6))
|
.saturating_add(RocksDbWeight::get().reads(8))
|
||||||
.saturating_add(RocksDbWeight::get().writes(2))
|
.saturating_add(RocksDbWeight::get().writes(3))
|
||||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(0, 33).saturating_mul(a.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
@ -119,12 +119,12 @@ impl WeightInfo for () {
|
|||||||
/// The range of component `a` is `[1, 144]`.
|
/// The range of component `a` is `[1, 144]`.
|
||||||
fn pull_utxo_thread(a: u32, ) -> Weight {
|
fn pull_utxo_thread(a: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `449`
|
// Measured: `500`
|
||||||
// Estimated: `3914`
|
// Estimated: `3965`
|
||||||
// Minimum execution time: 217_880_000 picoseconds.
|
// Minimum execution time: 217_481_000 picoseconds.
|
||||||
Weight::from_parts(217_119_201, 0)
|
Weight::from_parts(216_492_234, 0)
|
||||||
// Standard Error: 4_368
|
// Standard Error: 4_414
|
||||||
.saturating_add(Weight::from_parts(3_445_491, 0).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(3_376_569, 0).saturating_mul(a.into()))
|
||||||
.saturating_add(RocksDbWeight::get().reads(6))
|
.saturating_add(RocksDbWeight::get().reads(6))
|
||||||
.saturating_add(RocksDbWeight::get().writes(4))
|
.saturating_add(RocksDbWeight::get().writes(4))
|
||||||
}
|
}
|
||||||
@ -142,11 +142,11 @@ impl WeightInfo for () {
|
|||||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||||
fn pull_evm_thread() -> Weight {
|
fn pull_evm_thread() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `449`
|
// Measured: `500`
|
||||||
// Estimated: `3914`
|
// Estimated: `3965`
|
||||||
// Minimum execution time: 183_413_000 picoseconds.
|
// Minimum execution time: 176_861_000 picoseconds.
|
||||||
Weight::from_parts(186_271_000, 0)
|
Weight::from_parts(177_861_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3914))
|
.saturating_add(Weight::from_parts(0, 3965))
|
||||||
.saturating_add(RocksDbWeight::get().reads(6))
|
.saturating_add(RocksDbWeight::get().reads(6))
|
||||||
.saturating_add(RocksDbWeight::get().writes(4))
|
.saturating_add(RocksDbWeight::get().writes(4))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "casper-runtime"
|
name = "casper-runtime"
|
||||||
version = "4.0.14"
|
version = "4.0.20"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
description = "Runtime of the Casper Network"
|
description = "Runtime of the Casper Network"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
@ -75,6 +75,7 @@ ghost-networks = { workspace = true }
|
|||||||
ghost-governance = { workspace = true }
|
ghost-governance = { workspace = true }
|
||||||
ghost-weaver = { workspace = true }
|
ghost-weaver = { workspace = true }
|
||||||
ghost-exodus = { workspace = true }
|
ghost-exodus = { workspace = true }
|
||||||
|
ghost-exodus-runtime-api = { workspace = true }
|
||||||
ghost-sudo = { workspace = true }
|
ghost-sudo = { workspace = true }
|
||||||
ghost-traits = { workspace = true }
|
ghost-traits = { workspace = true }
|
||||||
ghost-helpers = { workspace = true }
|
ghost-helpers = { workspace = true }
|
||||||
@ -188,6 +189,7 @@ std = [
|
|||||||
"ghost-governance/std",
|
"ghost-governance/std",
|
||||||
"ghost-weaver/std",
|
"ghost-weaver/std",
|
||||||
"ghost-exodus/std",
|
"ghost-exodus/std",
|
||||||
|
"ghost-exodus-runtime-api/std",
|
||||||
"ghost-sudo/std",
|
"ghost-sudo/std",
|
||||||
"casper-runtime-constants/std",
|
"casper-runtime-constants/std",
|
||||||
"runtime-common/std",
|
"runtime-common/std",
|
||||||
|
|||||||
@ -69,6 +69,7 @@ pub use frame_system::Call as SystemCall;
|
|||||||
pub use pallet_balances::Call as BalancesCall;
|
pub use pallet_balances::Call as BalancesCall;
|
||||||
pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase};
|
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_weaver::sr25519::AuthorityId as GhostWeaverId;
|
||||||
use ghost_exodus::sr25519::AuthorityId as GhostExodusId;
|
use ghost_exodus::sr25519::AuthorityId as GhostExodusId;
|
||||||
|
|
||||||
@ -123,7 +124,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
spec_name: create_runtime_str!("casper"),
|
spec_name: create_runtime_str!("casper"),
|
||||||
impl_name: create_runtime_str!("casper-svengali"),
|
impl_name: create_runtime_str!("casper-svengali"),
|
||||||
authoring_version: 0,
|
authoring_version: 0,
|
||||||
spec_version: 7,
|
spec_version: 14,
|
||||||
impl_version: 0,
|
impl_version: 0,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
transaction_version: 1,
|
transaction_version: 1,
|
||||||
@ -906,6 +907,7 @@ parameter_types! {
|
|||||||
pub ExodusUnsignedPriority: TransactionPriority =
|
pub ExodusUnsignedPriority: TransactionPriority =
|
||||||
Perbill::from_percent(90) * TransactionPriority::MAX;
|
Perbill::from_percent(90) * TransactionPriority::MAX;
|
||||||
|
|
||||||
|
pub MaxExodusRequestCount: u32 = 32;
|
||||||
pub MaxAuthoritiesChunks: u32 = 32;
|
pub MaxAuthoritiesChunks: u32 = 32;
|
||||||
pub WeavingDelay: u64 = 50;
|
pub WeavingDelay: u64 = 50;
|
||||||
pub AttestationDelay: u64 = 25;
|
pub AttestationDelay: u64 = 25;
|
||||||
@ -949,6 +951,7 @@ impl ghost_exodus::Config for Runtime {
|
|||||||
type UnsignedPriority = ExodusUnsignedPriority;
|
type UnsignedPriority = ExodusUnsignedPriority;
|
||||||
type MaxAuthorities = MaxActiveValidators;
|
type MaxAuthorities = MaxActiveValidators;
|
||||||
type MaxAuthoritiesChunks = MaxAuthoritiesChunks;
|
type MaxAuthoritiesChunks = MaxAuthoritiesChunks;
|
||||||
|
type MaxExodusRequestCount = MaxExodusRequestCount;
|
||||||
|
|
||||||
type DkgRoundPeriod = ExodusDkgRoundPeriod;
|
type DkgRoundPeriod = ExodusDkgRoundPeriod;
|
||||||
type RemovalLimit = ExodusRemovalLimit;
|
type RemovalLimit = ExodusRemovalLimit;
|
||||||
@ -1032,7 +1035,10 @@ pub type SignedExtra = (
|
|||||||
|
|
||||||
/// All migrations that will run on the next runtime upgrade.
|
/// All migrations that will run on the next runtime upgrade.
|
||||||
/// Should be cleared after release.
|
/// Should be cleared after release.
|
||||||
pub type Migrations = ();
|
pub type Migrations = (
|
||||||
|
ghost_weaver::migrations::MigrateV0ToV1<Runtime>,
|
||||||
|
ghost_weaver::migrations::MigrateV1ToV2<Runtime>,
|
||||||
|
);
|
||||||
|
|
||||||
/// Unchecked extrinsic type as expected by this runtime.
|
/// Unchecked extrinsic type as expected by this runtime.
|
||||||
pub type UncheckedExtrinsic =
|
pub type UncheckedExtrinsic =
|
||||||
@ -1156,6 +1162,39 @@ 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 {
|
impl pallet_staking_runtime_api::StakingApi<Block, Balance, AccountId> for Runtime {
|
||||||
fn nominations_quota(balance: Balance) -> u32 {
|
fn nominations_quota(balance: Balance) -> u32 {
|
||||||
Staking::api_nominations_quota(balance)
|
Staking::api_nominations_quota(balance)
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
//! Autogenerated weights for `ghost_exodus`
|
//! Autogenerated weights for `ghost_exodus`
|
||||||
//!
|
//!
|
||||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||||
//! DATE: 2026-09-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||||
//! WORST CASE MAP SIZE: `1000000`
|
//! WORST CASE MAP SIZE: `1000000`
|
||||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||||
@ -46,252 +46,232 @@ use core::marker::PhantomData;
|
|||||||
/// Weight functions for `ghost_exodus`.
|
/// Weight functions for `ghost_exodus`.
|
||||||
pub struct WeightInfo<T>(PhantomData<T>);
|
pub struct WeightInfo<T>(PhantomData<T>);
|
||||||
impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
|
impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:1)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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 {
|
fn register_round0_package() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `351`
|
// Measured: `365`
|
||||||
// Estimated: `3816`
|
// Estimated: `3830`
|
||||||
// Minimum execution time: 240_813_000 picoseconds.
|
// Minimum execution time: 240_843_000 picoseconds.
|
||||||
Weight::from_parts(243_523_000, 0)
|
Weight::from_parts(243_855_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3816))
|
.saturating_add(Weight::from_parts(0, 3830))
|
||||||
.saturating_add(T::DbWeight::get().reads(4))
|
.saturating_add(T::DbWeight::get().reads(4))
|
||||||
.saturating_add(T::DbWeight::get().writes(3))
|
.saturating_add(T::DbWeight::get().writes(2))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Round1Packages` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::Round1Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Round1Packages` (`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`)
|
||||||
/// The range of component `c` is `[4, 300]`.
|
/// The range of component `c` is `[4, 300]`.
|
||||||
fn register_round1_package(c: u32, ) -> Weight {
|
fn register_round1_package(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `391 + c * (32 ±0)`
|
// Measured: `405 + c * (32 ±0)`
|
||||||
// Estimated: `3856 + c * (32 ±0)`
|
// Estimated: `3870 + c * (32 ±0)`
|
||||||
// Minimum execution time: 1_356_791_000 picoseconds.
|
// Minimum execution time: 1_349_108_000 picoseconds.
|
||||||
Weight::from_parts(1_221_760_215, 0)
|
Weight::from_parts(1_224_956_354, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3856))
|
.saturating_add(Weight::from_parts(0, 3870))
|
||||||
// Standard Error: 16_481
|
// Standard Error: 14_930
|
||||||
.saturating_add(Weight::from_parts(33_163_393, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(33_204_477, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(T::DbWeight::get().reads(6))
|
.saturating_add(T::DbWeight::get().reads(5))
|
||||||
.saturating_add(T::DbWeight::get().writes(2))
|
.saturating_add(T::DbWeight::get().writes(1))
|
||||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Round2Packages` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::Round2Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Round2Packages` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// The range of component `c` is `[1, 37]`.
|
/// 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_encrypted_round2_packages(c: u32, ) -> Weight {
|
fn register_encrypted_round2_packages(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `317 + c * (257 ±0)`
|
// Measured: `332 + c * (32 ±0)`
|
||||||
// Estimated: `3783 + c * (257 ±0)`
|
// Estimated: `3797 + c * (32 ±0)`
|
||||||
// Minimum execution time: 254_590_000 picoseconds.
|
// Minimum execution time: 245_305_000 picoseconds.
|
||||||
Weight::from_parts(258_091_105, 0)
|
Weight::from_parts(253_863_353, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3783))
|
.saturating_add(Weight::from_parts(0, 3797))
|
||||||
// Standard Error: 25_082
|
// Standard Error: 3_527
|
||||||
.saturating_add(Weight::from_parts(6_595_878, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(810_623, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(T::DbWeight::get().reads(5))
|
.saturating_add(T::DbWeight::get().reads(4))
|
||||||
.saturating_add(T::DbWeight::get().writes(2))
|
.saturating_add(T::DbWeight::get().writes(1))
|
||||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Complaints` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::Complaints` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Complaints` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// The range of component `c` is `[1, 37]`.
|
/// 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 {
|
fn register_round3_complaints(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `317 + c * (257 ±0)`
|
// Measured: `332 + c * (32 ±0)`
|
||||||
// Estimated: `3783 + c * (257 ±0)`
|
// Estimated: `3797 + c * (32 ±0)`
|
||||||
// Minimum execution time: 240_888_000 picoseconds.
|
// Minimum execution time: 238_391_000 picoseconds.
|
||||||
Weight::from_parts(245_480_975, 0)
|
Weight::from_parts(242_937_380, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3783))
|
.saturating_add(Weight::from_parts(0, 3797))
|
||||||
// Standard Error: 13_733
|
// Standard Error: 1_789
|
||||||
.saturating_add(Weight::from_parts(371_161, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(39_316, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(T::DbWeight::get().reads(5))
|
.saturating_add(T::DbWeight::get().reads(4))
|
||||||
.saturating_add(T::DbWeight::get().writes(2))
|
.saturating_add(T::DbWeight::get().writes(1))
|
||||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::Justifications` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::Justifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::Justifications` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// The range of component `c` is `[1, 37]`.
|
/// 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 {
|
fn register_round4_justifications(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `317 + c * (257 ±0)`
|
// Measured: `332 + c * (32 ±0)`
|
||||||
// Estimated: `3783 + c * (257 ±0)`
|
// Estimated: `3797 + c * (32 ±0)`
|
||||||
// Minimum execution time: 251_521_000 picoseconds.
|
// Minimum execution time: 245_916_000 picoseconds.
|
||||||
Weight::from_parts(253_053_636, 0)
|
Weight::from_parts(251_070_206, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3783))
|
.saturating_add(Weight::from_parts(0, 3797))
|
||||||
// Standard Error: 14_691
|
// Standard Error: 2_152
|
||||||
.saturating_add(Weight::from_parts(4_101_872, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(508_508, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(T::DbWeight::get().reads(5))
|
.saturating_add(T::DbWeight::get().reads(4))
|
||||||
.saturating_add(T::DbWeight::get().writes(2))
|
.saturating_add(T::DbWeight::get().writes(1))
|
||||||
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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: 265_187_000 picoseconds.
|
|
||||||
Weight::from_parts(269_124_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)
|
/// Storage: `GhostExodus::QualificationAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
/// Storage: `GhostExodus::Verifications` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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))
|
||||||
|
.saturating_add(T::DbWeight::get().reads(5))
|
||||||
|
.saturating_add(T::DbWeight::get().writes(2))
|
||||||
|
}
|
||||||
|
/// 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::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::VerifyingKeyConsensus` (r:1 w:0)
|
/// Storage: `GhostExodus::VerifyingKeyConsensus` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::VerifyingKeyConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::VerifyingShares` (r:1 w:1)
|
/// Storage: `GhostExodus::VerifyingShares` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::VerifyingShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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]`.
|
/// The range of component `c` is `[1, 9]`.
|
||||||
fn register_round6_public_share_package(c: u32, ) -> Weight {
|
fn register_round6_public_share_package(c: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `0 + c * (770 ±0)`
|
// Measured: `0 + c * (770 ±0)`
|
||||||
// Estimated: `1551 + c * (1019 ±27)`
|
// Estimated: `1698 + c * (1019 ±27)`
|
||||||
// Minimum execution time: 284_558_000 picoseconds.
|
// Minimum execution time: 283_863_000 picoseconds.
|
||||||
Weight::from_parts(284_117_484, 0)
|
Weight::from_parts(286_691_978, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 1551))
|
.saturating_add(Weight::from_parts(0, 1698))
|
||||||
// Standard Error: 74_361
|
// Standard Error: 85_685
|
||||||
.saturating_add(Weight::from_parts(3_551_271, 0).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(2_854_037, 0).saturating_mul(c.into()))
|
||||||
.saturating_add(T::DbWeight::get().reads(7))
|
.saturating_add(T::DbWeight::get().reads(6))
|
||||||
.saturating_add(T::DbWeight::get().writes(3))
|
.saturating_add(T::DbWeight::get().writes(2))
|
||||||
.saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into()))
|
.saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::ActiveDkgAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
/// Storage: `GhostExodus::NonceCommitments` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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::RoastSessionStates` (r:1 w:1)
|
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::RoastSessionStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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 {
|
fn register_nonce_commitment() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `627`
|
// Measured: `633`
|
||||||
// Estimated: `4092`
|
// Estimated: `4098`
|
||||||
// Minimum execution time: 315_066_000 picoseconds.
|
// Minimum execution time: 369_666_000 picoseconds.
|
||||||
Weight::from_parts(318_561_000, 0)
|
Weight::from_parts(373_163_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 4092))
|
.saturating_add(Weight::from_parts(0, 4098))
|
||||||
.saturating_add(T::DbWeight::get().reads(8))
|
.saturating_add(T::DbWeight::get().reads(8))
|
||||||
.saturating_add(T::DbWeight::get().writes(5))
|
.saturating_add(T::DbWeight::get().writes(4))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::ActiveDkgAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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::RoastSessions` (r:1 w:0)
|
/// Storage: `GhostExodus::RoastSessions` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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::ExodusRequests` (r:1 w:0)
|
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::GroupCommitters` (r:1 w:1)
|
/// Storage: `GhostExodus::GroupCommitters` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::GroupCommitters` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::GroupCommitmentsConsensus` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
fn register_group_commitment() -> Weight {
|
fn register_group_commitment() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `992`
|
// Measured: `1030`
|
||||||
// Estimated: `4457`
|
// Estimated: `4495`
|
||||||
// Minimum execution time: 338_644_000 picoseconds.
|
// Minimum execution time: 339_569_000 picoseconds.
|
||||||
Weight::from_parts(343_954_000, 0)
|
Weight::from_parts(341_788_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 4457))
|
.saturating_add(Weight::from_parts(0, 4495))
|
||||||
.saturating_add(T::DbWeight::get().reads(10))
|
.saturating_add(T::DbWeight::get().reads(9))
|
||||||
.saturating_add(T::DbWeight::get().writes(4))
|
.saturating_add(T::DbWeight::get().writes(3))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:0)
|
/// Storage: `GhostNetworks::NetworkTypes` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkTypes` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
/// Storage: `GhostExodus::ActiveDkgAuthorities` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::ActiveDkgAuthorities` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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::RoastSessions` (r:1 w:1)
|
/// Storage: `GhostExodus::RoastSessions` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::RoastSessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ExodusActivity` (r:1 w:1)
|
/// Storage: `GhostExodus::RoastSessionStates` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::ExodusActivity` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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::GroupCommitmentsConsensus` (r:1 w:1)
|
/// Storage: `GhostExodus::GroupCommitmentsConsensus` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::GroupCommitmentsConsensus` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ExodusSignedGovernance` (r:1 w:1)
|
/// Storage: `GhostExodus::ExodusSignedGovernance` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::ExodusSignedGovernance` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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)
|
/// Storage: `GhostExodus::NonceCommitments` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::NonceCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::NonceCommitments` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::VerifyingShares` (r:1 w:0)
|
/// Storage: `GhostExodus::VerifyingShares` (r:1 w:0)
|
||||||
@ -306,13 +286,13 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
|
|||||||
/// Proof: `GhostExodus::GroupCommitters` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::GroupCommitters` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
fn register_signature_share() -> Weight {
|
fn register_signature_share() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `11299`
|
// Measured: `11337`
|
||||||
// Estimated: `14764`
|
// Estimated: `14802`
|
||||||
// Minimum execution time: 3_968_938_000 picoseconds.
|
// Minimum execution time: 4_046_065_000 picoseconds.
|
||||||
Weight::from_parts(3_975_088_000, 0)
|
Weight::from_parts(4_059_064_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 14764))
|
.saturating_add(Weight::from_parts(0, 14802))
|
||||||
.saturating_add(T::DbWeight::get().reads(15))
|
.saturating_add(T::DbWeight::get().reads(14))
|
||||||
.saturating_add(T::DbWeight::get().writes(9))
|
.saturating_add(T::DbWeight::get().writes(8))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostExodus::CounterForExodusRequests` (r:1 w:1)
|
/// Storage: `GhostExodus::CounterForExodusRequests` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::CounterForExodusRequests` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::CounterForExodusRequests` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||||
@ -324,17 +304,17 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
|
|||||||
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
/// Storage: `GhostExodus::QualificationDkgState` (r:1 w:0)
|
||||||
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::QualificationDkgState` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::CurrentExodus` (r:1 w:1)
|
/// Storage: `GhostExodus::CurrentExodusSessions` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::CurrentExodus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::CurrentExodusSessions` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
/// Storage: `GhostExodus::ExodusRequests` (r:1 w:1)
|
||||||
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostExodus::ExodusRequests` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
fn register_evm_bridge_out_exodus() -> Weight {
|
fn register_evm_bridge_out_exodus() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `448`
|
// Measured: `457`
|
||||||
// Estimated: `3913`
|
// Estimated: `3922`
|
||||||
// Minimum execution time: 191_374_000 picoseconds.
|
// Minimum execution time: 195_417_000 picoseconds.
|
||||||
Weight::from_parts(192_991_000, 0)
|
Weight::from_parts(196_842_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3913))
|
.saturating_add(Weight::from_parts(0, 3922))
|
||||||
.saturating_add(T::DbWeight::get().reads(7))
|
.saturating_add(T::DbWeight::get().reads(7))
|
||||||
.saturating_add(T::DbWeight::get().writes(5))
|
.saturating_add(T::DbWeight::get().writes(5))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
//! Autogenerated weights for `ghost_governance`
|
//! Autogenerated weights for `ghost_governance`
|
||||||
//!
|
//!
|
||||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||||
//! DATE: 2026-09-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||||
//! WORST CASE MAP SIZE: `1000000`
|
//! WORST CASE MAP SIZE: `1000000`
|
||||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||||
@ -61,11 +61,11 @@ impl<T: frame_system::Config> ghost_governance::WeightInfo for WeightInfo<T> {
|
|||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `283`
|
// Measured: `283`
|
||||||
// Estimated: `3748`
|
// Estimated: `3748`
|
||||||
// Minimum execution time: 229_254_000 picoseconds.
|
// Minimum execution time: 224_852_000 picoseconds.
|
||||||
Weight::from_parts(229_992_093, 0)
|
Weight::from_parts(225_347_733, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3748))
|
.saturating_add(Weight::from_parts(0, 3748))
|
||||||
// Standard Error: 25_680
|
// Standard Error: 21_234
|
||||||
.saturating_add(Weight::from_parts(1_874_433, 0).saturating_mul(p.into()))
|
.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().reads(5))
|
||||||
.saturating_add(T::DbWeight::get().writes(5))
|
.saturating_add(T::DbWeight::get().writes(5))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
//! Autogenerated weights for `ghost_weaver`
|
//! Autogenerated weights for `ghost_weaver`
|
||||||
//!
|
//!
|
||||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
|
||||||
//! DATE: 2026-09-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
//! DATE: 2026-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||||
//! WORST CASE MAP SIZE: `1000000`
|
//! WORST CASE MAP SIZE: `1000000`
|
||||||
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
|
||||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
|
||||||
@ -46,34 +46,40 @@ use core::marker::PhantomData;
|
|||||||
/// Weight functions for `ghost_weaver`.
|
/// Weight functions for `ghost_weaver`.
|
||||||
pub struct WeightInfo<T>(PhantomData<T>);
|
pub struct WeightInfo<T>(PhantomData<T>);
|
||||||
impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
|
impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
|
||||||
/// 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)
|
/// Storage: `GhostWeaver::Authorities` (r:1 w:0)
|
||||||
/// Proof: `GhostWeaver::Authorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// 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: `GhostNetworks::Networks` (r:1 w:0)
|
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostWeaver::TapestryDrafts` (r:1 w:0)
|
/// Storage: `GhostWeaver::TapestryDrafts` (r:1 w:0)
|
||||||
/// Proof: `GhostWeaver::TapestryDrafts` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// 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]`.
|
/// The range of component `a` is `[1, 300]`.
|
||||||
fn extend_warp(a: u32, ) -> Weight {
|
fn extend_warp(a: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `223 + a * (32 ±0)`
|
// Measured: `274 + a * (33 ±0)`
|
||||||
// Estimated: `3687 + a * (32 ±0)`
|
// Estimated: `3736 + a * (33 ±0)`
|
||||||
// Minimum execution time: 212_751_000 picoseconds.
|
// Minimum execution time: 229_711_000 picoseconds.
|
||||||
Weight::from_parts(215_022_916, 0)
|
Weight::from_parts(235_206_680, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3687))
|
.saturating_add(Weight::from_parts(0, 3736))
|
||||||
// Standard Error: 1_319
|
// Standard Error: 1_554
|
||||||
.saturating_add(Weight::from_parts(53_379, 0).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(66_905, 0).saturating_mul(a.into()))
|
||||||
.saturating_add(T::DbWeight::get().reads(5))
|
.saturating_add(T::DbWeight::get().reads(6))
|
||||||
.saturating_add(T::DbWeight::get().writes(1))
|
.saturating_add(T::DbWeight::get().writes(2))
|
||||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(0, 33).saturating_mul(a.into()))
|
||||||
}
|
}
|
||||||
/// 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)
|
/// Storage: `GhostWeaver::Authorities` (r:1 w:0)
|
||||||
/// Proof: `GhostWeaver::Authorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
|
/// 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: `GhostNetworks::Networks` (r:1 w:0)
|
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
/// Storage: `GhostWeaver::TapestryDrafts` (r:1 w:0)
|
/// Storage: `GhostWeaver::TapestryDrafts` (r:1 w:0)
|
||||||
@ -85,16 +91,16 @@ impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
|
|||||||
/// The range of component `a` is `[1, 300]`.
|
/// The range of component `a` is `[1, 300]`.
|
||||||
fn weave_weft(a: u32, ) -> Weight {
|
fn weave_weft(a: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `518 + a * (32 ±0)`
|
// Measured: `569 + a * (33 ±0)`
|
||||||
// Estimated: `3982 + a * (32 ±0)`
|
// Estimated: `4031 + a * (33 ±0)`
|
||||||
// Minimum execution time: 243_006_000 picoseconds.
|
// Minimum execution time: 262_809_000 picoseconds.
|
||||||
Weight::from_parts(246_374_350, 0)
|
Weight::from_parts(267_769_707, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3982))
|
.saturating_add(Weight::from_parts(0, 4031))
|
||||||
// Standard Error: 1_865
|
// Standard Error: 2_375
|
||||||
.saturating_add(Weight::from_parts(38_601, 0).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(39_109, 0).saturating_mul(a.into()))
|
||||||
.saturating_add(T::DbWeight::get().reads(6))
|
.saturating_add(T::DbWeight::get().reads(8))
|
||||||
.saturating_add(T::DbWeight::get().writes(2))
|
.saturating_add(T::DbWeight::get().writes(3))
|
||||||
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(0, 33).saturating_mul(a.into()))
|
||||||
}
|
}
|
||||||
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
|
||||||
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||||
@ -111,13 +117,13 @@ impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
|
|||||||
/// The range of component `a` is `[1, 144]`.
|
/// The range of component `a` is `[1, 144]`.
|
||||||
fn pull_utxo_thread(a: u32, ) -> Weight {
|
fn pull_utxo_thread(a: u32, ) -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `449`
|
// Measured: `500`
|
||||||
// Estimated: `3914`
|
// Estimated: `3965`
|
||||||
// Minimum execution time: 217_880_000 picoseconds.
|
// Minimum execution time: 217_481_000 picoseconds.
|
||||||
Weight::from_parts(217_119_201, 0)
|
Weight::from_parts(216_492_234, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3914))
|
.saturating_add(Weight::from_parts(0, 3965))
|
||||||
// Standard Error: 5_460
|
// Standard Error: 4_414
|
||||||
.saturating_add(Weight::from_parts(3_445_491, 0).saturating_mul(a.into()))
|
.saturating_add(Weight::from_parts(3_376_569, 0).saturating_mul(a.into()))
|
||||||
.saturating_add(T::DbWeight::get().reads(6))
|
.saturating_add(T::DbWeight::get().reads(6))
|
||||||
.saturating_add(T::DbWeight::get().writes(4))
|
.saturating_add(T::DbWeight::get().writes(4))
|
||||||
}
|
}
|
||||||
@ -135,11 +141,11 @@ impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
|
|||||||
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
|
||||||
fn pull_evm_thread() -> Weight {
|
fn pull_evm_thread() -> Weight {
|
||||||
// Proof Size summary in bytes:
|
// Proof Size summary in bytes:
|
||||||
// Measured: `449`
|
// Measured: `500`
|
||||||
// Estimated: `3914`
|
// Estimated: `3965`
|
||||||
// Minimum execution time: 183_413_000 picoseconds.
|
// Minimum execution time: 176_861_000 picoseconds.
|
||||||
Weight::from_parts(186_271_000, 0)
|
Weight::from_parts(177_918_000, 0)
|
||||||
.saturating_add(Weight::from_parts(0, 3914))
|
.saturating_add(Weight::from_parts(0, 3965))
|
||||||
.saturating_add(T::DbWeight::get().reads(6))
|
.saturating_add(T::DbWeight::get().reads(6))
|
||||||
.saturating_add(T::DbWeight::get().writes(4))
|
.saturating_add(T::DbWeight::get().writes(4))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,10 +20,11 @@ MORDOR_RPC=(
|
|||||||
HOODI_RPC=(
|
HOODI_RPC=(
|
||||||
"https://rpc.hoodi.ethpandaops.io"
|
"https://rpc.hoodi.ethpandaops.io"
|
||||||
"https://0xrpc.io/hoodi"
|
"https://0xrpc.io/hoodi"
|
||||||
"https://ethereum-hoodi.gateway.tatum.io"
|
|
||||||
"https://rpc.sentio.xyz/hoodi"
|
"https://rpc.sentio.xyz/hoodi"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
HOODI_GATEKEEPER="0xc9D5f50e17eeEAF39E0D0cDbbcF4B04FA4A4Bbd6"
|
||||||
|
|
||||||
show_help() {
|
show_help() {
|
||||||
cat << EOF
|
cat << EOF
|
||||||
Usage: $(basename "$0") [OPTIONS]
|
Usage: $(basename "$0") [OPTIONS]
|
||||||
@ -58,20 +59,66 @@ spinner() {
|
|||||||
tput cnorm
|
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() {
|
check_network() {
|
||||||
local name=$1
|
local name=$1
|
||||||
shift
|
local gatekeeper=$2
|
||||||
|
shift 2
|
||||||
local rpcs=("$@")
|
local rpcs=("$@")
|
||||||
local target_dir="${OUT_DIR:-/tmp}"
|
local target_dir="${OUT_DIR:-/tmp}"
|
||||||
local tmp_file="${target_dir}/$(date +%s)_${name,,}"
|
local tmp_file="${target_dir}/$(date +%s)_${name,,}"
|
||||||
|
|
||||||
|
local root_width=66
|
||||||
|
local sess_width=6
|
||||||
local max_len=0
|
local max_len=0
|
||||||
for e in "${rpcs[@]}"; do (( ${#e} > max_len )) && max_len=${#e}; done
|
for e in "${rpcs[@]}"; do (( ${#e} > max_len )) && max_len=${#e}; done
|
||||||
[[ $max_len -lt 20 ]] && max_len=20
|
[[ $max_len -lt 20 ]] && max_len=20
|
||||||
|
|
||||||
local total_width=$(( max_len + 32 ))
|
local total_width=$(( max_len + 95 ))
|
||||||
local line=$(printf "%.0s-" $(seq 1 $total_width))
|
local line=$(printf "%.0s-" $(seq 1 $total_width))
|
||||||
local header_fmt="| %-${max_len}s | %-12s | %-10s |\n"
|
local header_fmt="| %-${max_len}s | %-10s | %-${root_width}s | %-${sess_width}s |\n"
|
||||||
|
|
||||||
(
|
(
|
||||||
for endpoint in "${rpcs[@]}"; do
|
for endpoint in "${rpcs[@]}"; do
|
||||||
@ -80,11 +127,15 @@ check_network() {
|
|||||||
hex=$(echo "$res_b" | grep -o '"result":"[^"]*' | cut -d'"' -f4)
|
hex=$(echo "$res_b" | grep -o '"result":"[^"]*' | cut -d'"' -f4)
|
||||||
[[ -n "$hex" && "$hex" != "null" ]] && blk=$(printf "%d" "$hex") || blk="ERROR"
|
[[ -n "$hex" && "$hex" != "null" ]] && blk=$(printf "%d" "$hex") || blk="ERROR"
|
||||||
|
|
||||||
res_l=$(curl -s -X POST -H "Content-Type: application/json" --max-time 10 \
|
root="N/A"
|
||||||
--data '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x1","toBlock":"0x2"}],"id":1}' "$endpoint")
|
if [[ -n "$blk" && "$blk" != "ERROR" ]]; then
|
||||||
echo "$res_l" | grep -q '"result"' && ev="YES" || ev="NO"
|
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
|
||||||
|
|
||||||
echo "$endpoint|$blk|$ev"
|
echo "$endpoint|$blk|$root"
|
||||||
done
|
done
|
||||||
) > "$tmp_file" &
|
) > "$tmp_file" &
|
||||||
|
|
||||||
@ -94,10 +145,17 @@ check_network() {
|
|||||||
spinner $worker_pid "$name"
|
spinner $worker_pid "$name"
|
||||||
|
|
||||||
local table_output="$line\n"
|
local table_output="$line\n"
|
||||||
table_output+=$(printf "$header_fmt" "Endpoint" "Block" "Events")"\n"
|
table_output+=$(printf "$header_fmt" "Endpoint" "Block" "Merkle Root" "Session")"\n"
|
||||||
table_output+="$line\n"
|
table_output+="$line\n"
|
||||||
while IFS="|" read -r url blk ev; do
|
while IFS="|" read -r url blk root; do
|
||||||
table_output+=$(printf "$header_fmt" "$url" "$blk" "$ev")"\n"
|
if [[ "$root" == *" "* ]]; then
|
||||||
|
hash="${root%% *}"
|
||||||
|
sess="${root##* }"
|
||||||
|
else
|
||||||
|
hash="$root"
|
||||||
|
sess="-"
|
||||||
|
fi
|
||||||
|
table_output+=$(printf "$header_fmt" "$url" "$blk" "$hash" "$sess")"\n"
|
||||||
done < "$tmp_file"
|
done < "$tmp_file"
|
||||||
table_output+="$line"
|
table_output+="$line"
|
||||||
|
|
||||||
@ -111,6 +169,7 @@ check_network() {
|
|||||||
CHOSEN_CHAIN=""
|
CHOSEN_CHAIN=""
|
||||||
BASE_OUT_DIR=""
|
BASE_OUT_DIR=""
|
||||||
CUSTOM_RPCS=""
|
CUSTOM_RPCS=""
|
||||||
|
SELECTOR="d4be7935"
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@ -132,14 +191,14 @@ if [[ -n "$CUSTOM_RPCS" ]]; then
|
|||||||
check_network "Custom" "${USER_RPC_ARRAY[@]}"
|
check_network "Custom" "${USER_RPC_ARRAY[@]}"
|
||||||
else
|
else
|
||||||
if [ "$CHOSEN_CHAIN" == "sepolia" ]; then
|
if [ "$CHOSEN_CHAIN" == "sepolia" ]; then
|
||||||
check_network "Sepolia" "${SEPOLIA_RPC[@]}"
|
check_network "Sepolia" "$SEPOLIA_GATEKEEPER" "${HOODI_RPC[@]}"
|
||||||
elif [ "$CHOSEN_CHAIN" == "mordor" ]; then
|
elif [ "$CHOSEN_CHAIN" == "mordor" ]; then
|
||||||
check_network "Mordor" "${MORDOR_RPC[@]}"
|
check_network "Mordor" "$MORDOR_GATEKEEPER" "${HOODI_RPC[@]}"
|
||||||
elif [ "$CHOSEN_CHAIN" == "hoodi" ]; then
|
elif [ "$CHOSEN_CHAIN" == "hoodi" ]; then
|
||||||
check_network "Hoodi" "${HOODI_RPC[@]}"
|
check_network "Hoodi" "$HOODI_GATEKEEPER" "${HOODI_RPC[@]}"
|
||||||
else
|
else
|
||||||
check_network "Sepolia" "${SEPOLIA_RPC[@]}"
|
check_network "Sepolia" "$SEPOLIA_GATEKEEPER" "${SEPOLIA_RPC[@]}"
|
||||||
check_network "Mordor" "${MORDOR_RPC[@]}"
|
check_network "Mordor" "$MORDOR_GATEKEEPER" "${MORDOR_RPC[@]}"
|
||||||
check_network "Hoodi" "${HOODI_RPC[@]}"
|
check_network "Hoodi" "$HOODI_GATEKEEPER" "${HOODI_RPC[@]}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -9,6 +9,7 @@ UNIT_FILE=false
|
|||||||
SKIP_BUILD=false
|
SKIP_BUILD=false
|
||||||
SET_ENVIRONMENT=false
|
SET_ENVIRONMENT=false
|
||||||
VALIDATE=false
|
VALIDATE=false
|
||||||
|
FIX_WEAVER_KEYSTORE=false
|
||||||
EXECUTABLE_PATH="/usr/bin/"
|
EXECUTABLE_PATH="/usr/bin/"
|
||||||
SPECIFICATION_PATH="/etc/ghost/"
|
SPECIFICATION_PATH="/etc/ghost/"
|
||||||
BASE_PATH="/var/lib/ghost"
|
BASE_PATH="/var/lib/ghost"
|
||||||
@ -120,7 +121,8 @@ help() {
|
|||||||
echo -e "-s, --base-path\n\tPath to the folder with chain database ('/var/lib/ghost' is default)."
|
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 "-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 "-n, --specification-name\n\tSpecification name to be used ('casper' is default)."
|
||||||
echo -e "-g, --generate-genesis\n\tGenerate keys to participate in the genesis file."
|
echo -e "--generate-genesis\n\tGenerate keys to participate in the genesis file."
|
||||||
|
echo -e "--fix-weaver-keystore\n\tFix keystore prefixes (wevr -> weav) to ensure the offchain worker can find the key."
|
||||||
echo -e "--hard-reset-i-know-what-im-doing\n\tWill completely remove ledger along with associated session keys."
|
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."
|
echo -e "-h, --help\n\tPrints help information."
|
||||||
}
|
}
|
||||||
@ -192,9 +194,12 @@ while [ $# -gt 0 ]; do
|
|||||||
--hard-reset-i-know-what-im-doing)
|
--hard-reset-i-know-what-im-doing)
|
||||||
HARD_RESET=true
|
HARD_RESET=true
|
||||||
;;
|
;;
|
||||||
--generate-genesis|-g)
|
--generate-genesis)
|
||||||
GENERATE_GENESIS=true
|
GENERATE_GENESIS=true
|
||||||
;;
|
;;
|
||||||
|
--fix-weaver-keystore)
|
||||||
|
FIX_WEAVER_KEYSTORE=true
|
||||||
|
;;
|
||||||
--help|-h)
|
--help|-h)
|
||||||
help
|
help
|
||||||
exit 0
|
exit 0
|
||||||
@ -460,7 +465,7 @@ if [ $CHECK_KEYS = true ]; then
|
|||||||
rpc_endpoint="${rpc_endpoint:-localhost:9945}"
|
rpc_endpoint="${rpc_endpoint:-localhost:9945}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for type in $(echo audi babe gran wevr exds); do
|
for type in $(echo audi babe gran weav exds); do
|
||||||
echo "[+] parsing session key for [$type]"
|
echo "[+] parsing session key for [$type]"
|
||||||
scheme="sr25519"
|
scheme="sr25519"
|
||||||
if [ $type = "gran" ]; then
|
if [ $type = "gran" ]; then
|
||||||
@ -528,6 +533,51 @@ if [ $UNIT_FILE = true ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ $FIX_WEAVER_KEYSTORE = true ]; then
|
||||||
|
echo "[+] Starting keystore prefix fix (wevr -> weav)..."
|
||||||
|
|
||||||
|
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="77657672" # "wevr"
|
||||||
|
CORRECT_PREFIX="77656176" # "weav"
|
||||||
|
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
|
if [ "$GENERATE_GENESIS" = true ]; then
|
||||||
echo "[+] Generating keys for genesis configuration..."
|
echo "[+] Generating keys for genesis configuration..."
|
||||||
|
|
||||||
@ -561,7 +611,7 @@ if [ "$GENERATE_GENESIS" = true ]; then
|
|||||||
BABE_HEX=$(ghost key inspect --scheme=sr25519 "$SESSION_SEED//babe" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
BABE_HEX=$(ghost key inspect --scheme=sr25519 "$SESSION_SEED//babe" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
||||||
GRAN_HEX=$(ghost key inspect --scheme=ed25519 "$SESSION_SEED//gran" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
GRAN_HEX=$(ghost key inspect --scheme=ed25519 "$SESSION_SEED//gran" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
||||||
AUDI_HEX=$(ghost key inspect --scheme=sr25519 "$SESSION_SEED//audi" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
AUDI_HEX=$(ghost key inspect --scheme=sr25519 "$SESSION_SEED//audi" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
||||||
WEVR_HEX=$(ghost key inspect --scheme=sr25519 "$SESSION_SEED//wevr" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
WEAV_HEX=$(ghost key inspect --scheme=sr25519 "$SESSION_SEED//weav" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
||||||
EXDS_HEX=$(ghost key inspect --scheme=sr25519 "$SESSION_SEED//exds" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
EXDS_HEX=$(ghost key inspect --scheme=sr25519 "$SESSION_SEED//exds" | grep "Public key (hex)" | awk '{print $4}' | sed 's/^0x//')
|
||||||
|
|
||||||
STASH_SS58=$(ghost key inspect --scheme=sr25519 "$STASH_SEED" | grep "SS58 Address" | awk '{print $3}')
|
STASH_SS58=$(ghost key inspect --scheme=sr25519 "$STASH_SEED" | grep "SS58 Address" | awk '{print $3}')
|
||||||
@ -575,7 +625,7 @@ if [ "$GENERATE_GENESIS" = true ]; then
|
|||||||
echo " .with_babe_id(BabeId::unchecked_from(hex!(\"$BABE_HEX\")))"
|
echo " .with_babe_id(BabeId::unchecked_from(hex!(\"$BABE_HEX\")))"
|
||||||
echo " .with_grandpa_id(GrandpaId::unchecked_from(hex!(\"$GRAN_HEX\")))"
|
echo " .with_grandpa_id(GrandpaId::unchecked_from(hex!(\"$GRAN_HEX\")))"
|
||||||
echo " .with_authority_id(AuthorityDiscoveryId::unchecked_from(hex!(\"$AUDI_HEX\")))"
|
echo " .with_authority_id(AuthorityDiscoveryId::unchecked_from(hex!(\"$AUDI_HEX\")))"
|
||||||
echo " .with_weaver_id(WeaverId::unchecked_from(hex!(\"$WEVR_HEX\")))"
|
echo " .with_weaver_id(WeaverId::unchecked_from(hex!(\"$WEAV_HEX\")))"
|
||||||
echo " .with_exodus_id(ExodusId::unchecked_from(hex!(\"$EXDS_HEX\")))"
|
echo " .with_exodus_id(ExodusId::unchecked_from(hex!(\"$EXDS_HEX\")))"
|
||||||
echo " .build(),"
|
echo " .build(),"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user