Compare commits

..

1 Commits

Author SHA1 Message Date
6e3c955bec
Add Doctor K keys to genesis
Signed-off-by: Doctor K <doctor_whoami@ghostchain.io>
2026-09-06 23:56:08 +03:00
50 changed files with 1782 additions and 1492 deletions

22
Cargo.lock generated
View File

@ -1195,7 +1195,7 @@ dependencies = [
[[package]] [[package]]
name = "casper-runtime" name = "casper-runtime"
version = "4.0.11" version = "4.0.6"
dependencies = [ dependencies = [
"casper-runtime-constants", "casper-runtime-constants",
"frame-benchmarking", "frame-benchmarking",
@ -3363,10 +3363,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "frost-secp256k1-tr" name = "frost-secp256k1"
version = "2.2.0" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff8a25b14bfd5d25deba5edce61ec99c3afb752a1d26630a196bba4cb1c4ca5e" checksum = "4f6974379aee791f2f9e0db47c37d9e4c77ea8a8233e488ae8949ce4c6864e96"
dependencies = [ dependencies = [
"document-features", "document-features",
"frost-core", "frost-core",
@ -3684,7 +3684,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-exodus" name = "ghost-exodus"
version = "0.0.11" version = "0.0.7"
dependencies = [ dependencies = [
"chacha20poly1305", "chacha20poly1305",
"frame-benchmarking", "frame-benchmarking",
@ -3693,7 +3693,7 @@ dependencies = [
"frame-system", "frame-system",
"frost-core", "frost-core",
"frost-ed25519", "frost-ed25519",
"frost-secp256k1-tr", "frost-secp256k1",
"ghost-helpers", "ghost-helpers",
"ghost-networks", "ghost-networks",
"ghost-traits", "ghost-traits",
@ -3733,7 +3733,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-governance" name = "ghost-governance"
version = "0.3.7" version = "0.3.5"
dependencies = [ dependencies = [
"frame-benchmarking", "frame-benchmarking",
"frame-support", "frame-support",
@ -3757,7 +3757,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-helpers" name = "ghost-helpers"
version = "0.0.11" version = "0.0.6"
dependencies = [ dependencies = [
"frame-support", "frame-support",
"ghost-traits", "ghost-traits",
@ -3839,7 +3839,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-networks" name = "ghost-networks"
version = "0.2.10" version = "0.2.9"
dependencies = [ dependencies = [
"frame-benchmarking", "frame-benchmarking",
"frame-support", "frame-support",
@ -4085,7 +4085,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-traits" name = "ghost-traits"
version = "0.4.6" version = "0.4.4"
dependencies = [ dependencies = [
"frame-support", "frame-support",
"frost-core", "frost-core",
@ -4109,7 +4109,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-weaver" name = "ghost-weaver"
version = "0.0.10" version = "0.0.4"
dependencies = [ dependencies = [
"frame-benchmarking", "frame-benchmarking",
"frame-support", "frame-support",
@ -8553,7 +8553,7 @@ dependencies = [
[[package]] [[package]]
name = "runtime-common" name = "runtime-common"
version = "0.4.9" version = "0.4.8"
dependencies = [ dependencies = [
"frame-support", "frame-support",
"frame-system", "frame-system",

View File

@ -89,7 +89,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features =
scale-info = { version = "2.5.0", default-features = false } scale-info = { version = "2.5.0", default-features = false }
subxt = { version = "0.37.0", default-features = false } subxt = { version = "0.37.0", default-features = false }
frost-secp256k1-tr = { version = "2.2.0", default-features = false, features = ["serialization"] } frost-secp256k1 = { version = "2.2.0", default-features = false, features = ["serialization"] }
frost-ed25519 = { version = "2.2.0", default-features = false, features = ["serialization"] } frost-ed25519 = { version = "2.2.0", default-features = false, features = ["serialization"] }
chacha20poly1305 = { version = "0.10.1", default-features = false, features = ["alloc"] } chacha20poly1305 = { version = "0.10.1", default-features = false, features = ["alloc"] }
frost-core = { version = "2.2.0", default-features = false } frost-core = { version = "2.2.0", default-features = false }
@ -345,7 +345,7 @@ curve25519-dalek = { opt-level = 3 }
ed25519-dalek = { opt-level = 3 } ed25519-dalek = { opt-level = 3 }
flate2 = { opt-level = 3 } flate2 = { opt-level = 3 }
frost-core = { opt-level = 3 } frost-core = { opt-level = 3 }
frost-secp256k1-tr = { opt-level = 3 } frost-secp256k1 = { opt-level = 3 }
futures-channel = { opt-level = 3 } futures-channel = { opt-level = 3 }
hash-db = { opt-level = 3 } hash-db = { opt-level = 3 }
hashbrown = { opt-level = 3 } hashbrown = { opt-level = 3 }

View File

@ -346,7 +346,7 @@ sha256sum /etc/ghost/casper.json
You should see: You should see:
``` ```
4645c7d39a64424d823f659d408070f8c90426117e7af147b0360697b2db7f4f /etc/ghost/casper.json 9da6045ed6d4fd844e3939573b31c013d0e564e542029330faa6d978cb4a915a
``` ```
Create running `ghost-node` service that starts on system boot using `--unit-file` flag. Create running `ghost-node` service that starts on system boot using `--unit-file` flag.

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-exodus" name = "ghost-exodus"
version = "0.0.11" version = "0.0.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
@ -28,7 +28,7 @@ sp-core = { workspace = true }
sp-std = { workspace = true } sp-std = { workspace = true }
sp-io = { workspace = true } sp-io = { workspace = true }
frost-secp256k1-tr = { workspace = true } frost-secp256k1 = { workspace = true }
frost-ed25519 = { workspace = true } frost-ed25519 = { workspace = true }
frost-core = { workspace = true } frost-core = { workspace = true }
rand_chacha = { workspace = true } rand_chacha = { workspace = true }
@ -75,7 +75,7 @@ std = [
"sp-core/std", "sp-core/std",
"sp-std/std", "sp-std/std",
"sp-io/std", "sp-io/std",
"frost-secp256k1-tr/std", "frost-secp256k1/std",
"frost-ed25519/std", "frost-ed25519/std",
"frost-core/std", "frost-core/std",
"ghost-traits/std", "ghost-traits/std",

View File

@ -74,7 +74,7 @@ mod benchmarks {
c: Linear<4, { T::MaxAuthorities::get() }> c: Linear<4, { T::MaxAuthorities::get() }>
) -> Result<(), BenchmarkError> { ) -> Result<(), BenchmarkError> {
let max_signers = c as AuthIndex; let max_signers = c as AuthIndex;
let min_signers = get_byzantium_quorum_threshold(max_signers); let min_signers = get_byzantium_threshold(max_signers);
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);
@ -637,7 +637,7 @@ mod benchmarks {
#[benchmark] #[benchmark]
fn register_signature_share() -> Result<(), BenchmarkError> { fn register_signature_share() -> Result<(), BenchmarkError> {
let max_signers = T::MaxAuthorities::get(); let max_signers = T::MaxAuthorities::get();
let threshold = get_byzantium_quorum_threshold(max_signers); let threshold = get_byzantium_threshold(max_signers);
let network_id: NetworkIdOf<T> = 69_420u64.unique_saturated_into(); let network_id: NetworkIdOf<T> = 69_420u64.unique_saturated_into();
let (mut dkg_state, network_curve, authority, authority_index) = let (mut dkg_state, network_curve, authority, authority_index) =

View File

@ -35,7 +35,7 @@ impl DistributedKeyGeneration<AuthIndex, ExodusError> for NetworkCurve {
$field2:ident : $action2:tt, $field2:ident : $action2:tt,
) => {{ ) => {{
let secret_package = <$package_type>::deserialize(secret_package_bytes) let secret_package = <$package_type>::deserialize(secret_package_bytes)
.map_err(|_| ExodusError::DeserializationError)?; .map_err(|_| ExodusError::DeserializationError)?;
let min_signers = *secret_package.min_signers(); let min_signers = *secret_package.min_signers();
@ -64,7 +64,7 @@ impl DistributedKeyGeneration<AuthIndex, ExodusError> for NetworkCurve {
); );
new_secret_package.serialize() new_secret_package.serialize()
.map_err(|_| ExodusError::SerializationError) .map_err(|_| ExodusError::SerializationError)
}}; }};
} }
@ -285,18 +285,15 @@ impl DistributedKeyGeneration<AuthIndex, ExodusError> for NetworkCurve {
_ => ExodusError::Unknown, _ => ExodusError::Unknown,
})?; })?;
let key_package = key_package.normalize_package();
let pubkey_package = pubkey_package.normalize_package();
let key_package_bytes = key_package.serialize() let key_package_bytes = key_package.serialize()
.map_err(|_| ExodusError::SerializationError)?; .map_err(|_| ExodusError::SerializationError)?;
let verifying_shares_merkle_tree = let verifying_shares_merkle_tree =
Self::build_merkle_tree( Self::build_merkle_tree(
pubkey_package.verifying_shares(), pubkey_package.verifying_shares(),
|verifying_share| verifying_share.serialize() |verifying_share| verifying_share.serialize()
.map_err(|_| ExodusError::SerializationError) .map_err(|_| ExodusError::SerializationError)
)?; )?;
let (_, merkle_proof) = let (_, merkle_proof) =
Self::generate_merkle_proof_from_tree( Self::generate_merkle_proof_from_tree(
@ -340,4 +337,15 @@ impl DistributedKeyGeneration<AuthIndex, ExodusError> for NetworkCurve {
.map_err(|_| ExodusError::SerializationError) .map_err(|_| ExodusError::SerializationError)
}) })
} }
fn dkg_decompress_key(
&self,
verifying_key_bytes: &[u8],
) -> Result<Vec<u8>, ExodusError> {
with_ciphersuite!(self, |f| {
let verifying_key = f::VerifyingKey::deserialize(verifying_key_bytes)
.map_err(|_| ExodusError::DeserializationError)?;
decomporess_key(verifying_key)
})
}
} }

View File

@ -17,13 +17,6 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
fn header_bytes_len(&self) -> usize { 5 } 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 { fn element_bytes_len(&self) -> usize {
match self { match self {
NetworkCurve::Secp256k1 => 33, NetworkCurve::Secp256k1 => 33,
@ -83,7 +76,7 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
<InnerGroup as frost_core::Group>::Serialization::try_from(group_commitment_bytes.as_ref()) <InnerGroup as frost_core::Group>::Serialization::try_from(group_commitment_bytes.as_ref())
.map_err(|_| ExodusError::DeserializationError)?; .map_err(|_| ExodusError::DeserializationError)?;
let mut group_commitment_element = let group_commitment_element =
<InnerGroup as frost_core::Group>::deserialize(&group_commitment_serialization) <InnerGroup as frost_core::Group>::deserialize(&group_commitment_serialization)
.map_err(|_| ExodusError::DeserializationError)?; .map_err(|_| ExodusError::DeserializationError)?;
@ -102,6 +95,15 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
let verifying_key = f::VerifyingKey::deserialize(verifying_key_bytes) let verifying_key = f::VerifyingKey::deserialize(verifying_key_bytes)
.map_err(|_| ExodusError::DeserializationError)?; .map_err(|_| ExodusError::DeserializationError)?;
let challenge = frost_core::challenge(
&group_commitment_element,
&verifying_key,
message,
).map_err(|err| match err {
f::Error::SerializationError => ExodusError::SerializationError,
_ => ExodusError::Unknown,
})?;
let hiding_element_serialization = let hiding_element_serialization =
<InnerGroup as frost_core::Group>::Serialization::try_from(nonce_hiding_bytes.as_ref()) <InnerGroup as frost_core::Group>::Serialization::try_from(nonce_hiding_bytes.as_ref())
.map_err(|_| ExodusError::DeserializationError)?; .map_err(|_| ExodusError::DeserializationError)?;
@ -118,27 +120,9 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
<InnerGroup as frost_core::Group>::deserialize(&binding_element_serialization) <InnerGroup as frost_core::Group>::deserialize(&binding_element_serialization)
.map_err(|_| ExodusError::DeserializationError)?; .map_err(|_| ExodusError::DeserializationError)?;
let mut r_i_element = hiding_element + (binding_element * binding_factor_scalar); let r_i_element = hiding_element + (binding_element * binding_factor_scalar);
let group_commitment_wrapper =
frost_core::GroupCommitment::<Ciphersuite>::from_element(group_commitment_element);
if !group_commitment_wrapper.is_normalized() {
r_i_element = -r_i_element;
group_commitment_element = -group_commitment_element;
}
let challenge = <Ciphersuite as frost_core::Ciphersuite>::challenge(
&group_commitment_element,
&verifying_key,
message,
).map_err(|err| match err {
f::Error::SerializationError => ExodusError::SerializationError,
_ => ExodusError::Unknown,
})?;
let commitment_share = let commitment_share =
frost_core::round1::GroupCommitmentShare::from_element(r_i_element); frost_core::round1::GroupCommitmentShare::from_element(r_i_element);
signature_share.verify( signature_share.verify(
identifier, identifier,
@ -275,7 +259,7 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
let hiding_serialization = <InnerGroup as frost_core::Group>::Serialization::try_from(hiding_bytes.as_ref()).ok()?; let hiding_serialization = <InnerGroup as frost_core::Group>::Serialization::try_from(hiding_bytes.as_ref()).ok()?;
let hiding_nonce = f::round1::NonceCommitment::deserialize(&hiding_serialization).ok()?; let hiding_nonce = f::round1::NonceCommitment::deserialize(&hiding_serialization).ok()?;
let binding_serialization = <InnerGroup as frost_core::Group>::Serialization::try_from((*binding_bytes).as_ref()).ok()?; let binding_serialization = <InnerGroup as frost_core::Group>::Serialization::try_from((*binding_bytes).as_ref()).ok()?;
let binding_nonce = f::round1::NonceCommitment::deserialize(&binding_serialization).ok()?; let binding_nonce = f::round1::NonceCommitment::deserialize(&binding_serialization).ok()?;
let commitments = f::round1::SigningCommitments::new(hiding_nonce, binding_nonce); let commitments = f::round1::SigningCommitments::new(hiding_nonce, binding_nonce);
@ -291,14 +275,14 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
let signing_package = f::SigningPackage::new(signing_commitments, message); let signing_package = f::SigningPackage::new(signing_commitments, message);
let binding_factors_list_wrapped = let binding_factors_list_wrapped =
frost_core::compute_binding_factor_list::<Ciphersuite>(&signing_package, &verifying_key, &[]) frost_core::compute_binding_factor_list(&signing_package, &verifying_key, &[])
.map_err(|err| match err { .map_err(|err| match err {
f::Error::SerializationError => ExodusError::SerializationError, f::Error::SerializationError => ExodusError::SerializationError,
_ => ExodusError::Unknown, _ => ExodusError::Unknown,
})?; })?;
let group_commitment = let group_commitment =
frost_core::compute_group_commitment::<Ciphersuite>(&signing_package, &binding_factors_list_wrapped) frost_core::compute_group_commitment(&signing_package, &binding_factors_list_wrapped)
.map_err(|err| match err { .map_err(|err| match err {
f::Error::IdentityCommitment => ExodusError::IdentityCommitment, f::Error::IdentityCommitment => ExodusError::IdentityCommitment,
f::Error::UnknownIdentifier => ExodusError::UnknownIdentifier, f::Error::UnknownIdentifier => ExodusError::UnknownIdentifier,
@ -322,7 +306,7 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
}) })
.flatten()?; .flatten()?;
Some((identifier, binding_factor)) Some((identifier, binding_factor))
}) })
.collect::<BTreeMap<_, _>>(); .collect::<BTreeMap<_, _>>();
@ -344,7 +328,7 @@ impl FlexibleRoundOptimizedSchnorrThresholdSignature<AuthIndex, ExodusError> for
&binding_factor_tree, &binding_factor_tree,
authority_index, authority_index,
|binding_factor| { |binding_factor| {
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()) Ok(serialized.as_ref().to_vec())
} }
)?; )?;

View File

@ -3,53 +3,46 @@ macro_rules! with_ciphersuite {
($curve:expr, |$alias:ident| $body:block) => { ($curve:expr, |$alias:ident| $body:block) => {
match $curve { match $curve {
NetworkCurve::Secp256k1 => { NetworkCurve::Secp256k1 => {
#[allow(unused_imports)] use k256::elliptic_curve::sec1::ToEncodedPoint;
use frost_secp256k1_tr as $alias; use frost_secp256k1 as $alias;
#[allow(unused_imports)] #[allow(unused_imports)]
use frost_secp256k1_tr::Secp256K1Sha256TR as Ciphersuite; use frost_secp256k1::Secp256K1Sha256 as Ciphersuite;
use $alias::keys::EvenY;
#[allow(dead_code)] #[allow(dead_code)]
trait UniversalNormalizer { fn decomporess_key(
fn normalize_package(self) -> Self; verifying_key: $alias::VerifyingKey,
fn is_normalized(&self) -> bool; ) -> Result<Vec<u8>, ExodusError> {
} let element = verifying_key.to_element();
impl<T: EvenY> UniversalNormalizer for T { if element == k256::ProjectivePoint::IDENTITY {
#[inline] return Err(ExodusError::InvalidIdentityElement);
fn normalize_package(self) -> Self {
self.into_even_y(None)
} }
#[inline] let mut fixed_serialized = [0; 65];
fn is_normalized(&self) -> bool { let serialized_point = element.to_affine().to_encoded_point(false);
self.has_even_y() let serialized = serialized_point.as_bytes();
} fixed_serialized.copy_from_slice(serialized);
Ok(fixed_serialized.to_vec())
} }
$body $body
}, },
NetworkCurve::Ed25519 => { NetworkCurve::Ed25519 => {
#[allow(unused_imports)]
use frost_ed25519 as $alias; use frost_ed25519 as $alias;
#[allow(unused_imports)] #[allow(unused_imports)]
use frost_ed25519::Ed25519Sha512 as Ciphersuite; use frost_ed25519::Ed25519Sha512 as Ciphersuite;
#[allow(dead_code)] #[allow(dead_code)]
trait UniversalNormalizer { fn decomporess_key(
fn normalize_package(self) -> Self; verifying_key: $alias::VerifyingKey,
fn is_normalized(&self) -> bool; ) -> Result<Vec<u8>, ExodusError> {
} verifying_key.serialize().map_err(|err| match err {
f::Error::SerializationError => ExodusError::SerializationError,
impl<T> UniversalNormalizer for T { _ => ExodusError::Unknown,
#[inline] })
fn normalize_package(self) -> Self { self }
#[inline]
fn is_normalized(&self) -> bool { true }
} }
$body $body

View File

@ -29,7 +29,7 @@ use sp_runtime::traits::BlockNumberProvider;
use sp_io::hashing::blake2_256; use sp_io::hashing::blake2_256;
use ghost_helpers::{ use ghost_helpers::{
get_byzantium_quorum_threshold, SubstrateBlake2Hasher, get_byzantium_threshold, SubstrateBlake2Hasher,
hash_chain::sequential_hash, hash_chain::sequential_hash,
networks::{NetworkData, NetworkCurve, NetworkType}, networks::{NetworkData, NetworkCurve, NetworkType},
bounded_bitmap::{validate_bitmap_sizes, BoundedBitmap}, bounded_bitmap::{validate_bitmap_sizes, BoundedBitmap},
@ -130,17 +130,26 @@ const fn postcard_varint_len(len: usize) -> usize {
else { 3 } else { 3 }
} }
const fn signature_bytes_len(
element_bytes_len: usize,
scalar_bytes_len: usize,
)-> usize {
let signature_bytes_len = element_bytes_len.saturating_add(scalar_bytes_len);
let signature_vec_prefix = postcard_varint_len(signature_bytes_len);
signature_bytes_len.saturating_add(signature_vec_prefix)
}
const fn round1_package_size( const fn round1_package_size(
commitments_count: usize, commitments_count: usize,
element_bytes_len: usize, element_bytes_len: usize,
signature_bytes_len: usize, scalar_bytes_len: usize,
header_bytes_len: usize header_bytes_len: usize
) -> usize { ) -> usize {
let commitments_bytes_len = commitments_count.saturating_mul(element_bytes_len); let commitments_bytes_len = commitments_count.saturating_mul(element_bytes_len);
let commitment_vec_prefix = postcard_varint_len(commitments_count); let commitment_vec_prefix = postcard_varint_len(commitments_count);
postcard_varint_len(signature_bytes_len) signature_bytes_len(element_bytes_len, scalar_bytes_len)
.saturating_add(signature_bytes_len)
.saturating_add(header_bytes_len) .saturating_add(header_bytes_len)
.saturating_add(commitment_vec_prefix) .saturating_add(commitment_vec_prefix)
.saturating_add(commitments_bytes_len) .saturating_add(commitments_bytes_len)
@ -254,13 +263,12 @@ pub struct Round1MaxBytes<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> Get<u32> for Round1MaxBytes<T> { impl<T: Config> Get<u32> for Round1MaxBytes<T> {
fn get() -> u32 { fn get() -> u32 {
let max_authorities = T::MaxAuthorities::get(); let max_authorities = T::MaxAuthorities::get();
let min_authorities = get_byzantium_quorum_threshold(max_authorities); let min_authorities = get_byzantium_threshold(max_authorities);
let max_signature_bytes = ELEMENT_MAX_BYTES + SCALAR_MAX_BYTES;
round1_package_size( round1_package_size(
min_authorities as usize, min_authorities as usize,
ELEMENT_MAX_BYTES as usize, ELEMENT_MAX_BYTES as usize,
max_signature_bytes as usize, SCALAR_MAX_BYTES as usize,
HEADER_MAX_BYTES as usize, HEADER_MAX_BYTES as usize,
) as u32 ) as u32
} }
@ -316,7 +324,7 @@ pub struct BindingFactorsProof<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> Get<u32> for BindingFactorsProof<T> { impl<T: Config> Get<u32> for BindingFactorsProof<T> {
fn get() -> u32 { fn get() -> u32 {
let max_authorities = T::MaxAuthorities::get(); let max_authorities = T::MaxAuthorities::get();
get_byzantium_quorum_threshold(max_authorities) get_byzantium_threshold(max_authorities)
.next_power_of_two() .next_power_of_two()
.trailing_zeros() .trailing_zeros()
} }
@ -355,8 +363,10 @@ impl<T: Config> Get<u32> for SignatureShareMaxBytes<T> {
pub struct SignatureMaxBytes<T>(sp_std::marker::PhantomData<T>); pub struct SignatureMaxBytes<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> Get<u32> for SignatureMaxBytes<T> { impl<T: Config> Get<u32> for SignatureMaxBytes<T> {
fn get() -> u32 { fn get() -> u32 {
let signature_max_bytes = ELEMENT_MAX_BYTES + SCALAR_MAX_BYTES; signature_bytes_len(
postcard_varint_len(signature_max_bytes as usize) as u32 ELEMENT_MAX_BYTES as usize,
SCALAR_MAX_BYTES as usize,
) as u32
} }
} }
@ -1412,7 +1422,7 @@ pub mod pallet {
}; };
let threshold = ActiveAuthorities::<T>::decode_len(&network_curve) let threshold = ActiveAuthorities::<T>::decode_len(&network_curve)
.map(|max_participants| get_byzantium_quorum_threshold(max_participants)) .map(|max_participants| get_byzantium_threshold(max_participants))
.ok_or(Error::<T>::DkgAuthoritiesNotInitialized)?; .ok_or(Error::<T>::DkgAuthoritiesNotInitialized)?;
let exodus_session = package.session; let exodus_session = package.session;
@ -1505,7 +1515,7 @@ pub mod pallet {
let max_authorities = ActiveAuthorities::<T>::decode_len(&network_curve) let max_authorities = ActiveAuthorities::<T>::decode_len(&network_curve)
.ok_or(Error::<T>::DkgAuthoritiesNotInitialized)?; .ok_or(Error::<T>::DkgAuthoritiesNotInitialized)?;
let threshold = get_byzantium_quorum_threshold(max_authorities); let threshold = get_byzantium_threshold(max_authorities);
let exodus_session = package.session; let exodus_session = package.session;
ensure!( ensure!(
@ -1623,7 +1633,7 @@ pub mod pallet {
}; };
let threshold = ActiveAuthorities::<T>::decode_len(&network_curve) let threshold = ActiveAuthorities::<T>::decode_len(&network_curve)
.map(|max_participants| get_byzantium_quorum_threshold(max_participants)) .map(|max_participants| get_byzantium_threshold(max_participants))
.ok_or(Error::<T>::DkgAuthoritiesNotInitialized)?; .ok_or(Error::<T>::DkgAuthoritiesNotInitialized)?;
let exodus_session = package.session; let exodus_session = package.session;
@ -1888,7 +1898,7 @@ pub mod pallet {
None => return weight, None => return weight,
}; };
let min_threshold = get_byzantium_quorum_threshold(qualification_len); let min_threshold = get_byzantium_threshold(qualification_len);
weight.saturating_accrue(T::DbWeight::get().reads(1)); weight.saturating_accrue(T::DbWeight::get().reads(1));
let maybe_cursor = DkgMaybeCursor::<T>::get(&network_curve); let maybe_cursor = DkgMaybeCursor::<T>::get(&network_curve);
@ -2417,7 +2427,6 @@ impl<T: Config> Pallet<T> {
let mut number_of_leaked_keys = 0; let mut number_of_leaked_keys = 0;
let qualified_indexes = dkg_qualification.get_indexes(); let qualified_indexes = dkg_qualification.get_indexes();
let total_authorities_len = qualified_indexes.count_ones::<usize>();
let mut failed_authorities = ParticipantsBitmap::<T>::empty_from( let mut failed_authorities = ParticipantsBitmap::<T>::empty_from(
&qualified_indexes, &qualified_indexes,
@ -2427,17 +2436,17 @@ impl<T: Config> Pallet<T> {
&qualified_indexes, &qualified_indexes,
); );
let mut complaints_matrix = vec![ let mut complaints_matrix: BTreeMap<AuthIndex, ParticipantsBitmap<T>> =
ParticipantsBitmap::<T>::empty_from(&qualified_indexes); BTreeMap::new();
total_authorities_len
];
complaints_bitmap.iter().for_each(|(&accuser_index, offenders_bitmap)| { complaints_bitmap.iter().for_each(|(&accuser_index, offenders_bitmap)| {
offenders_bitmap.iter().for_each(|offended_index: AuthIndex| { offenders_bitmap.iter().for_each(|offended_index| {
let idx = offended_index as usize; complaints_matrix
if idx >= complaints_matrix.len() { return; } .entry(offended_index)
.or_insert_with(|| {
complaints_matrix[idx].insert(accuser_index); ParticipantsBitmap::<T>::empty_from(&qualified_indexes)
})
.insert(accuser_index);
}); });
}); });
@ -2448,17 +2457,13 @@ impl<T: Config> Pallet<T> {
number_of_leaked_keys.saturating_inc(); number_of_leaked_keys.saturating_inc();
} }
let idx = offended_index as usize; if let Some(accusers_bitmap) = complaints_matrix.get(&offended_index) {
if idx >= complaints_matrix.len() { return; } let successful_justifications = accusers_bitmap & recipients_bitmap;
let failed_to_justify = successful_justifications != *accusers_bitmap;
let accusers_bitmap = &complaints_matrix[idx]; if failed_to_justify {
if accusers_bitmap.is_empty() { return; } failed_authorities.insert(offended_index);
}
let successful_justifications = accusers_bitmap & recipients_bitmap;
let failed_to_justify = successful_justifications != *accusers_bitmap;
if failed_to_justify {
failed_authorities.insert(offended_index);
} }
}); });
@ -2528,7 +2533,6 @@ impl<T: Config> Pallet<T> {
dkg_qualification.intersect_indexes(&participants); dkg_qualification.intersect_indexes(&participants);
if dkg_qualification.count_ones::<AuthIndex>() < min_threshold { if dkg_qualification.count_ones::<AuthIndex>() < min_threshold {
dkg_qualification.nullify_indexes(); dkg_qualification.nullify_indexes();
return; return;
@ -2707,12 +2711,12 @@ impl<T: Config> Pallet<T> {
} }
let authorities = QualificationAuthorities::<T>::get(&network_curve); let authorities = QualificationAuthorities::<T>::get(&network_curve);
let expected_count = get_byzantium_quorum_threshold(authorities.len()); let expected_count = get_byzantium_threshold(authorities.len());
let expected_package_len = round1_package_size( let expected_package_len = round1_package_size(
expected_count, expected_count,
network_curve.element_bytes_len(), network_curve.element_bytes_len(),
network_curve.signature_bytes_len(), network_curve.scalar_bytes_len(),
network_curve.header_bytes_len(), network_curve.header_bytes_len(),
); );
@ -3279,7 +3283,7 @@ impl<T: Config> Pallet<T> {
let max_authorities = ActiveAuthorities::<T>::decode_len(&network_curve) let max_authorities = ActiveAuthorities::<T>::decode_len(&network_curve)
.ok_or(ExodusError::NoActiveAuthorities)?; .ok_or(ExodusError::NoActiveAuthorities)?;
let threshold = get_byzantium_quorum_threshold(max_authorities); let threshold = get_byzantium_threshold(max_authorities);
let mut exodus_requests = ExodusRequests::<T>::iter_prefix(&network_curve) let mut exodus_requests = ExodusRequests::<T>::iter_prefix(&network_curve)
.collect::<Vec<(ExodusSession, ExodusRequest<_, _>)>>(); .collect::<Vec<(ExodusSession, ExodusRequest<_, _>)>>();
@ -3728,7 +3732,7 @@ impl<T: Config> Pallet<T> {
.map(|max_signers| max_signers as AuthIndex) .map(|max_signers| max_signers as AuthIndex)
.ok_or(ExodusError::InvalidMaxSigners(0))?; .ok_or(ExodusError::InvalidMaxSigners(0))?;
let min_signers = get_byzantium_quorum_threshold(max_signers); let min_signers = get_byzantium_threshold(max_signers);
if qualification_state.contains_index(authority_index) { if qualification_state.contains_index(authority_index) {
return Ok(ExodusOk::DkgRoundAlreadyPassed( return Ok(ExodusOk::DkgRoundAlreadyPassed(

View File

@ -15,8 +15,8 @@ use rand_chacha::rand_core::SeedableRng;
use rand_chacha::ChaCha20Rng; use rand_chacha::ChaCha20Rng;
use frost_core::Field; use frost_core::Field;
use frost_secp256k1_tr::{ use frost_secp256k1::{
Secp256K1Sha256TR, Secp256K1ScalarField, Identifier as Secp256K1Identifier, Secp256K1Sha256, Secp256K1ScalarField, Identifier as Secp256K1Identifier,
keys::{ keys::{
VerifyingShare as Secp256K1VerifyingShare, VerifyingShare as Secp256K1VerifyingShare,
SigningShare as Secp256K1SigningShare, SigningShare as Secp256K1SigningShare,
@ -841,7 +841,7 @@ fn run_dkg_session(
let threshold = ext.execute_with(|| { let threshold = ext.execute_with(|| {
let len = ActiveAuthorities::<Runtime>::decode_len(&curve) let len = ActiveAuthorities::<Runtime>::decode_len(&curve)
.unwrap_or(0); .unwrap_or(0);
get_byzantium_quorum_threshold(len) as u16 get_byzantium_threshold(len) as u16
}); });
let mut exodus_steps_outer = BTreeMap::new(); let mut exodus_steps_outer = BTreeMap::new();
@ -1259,7 +1259,7 @@ fn test_exodus_dkg_robustness() {
assert_eq!(state.get_dkg_index(), dkg_index); assert_eq!(state.get_dkg_index(), dkg_index);
assert_eq!(state.get_phase(), DkgPhase::Finalized); assert_eq!(state.get_phase(), DkgPhase::Finalized);
let bft_threshold = get_byzantium_quorum_threshold(authorities_len); let bft_threshold = get_byzantium_threshold(authorities_len);
assert!(qualification_count >= bft_threshold); assert!(qualification_count >= bft_threshold);
assert!(state.count_ones::<usize>() >= bft_threshold); assert!(state.count_ones::<usize>() >= bft_threshold);
assert_eq!(state.get_indexes().active_bits_count(), authorities_len as u32); assert_eq!(state.get_indexes().active_bits_count(), authorities_len as u32);
@ -1299,7 +1299,7 @@ fn test_prepare_round4_abort_on_byzantine_attack() {
} }
} }
let bft_threshold = get_byzantium_quorum_threshold(authorities_len); let bft_threshold = get_byzantium_threshold(authorities_len);
ext.execute_with(|| { ext.execute_with(|| {
let mut complaints_map = BitmapByAuthority::<Runtime>::default(); let mut complaints_map = BitmapByAuthority::<Runtime>::default();
for authority in 0..=bft_threshold { for authority in 0..=bft_threshold {
@ -1344,7 +1344,7 @@ fn test_prepare_round5_abort_on_byzantine_attack() {
} }
} }
let bft_threshold = get_byzantium_quorum_threshold(authorities_len); let bft_threshold = get_byzantium_threshold(authorities_len);
ext.execute_with(|| { ext.execute_with(|| {
let mut justifications_map = BitmapByAuthority::<Runtime>::default(); let mut justifications_map = BitmapByAuthority::<Runtime>::default();
for authority in 0..=bft_threshold { for authority in 0..=bft_threshold {
@ -1452,7 +1452,7 @@ fn test_merkle_tree_success_power_of_two_for_shares() {
let indices = (1..=32).collect::<Vec<AuthIndex>>(); let indices = (1..=32).collect::<Vec<AuthIndex>>();
let shares = generate_mock_secp256k1_shares(&indices); let shares = generate_mock_secp256k1_shares(&indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
|share| share.serialize().map_err(|_| ExodusError::SerializationError), |share| share.serialize().map_err(|_| ExodusError::SerializationError),
).unwrap(); ).unwrap();
@ -1465,7 +1465,7 @@ fn test_merkle_tree_success_power_of_two_for_shares() {
).unwrap(); ).unwrap();
let (shares_bytes, proof) = let (shares_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
&tree, &tree,
auth_index, auth_index,
@ -1489,7 +1489,7 @@ fn test_merkle_tree_success_power_of_two_for_scalar() {
let indices = (1..=32).collect::<Vec<AuthIndex>>(); let indices = (1..=32).collect::<Vec<AuthIndex>>();
let scalars = generate_mock_secp256k1_scalars(&indices); let scalars = generate_mock_secp256k1_scalars(&indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
|scalar| { |scalar| {
let serialized = <Secp256K1ScalarField as Field>::serialize(scalar); let serialized = <Secp256K1ScalarField as Field>::serialize(scalar);
@ -1505,7 +1505,7 @@ fn test_merkle_tree_success_power_of_two_for_scalar() {
).unwrap(); ).unwrap();
let (shares_bytes, proof) = let (shares_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
&tree, &tree,
auth_index, auth_index,
@ -1538,7 +1538,7 @@ fn test_random_sparse_combinations_stress_for_shares() {
let indices: Vec<AuthIndex> = unique_indices.into_iter().collect(); let indices: Vec<AuthIndex> = unique_indices.into_iter().collect();
let shares = generate_mock_secp256k1_shares(&indices); let shares = generate_mock_secp256k1_shares(&indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
|share| share.serialize().map_err(|_| ExodusError::SerializationError), |share| share.serialize().map_err(|_| ExodusError::SerializationError),
).unwrap(); ).unwrap();
@ -1547,7 +1547,7 @@ fn test_random_sparse_combinations_stress_for_shares() {
for &auth_index in &indices { for &auth_index in &indices {
let (shares_bytes, proof) = let (shares_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
&tree, &tree,
auth_index, auth_index,
@ -1576,7 +1576,7 @@ fn test_random_sparse_combinations_stress_for_scalars() {
let indices: Vec<AuthIndex> = unique_indices.into_iter().collect(); let indices: Vec<AuthIndex> = unique_indices.into_iter().collect();
let scalars = generate_mock_secp256k1_scalars(&indices); let scalars = generate_mock_secp256k1_scalars(&indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
|scalar| { |scalar| {
let serialized = <Secp256K1ScalarField as Field>::serialize(scalar); let serialized = <Secp256K1ScalarField as Field>::serialize(scalar);
@ -1588,7 +1588,7 @@ fn test_random_sparse_combinations_stress_for_scalars() {
for &auth_index in &indices { for &auth_index in &indices {
let (scalars_bytes, proof) = let (scalars_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
&tree, &tree,
auth_index, auth_index,
@ -1614,7 +1614,7 @@ fn test_participants_with_high_index_gap_for_shares() {
let indices = vec![1, 1023]; let indices = vec![1, 1023];
let shares = generate_mock_secp256k1_shares(&indices); let shares = generate_mock_secp256k1_shares(&indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
|share| share.serialize().map_err(|_| ExodusError::SerializationError), |share| share.serialize().map_err(|_| ExodusError::SerializationError),
).unwrap(); ).unwrap();
@ -1622,7 +1622,7 @@ fn test_participants_with_high_index_gap_for_shares() {
let root = *tree.last().unwrap(); let root = *tree.last().unwrap();
let (shares_bytes, proof) = let (shares_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
&tree, &tree,
1023, 1023,
@ -1646,7 +1646,7 @@ fn test_participants_with_high_index_gap_for_scalars() {
let indices = vec![1, 1023]; let indices = vec![1, 1023];
let scalars = generate_mock_secp256k1_scalars(&indices); let scalars = generate_mock_secp256k1_scalars(&indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
|scalar| { |scalar| {
let serialized = <Secp256K1ScalarField as Field>::serialize(scalar); let serialized = <Secp256K1ScalarField as Field>::serialize(scalar);
@ -1657,7 +1657,7 @@ fn test_participants_with_high_index_gap_for_scalars() {
let root = *tree.last().unwrap(); let root = *tree.last().unwrap();
let (scalars_bytes, proof) = let (scalars_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
&tree, &tree,
1023, 1023,
@ -1684,7 +1684,7 @@ fn test_regression_consecutive_vs_position_for_shares() {
let custom_indices = vec![2, 3]; let custom_indices = vec![2, 3];
let shares = generate_mock_secp256k1_shares(&custom_indices); let shares = generate_mock_secp256k1_shares(&custom_indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
|scalar| scalar.serialize().map_err(|_| ExodusError::SerializationError), |scalar| scalar.serialize().map_err(|_| ExodusError::SerializationError),
).unwrap(); ).unwrap();
@ -1692,7 +1692,7 @@ fn test_regression_consecutive_vs_position_for_shares() {
let root = *tree.last().unwrap(); let root = *tree.last().unwrap();
let (shares_bytes, proof) = let (shares_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
&tree, &tree,
2, 2,
@ -1709,7 +1709,7 @@ fn test_regression_consecutive_vs_position_for_scalars() {
let custom_indices = vec![2, 3]; let custom_indices = vec![2, 3];
let scalars = generate_mock_secp256k1_scalars(&custom_indices); let scalars = generate_mock_secp256k1_scalars(&custom_indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
|scalar| { |scalar| {
let serialized = <Secp256K1ScalarField as Field>::serialize(scalar); let serialized = <Secp256K1ScalarField as Field>::serialize(scalar);
@ -1720,7 +1720,7 @@ fn test_regression_consecutive_vs_position_for_scalars() {
let root = *tree.last().unwrap(); let root = *tree.last().unwrap();
let (scalars_bytes, proof) = let (scalars_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
&tree, &tree,
2, 2,
@ -1740,7 +1740,7 @@ fn test_attack_with_unknown_authority_index_for_shares() {
let custom_indices = vec![1, 2, 3]; let custom_indices = vec![1, 2, 3];
let shares = generate_mock_secp256k1_shares(&custom_indices); let shares = generate_mock_secp256k1_shares(&custom_indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
|scalar| scalar.serialize().map_err(|_| ExodusError::SerializationError), |scalar| scalar.serialize().map_err(|_| ExodusError::SerializationError),
).unwrap(); ).unwrap();
@ -1748,7 +1748,7 @@ fn test_attack_with_unknown_authority_index_for_shares() {
let root = *tree.last().unwrap(); let root = *tree.last().unwrap();
let (shares_bytes, proof) = let (shares_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&shares, &shares,
&tree, &tree,
2, 2,
@ -1765,7 +1765,7 @@ fn test_attack_with_unknown_authority_index_for_scalars() {
let custom_indices = vec![1, 2, 3]; let custom_indices = vec![1, 2, 3];
let scalars = generate_mock_secp256k1_scalars(&custom_indices); let scalars = generate_mock_secp256k1_scalars(&custom_indices);
let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256TR, _, _>( let tree = NetworkCurve::build_merkle_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
|scalar| { |scalar| {
let serialized = <Secp256K1ScalarField as Field>::serialize(scalar); let serialized = <Secp256K1ScalarField as Field>::serialize(scalar);
@ -1776,7 +1776,7 @@ fn test_attack_with_unknown_authority_index_for_scalars() {
let root = *tree.last().unwrap(); let root = *tree.last().unwrap();
let (scalars_bytes, proof) = let (scalars_bytes, proof) =
NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256TR, _, _>( NetworkCurve::generate_merkle_proof_from_tree::<Secp256K1Sha256, _, _>(
&scalars, &scalars,
&tree, &tree,
2, 2,
@ -2227,7 +2227,7 @@ fn curve_wrapper_for_dkg_works() {
#[test] #[test]
fn test_common_way_of_frost_usage() { fn test_common_way_of_frost_usage() {
use frost_secp256k1_tr as frost; use frost_secp256k1 as frost;
let mut rng = ChaCha20Rng::from_seed(Default::default()); let mut rng = ChaCha20Rng::from_seed(Default::default());

View File

@ -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-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2026-09-05, 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
@ -77,8 +77,8 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `351` // Measured: `351`
// Estimated: `3816` // Estimated: `3816`
// Minimum execution time: 239_012_000 picoseconds. // Minimum execution time: 239_348_000 picoseconds.
Weight::from_parts(241_388_000, 0) Weight::from_parts(241_125_000, 0)
.saturating_add(Weight::from_parts(0, 3816)) .saturating_add(Weight::from_parts(0, 3816))
.saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().reads(4))
.saturating_add(RocksDbWeight::get().writes(3)) .saturating_add(RocksDbWeight::get().writes(3))
@ -100,11 +100,11 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `391 + c * (32 ±0)` // Measured: `391 + c * (32 ±0)`
// Estimated: `3856 + c * (32 ±0)` // Estimated: `3856 + c * (32 ±0)`
// Minimum execution time: 1_339_828_000 picoseconds. // Minimum execution time: 1_372_279_000 picoseconds.
Weight::from_parts(1_212_625_790, 0) Weight::from_parts(1_268_130_469, 0)
.saturating_add(Weight::from_parts(0, 3856)) .saturating_add(Weight::from_parts(0, 3856))
// Standard Error: 11_831 // Standard Error: 17_178
.saturating_add(Weight::from_parts(33_120_868, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(32_976_202, 0).saturating_mul(c.into()))
.saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().reads(6))
.saturating_add(RocksDbWeight::get().writes(2)) .saturating_add(RocksDbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
@ -124,11 +124,11 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `317 + c * (257 ±0)` // Measured: `317 + c * (257 ±0)`
// Estimated: `3783 + c * (257 ±0)` // Estimated: `3783 + c * (257 ±0)`
// Minimum execution time: 251_478_000 picoseconds. // Minimum execution time: 253_301_000 picoseconds.
Weight::from_parts(254_144_621, 0) Weight::from_parts(255_449_282, 0)
.saturating_add(Weight::from_parts(0, 3783)) .saturating_add(Weight::from_parts(0, 3783))
// Standard Error: 24_613 // Standard Error: 25_029
.saturating_add(Weight::from_parts(6_595_819, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(6_615_251, 0).saturating_mul(c.into()))
.saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().reads(5))
.saturating_add(RocksDbWeight::get().writes(2)) .saturating_add(RocksDbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
@ -148,11 +148,11 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `317 + c * (257 ±0)` // Measured: `317 + c * (257 ±0)`
// Estimated: `3783 + c * (257 ±0)` // Estimated: `3783 + c * (257 ±0)`
// Minimum execution time: 236_155_000 picoseconds. // Minimum execution time: 238_882_000 picoseconds.
Weight::from_parts(242_055_948, 0) Weight::from_parts(242_930_556, 0)
.saturating_add(Weight::from_parts(0, 3783)) .saturating_add(Weight::from_parts(0, 3783))
// Standard Error: 15_623 // Standard Error: 13_070
.saturating_add(Weight::from_parts(360_411, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(426_492, 0).saturating_mul(c.into()))
.saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().reads(5))
.saturating_add(RocksDbWeight::get().writes(2)) .saturating_add(RocksDbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
@ -172,11 +172,11 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `317 + c * (257 ±0)` // Measured: `317 + c * (257 ±0)`
// Estimated: `3783 + c * (257 ±0)` // Estimated: `3783 + c * (257 ±0)`
// Minimum execution time: 249_507_000 picoseconds. // Minimum execution time: 250_894_000 picoseconds.
Weight::from_parts(248_505_595, 0) Weight::from_parts(252_272_982, 0)
.saturating_add(Weight::from_parts(0, 3783)) .saturating_add(Weight::from_parts(0, 3783))
// Standard Error: 20_302 // Standard Error: 17_703
.saturating_add(Weight::from_parts(4_191_526, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(4_110_522, 0).saturating_mul(c.into()))
.saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().reads(5))
.saturating_add(RocksDbWeight::get().writes(2)) .saturating_add(RocksDbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
@ -197,8 +197,8 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `448` // Measured: `448`
// Estimated: `3913` // Estimated: `3913`
// Minimum execution time: 264_214_000 picoseconds. // Minimum execution time: 265_392_000 picoseconds.
Weight::from_parts(266_905_000, 0) Weight::from_parts(268_799_000, 0)
.saturating_add(Weight::from_parts(0, 3913)) .saturating_add(Weight::from_parts(0, 3913))
.saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().reads(6))
.saturating_add(RocksDbWeight::get().writes(3)) .saturating_add(RocksDbWeight::get().writes(3))
@ -222,11 +222,11 @@ impl WeightInfo for () {
// 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: `1551 + c * (1019 ±27)`
// Minimum execution time: 281_073_000 picoseconds. // Minimum execution time: 282_654_000 picoseconds.
Weight::from_parts(280_778_987, 0) Weight::from_parts(286_257_905, 0)
.saturating_add(Weight::from_parts(0, 1551)) .saturating_add(Weight::from_parts(0, 1551))
// Standard Error: 92_951 // Standard Error: 92_951
.saturating_add(Weight::from_parts(3_489_552, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(2_838_516, 0).saturating_mul(c.into()))
.saturating_add(RocksDbWeight::get().reads(7)) .saturating_add(RocksDbWeight::get().reads(7))
.saturating_add(RocksDbWeight::get().writes(3)) .saturating_add(RocksDbWeight::get().writes(3))
.saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into()))
@ -253,8 +253,8 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `588` // Measured: `588`
// Estimated: `4053` // Estimated: `4053`
// Minimum execution time: 291_972_000 picoseconds. // Minimum execution time: 296_169_000 picoseconds.
Weight::from_parts(295_122_000, 0) Weight::from_parts(298_267_000, 0)
.saturating_add(Weight::from_parts(0, 4053)) .saturating_add(Weight::from_parts(0, 4053))
.saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().reads(8))
.saturating_add(RocksDbWeight::get().writes(5)) .saturating_add(RocksDbWeight::get().writes(5))
@ -283,8 +283,8 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `968` // Measured: `968`
// Estimated: `4433` // Estimated: `4433`
// Minimum execution time: 331_528_000 picoseconds. // Minimum execution time: 332_972_000 picoseconds.
Weight::from_parts(333_974_000, 0) Weight::from_parts(336_569_000, 0)
.saturating_add(Weight::from_parts(0, 4433)) .saturating_add(Weight::from_parts(0, 4433))
.saturating_add(RocksDbWeight::get().reads(10)) .saturating_add(RocksDbWeight::get().reads(10))
.saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes(4))
@ -324,7 +324,7 @@ impl WeightInfo for () {
// Measured: `11259` // Measured: `11259`
// Estimated: `14724` // Estimated: `14724`
// Minimum execution time: 3_842_259_000 picoseconds. // Minimum execution time: 3_842_259_000 picoseconds.
Weight::from_parts(3_985_167_000, 0) Weight::from_parts(3_853_670_000, 0)
.saturating_add(Weight::from_parts(0, 14724)) .saturating_add(Weight::from_parts(0, 14724))
.saturating_add(RocksDbWeight::get().reads(14)) .saturating_add(RocksDbWeight::get().reads(14))
.saturating_add(RocksDbWeight::get().writes(8)) .saturating_add(RocksDbWeight::get().writes(8))
@ -343,11 +343,11 @@ 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`)
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: `447`
// Estimated: `3913` // Estimated: `3912`
// Minimum execution time: 137_053_000 picoseconds. // Minimum execution time: 138_303_000 picoseconds.
Weight::from_parts(138_693_000, 0) Weight::from_parts(139_968_000, 0)
.saturating_add(Weight::from_parts(0, 3913)) .saturating_add(Weight::from_parts(0, 3912))
.saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().reads(5))
.saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes(4))
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-governance" name = "ghost-governance"
version = "0.3.7" version = "0.3.5"
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

View File

@ -40,27 +40,24 @@ mod benchmarks {
}; };
let preimage_init = claim_package_init.get_preimage(&dummy_evm_address, network_id); let preimage_init = claim_package_init.get_preimage(&dummy_evm_address, network_id);
let some_hash = SubstrateKeccakHasher::hash(&preimage_init);
let mut leaf_combined = sp_std::vec![0u8; 1 + preimage_init.len()];
leaf_combined[1..].copy_from_slice(&preimage_init);
let some_hash = SubstrateKeccakHasher::hash(&leaf_combined);
let mut current_hash = some_hash; let mut current_hash = some_hash;
let mut proof_hashes = Vec::with_capacity(max_proof_depth as usize); let mut proof_hashes = Vec::with_capacity(max_proof_depth as usize);
let mut current_index = target_index as usize; let mut current_index = target_index as usize;
let hash_len = SubstrateKeccakHasher::hash_len(); let hash_len = SubstrateKeccakHasher::hash_len();
let mut combined = sp_std::vec![1u8; 1 + hash_len * 2]; let mut combined = sp_std::vec![0u8; hash_len * 2];
for _ in 0..max_proof_depth { for _ in 0..max_proof_depth {
proof_hashes.push(some_hash); proof_hashes.push(some_hash);
if current_index % 2 == 0 { if current_index % 2 == 0 {
combined[1..1 + hash_len].copy_from_slice(&current_hash.to_fixed_bytes()); combined[..hash_len].copy_from_slice(&current_hash.to_fixed_bytes());
combined[1 + hash_len..1 + hash_len * 2].copy_from_slice(&some_hash.to_fixed_bytes()); combined[hash_len..].copy_from_slice(&some_hash.to_fixed_bytes());
} else { } else {
combined[1..1 + hash_len].copy_from_slice(&some_hash.to_fixed_bytes()); combined[..hash_len].copy_from_slice(&some_hash.to_fixed_bytes());
combined[1 + hash_len..1 + hash_len * 2].copy_from_slice(&current_hash.to_fixed_bytes()); combined[hash_len..].copy_from_slice(&current_hash.to_fixed_bytes());
} }
current_hash = SubstrateKeccakHasher::hash(&combined); current_hash = SubstrateKeccakHasher::hash(&combined);

View File

@ -176,18 +176,18 @@ fn claim_happy_path() {
fn verify_proof_from_python_preclaims_for_sepolia() { fn verify_proof_from_python_preclaims_for_sepolia() {
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
// =========================================================================================================== // ===========================================================================================================
// === FINAL MERKLE ROOT FOR [SEPOLIA]: c41c281c8404f5ce0adfca067ef8ed260f28c2cb1d7944c84ce2431936b1919e === // === FINAL MERKLE ROOT FOR [SEPOLIA]: 0xd7f7f0061338c2c59a96caa8a2572491315755cdcce534954d4ce30150c3bb7c ===
// =========================================================================================================== // ===========================================================================================================
// [+] Total padded leaves: 128 // [+] Total padded leaves: 128
// [+] Merkle tree size: 255 // [+] Merkle tree size: 255
// [+] Network ID: 11155111 // [+] Network ID: 11155111
// [+] Proof size: 7 // [+] Proof size: 7
// [+] Total shares: 1398900000000000000000 // [+] Total shares: 694000000000000000000
let network_id = 11155111u64; let network_id = 11155111u64;
let merkle_root = EvmHash::from(hex!("c41c281c8404f5ce0adfca067ef8ed260f28c2cb1d7944c84ce2431936b1919e")); let merkle_root = EvmHash::from(hex!("d7f7f0061338c2c59a96caa8a2572491315755cdcce534954d4ce30150c3bb7c"));
let proof_size = 7; let proof_size = 7;
let total_shares = 1398900000000000000000; let total_shares = 694000000000000000000;
let network_state = NetworkShare::new(total_shares, merkle_root, proof_size); let network_state = NetworkShare::new(total_shares, merkle_root, proof_size);
let global_state = ShareState::new(total_shares); let global_state = ShareState::new(total_shares);
@ -198,16 +198,16 @@ fn verify_proof_from_python_preclaims_for_sepolia() {
let claim_package_1 = ClaimPackage { let claim_package_1 = ClaimPackage {
index: 0, index: 0,
token_id: 1, token_id: 1,
shares: 684900000000000000000, shares: 670000000000000000000,
merkle_proof: BoundedVec::try_from( merkle_proof: BoundedVec::try_from(
vec![ vec![
EvmHash::from(hex!("86d599b297ed8fb56476884b43502e15e7b207835f9a62bd07b4f3338ac63b44")), EvmHash::from(hex!("4dba08ba4fae6cbb0a6be6bdce81e91baf913d1857f470e97388157edd4d8d5c")),
EvmHash::from(hex!("85ec1f887b1a32e76cd1b70de6a5b1900045efd7dfe3b218d3b6cef672735da6")), EvmHash::from(hex!("7c1a4d2ebe6a500171b0c0f6c624898261da62d09c132106c4acec277660bd01")),
EvmHash::from(hex!("1e8a291eb2ba08696ca482c7869cab5ad360da4e4df55589adf40b08b020cc5b")), EvmHash::from(hex!("00c5bca05597b46f72d9ee739bd3c6ff80ebd1d20944879fe0c8d1dc9fda1643")),
EvmHash::from(hex!("a090ff633d4831ca76640ffce9d9399a0f8409bbbc98814d0d885c538c9ebc08")), EvmHash::from(hex!("5cf752cd738db6581182f07395e89cc61cd2ca630d6e85235d506f7395217d5f")),
EvmHash::from(hex!("85ad79082ed24d2fc6748f131ed39280d402cb7a0844b42b9d768d4639b516a9")), EvmHash::from(hex!("4df068cecd63b6ccfd326df735afbfbe254df62613f7d9b52769f0e99f156957")),
EvmHash::from(hex!("2c55408bc86c5a292611bc01ba46ac6c6b37b8409097b752bad884be24249ec4")), EvmHash::from(hex!("d7f20777e3a1fed303fe1a459ce115e2561a92d66b34fd16dd793b8b69295082")),
EvmHash::from(hex!("9e046ea7683ac6dfa95caf833912d806b41296fcaa86718b4822f42ae68a6ff5")) EvmHash::from(hex!("4524fdc1aa98beafabe1341f53ee2373e541ad2efd152963fd9ce94571d283e4")),
] ]
).unwrap(), ).unwrap(),
}; };
@ -226,16 +226,16 @@ fn verify_proof_from_python_preclaims_for_sepolia() {
let claim_package_2 = ClaimPackage { let claim_package_2 = ClaimPackage {
index: 2, index: 2,
token_id: 3, token_id: 3,
shares: 14900000000000000000, shares: 8000000000000000000,
merkle_proof: BoundedVec::try_from( merkle_proof: BoundedVec::try_from(
vec![ vec![
EvmHash::from(hex!("547eb6ce3345e183448c61ee30e4eca0523537114e8d3971894196598651040e")), EvmHash::from(hex!("a8bbe4e0578964e3e6c40b93380967d69b7a1fd0358bffe789473892ec82872d")),
EvmHash::from(hex!("9e9936d6cd248898747a8d29d2ef1b02ca06c40583873fd7c3a7ddd1554f5472")), EvmHash::from(hex!("9b771d13977930979a26632d74e350885d5750b00646a5b03114b5815afb9f2f")),
EvmHash::from(hex!("1e8a291eb2ba08696ca482c7869cab5ad360da4e4df55589adf40b08b020cc5b")), EvmHash::from(hex!("00c5bca05597b46f72d9ee739bd3c6ff80ebd1d20944879fe0c8d1dc9fda1643")),
EvmHash::from(hex!("a090ff633d4831ca76640ffce9d9399a0f8409bbbc98814d0d885c538c9ebc08")), EvmHash::from(hex!("5cf752cd738db6581182f07395e89cc61cd2ca630d6e85235d506f7395217d5f")),
EvmHash::from(hex!("85ad79082ed24d2fc6748f131ed39280d402cb7a0844b42b9d768d4639b516a9")), EvmHash::from(hex!("4df068cecd63b6ccfd326df735afbfbe254df62613f7d9b52769f0e99f156957")),
EvmHash::from(hex!("2c55408bc86c5a292611bc01ba46ac6c6b37b8409097b752bad884be24249ec4")), EvmHash::from(hex!("d7f20777e3a1fed303fe1a459ce115e2561a92d66b34fd16dd793b8b69295082")),
EvmHash::from(hex!("9e046ea7683ac6dfa95caf833912d806b41296fcaa86718b4822f42ae68a6ff5")) EvmHash::from(hex!("4524fdc1aa98beafabe1341f53ee2373e541ad2efd152963fd9ce94571d283e4")),
] ]
).unwrap(), ).unwrap(),
}; };
@ -254,16 +254,16 @@ fn verify_proof_from_python_preclaims_for_sepolia() {
let claim_package_3 = ClaimPackage { let claim_package_3 = ClaimPackage {
index: 6, index: 6,
token_id: 7, token_id: 7,
shares: 10900000000000000000, shares: 4000000000000000000,
merkle_proof: BoundedVec::try_from( merkle_proof: BoundedVec::try_from(
vec![ vec![
EvmHash::from(hex!("441f13d353fe0224fe4ab418fe56c66287e0ba1e5e562f56a4b7195ca3d9f741")), EvmHash::from(hex!("d28eec1544597d9e050c88a7a84535be82caf9b9e0b0c9b59b39283e7885a0d1")),
EvmHash::from(hex!("17f9ae41fbcbbfc35accf1e4e132a905b0a95e68e085757ae8304b6a0554e908")), EvmHash::from(hex!("6e939188f98c3ed00931e66fdfc220c036b98edc54a212f5b18e2d3776c7c22f")),
EvmHash::from(hex!("a6f6783441ed0d4c5f1da8d1f026c037e15706c4ecb4c400216d485105ec9596")), EvmHash::from(hex!("4141baa2d892b0111bbb102078bd3ad5331c74f176b228c588741c1c306cb67d")),
EvmHash::from(hex!("a090ff633d4831ca76640ffce9d9399a0f8409bbbc98814d0d885c538c9ebc08")), EvmHash::from(hex!("5cf752cd738db6581182f07395e89cc61cd2ca630d6e85235d506f7395217d5f")),
EvmHash::from(hex!("85ad79082ed24d2fc6748f131ed39280d402cb7a0844b42b9d768d4639b516a9")), EvmHash::from(hex!("4df068cecd63b6ccfd326df735afbfbe254df62613f7d9b52769f0e99f156957")),
EvmHash::from(hex!("2c55408bc86c5a292611bc01ba46ac6c6b37b8409097b752bad884be24249ec4")), EvmHash::from(hex!("d7f20777e3a1fed303fe1a459ce115e2561a92d66b34fd16dd793b8b69295082")),
EvmHash::from(hex!("9e046ea7683ac6dfa95caf833912d806b41296fcaa86718b4822f42ae68a6ff5")) EvmHash::from(hex!("4524fdc1aa98beafabe1341f53ee2373e541ad2efd152963fd9ce94571d283e4"))
] ]
).unwrap(), ).unwrap(),
}; };
@ -282,16 +282,16 @@ fn verify_proof_from_python_preclaims_for_sepolia() {
let claim_package_4 = ClaimPackage { let claim_package_4 = ClaimPackage {
index: 35, index: 35,
token_id: 36, token_id: 36,
shares: 10900000000000000000, shares: 4000000000000000000,
merkle_proof: BoundedVec::try_from( merkle_proof: BoundedVec::try_from(
vec![ vec![
EvmHash::from(hex!("5ddb291d62d02afab17cee218f2f367d612736b0f1ae59d2d28aac811e2057f3")), EvmHash::from(hex!("6b405422bcab22b7c28a9b429096e31d664522154856efb0d7b16485080b2e2a")),
EvmHash::from(hex!("d990cb37076db084b1621bc8327e0f740e242da4c463ea3a0457a6483c07fdbf")), EvmHash::from(hex!("620bb1858eaf6c6bb543fcf5f4b0d0b5adfbb95506403038eb153f075a00f522")),
EvmHash::from(hex!("7bf41c14904c75e189893d05cf99c55516a194882463980cf08468c3bfd7dd8a")), EvmHash::from(hex!("e0b7058849ff216808963201ad2336f5587ff02eff08aceddb4764cc785413fd")),
EvmHash::from(hex!("1c4c8136fe9e6dc08dc1c69f2da707a271ae510cdb5af6051b5222f2812edee0")), EvmHash::from(hex!("e23325a502fe4248c8e049400a92a1c655689499c129b0ce6be3fad5d4a12dc1")),
EvmHash::from(hex!("3ec8d2443fd6f9decef06bf930e37cd37d78bf1c6004dc84b9ca1199712a82f8")), EvmHash::from(hex!("0cde8f646452003d6c8ff1fd265ea41cd3af2e733e63ec25a9dfc82ddf41e968")),
EvmHash::from(hex!("1951c00e48f734ba95daeb3e8f6a2d971cc6fb0afac471ae39a21013f5756794")), EvmHash::from(hex!("c012942dae89ee6d1e1e44e876ae29b9421aaf0597dd2345f07a1439a98e0cbd")),
EvmHash::from(hex!("9e046ea7683ac6dfa95caf833912d806b41296fcaa86718b4822f42ae68a6ff5")) EvmHash::from(hex!("4524fdc1aa98beafabe1341f53ee2373e541ad2efd152963fd9ce94571d283e4"))
] ]
).unwrap(), ).unwrap(),
}; };

View File

@ -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-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2026-09-05, 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
@ -65,11 +65,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: 214_208_000 picoseconds. // Minimum execution time: 216_605_000 picoseconds.
Weight::from_parts(216_987_870, 0) Weight::from_parts(217_612_486, 0)
.saturating_add(Weight::from_parts(0, 3748)) .saturating_add(Weight::from_parts(0, 3748))
// Standard Error: 30_856 // Standard Error: 23_409
.saturating_add(Weight::from_parts(1_702_104, 0).saturating_mul(p.into())) .saturating_add(Weight::from_parts(1_544_250, 0).saturating_mul(p.into()))
.saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().reads(4))
.saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes(4))
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-helpers" name = "ghost-helpers"
version = "0.0.11" version = "0.0.6"
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

View File

@ -34,18 +34,20 @@ pub type NetworkIdU32 = u32;
pub type NetworkIdU64 = u64; pub type NetworkIdU64 = u64;
pub type NetworkIdU128 = u128; pub type NetworkIdU128 = u128;
pub fn get_byzantium_quorum_threshold<I>(value: I) -> I pub fn get_byzantium_threshold<I>(value: I) -> I
where where
I: num_traits::PrimInt, I: num_traits::PrimInt,
{ {
let zero = I::zero(); let zero = I::zero();
let one = I::one(); let one = I::one();
let three = one + one + one; let two = one + one;
let three = two + one;
if value == zero { return zero; } if value == zero {
return zero;
}
let f = (value - one) / three; (value - one) / three * two + one
value - f
} }
pub struct SubstrateBlake2Hasher; pub struct SubstrateBlake2Hasher;
@ -95,43 +97,3 @@ impl GhostHasher for UtxoSha2Hasher {
H256::zero() H256::zero()
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bft_threshold_standard_paper_cases() {
// Lower boundaries (f increases here)
assert_eq!(get_byzantium_quorum_threshold(1u32), 1);
assert_eq!(get_byzantium_quorum_threshold(4u32), 3);
assert_eq!(get_byzantium_quorum_threshold(7u32), 5);
assert_eq!(get_byzantium_quorum_threshold(10u32), 7);
// Upper boundaries (max nodes for a given 'f')
assert_eq!(get_byzantium_quorum_threshold(3u32), 3);
assert_eq!(get_byzantium_quorum_threshold(6u32), 5);
assert_eq!(get_byzantium_quorum_threshold(9u32), 7);
}
#[test]
fn test_bft_threshold_zero_nodes() {
assert_eq!(get_byzantium_quorum_threshold(0u32), 0);
}
#[test]
fn test_bft_threshold_integer_boundaries() {
let max_val = usize::MAX;
let expected_f = (max_val - 1) / 3;
let expected_honest = max_val - expected_f;
assert_eq!(get_byzantium_quorum_threshold(max_val), expected_honest);
}
#[test]
fn test_bft_threshold_different_types() {
assert_eq!(get_byzantium_quorum_threshold(4u8), 3u8);
assert_eq!(get_byzantium_quorum_threshold(4u64), 3u64);
assert_eq!(get_byzantium_quorum_threshold(4usize), 3usize);
}
}

View File

@ -3,29 +3,6 @@ use sp_arithmetic::traits::AtLeast8BitUnsigned;
use sp_runtime::traits::UniqueSaturatedInto; use sp_runtime::traits::UniqueSaturatedInto;
use sp_std::vec::Vec; use sp_std::vec::Vec;
const LEAF_PREFIX: u8 = 0;
const NODE_PREFIX: u8 = 1;
fn leaf_prefixed<H>(preimage: &[u8]) -> H::Hash
where
H: GhostHasher,
{
let mut prefixed_data = sp_std::vec![LEAF_PREFIX; 1 + preimage.len()];
prefixed_data[1..].copy_from_slice(preimage);
H::hash(&prefixed_data)
}
fn node_prefixed<H>(preimage1: &[u8], preimage2: &[u8]) -> H::Hash
where
H: GhostHasher,
{
let total_len = preimage1.len() + preimage2.len();
let mut prefixed_data = sp_std::vec![NODE_PREFIX; 1 + total_len];
prefixed_data[1..1 + preimage1.len()].copy_from_slice(preimage1);
prefixed_data[1 + preimage1.len()..].copy_from_slice(preimage2);
H::hash(&prefixed_data)
}
pub fn generate_tree<H, I, S, F, E>( pub fn generate_tree<H, I, S, F, E>(
max_index: I, max_index: I,
raw_values: S, raw_values: S,
@ -40,28 +17,30 @@ where
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;
let mut merkle_tree = sp_std::vec![H::empty(); total_capacity];
let empty_hash = H::empty();
let empty_leaf_hash = leaf_prefixed::<H>(empty_hash.as_ref());
let mut merkle_tree = sp_std::vec![empty_leaf_hash; total_capacity];
for item in raw_values.into_iter() { for item in raw_values.into_iter() {
let (index, preimage) = generate_preimage(item)?; let (index, preimage) = generate_preimage(item)?;
if index >= padded_leaves { return Ok(sp_std::vec![]); } merkle_tree[index] = H::hash(&preimage);
merkle_tree[index] = leaf_prefixed::<H>(&preimage)
} }
let mut layer_start = 0; let mut layer_start = 0;
let mut current_layer_len = padded_leaves; let mut current_layer_len = padded_leaves;
let mut write_ptr = padded_leaves; let mut write_ptr = padded_leaves;
let hash_len = H::hash_len();
let mut combined = sp_std::vec![0u8; hash_len * 2];
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].as_ref();
let right_bytes = merkle_tree[layer_index | 1].as_ref(); let right_bytes = merkle_tree[layer_index | 1].as_ref();
merkle_tree[write_ptr] = node_prefixed::<H>(left_bytes, right_bytes); combined[..hash_len].copy_from_slice(left_bytes);
combined[hash_len..].copy_from_slice(right_bytes);
merkle_tree[write_ptr] = H::hash(&combined);
write_ptr += 1; write_ptr += 1;
} }
layer_start += current_layer_len; layer_start += current_layer_len;
@ -71,17 +50,11 @@ where
Ok(merkle_tree) Ok(merkle_tree)
} }
pub fn generate_proof<H, I>( pub fn generate_proof<H, I>(merkle_tree: &[H::Hash], max_index: I, index: I) -> Vec<H::Hash>
merkle_tree: &[H::Hash],
max_index: I,
index: I,
) -> Vec<H::Hash>
where where
H: GhostHasher, H: GhostHasher,
I: AtLeast8BitUnsigned + UniqueSaturatedInto<usize>, I: AtLeast8BitUnsigned + UniqueSaturatedInto<usize>,
{ {
if index > max_index { return sp_std::vec![]; }
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();
let mut current_layer_len = num_of_leaves.next_power_of_two(); let mut current_layer_len = num_of_leaves.next_power_of_two();
@ -114,21 +87,29 @@ where
H: GhostHasher, H: GhostHasher,
I: PartialOrd + UniqueSaturatedInto<usize>, I: PartialOrd + UniqueSaturatedInto<usize>,
{ {
let mut current_hash = H::hash(preimage);
let mut current_index: usize = index.unique_saturated_into(); let mut current_index: usize = index.unique_saturated_into();
if current_index >= (1 << merkle_proof.len()) { return false; }
let mut current_hash = leaf_prefixed::<H>(preimage); if current_index >= (1 << merkle_proof.len()) {
return false;
}
let hash_len = H::hash_len();
let mut combined = sp_std::vec![0u8; hash_len * 2];
for sibling in merkle_proof.iter() { for sibling in merkle_proof.iter() {
let sibling_bytes = sibling.as_ref(); let sibling_bytes = sibling.as_ref();
let hash_bytes = current_hash.as_ref(); let hash_bytes = current_hash.as_ref();
if current_index % 2 == 0 { if current_index % 2 == 0 {
current_hash = node_prefixed::<H>(hash_bytes, sibling_bytes); combined[..hash_len].copy_from_slice(hash_bytes);
combined[hash_len..].copy_from_slice(sibling_bytes);
} else { } else {
current_hash = node_prefixed::<H>(sibling_bytes, hash_bytes); combined[..hash_len].copy_from_slice(sibling_bytes);
combined[hash_len..].copy_from_slice(hash_bytes);
} }
current_hash = H::hash(&combined);
current_index >>= 1; current_index >>= 1;
} }
@ -176,27 +157,24 @@ mod tests {
assert_eq!(tree.len(), 7); assert_eq!(tree.len(), 7);
let h0 = TestBlake2Hasher::hash(&[ &[0u8], [1].as_slice() ].concat()); let h0 = TestBlake2Hasher::hash(&vec![1]);
let h1 = TestBlake2Hasher::hash(&[ &[0u8], [2].as_slice() ].concat()); let h1 = TestBlake2Hasher::hash(&vec![2]);
let h2 = TestBlake2Hasher::hash(&[ &[0u8], [3].as_slice() ].concat()); let h2 = TestBlake2Hasher::hash(&vec![3]);
let h3 = TestBlake2Hasher::hash(&[ &[0u8], [4].as_slice() ].concat()); let h3 = TestBlake2Hasher::hash(&vec![4]);
let mut c1 = [0u8; 65]; let mut c1 = [0u8; 64];
c1[0] = NODE_PREFIX; c1[..32].copy_from_slice(h0.as_ref());
c1[1..33].copy_from_slice(h0.as_ref()); c1[32..].copy_from_slice(h1.as_ref());
c1[33..].copy_from_slice(h1.as_ref());
let parent_left = TestBlake2Hasher::hash(&c1); let parent_left = TestBlake2Hasher::hash(&c1);
let mut c2 = [0u8; 65]; let mut c2 = [0u8; 64];
c2[0] = NODE_PREFIX; c2[..32].copy_from_slice(h2.as_ref());
c2[1..33].copy_from_slice(h2.as_ref()); c2[32..].copy_from_slice(h3.as_ref());
c2[33..].copy_from_slice(h3.as_ref());
let parent_right = TestBlake2Hasher::hash(&c2); let parent_right = TestBlake2Hasher::hash(&c2);
let mut c_root = [0u8; 65]; let mut c_root = [0u8; 64];
c_root[0] = NODE_PREFIX; c_root[..32].copy_from_slice(parent_left.as_ref());
c_root[1..33].copy_from_slice(parent_left.as_ref()); c_root[32..].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 = TestBlake2Hasher::hash(&c_root);
assert_eq!(tree.last().unwrap(), &expected_root); assert_eq!(tree.last().unwrap(), &expected_root);
@ -218,23 +196,17 @@ mod tests {
) )
.unwrap(); .unwrap();
let mut empty_data = sp_std::vec![LEAF_PREFIX];
empty_data.extend_from_slice(&H256::zero().to_fixed_bytes());
let empty_hash = TestBlake2Hasher::hash(&empty_data);
assert_eq!(tree.len(), 7); assert_eq!(tree.len(), 7);
assert_eq!(tree[3], empty_hash); assert_eq!(tree[3], H256::zero());
let mut leaf2_data = sp_std::vec![LEAF_PREFIX]; let h2 = TestBlake2Hasher::hash(&vec![3]);
leaf2_data.extend_from_slice(&[3]); let h3_empty = H256::zero();
let h2 = TestBlake2Hasher::hash(&leaf2_data);
let mut combined_right = [0u8; 65];
combined_right[0] = NODE_PREFIX;
combined_right[1..33].copy_from_slice(h2.as_ref());
combined_right[33..].copy_from_slice(empty_hash.as_ref());
let mut combined_right = [0u8; 64];
combined_right[..32].copy_from_slice(h2.as_ref());
combined_right[32..].copy_from_slice(h3_empty.as_ref());
let expected_parent_right = TestBlake2Hasher::hash(&combined_right); let expected_parent_right = TestBlake2Hasher::hash(&combined_right);
assert_eq!(tree[5], expected_parent_right); assert_eq!(tree[5], expected_parent_right);
} }
@ -279,7 +251,7 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!(tree.len(), 1); assert_eq!(tree.len(), 1);
assert_eq!(tree[0], TestBlake2Hasher::hash(&vec![LEAF_PREFIX, 42])); assert_eq!(tree[0], TestBlake2Hasher::hash(&vec![42]));
} }
#[test] #[test]
@ -400,14 +372,10 @@ mod tests {
raw_data, raw_data,
|(index, bytes)| Ok((index, bytes)), |(index, bytes)| Ok((index, bytes)),
) )
.unwrap(); .unwrap();
let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 2); let proof = generate_proof::<TestBlake2Hasher, u32>(&tree, max_index, 2);
assert_eq!(proof[0], H256::zero());
let mut empty_data = sp_std::vec![LEAF_PREFIX];
empty_data.extend_from_slice(&H256::zero().to_fixed_bytes());
let empty_hash = TestBlake2Hasher::hash(&empty_data);
assert_eq!(proof[0], empty_hash);
let root = *tree.last().unwrap(); let root = *tree.last().unwrap();
let is_valid = let is_valid =

View File

@ -175,43 +175,27 @@ pub struct NetworkClaim<NetworkId, Balance> {
pub proof_size: u32 pub proof_size: u32
} }
#[derive(Default)] impl<NetworkId, Balance> NetworkClaim<NetworkId, Balance> {
pub struct NetworkClaimBuilder<NetworkId, Balance> {
network_id: Option<NetworkId>,
merkle_root: Option<H256>,
amount: Option<Balance>,
proof_size: Option<u32>
}
impl<NetworkId, Balance> NetworkClaimBuilder<NetworkId, Balance> {
pub fn with_amount(mut self, amount: Balance) -> Self { pub fn with_amount(mut self, amount: Balance) -> Self {
self.amount = Some(amount); self.amount = amount;
self self
} }
pub fn with_network_id(mut self, network_id: NetworkId) -> Self { pub fn with_network_id(mut self, network_id: NetworkId) -> Self {
self.network_id = Some(network_id); self.network_id = network_id;
self self
} }
pub fn with_merkle_root(mut self, merkle_root: H256) -> Self { pub fn with_merkle_root(mut self, merkle_root: H256) -> Self {
self.merkle_root = Some(merkle_root); self.merkle_root = merkle_root;
self self
} }
pub fn with_proof_size(mut self, proof_size: u32) -> Self { pub fn with_proof_size(mut self, proof_size: u32) -> Self {
self.proof_size = Some(proof_size); self.proof_size = proof_size;
self self
} }
pub fn build(self) -> NetworkClaim<NetworkId, Balance> {
NetworkClaim {
network_id: self.network_id.expect("NetworkClaim Error: missing network_id"),
amount: self.amount.expect("NetworkClaim Error: missing amount"),
merkle_root: self.merkle_root.expect("NetworkClaim Error: merkle_root"),
proof_size: self.proof_size.expect("NetworkClaim Error: missing proof_size"),
}
}
} }
#[derive( #[derive(
@ -234,7 +218,6 @@ pub struct NetworkData {
pub r#type: NetworkType, pub r#type: NetworkType,
pub curve: NetworkCurve, pub curve: NetworkCurve,
pub decimals: u8,
pub finality_delay: u64, pub finality_delay: u64,
pub rate_limit_delay: u64, pub rate_limit_delay: u64,
@ -252,7 +235,6 @@ pub struct NetworkDataBuilder {
pub r#type: NetworkType, pub r#type: NetworkType,
pub curve: NetworkCurve, pub curve: NetworkCurve,
pub decimals: u8,
pub finality_delay: u64, pub finality_delay: u64,
pub rate_limit_delay: u64, pub rate_limit_delay: u64,
@ -283,11 +265,6 @@ impl NetworkDataBuilder {
self self
} }
pub fn with_decimals(mut self, decimals: u8) -> Self {
self.decimals = decimals;
self
}
pub fn with_finality_delay(mut self, finality_delay: u64) -> Self { pub fn with_finality_delay(mut self, finality_delay: u64) -> Self {
self.finality_delay = finality_delay; self.finality_delay = finality_delay;
self self
@ -346,7 +323,6 @@ impl NetworkDataBuilder {
r#type: self.r#type, r#type: self.r#type,
curve: self.curve, curve: self.curve,
decimals: self.decimals,
finality_delay: self.finality_delay, finality_delay: self.finality_delay,
rate_limit_delay: self.rate_limit_delay, rate_limit_delay: self.rate_limit_delay,

View File

@ -3,10 +3,11 @@ 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_SCRIPT_LEN: usize = 512; const MAX_SCRIPT_LEN: usize = 34;
pub const MAX_TX_LEN: usize = 4096; const MAX_WITNESS_STACK_DEPTH: usize = 3;
const MAX_WITNESS_ITEMS_LEN: usize = 73;
type Prefix = [u8; 7]; pub const MAX_TX_LEN: usize = 512;
pub struct TxIn<H: GhostHasher> { pub struct TxIn<H: GhostHasher> {
pub prev_txid: H::Hash, pub prev_txid: H::Hash,
@ -20,11 +21,24 @@ pub struct TxOut {
pub script_pubkey: Vec<u8>, pub script_pubkey: Vec<u8>,
} }
pub struct Transaction<H: GhostHasher> { pub struct Witness {
version: i32, pub stack: Vec<Vec<u8>>,
inputs: Vec<TxIn<H>>, }
outputs: Vec<TxOut>,
lock_time: u32, pub enum Transaction<H: GhostHasher> {
Legacy {
version: i32,
inputs: Vec<TxIn<H>>,
outputs: Vec<TxOut>,
lock_time: u32,
},
SegWit {
version: i32,
inputs: Vec<TxIn<H>>,
outputs: Vec<TxOut>,
witnesses: Vec<Witness>,
lock_time: u32,
},
} }
pub struct Header<H: GhostHasher> { pub struct Header<H: GhostHasher> {
@ -149,8 +163,24 @@ where
H: GhostHasher<HashBytes = [u8; 32]>, H: GhostHasher<HashBytes = [u8; 32]>,
{ {
pub fn compute_txid(&self) -> Option<H::Hash> { pub fn compute_txid(&self) -> Option<H::Hash> {
let version_bytes = self.version.to_le_bytes(); let (version, inputs, outputs, lock_time) = match self {
let lock_time_bytes = self.lock_time.to_le_bytes(); Self::Legacy {
version,
inputs,
outputs,
lock_time,
} => (version, inputs, outputs, lock_time),
Self::SegWit {
version,
inputs,
outputs,
lock_time,
..
} => (version, inputs, outputs, lock_time),
};
let version_bytes = version.to_le_bytes();
let lock_time_bytes = lock_time.to_le_bytes();
let mut tx_buffer = [0u8; MAX_TX_LEN]; let mut tx_buffer = [0u8; MAX_TX_LEN];
let mut cursor = 0; let mut cursor = 0;
@ -158,14 +188,11 @@ where
tx_buffer[cursor..cursor + 4].copy_from_slice(&version_bytes); tx_buffer[cursor..cursor + 4].copy_from_slice(&version_bytes);
cursor += 4; cursor += 4;
cursor = Self::serialize_inputs_and_outputs( cursor = Self::serialize_inputs_and_outputs(&mut tx_buffer, cursor, inputs, outputs)?;
&mut tx_buffer,
cursor,
&self.inputs,
&self.outputs,
)?;
if cursor + 4 > MAX_TX_LEN { return None; } if cursor + 4 > MAX_TX_LEN {
return None;
}
tx_buffer[cursor..cursor + 4].copy_from_slice(&lock_time_bytes); tx_buffer[cursor..cursor + 4].copy_from_slice(&lock_time_bytes);
cursor += 4; cursor += 4;
@ -240,21 +267,29 @@ where
let mut cursor = cursor; let mut cursor = cursor;
if value < 253 { if value < 253 {
if cursor + 1 > MAX_TX_LEN { return None; } if cursor + 1 > MAX_TX_LEN {
return None;
}
buffer[cursor] = value as u8; buffer[cursor] = value as u8;
cursor += 1; cursor += 1;
} else if value <= 0xffff { } else if value <= 0xffff {
if cursor + 3 > MAX_TX_LEN { return None; } if cursor + 3 > MAX_TX_LEN {
return None;
}
buffer[cursor] = 253; buffer[cursor] = 253;
buffer[cursor + 1..cursor + 3].copy_from_slice(&(value as u16).to_le_bytes()); buffer[cursor + 1..cursor + 3].copy_from_slice(&(value as u16).to_le_bytes());
cursor += 3; cursor += 3;
} else if value <= 0xffffffff { } else if value <= 0xffffffff {
if cursor + 5 > MAX_TX_LEN { return None; } if cursor + 5 > MAX_TX_LEN {
return None;
}
buffer[cursor] = 254; buffer[cursor] = 254;
buffer[cursor + 1..cursor + 5].copy_from_slice(&(value as u32).to_le_bytes()); buffer[cursor + 1..cursor + 5].copy_from_slice(&(value as u32).to_le_bytes());
cursor += 5; cursor += 5;
} else { } else {
if cursor + 9 > MAX_TX_LEN { return None; } if cursor + 9 > MAX_TX_LEN {
return None;
}
buffer[cursor] = 255; buffer[cursor] = 255;
buffer[cursor + 1..cursor + 9].copy_from_slice(&value.to_le_bytes()); buffer[cursor + 1..cursor + 9].copy_from_slice(&value.to_le_bytes());
cursor += 9; cursor += 9;
@ -263,73 +298,141 @@ where
Some(cursor) Some(cursor)
} }
pub fn parse_receiver_and_amount( pub fn validate<I, A>(
&self, &self,
o_index_i: I,
w_index_i: I,
destination: &[u8], destination: &[u8],
prefix: &Prefix, expected_amount_a: A,
) -> Option<([u8; 32], u64)> { ) -> Option<[u8; 32]>
let mut maybe_receiver = None; where
let mut op_return_count = 0; I: sp_runtime::traits::UniqueSaturatedInto<usize>,
let mut total_amount: u64 = 0; A: sp_runtime::traits::UniqueSaturatedInto<u128>,
{
let o_index: usize = o_index_i.unique_saturated_into();
let w_index: usize = w_index_i.unique_saturated_into();
for output in self.outputs.iter() { let expected_amount_u128: u128 = expected_amount_a.unique_saturated_into();
let script = &output.script_pubkey; let expected_amount: u64 = expected_amount_u128.try_into().ok()?;
if let Some(receiver) = self.parse_receiver(script, prefix) { match self {
op_return_count += 1; Self::Legacy { outputs, .. } => {
maybe_receiver = Some(receiver); let output = outputs.get(o_index)?;
if expected_amount != output.value {
return None;
}
if output.script_pubkey.len() != 57 {
return None;
}
let slice = &output.script_pubkey;
let receiver_address = self.parse_receiver(slice)?;
if receiver_address != destination {
return None;
}
let mut extra_data = [0u8; 32];
extra_data.copy_from_slice(&slice[25..57]);
Some(extra_data)
} }
Self::SegWit {
witnesses, outputs, ..
} => {
let output = outputs.get(o_index)?;
if expected_amount != output.value {
return None;
}
if script == &destination { let receiver_address = self.parse_receiver(&output.script_pubkey)?;
total_amount = total_amount.checked_add(output.value)?; if receiver_address != destination {
return None;
}
let witness = witnesses.get(w_index)?;
let target_account: [u8; 32];
// NOTE: change it right after the real bridging tx
// will take place, or find something similar
#[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
{
let _ = witness.stack;
target_account = [105u8; 32]; // 0x69 in decimal
}
#[cfg(not(any(feature = "runtime-benchmarks", feature = "std")))]
{
if witness.stack.len() < 3 || witness.stack[2].len() != 32 {
return None;
}
target_account = witness.stack[2][..32].try_into().ok()?;
}
Some(target_account)
} }
} }
}
if total_amount > 0 && op_return_count == 1 { fn parse_receiver(&self, script: &[u8]) -> Option<[u8; 32]> {
maybe_receiver.map(|receiver| (receiver, total_amount)) let mut receiver = [0u8; 32];
} else {
None // 1. Parse Pay-to-Taproot (P2TR / SegWit v1)
// Markers: OP_1 (0x51) + OP_PUSHBYTES_32 (0x20) + 32 bytes key
if script.len() == 34 && script[0] == 0x51 && script[1] == 0x20 {
receiver.copy_from_slice(&script[2..34]);
return Some(receiver);
} }
}
pub fn convert_into_p2pkh(hash: &[u8]) -> Option<[u8; 25]> { // 2. Parse Pay-to-Witness-Script-Hash (P2WSH / SegWit v0)
if hash.len() != 20 { return None; } // Markers: OP_0 (0x00) + OP_PUSHBYTES_32 (0x20) + 32 bytes hash script
if script.len() == 34 && script[0] == 0x00 && script[1] == 0x20 {
receiver.copy_from_slice(&script[2..34]);
return Some(receiver);
}
let mut script = [0u8; 25]; // 3a. Parse Native SegWit 20-bytes key (P2WPKH) zero-padding
// Markers: 22 bytes len, starts with OP_0 (0x00), next OP_PUSHBYTES_20 (0x14)
if script.len() == 22 && script[0] == 0x00 && script[1] == 0x14 {
receiver[..20].copy_from_slice(&script[2..22]);
return Some(receiver);
}
script[0] = 0x76; // OP_DUP // 3b. Parse Pay-to-Script-Hash (P2SH)
script[1] = 0xa9; // OP_HASH160 // Script: OP_HASH160 (0xa9) OP_PUSHBYTES_20 (0x14) + 20 bytes hash + OP_EQUAL (0x87)
script[2] = 0x14; // OP_PUSHBYTES_20 if script.len() == 23 && script[0] == 0xa9 && script[1] == 0x14 && script[22] == 0x87 {
script[3..23].copy_from_slice(hash); receiver[..20].copy_from_slice(&script[2..22]);
script[23] = 0x88; // OP_EQUALVERIFY return Some(receiver);
script[24] = 0xac; // OP_CHECKSIG }
Some(script) // 4. Parse Legacy (P2PKH) zero-padding
} // Script: OP_DUP(0x76) OP_HASH160(0xa9) OP_PUSHBYTES_20(0x14) +
// 20 bytes hash + OP_EQUALVERIFY(0x88) OP_CHECKSIG(0xac)
if script.len() == 25
&& script[0] == 0x76
&& script[1] == 0xa9
&& script[2] == 0x14
&& script[23] == 0x88
&& script[24] == 0xac
{
receiver[..20].copy_from_slice(&script[3..23]);
return Some(receiver);
}
pub fn convert_into_p2tr(pubkey: &[u8]) -> Option<[u8; 34]> { // 5. Custom one: Legacy (P2PKH) + 32 bytes
if pubkey.len() != 32 { return None; } // Script: [0..25] — basic P2PKH, [25..57] — 32 bytes of extra data
if script.len() == 57
let mut script = [0u8; 34]; && script[0] == 0x76 // OP_DUP
script[0] = 0x51; // OP_1 (Taproot indicator) && script[1] == 0xa9 // OP_HASH160
script[1] = 0x20; // OP_PUSHBYTES_32 && script[2] == 0x14 // OP_PUSHBYTES_20
script[2..34].copy_from_slice(pubkey); && script[23] == 0x88 // OP_EQUALVERIFY
&& script[24] == 0xac
Some(script) // OP_CHECKSIG
} {
receiver[..20].copy_from_slice(&script[3..23]);
fn parse_receiver(&self, script: &[u8], prefix: &Prefix) -> Option<[u8; 32]> { return Some(receiver);
// Standard OP_RETURN with 32 bytes of data:
// script[0] = 0x6a (OP_RETURN)
// script[1] = 0x27 (OP_PUSHBYTES_39)
// script[2..9] = 7 bytes for prefix
// script[9..41] = 32 bytes of account
if script.len() == 41 && script[0] == 0x6a && script[1] == 0x27 {
if &script[2..9] == prefix.as_ref() {
let mut receiver = [0u8; 32];
receiver.copy_from_slice(&script[9..41]);
return Some(receiver)
}
} }
None None
@ -417,6 +520,11 @@ impl<'a, H: GhostHasher> TryFrom<&'a [u8]> for Transaction<H> {
); );
bytes = &bytes[4..]; bytes = &bytes[4..];
let is_segwit = bytes.len() >= 2 && bytes[0] == 0x00 && bytes[1] == 0x01;
if is_segwit {
bytes = &bytes[2..];
}
let input_count = read_varint(&mut bytes)?; let input_count = read_varint(&mut bytes)?;
if input_count > MAX_INPUTS { if input_count > MAX_INPUTS {
return Err(ParseError::ExceededMaxLimits); return Err(ParseError::ExceededMaxLimits);
@ -507,22 +615,75 @@ impl<'a, H: GhostHasher> TryFrom<&'a [u8]> for Transaction<H> {
.filter_map(|opt| opt.take()) .filter_map(|opt| opt.take())
.collect(); .collect();
if bytes.len() < 4 { if is_segwit {
return Err(ParseError::InvalidLength); let mut witnesses_buffer: [Option<Witness>; MAX_INPUTS] = [const { None }; MAX_INPUTS];
for idx in 0..input_count {
let item_count = read_varint(&mut bytes)?;
if item_count > MAX_WITNESS_STACK_DEPTH {
return Err(ParseError::ExceededMaxLimits);
}
let mut stack_buffer: [Option<Vec<u8>>; MAX_WITNESS_STACK_DEPTH] =
[const { None }; MAX_WITNESS_STACK_DEPTH];
for s_idx in 0..item_count {
let item_len = read_varint(&mut bytes)?;
if item_len > MAX_WITNESS_ITEMS_LEN {
return Err(ParseError::ExceededMaxLimits);
}
if bytes.len() < item_len {
return Err(ParseError::InvalidLength);
}
stack_buffer[s_idx] = Some(bytes[..item_len].to_vec());
bytes = &bytes[item_len..];
}
let stack: Vec<Vec<u8>> = stack_buffer[..item_count]
.iter_mut()
.filter_map(|opt| opt.take())
.collect();
witnesses_buffer[idx] = Some(Witness { stack });
}
let witnesses: Vec<Witness> = witnesses_buffer[..input_count]
.iter_mut()
.filter_map(|opt| opt.take())
.collect();
if bytes.len() < 4 {
return Err(ParseError::InvalidLength);
}
let lock_time = u32::from_le_bytes(
bytes[..4]
.try_into()
.map_err(|_| ParseError::TypeConversionFailed)?,
);
Ok(Transaction::SegWit {
version,
inputs,
outputs,
witnesses,
lock_time,
})
} else {
if bytes.len() < 4 {
return Err(ParseError::InvalidLength);
}
let lock_time = u32::from_le_bytes(
bytes[..4]
.try_into()
.map_err(|_| ParseError::TypeConversionFailed)?,
);
Ok(Transaction::Legacy {
version,
inputs,
outputs,
lock_time,
})
} }
let lock_time = u32::from_le_bytes(
bytes[..4]
.try_into()
.map_err(|_| ParseError::TypeConversionFailed)?,
);
Ok(Transaction {
version,
inputs,
outputs,
lock_time,
})
} }
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-networks" name = "ghost-networks"
version = "0.2.10" version = "0.2.9"
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

View File

@ -186,18 +186,6 @@ benchmarks! {
assert_ne!(GhostNetworks::<T>::networks(chain_id), prev_network); assert_ne!(GhostNetworks::<T>::networks(chain_id), prev_network);
} }
update_network_decimals {
let decimals = 18;
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
let authority = T::UpdateOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let prev_network = create_network::<T>(chain_id, network)?;
}: _<T::RuntimeOrigin>(authority, chain_id, decimals)
verify {
assert_last_event::<T>(Event::NetworkDecimalsUpdated { chain_id, decimals }.into());
assert_ne!(GhostNetworks::<T>::networks(chain_id), prev_network);
}
update_network_gatekeeper { update_network_gatekeeper {
let mut raw_gatekeeper = b"0x".to_vec(); let mut raw_gatekeeper = b"0x".to_vec();
for i in 0..40 { raw_gatekeeper.push(i + 1); } for i in 0..40 { raw_gatekeeper.push(i + 1); }

View File

@ -175,7 +175,6 @@ pub mod module {
NetworkBlockDeviationUpdated { chain_id: T::NetworkId, block_deviation: u64 }, NetworkBlockDeviationUpdated { chain_id: T::NetworkId, block_deviation: u64 },
NetworkTypeUpdated { chain_id: T::NetworkId, network_type: NetworkType }, NetworkTypeUpdated { chain_id: T::NetworkId, network_type: NetworkType },
NetworkCurveUpdated { chain_id: T::NetworkId, network_curve: NetworkCurve }, NetworkCurveUpdated { chain_id: T::NetworkId, network_curve: NetworkCurve },
NetworkDecimalsUpdated { chain_id: T::NetworkId, decimals: u8 },
NetworkGatekeeperUpdated { chain_id: T::NetworkId }, NetworkGatekeeperUpdated { chain_id: T::NetworkId },
NetworkIncomingShareUpdated { chain_id: T::NetworkId, incoming_share: u32 }, NetworkIncomingShareUpdated { chain_id: T::NetworkId, incoming_share: u32 },
NetworkOutgoingShareUpdated { chain_id: T::NetworkId, outgoing_share: u32 }, NetworkOutgoingShareUpdated { chain_id: T::NetworkId, outgoing_share: u32 },
@ -397,17 +396,6 @@ pub mod module {
T::RemoveOrigin::ensure_origin_or_root(origin)?; T::RemoveOrigin::ensure_origin_or_root(origin)?;
Self::do_remove_network(chain_id) Self::do_remove_network(chain_id)
} }
#[pallet::call_index(12)]
#[pallet::weight(T::WeightInfo::update_network_decimals())]
pub fn update_network_decimals(
origin: OriginFor<T>,
chain_id: T::NetworkId,
decimals: u8,
) -> DispatchResult {
T::UpdateOrigin::ensure_origin_or_root(origin)?;
Self::do_update_network_decimals(chain_id, decimals)
}
} }
} }
@ -603,23 +591,6 @@ impl<T: Config> Pallet<T> {
Ok(()) Ok(())
} }
/// Update existent network decimals.
pub fn do_update_network_decimals(
chain_id: T::NetworkId,
decimals: u8,
) -> DispatchResult {
Networks::<T>::try_mutate(&chain_id, |maybe_network| -> DispatchResult {
let network = maybe_network.as_mut().ok_or(Error::<T>::NetworkDoesNotExist)?;
network.decimals = decimals;
Ok(())
})?;
Self::deposit_event(Event::<T>::NetworkDecimalsUpdated {
chain_id,
decimals,
});
Ok(())
}
/// Update existent network type. /// Update existent network type.
pub fn do_update_network_type( pub fn do_update_network_type(
chain_id: T::NetworkId, chain_id: T::NetworkId,

View File

@ -16,7 +16,7 @@
//! Autogenerated weights for `ghost_networks` //! Autogenerated weights for `ghost_networks`
//! //!
//! 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-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2026-09-02, 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
@ -57,7 +57,6 @@ pub trait WeightInfo {
fn update_network_block_deviation() -> Weight; fn update_network_block_deviation() -> Weight;
fn update_network_type() -> Weight; fn update_network_type() -> Weight;
fn update_network_curve() -> Weight; fn update_network_curve() -> Weight;
fn update_network_decimals() -> Weight;
fn update_network_gatekeeper() -> Weight; fn update_network_gatekeeper() -> Weight;
fn update_incoming_network_share() -> Weight; fn update_incoming_network_share() -> Weight;
fn update_outgoing_network_share() -> Weight; fn update_outgoing_network_share() -> Weight;
@ -80,15 +79,15 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `6` // Measured: `6`
// Estimated: `3471` // Estimated: `3471`
// Minimum execution time: 57_039_000 picoseconds. // Minimum execution time: 60_167_000 picoseconds.
Weight::from_parts(53_368_140, 0) Weight::from_parts(56_015_384, 0)
.saturating_add(Weight::from_parts(0, 3471)) .saturating_add(Weight::from_parts(0, 3471))
// Standard Error: 874 // Standard Error: 1_219
.saturating_add(Weight::from_parts(8_884, 0).saturating_mul(i.into())) .saturating_add(Weight::from_parts(6_146, 0).saturating_mul(i.into()))
// Standard Error: 442 // Standard Error: 617
.saturating_add(Weight::from_parts(32_778, 0).saturating_mul(j.into())) .saturating_add(Weight::from_parts(37_564, 0).saturating_mul(j.into()))
// Standard Error: 5_890 // Standard Error: 8_216
.saturating_add(Weight::from_parts(833_630, 0).saturating_mul(k.into())) .saturating_add(Weight::from_parts(864_641, 0).saturating_mul(k.into()))
.saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().reads(4))
.saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes(4))
} }
@ -96,11 +95,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_selector() -> Weight { fn update_network_selector() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 42_680_000 picoseconds. // Minimum execution time: 43_957_000 picoseconds.
Weight::from_parts(43_454_000, 0) Weight::from_parts(44_541_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
} }
@ -111,11 +110,11 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `166` // Measured: `166`
// Estimated: `3631` // Estimated: `3631`
// Minimum execution time: 42_265_000 picoseconds. // Minimum execution time: 44_092_000 picoseconds.
Weight::from_parts(43_357_887, 0) Weight::from_parts(45_181_439, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
// Standard Error: 457 // Standard Error: 402
.saturating_add(Weight::from_parts(13_745, 0).saturating_mul(n.into())) .saturating_add(Weight::from_parts(16_387, 0).saturating_mul(n.into()))
.saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
} }
@ -125,9 +124,9 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `166` // Measured: `166`
// Estimated: `3631` // Estimated: `3631`
// Minimum execution time: 43_008_000 picoseconds. // Minimum execution time: 45_603_000 picoseconds.
Weight::from_parts(43_917_000, 0) Weight::from_parts(46_116_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
} }
@ -135,11 +134,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_rate_limit_delay() -> Weight { fn update_network_rate_limit_delay() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 43_104_000 picoseconds. // Minimum execution time: 45_607_000 picoseconds.
Weight::from_parts(43_981_000, 0) Weight::from_parts(46_615_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
} }
@ -147,11 +146,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_block_deviation() -> Weight { fn update_network_block_deviation() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 41_734_000 picoseconds. // Minimum execution time: 43_510_000 picoseconds.
Weight::from_parts(42_645_000, 0) Weight::from_parts(43_840_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
} }
@ -159,11 +158,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_type() -> Weight { fn update_network_type() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 42_080_000 picoseconds. // Minimum execution time: 43_737_000 picoseconds.
Weight::from_parts(42_404_000, 0) Weight::from_parts(44_347_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
} }
@ -175,35 +174,23 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn update_network_curve() -> Weight { fn update_network_curve() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `180` // Measured: `179`
// Estimated: `6120` // Estimated: `6119`
// Minimum execution time: 82_975_000 picoseconds. // Minimum execution time: 85_784_000 picoseconds.
Weight::from_parts(84_583_000, 0) Weight::from_parts(86_768_000, 0)
.saturating_add(Weight::from_parts(0, 6120)) .saturating_add(Weight::from_parts(0, 6119))
.saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().reads(4))
.saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes(4))
} }
/// Storage: `GhostNetworks::Networks` (r:1 w:1) /// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_decimals() -> Weight {
// Proof Size summary in bytes:
// Measured: `167`
// Estimated: `3632`
// Minimum execution time: 41_602_000 picoseconds
Weight::from_parts(42_603_000, 0)
.saturating_add(Weight::from_parts(0, 3632))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_gatekeeper() -> Weight { fn update_network_gatekeeper() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 42_643_000 picoseconds. // Minimum execution time: 44_801_000 picoseconds.
Weight::from_parts(43_190_000, 0) Weight::from_parts(45_240_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
} }
@ -211,11 +198,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_incoming_network_share() -> Weight { fn update_incoming_network_share() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 42_978_000 picoseconds. // Minimum execution time: 45_404_000 picoseconds.
Weight::from_parts(43_002_000, 0) Weight::from_parts(46_161_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
} }
@ -223,11 +210,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_outgoing_network_share() -> Weight { fn update_outgoing_network_share() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 43_436_000 picoseconds. // Minimum execution time: 45_476_000 picoseconds.
Weight::from_parts(44_193_000, 0) Weight::from_parts(46_312_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
} }
@ -241,11 +228,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn remove_network() -> Weight { fn remove_network() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `180` // Measured: `179`
// Estimated: `3645` // Estimated: `3644`
// Minimum execution time: 75_969_000 picoseconds. // Minimum execution time: 78_480_000 picoseconds.
Weight::from_parts(77_610_000, 0) Weight::from_parts(79_105_000, 0)
.saturating_add(Weight::from_parts(0, 3645)) .saturating_add(Weight::from_parts(0, 3644))
.saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().reads(4))
.saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes(4))
} }

View File

@ -41,7 +41,6 @@ use ghost_networks::{
NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler, NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler,
NetworkType, NetworkType,
}; };
use ghost_traits::evictor::StakingEvictor;
use ghost_traits::exposure::ExposureListener; use ghost_traits::exposure::ExposureListener;
pub mod migrations; pub mod migrations;
@ -310,7 +309,6 @@ pub mod pallet {
>; >;
type DisabledValidators: DisabledValidators; type DisabledValidators: DisabledValidators;
type ExposureListener: ExposureListener<BalanceOf<Self>, Self::AccountId>; type ExposureListener: ExposureListener<BalanceOf<Self>, Self::AccountId>;
type StakingEvictor: StakingEvictor<Self::AccountId>;
#[pallet::constant] #[pallet::constant]
type MaxAuthorities: Get<u32>; type MaxAuthorities: Get<u32>;
@ -1457,15 +1455,7 @@ impl<T: Config> Pallet<T> {
let authority_index = index as AuthIndex; let authority_index = index as AuthIndex;
if offence_bitmap.exists(&authority_index) { if offence_bitmap.exists(&authority_index) {
weight.saturating_accrue(T::DbWeight::get().reads(2)); weight.saturating_accrue(T::DbWeight::get().reads(1));
if let Some(account_id) = T::ExposureListener::get_account_by_index(index) {
weight.saturating_accrue(T::DbWeight::get().reads(1));
if T::StakingEvictor::try_evict_validator(&account_id) {
weight.saturating_accrue(T::DbWeight::get().writes(2));
}
}
if let Some(full_id) = <T::ValidatorSet as ValidatorSetWithIdentification< if let Some(full_id) = <T::ValidatorSet as ValidatorSetWithIdentification<
T::AccountId, T::AccountId,
>>::IdentificationOf::convert(id.clone()) >>::IdentificationOf::convert(id.clone())
@ -1647,7 +1637,7 @@ impl<Offender: Clone> Offence<Offender> for SlowClapOffence<Offender> {
missed_percent.saturating_mul(Perbill::from_rational(1, offenders_count)) missed_percent.saturating_mul(Perbill::from_rational(1, offenders_count))
} }
OffenceType::CommitmentOffence => offenders_count OffenceType::CommitmentOffence => offenders_count
.checked_sub(Perbill::from_percent(9).mul_floor(self.validator_set_count)) .checked_sub(Perbill::from_percent(9).mul_ceil(self.validator_set_count))
.map(|threshold| { .map(|threshold| {
Perbill::from_rational(threshold.saturating_mul(4), self.validator_set_count) Perbill::from_rational(threshold.saturating_mul(4), self.validator_set_count)
.square() .square()

View File

@ -5,7 +5,6 @@ use frame_support::{
traits::{ConstU32, ConstU64}, traits::{ConstU32, ConstU64},
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
use ghost_traits::evictor::StakingEvictor;
use pallet_session::historical as pallet_session_historical; use pallet_session::historical as pallet_session_historical;
use sp_runtime::{ use sp_runtime::{
curve::PiecewiseLinear, curve::PiecewiseLinear,
@ -37,7 +36,6 @@ frame_support::construct_runtime!(
); );
parameter_types! { parameter_types! {
pub static EvicatedValidators: Vec<u64> = vec![];
pub static FixedValidators: Vec<u64> = vec![0, 1, 2, 3]; pub static FixedValidators: Vec<u64> = vec![0, 1, 2, 3];
} }
@ -174,25 +172,6 @@ impl pallet_balances::Config for Runtime {
type Balance = u64; type Balance = u64;
pub struct TestStakingEvictor;
impl StakingEvictor<u64> for TestStakingEvictor {
fn try_evict_validator(who: &u64) -> bool {
if !FixedValidators::get().contains(who) {
return false;
}
let mut evicted_validators = EvicatedValidators::get();
match evicted_validators.iter().position(|x| x == who) {
Some(_) => false,
None => {
evicted_validators.push(*who);
EvicatedValidators::set(evicted_validators);
true
}
}
}
}
pub struct TestExposureListener; pub struct TestExposureListener;
impl ExposureListener<Balance, u64> for TestExposureListener impl ExposureListener<Balance, u64> for TestExposureListener
where where
@ -238,7 +217,6 @@ impl Config for Runtime {
type ReportUnresponsiveness = OffenceHandler; type ReportUnresponsiveness = OffenceHandler;
type DisabledValidators = Session; type DisabledValidators = Session;
type ExposureListener = TestExposureListener; type ExposureListener = TestExposureListener;
type StakingEvictor = TestStakingEvictor;
type MaxAuthorities = ConstU32<5>; type MaxAuthorities = ConstU32<5>;
type ApplauseThreshold = ConstU32<500_000_000>; type ApplauseThreshold = ConstU32<500_000_000>;

View File

@ -1691,40 +1691,6 @@ fn migration_from_v2_to_v3_works_fine() {
}); });
} }
#[test]
fn validators_are_evicted_during_offence() {
let (network_id, _, _) = generate_unique_hash(None, None, None, None, None);
new_test_ext().execute_with(|| {
let session_index = advance_session_and_get_index();
prepare_evm_network(None, None);
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
System::set_block_number(5 * EpochDuration::get() / 2);
let last_stored_block = 69;
for i in 0..3 {
assert_ok!(do_block_commitment(
session_index,
network_id,
i,
last_stored_block,
));
}
assert_eq!(EvicatedValidators::get().len(), 0);
let current_block = SlowClap::current_block_number();
SlowClap::on_initialize(current_block);
System::assert_has_event(RuntimeEvent::SlowClap(
crate::Event::SomeAuthoritiesDelayed {
delayed: vec![(3, 3)],
},
));
assert_eq!(EvicatedValidators::get().len(), 1);
});
}
fn assert_clapped_amount( fn assert_clapped_amount(
session_index: &SessionIndex, session_index: &SessionIndex,
unique_hash: &H256, unique_hash: &H256,

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-traits" name = "ghost-traits"
version = "0.4.6" version = "0.4.4"
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

View File

@ -1,3 +0,0 @@
pub trait StakingEvictor<AccountId> {
fn try_evict_validator(who: &AccountId) -> bool;
}

View File

@ -17,7 +17,6 @@ pub trait FlexibleRoundOptimizedSchnorrThresholdSignature<A, E>: MerkleTreeBuild
fn header_bytes_len(&self) -> usize; fn header_bytes_len(&self) -> usize;
fn element_bytes_len(&self) -> usize; fn element_bytes_len(&self) -> usize;
fn signature_bytes_len(&self) -> usize;
fn scalar_bytes_len(&self) -> usize; fn scalar_bytes_len(&self) -> usize;
fn verify_signature_share( fn verify_signature_share(
@ -85,6 +84,7 @@ pub trait DistributedKeyGeneration<A, E>: MerkleTreeBuilder<A, E> {
) -> Self::Part3Result; ) -> Self::Part3Result;
fn dkg_derive_verifying_share(&self, sk: &[u8]) -> Result<Vec<u8>, E>; fn dkg_derive_verifying_share(&self, sk: &[u8]) -> Result<Vec<u8>, E>;
fn dkg_decompress_key(&self, vk: &[u8]) -> Result<Vec<u8>, E>;
} }
pub trait MerkleTreeBuilder<A, E>: IdentifierConverter<A, E> { pub trait MerkleTreeBuilder<A, E>: IdentifierConverter<A, E> {

View File

@ -4,7 +4,7 @@ use sp_core::H256;
pub trait MerkleTree<A, E>: IdentifierConverter<A, E> { pub trait MerkleTree<A, E>: IdentifierConverter<A, E> {
type VerifyingShares; type VerifyingShares;
type Hash: AsRef<[u8]>; type Hash;
fn merkle_build_tree(vs: &Self::VerifyingShares) -> Result<Vec<Self::Hash>, E>; fn merkle_build_tree(vs: &Self::VerifyingShares) -> Result<Vec<Self::Hash>, E>;
fn merkle_generate_proof_from_tree(vsm: &Self::VerifyingShares, t: &[Self::Hash], i: A) -> Result<(Vec<u8>, Vec<H256>), E>; fn merkle_generate_proof_from_tree(vsm: &Self::VerifyingShares, t: &[Self::Hash], i: A) -> Result<(Vec<u8>, Vec<H256>), E>;

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-weaver" name = "ghost-weaver"
version = "0.0.10" version = "0.0.4"
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

View File

@ -3,13 +3,13 @@
use super::*; use super::*;
use frame_benchmarking::v2::*; use frame_benchmarking::v2::*;
use frame_system::RawOrigin; use frame_system::RawOrigin;
use sp_runtime::AccountId32;
use sp_std::vec; use sp_std::vec;
use ghost_helpers::networks::NetworkDataBuilder; use ghost_helpers::networks::NetworkDataBuilder;
fn prepare_pallet<T: Config>( fn prepare_pallet<T: Config>(
authorities_len: u32, authorities_len: u32
maybe_network_id: Option<u64>,
) -> (NetworkIdOf<T>, T::AuthorityId, AuthIndex) { ) -> (NetworkIdOf<T>, T::AuthorityId, AuthIndex) {
let authority = T::AuthorityId::generate_pair(None); let authority = T::AuthorityId::generate_pair(None);
let authorities = vec![authority.clone(); authorities_len as usize]; let authorities = vec![authority.clone(); authorities_len as usize];
@ -19,14 +19,12 @@ fn prepare_pallet<T: Config>(
Authorities::<T>::put(bounded_authorities); Authorities::<T>::put(bounded_authorities);
let network_id_u64 = maybe_network_id.unwrap_or_default(); let network_id = NetworkIdOf::<T>::default();
let network_id: NetworkIdOf<T> = network_id_u64.unique_saturated_into();
let network_data = NetworkDataBuilder::default() let network_data = NetworkDataBuilder::default()
.with_network_type(NetworkType::Utxo) .with_network_type(NetworkType::Utxo)
.with_gatekeeper( .with_gatekeeper(
// Transaction: https://blockstream.info/tx/4a3fdd9ebb30b9c6df05d4199f8474b2f0c795d1f40a58d0d73342fc666b4a2e // Transaction: https://blockstream.info/tx/c41999f86269d5a22f39e18530b065854f447ef64a48be4013c4a9faa657f418
hex::decode("4635b1794a22bfbe6c5c5eba17b693f4aaf0e348") hex::decode("c6e4e0f822c31540b4b05903ce3c67b6cff8e6d4000000000000000000000000")
.expect("Bytes32 from UTXO should be valid"), .expect("Bytes32 from UTXO should be valid"),
) )
.build(); .build();
@ -45,7 +43,7 @@ mod benchmarks {
fn extend_warp( fn extend_warp(
a: Linear<1, { T::MaxAuthorities::get() as u32 }>, a: Linear<1, { T::MaxAuthorities::get() as u32 }>,
) -> Result<(), BenchmarkError> { ) -> Result<(), BenchmarkError> {
let (network_id, authority, authority_index) = prepare_pallet::<T>(a, None); let (network_id, authority, authority_index) = prepare_pallet::<T>(a);
TapestryDrafts::<T>::remove(&network_id); TapestryDrafts::<T>::remove(&network_id);
@ -76,7 +74,7 @@ mod benchmarks {
let next_session = weaving_session + 1; let next_session = 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);
let tapestry_key = (network_id, weaving_session, next_session, root_hash); let tapestry_key = (network_id, weaving_session, next_session, root_hash);
TapestryStrands::<T>::mutate(&tapestry_key, |tapestry| { TapestryStrands::<T>::mutate(&tapestry_key, |tapestry| {
@ -142,184 +140,204 @@ mod benchmarks {
) -> Result<(), BenchmarkError> { ) -> Result<(), BenchmarkError> {
let session = 69; let session = 69;
let max_history_depth = a as usize; let max_history_depth = a as usize;
let (network_id, _, _) = prepare_pallet::<T>(1, None); let (network_id, _, _) = prepare_pallet::<T>(1);
// Real world tx at block #481838 // https://blockstream.info/tx/6fdcb55eaeddae87fdbbd3e6fd8c2b80c1e7e7c1214e1a6e35c06a70e5f21fba?expand
// Block https://blockstream.info/block/0000000000000000011bdccb39e19e942a60edffdccd9779653c5b46b337904a // NOTE: this is the best transaction that matches the max sizes I found,
// Transaction: https://blockstream.info/tx/4a3fdd9ebb30b9c6df05d4199f8474b2f0c795d1f40a58d0d73342fc666b4a2e // would be nice to find exact edge case
let historical_hashes = vec![ let historical_hashes = vec![
hex::decode("000000204a9037b3465b3c657997cddcffed602a949ee139cbdc1b010000000000000000669c3e2472384bc95993f154aada38d6b2113d8d32069e32e2724ba40915a1802a669e59e93c011801c8c735").unwrap(), hex::decode("00a01520c1d508977a3787523a0f959e14a8df763dc87927c7910000000000000000000036303f2bcf94f752a1d4b0641d1adbc2d80aa89628feefd7f837a74792e26ab8bb276a6ad43a0217bece2e64").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020926b3b1cfec537afaa88f002a45a5a5c3dc25c0664dae7000000000000000000af0f270bf3f868d47089f395197809c360f1506636c960d96afed68bbd72d0b4496d9e59e93c01183ac94b67").unwrap(), hex::decode("0400e020702ff95ecc1b8575cff205bfc24592c87ba09280bd84000000000000000000008ca9c40d5ab762f160661635cade50fd14571dcf5fdf8c463b617caf9b07dc5a3b296a6ad43a02171340d661").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002093b3d5716570bdd5afd75a1c7d87873bacc062936dda630000000000000000009ab437e7c66b10a59b67127f290d24f381aba4e03d5e16c062a356eea4d608dea56d9e59e93c0118264f310e").unwrap(), hex::decode("000000345457ca4006ddc376db24b7a37db04dfa0b46c1d99267010000000000000000009409d64eb06a6dd83ae2937f70d07222d75505a07f12e756b61a27189851e3bbfe2c6a6ad43a0217a06575b5").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002026309618b52c68271702f57fbe684326663374eb6360ec00000000000000000023c441f913d1c77fb635544f9061fa761f876ce7d93ccbef5dc7f88e84891cb1aa6e9e59e93c01185bce3c9b").unwrap(), hex::decode("004007220e37af053c56a86899e1219107937fd5e83ff61aeb7800000000000000000000c0588f8b7a697ff9f367ec4a69a9998ef8f2552f808b5025b4b8f604d0a145c6123e6a6ad43a0217a662289d").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020a3776fc8ad2be759cd4bd3d60eaf8d8225c869864490520000000000000000006a8e7d27c71b9886b090a7422e7b5c12bb2c88255af0273d2724b69bb8c1a817b3709e59e93c01186a257ab3").unwrap(), hex::decode("00e0ff3feeae586d6f7215f48e857ed7fcf823b27117f2805fe000000000000000000000dcaa345e44c85be86da35ab0f25e2f089f04f66c1e3a3881a8455b1e42ba2500ad3e6a6ad43a0217b3810985").expect("Bytes32 from UTXO should be valid"),
hex::decode("1200002076d65fb74b1285c9b4d809645f6bb6f8f076a36295d9d400000000000000000062c8a7f4f7aa43726f753304ac9bc071877ef81273fa5f9e2f8e6f2df92f1211eb739e59e93c0118b2f12aee").unwrap(), hex::decode("00600520214f05f95e93d1d46c768a910fe0a15da3de556c2a7a01000000000000000000a129b7d281efd307700bff535137324aa0c5decc9829243bb7b29f1cafcbbd6c114b6a6ad43a0217cd209b45").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020762d95fbba0466c983446595dd608487ffafaa71e123d9000000000000000000e639b7f88ac7d1187bf9e8c82e8e504eabb2af5f0f05beaaefa09bff7d7314d6a07a9e59e93c0118be840af6").unwrap(), hex::decode("0000df2d608f226bda092f6d8da18e92e3cbb41d5c99c7ddbf20010000000000000000009848dfe4f23c9211df920b37d571b2a4363afac3efb83d7cf4249b6491a6c8dfff4c6a6ad43a02174646c9ff").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000203e5a55d70de3f462efd40e8780adee7dfdb451b57eda230100000000000000003efb1342b5fe12376a09f89a1dbb775e5855f9a1accc41b40929ec911ec1efd6f07f9e59e93c011829615752").unwrap(), hex::decode("00000020c69aef55529fcbf6d18aea8a701177317483d63c32d1000000000000000000000c3551d009eb18b1cc5da8420c5e1268c1de482127623b11f74743d46f3f34ebf84e6a6ad43a021796234549").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000206cac3182c85d630fe6938284a88177b1265f8875738b0a0000000000000000006b9d69ba608cc06e8d519373c2d0a78a62b0bcffd150e37f79f31e97a8af1af4568c9e59e93c01185f5c7c32").unwrap(), hex::decode("00800820d50e734c76e83a3d2658d1977034372b68362927c06b010000000000000000007b701acfc56d4ef6086eda92cde2c809d6960dca65ec9e617d53e0761f620bb72e506a6ad43a0217416f2f2b").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020e2f550d7404324de1bd8c83a79a1c0133635a34269120700000000000000000057819057a8a85c8f1cafb13e5eed7d6739e13d855d63421c9cef5bf1a98101a33b939e59e93c0118ee220467").unwrap(), hex::decode("00009f23d562db91d625b878e92f5d410c04775ed88006a18a0300000000000000000000a7b1bbad02565047b4428e2ef0cf3acbd0714c77934e44abc367451b85c3e56be3556a6ad43a0217c3b1aebd").expect("Bytes32 from UTXO should be valid"),
hex::decode("12000020ce9c0848d500c2fea3efd38f4e2822d8962555a1d68b2f000000000000000000e38b12110e6b8978155dad2724cf0ce4d8ab827712f8e750ce7be253227a10bdc4969e59e93c0118dc3403b6").unwrap(), hex::decode("0000003e8c4ec35b8fd1f07d6ff39de67c1ade69a25df69d84030100000000000000000033d4dab1c4958ae6d9cb853278362cbf74d25c1c3c7150889883c7fbdfa5004506566a6ad43a021751a2160f").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000202431a9c869c26ce0e76b1ed6c6543be9b7fff0ace4735d00000000000000000073811d01111496203c08c0e5941fee2c7791e1b7cfdc852258864c873df8fa6b6c9e9e59e93c01187a4ed56c").unwrap(), hex::decode("00a00020dfde782b9446c17ae40a86dcb2e308d4c729a46c162500000000000000000000cadaf134229eba7775042b3d8689553ba93d0ea929f411d3a1a01693b923b1bf22586a6ad43a02172393ef65").expect("Bytes32 from UTXO should be valid"),
hex::decode("12000020808101492d7f3237125b79288a39cf6f71bc279e45b5c9000000000000000000d7d57e05a60bae464dced00c83eff37b447fcb07e95fadce2f610267146c622fa2a39e59e93c0118919a5f2a").unwrap(), hex::decode("00800c204ec04712a453ed72818b60cb9f74931cc5a59bbcac0d0100000000000000000059eb7a758ff3809a2a5010a3e849201314378120b02b6386490c8b11ad56be308d5c6a6ad43a02177bc26d48").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000207272193a5971c9c5b8440ade64d14a0de46baa43c3faa3000000000000000000e7b1dbce250ea8e3e44e601fb26cb814e6e6e7b3b3e87e6239f6a745e3c9194780a79e59e93c011849f1593d").unwrap(), hex::decode("00801935e8c63aa1065f46a7d31bc5063be04108bdd3b18dd326020000000000000000009a3cfbb7b79d1d51f11ebd0a28ed2bf29e53d36ccefddff12322ca47d00665076c5d6a6ad43a0217dc5d92d8").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000202e6cfa8b6c2ee74f0648137131bf782c6756a7f8462f4100000000000000000056fb99126c1a78c143d86e89787de7bfc08f5492bd26df1c4314280a34e64be797a79e59e93c0118ae471ff4").unwrap(), hex::decode("0000003644663bcc00a79e38e833e4a16805ae72cc373cb7e51c01000000000000000000a33b3c0378b2a2d213aac062c7cd8b2c2b3a9c11aaeb4824a037863e7bd5fe7701636a6ad43a02173b36822e").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020be74317e078482f6a5a3723044aa62cb858b82dffd1be300000000000000000051111cc62fdcd7de11a577853ee3e4832394963da62e5bae92173ae2f366e4dabba89e59e93c01185adb0d11").unwrap(), hex::decode("0000002a4a1da985bd4aa15be31a03fd3efbe77ad0ebabc392ff0100000000000000000077eb14d0e30b97aa2baff829fa7754de88a359e6a3711300f4e2e0c1ad1435829d6b6a6ad43a0217c8ef1999").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000209cd483b9091395be33ed7712c0e8c3695b35ed8f62e71b01000000000000000046df5dea1198544e5bbbbe9db155f97f79716cd811f8d208c06be7603b70c742a4ac9e59e93c01180c032031").unwrap(), hex::decode("00000024a4efb58211a7c804ef24ee11f5f9f9db2509be9bc5da010000000000000000001cc7ac2fe2e38bfd4582367690b0521e71c30f0083f68565fd948ad4ee124fb91b6c6a6ad43a0217851e16c0").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000207936ae0f3ffbf1673598053377e6283e3a27d9fb023e440000000000000000002ee47a3ec50659fbfb117eb7c21ed26b493908bb9f8d172ed19cea85e402e66b57b59e59e93c01188178d5bf").unwrap(), hex::decode("0060e729537b191715a6f594c55e85574253c84580909a2fa72200000000000000000000fa2959118ac66e3569081e4645f87f9560742290b52ee54f7886b6fa5f83aa3d016d6a6ad43a021708a2ad64").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002094fb4f7b930b3c540db44b2dfc909ef5baccba57b435ee0000000000000000006dd2cc7164d9e6d2d0400609cf5d76531391ca93f879bbbcfafbf560b6b031e8cbb79e59e93c0118374c86df").unwrap(), hex::decode("0000ff3f6fe5befcf9e4c77cf03673076ff822740622f75cd74e010000000000000000008da0cd1fb34cfd4e58b5d3f1e20f6104e491320d5dc109fe16a455e3d385adb90d6f6a6ad43a02175c26ad30").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020e4085486f70e220273bff0fa6fc767eb74b69d2c978d26000000000000000000c991b50232e52220d94177b6ee0b606c52c010037070fc101945e160ca24786c38b99e59e93c0118c1d0e6a4").unwrap(), hex::decode("00204120cd2dba55f0867cff62ee5bab27b0ba85ac58c869f55c00000000000000000000a685eaec339dbb6e4fa52dacd2752291d5bb55dceb0b8b359e5ecbc0b2d1f884506f6a6ad43a0217de2f0c8c").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000200a5d7c8f4134ebd1e3aa19ad554dd8fd3281c94f8fda1b000000000000000000a95d611bdd5d90d2710a62915ebb1592d1bf224b104e3b8f5b289fe873d021eaf1bd9e59e93c0118d5e7ef59").unwrap(), hex::decode("00e01420a16b828d829748aa9602930d3ef1d4c983b86b39a20101000000000000000000d6e8aecebb3748113be25a6522f47e10e63c57fe95a09f35052fdabcc8a68ad819736a6ad43a021729b35edd").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020d7cafeddd0815ba95c6e90afc16970e0514729c0a7cd600000000000000000001b3886b882cfaca6d59367c1406f9b7556fc22c190b11ff414b8b2f0269c968aeec19e59e93c0118434c5f61").unwrap(), hex::decode("008067269f4c1aaf3129211de19714c6a5bb9c5481ea34f044da00000000000000000000734b07e26a80d3345fa74d1450a1b68d95e0714c163dc7b2b3eb9a0aef8b50c934756a6ad43a02172eba7608").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000204384ba6db53aa87a604259c9f9c6844b99ced37e29db0b0100000000000000000c24d07c38afc18bd830aebc2476564df8fa64dfcc8d44dd68ed7df3fc5d206795c49e59e93c0118b415f46f").unwrap(), hex::decode("00e0fc20ed544115339aa1a59249f02f62856feb602ea083f93300000000000000000000d30c9e1e276efd3be62b7cd7194aa7fb0b807f2fecb9a56074247887b2299882f5756a6ad43a021702a2b823").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000209986db62bd16a5de375470344aeec6d17ea322972d75bb000000000000000000d5c8ccb89f92e3b16e3a230d941d7ccc946b91fddae922c08c3245823210f47f43c89e59e93c011843c47fea").unwrap(), hex::decode("000000202d2c60af64f5b2a415bc46bca915042d5136b46929c501000000000000000000e0e3b49cd8b926a7468831c1b115e14838640cb735833561d551a804cf1a752cc3766a6ad43a0217d81e878d").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000201e8afdebfade79e0a483e56f2fb87a277a513769add0410000000000000000003b8b9fc7fb33f2b8c8520dcf76eb751017c06d0ed4bac49c2ebdd036abd9ee76a4c99e59e93c0118b7b6dbcd").unwrap(), hex::decode("0000ff3f3c41153e725b51dc793b18c0bfd9cfaf14cd091e000402000000000000000000ff9b55b7ed1dcff73f458e48dd2799ae141829586ce0a3902a783f00981c798bff776a6ad43a021700849f4b").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000200a5fa5f3d854fecd0c8fea9a71879443347058ddec1c0f0000000000000000009d3249cb64dda39bf0ed9ab4b665780f6c6aa72d35460bd972f1212a32e84c75a5c99e59e93c0118ae216161").unwrap(), hex::decode("00200f237376e2f7ed32d9e0818617150255cc5c87bfc43d182c000000000000000000003c08d2ba07dda561bcb53f56fff0780c5d1046686c363743b17e1591de293a8538776a6ad43a02176fda963f").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000201cdefc545aa71150e97a9763785dbc2855710f33ba3f1e010000000000000000e072dd1b8043b5dd632d4a91769cb91ca55c0343dc3d8cbbbf838c6efb1940d229d09e59e93c011853549672").unwrap(), hex::decode("00800020f3ac5bb512764387873548d1cc0d4fef3b70077b6e700100000000000000000035accf350c72501ce6aedd556177cd99090cb4952c7b23fa424ac1f7a282c0315a786a6ad43a02174cf87729").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020375d4cbf7b4d0550803dcf160ebd264bcb594d3c82c56700000000000000000058dee1ace217c483b05544f9e5d77da2857b5b443380d22761ff14869fd8ea473dd39e59e93c01187e31b1b4").unwrap(), hex::decode("0000ff3fcee6362f1a42288aa20c3f21e9fcde46dcc1a9402d19010000000000000000006e40bfc29eb8859f30d083cefc45482f77946dcb429bcf1e064d1bcbd378f23c0c7b6a6ad43a02173d75f866").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020560be37ca005f2c792755368aaf63b5a664ea36c2c69be00000000000000000026cda0eeaf84644b2aa9d072e5b5bf14c8c8b707a671e4b2232c7e569fc2a07763d69e59e93c0118e2b558a6").unwrap(), hex::decode("0000002ae9ef834e71842c871391dd44a09960dd63990dd557e30100000000000000000052b6b1f008e5b0a5f38be6b2082ec17889619f0627f4064106e820364e1cc8072f7a6a6ad43a021740becfc5").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020546da8a3fde6bd1f52247bc8a6cd0251e772eae3b5556600000000000000000029b4e20ecbc778975e189bd28631e94b2809422d8efef15b7e440f624e79d9964fda9e59e93c01184f91c402").unwrap(), hex::decode("00a0ab238496ac097daf6fee7acdd40ef1a503089d76db2256c400000000000000000000a6e564e0de9af79eb797a4b9afb26b5ad56395f3cbb7a9b4bde5a760d140aae8ba7a6a6ad43a021735b5f7f8").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000200bee1075fc01582e0b453bfacfe49add055d6cbccea7a500000000000000000020e6280b3d966f5af7290a164087a6c8cb177b41ec7be91035d0f5c45f1434f129dc9e59e93c0118cb35d326").unwrap(), hex::decode("00200320e3d603f57832afb5e67c782aa5fd5d8e2d655230b50e020000000000000000005451ec2c708395b414a347863a8cb7ee4a7d8b0309086af4c329c3ba164be5930d7c6a6ad43a02171ffe7b21").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020f07f65f1ed56e656a942eb424dbc76d78cde25acf1e7f30000000000000000006c6419dc5a46235b11f9a14f472ec166f7ee40f4ba8f031294c9ec8a20471bd6ffdd9e59e93c0118f55c1c76").unwrap(), hex::decode("00000720159f0a42d5afd3196d6bc4745786b08017e9f2fe65c4010000000000000000002204634460a10b17be10462c08d3a3247e8955da5ec01f525fd0d58b14a5e2ebab826a6ad43a021737c8b684").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000201c30d0ecfff1a55c6531ce992467b0a02d25d6a545120e0100000000000000004349f28fae9da9ced1744f9988d6c7ffffe10892e2ee2a0a3228f2555c13639461e19e59e93c011802b33340").unwrap(), hex::decode("0000022030d1a71c70fe8d8e994e1dcddcda8c8c5798ea9bb20d000000000000000000005d5579d7b5cc4c5e43d45169c93abf90dc6f212cd462407a48fc144d8315efb35b836a6ad43a0217aeaa2b47").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020f47f05efbfddee4a1d0a0c502f8a9604ef2236e60b02c8000000000000000000ad0f318ca8bb97a73a3490ac79c8cd1922ec53084493a5d2dd7c6bbe64889b1766e29e59e93c0118184be748").unwrap(), hex::decode("000000222a3e9205528e4d5618a7287d3d2370a41a6cd2d346fb0000000000000000000016d19ca5aad54bceea5245a221fddbaedb3f56fd6b8f12d59af65a167a7ab56aee836a6ad43a02173c540bc8").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020a9446ad105a3a4434273e72d9d47f23544bd2d4223d4fc00000000000000000081078f171421ea27808a8bf0e74d9679d9e756197a832d17e44cad3a67e5b8104be79e59e93c011822774361").unwrap(), hex::decode("00e0ff3f9ddcd3ff85fdcd54b32df85a1eb8648b211b72a247870000000000000000000043b56016ddc1c29bd76c92a831b4de36a59cc0fb88d294b6faf24339afd8d64de6886a6ad43a0217126de83e").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002060e290b87ee42f2d9497b8d588a144c8ff3013d4036ee4000000000000000000cf51f2b3e82a3da5adbf8baa8da3ce0dde7d9bc0f68ea7d241bfe7ddb6a6a5302be89e59e93c011841dd5d0e").unwrap(), hex::decode("0060c424aa0dedbd17459541b2df58d403e78824d0b306e13888000000000000000000000d05d08f6044eb00963044e75b4dc14417fd7c3acf1f6d2f9eaf9432627d6a93c68a6a6ad43a0217971b219c").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002037e7cd68d910094e9963ae1953173141bd1dd22756bf1801000000000000000098416fb809d13de6c54ccce4927b167e9d561db613df3cd05fd2345daa1ceee5b5e99e59e93c0118a9f6e6fd").unwrap(), hex::decode("00006c2235ade56a30b832a1d86a389853d9d7ef251dcd31d5de0000000000000000000028cbac80a576b4b03407029062c64268eae619201f84de43d65b6cc29d49945d598b6a6ad43a02178216ff0c").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020cd116024d228583ad1f60c649452ff34224cba9943288f000000000000000000b9c1df740343350581e7b896f3e8edb4ed5a04d3f6fbccff4f69fa272916b110ffea9e59e93c011875c11682").unwrap(), hex::decode("0060c924fee183b290d1e5ba0dd2a211888cb9a45ac3261128ca01000000000000000000c64693de6d95445e23df797f3591719428ea07754aad0c5c03707a1696a49316e48c6a6ad43a02172c70405e").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002050599ca8da62a8cfd3a07144f555651df0036933cf72c0000000000000000000485624901693271d8c6e343e603c2ce8e90b471cca311f023ba85e010a0e21913cec9e59e93c0118945a3cda").unwrap(), hex::decode("00c09c217b4715e06ee536c88f2b04f8da84c9be46bb89b337cb0000000000000000000035ed0514da32bff54f234681d567b7bb8bebd48c1981e88a480a0069cf19fae9318f6a6ad43a0217578cf0e8").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000205ca35aa16b669d252de566ff111a2800250bfdfae5e72300000000000000000099a99f1cb9f487794d70dd2dabdb63542aad056ff20cf5e435d1a350a5dd8f7435f09e59e93c01182d21bc70").unwrap(), hex::decode("00c00f2089ef5721cd6bfe541cf56a30fe029e8b6a99d426b59b010000000000000000001cc5db1b35955722b2b072be5497665f2bcc0116021fc52ad106b86f85eb7a15ea8f6a6ad43a021726299c25").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020751510083e009cc429c10ce2a1f7ce1f95c87f4716275c000000000000000000d1c1b3b2a58a4d7780fd7855cb168a3187fbb48766a77e2237e61a987f7a04a0a4f49e59e93c01188c23e65e").unwrap(), hex::decode("00400a20b73d674783455e1728c82701ae1c5bab268563697aa001000000000000000000c7ef430a886118fb6bdd0536e867b9b6fc15cb198c7df4f4669c2fb94244445ebc916a6ad43a021757775d4f").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020ca376c104bded3b6f2ecd502c4626b4e4ba77ede0f2817010000000000000000007ed4eebdd8353dbaf9d2038858dd5d075efbc8d88ecf8390c9bd4629561739b6f49e59e93c0118680992f1").unwrap(), hex::decode("00e0012028d9ad98ee6302bffc27d2fc51e905e7ff1455e9ad9a000000000000000000005334bd5deb896d99d5f85f762ca5b5057bd8a11fb1f718f794ed67525ce5275639926a6ad43a021742a4ad22").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002054ddd7cc1845abc2f45fb6fdd477fc060c621cfc3f64a300000000000000000027b24757e89286c84b438fdd7221d5eeec72dc3214f96bfcbb034480b8d17dfcf2f79e59e93c01189e1f97f6").unwrap(), hex::decode("00e0982497ed444856620be9d4a2b3f2dd8385aef13794945fc4000000000000000000007a27f7d0b1a20ec5e2f5b69edb844ceb52acbe24cc44b1e486a86105591678c846926a6ad43a02176d3f1083").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020f49dc697e664b8b0c2029098b02ffef095d48c1e477145000000000000000000c644ff082cb1fa4ecce54bed1b73568f1d822871004222d5a72f3cc498e2f44763f99e59e93c0118f9f8e680").unwrap(), hex::decode("00800420a90444f33700b0a903d8dd28c7e4b00f1784a4f12c0801000000000000000000068f9295a349845eb2431428cfc318b72eff6d8b828b61533e5b9889be6a455f69926a6ad43a02176536c20e").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000206549bb716f4d1f739f6ec0eec4e7bd579d13a08f32ec910000000000000000004d9a9c3c118ada3bc0bf92527bcf58b9dd9a2ebfcd32e863ddf55bf4b8ea51acd3fa9e59e93c0118dd521ee6").unwrap(), hex::decode("00e0ff3f9efdf00d718c728b94e39dde5c42b0450539b1e0d20a02000000000000000000fff04185f99913ff903e7fff46f04e0ae0f132677d10b8fa1537b98be859020c3f946a6ad43a021759b8976c").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000209a368fcdfa9401ade089f9caffa5f4247b8d98df587907000000000000000000b4f37f6ec854a54768e754813ffb7e8a28cbf1e96c83d591b991d3f18e314c2b35fc9e59e93c01180d8068c8").unwrap(), hex::decode("0000002ecf497d98fdd70adce90e8ce350f3d9f14b735f7cd03c010000000000000000003e3c02c9fd4bf5cde2f4f0ef50570669aa586b3b12e1dff52507337198d3d879bc966a6ad43a0217d2822239").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020452cab805c77683d7311ca8678c7597791da79fe540a090100000000000000006445c736195151df49c936a6f0d981b6a13cfe2786da44e49972753dc90af2e452fd9e59e93c0118f0572502").unwrap(), hex::decode("00000522c9273bf66ca7ea531cd3409f3b7fb9f228966e67149300000000000000000000ad5c81834cc230f4ea59cd148298080d22cd008a440a75e34d946ea646f94e7791976a6ad43a0217899d978e").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000200d95d828b4772e62a3fda7c5105a5e62ae59bfa41b897c000000000000000000762cef2e97c31814210393e4acb278c155fe040b711635c6e91ee500e53754431f049f59e93c0118969361d6").unwrap(), hex::decode("008003203404ad959ad7bc9787388e0035542ad5d540f5077130010000000000000000005082dd1fd7487596fe92f1c06261d3f1abd2da19c2116b175d62adc245ae9ccfcf976a6ad43a0217eafb7678").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020649b9a19c0145467f3a1a58e1bcc05a65ec1056ef93688000000000000000000dd4ccf726384ebdc3ccc54cb2fb333e1d53929c8ab31d53e67b53cd77d61454894079f59e93c0118bed9774f").unwrap(), hex::decode("00e0ff3f6e2ede80814d029f614eca38ab9c9a15e9400a023d0200000000000000000000429fa6b33b892eb6544a11e0f3728d109acbeb0f9ad59a48ecd3d64e28543a4987986a6ad43a02179c1c0930").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000206f3f9474e424ca652456920f944c7b17b3d240ad37aa3b0000000000000000009a92e0f32aeb11ff2edd48fb838cbb0a3e25c77110c903821f339f7af5b241fb540a9f59e93c0118b5e8548c").unwrap(), hex::decode("00a00820b709f5dde282465f55c4d7e66cb2ba6fc916c0d51c4c01000000000000000000eb37059a5ba1cdd3f3810607c8d194363679bc9f99dcd95652283a12d7603b29ed986a6ad43a02174b733dd8").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000200aa99abfd7da0f5f5448aa667e6de3e077c883614be8b200000000000000000075761a440b33470907d040f1a155297ca051031a51f8fa86354759b07bd1f664a10a9f59e93c01184b5fa896").unwrap(), hex::decode("0000ff3f4b173d1bc45aa63418b7bba7c0fa5a5acfe53d22eb1e01000000000000000000f745f6a23d5cc180ff74ad724e3a12bf2bdf6d5d8f1cbacac629b28634fdd3b71c9c6a6ad43a02174c304983").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000206bd57fe048b0bfc457f7d5d2391e01726fe292ab1fcb18010000000000000000172bba412df81c10668c127231b0aa6d0bb956e5e8fc0e8d049bdf2ad5ae7fb7ad0a9f59e93c0118503dab85").unwrap(), hex::decode("0000002830ec33bdc09b86dd4d9e637a2c5c4811989d9bc33505010000000000000000008caab6a74d42b54943d5ab85c80a95f17bdabaaccf27f8e1d18923fe2ad0113c2f9d6a6ad43a0217a53735c3").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002001930a8eaedf739fcee4ff0b813f3c30e9893adc7c2f750000000000000000008c070fd6e6fb402464b941679aa9d4729039649e6d0291503f707b0e18f15e43050d9f59e93c011853eff7b1").unwrap(), hex::decode("00a04c25fb6183fac04e92b6a4b899c9ef156babf959dce7c7b600000000000000000000adae556e5b521d5c392f39d3c8695d5cc11dd3234a6c38c7c423ac430fe5d10f2b9f6a6ad43a0217fd964416").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002032065359c9d1ec45b0e44777179e815c5dea5df6d2b80d000000000000000000e0df9831a1340b0f43e9c1cb184b3c908088c22b3f7c0e83753899fadd7b19a4160f9f59e93c0118ae79fdbb").unwrap(), hex::decode("00606b202e489dafa11d28ef8c748ed8da4a954c5affb25454bb01000000000000000000e3f9ee43488ffbb8b711222f0540d1fd61bbec8ffbb9ced960dc2352392eeee180a06a6ad43a02170208ea28").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000208790994382f84e67407b33e82f0a8e268d5728cdf51113000000000000000000012a6be8a94ed2b80d931826d1c3e9041b0db02d526bdb01f29cdafe867e8e1952169f59e93c0118baa84dfa").unwrap(), hex::decode("00a00b207940814db8828f2f99a835fec3507ac1e3c6b8c7aaf100000000000000000000a4986016840beba7d215510f02f5e88cd41fc4cfc9bee4069ea56a4a7a9cae8715a26a6ad43a02177d018b27").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000206ee4581dd794f9a4fdfe832fe065309357d674b8128834010000000000000000888e623880da62cf81367c8b77e3e2ce52747b2371e82f4abd0f1ba8e41f84fc78189f59e93c011811f10c19").unwrap(), hex::decode("00e04325f4a84a1a7043948c2af0faa632f4735b8dd989f49c250100000000000000000072707db2fc682148e6aa27d4dbdf7c20009db65c848132f76bc1b3a31bcddcb57ca46a6ad43a021777dae935").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020077535a944b5339304140abe45ae8074fc2608647123210100000000000000005ed755f1b7abccc300cfa05d5912b2735fd5af94005c483363750315352d91a0971b9f59e93c01186f9d5e9f").unwrap(), hex::decode("00e0ff3fad0b6289eaa9c8932a76daadd7a5c3bef539fa19708b00000000000000000000dd2c965c6cea3dc01c21466b8b575c24f0b789a79c6e3f6ba7dcbe45740e1fbb9ea86a6ad43a02173bd6dce6").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000202c66b86db7a058c3c44539ddeffb4f1b57015f9b2b8fd5000000000000000000e9b0a033bc22b16c9947bb1cf8666c8b7e31ab98572a12df526c7941eab4325a4f209f59e93c0118d5062214").unwrap(), hex::decode("0000022064c18468116c4e6aa84afd708a1dc597a4aeb5e0d26001000000000000000000d0132ba263c4eb125280313ea30d4853b2201973b825588780c5e080eaaa8418c0a96a6ad43a0217d3de833b").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020f22aab764863f3f9e88a769ac022585b6ffe1bbad8ee510000000000000000000ee1ae23c89a4e6a19d737f0bf177d3a208bd00e1d0ad4cae38227e86ddfb36250229f59e93c01182447fb2c").unwrap(), hex::decode("00c00e25575e08652190884e0ce0e963d24dc654eeeb47c77f1900000000000000000000068daf8886ba4daec55638e8f7e06890a186b6e6aefb5e7912b360a5a644bf1704aa6a6ad43a0217693c1a54").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020d1570bf5d1ac720a7452201a3287325bc5dae8524739b30000000000000000007a05c7cd9b70624c6a5d60bdd06839aba4fcc8e7252edd243b65c14243074437ce239f59e93c0118f63384cf").unwrap(), hex::decode("0000002ccb2e57d6fa6db31eb2fe4b099c98602747060080927a010000000000000000004ae5c82107d3b01d762bd7250842757420ab88bd9eafa531e45ddd5460ac1c4524aa6a6ad43a0217ae883618").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020aca96f50dac6c74043cc30b2ab63a11af71348913c99070000000000000000006dda0c090803e1207eb4d5151bfc572fec8c5869014dcd528255280fc3c6be0ff02b9f59e93c0118aaeafdd9").unwrap(), hex::decode("00000420385cfb56a9c0aa212ad2d8cfc3be492cb768e7be66e801000000000000000000e47b35c93528a98e5ccc07f7a64120f10fe44a7d2add76f851f2ef1ff86fb35588aa6a6ad43a0217e74aa794").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002062b7c2b4bfdac0e47f8a510e05e56ec3a2aa159a198b210100000000000000005d1c0f705fb6dda30d8787b483ec14391dca7dba3bc927b5c5d2d6ce5aa605f8e42c9f59e93c01182b168198").unwrap(), hex::decode("0000002ae44f541085b616ee2b6b66143d45b8d9d005a13ee58601000000000000000000eb7efe30fbcae6ef197af5303e922d5f13af046afe6722a44a407de33cfb05ecd1aa6a6ad43a0217cc1c1fc5").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020ed0a2c738b93a2020850d1e6e696c409c7e1f386e36f5d000000000000000000ad0ab3a5dc8fa3680ec23d44ad6ae25c34ff4b8880c50ec5930ac8e2e539a59247319f59e93c0118a250018b").unwrap(), hex::decode("00c00220ddf782b16cfb698ec47c721caa0e043c6e3045bd7d3f010000000000000000008ebe86fc87779b0ab7b1eeda4f938fa6bff75fdf3f03326d4c3f0f212db1a5df24ac6a6ad43a021787917f4b").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000209ddcae121db975e6dd5e81c170baf5b3c282ab20394bde00000000000000000080f2facb6a18fafe52015165da8389eeaf7c3ecefb7407bc64746b4848d237a096319f59e93c0118832b1484").unwrap(), hex::decode("0000003a8e0ffb97a26cb108666a56d11cfa7e8083858aefd35c00000000000000000000f741327a673e2680ea856c80fe7c45f495f35c0809c79095d2aa49bdac42d8a91eae6a6ad43a0217ee19f61c").expect("Bytes32 from UTXO should be valid"),
hex::decode("120000209eb0ab39e2c28b15ea5af8d29384b0cd75e0fd8ca333800000000000000000009e664c6c013e556a0e533ea58cdb611fd18f004780f2d8fa9e960f531077723ed3369f59e93c01183ed29cd1").unwrap(), hex::decode("0420a12a06c61bdd24754ca5788b5b98127fa4cad6bfc6b4943000000000000000000000c0bc9db8ba6c3cd5e4852713723ab9462ed8cdff9a8e7a59f106a7d1e5d9596223af6a6ad43a021752931fe7").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002004b9908261d98fc854b3a60e7c6550be0e80f1faca2e9200000000000000000051ab7c2206c0af2fd0109857e2813667b20c60b44eba0429d12d2bf445b62dd18b399f59e93c011866f2e5ec").unwrap(), hex::decode("00a0cd2bcda5fed994deb88252ba588292824dafbfed2be7bb8300000000000000000000b021ceecadb5f6f0fcdec2d4dc38cc9021bec331a411769cdbfa1f0d731756c55fb16a6ad43a02174c791b12").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000208aa7de3780cc6675d5dba2bf9cc9a282affe39a6f7150500000000000000000097f2a23d7efd9dfe84826085d7c60aa3af1838853b39e0de3eb2479070f86ad8b73e9f59e93c01189c2b7650").unwrap(), hex::decode("04e05c24b1a2e59ea42a7424eea8fdb9b95d65865090c6745fec01000000000000000000d49392556462b7cc6a324f3297b95655e8558a842829fa4dbe42a8e8740029149ab16a6ad43a021794875146").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000200446629b6bc0dcacc173df9cb47f001784913e61aff4db0000000000000000003118dcc3cbfd4f0d70955243b0f82945303bc0c1065d81dcb804cc960b2e229406409f59e93c011882e333c3").unwrap(), hex::decode("00a037310cb4c38e4d2d46702721cf104e9adf7a2120c0ddf85e01000000000000000000309c7334a84c50b5274a7efcc0ee46380415322cb2215a0220d84b7db6f96e6ac3b16a6ad43a0217d06362de").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000209dd0c92839267422e8a4c18abc1d098219bdc9cbcee6c500000000000000000020449bc225a5eb4fa2599bb828ad08315ff6070cdae1fcd54f4c12af5a738e78e4429f59e93c0118a43c58f5").unwrap(), hex::decode("00001c2a5253d07fb8f9c845066cd8d88ae9cbe590f2239d323a010000000000000000002430bbca343667d2cee8a3d7a86901914c852f38a92dcc8142f694235c3d8bf334b26a6ad43a0217dd6db83c").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020a8ce692a8a4feb0aa11b111173578f62fe62a1f9b7d1250000000000000000008da525d2694931ef00938ad1adf80dc1d98961da742899a3e8e9a9f9d52d139d5d479f59e93c0118299a5e44").unwrap(), hex::decode("00805c22ab4c07fb2ce6a683075bde23e7d94f50b588e8f9aa9c00000000000000000000ae3e39b85b23c403d31143839b34cc074e7eef0ecb1bf27c54e324a5be96676d92b26a6ad43a02177008583b").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000209d0fd9053369245ce38bb78a5615f28c35e11a5973c5f700000000000000000063b3af6eb819369034653030bde01fdb932c387de6df52de2706247d85e459cc114d9f59e93c01184a0be1da").unwrap(), hex::decode("00c004200a2cd7ef7703ae1fb2093c550eb744c3ea18108ae7a800000000000000000000d0bada625a70a2fd6cfaa2aede6d72bf4bdd10b64a52289820832323519d62ef43b56a6ad43a021767cab9b1").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000202edbe7bc738f7738539edbe8ef297845d6dd3172929008010000000000000000c168d44f58778e26a32f2cae4ad24438ef9a224247560597f90807150f12ce2c954d9f59e93c011837f3cd54").unwrap(), hex::decode("008000206d1cce7f0978d68ffdf92d43c7027bdb81b612641586010000000000000000008d818799a9cada0f4f9243f2cad85b8940125850a9ba37f7d1e6fd282c8c62e145b76a6ad43a02179e855276").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002015fa542454cfb0ae97e23ad4b4ce5703b3108716c01357000000000000000000a806a100d3b35f96c39ca66e22a1beda6f3f6fe713d42dc2e6ffeb28dd8c28e9565f9f59e93c011806b57820").unwrap(), hex::decode("0060af24e8f12bb06b4a71cf56a91e73a3966e14c17208a54d6501000000000000000000fbc1e7250797d3e71b49e1abaef047d8cf7e16f1c0ff9de688182d503d0cae67d6b86a6ad43a02171ebed5cc").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000205ec54cb5b7b605cfc74c84f8ba30b366967477158e7eaa00000000000000000003bba352d0ff1f1da8d6236d56537f04f010c244241cfada8413d411bb05f2acbf5f9f59e93c0118c1ddb052").unwrap(), hex::decode("00c00220511c75e44d1d627b986749aead0f55ab37f04df146ad0100000000000000000037e94c77e2c639bbec32dc4dd570b31516ea25fd1497156602b5e149f8d391d682c06a6ad43a02176534c3d3").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002099e2bf03160945de2c32994587f206fc03a8729873f71b0100000000000000000a41ec1170bd9ae021715e237a8bceb081bbf7fe54c710bc53d5e847cf0e42f83e659f59e93c0118d5368f54").unwrap(), hex::decode("0000ff3f78fb96b3c3c7b29aa1915342bddc921bffd01bfbb63d010000000000000000007a5c1741944ca4332ef03742b971469c0c966655b31d10609a8ffbea38a94cfa2dc56a6ad43a0217a35c947e").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020f7039f439dc89d835d02760938b27f38aa23ca450edfe7000000000000000000d53db2eefe53fe8f7b0bbfda2f6b0fdcdf05b3db319c6d0f8b1c6de724cdfad4bd669f59e93c011886b1e482").unwrap(), hex::decode("00e004204870e85ab18fcb38d67c35979efc5df4105490b6713f00000000000000000000c7714efab1a223e7fa21c6f87db62b32cdcd048d5b70e59def0d434de384b3e871c66a6ad43a02178f3d7140").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020849f13fa4db5a9df69b6c7432787aa46ab907a73eb8958000000000000000000cce6f694fb27b616b555dc7102ec152bde972c81e2872a3e563ef42012aff052cb6b9f59e93c0118e0c9a5a7").unwrap(), hex::decode("004005209f1f0b92d362f5d4f3b1cceab1a7b6e0d2e55e2c38e8010000000000000000000f4e65ca15db0700809fa074c96785754236d3429e2fcf909a0a0cd7e59a31e6c0ce6a6ad43a02172c31d37e").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020a2483433891049526ac33b6ea00686a35559e02754612e01000000000000000089f3b6be3169c4a876aca2ffe4356c3d0360318b0944361b50877c4c18684d0a466e9f59e93c0118d708e05a").unwrap(), hex::decode("0080e029852c36bc969233723d0d0c7b44c3820b1233edd53c0001000000000000000000b068c891e2d2e65e1d48a74cb19d5e2aba449403d0cc021cf49cec0175226499d5ce6a6ad43a02171413e6c3").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002005b1a1dde1c62d56a012b4f03d8b728a2a94f673e32654000000000000000000d02cfa1f6e7718bcc995a9ae1058dd104b46f5f1602fa04342976a33b2d9de4fed6e9f59e93c0118565c6ad1").unwrap(), hex::decode("00e00020947175283c53840a5fd95ff5fb52a69cbf049640600e00000000000000000000d4ffb8d309f3aaf7023d9e3df8587e63b672b2180b85c0d307cfbf3e334ddb1a5fd76a6ad43a0217d543d85a").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002058a8c2c6e79a29d7cae4638b45250afcba2c78931a1a4e000000000000000000047a409d56ecb504f03f625f02debe5e4f8e4afb2e7db585da0e6267e5a9c1241b749f59e93c01183cc51dda").unwrap(), hex::decode("00801d21203bd017379dede3b30858ec121ad3afebe66093deaa00000000000000000000b15433a1853ef7eab266109f32e22af002690eea752fa0afcfd517c8c51957ed5ad76a6ad43a0217e750210f").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000208ea76979f75c77af7770c510ba0b29d10929a78a67a1ab0000000000000000000025f4241f566b426d0482decd6e50433e599e876a5eb19e077198490341c633d1749f59e93c0118eea47b4e").unwrap(), hex::decode("0040032083cc6f37b94764a79231d6aff125a14f964aa83aef2300000000000000000000605c53cb797ad5e44717e9345170a30375813712b4374440b7b2db0c916fcce34ddd6a6ad43a0217ac7dca95").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002017cbe57c7bdd58d8dd4a330e75134f505d23337545a0c3000000000000000000a0c7805564032c4837f6aadf9ca1f7c0c05e43a15b5c85b24113edf5463a3c2b63759f59e93c01180d829750").unwrap(), hex::decode("00e00020d8f1948230933cf727b9d64f1e5786939d595727ca0c0000000000000000000064559da1901f51ddb2307790cd717cdb08421a0d596a119ea26c795695e91fb60ade6a6ad43a0217252accd0").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000201daf8e737418b092385d91052dc9bf25c78db4947eb55b00000000000000000060a707c9f3152e692ded4eac22e1b94b5ad2ec5054146f252656824385e648a8b8759f59e93c01182341df8c").unwrap(), hex::decode("0060e524ba12f94ea5504e31ef86e8cfaacd1dfde5f2981a0a1202000000000000000000b7768b6df326e64a6091b06c253adf3ad85d58b6900c9f0262ceeff036c65ae969df6a6ad43a02177e5d71b9").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002096c2dcf962dbfa7ad045b4b8b8b7a4886cad2379ebaea6000000000000000000af2bd41304d6282d189dd7dfa2a9b4e4f9d6dbec56fbec8ca89a79c04f8120a3b1779f59e93c01181ab38dd1").unwrap(), hex::decode("00200a2052a2caca7cbb37e81cafc0d37c29bb530ac9bbc42cc701000000000000000000d2b7cf8533ff1f8f67aa7a9278cea1885a1404465b8d42beee3c22572887406e7be36a6ad43a021723dfac06").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002030656d4c0fd65650a9816435d319a28b65b7565ef68e1100000000000000000026b47d3d67ea2ac89e74a31b9db03d4d3055efa98bb8368e12699a10406e49e4437b9f59e93c01185a356dc0").unwrap(), hex::decode("000000220550058d8ed56d8640ee35b6684020f73610626342c900000000000000000000adfcd1ef1d32d7394be8a552ced86e00d4a1fecd68c78e047ea79bf6fc002b7a91e46a6ad43a0217ca6118f3").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020d595c94c828b7f0d7833781a9c7c7c698966f251ee3420000000000000000000b182443ec96ca031c8e2fbb6492a1a51ae6cc80e886122d29d01b69269e91ca03a7c9f59e93c0118bfd8da6e").unwrap(), hex::decode("00c0c02658c8f4dfd9d02cccdc514498243a7fefb91f9c49069400000000000000000000a48bf36c7ff5543f078df43076242f3992e00a7cf842e80af8f3e1699acb242db3e76a6ad43a0217637c9ff1").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002018ea7a48e4f65e887ae7f5f1fc1395d25c5e454432995c0000000000000000008533a46a3c5b3e2ade0cf423d12d400b62586f8b8bea62e6a075d6b8c976ff6e8f7e9f59e93c01180f245714").unwrap(), hex::decode("002047242bfc14c46c37991c2cef140720b1b3081ef7d87db8d3010000000000000000007f4d937fe1cfa4629e958b43d638b2079ea77e57c9cef7606f07e2fe5e888b18c4e76a6ad43a02178d9c644f").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020bfdc2e0d03ac8d66bb2a18da3b9d03574e538c5e837a1d010000000000000000ac88acc66f208e84153c725753bdae77fc6d19ef0a640b6d1caf12cf8b851aeabf7f9f59e93c011805fc019a").unwrap(), hex::decode("00a091278a26924cfba43b61448a7a64c5b1fee904fb8e811cd70000000000000000000008abe2adedf7edfe2fab80f34a7a930b1267f123679414348649a39ff53230808def6a6ad43a021753c783de").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020831e7f6ff11c94025c12c7ee0246309c60243cfa79c6340100000000000000002a4d15a07780dd0685e4f517ee3fe822c19c1f88c97fbef7d4cc9125156244de95809f59e93c0118032ce04b").unwrap(), hex::decode("00004830337426f9ece788d4c8241e02589ffea33f898cbe09f501000000000000000000e2e8f5511c6553157451a89067fdcc790097d030bb4bc0690bc17014eef5d2c990f16a6ad43a0217a872716e").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002010fa7fe6e27ce9ad5f51bf00d5078a9e577f2d08115c1f00000000000000000062d112144604b9f9b83e4f421b234fdb17d0d7bd71590b2a1994ac73f0d9fb2759879f59e93c011870e590f2").unwrap(), hex::decode("00e02920546922cd52e7f92111d725d812c1532308eb59fa22ee00000000000000000000fe634310b53673fc6c018af12c64c19060157b1fc3b73d5a5c9caa03cf3565f2baf56a6ad43a0217c76fd370").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002065fee6168588d22fbe99ac61f5767f7d1f38408d4a15390000000000000000002ae612abb95ed62f051af05b0e942fd1763ef6f3011662c71d4f4d9c984c6da1dd899f59e93c01181231b844").unwrap(), hex::decode("00e0c121fa38469efe9223b571f74e760c96df203d80b08f3b5600000000000000000000f33c1eea09c6d87bbc4d1d2321270c21454495f21ff525534f4e20c85138a592c1f56a6ad43a021792df7b16").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002024bf07643212552bd0d4fa4779762994eda338868ba20b010000000000000000700b14840728bb630ee467a705dacba32ef040e39245d4e18e0381a1fb42e5b2e2899f59e93c0118687dc2a8").unwrap(), hex::decode("00c0a126df55ad5154bd8f45fbe0cdb9fc9722783ce4b7a535ac01000000000000000000c533cefab59d506f73176e595df8cea46363e9b5567dff08a163a3c465dc98d14ffc6a6ad43a0217c26d2516").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020fd21bdf774f4ab391ee951404c7c3d9df1f20a21fbd6be000000000000000000e948d27a0e531f5cbab3a5c5cb3f33cddf8228215ca3d934336f26cdecc8a587aa979f59e93c011835ccc946").unwrap(), hex::decode("00a09d2b81fd6f7a8e612d81d80d5b5d64859c1b2b2b101bd1fb00000000000000000000800989d2c31d1dc5a3308452b91b1ed40206a030839737953c9d21d6923786451efd6a6ad43a021749e04799").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020153d617dd664fa4f49aa0ef145227331b4aef23a9beed0000000000000000000283f8529ed8419bbd45076bf1ef58a2f232c4cd869aa5e9a8687a932ea6b8cab2a9d9f59e93c011884f44a28").unwrap(), hex::decode("00c0d729b34736f399b13a8a2fb7479954d43c2df771c757e23901000000000000000000f7c933bad214186ec2e49c9d1b1585937280868818f320803cf6436e09a8626973016b6ad43a02171b81e870").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002094a5ac9376865366f4494ff6782e9e0558eb485671451101000000000000000031dbb81b18060f9afa4a82a55391911102a01122b6e25bbad2227d036aa402cf69a19f59e93c0118a38dcf53").unwrap(), hex::decode("00601521556ce1a2354410a18c80b0a67be6dc16257be28890ec010000000000000000003059a134b7eca83de9aca917fabb76ee41d97032583222d6840ef22da16b5b92dd016b6ad43a021725071a5b").expect("Bytes32 from UTXO should be valid"),
hex::decode("1200002020311f7c3ea7fabfb3da39c120d7256421b8ba1f7c9d2700000000000000000043b494d744397958f9fcbdbc78e2fa238a65ce4a8c99c8cae41094bf5f620274dcab9f59e93c01187257ce43").unwrap(), hex::decode("00602e2064168b2c362c354444ea0828f36d7cdb3572169b615601000000000000000000a4aeaacb4c25d3a83b2f8ea594325d756ec78f290a73c4953f3cbfaff10e3a3792026b6ad43a02170bb4640f").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020be1808de4c0bc3a8cca96651411de3bcb04b03ca9cd5ad00000000000000000061248b66ec93f45b75d1fe61bc62994b769ac8fc6a5140c2e1fcd8ed3ad8734bf9ab9f59e93c0118c46a224d").unwrap(), hex::decode("0040c82357a6c79e2fb6f4d4bf95724a4bcc29bde7b449debdec01000000000000000000fa99bac89c24d15717ad877fecfbf734eb0bc75f8fb578f9470a5db668dbb8fbc0046b6ad43a02174b869a7d").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000206de1e86d50d4043ea7b06394598eb0d39316de61ebdb1d010000000000000000cbad54eff729d2e964a3b97e754a01da55cdbc8924788f415ad0e5e04f030bfb6baf9f59e93c0118bc7d5352").unwrap(), hex::decode("00000034395bcc21a6a2c2d3ccbc2773194d11a7ddfebf0e0919000000000000000000006f505e60f36ce9f73494bfbf0c0f058fee1e2e4822c1b0fa766fb9e3251fd9b38e056b6ad43a02172c4c0184").expect("Bytes32 from UTXO should be valid"),
hex::decode("12000020971fb5337db4cfcdabe3d0a19414e22f200d0dcfa60ae9000000000000000000f1e07bba0d854c76d60dfbdab247d68ebfc80ba5e95d4d83997178653fdbdcc5d1b09f59e93c01180b0f8fab").unwrap(), hex::decode("00800d20354b5388fb81effe12c3291a4cb50cc2adc5b98d079b00000000000000000000103e5e5b3d6d17e134cc0c76af0e91fe08d72591bf4c3ad7b6aa869d5d4cb02ba7066b6ad43a02172202f70c").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020b915dca0172c00dff21d436900f81fa55c4d0c94789708000000000000000000c0d80eedeab0a2e5ac800e4e0800b9a67a51d8095ff013977c56a5ee6a82564b91b19f59e93c0118626d6930").unwrap(), hex::decode("00200e20b3001fb8573b91195cb7b9c1de390d9991f3c07978d3010000000000000000003e6addca9c34eee9459e631d9d08e77c2de70703f102ce7903838cc77208f595c7066b6ad43a02173fa4ae35").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002038b29a8148601f802389e59448bd915254374cd89e3e07000000000000000000000f9be6ad775720838d044faabaa507c1d27374710fe36b66e7e855f275603c11b59f59e93c01186830dc10").unwrap(), hex::decode("006004209e4646297e4d4fd4f60548b0616a359650c35f1de7f30000000000000000000072aff40819e1e686905c68af2e73b9b951be3736437b416986cf18fd71fb8bd95a0b6b6ad43a021729d33887").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020f66bbe99a28e70f00ed13fae994a12950025129ee29dbb0000000000000000006e2e590253d6d4de2cb44f95292681e8a8dfe425ba3a231aefb0e239241d338747b99f59e93c01186621bcd3").unwrap(), hex::decode("00000022ee651093128e4598ff28ca297f351401d19696638b380000000000000000000038d529507d803dcf8080875cf2258aa8a551511c24f8b8ae3fa88423b0602748920b6b6ad43a02170846a89b").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000200b449c16f78cc9f3f56e7eb84c8c535b29230866ccc410010000000000000000b201b9bc39851f34c3d68a80453de339560947fa76f0d3d28aaa0fe6f3c09f0870bc9f59e93c0118a6f6bf4b").unwrap(), hex::decode("00608320be57374d6179c78ada919fffb2d9f908f5e18a74ff0501000000000000000000fa2f2dfb7b4d5235da7f1029804e23edbb7d3323af88199fc0ef1b79a1753459120c6b6ad43a02179a132a56").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000209073c42915b4ec2f93cb625299befbbe115867f9ffd6a400000000000000000065e326a16c150c95b145deff23e31b829ec224e16d62f426037fa0a9f515d96c11bf9f59e93c01189c3db0ca").unwrap(), hex::decode("00a0d227a580e546e615e1c532f47d89de7368c30df20e2e781b01000000000000000000e12705f05a4bbf09b87493335471db4f833e12d99fd36d76c5b3279082dd096e580c6b6ad43a02177e704ef5").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002000a52727e49fa397f8f211204c5a0bc40497b9b142c311000000000000000000ac88a88861b6c454b4dfc4bb8e4cd2fb475cacbb003c80bb4dcc44d89e324ef4ddbf9f59e93c01184ca16dab").unwrap(), hex::decode("00600f3912f664c2673dde9ab6886a85a2c9fc4efc177a0cbf4c01000000000000000000f1a81ddd80ef01b4a480de488f15402069ae8683ecc46770878b54fb7991c1a57d0d6b6ad43a0217bb384b12").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020643522aca18b6dd72993667995c1a0ed0db40a8ccfb014010000000000000000536ef1c8b3b657824e7dcf7650cb37bf8916773d0961ea46039880e81150dce130c19f59e93c01189304ead8").unwrap(), hex::decode("00803427b9cddcc2df57f4563ae0131adb3dd35bb9917139b95400000000000000000000c0b2ec9353f60fbdf5cf7da0ab0c17a78003bce2052a412c27d12665f76cb555fa136b6ad43a0217066d21e6").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000209f39c386609cf5fcde82901e09e3c21614d6c91bf1bf500000000000000000006a2196cfa5da0d2bfcddbafb8ef33c3535e2c6abfbbf0b9be5668a7d382d182b95c79f59e93c0118d7c51033").unwrap(), hex::decode("0040ec33bb8f6fa5e2f2ed3cf60cf91d6e79fcf7cde05b11087e01000000000000000000e6075b19a084d7c5aaa8484aeff15d8b5db4db88ad69d5ee647a3d9f778fedda61146b6ad43a0217a27b3033").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000204171fce850d6b9972bc84b5c129097700fcc940801daed000000000000000000c802782b023172b77fd0d67868e2c6fff4691b9081385c0b1fa8ee9b0edb9488afc89f59e93c0118dc47db2e").unwrap(), hex::decode("10a0c2227eb8240f150309fcaad8a2be205ddcbf06429a508662010000000000000000007e17cf9282b77723437c083af1aa83482a73fee35c73f110303d402d88fa8bed4c156b6ad43a02174b470b31").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000208229fd4875d341096fe972b42ec09c37ba5b3f5761307a000000000000000000f6d6b2238c3510a57ea4c85efa9ce8131a2e0e18b5db6ccb3ba62cfdb360d79a7ecd9f59e93c011878faaac7").unwrap(), hex::decode("00e00320cb4dec5b41a12bc19c29a6d424197f86c3b2ba025e25010000000000000000009d1a60c3889690294fc993f397a4dd1df48b3f9c4bdcb41306c3dedf033e4ee8461b6b6ad43a021763b89d28").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002016209868f23cee45d08d78e0a0a407cd2f44163e44cb3901000000000000000093d2238bcdc26dc75023b9c5118928bad163e39c2f71df8e95d6edd751ba79e648cf9f59e93c01188440a013").unwrap(), hex::decode("0000022052e6e25c9112220845c4c3e7fd939340336d3d33cdb600000000000000000000bfc9920255dcbba49376571e9ce3bcafc87bd36045903ecf4076480d96614b7b051d6b6ad43a02172e1a9b25").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000209207740837717a41d191055edaca417441ba8a518a008d000000000000000000ca7617ee77e441b43320206c73b0ab694e1a6e5cae68de543906bc78884ec96f54d19f59e93c0118ea3cdbf7").unwrap(), hex::decode("00209b22982e9a7ed287539bce7c3e603687aa2d3125079fb86a010000000000000000004102e56d0ce9029acb48c28745a9dce1783074391f3e70c695afdd392f6ad6d0ef1d6b6ad43a021722025f6d").expect("Bytes32 from UTXO should be valid"),
hex::decode("0200002095de633721183adca50ee64eb432278067f271ed5c6d110000000000000000008d58a1f0310aaa879af6d1567042c56316d0944a3745a48477eee8c0a9b160e0ded59f59e93c011840274171").unwrap(), hex::decode("10e0ff3f1bb91d2d09c8f74d7245ec18f7e5b6810a7f461dcdc900000000000000000000ac2b5e4ba6695790ec04953ef4774ece540667da058dc6c0888363c4fe922e0dc81f6b6ad43a021760ea40d6").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020eac6f48951848edb142e7d2cb65e5325e168eff217a9b100000000000000000018a5f3609c392597179460b0eb4f552150ea919674c07110541b3b937d61895bbcd69f59e93c0118990775cc").unwrap(), hex::decode("00c0f731f4aa3d9f670eaece00ac84c4c19cc4e2a26ef07851220200000000000000000060ee14b2e84e0f736907009618bc2d8296194d66c7ca0a027c702569990b49090d206b6ad43a0217eeb19de9").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020cd852383fdc3580f03d70427842597998ff05d642c301700000000000000000016d1f41abbeb84cf1260a156bb107f1831e1d4043087a62b91a802b6504ae82100de9f59e93c0118a2caa3e0").unwrap(), hex::decode("0020f92325a882bfdca063304e330248bdc067d51df8e92bcaf800000000000000000000c753e6732da8e5c98b3376480be610cbdf3cb16d836b59ab6362d2d228efedea29206b6ad43a0217c924f2a1").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020ba3564570e67b5e9258a0741a9b0a8c7eb21fc531e47340000000000000000008d51759065e5b563aa22534da2fe013cb78081b109a430f5224f2e3de395c31423de9f59e93c0118f387b5b2").unwrap(), hex::decode("00a0a220f0dc827b72a458a9ce7550312c0a8750d4f068713efa01000000000000000000cc94b5a5e75437a7c856b29b12da804ddb02fe1353bb210da2606d8180ec6fb631206b6ad43a02174e9d590a").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000205dd7d70d5b3b8654915a80a502636d762de4349b7ea35e0000000000000000005fad44d833d5963038adccc421a1f027e3ecdd321d94ce2981958a92d543a9823fde9f59e93c011809f75b68").unwrap(), hex::decode("0000082063447f3bc8b428d461b82a070be3db9410ab1fc40f24000000000000000000008dc755c30eaa2c22cc7a4a5792e3656f4bf698d38c41ebc4c85165fb8c9c6ded79206b6ad43a02173e731a1f").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020f6a223280df450a99052b9644fdbbb17c873cc650079c2000000000000000000ce4ecb69781542236a03b3f1ac1bcf33ff0c5392ea1e10810092c71607ed9b5cadec9f59e93c011831acafd8").unwrap(), hex::decode("10c05729b6ea9fbe42fb1d9405e47116cb0424329411d017e1aa0000000000000000000076a747223eaa6d45d3f84e2f6828cdc487c0dbdbad42b08a9b8fffc27665a960a7216b6ad43a02174394d82b").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020e572b677fdbc2c58ccfd064be23380d1a48880e2f57630010000000000000000de94574c2ba3c13464037089196614b4c7d3cb4d5af1fd8c42b7dc48099ddb29ecef9f59e93c0118718ceb94").unwrap(), hex::decode("00a08520af579ef409a189ab162c788896ad825b38faea3641c401000000000000000000dee9be72bd60eda2ab12e0217e2ca16a8bcb34c32f4972b273b77a17440d00e70a226b6ad43a0217116884ce").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000202b8b12967db07d4ebb88aa85ef66116c191a93e99b27120100000000000000003fd47c683e1e17d680a9110af97f0ca4c645760d1a2b9934dce5f2e88be5093c7af29f59e93c01185714a38b").unwrap(), hex::decode("00a00620482fd173f0a825fc34f487502c1566555f2862f0a02801000000000000000000bb5482aae60bfd220388693225362b18f72e82f9b5ceb9c6d2f9a61f2c28094fe0296b6ad43a0217fb407034").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000207880fe8eb9ce3c0868742ae98e71b18e23bc94f62ab02a010000000000000000817fb1fa49e3aff325c1b0e445629e06d31699b565daebf741b1b731d1e3db4a8cfc9f59e93c0118fc165574").unwrap(), hex::decode("00c00120e0e9282069496b464ef564a9ead03d37ce8e7a9f12c701000000000000000000975e9f48c1083438f32c873d67b2fddfc3c8e130ac9fbc1a53da01c01c3d46c8992a6b6ad43a0217ed908988").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020eae605b0e27d01a4a967f8b2788222bdf7d06c3f2cffb70000000000000000004647da086d8d604990e4e95a832430372fa388532599f5f2dc2c4248d6c62019c1fc9f59e93c0118346c62f4").unwrap(), hex::decode("00200723899fc0d3576718c15a6719c4bc71a91bd3ccc96192ec0000000000000000000004fdb6ab38260ca750671d7a6637ef75a651448c82cfc14554d57e2748be2be9722e6b6ad43a02178a807416").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020fb5de90e254a00c4f2e88b478d927e97f8cc7bcde99de7000000000000000000d31910146254c1034ee847eeb991d7a758be6b475bcfa2039ed8b8746160c6365bff9f59e93c01184568f141").unwrap(), hex::decode("0000ff3fbf073df0898e0324336409d64b6b11987fd4465bd82900000000000000000000f4e8fc5a02f4d8f4311eb5fbf73592c88906b0bce6a08b6e321e6c7b19509dfe8f326b6ad43a02175cba391b").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002001d8d41aac3bc8be7ec45a469db006bfd484e174c86d1400000000000000000080707a5e00bf7ee43650b1428d3fb7aa3ae10edce68fc1c44c0d50042251eee8c102a059e93c0118c28a0a25").unwrap(), hex::decode("00000b2080a47bfbe3066208d4fc39e065d584930a323adb645b0100000000000000000044ad1fa9768359f8528ddcbee3b5f1c773f184fabb6bf87d883e91b0f3f15b89d8316b6ad43a0217329de815").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020f4d340137354701e5acbaed498ebd833cb0bf6d4d4c0a400000000000000000058972fc8cad5065ec473d657070631c769714d5245f2a1c60819c0d58f2110d67306a059e93c01188ad1f723").unwrap(), hex::decode("006003204682f5d50b7c8bdea389f6c43515d3459584ab50c406010000000000000000003d441907ec00061b73368da7754ad305e6fd796cb4cf9d3410d5a65927d8e6ce74356b6ad43a02174b0fcdc3").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000201a0c546ed7a8560f402810f7db7e9ed31bb9ee33cca548000000000000000000fbc835eee64458ccf98e4e9b2f464b74c4a8f19ca62d88e91d370a5140ca849f8609a059e93c0118f85d071c").unwrap(), hex::decode("0000d3255924665d3d5fe933b16e09b06dcdd3bf7cce977223690000000000000000000024f812c8d99a9596021d3934a646bd50db9ca98931f3228c236952ac222217d3fe356b6ad43a0217effcbbff").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000202ed3ce68191cf5f2a141e1beda144282aa3cb91c86bb3a0100000000000000006baff826721270cbb61b6e87a200878944de3bc288b89c1ad9f4660a90b0de592d0da059e93c01180913db03").unwrap(), hex::decode("0000ff3f11bce3edc9ad7d6858a81f240977adb5517ef078ac5600000000000000000000a11d0de0146f427f426965160dbb0db66cebb6eb805bb3af11ee21924f2bdd71383c6b6ad43a0217936d08ca").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002037fefbaa4a417acddcff01b67e375aa274a5159b00cd250000000000000000000ad0731c0295fa7ad74b78ab37dda1760d98feb225c38932ebed3b3ab86010219d15a059e93c01180029355d").unwrap(), hex::decode("00e0002007bb096f631e7168dcda31d75201201e543037a0b43300000000000000000000a2a7803b593fbcd881866db771b59f2f98f5f69600460fb6ad553867a1e00a00323e6b6ad43a02170dbeda27").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000208d3517e8c5ac9576de6376dbe18bbc3f68b714bd90ff06000000000000000000f09393c9f8cdb4fa5e45a556d7aa3ee3abc08ff175fab17c321144c1540da3aa9316a059e93c0118394eb993").unwrap(), hex::decode("000000205a18258ccf12385ebd72c8f4f0aa2f5b5c5ec841ce10000000000000000000004a994b5f6c109f3cf616de3c0641711d1d4b848c7a04fe6e243765f67ec9cac875406b6ad43a02170d80ed5a").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002093b6ad64d95790be03f40782e42dd217d91a062514b482000000000000000000b4ce3863a62be400d10c4b06f31f8d805c52df6bbcc9d672fbf1ed110394f015f916a059e93c01188f006b8b").unwrap(), hex::decode("00c0722b62395602530b6d60060a8fce332cd1908f21b30b8be4010000000000000000009508e51190aa63ec2298af3cb644eeb1498c0d83d67680efe30d5fd1f6a95d6d7e426b6ad43a02179c08e6e0").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000206af6d3062235cfbc8dbac1f5f33b790b48eb025e945677000000000000000000e0b4b06f31170c9cc54e623247a18d3dcb5b37a97799abadf5be22cac18ab650a818a059e93c01182a2eadc0").unwrap(), hex::decode("00a02320b4b25be6c2ba4576586b90f8c4c3732648680cc5c2d901000000000000000000e5865a3d45646d51b65855b4b9a972198fca36241574a652ecfbab67b3f6256f97456b6ad43a021715c30439").expect("Bytes32 from UTXO should be valid"),
hex::decode("00000020e44d7e3e4e7ed258fd9dabb368bd20f42a5134ac63a9eb00000000000000000047da7bf618553524026b5f6054372b9fc26e3f561345290b4b2775f65214d76a7d22a059e93c011889243aa1").unwrap(), hex::decode("00000030ee8847f7a144b68c6e1e0bef2b4183db01bf825d6d05020000000000000000009798b0f81dc791ce7b17eec0d89ef9db7a2b541e9f582fb2387fd9b642418faa6e476b6ad43a0217a06ef431").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000200428d486033251c65fc8921aeda5d627b4974b2ed8710a01000000000000000026049ae797b8658ddff66af57c00fff50d83d123ecf2d70c5f7b6f40537aabbe9526a059e93c0118568368f3").unwrap(), hex::decode("00804521440b70d25839dbc3dd0bccd37ef751d50e576188eaa500000000000000000000314ff0850863609b917541ec201a10cd9f47f69cd2d1bf267cdb19fe3e91238bcc486b6ad43a02175e15bd74").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000204025364ce1f01cdfaf82e8c16665cb47a1b8156ce2c5be000000000000000000c4a56c66a75c261587536605fd4442dcfc190a4ddf5a13d6a063110e140bc5177e2ea059e93c0118fe232164").unwrap(), hex::decode("000065337e07a76349f99f3eaedfbd7ec9b048ae462fc439cddf0100000000000000000000268bf66e3c00ffff66a507729af9df227492b86f436331ebad0241ad055fe97b516b6ad43a021729b64713").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002072dd4401dd1ee65956efb1ef3e3c468611d2c4cbb9dfae000000000000000000f6d476f9b69b756b87fb6596d16409bc5d40803489c5d52ffbbb03d12d594a174b30a059e93c0118ad048658").unwrap(), hex::decode("00000022b936d35a2f4a755778159e39d6d80b5946bbf15b7c0b01000000000000000000640504d1606de9fce2fd0be5304c553b7f7092bd5f18c291e3fb1c63a973194fc3566b6ad43a021725c6c2d8").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000200f2e93d616b03ffa6d2377bb6c8a5eb31385fdb30f5ac7000000000000000000f6187a2f8e73a661cc90ed86546b62f45ab68a174e56d08d2d93ae12eda9b181ed32a059e93c01184d5d246d").unwrap(), hex::decode("00000020301ba83277f8012e1902f97eea3e53d0515ef73319f201000000000000000000f8a415b0a937ef5175c9715ac98e3373e373afad63cbc9c8541c51119d91115fca5b6b6ad43a02176c9b53e1").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000207f3d929b96f2121056e0cad6a3363316d648a56a3baa2d0000000000000000001ba48a3c40fd114080ca67441bbf6c1b787b7caf4e3f19a124627493f0e3334e6234a059e93c0118b34d5e41").unwrap(), hex::decode("00800420ec8823f23684b5a607fa9d6194dc174497f8501a194301000000000000000000af001c7d8797bdc2f8f45149d1f4cd394903e12d59c1f8afbcdbdce3b9925436665d6b6ad43a021776224a13").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002091c6841e0adf8d4bea707e3ab1e412b45bbfc80068b37a000000000000000000c273a936450ebd6f0ec9f16b04a955ccadd42fa446fb4ba0ac8cbd2874af988a2838a059e93c011889d44f30").unwrap(), hex::decode("00000020465a566082cb8faeeb44e097377a9174a11b65a051ff010000000000000000000b6ef86b33a25b37856c2e7c68543a5066dbe67c2a087c8f4199eb289357b17360616b6ad43a021776fc5e72").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000208a4af4109c84e53ca1ca671dc1ba75a55a2886f8eafd55000000000000000000e5b46a9cb2b8a975ab7c742fa57d942f5e52d0b92eff25954e916718f0eaaee1343aa059e93c0118e9904b69").unwrap(), hex::decode("10e0a02c5d89719ab4dce3ed69c543336776072cdcca1c26514301000000000000000000e860d743e10db71b2b7c5a1fadb2cea11ab7200ba04b4b776fd55d0939dc6cbc61616b6ad43a02171151725e").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000202d6cf055320a0e2781b77d1c0525e2897cd01cb03c9118010000000000000000fc8093d44e1279783a4d478a53bddcb55b58c4d06d51ea4bd8aeda28b66b2e7b423aa059e93c0118bc883a1e").unwrap(), hex::decode("00606e31bb3cc5e304822bfdf4506cc3b2e0aeb98a7b21280a0f01000000000000000000c897183f710feca8271a8709df053983a6d4489610a73d85b9f0014f58dd770262636b6ad43a0217a723ee06").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000208d5c1f0e78fc6b87fba844848dd41a37bedebe409ebb0f0100000000000000008b34b89a7e9b732d940cb77f642cf9c9eabff198f369aa94220ebcdf07d3e138ab3aa059e93c0118e0078029").unwrap(), hex::decode("00c0812002e5d76425f391738eac0c614d8afc795fde8c0dbf7d010000000000000000008c6bae74a46ad9f2905e5258d4adaf61af2bcf7c87e86a22f084f11710d58e2b36646b6ad43a021795ac6c1e").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020c639651d0a5acf604c4feac92e0879c16154ca9cad8c940000000000000000001802b2fb1bf4dd20a96a68aa416cd86325201b813ac9b3081d025e06a8632a2cfc3ca059e93c011864300336").unwrap(), hex::decode("00601820856aed25759848cd1ad02caec25afdc0cf17e9ffa0aa01000000000000000000c17d5c0a7bf4af165552c3e91b4d98f4d2afa2938e7b1bdf0912f1e850680a1c53656b6ad43a0217193b3d87").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000202ed62872636d3ae7803d9515f3a4360c0f096b08d9f8380100000000000000008476fe527a397800280d359dad7720ef220f2d749665fa8f3a5767a85d81a39f273fa059e93c0118ef87a752").unwrap(), hex::decode("00e02c3ade01a429e0f5c328824f4ee063b98f24ff3b0dc0db08000000000000000000009d0b402f41ab9c16e08f95de962044b206413f878608abca2015ee2074713078606d6b6ad43a0217c0650150").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000206bf7dfa1d97a1bfca63d76e41644ddbf34e1df525ff657000000000000000000cb05597fae3e31ae3a0dc3696bad38552e47b3d87987111e2ee602a8112f9495463fa059e93c0118d8578079").unwrap(), hex::decode("00008f2604b952dcd44dfcb61080ad77c5b626efd760e5f8ac8401000000000000000000ee81697e6cf7f41db37b63a9680906d3023be7a905785ef1b5ebd03fd22dd8bb2d6f6b6ad43a0217287aa17f").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002085dfc2bc2e4753ea4fa2079c69acc42a6d9da90b26530c00000000000000000069a1ec768f8b395c3efd9c04a7f11273b10589e1bfd4fa145fe26dc9cc603655d048a059e93c0118122e33dd").unwrap(), hex::decode("008017262c315a069a8896ec04d88ef423ff5cb3845320a6f123010000000000000000002d42d9519e62f5a48d4880b0ff0cd8021a38eadd469a2f7aabd0886061026a5026706b6ad43a02172ea14dd2").expect("Bytes32 from UTXO should be valid"),
]; ];
let receiver_32: [u8; 32] =
hex::decode("6969696969696969696969696969696969696969696969696969696969696969")
.expect("Bytes32 from UTXO should be valid")
.try_into()
.expect("Receiver address must be exactly 32 bytes");
let receiver_account = AccountId32::from(receiver_32);
let transfer_amount: BalanceOf<T> = 140_693u64.unique_saturated_into();
let ancestry_headers_vec: Vec<Vec<u8>> = historical_hashes let ancestry_headers_vec: Vec<Vec<u8>> = historical_hashes
.iter() .iter()
.take(max_history_depth) .take(max_history_depth)
.cloned() .cloned()
.collect(); .collect();
let gettxproof_bytes = hex::decode("00000020375a14cfcf5730daa8ff8d7a5bd2cf59fba797e289c2e0000000000000000000529cd017146361b57e6b7353b16d8d38d32f92ee842039dd779d35bfbfa2f3e53f649e59e93c01187900ea9fb40600000cfbd7b718845d123b1ae1a7fd3bce9c97acba097dc912c4ac67a920395db07ba4eef685960869ba70e0ca38890565c97dc11f1d7ae538e7b509069f81e38eff1a2e4a6b66fc4233d7d0580af4d195c7f0b274849f19d405dfc6b930bb9edd3f4a4c1f1e9fa3a336c50e8ea16039e4db4bef7ff5946e3a019937bdf626c2336d0e3926a83a575218f84e6dc55ffb9d0997a41e4b4d5425a85f22160c9f52362a95021a573ff96bb429bd80a8ec9dcb899971553efe91b6a0fe57c4694c3e8da8dc7f1babd514f2746da1ed06f08664baed853c334e0a3917d0c859b19ee14f448f77e624822070db3b606d5092027ca9ecf7e0243e6c151081021ebb3ddcdd28c1b8f9fdcffebd1962590477675f3d29d52602a1e7e941f772a3bbff42cf2eb6e74a1124bf424f767e294ae6253a21602c7c6b0381743dd6dcd57b025983e0e34375b24f67ac8beb00713d2f70594bbf797d5d94c061cb9965e6458f2f017f983d7ce37361fa13fda372f595dc1f22895ab93339457c72c480fed1c4d1164a242303ff3600").expect("Bytes32 from UTXO should be valid"); let gettxproof_bytes = hex::decode("008008201643a05d24fe1f015bf472fdedd8ef39dd8247568d3901000000000000000000569ac8f0aed0c5b632dd1dcc031f3d826a170e13cd8176430a2873a33d4694c2501f6a6ad43a02178dbac0d66b1600000e88be94dbcedc3f32bce789eb4512c68b39b91b54c4f2913e84baf7bae21bdc466d954b10876c1e8ad6591461027236c9a471883f96c028a7d1f08deb833f56fa18f457a6faa9c41340be484af67e444f8565b03085e1392fa2d56962f89919c4fcfff99fc6e92be067d01028fb54e8dc1e8425f0ef6bf1cc64220a2ba22163666eb01f99648e8c2af1bb1a0e1ba297f0244a09aa6a6ff87092312b02e8d75aef61e5c08f5b59184a45855e987c5ea114e5da61e55337bfae99f3a2e9601e72ae6036633dc97631609813a30d1185f98e7d6effc4a0330db0394da388c0058e9a730a62d8c679c35bf8d270ca8b95cec7d848729cdfd94a284f060f353b379bfc36310ac78306183a056a04156efd7e77661ce7ba50a4ef9f9e6b3681dfb39d8d0161ad0d2ec46834b5f270b67aa63a8a5b69287e8606b8a438785f8a5af66f84a2641438ba4a5fa22029227e9c2ddb6f23867b112c027d2fc2cf031a46c874701768b5c4983959b98d98736a2ed5ab0dd064ee24e49a3a7dac63e8b857ad4c8b5aa0cf22a7eac3180f3a54630b486de928ecf590e807d2e821818e2fe7e86610187d6673a6f95c639af80a7a7710b0088d44057ca61bdf5f4d5ba68d46b88e4304ffb70000").expect("Bytes32 from UTXO should be valid");
let getrawtransaction_bytes = hex::decode("010000000299a43fae581f80baf44e021ddf7b11995f184db282d6e48c22248b9fe79c43bb010000008b483045022100e9db01784dcd879c65d66127c2d52a4f9244321d15796893d6dccadaa1146e3d02203d9bb80f8df8b66692d3d9517f7cbb898d7cc40a30b175432322e1956c9b973a0141048097e4f8bb8ee104d5c2ece11d42f7e4719df8ddba459ecadecaba87d233c81a3c14830371392dd8ed030ef970450c0b7af48d9db4ba20c046896481602eb9dbffffffffb3fd05bc6000a5a0384e9a613d452e9307568df0a964907068e00403a0a0e09e020000006a47304402205bb1cbad4b29421648c1e22cac32a56aa06c933fe655559823fffb71ffebbc0b022021648d970560aa5b2031560b52a0fd06305995a58a457663324c18c1a9b0bd0b8121020d6e50b2660af27933c42bc1395fe93df90ffac5e2a989f6a134919fb8cf8075ffffffff030000000000000000296a2769642b5bb666ac1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e7c150000000000001976a914c1c69d91a5719a23ba2094d89a4df3eadfa4aef788acefea2309000000001976a9144635b1794a22bfbe6c5c5eba17b693f4aaf0e34888ac00000000").expect("Bytes32 from UTXO should be valid");
let last_header = ancestry_headers_vec.last().unwrap(); let dynamic_trusted_root = if ancestry_headers_vec.is_empty() {
let first_sha = sp_io::hashing::sha2_256(&last_header[..80]); let first_sha = sp_io::hashing::sha2_256(&gettxproof_bytes[..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); H256::from(native_le)
} else {
let last_header = ancestry_headers_vec.last().unwrap();
let first_sha = sp_io::hashing::sha2_256(&last_header[..80]);
let mut native_le = sp_io::hashing::sha2_256(&first_sha);
native_le.reverse();
H256::from(native_le)
};
LoomStates::<T>::insert(&network_id, &session, dynamic_trusted_root); LoomStates::<T>::insert(&network_id, &session, dynamic_trusted_root);
let payload = ThreadPayload::new(12, transfer_amount, receiver_account);
let utxo_thread_proof = UtxoThreadProof::new( let utxo_thread_proof = UtxoThreadProof::new(
1,
0,
transfer_amount,
payload,
gettxproof_bytes, gettxproof_bytes,
getrawtransaction_bytes, hex::decode("020000000001029ee4235efd4a3cb183d4c311ce858eeee7748263a28afd3d861bac1cb4a8d368010000000001000000d7c5869bfffaa1877d0ecd37e46dc70c232a16f7955e635d57f926d1b3e640bf0100000000ffffffff02ff490b0000000000160014f635b17877709ba3c5acbe153f38a47a733f5b169525020000000000160014c6e4e0f822c31540b4b05903ce3c67b6cff8e6d40247304402200f2f3763fad59d38b4e101b9675450c0a54d45fe17e2b1babde0d0ce6051ea5b0220643e71d66752c0f1bd30dc0897305da77f223d14c781e86063ac181ad7fb90b6012102aad4cca3dab6427bc754a5a123de32cd037e7177fade9f72d83088b00066cffc0247304402200c8f1ff8230813e5e4ab8ec802c614bc8705c407c5958d64dd79cc8422d85a6202203ea832d581c404200b5974fd1a11abfe1ebac213842083cb02eba3f253c8c2aa012102d70df1d4d58701adab82b4816e0640c27403d1fab859ca9f47cb6eccca3dd96200000000").expect("Bytes32 from UTXO should be valid"),
ancestry_headers_vec, ancestry_headers_vec,
); );
let thread_proof = ThreadProof::UtxoThreadProof(utxo_thread_proof); let thread_proof = ThreadProof::UtxoThreadProof(utxo_thread_proof);
let pulled_thread_key = thread_proof.get_unique_key(session, network_id); let pulled_thread_key = thread_proof.get_unique_key(session);
assert!(!PulledThreads::<T>::contains_key(&pulled_thread_key)); assert!(!PulledThreads::<T>::contains_key(&pulled_thread_key));
@ -333,15 +351,14 @@ mod benchmarks {
#[benchmark] #[benchmark]
fn pull_evm_thread() -> Result<(), BenchmarkError> { fn pull_evm_thread() -> Result<(), BenchmarkError> {
let session = 0; let session = 69;
let sepolia_network_id = 11155111; let (network_id, _, _) = prepare_pallet::<T>(1);
let (network_id, _, _) = prepare_pallet::<T>(1, Some(sepolia_network_id));
// https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract // https://sepolia.etherscan.io/address/0x9cffbdbdf29c67c5dbab1b5e8ae897aeafcaf70c#readContract
// getRoot: session 0, atBlock 11716130 // getRoot: session 0, atBlock 11383380
let root_string = let root_string =
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129") hex::decode("f72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d")
.expect("EVM Root hex should be valid"); .expect("EVM Root hex should be valid");
let expected_root = H256::from_slice(&root_string); let expected_root = H256::from_slice(&root_string);
LoomStates::<T>::insert(&network_id, &session, expected_root); LoomStates::<T>::insert(&network_id, &session, expected_root);
@ -356,24 +373,49 @@ mod benchmarks {
let transfer_amount: BalanceOf<T> = 420u64.unique_saturated_into(); let transfer_amount: BalanceOf<T> = 420u64.unique_saturated_into();
let proof = vec![ let proof = vec![
H256::from_slice(&hex::decode("7d831a4be9e37572687117870c3f96669a66bf07971e4fd705a36a0a4d6365b0").expect("Proof should be valid")), H256::from_slice(
H256::from_slice(&hex::decode("9f00b99751b7ccea1903949210408edb3ce50343985708c36a0b1d44e0a7628c").expect("Proof should be valid")), &hex::decode("6dfb19f049f557abff273ce9efb9195924d41e5699b1b7755be2c515b25ef7b6")
H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")), .expect("Proof should be valid"),
H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")), ),
H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")), H256::from_slice(
H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")), &hex::decode("9e0f9c5b8ffa146b74bb614482c0bc65a1ef961a8fa9a3a031a36c97f8c70733")
H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")), .expect("Proof should be valid"),
H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")), ),
H256::from_slice(
&hex::decode("890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d")
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode("3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd8")
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode("ecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da")
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode("defff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da5")
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode("617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d7")
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode("292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead")
.expect("Proof should be valid"),
),
]; ];
let slots = vec![H256::from_slice( let slots = vec![H256::from_slice(
&hex::decode("f6182b8c276793f53d1820ad0405665177516e46e40af45e0dfea73c39a2306e") &hex::decode("2e474dabf492786b3505d7b7cf0bf07c9dbce92c91982fa7344c77e24fd4310d")
.expect("Slot should be valid hex"), .expect("Slot should be valid hex"),
)]; )];
let evm_thread_proof = EvmThreadProof::new(0, 1, receiver_account, transfer_amount, proof, slots); let payload = ThreadPayload::new(1, transfer_amount, receiver_account);
let evm_thread_proof = EvmThreadProof::new(0, payload, proof, slots);
let thread_proof = ThreadProof::EvmThreadProof(evm_thread_proof); let thread_proof = ThreadProof::EvmThreadProof(evm_thread_proof);
let pulled_thread_key = thread_proof.get_unique_key(session, network_id); let pulled_thread_key = thread_proof.get_unique_key(session);
assert!(!PulledThreads::<T>::contains_key(&pulled_thread_key)); assert!(!PulledThreads::<T>::contains_key(&pulled_thread_key));

View File

@ -25,7 +25,7 @@ use sp_runtime::{
use ghost_helpers::{ use ghost_helpers::{
bounded_bitmap::{validate_bitmap_sizes, BoundedBitmap}, bounded_bitmap::{validate_bitmap_sizes, BoundedBitmap},
get_byzantium_quorum_threshold, get_byzantium_threshold,
networks::{NetworkData, NetworkType}, networks::{NetworkData, NetworkType},
}; };
use ghost_traits::{ use ghost_traits::{
@ -439,21 +439,22 @@ pub mod pallet {
.ok_or(Error::<T>::NonExistentNetworkId)?; .ok_or(Error::<T>::NonExistentNetworkId)?;
let root_hash = LoomStates::<T>::get(&network_id, &session); let root_hash = 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);
ensure!( ensure!(
!PulledThreads::<T>::contains_key(&pulled_thread_key), !PulledThreads::<T>::contains_key(&pulled_thread_key),
Error::<T>::ThreadAlreadyPulled, Error::<T>::ThreadAlreadyPulled,
); );
let (receiver_account, amount) = thread_proof let receiver_account = thread_proof
.verify_thread_proof(root_hash, network_id, &network_data.gatekeeper) .verify_proof(root_hash, &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();
let receiver = T::AccountId::decode(&mut &receiver_bytes[..]) let receiver = T::AccountId::decode(&mut &receiver_bytes[..])
.map_err(|_| Error::<T>::InvalidReceiverAddress)?; .map_err(|_| Error::<T>::InvalidReceiverAddress)?;
let amount = thread_proof.amount();
let pure_amount = let pure_amount =
T::NetworkDataHandler::register_incoming(&network_id, amount) T::NetworkDataHandler::register_incoming(&network_id, amount)
.map_err(|_| Error::<T>::CouldNotRegisterIncoming)?; .map_err(|_| Error::<T>::CouldNotRegisterIncoming)?;
@ -486,7 +487,7 @@ pub mod pallet {
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 1)); weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 1));
let len = Authorities::<T>::decode_len().unwrap_or_default(); let len = Authorities::<T>::decode_len().unwrap_or_default();
let weaving_threshold = get_byzantium_quorum_threshold(len); let weaving_threshold = get_byzantium_threshold(len);
let maybe_tapestry_drafts = TapestryDrafts::<T>::get(&network_id); let maybe_tapestry_drafts = TapestryDrafts::<T>::get(&network_id);
@ -849,7 +850,7 @@ impl<T: Config> Pallet<T> {
.parse_block_requests(pending_requests, deadline, request_id); .parse_block_requests(pending_requests, deadline, request_id);
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_threshold(total_blocks);
let median_block = Self::validate_block_numbers_consensus( let median_block = Self::validate_block_numbers_consensus(
&mut block_numbers, &mut block_numbers,

View File

@ -14,11 +14,8 @@ use sp_runtime::codec::Encode;
use sp_core::{H256, crypto::Pair}; use sp_core::{H256, crypto::Pair};
use sp_runtime::{ use sp_runtime::{
Perbill,
traits::{Dispatchable, ValidateUnsigned}, traits::{Dispatchable, ValidateUnsigned},
transaction_validity::{ transaction_validity::{InvalidTransaction, TransactionSource, TransactionValidityError},
InvalidTransaction, TransactionSource, TransactionValidityError,
},
}; };
use sp_core::offchain::{ use sp_core::offchain::{
@ -68,9 +65,7 @@ fn should_successfully_compute_median_and_start_weaving_round() {
let pair3 = AuthorityPair::from_string("//Carol", None).expect("Should be valid seed"); let pair3 = AuthorityPair::from_string("//Carol", None).expect("Should be valid seed");
let network_id = 1; let network_id = 1;
let network_data = NetworkDataBuilder::default() let network_data = NetworkDataBuilder::default().build();
.with_block_deviation(5)
.build();
let authorities = vec![pair1.clone(), pair2.clone(), pair3.clone()]; let authorities = vec![pair1.clone(), pair2.clone(), pair3.clone()];
let networks = vec![(network_id, network_data, Default::default())]; let networks = vec![(network_id, network_data, Default::default())];
@ -127,8 +122,8 @@ fn should_apply_cooldown_delay_on_consensus_failure() {
.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);
let att2 = context.with_authority_index(1).build_block_attestation(102); let att2 = context.with_authority_index(1).build_block_attestation(500);
let att3 = context.with_authority_index(2).build_block_attestation(104); let att3 = context.with_authority_index(2).build_block_attestation(900);
let sig1 = pair1.sign(&att1.encode()); let sig1 = pair1.sign(&att1.encode());
let sig2 = pair2.sign(&att2.encode()); let sig2 = pair2.sign(&att2.encode());
@ -560,7 +555,7 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
fn should_successfully_pull_evm_thread_and_mint_currency() { fn should_successfully_pull_evm_thread_and_mint_currency() {
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 network_id = 11155111; let network_id = 1;
let network_data = NetworkDataBuilder::default() let network_data = NetworkDataBuilder::default()
.with_network_type(NetworkType::Evm) .with_network_type(NetworkType::Evm)
.build(); .build();
@ -568,78 +563,204 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
let authorities = vec![pair.clone()]; let authorities = vec![pair.clone()];
let networks = vec![(network_id, network_data, Default::default())]; let networks = vec![(network_id, network_data, Default::default())];
// Contract address: 0x7fec11e652f4d54e8cf11c4b52c360380332f2bd // Contract address: 0x9a52C28dA655b69d8ddc430d6ebD04630BA0e845
// //
// three inserts // three inserts
// 69 sfJ9hc4A7r578XM35nd48B3FWcd33XjpVnAbGC5tvtwthMWdU - 0xc477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e // 69 sfJ9hc4A7r578XM35nd48B3FWcd33XjpVnAbGC5tvtwthMWdU - 0xc477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e
// 420 sfDxNicCEPts6CVttVMPCs2eoymDpQahu1GUVyGPWu6dhwADJ - 0x0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e // 420 sfDxNicCEPts6CVttVMPCs2eoymDpQahu1GUVyGPWu6dhwADJ - 0x0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e
// 1337 sfH6zJ63fcxrFAZ1RmiHbxgy2t3sEufY26WdsBSS359AzJd4w - 0x962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b // 1337 sfH6zJ63fcxrFAZ1RmiHbxgy2t3sEufY26WdsBSS359AzJd4w - 0x962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b
// https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract // https://sepolia.etherscan.io/address/0x9cffbdbdf29c67c5dbab1b5e8ae897aeafcaf70c#readContract
// getRoot: atBlock 11716130, globalIndexes from 0 to 2 // getRoot: atBlock 11383380, globalIndexes from 0 to 2
let inserts = vec![ let inserts = vec![
( (
0, 0,
hex::decode("c477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e").expect("Bytes32 from EVM should be valid"), hex::decode("c477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e")
.expect("Bytes32 from EVM should be valid"),
69u64, 69u64,
vec![ vec![
H256::from_slice(&hex::decode("2d931b11b1652669a04e7b5b50418f5e1e2fabb6791dabc9a196e719ad5cf9c6").expect("Proof should be valid")), H256::from_slice(
H256::from_slice(&hex::decode("9f00b99751b7ccea1903949210408edb3ce50343985708c36a0b1d44e0a7628c").expect("Proof should be valid")), &hex::decode(
H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")), "c7a710c9acbc193692f34ac1f1979013b04240a4c0d02b49b9178f17721350b1",
H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")), )
H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")), .expect("Proof should be valid"),
H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")), ),
H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")), H256::from_slice(
H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")), &hex::decode(
"9e0f9c5b8ffa146b74bb614482c0bc65a1ef961a8fa9a3a031a36c97f8c70733",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd8",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"ecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"defff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da5",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d7",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead",
)
.expect("Proof should be valid"),
),
], ],
vec![H256::from_slice( vec![H256::from_slice(
&hex::decode("f494b2065ca61f2af007a3dd5f1f3d228a3ad09f4f7b7c5ef3eeb3aee6718ee2").expect("Slot should be valid hex"), &hex::decode("350a78f78c810898b7c60ddba671543bfbe683ffb0ac393df0e132f607b5f738")
.expect("Slot should be valid hex"),
)], )],
), ),
( (
1, 1,
hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e").expect("Bytes32 from EVM should be valid"), hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e")
.expect("Bytes32 from EVM should be valid"),
420u64, 420u64,
vec![ vec![
H256::from_slice(&hex::decode("7d831a4be9e37572687117870c3f96669a66bf07971e4fd705a36a0a4d6365b0").expect("Proof should be valid")), H256::from_slice(
H256::from_slice(&hex::decode("9f00b99751b7ccea1903949210408edb3ce50343985708c36a0b1d44e0a7628c").expect("Proof should be valid")), &hex::decode(
H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")), "6dfb19f049f557abff273ce9efb9195924d41e5699b1b7755be2c515b25ef7b6",
H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")), )
H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")), .expect("Proof should be valid"),
H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")), ),
H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")), H256::from_slice(
H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")), &hex::decode(
"9e0f9c5b8ffa146b74bb614482c0bc65a1ef961a8fa9a3a031a36c97f8c70733",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd8",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"ecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"defff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da5",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d7",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead",
)
.expect("Proof should be valid"),
),
], ],
vec![H256::from_slice( vec![H256::from_slice(
&hex::decode("f6182b8c276793f53d1820ad0405665177516e46e40af45e0dfea73c39a2306e").expect("Slot should be valid hex"), &hex::decode("2e474dabf492786b3505d7b7cf0bf07c9dbce92c91982fa7344c77e24fd4310d")
.expect("Slot should be valid hex"),
)], )],
), ),
( (
2, 2,
hex::decode("962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b").expect("Bytes32 from EVM should be valid"), hex::decode("962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b")
.expect("Bytes32 from EVM should be valid"),
1337u64, 1337u64,
vec![ vec![
H256::from_slice(&hex::decode("f39a869f62e75cf5f0bf914688a6b289caf2049435d8e68c5c5e6d05e44913f3").expect("Proof should be valid")), H256::from_slice(
H256::from_slice(&hex::decode("385de173dc8295d4153b2de3bd705dd96556c8c316a996b3e56adce0970ffa36").expect("Proof should be valid")), &hex::decode(
H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")), "290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563",
H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")), )
H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")), .expect("Proof should be valid"),
H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")), ),
H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")), H256::from_slice(
H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")), &hex::decode(
"82ca531d09faff937c9b68f53d473c9f2c88bdbc8b1629af894479367881db5c",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd8",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"ecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"defff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da5",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d7",
)
.expect("Proof should be valid"),
),
H256::from_slice(
&hex::decode(
"292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead",
)
.expect("Proof should be valid"),
),
], ],
vec![H256::from_slice( vec![H256::from_slice(
&hex::decode("2f52c7d2d3f4167c436f3b6cc0a7d944a45846ba87f74998100b83122d5eb0ad").expect("Slot should be valid hex"), &hex::decode("bde870fce92d701a7a5d6f63003e1cd2cb61c3266fc1be256844b8ca61d9c9ab")
.expect("Slot should be valid hex"),
)], )],
), ),
]; ];
new_test_ext(authorities, networks).execute_with(|| { new_test_ext(authorities, networks).execute_with(|| {
// https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract // https://sepolia.etherscan.io/address/0x9cffbdbdf29c67c5dbab1b5e8ae897aeafcaf70c#readContract
// getRoot: session 0, atBlock 11716130 // getRoot: session 0, atBlock 11383380
let session = 0; let session = 0;
let root_string = let root_string =
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129") hex::decode("f72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d")
.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); LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root);
@ -656,20 +777,17 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
let receiver_account = sp_runtime::AccountId32::from(receiver_32); let receiver_account = sp_runtime::AccountId32::from(receiver_32);
let transfer_amount = insert.2; let transfer_amount = insert.2;
let payload =
ThreadPayload::new(proof_index, transfer_amount, receiver_account.clone());
let proof = insert.3; let proof = insert.3;
let slots = insert.4; let slots = insert.4;
let evm_thread_proof = EvmThreadProof::new( let evm_thread_proof = EvmThreadProof::new(slot_index, payload, proof, slots);
slot_index,
proof_index,
receiver_account.clone(),
transfer_amount,
proof,
slots,
);
let thread_info = ThreadProof::EvmThreadProof(evm_thread_proof); let thread_info = ThreadProof::EvmThreadProof(evm_thread_proof);
let pulled_thread_key = thread_info.get_unique_key(session, network_id); let pulled_thread_key = thread_info.get_unique_key(session);
assert_eq!(Balances::free_balance(&receiver_account), 0); assert_eq!(Balances::free_balance(&receiver_account), 0);
assert!(!PulledThreads::<TestRuntime>::contains_key( assert!(!PulledThreads::<TestRuntime>::contains_key(
@ -680,7 +798,8 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
network_id, network_id,
session, session,
thread_info thread_info
).is_ok()); )
.is_ok());
assert!(PulledThreads::<TestRuntime>::contains_key( assert!(PulledThreads::<TestRuntime>::contains_key(
&pulled_thread_key &pulled_thread_key
@ -707,15 +826,13 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
#[test] #[test]
fn should_successfully_pull_utxo_thread_and_mint_currency() { fn should_successfully_pull_utxo_thread_and_mint_currency() {
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 incoming_share = 500_000_000;
let network_id = 69; let network_id = 69;
let network_data = NetworkDataBuilder::default() let network_data = NetworkDataBuilder::default()
.with_network_type(NetworkType::Utxo) .with_network_type(NetworkType::Utxo)
.with_incoming_share(incoming_share)
.with_gatekeeper( .with_gatekeeper(
// Transaction: https://blockstream.info/tx/4a3fdd9ebb30b9c6df05d4199f8474b2f0c795d1f40a58d0d73342fc666b4a2e // Transaction: https://blockstream.info/tx/c41999f86269d5a22f39e18530b065854f447ef64a48be4013c4a9faa657f418
hex::decode("4635b1794a22bfbe6c5c5eba17b693f4aaf0e348") hex::decode("c6e4e0f822c31540b4b05903ce3c67b6cff8e6d4000000000000000000000000")
.expect("Bytes32 from UTXO should be valid"), .expect("Bytes32 from UTXO should be valid"),
) )
.build(); .build();
@ -723,80 +840,100 @@ fn should_successfully_pull_utxo_thread_and_mint_currency() {
let authorities = vec![pair.clone()]; let authorities = vec![pair.clone()];
let networks = vec![(network_id, network_data, Default::default())]; let networks = vec![(network_id, network_data, Default::default())];
// Real world tx at block #481838 // Real world tx at block #960127
// Block https://blockstream.info/block/0000000000000000011bdccb39e19e942a60edffdccd9779653c5b46b337904a // Block: https://blockstream.info/block/0000000000000000000091c72779c83d76dfa8149e950f3a5287377a9708d5c1
// Transaction: https://blockstream.info/tx/4a3fdd9ebb30b9c6df05d4199f8474b2f0c795d1f40a58d0d73342fc666b4a2e let inserts = vec![
(
let payload = ( // Transaction: https://blockstream.info/tx/c41999f86269d5a22f39e18530b065854f447ef64a48be4013c4a9faa657f418
// curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "gettxoutproof", "params": [["4a3fdd9ebb30b9c6df05d4199f8474b2f0c795d1f40a58d0d73342fc666b4a2e"], "0000000000000000011bdccb39e19e942a60edffdccd9779653c5b46b337904a"]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com // We are looking into second output and first witness
hex::decode("00000020375a14cfcf5730daa8ff8d7a5bd2cf59fba797e289c2e0000000000000000000529cd017146361b57e6b7353b16d8d38d32f92ee842039dd779d35bfbfa2f3e53f649e59e93c01187900ea9fb40600000cfbd7b718845d123b1ae1a7fd3bce9c97acba097dc912c4ac67a920395db07ba4eef685960869ba70e0ca38890565c97dc11f1d7ae538e7b509069f81e38eff1a2e4a6b66fc4233d7d0580af4d195c7f0b274849f19d405dfc6b930bb9edd3f4a4c1f1e9fa3a336c50e8ea16039e4db4bef7ff5946e3a019937bdf626c2336d0e3926a83a575218f84e6dc55ffb9d0997a41e4b4d5425a85f22160c9f52362a95021a573ff96bb429bd80a8ec9dcb899971553efe91b6a0fe57c4694c3e8da8dc7f1babd514f2746da1ed06f08664baed853c334e0a3917d0c859b19ee14f448f77e624822070db3b606d5092027ca9ecf7e0243e6c151081021ebb3ddcdd28c1b8f9fdcffebd1962590477675f3d29d52602a1e7e941f772a3bbff42cf2eb6e74a1124bf424f767e294ae6253a21602c7c6b0381743dd6dcd57b025983e0e34375b24f67ac8beb00713d2f70594bbf797d5d94c061cb9965e6458f2f017f983d7ce37361fa13fda372f595dc1f22895ab93339457c72c480fed1c4d1164a242303ff3600").expect("Bytes32 from UTXO should be valid"), // NOTE: would be nice to use on of our txs
// 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("6969696969696969696969696969696969696969696969696969696969696969").expect("Bytes32 from UTXO should be valid"),
hex::decode("010000000299a43fae581f80baf44e021ddf7b11995f184db282d6e48c22248b9fe79c43bb010000008b483045022100e9db01784dcd879c65d66127c2d52a4f9244321d15796893d6dccadaa1146e3d02203d9bb80f8df8b66692d3d9517f7cbb898d7cc40a30b175432322e1956c9b973a0141048097e4f8bb8ee104d5c2ece11d42f7e4719df8ddba459ecadecaba87d233c81a3c14830371392dd8ed030ef970450c0b7af48d9db4ba20c046896481602eb9dbffffffffb3fd05bc6000a5a0384e9a613d452e9307568df0a964907068e00403a0a0e09e020000006a47304402205bb1cbad4b29421648c1e22cac32a56aa06c933fe655559823fffb71ffebbc0b022021648d970560aa5b2031560b52a0fd06305995a58a457663324c18c1a9b0bd0b8121020d6e50b2660af27933c42bc1395fe93df90ffac5e2a989f6a134919fb8cf8075ffffffff030000000000000000296a2769642b5bb666ac1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e7c150000000000001976a914c1c69d91a5719a23ba2094d89a4df3eadfa4aef788acefea2309000000001976a9144635b1794a22bfbe6c5c5eba17b693f4aaf0e34888ac00000000").expect("Bytes32 from UTXO should be valid"), 140_693u64,
vec![ 1,
// curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "getblockheader", "params": ["000000000000000000e7da64065cc23d5c5a5aa402f088aaaf37c5fe1c3b6b92", false]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com 0,
hex::decode("000000204a9037b3465b3c657997cddcffed602a949ee139cbdc1b010000000000000000669c3e2472384bc95993f154aada38d6b2113d8d32069e32e2724ba40915a1802a669e59e93c011801c8c735").expect("Bytes32 from UTXO should be valid"), // curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "gettxoutproof", "params": [["c41999f86269d5a22f39e18530b065854f447ef64a48be4013c4a9faa657f418"], "0000000000000000000091c72779c83d76dfa8149e950f3a5287377a9708d5c1"]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
// 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("008008201643a05d24fe1f015bf472fdedd8ef39dd8247568d3901000000000000000000569ac8f0aed0c5b632dd1dcc031f3d826a170e13cd8176430a2873a33d4694c2501f6a6ad43a02178dbac0d66b1600000e88be94dbcedc3f32bce789eb4512c68b39b91b54c4f2913e84baf7bae21bdc466d954b10876c1e8ad6591461027236c9a471883f96c028a7d1f08deb833f56fa18f457a6faa9c41340be484af67e444f8565b03085e1392fa2d56962f89919c4fcfff99fc6e92be067d01028fb54e8dc1e8425f0ef6bf1cc64220a2ba22163666eb01f99648e8c2af1bb1a0e1ba297f0244a09aa6a6ff87092312b02e8d75aef61e5c08f5b59184a45855e987c5ea114e5da61e55337bfae99f3a2e9601e72ae6036633dc97631609813a30d1185f98e7d6effc4a0330db0394da388c0058e9a730a62d8c679c35bf8d270ca8b95cec7d848729cdfd94a284f060f353b379bfc36310ac78306183a056a04156efd7e77661ce7ba50a4ef9f9e6b3681dfb39d8d0161ad0d2ec46834b5f270b67aa63a8a5b69287e8606b8a438785f8a5af66f84a2641438ba4a5fa22029227e9c2ddb6f23867b112c027d2fc2cf031a46c874701768b5c4983959b98d98736a2ed5ab0dd064ee24e49a3a7dac63e8b857ad4c8b5aa0cf22a7eac3180f3a54630b486de928ecf590e807d2e821818e2fe7e86610187d6673a6f95c639af80a7a7710b0088d44057ca61bdf5f4d5ba68d46b88e4304ffb70000").expect("Bytes32 from UTXO should be valid"),
hex::decode("02000020926b3b1cfec537afaa88f002a45a5a5c3dc25c0664dae7000000000000000000af0f270bf3f868d47089f395197809c360f1506636c960d96afed68bbd72d0b4496d9e59e93c01183ac94b67").expect("Bytes32 from UTXO should be valid"), // curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "getrawtransaction", "params": ["c41999f86269d5a22f39e18530b065854f447ef64a48be4013c4a9faa657f418", true]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
// 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("020000000001029ee4235efd4a3cb183d4c311ce858eeee7748263a28afd3d861bac1cb4a8d368010000000001000000d7c5869bfffaa1877d0ecd37e46dc70c232a16f7955e635d57f926d1b3e640bf0100000000ffffffff02ff490b0000000000160014f635b17877709ba3c5acbe153f38a47a733f5b169525020000000000160014c6e4e0f822c31540b4b05903ce3c67b6cff8e6d40247304402200f2f3763fad59d38b4e101b9675450c0a54d45fe17e2b1babde0d0ce6051ea5b0220643e71d66752c0f1bd30dc0897305da77f223d14c781e86063ac181ad7fb90b6012102aad4cca3dab6427bc754a5a123de32cd037e7177fade9f72d83088b00066cffc0247304402200c8f1ff8230813e5e4ab8ec802c614bc8705c407c5958d64dd79cc8422d85a6202203ea832d581c404200b5974fd1a11abfe1ebac213842083cb02eba3f253c8c2aa012102d70df1d4d58701adab82b4816e0640c27403d1fab859ca9f47cb6eccca3dd96200000000").expect("Bytes32 from UTXO should be valid"),
hex::decode("0000002093b3d5716570bdd5afd75a1c7d87873bacc062936dda630000000000000000009ab437e7c66b10a59b67127f290d24f381aba4e03d5e16c062a356eea4d608dea56d9e59e93c0118264f310e").expect("Bytes32 from UTXO should be valid"), vec![
], // curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "getblockheader", "params": ["0000000000000000000084bd8092a07bc89245c2bf05f2cf75851bcc5ef92f70", false]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
); hex::decode("00a01520c1d508977a3787523a0f959e14a8df763dc87927c7910000000000000000000036303f2bcf94f752a1d4b0641d1adbc2d80aa89628feefd7f837a74792e26ab8bb276a6ad43a0217bece2e64").expect("Bytes32 from UTXO should be valid"),
// curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "getblockheader", "params": ["000000000000000000016792d9c1460bfa4db07da3b724db76c3dd0640ca5754", false]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
hex::decode("0400e020702ff95ecc1b8575cff205bfc24592c87ba09280bd84000000000000000000008ca9c40d5ab762f160661635cade50fd14571dcf5fdf8c463b617caf9b07dc5a3b296a6ad43a02171340d661").expect("Bytes32 from UTXO should be valid"),
// curl --data-binary '{"jsonrpc": "2.0", "id": "test-proof", "method": "getblockheader", "params": ["0000000000000000000078eb1af63fe8d57f93079121e19968a8563c05af370e", false]}' -H 'Content-Type: application/json' https://bitcoin-rpc.publicnode.com
hex::decode("000000345457ca4006ddc376db24b7a37db04dfa0b46c1d99267010000000000000000009409d64eb06a6dd83ae2937f70d07222d75505a07f12e756b61a27189851e3bbfe2c6a6ad43a0217a06575b5").expect("Bytes32 from UTXO should be valid"),
],
)
];
new_test_ext(authorities, networks).execute_with(|| { new_test_ext(authorities, networks).execute_with(|| {
let session = 0; let session = 0;
let block_hash = let root_string =
hex::decode("000000000000000000ec6063eb743366264368be7ff5021727682cb518963026") hex::decode("0000000000000000000078eb1af63fe8d57f93079121e19968a8563c05af370e")
.expect("Bitcoin Root hex should be valid"); .expect("Bitcoin Root hex should be valid");
let expected_root = H256::from_slice(&root_string);
let expected_root = H256::from_slice(&block_hash);
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root); LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root);
let expected_receiver_bytes = hex::decode("1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e").unwrap(); for insert in inserts.into_iter() {
let mut receiver_raw = [0u8; 32]; let receiver_32: [u8; 32] = insert
receiver_raw.copy_from_slice(&expected_receiver_bytes); .0
.try_into()
.expect("Receiver address must be exactly 32 bytes");
let receiver_account = sp_runtime::AccountId32::from(receiver_32);
let transfer_amount = insert.1;
let receiver_account = sp_runtime::AccountId32::from(receiver_raw); let payload = ThreadPayload::new(12, transfer_amount, receiver_account.clone());
let transfer_amount: u64 = 153348847; let utxo_thread_proof = UtxoThreadProof::new(
insert.2,
insert.3,
transfer_amount,
payload,
insert.4,
insert.5,
insert.6,
);
let utxo_thread_proof = UtxoThreadProof::new(payload.0, payload.1, payload.2); let thread_info = ThreadProof::UtxoThreadProof(utxo_thread_proof);
let thread_info = ThreadProof::UtxoThreadProof(utxo_thread_proof); let pulled_thread_key = thread_info.get_unique_key(session);
let pulled_thread_key = thread_info.get_unique_key(session, network_id);
assert_eq!(Balances::free_balance(&receiver_account), 0); assert_eq!(Balances::free_balance(&receiver_account), 0);
assert!(!PulledThreads::<TestRuntime>::contains_key( assert!(!PulledThreads::<TestRuntime>::contains_key(
&pulled_thread_key &pulled_thread_key
)); ));
assert!(GhostWeaver::pull_thread( assert!(GhostWeaver::pull_thread(
RuntimeOrigin::none(), RuntimeOrigin::none(),
network_id, network_id,
session, session,
thread_info thread_info
).is_ok()); )
.is_ok());
assert!(PulledThreads::<TestRuntime>::contains_key( assert!(PulledThreads::<TestRuntime>::contains_key(
&pulled_thread_key &pulled_thread_key
)); ));
let curve_share = Perbill::from_parts(incoming_share).mul_ceil(transfer_amount); let expected_commission = 0u64;
let expected_pure_amount = transfer_amount.saturating_sub(curve_share); let expected_pure_amount = transfer_amount - expected_commission;
assert_eq!( assert_eq!(
Balances::free_balance(&receiver_account), Balances::free_balance(&receiver_account),
expected_pure_amount expected_pure_amount
); );
System::assert_last_event(RuntimeEvent::GhostWeaver(Event::ThreadPulled { System::assert_last_event(RuntimeEvent::GhostWeaver(Event::ThreadPulled {
pulled_thread_key, pulled_thread_key,
network_id, network_id,
receiver: receiver_account, receiver: receiver_account,
amount: transfer_amount, amount: transfer_amount,
})); }));
}
}); });
} }
#[test] #[test]
fn on_initialize_should_finalize_session_when_timeout_is_reached() { fn on_initialize_should_finalize_session_when_threshold_or_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");
let pair2 = AuthorityPair::from_string("//Bob", 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 pair3 = AuthorityPair::from_string("//Charlie", None).expect("Should be valid seed");
@ -858,12 +995,14 @@ fn on_initialize_should_finalize_session_when_timeout_is_reached() {
let current_session = CurrentWeavingSession::<TestRuntime>::get(&network_id); let current_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
GhostWeaver::on_initialize(current_substrate_block); GhostWeaver::on_initialize(current_substrate_block);
let saved_loom = LoomStates::<TestRuntime>::get(&network_id, current_session); let saved_loot = LoomStates::<TestRuntime>::get(&network_id, current_session);
assert_ne!(saved_loom, target_hash); assert_eq!(saved_loot, target_hash);
assert_eq!(saved_loom, saved_loom);
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 + 1);
System::set_block_number(15);
GhostWeaver::on_initialize(15);
}); });
} }

View File

@ -31,11 +31,6 @@ const UTXO_MAX_HISTORY_DEPTH: u32 = UTXO_MAX_HISTORY_DEPTH_VALUE;
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
pub const UTXO_MAX_HISTORY_DEPTH: u32 = UTXO_MAX_HISTORY_DEPTH_VALUE; pub const UTXO_MAX_HISTORY_DEPTH: u32 = UTXO_MAX_HISTORY_DEPTH_VALUE;
#[cfg(any(test, feature = "runtime-benchmarks"))]
const PROTOCOL_PREFIX: [u8; 7] = [0x69, 0x64, 0x2b, 0x5b, 0xb6, 0x66, 0xac];
#[cfg(not(any(test, feature = "runtime-benchmarks")))]
const PROTOCOL_PREFIX: [u8; 7] = [0x47, 0x48, 0x53, 0x54, 0x74, 0x6F, 0x3A];
pub enum WeavingOk<NetworkId> { pub enum WeavingOk<NetworkId> {
Block(ExternalBlockNumber, NetworkId), Block(ExternalBlockNumber, NetworkId),
Hash(ExternalBlockNumber, H256, WeavingSession, NetworkId), Hash(ExternalBlockNumber, H256, WeavingSession, NetworkId),
@ -277,51 +272,75 @@ where
} }
} }
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct ThreadPayload<Balance: UniqueSaturatedInto<u128>> {
proof_index: ThreadId,
amount: Balance,
receiver: AccountId32,
}
impl<Balance> ThreadPayload<Balance>
where
Balance: UniqueSaturatedInto<u128>,
{
pub fn new(proof_index: ThreadId, amount: Balance, receiver: AccountId32) -> Self {
Self {
proof_index,
amount,
receiver,
}
}
}
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub enum ThreadProof<Balance: UniqueSaturatedInto<u128>> { pub enum ThreadProof<Balance: UniqueSaturatedInto<u128>> {
EvmThreadProof(EvmThreadProof<Balance>), EvmThreadProof(EvmThreadProof<Balance>),
UtxoThreadProof(UtxoThreadProof), UtxoThreadProof(UtxoThreadProof<Balance>),
} }
impl<Balance> ThreadProof<Balance> impl<Balance> ThreadProof<Balance>
where where
Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>, Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>,
u64: UniqueSaturatedInto<Balance>,
{ {
pub fn verify_thread_proof<NetworkId>( pub fn is_evm_proof_correct(&self) -> bool {
&self,
root_hash: H256,
network_id: NetworkId,
gatekeeper: &[u8]
) -> Option<(AccountId32, Balance)>
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
match self { match self {
Self::UtxoThreadProof(utxo_thread) => { Self::EvmThreadProof(_) => true,
utxo_thread.verify_thread_proof(root_hash, gatekeeper) Self::UtxoThreadProof(_) => false,
},
Self::EvmThreadProof(evm_thread) => {
evm_thread.verify_thread_proof(root_hash, network_id)
},
} }
} }
pub fn get_unique_key<NetworkId>( pub fn is_utxo_proof_correct(&self) -> bool {
&self,
session: WeavingSession,
network_id: NetworkId,
) -> H256
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
match self { match self {
Self::EvmThreadProof(thread_info) => { Self::UtxoThreadProof(_) => true,
thread_info.get_unique_key(session, network_id) Self::EvmThreadProof(_) => false,
}, }
Self::UtxoThreadProof(utxo_thread) => { }
utxo_thread.get_unique_key(network_id)
}, pub fn amount(&self) -> Balance {
match self {
Self::UtxoThreadProof(utxo_thread) => utxo_thread.amount(),
Self::EvmThreadProof(evm_thread) => evm_thread.amount(),
}
}
pub fn proof_index(&self) -> ThreadId {
match self {
Self::UtxoThreadProof(utxo_thread) => utxo_thread.proof_index(),
Self::EvmThreadProof(evm_thread) => evm_thread.proof_index(),
}
}
pub fn verify_proof(&self, root_hash: H256, gatekeeper: &[u8]) -> Option<AccountId32> {
match self {
Self::UtxoThreadProof(utxo_thread) => utxo_thread.verify_proof(root_hash, gatekeeper),
Self::EvmThreadProof(evm_thread) => evm_thread.verify_proof(root_hash),
}
}
pub fn get_unique_key(&self, session: WeavingSession) -> H256 {
match self {
Self::EvmThreadProof(thread_info) => thread_info.get_unique_key(session),
Self::UtxoThreadProof(utxo_thread) => utxo_thread.get_unique_key(),
} }
} }
} }
@ -329,9 +348,7 @@ where
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct EvmThreadProof<Balance: UniqueSaturatedInto<u128>> { pub struct EvmThreadProof<Balance: UniqueSaturatedInto<u128>> {
slot_index: ThreadId, slot_index: ThreadId,
proof_index: ThreadId, payload: ThreadPayload<Balance>,
receiver: AccountId32,
amount: Balance,
proof: BoundedVec<H256, ConstU32<EVM_MERKLE_DEPTH>>, proof: BoundedVec<H256, ConstU32<EVM_MERKLE_DEPTH>>,
slots: BoundedVec<H256, ConstU32<EVM_VALUES_DEPTH>>, slots: BoundedVec<H256, ConstU32<EVM_VALUES_DEPTH>>,
} }
@ -340,112 +357,70 @@ impl<Balance> EvmThreadProof<Balance>
where where
Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>, Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>,
{ {
pub fn verify_thread_proof<NetworkId>( pub fn amount(&self) -> Balance {
&self, self.payload.amount.clone()
root_hash: H256, }
network_id: NetworkId, pub fn proof_index(&self) -> ThreadId {
) -> Option<(AccountId32, Balance)> self.payload.proof_index
where }
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{ pub fn verify_proof(&self, root_hash: H256) -> Option<AccountId32> {
if EVM_MERKLE_DEPTH as usize != self.proof.len() { return None; } if EVM_MERKLE_DEPTH as usize != self.proof.len() {
return None;
}
let proof_valid = verify_tree_proof::<SubstrateKeccakHasher, _>( let proof_valid = verify_tree_proof::<SubstrateKeccakHasher, _>(
&self.get_preimage_slice(network_id).to_fixed_bytes(), &self.get_preimage_slice().to_fixed_bytes(),
self.proof.as_ref(), self.proof.as_ref(),
root_hash, root_hash,
self.proof_index, self.payload.proof_index,
); );
if !proof_valid { return None; } if !proof_valid {
return None;
Some((self.receiver.clone(), self.amount))
}
fn get_preimage_slice<NetworkId>(&self, network_id: NetworkId) -> H256
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
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) {
Some(slot) => {
*slot = self.compute_arguments_hash(network_id);
cumulative_hash::<SubstrateKeccakHasher, _>(slot_values)
}
None => {
SubstrateKeccakHasher::empty()
}
} }
Some(self.payload.receiver.clone())
} }
pub fn get_unique_key<NetworkId>( fn get_preimage_slice(&self) -> H256 {
&self, let slot_index_usize: usize = self.slot_index.unique_saturated_into();
session: WeavingSession,
network_id: NetworkId,
) -> H256
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
let session_bytes = (session as u64).to_be_bytes();
let slot_index_bytes = (self.slot_index as u64).to_be_bytes();
let proof_index_bytes = (self.proof_index as u64).to_be_bytes();
let network_id_u64: u64 = network_id.unique_saturated_into(); (slot_index_usize < self.slots.len())
let network_id_bytes = network_id_u64.to_be_bytes(); .then(|| {
self.slots
.iter()
.enumerate()
.map(|(index, &preimage)| {
if index == slot_index_usize {
self.compute_arguments_hash()
} else {
preimage
}
})
.collect::<Vec<_>>()
})
.map(|slots| cumulative_hash::<SubstrateKeccakHasher, _>(slots))
.unwrap_or(SubstrateKeccakHasher::empty())
}
pub fn get_unique_key(&self, session: WeavingSession) -> H256 {
let session_bytes = (session as u64).to_be_bytes();
let slot_bytes = (self.slot_index as u64).to_be_bytes();
let proof_bytes = (self.payload.proof_index as u64).to_be_bytes();
let mut h1 = [0u8; 32]; h1[24..32].copy_from_slice(&session_bytes); let mut h1 = [0u8; 32]; h1[24..32].copy_from_slice(&session_bytes);
let mut h2 = [0u8; 32]; h2[24..32].copy_from_slice(&slot_index_bytes); let mut h2 = [0u8; 32]; h2[24..32].copy_from_slice(&slot_bytes);
let mut h3 = [0u8; 32]; h3[24..32].copy_from_slice(&proof_index_bytes); let mut h3 = [0u8; 32]; h3[24..32].copy_from_slice(&proof_bytes);
let mut h4 = [0u8; 32]; h4[24..32].copy_from_slice(&network_id_bytes);
let metadata: [H256; 4] = [ let metadata: [H256; 3] = [H256::from(h1), H256::from(h2), H256::from(h3)];
H256::from(h1),
H256::from(h2),
H256::from(h3),
H256::from(h4),
];
sequential_hash::<SubstrateBlake2Hasher, _>(metadata) sequential_hash::<SubstrateBlake2Hasher, _>(metadata)
} }
fn compute_arguments_hash<NetworkId>(&self, network_id: NetworkId) -> H256
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
let amount_u128: u128 = self.amount.unique_saturated_into();
let slot_index_u64: u64 = self.slot_index.unique_saturated_into();
let network_id_u64: u64 = network_id.unique_saturated_into();
let amount_u256 = U256::from(amount_u128);
let slot_index_u256 = U256::from(slot_index_u64);
let network_id_u256 = U256::from(network_id_u64);
let mut padded_amount = [0u8; 32];
amount_u256.to_big_endian(&mut padded_amount);
let mut padded_slot_index = [0u8; 32];
slot_index_u256.to_big_endian(&mut padded_slot_index);
let mut padded_network_id = [0u8; 32];
network_id_u256.to_big_endian(&mut padded_network_id);
let inputs: [&[u8]; 4] = [
padded_amount.as_ref(),
self.receiver.as_ref(),
padded_slot_index.as_ref(),
padded_network_id.as_ref(),
];
sequential_hash::<SubstrateKeccakHasher, _>(inputs)
}
pub fn new( pub fn new(
slot_index: ThreadId, slot_index: ThreadId,
proof_index: ThreadId, payload: ThreadPayload<Balance>,
receiver: AccountId32,
amount: Balance,
proof_vec: Vec<H256>, proof_vec: Vec<H256>,
slots_vec: Vec<H256>, slots_vec: Vec<H256>,
) -> Self { ) -> Self {
@ -457,17 +432,41 @@ where
Self { Self {
slot_index, slot_index,
proof_index, payload,
receiver,
amount,
proof, proof,
slots, slots,
} }
} }
fn compute_arguments_hash(&self) -> H256 {
let amount_u128: u128 = self.amount().unique_saturated_into();
let amount_u256 = U256::from(amount_u128);
let slot_index_u64: u64 = self.slot_index.unique_saturated_into();
let slot_index_u256 = U256::from(slot_index_u64);
let mut padded_amount = [0u8; 32];
amount_u256.to_big_endian(&mut padded_amount);
let mut padded_slot_index = [0u8; 32];
slot_index_u256.to_big_endian(&mut padded_slot_index);
let inputs: [&[u8]; 3] = [
padded_amount.as_ref(),
self.payload.receiver.as_ref(),
padded_slot_index.as_ref(),
];
sequential_hash::<SubstrateKeccakHasher, _>(inputs)
}
} }
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct UtxoThreadProof { pub struct UtxoThreadProof<Balance: UniqueSaturatedInto<u128>> {
o_index: ThreadId,
w_index: ThreadId,
expected_amount: Balance,
payload: ThreadPayload<Balance>,
gettxproof_bytes: BoundedVec<u8, ConstU32<UTXO_MAX_PROOF_BYTES>>, gettxproof_bytes: BoundedVec<u8, ConstU32<UTXO_MAX_PROOF_BYTES>>,
getrawtransaction_bytes: BoundedVec<u8, ConstU32<UTXO_MAX_TX_BYTES>>, getrawtransaction_bytes: BoundedVec<u8, ConstU32<UTXO_MAX_TX_BYTES>>,
ancestry_headers: BoundedVec< ancestry_headers: BoundedVec<
@ -476,20 +475,24 @@ pub struct UtxoThreadProof {
>, >,
} }
impl UtxoThreadProof { impl<Balance> UtxoThreadProof<Balance>
where
Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>,
{
pub fn ancestry_headers_len(&self) -> u32 { pub fn ancestry_headers_len(&self) -> u32 {
self.ancestry_headers.len() as u32 self.ancestry_headers.len() as u32
} }
pub fn amount(&self) -> Balance {
self.expected_amount
}
pub fn receiver(&self) -> AccountId32 {
self.payload.receiver.clone()
}
pub fn proof_index(&self) -> ThreadId {
self.payload.proof_index
}
pub fn verify_thread_proof<Balance>( pub fn verify_proof(&self, root_hash: H256, gatekeeper_ref: &[u8]) -> Option<AccountId32> {
&self,
root_hash: H256,
gatekeeper_ref: &[u8],
) -> Option<(AccountId32, Balance)>
where
Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>,
u64: UniqueSaturatedInto<Balance>,
{
use ghost_helpers::utxo::{Header, Transaction}; use ghost_helpers::utxo::{Header, Transaction};
if self.gettxproof_bytes.len() < 85 { return None; } if self.gettxproof_bytes.len() < 85 { return None; }
@ -503,47 +506,48 @@ impl UtxoThreadProof {
if !is_chain_valid { return None; } if !is_chain_valid { return None; }
let transaction = Transaction::<UtxoSha2Hasher>::try_from( let transaction =
self.getrawtransaction_bytes.as_ref() Transaction::<UtxoSha2Hasher>::try_from(self.getrawtransaction_bytes.as_ref()).ok()?;
).ok()?; let header = Header::<UtxoSha2Hasher>::try_from(self.gettxproof_bytes.as_ref()).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()?; let root_hash = header.extract_proof(txid_preimage).ok()?;
if root_hash != header.merkle_root { return None; }
#[cfg(not(any(test, feature = "runtime-benchmarks")))] if root_hash != header.merkle_root {
let destination_script = Transaction::<UtxoSha2Hasher>::convert_into_p2tr(gatekeeper_ref)?; return None;
#[cfg(any(test, feature = "runtime-benchmarks"))] }
let destination_script = Transaction::<UtxoSha2Hasher>::convert_into_p2pkh(gatekeeper_ref)?;
transaction.parse_receiver_and_amount(&destination_script, &PROTOCOL_PREFIX) let account_id_bytes = transaction.validate(
.map(|(receiver, amount)| ( self.o_index,
AccountId32::new(receiver), self.w_index,
amount.unique_saturated_into(), gatekeeper_ref,
)) self.expected_amount,
)?;
Some(AccountId32::new(account_id_bytes))
} }
pub fn get_unique_key<NetworkId>(&self, network_id: NetworkId) -> H256 pub fn get_unique_key(&self) -> H256 {
where let o_index_bytes = (self.o_index as u64).to_be_bytes();
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>, let mut o_index_raw = [0u8; 32];
{ o_index_raw[24..32].copy_from_slice(&o_index_bytes);
let network_id_u64: u64 = network_id.unique_saturated_into();
let network_id_bytes = network_id_u64.to_be_bytes();
let o_index_hash = H256::from(o_index_raw);
let metadata: &[&[u8]] = &[ let metadata: &[&[u8]] = &[
self.gettxproof_bytes.as_ref(), self.gettxproof_bytes.as_ref(),
self.getrawtransaction_bytes.as_ref(), self.getrawtransaction_bytes.as_ref(),
network_id_bytes.as_ref(), o_index_hash.as_ref(),
]; ];
sequential_hash::<SubstrateBlake2Hasher, _>(metadata) sequential_hash::<SubstrateBlake2Hasher, _>(metadata)
} }
pub fn new( pub fn new(
o_index: ThreadId,
w_index: ThreadId,
expected_amount: Balance,
payload: ThreadPayload<Balance>,
gettxproof_vec: Vec<u8>, gettxproof_vec: Vec<u8>,
getrawtransaction_vec: Vec<u8>, getrawtransaction_vec: Vec<u8>,
ancestry_headers_vec: Vec<Vec<u8>>, ancestry_headers_vec: Vec<Vec<u8>>,
@ -567,12 +571,17 @@ impl UtxoThreadProof {
let ancestry_headers = BoundedVec::< let ancestry_headers = BoundedVec::<
BoundedVec<u8, ConstU32<UTXO_MAX_HEADER_BYTES>>, BoundedVec<u8, ConstU32<UTXO_MAX_HEADER_BYTES>>,
ConstU32<UTXO_MAX_HISTORY_DEPTH>, ConstU32<UTXO_MAX_HISTORY_DEPTH>,
>::try_from(inner_bounded_headers).expect("Should be valud UTXO headers"); >::try_from(inner_bounded_headers)
.expect("Should be valud UTXO headers");
Self { Self {
o_index,
w_index,
expected_amount,
gettxproof_bytes, gettxproof_bytes,
getrawtransaction_bytes, getrawtransaction_bytes,
ancestry_headers, ancestry_headers,
payload,
} }
} }
} }

View File

@ -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-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2026-09-05, 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
@ -69,11 +69,11 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `223 + a * (32 ±0)` // Measured: `223 + a * (32 ±0)`
// Estimated: `3687 + a * (32 ±0)` // Estimated: `3687 + a * (32 ±0)`
// Minimum execution time: 211_189_000 picoseconds. // Minimum execution time: 209_842_000 picoseconds.
Weight::from_parts(215_074_977, 0) Weight::from_parts(214_884_530, 0)
.saturating_add(Weight::from_parts(0, 3687)) .saturating_add(Weight::from_parts(0, 3687))
// Standard Error: 1_505 // Standard Error: 1_520
.saturating_add(Weight::from_parts(46_499, 0).saturating_mul(a.into())) .saturating_add(Weight::from_parts(45_535, 0).saturating_mul(a.into()))
.saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().reads(5))
.saturating_add(RocksDbWeight::get().writes(1)) .saturating_add(RocksDbWeight::get().writes(1))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into())) .saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
@ -95,11 +95,11 @@ impl WeightInfo for () {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `518 + a * (32 ±0)` // Measured: `518 + a * (32 ±0)`
// Estimated: `3982 + a * (32 ±0)` // Estimated: `3982 + a * (32 ±0)`
// Minimum execution time: 241_010_000 picoseconds. // Minimum execution time: 241_362_000 picoseconds.
Weight::from_parts(245_378_305, 0) Weight::from_parts(244_695_658, 0)
.saturating_add(Weight::from_parts(0, 3982)) .saturating_add(Weight::from_parts(0, 3982))
// Standard Error: 1_583 // Standard Error: 1_644
.saturating_add(Weight::from_parts(32_330, 0).saturating_mul(a.into())) .saturating_add(Weight::from_parts(30_947, 0).saturating_mul(a.into()))
.saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().reads(6))
.saturating_add(RocksDbWeight::get().writes(2)) .saturating_add(RocksDbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into())) .saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
@ -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: `346` // Measured: `358`
// Estimated: `3811` // Estimated: `3823`
// Minimum execution time: 170_701_000 picoseconds. // Minimum execution time: 174_434_000 picoseconds.
Weight::from_parts(170_150_850, 0) Weight::from_parts(173_218_259, 0)
// Standard Error: 4_368 // Standard Error: 4_108
.saturating_add(Weight::from_parts(3_363_930, 0).saturating_mul(a.into())) .saturating_add(Weight::from_parts(3_390_809, 0).saturating_mul(a.into()))
.saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().reads(6))
.saturating_add(RocksDbWeight::get().writes(3)) .saturating_add(RocksDbWeight::get().writes(3))
} }
@ -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: `3446` // Measured: `358`
// Estimated: `3811` // Estimated: `3823`
// Minimum execution time: 138_215_000 picoseconds. // Minimum execution time: 131_682_000 picoseconds.
Weight::from_parts(140_004_000, 0) Weight::from_parts(132_731_000, 0)
.saturating_add(Weight::from_parts(0, 3811)) .saturating_add(Weight::from_parts(0, 3823))
.saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().reads(6))
.saturating_add(RocksDbWeight::get().writes(3)) .saturating_add(RocksDbWeight::get().writes(3))
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "casper-runtime" name = "casper-runtime"
version = "4.0.11" version = "4.0.6"
build = "build.rs" build = "build.rs"
description = "Runtime of the Casper Network" description = "Runtime of the Casper Network"
edition.workspace = true edition.workspace = true

View File

@ -11,7 +11,7 @@ use grandpa_primitives::AuthorityId as GrandpaId;
use hex_literal::hex; use hex_literal::hex;
use sp_core::crypto::UncheckedFrom; use sp_core::crypto::UncheckedFrom;
use sp_core::{sr25519, H256, Pair, Public}; use sp_core::{sr25519, Pair, Public};
use sp_runtime::{traits::IdentifyAccount, Perbill}; use sp_runtime::{traits::IdentifyAccount, Perbill};
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
use sp_std::alloc::format; use sp_std::alloc::format;
@ -22,7 +22,7 @@ use crate::{Balance, NetworkId};
use ghost_weaver::sr25519::AuthorityId as WeaverId; use ghost_weaver::sr25519::AuthorityId as WeaverId;
use ghost_exodus::sr25519::AuthorityId as ExodusId; use ghost_exodus::sr25519::AuthorityId as ExodusId;
use ghost_helpers::networks::{NetworkClaim, NetworkClaimBuilder, NetworkInitiation}; use ghost_helpers::networks::{NetworkClaim, NetworkInitiation};
#[derive(Clone)] #[derive(Clone)]
pub struct AuthorityInitiation { pub struct AuthorityInitiation {
@ -187,29 +187,7 @@ fn casper_staging_initial_authorities() -> Vec<AuthorityInitiation> {
.with_weaver_id(WeaverId::unchecked_from(hex!("681cbbab1f95d0ee4183a8c60081380b59920e1a9189d872c8fc8b38dcdd020b"))) .with_weaver_id(WeaverId::unchecked_from(hex!("681cbbab1f95d0ee4183a8c60081380b59920e1a9189d872c8fc8b38dcdd020b")))
.with_exodus_id(ExodusId::unchecked_from(hex!("7277c176a3eb110ea2e259d09994c1bce303ca028b8daccc5b10d8d8f1baea40"))) .with_exodus_id(ExodusId::unchecked_from(hex!("7277c176a3eb110ea2e259d09994c1bce303ca028b8daccc5b10d8d8f1baea40")))
.build(), .build(),
// sfHcJxw5cgkvukZZyxcNUMCdbm9e7773orByLrGgAREka81TK
AuthorityInitiationBuilder::default()
.with_stash(AccountId::new(hex!("8a0d0b66e827bf20e79f9a499317e73925ce4f422371067edfab690e43857f13")))
.with_account(AccountId::new(hex!("ac871e8bab00dd56ba3a1c0bd289357203dcaf10010b0b04ad7472870cd22a3c")))
.with_babe_id(BabeId::unchecked_from(hex!("e0f0a776ecc9fa5e1f22e2fa001fe3fba5aea52b9444bc894b45589d42132475")))
.with_grandpa_id(GrandpaId::unchecked_from(hex!("b63c5a0cf342b9b04931bc8ed74d7d0165ab99ab5f8a4514797d4b299a4501fe")))
.with_authority_id(AuthorityDiscoveryId::unchecked_from(hex!("2cf69452e9f2a8457119139408884941ed50f590c0fc0f2b044c4d82c69e4245")))
.with_weaver_id(WeaverId::unchecked_from(hex!("22bc96d10ca7c04ba72a649db6b4c8f499744bb718d67b6fb7694f4bc2b46010")))
.with_exodus_id(ExodusId::unchecked_from(hex!("c20f8dbc1f86ae1520e6f9dc65239ec7e1e1e80eea7b5c1de2035a684e25ea48")))
.build(),
// sfFD7KSRi2aSREJWc9X75sVTN4a5pbPM5VSSJefmPvMuiVbPr
AuthorityInitiationBuilder::default()
.with_stash(AccountId::new(hex!("6c0283f4c688f0e75ad546c790bbd5961c1a6931543aa589f368f8272c44b758")))
.with_account(AccountId::new(hex!("425ccd7bda4f5c76788ba23bc0381d7a2e496179c93301208c57501c80a4232a")))
.with_babe_id(BabeId::unchecked_from(hex!("74fa7381a7a74b316afb6793a00387eed9d95d46a69866cbb316b5d9c918af0e")))
.with_grandpa_id(GrandpaId::unchecked_from(hex!("236d2fa03f4ed8cb65de7e514d7540159b328f1c170dd402b094ad7fbf547218")))
.with_authority_id(AuthorityDiscoveryId::unchecked_from(hex!("00946618c353e4c6546b87f9ca1089b846b0ea4658ee8e6d9d1200c24cb5ee27")))
.with_weaver_id(WeaverId::unchecked_from(hex!("10ab42a4a2e41d7921ded8138f406b15a61cf98147c43f9cdd5dd0b4e854ca0f")))
.with_exodus_id(ExodusId::unchecked_from(hex!("76aba3841978e8a4c5f22172c0cd0c34bedee4ebfcc8d93e1e44201ee013081b")))
.build(),
// sfH29zyFYtoFj6fSXskAEXG5XyyMCa5YycahJkYMwSUz8CcEU // sfH29zyFYtoFj6fSXskAEXG5XyyMCa5YycahJkYMwSUz8CcEU
AuthorityInitiationBuilder::default() AuthorityInitiationBuilder::default()
.with_stash(AccountId::new(hex!("b24feb55b2cac4b365a9245c2a97525b01bd1a594d2d42b91f6bc38c9c2e6517"))) .with_stash(AccountId::new(hex!("b24feb55b2cac4b365a9245c2a97525b01bd1a594d2d42b91f6bc38c9c2e6517")))
@ -220,17 +198,6 @@ fn casper_staging_initial_authorities() -> Vec<AuthorityInitiation> {
.with_weaver_id(WeaverId::unchecked_from(hex!("78efbd73e499bea76bf9bab1cb136fbe51aee389b1a8d151496e30bd55888429"))) .with_weaver_id(WeaverId::unchecked_from(hex!("78efbd73e499bea76bf9bab1cb136fbe51aee389b1a8d151496e30bd55888429")))
.with_exodus_id(ExodusId::unchecked_from(hex!("b469187ddf8f7458d67262328e236a252bd2db9e2f87e8313e7e3b322aecdc3e"))) .with_exodus_id(ExodusId::unchecked_from(hex!("b469187ddf8f7458d67262328e236a252bd2db9e2f87e8313e7e3b322aecdc3e")))
.build(), .build(),
// sfEwRjyvEQcpRQ1qbCZum27nEkTggKEt7DtqxwyYQULt9UuUN
AuthorityInitiationBuilder::default()
.with_stash(AccountId::new(hex!("a0ba0196e6ee7e6b5b0553035c5cb5c04e9725001b5732839d0529cbc00c9600")))
.with_account(AccountId::new(hex!("3666e4e19f87bb8680495f31864ce1f1c69d4178002cc01911aef2cc7313f203")))
.with_babe_id(BabeId::unchecked_from(hex!("6c4dd88b43e2011cf9a6a73d53446336ac9e04cdd4ca23587df63187ac455e49")))
.with_grandpa_id(GrandpaId::unchecked_from(hex!("8f9ea20bf4a807a8e710f7559dece86e94672b5b361de157bdaa5c1f37849f8d")))
.with_authority_id(AuthorityDiscoveryId::unchecked_from(hex!("90db5ed339a559ed157995a48d781f44c7df972dfba4bc855e4b59fa46438e17")))
.with_weaver_id(WeaverId::unchecked_from(hex!("5e7fdff77b38a07fad6dbc1cbfed9bb08b0c670459e6d4962f37c46a145f2214")))
.with_exodus_id(ExodusId::unchecked_from(hex!("bcb1948a376a30a92bc6ecce17d95185775b51a655dc1d4d393ed5c26b8b201e")))
.build(),
] ]
} }
@ -244,8 +211,8 @@ pub fn testnet_config_genesis(
initial_networks: Vec<NetworkInitiation<NetworkId, Balance>>, initial_networks: Vec<NetworkInitiation<NetworkId, Balance>>,
initial_claims: Vec<NetworkClaim<NetworkId, Balance>>, initial_claims: Vec<NetworkClaim<NetworkId, Balance>>,
) -> serde_json::Value { ) -> serde_json::Value {
const ENDOWMENT: u128 = 34 * CSPR; const ENDOWMENT: u128 = 31 * CSPR;
const STASH_BOND: u128 = 34 * CSPR; const STASH_BOND: u128 = 68 * CSPR;
const STASH_FEES: u128 = 1 * CSPR; const STASH_FEES: u128 = 1 * CSPR;
let sudo = initial_authorities.first().map(|x| x.account.clone()).unwrap(); let sudo = initial_authorities.first().map(|x| x.account.clone()).unwrap();
@ -295,7 +262,7 @@ pub fn testnet_config_genesis(
"babe": { "epochConfig": Some(crate::BABE_GENESIS_EPOCH_CONFIG) }, "babe": { "epochConfig": Some(crate::BABE_GENESIS_EPOCH_CONFIG) },
"ghostNominationPools": { "ghostNominationPools": {
"minJoinBond": 10 * STNK, "minJoinBond": 10 * STNK,
"minCreateBond": 42 * CSPR, "minCreateBond": 50 * CSPR,
"maxPools": 256u32, "maxPools": 256u32,
"maxMembersPerPool": 1024u32, "maxMembersPerPool": 1024u32,
"maxMembers": 20000u32, "maxMembers": 20000u32,
@ -347,27 +314,11 @@ pub fn casper_local_config_genesis() -> serde_json::Value {
} }
pub fn casper_staging_config_genesis() -> serde_json::Value { pub fn casper_staging_config_genesis() -> serde_json::Value {
let initial_preclaims = vec![
NetworkClaimBuilder::default()
.with_amount(1922500000000000000000u128.into())
.with_network_id(11155111)
.with_merkle_root(H256::from_slice(&hex!("f8d8c981f214958cc2738bf068807c0f504f0e9a1d61ba5c8cd01bc7f9cc6d26")))
.with_proof_size(8)
.build(),
NetworkClaimBuilder::default()
.with_amount(18550200000000000000000u128.into())
.with_network_id(7001)
.with_merkle_root(H256::from_slice(&hex!("793b300540c6530c24be7cc40b1ba91f0a586da8e180b98e91b055a9a12f45e2")))
.with_proof_size(11)
.build(),
];
testnet_config_genesis( testnet_config_genesis(
casper_staging_initial_authorities(), casper_staging_initial_authorities(),
Default::default(), Default::default(),
casper_testnet_networks(), casper_testnet_networks(),
initial_preclaims, Default::default(),
) )
} }

View File

@ -123,8 +123,8 @@ 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: 6,
impl_version: 0, impl_version: 4,
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
transaction_version: 1, transaction_version: 1,
state_version: 1, state_version: 1,

View File

@ -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-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2026-09-05, 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
@ -60,8 +60,8 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `351` // Measured: `351`
// Estimated: `3816` // Estimated: `3816`
// Minimum execution time: 239_012_000 picoseconds. // Minimum execution time: 239_348_000 picoseconds.
Weight::from_parts(241_388_000, 0) Weight::from_parts(241_125_000, 0)
.saturating_add(Weight::from_parts(0, 3816)) .saturating_add(Weight::from_parts(0, 3816))
.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(3))
@ -83,11 +83,11 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `391 + c * (32 ±0)` // Measured: `391 + c * (32 ±0)`
// Estimated: `3856 + c * (32 ±0)` // Estimated: `3856 + c * (32 ±0)`
// Minimum execution time: 1_339_828_000 picoseconds. // Minimum execution time: 1_372_279_000 picoseconds.
Weight::from_parts(1_212_625_790, 0) Weight::from_parts(1_268_130_469, 0)
.saturating_add(Weight::from_parts(0, 3856)) .saturating_add(Weight::from_parts(0, 3856))
// Standard Error: 11_831 // Standard Error: 17_178
.saturating_add(Weight::from_parts(33_120_868, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(32_976_202, 0).saturating_mul(c.into()))
.saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
@ -107,11 +107,11 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `317 + c * (257 ±0)` // Measured: `317 + c * (257 ±0)`
// Estimated: `3783 + c * (257 ±0)` // Estimated: `3783 + c * (257 ±0)`
// Minimum execution time: 251_478_000 picoseconds. // Minimum execution time: 253_301_000 picoseconds.
Weight::from_parts(254_144_621, 0) Weight::from_parts(255_449_282, 0)
.saturating_add(Weight::from_parts(0, 3783)) .saturating_add(Weight::from_parts(0, 3783))
// Standard Error: 24_613 // Standard Error: 25_029
.saturating_add(Weight::from_parts(6_595_819, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(6_615_251, 0).saturating_mul(c.into()))
.saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
@ -131,11 +131,11 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `317 + c * (257 ±0)` // Measured: `317 + c * (257 ±0)`
// Estimated: `3783 + c * (257 ±0)` // Estimated: `3783 + c * (257 ±0)`
// Minimum execution time: 236_155_000 picoseconds. // Minimum execution time: 238_882_000 picoseconds.
Weight::from_parts(242_055_898, 0) Weight::from_parts(242_930_556, 0)
.saturating_add(Weight::from_parts(0, 3783)) .saturating_add(Weight::from_parts(0, 3783))
// Standard Error: 15_623 // Standard Error: 13_070
.saturating_add(Weight::from_parts(360_411, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(426_492, 0).saturating_mul(c.into()))
.saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
@ -155,11 +155,11 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `317 + c * (257 ±0)` // Measured: `317 + c * (257 ±0)`
// Estimated: `3783 + c * (257 ±0)` // Estimated: `3783 + c * (257 ±0)`
// Minimum execution time: 249_507_000 picoseconds. // Minimum execution time: 250_894_000 picoseconds.
Weight::from_parts(248_505_595, 0) Weight::from_parts(252_272_982, 0)
.saturating_add(Weight::from_parts(0, 3783)) .saturating_add(Weight::from_parts(0, 3783))
// Standard Error: 20_302 // Standard Error: 17_703
.saturating_add(Weight::from_parts(4_191_526, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(4_110_522, 0).saturating_mul(c.into()))
.saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 257).saturating_mul(c.into()))
@ -180,8 +180,8 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `448` // Measured: `448`
// Estimated: `3913` // Estimated: `3913`
// Minimum execution time: 264_214_000 picoseconds. // Minimum execution time: 265_392_000 picoseconds.
Weight::from_parts(266_905_000, 0) Weight::from_parts(268_799_000, 0)
.saturating_add(Weight::from_parts(0, 3913)) .saturating_add(Weight::from_parts(0, 3913))
.saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes(3))
@ -205,11 +205,11 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// 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: `1551 + c * (1019 ±27)`
// Minimum execution time: 281_073_000 picoseconds. // Minimum execution time: 282_654_000 picoseconds.
Weight::from_parts(280_778_987, 0) Weight::from_parts(286_257_905, 0)
.saturating_add(Weight::from_parts(0, 1551)) .saturating_add(Weight::from_parts(0, 1551))
// Standard Error: 79_426 // Standard Error: 92_951
.saturating_add(Weight::from_parts(3_449_552, 0).saturating_mul(c.into())) .saturating_add(Weight::from_parts(2_838_516, 0).saturating_mul(c.into()))
.saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().reads(7))
.saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes(3))
.saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 1019).saturating_mul(c.into()))
@ -236,8 +236,8 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `588` // Measured: `588`
// Estimated: `4053` // Estimated: `4053`
// Minimum execution time: 291_972_000 picoseconds. // Minimum execution time: 296_169_000 picoseconds.
Weight::from_parts(295_122_000, 0) Weight::from_parts(298_267_000, 0)
.saturating_add(Weight::from_parts(0, 4053)) .saturating_add(Weight::from_parts(0, 4053))
.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(5))
@ -266,8 +266,8 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `968` // Measured: `968`
// Estimated: `4433` // Estimated: `4433`
// Minimum execution time: 331_528_000 picoseconds. // Minimum execution time: 332_972_000 picoseconds.
Weight::from_parts(333_974_000, 0) Weight::from_parts(336_569_000, 0)
.saturating_add(Weight::from_parts(0, 4433)) .saturating_add(Weight::from_parts(0, 4433))
.saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().reads(10))
.saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes(4))
@ -306,8 +306,8 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `11259` // Measured: `11259`
// Estimated: `14724` // Estimated: `14724`
// Minimum execution time: 3_980_585_000 picoseconds. // Minimum execution time: 3_842_259_000 picoseconds.
Weight::from_parts(3_985_167_000, 0) Weight::from_parts(3_853_670_000, 0)
.saturating_add(Weight::from_parts(0, 14724)) .saturating_add(Weight::from_parts(0, 14724))
.saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().reads(14))
.saturating_add(T::DbWeight::get().writes(8)) .saturating_add(T::DbWeight::get().writes(8))
@ -326,11 +326,11 @@ impl<T: frame_system::Config> ghost_exodus::WeightInfo for WeightInfo<T> {
/// 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: `447`
// Estimated: `3913` // Estimated: `3912`
// Minimum execution time: 137_053_000 picoseconds. // Minimum execution time: 138_303_000 picoseconds.
Weight::from_parts(138_693_000, 0) Weight::from_parts(139_968_000, 0)
.saturating_add(Weight::from_parts(0, 3913)) .saturating_add(Weight::from_parts(0, 3912))
.saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes(4))
} }

View File

@ -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-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2026-09-05, 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
@ -59,11 +59,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: 214_208_000 picoseconds. // Minimum execution time: 216_605_000 picoseconds.
Weight::from_parts(216_987_870, 0) Weight::from_parts(217_612_486, 0)
.saturating_add(Weight::from_parts(0, 3748)) .saturating_add(Weight::from_parts(0, 3748))
// Standard Error: 30_856 // Standard Error: 23_409
.saturating_add(Weight::from_parts(1_702_104, 0).saturating_mul(p.into())) .saturating_add(Weight::from_parts(1_544_250, 0).saturating_mul(p.into()))
.saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes(4))
} }

View File

@ -16,7 +16,7 @@
//! Autogenerated weights for `ghost_networks` //! Autogenerated weights for `ghost_networks`
//! //!
//! 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-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2026-09-02, 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,15 +61,15 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `6` // Measured: `6`
// Estimated: `3471` // Estimated: `3471`
// Minimum execution time: 57_039_000 picoseconds. // Minimum execution time: 60_167_000 picoseconds.
Weight::from_parts(53_368_140, 0) Weight::from_parts(56_015_384, 0)
.saturating_add(Weight::from_parts(0, 3471)) .saturating_add(Weight::from_parts(0, 3471))
// Standard Error: 874 // Standard Error: 1_219
.saturating_add(Weight::from_parts(8_884, 0).saturating_mul(i.into())) .saturating_add(Weight::from_parts(6_146, 0).saturating_mul(i.into()))
// Standard Error: 442 // Standard Error: 617
.saturating_add(Weight::from_parts(32_778, 0).saturating_mul(j.into())) .saturating_add(Weight::from_parts(37_564, 0).saturating_mul(j.into()))
// Standard Error: 5_890 // Standard Error: 8_216
.saturating_add(Weight::from_parts(833_630, 0).saturating_mul(k.into())) .saturating_add(Weight::from_parts(864_641, 0).saturating_mul(k.into()))
.saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes(4))
} }
@ -77,11 +77,11 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_selector() -> Weight { fn update_network_selector() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 42_680_000 picoseconds. // Minimum execution time: 43_957_000 picoseconds.
Weight::from_parts(43_454_000, 0) Weight::from_parts(44_541_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@ -90,13 +90,13 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// The range of component `n` is `[1, 128]`. /// The range of component `n` is `[1, 128]`.
fn update_network_endpoint(n: u32, ) -> Weight { fn update_network_endpoint(n: u32, ) -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 42_265_000 picoseconds. // Minimum execution time: 44_092_000 picoseconds.
Weight::from_parts(43_357_887, 0) Weight::from_parts(45_181_439, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
// Standard Error: 457 // Standard Error: 402
.saturating_add(Weight::from_parts(13_745, 0).saturating_mul(n.into())) .saturating_add(Weight::from_parts(16_387, 0).saturating_mul(n.into()))
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@ -104,11 +104,11 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_finality_delay() -> Weight { fn update_network_finality_delay() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 43_008_000 picoseconds. // Minimum execution time: 45_603_000 picoseconds.
Weight::from_parts(43_917_000, 0) Weight::from_parts(46_116_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@ -116,11 +116,11 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_rate_limit_delay() -> Weight { fn update_network_rate_limit_delay() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 43_104_000 picoseconds. // Minimum execution time: 45_607_000 picoseconds.
Weight::from_parts(43_981_000, 0) Weight::from_parts(46_615_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@ -128,11 +128,11 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_block_deviation() -> Weight { fn update_network_block_deviation() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 41_734_000 picoseconds. // Minimum execution time: 43_510_000 picoseconds.
Weight::from_parts(42_645_000, 0) Weight::from_parts(43_840_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@ -140,11 +140,11 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_type() -> Weight { fn update_network_type() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 42_080_000 picoseconds. // Minimum execution time: 43_737_000 picoseconds.
Weight::from_parts(42_404_000, 0) Weight::from_parts(44_347_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@ -156,35 +156,23 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn update_network_curve() -> Weight { fn update_network_curve() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `180` // Measured: `179`
// Estimated: `6120` // Estimated: `6119`
// Minimum execution time: 82_975_000 picoseconds. // Minimum execution time: 85_784_000 picoseconds.
Weight::from_parts(84_583_000, 0) Weight::from_parts(86_768_000, 0)
.saturating_add(Weight::from_parts(0, 6120)) .saturating_add(Weight::from_parts(0, 6119))
.saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes(4))
} }
/// Storage: `GhostNetworks::Networks` (r:1 w:1) /// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_decimals() -> Weight {
// Proof Size summary in bytes:
// Measured: `167`
// Estimated: `3632`
// Minimum execution time: 41_602_000 picoseconds.
Weight::from_parts(42_603_000, 0)
.saturating_add(Weight::from_parts(0, 3632))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_gatekeeper() -> Weight { fn update_network_gatekeeper() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 42_643_000 picoseconds. // Minimum execution time: 44_801_000 picoseconds.
Weight::from_parts(43_190_000, 0) Weight::from_parts(45_240_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@ -192,11 +180,11 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_incoming_network_share() -> Weight { fn update_incoming_network_share() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 42_978_000 picoseconds. // Minimum execution time: 45_404_000 picoseconds.
Weight::from_parts(44_002_000, 0) Weight::from_parts(46_161_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@ -204,11 +192,11 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_outgoing_network_share() -> Weight { fn update_outgoing_network_share() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `167` // Measured: `166`
// Estimated: `3632` // Estimated: `3631`
// Minimum execution time: 43_436_000 picoseconds. // Minimum execution time: 45_476_000 picoseconds.
Weight::from_parts(44_193_000, 0) Weight::from_parts(46_312_000, 0)
.saturating_add(Weight::from_parts(0, 3632)) .saturating_add(Weight::from_parts(0, 3631))
.saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
} }
@ -222,11 +210,11 @@ impl<T: frame_system::Config> ghost_networks::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn remove_network() -> Weight { fn remove_network() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `180` // Measured: `179`
// Estimated: `3645` // Estimated: `3644`
// Minimum execution time: 75_969_000 picoseconds. // Minimum execution time: 78_480_000 picoseconds.
Weight::from_parts(77_610_000, 0) Weight::from_parts(79_105_000, 0)
.saturating_add(Weight::from_parts(0, 3645)) .saturating_add(Weight::from_parts(0, 3644))
.saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes(4))
} }

View File

@ -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-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2026-09-05, 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_weaver::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `223 + a * (32 ±0)` // Measured: `223 + a * (32 ±0)`
// Estimated: `3687 + a * (32 ±0)` // Estimated: `3687 + a * (32 ±0)`
// Minimum execution time: 211_189_000 picoseconds. // Minimum execution time: 209_842_000 picoseconds.
Weight::from_parts(215_074_977, 0) Weight::from_parts(214_884_530, 0)
.saturating_add(Weight::from_parts(0, 3687)) .saturating_add(Weight::from_parts(0, 3687))
// Standard Error: 1_505 // Standard Error: 1_520
.saturating_add(Weight::from_parts(46_499, 0).saturating_mul(a.into())) .saturating_add(Weight::from_parts(45_535, 0).saturating_mul(a.into()))
.saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes(1))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into())) .saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
@ -87,11 +87,11 @@ impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `518 + a * (32 ±0)` // Measured: `518 + a * (32 ±0)`
// Estimated: `3982 + a * (32 ±0)` // Estimated: `3982 + a * (32 ±0)`
// Minimum execution time: 241_010_000 picoseconds. // Minimum execution time: 241_362_000 picoseconds.
Weight::from_parts(245_378_305, 0) Weight::from_parts(244_695_658, 0)
.saturating_add(Weight::from_parts(0, 3982)) .saturating_add(Weight::from_parts(0, 3982))
// Standard Error: 1_583 // Standard Error: 1_644
.saturating_add(Weight::from_parts(32_330, 0).saturating_mul(a.into())) .saturating_add(Weight::from_parts(30_947, 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(2)) .saturating_add(T::DbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into())) .saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
@ -111,13 +111,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: `346` // Measured: `358`
// Estimated: `3811` // Estimated: `3823`
// Minimum execution time: 170_701_000 picoseconds. // Minimum execution time: 174_434_000 picoseconds.
Weight::from_parts(170_150_850, 0) Weight::from_parts(173_218_259, 0)
.saturating_add(Weight::from_parts(0, 3811)) .saturating_add(Weight::from_parts(0, 3823))
// Standard Error: 4_368 // Standard Error: 4_108
.saturating_add(Weight::from_parts(3_363_930, 0).saturating_mul(a.into())) .saturating_add(Weight::from_parts(3_390_809, 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(3)) .saturating_add(T::DbWeight::get().writes(3))
} }
@ -135,11 +135,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: `346` // Measured: `358`
// Estimated: `3811` // Estimated: `3823`
// Minimum execution time: 138_215_000 picoseconds. // Minimum execution time: 131_682_000 picoseconds.
Weight::from_parts(140_004_000, 0) Weight::from_parts(132_731_000, 0)
.saturating_add(Weight::from_parts(0, 3811)) .saturating_add(Weight::from_parts(0, 3823))
.saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes(3))
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "runtime-common" name = "runtime-common"
version = "0.4.9" version = "0.4.8"
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
homepage.workspace = true homepage.workspace = true

View File

@ -30,14 +30,14 @@ pub use sp_runtime::BuildStorage;
pub use impls::ToAuthor; pub use impls::ToAuthor;
/// We assume that an on-initialize consumes 15% of the weight on average, hence /// We assume that an on-initialize consumes 10% of the weight on average, hence
/// a single extrinsic will not be allowed to consume more than /// a single extrinsic will not be allowed to consume more than
/// `AvailableBlockRatio - 15%`. /// `AvailableBlockRatio - 10%`.
pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(15); pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
/// We allow `Normal` extrinsics to fill up the block up to 70%, the rest can /// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can
/// be used by `Operational` extrinsics. /// be used by `Operational` extrinsics.
pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(70); pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
/// We allow for 4 seconds of compute with a 12 seconds average block time. /// We allow for 4 seconds of compute with a 12 seconds average block time.
/// The storage proof size is not limited so far. /// The storage proof size is not limited so far.

View File

@ -1,4 +0,0 @@
[toolchain]
channel = "1.93.1"
components = ["rustfmt", "clippy", "rust-src"]
targets = ["wasm32-unknown-unknown"]

View File

@ -17,21 +17,15 @@ MORDOR_RPC=(
"https://rpc.mordor.etccooperative.org" "https://rpc.mordor.etccooperative.org"
) )
HOODI_RPC=(
"https://rpc.hoodi.ethpandaops.io"
"https://0xrpc.io/hoodi"
"https://ethereum-hoodi.gateway.tatum.io"
"https://rpc.sentio.xyz/hoodi"
)
show_help() { show_help() {
cat << EOF cat << EOF
Usage: $(basename "$0") [OPTIONS] Usage: $(basename "$0") [OPTIONS]
Options: Options:
--chain <name> Specify network: 'sepolia', 'hoodi' or 'mordor'. If omitted, checks all. --chain <name> Specify network: 'sepolia' or 'mordor'. If omitted, checks both.
--output <dir> Base directory to save results. Creates a subfolder with Unix Timestamp. --output <dir> Base directory to save results. Creates a subfolder with Unix Timestamp.
--rpcs <urls> Comma-separated list of custom RPC endpoints. Disables default networks lists. --rpcs <urls> Comma-separated list of custom RPC endpoints.
Disables default Sepolia/Mordor lists.
--help Show this help message. --help Show this help message.
Example: Example:
@ -135,11 +129,8 @@ else
check_network "Sepolia" "${SEPOLIA_RPC[@]}" check_network "Sepolia" "${SEPOLIA_RPC[@]}"
elif [ "$CHOSEN_CHAIN" == "mordor" ]; then elif [ "$CHOSEN_CHAIN" == "mordor" ]; then
check_network "Mordor" "${MORDOR_RPC[@]}" check_network "Mordor" "${MORDOR_RPC[@]}"
elif [ "$CHOSEN_CHAIN" == "hoodi" ]; then
check_network "Hoodi" "${HOODI_RPC[@]}"
else else
check_network "Sepolia" "${SEPOLIA_RPC[@]}" check_network "Sepolia" "${SEPOLIA_RPC[@]}"
check_network "Mordor" "${MORDOR_RPC[@]}" check_network "Mordor" "${MORDOR_RPC[@]}"
check_network "Hoodi" "${HOODI_RPC[@]}"
fi fi
fi fi

View File

@ -85,16 +85,30 @@ extract_seed() {
echo $seed echo $seed
} }
apply_patches_if_needed() { upgrade_compiler_if_needed() {
local PATCH_STATUS=0 UPDATE_STATUS=$(rustup check 2>&1)
"$SCRIPT_FOLDER"/patch.sh || PATCH_STATUS=$? "$SCRIPT_FOLDER"/patch.sh || PATCH_STATUS=$?
if [ "$PATCH_STATUS" -eq 2 ]; then if echo "$UPDATE_STATUS" | grep -q "Update available" || [ $PATCH_STATUS -eq 2 ]; then
echo "[+] clean all cache on the current system" echo "[+] clean all cache on the current system"
cargo clean
cargo install cargo-cache cargo install cargo-cache
cargo clean
cargo cache --remove-dir all cargo cache --remove-dir all
echo "[+] upgrading rustc compiler version to latest"
rustup update
toolchain_name=$(rustup show | grep default | head -n 1 | cut -d' ' -f1)
if ! rustup target list --installed | grep -q "wasm32-unknown-unknown"; then
echo "[+] installing wasm32-unknown-unknown target"
rustup target add wasm32-unknown-unknown
fi
if ! rustup component list --installed | grep -q "rust-src"; then
echo "[+] installing rust-src component"
rustup component add rust-src
fi
echo "[+] fetching all dependencies" echo "[+] fetching all dependencies"
cargo fetch cargo fetch
@ -226,7 +240,7 @@ if [[ $HARD_RESET = true ]]; then
exit 1 exit 1
fi fi
apply_patches_if_needed upgrade_compiler_if_needed
echo "[+] trying to stop current ghost-node" echo "[+] trying to stop current ghost-node"
sudo systemctl stop ghost-node sudo systemctl stop ghost-node
@ -335,12 +349,12 @@ if [[ $SET_ENVIRONMENT = true ]]; then
if prompt "[?] setup the rust environment (e.g. WASM support)?"; then if prompt "[?] setup the rust environment (e.g. WASM support)?"; then
rustup default stable rustup default stable
apply_patches_if_needed upgrade_compiler_if_needed
fi fi
fi fi
if [[ ! -z $RELEASE ]]; then if [[ ! -z $RELEASE ]]; then
apply_patches_if_needed upgrade_compiler_if_needed
if prompt "[?] 'cargo build $RELEASE $FEATURES' is what you want?"; then if prompt "[?] 'cargo build $RELEASE $FEATURES' is what you want?"; then
cd $PROJECT_FOLDER cd $PROJECT_FOLDER
echo "[+] starting build in 3 seconds..." echo "[+] starting build in 3 seconds..."
@ -585,7 +599,7 @@ if [ "$GENERATE_GENESIS" = true ]; then
echo " - $WALLET_KEY_PATH" echo " - $WALLET_KEY_PATH"
echo " - $STASH_KEY_PATH" echo " - $STASH_KEY_PATH"
echo "" echo ""
echo "IMPORTANT: Create a pull request to include these keys in the upcoming genesis." echo "IMPORTANT: Create a pool request to include these keys in the upcoming genesis."
echo "DO NOT DELETE THESE KEYS OR THE GENESIS WILL BE INVALID!" echo "DO NOT DELETE THESE KEYS OR THE GENESIS WILL BE INVALID!"
echo "Submit a PR with these keys to: https://git.ghostchain.io/ghostchain/ghost-node" echo "Submit a PR with these keys to: https://git.ghostchain.io/ghostchain/ghost-node"
echo "" echo ""

File diff suppressed because one or more lines are too long