Compare commits

...

10 Commits

Author SHA1 Message Date
f2544e3876
make governance work over exodus
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:57:28 +03:00
2387a2fe32
make exodus to change gatekeeped amount after bridge out
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:56:24 +03:00
5243bd7c3d
apply benchmarked weights
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:45:44 +03:00
8ee32ff609
make benchmarking dependant on the actual data
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:42:28 +03:00
06af604cc8
apply benchmarked weight as default
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:41:03 +03:00
c4f22df03d
remove warnings from auto-generated code
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:38:22 +03:00
554bc4499f
fix governance benchmarking; make id dependant on the proof length
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:36:27 +03:00
c7637d8ce6
additional trait for the evm governance
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:34:33 +03:00
3b8030527b
make benchmarking flag available based on the feature flag
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:29:03 +03:00
4d836ee8ac
remove unused pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2026-09-05 23:27:58 +03:00
36 changed files with 1783 additions and 1427 deletions

16
Cargo.lock generated
View File

@ -3628,7 +3628,7 @@ dependencies = [
[[package]]
name = "ghost-cli"
version = "0.9.1"
version = "0.9.2"
dependencies = [
"cfg-if",
"clap 4.5.4",
@ -3684,7 +3684,7 @@ dependencies = [
[[package]]
name = "ghost-exodus"
version = "0.0.2"
version = "0.0.3"
dependencies = [
"chacha20poly1305",
"frame-benchmarking",
@ -3775,7 +3775,7 @@ dependencies = [
[[package]]
name = "ghost-machine-primitives"
version = "0.9.1"
version = "0.9.2"
dependencies = [
"lazy_static",
"sc-sysinfo",
@ -3784,7 +3784,7 @@ dependencies = [
[[package]]
name = "ghost-metrics"
version = "0.9.1"
version = "0.9.2"
dependencies = [
"assert_cmd",
"bs58 0.5.1",
@ -3862,7 +3862,7 @@ dependencies = [
[[package]]
name = "ghost-node"
version = "0.9.1"
version = "0.9.2"
dependencies = [
"assert_cmd",
"color-eyre",
@ -3945,7 +3945,7 @@ dependencies = [
[[package]]
name = "ghost-rpc"
version = "0.9.1"
version = "0.9.2"
dependencies = [
"ghost-core-primitives",
"jsonrpsee",
@ -3974,7 +3974,7 @@ dependencies = [
[[package]]
name = "ghost-service"
version = "0.9.1"
version = "0.9.2"
dependencies = [
"assert_matches",
"async-trait",
@ -4085,7 +4085,7 @@ dependencies = [
[[package]]
name = "ghost-traits"
version = "0.4.3"
version = "0.4.4"
dependencies = [
"frame-support",
"frost-core",

View File

@ -17,7 +17,7 @@ homepage.workspace = true
[workspace.package]
license = "GPL-3.0-only"
authors = ["571nky", "57r37ch", "f4750"]
version = "0.9.1"
version = "0.9.2"
edition = "2021"
homepage = "https://ghostchain.io"
repository = "https://git.ghostchain.io/ghostchain/ghost-node"

View File

@ -1,13 +1,8 @@
use crate::cli::{Cli, Subcommand};
use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory};
use futures::future::TryFutureExt;
use keyring::Sr25519Keyring;
use sc_cli::SubstrateCli;
use service::{
self,
benchmarking::{benchmark_inherent_data, RemarkBuilder, TransferKeepAliveBuilder},
IdentifyVariant,
};
use service::{self, IdentifyVariant};
pub use crate::{error::Error, service::BlockId};
#[cfg(feature = "pyroscope")]
@ -300,6 +295,8 @@ pub fn run() -> Result<()> {
}),
// These commands are very similar and can be handled in nearly the same way
BenchmarkCmd::Extrinsic(_) | BenchmarkCmd::Overhead(_) => {
use service::benchmarking::{benchmark_inherent_data, RemarkBuilder, TransferKeepAliveBuilder};
runner.sync_run(|mut config| {
let (client, _, _, _) = service::new_chain_ops(&mut config)?;
@ -313,7 +310,7 @@ pub fn run() -> Result<()> {
BenchmarkCmd::Extrinsic(cmd) => {
let tka_builder = TransferKeepAliveBuilder::new(
client.clone(),
Sr25519Keyring::Alice.to_account_id(),
keyring::Sr25519Keyring::Alice.to_account_id(),
config.chain_spec.identify_chain(),
);
@ -360,13 +357,6 @@ pub fn run() -> Result<()> {
_ => Err(Error::CommandNotImplemented),
}
}
#[cfg(not(feature = "runtime-benchmarks"))]
Some(Subcommand::Benchmark(_)) => {
return Err(sc_cli::Error::Input(
"Benchmarking wasn't enabled when building the node. \
You can enable it with `--features=runtime-benchmarks`.".into(),
).into())
},
Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
Some(Subcommand::ChainInfo(cmd)) => {
let runner = cli.create_runner(cmd)?;

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-exodus"
version = "0.0.2"
version = "0.0.5"
description = "Threshold signature generation with DKG included"
license.workspace = true
authors.workspace = true

View File

@ -472,6 +472,7 @@ mod benchmarks {
#[benchmark]
fn register_nonce_commitment() -> Result<(), BenchmarkError> {
let network_id: NetworkIdOf<T> = 69_420u64.unique_saturated_into();
let (mut dkg_state, network_curve, authority, authority_index) =
prepare_pallet::<T>(1);
@ -483,9 +484,22 @@ mod benchmarks {
dkg_state.insert_index(authority_index);
let exodus_session = CurrentExodus::<T>::get();
let dummy_bytes = EvmBytes32::repeat_byte(69);
let dummy_address = EvmAddress::repeat_byte(69);
let dummy_nonce = vec![0u8; network_curve.element_bytes_len()];
let request = ExodusRequest::evm_rotation(exodus_session, dummy_bytes, 0);
let create_bond = GovernanceAction::Create {
market: [69, 420, 1337],
terms: [420, 1337],
token: dummy_address,
intervals: [34, 35],
booleans: [true, true],
};
let request = ExodusRequest::<NetworkIdOf<T>, BalanceOf<T>>::evm_governance(
exodus_session,
network_id,
dummy_address,
create_bond,
);
let authorities = QualificationAuthorities::<T>::get(&network_curve);
let active_dkg: ActivatedState<T> = (&dkg_state).into();
@ -534,6 +548,7 @@ mod benchmarks {
#[benchmark]
fn register_group_commitment() -> Result<(), BenchmarkError> {
let network_id: NetworkIdOf<T> = 69_420u64.unique_saturated_into();
let (mut dkg_state, network_curve, authority, authority_index) =
prepare_pallet::<T>(1);
@ -546,9 +561,23 @@ mod benchmarks {
let exodus_session = CurrentExodus::<T>::get();
let dummy_bytes = EvmBytes32::repeat_byte(69);
let dummy_address = EvmAddress::repeat_byte(69);
let dummy_merkle_root = ExodusHash::repeat_byte(69);
let dummy_group_commitment = vec![0u8; network_curve.element_bytes_len()];
let request = ExodusRequest::evm_rotation(exodus_session, dummy_bytes, 0);
let create_bond = GovernanceAction::Create {
market: [69, 420, 1337],
terms: [420, 1337],
token: dummy_address,
intervals: [34, 35],
booleans: [true, true],
};
let request = ExodusRequest::<NetworkIdOf<T>, BalanceOf<T>>::evm_governance(
exodus_session,
network_id,
dummy_address,
create_bond,
);
let authorities = QualificationAuthorities::<T>::get(&network_curve);
let active_dkg: ActivatedState<T> = (&dkg_state).into();
@ -609,6 +638,7 @@ mod benchmarks {
fn register_signature_share() -> Result<(), BenchmarkError> {
let max_signers = T::MaxAuthorities::get();
let threshold = get_byzantium_threshold(max_signers);
let network_id: NetworkIdOf<T> = 69_420u64.unique_saturated_into();
let (mut dkg_state, network_curve, authority, authority_index) =
prepare_pallet::<T>(max_signers as usize);
@ -632,8 +662,20 @@ mod benchmarks {
];
dummy_element[1..33].copy_from_slice(&g_x_coords);
let dummy_bytes = EvmBytes32::repeat_byte(69);
let request = ExodusRequest::evm_rotation(exodus_session, dummy_bytes, 0);
let dummy_address = EvmAddress::repeat_byte(69);
let create_bond = GovernanceAction::Create {
market: [69, 420, 1337],
terms: [420, 1337],
token: dummy_address,
intervals: [34, 35],
booleans: [true, true],
};
let request = ExodusRequest::<NetworkIdOf<T>, BalanceOf<T>>::evm_governance(
exodus_session,
network_id,
dummy_address,
create_bond,
);
let mut dummy_scalar = vec![0u8; network_curve.scalar_bytes_len()];
dummy_scalar[network_curve.scalar_bytes_len() - 1] = 1;
@ -755,7 +797,7 @@ mod benchmarks {
assert!(!committers_exists);
assert!(!ExodusRequests::<T>::contains_key(&network_curve, &exodus_session));
assert!(ExodusSignedRotations::<T>::contains_key((&exodus_session, NetworkType::Evm), dkg_index));
assert!(ExodusSignedGovernance::<T>::contains_key((&exodus_session, network_id), dkg_index));
Ok(())
}

View File

@ -1,496 +0,0 @@
use crate::{EncryptedMessage, FrostError};
use ghost_networks::NetworkCurve;
use chacha20poly1305::{
aead::{self, Aead, AeadCore, KeyInit},
Key as EncryptionKey,
Nonce as EncryptionNonce,
ChaCha20Poly1305 as EncryptionCipher,
};
use hkdf::Hkdf as KeyDerivation;
use sha2::{Digest, Sha256 as Hashing};
use rand_chacha::rand_core::{CryptoRng, RngCore};
use sp_std::collections::btree_map::BTreeMap;
macro_rules! with_ciphersuite {
($curve:expr, |$alias:ident| $body:block) => {
match $curve {
ExodusCurve::Secp256k1 => {
use frost_secp256k1 as $alias;
$body
},
NetworkCurve::Ed25519 => {
use frost_ed25519 as $alias;
$body
}
}
}
}
impl ExodusCurve {
pub fn dkg_verify_proof_of_knowledge(
&self,
index: u16,
round1_package_bytes: &[u8],
) -> Result<(), FrostError> {
with_ciphersuite!(self, |f| {
let identifier = index.try_into().map_err(|_| FrostError::InvalidParticipantId)?;
let round1_package = f::keys::dkg::round1::Package::deserialize(round1_package_bytes)
.map_err(|_| FrostError::DeserializationError)?;
frost_core::keys::dkg::verify_proof_of_knowledge(
identifier,
&round1_package.commitment(),
&round1_package.proof_of_knowledge(),
).map_err(|_| FrostError::InvalidProofOfKnowledge)
})
}
pub fn verify_signature_share(
&self,
index: u16,
verifying_share_bytes: &[u8],
signature_share_bytes: &[u8],
signing_package_bytes: &[u8],
verifying_key_bytes: &[u8],
) -> Result<(), FrostError> {
with_ciphersuite!(self, |f| {
let identifier = index.try_into().map_err(|_| FrostError::InvalidParticipantId)?;
let verifying_share = f::keys::VerifyingShare::deserialize(verifying_share_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let signature_share = f::round2::SignatureShare::deserialize(signature_share_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let signing_package = f::SigningPackage::deserialize(signing_package_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let verifying_key = f::VerifyingKey::deserialize(verifying_key_bytes)
.map_err(|_| FrostError::DeserializationError)?;
frost_core::verify_signature_share(
identifier,
&verifying_share,
&signature_share,
&signing_package,
&verifying_key,
).map_err(|err| match err {
f::Error::IdentityCommitment => FrostError::IdentityCommitment,
f::Error::UnknownIdentifier => FrostError::UnknownIdentifier,
f::Error::DuplicatedIdentifier => FrostError::DuplicatedIdentifier,
f::Error::InvalidSignatureShare { .. } => FrostError::InvalidSignatureShare,
_ => FrostError::Unknown,
})
})
}
pub fn aggregate_signature(
&self,
signing_package_bytes: &[u8],
signature_shares_bytes: &BTreeMap<u16, Vec<u8>>,
pubkeys_bytes: &[u8],
) -> Result<Vec<u8>, FrostError> {
with_ciphersuite!(self, |f| {
let signing_package = f::SigningPackage::deserialize(signing_package_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let mut signature_shares = BTreeMap::new();
for (&index, signature_share_bytes) in signature_shares_bytes.iter() {
let identifier = index.try_into().map_err(|_| FrostError::InvalidParticipantId)?;
let signature_share = f::round2::SignatureShare::deserialize(signature_share_bytes)
.map_err(|_| FrostError::DeserializationError)?;
signature_shares.insert(identifier, signature_share);
}
let pubkeys = f::keys::PublicKeyPackage::deserialize(pubkeys_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let signature = f::aggregate(&signing_package, &signature_shares, &pubkeys)
.map_err(|err| match err {
f::Error::UnknownIdentifier => FrostError::UnknownIdentifier,
f::Error::SerializationError => FrostError::SerializationError,
f::Error::IdentityCommitment => FrostError::IdentityCommitment,
f::Error::IncorrectNumberOfIdentifiers => FrostError::IncorrectNumberOfIdentifiers,
f::Error::DuplicatedIdentifier => FrostError::DuplicatedIdentifier,
f::Error::InvalidSecretShare { .. } => FrostError::InvalidSecretShare,
f::Error::InvalidSignature { .. } => FrostError::InvalidSignature,
_ => FrostError::Unknown,
})?;
let signature_bytes = signature.serialize()
.map_err(|_| FrostError::SerializationError)?;
Ok(signature_bytes)
})
}
pub fn is_signature_valid(
&self,
pubkey_bytes: &[u8],
signature_bytes: &[u8],
message: &[u8],
) -> bool {
with_ciphersuite!(self, |f| {
let get_verification_result = || -> Result<(), FrostError> {
let pubkeys = f::keys::PublicKeyPackage::deserialize(pubkey_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let signature = f::Signature::deserialize(signature_bytes)
.map_err(|_| FrostError::DeserializationError)?;
pubkeys.verifying_key()
.verify(message, &signature)
.map_err(|_| FrostError::InvalidSignature)?;
Ok(())
};
get_verification_result().is_ok()
})
}
pub fn dkg_part1<R: RngCore + CryptoRng>(
&self,
index: u16,
max_signers: u16,
min_signers: u16,
mut rng: R,
) -> Result<(Vec<u8>, Vec<u8>), FrostError> {
with_ciphersuite!(self, |f| {
let identifier = index.try_into().map_err(|_| FrostError::InvalidParticipantId)?;
let (round1_secret_package, round1_package) = f::keys::dkg::part1(
identifier,
max_signers,
min_signers,
&mut rng,
).map_err(|err| {
match err {
f::Error::InvalidMinSigners => FrostError::InvalidMinSigners(min_signers, max_signers),
f::Error::InvalidMaxSigners => FrostError::InvalidMaxSigners(max_signers),
f::Error::DKGNotSupported => FrostError::DKGNotSupported(*self),
_ => FrostError::Unknown,
}
})?;
let round1_secret_package_bytes = round1_secret_package.serialize()
.map_err(|_| FrostError::SerializationError)?;
let round1_package_bytes = round1_package.serialize()
.map_err(|_| FrostError::SerializationError)?;
Ok((round1_secret_package_bytes, round1_package_bytes))
})
}
fn convert_identifier_to_index(
identifier_bytes: Vec<u8>
) -> Result<u16, FrostError> {
const SIZE: usize = core::mem::size_of::<u16>();
let start = identifier_bytes.len().checked_sub(SIZE)
.ok_or(FrostError::InvalidParticipantId)?;
let bytes_array = identifier_bytes.get(start..)
.and_then(|slice| slice.try_into().ok())
.ok_or(FrostError::InvalidParticipantId)?;
Ok(u16::from_be_bytes(bytes_array))
}
pub fn dkg_part2(
&self,
round1_secret_package_bytes: &[u8],
round1_packages_bytes: &BTreeMap<u16, Vec<u8>>,
) -> Result<(Vec<u8>, BTreeMap<u16, Vec<u8>>), FrostError> {
with_ciphersuite!(self, |f| {
let round1_secret_package = f::keys::dkg::round1::SecretPackage::deserialize(round1_secret_package_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let mut round1_packages = BTreeMap::new();
for (&index, round1_package_bytes) in round1_packages_bytes.iter() {
let identifier = index.try_into().map_err(|_| FrostError::InvalidParticipantId)?;
let round1_package = f::keys::dkg::round1::Package::deserialize(round1_package_bytes)
.map_err(|_| FrostError::DeserializationError)?;
round1_packages.insert(identifier, round1_package);
}
let (round2_secret_package, round2_packages) = f::keys::dkg::part2(
round1_secret_package,
&round1_packages,
).map_err(|err| match err {
f::Error::IncorrectNumberOfCommitments => FrostError::IncorrectNumberOfCommitments,
f::Error::IncorrectNumberOfPackages => FrostError::IncorrectNumberOfPackages,
f::Error::InvalidProofOfKnowledge { .. } => FrostError::InvalidProofOfKnowledge,
_ => FrostError::Unknown,
})?;
let round2_secret_package_bytes = round2_secret_package.serialize()
.map_err(|_| FrostError::SerializationError)?;
let mut round2_packages_bytes = BTreeMap::new();
for (participant_identifier, round2_package) in round2_packages.iter() {
let index = Self::convert_identifier_to_index(
participant_identifier.serialize(),
)?;
let round2_package_bytes = round2_package.serialize()
.map_err(|_| FrostError::SerializationError)?;
round2_packages_bytes.insert(index as u16, round2_package_bytes);
}
Ok((round2_secret_package_bytes, round2_packages_bytes))
})
}
pub fn dkg_encrypt_round2_package<R: RngCore + CryptoRng>(
&self,
cipher: &EncryptionCipher,
associated_data: &[u8],
round2_package_bytes: &[u8],
mut rng: R,
) -> Result<(Vec<u8>, Vec<u8>), FrostError> {
let payload = aead::Payload {
msg: round2_package_bytes,
aad: associated_data,
};
let nonce = EncryptionCipher::generate_nonce(&mut rng);
let ciphertext = cipher.encrypt(&nonce, payload)
.map_err(|_| FrostError::EncryptionFailed)?;
Ok((ciphertext, nonce.to_vec()))
}
pub fn dkg_decrypt_round2_package(
&self,
cipher: &EncryptionCipher,
encrypted_message: &EncryptedMessage,
associated_data: &[u8],
) -> Result<Vec<u8>, FrostError> {
let nonce = EncryptionNonce::from_iter(encrypted_message.nonce.iter().cloned());
let payload = aead::Payload {
msg: &encrypted_message.ciphertext,
aad: associated_data,
};
cipher.decrypt(&nonce, payload)
.map_err(|_| FrostError::DecryptionFailed)
}
pub fn prepare_additional_info(
&self,
sender_index: u16,
receiver_index: u16,
session_index: u16,
) -> Vec<u8> {
let mut additional_info = match self {
ExodusCurve::Secp256k1 => b"EXODUS-SECP256K1-DKG-V1".to_vec(),
};
additional_info.extend_from_slice(&sender_index.to_be_bytes());
additional_info.extend_from_slice(&receiver_index.to_be_bytes());
additional_info.extend_from_slice(&session_index.to_be_bytes());
additional_info
}
pub fn prepare_cipher_from_keys(
&self,
round1_receiver_package_bytes: &[u8],
round1_secret_package_bytes: &[u8],
additional_info: &[u8],
) -> Result<EncryptionCipher, FrostError> {
with_ciphersuite!(self, |f| {
let coefficients =
f::keys::dkg::round1::SecretPackage::deserialize(round1_secret_package_bytes)
.map_err(|_| FrostError::DeserializationError)?
.coefficients();
let sender_secret_key = coefficients
.first()
.ok_or(FrostError::IncorrectNumberOfCoefficients)?;
let receiver_public_key =
f::keys::dkg::round1::Package::deserialize(round1_receiver_package_bytes)
.map_err(|_| FrostError::DeserializationError)?
.commitment()
.coefficients()
.first()
.ok_or(FrostError::MissingCommitment)?
.value();
let shared_secret_bytes = f::VerifyingKey::new(receiver_public_key * sender_secret_key)
.serialize()
.map_err(|_| FrostError::SerializationError)?;
let salt = Hashing::digest(&additional_info);
let hk = KeyDerivation::<Hashing>::new(Some(&salt), &shared_secret_bytes);
let mut encryption_key = EncryptionKey::default();
hk.expand(additional_info, &mut encryption_key)
.map_err(|_| FrostError::HKDFFailed)?;
let cipher = EncryptionCipher::new_from_slice(&encryption_key)
.expect("could not happen; length is already correct qed");
Ok(cipher)
})
}
pub fn dkg_verify_private_package(
&self,
index: u16,
round1_package_bytes: &[u8],
round2_package_bytes: &[u8],
) -> Result<(), FrostError> {
with_ciphersuite!(self, |f| {
let identifier = index.try_into().map_err(|_| FrostError::InvalidParticipantId)?;
let commitment = f::keys::dkg::round1::Package::deserialize(round1_package_bytes)
.map(|round1_package| round1_package.commitment().clone())
.map_err(|_| FrostError::DeserializationError)?;
let secret_share = f::keys::dkg::round2::Package::deserialize(round2_package_bytes)
.map(|round2_package| {
let signing_share = round2_package.signing_share().clone();
f::keys::SecretShare::new(identifier, signing_share, commitment)
})
.map_err(|_| FrostError::DeserializationError)?;
let _ = secret_share.verify().map_err(|_| FrostError::InvalidSecretShare)?;
Ok(())
})
}
pub fn dkg_part3(
&self,
round2_secret_package_bytes: &[u8],
round1_packages_bytes: &BTreeMap<u16, Vec<u8>>,
round2_packages_bytes: &BTreeMap<u16, Vec<u8>>,
) -> Result<(Vec<u8>, Vec<u8>), FrostError> {
with_ciphersuite!(self, |f| {
let round2_secret_package = f::keys::dkg::round2::SecretPackage::deserialize(round2_secret_package_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let mut round1_packages = BTreeMap::new();
for (&index, round1_package_bytes) in round1_packages_bytes.iter() {
let identifier = index.try_into().map_err(|_| FrostError::InvalidParticipantId)?;
let round1_package = f::keys::dkg::round1::Package::deserialize(round1_package_bytes)
.map_err(|_| FrostError::DeserializationError)?;
round1_packages.insert(identifier, round1_package);
}
let mut round2_packages = BTreeMap::new();
for (&index, round2_package_bytes) in round2_packages_bytes.iter() {
let identifier = index.try_into().map_err(|_| FrostError::InvalidParticipantId)?;
let round2_package = f::keys::dkg::round2::Package::deserialize(round2_package_bytes)
.map_err(|_| FrostError::DeserializationError)?;
round2_packages.insert(identifier, round2_package);
}
let (key_package, pubkey_package) = f::keys::dkg::part3(
&round2_secret_package,
&round1_packages,
&round2_packages,
).map_err(|err| match err {
f::Error::IncorrectNumberOfPackages => FrostError::IncorrectNumberOfPackages,
f::Error::IncorrectPackage => FrostError::IncorrectPackage,
f::Error::PackageNotFound => FrostError::PackageNotFound,
f::Error::InvalidSecretShare { .. } => FrostError::InvalidSecretShare,
f::Error::IncorrectNumberOfCommitments => FrostError::IncorrectNumberOfCommitments,
_ => FrostError::Unknown,
})?;
let key_package_bytes = key_package.serialize()
.map_err(|_| FrostError::SerializationError)?;
let pubkey_package_bytes = pubkey_package.serialize()
.map_err(|_| FrostError::SerializationError)?;
Ok((key_package_bytes, pubkey_package_bytes))
})
}
pub fn generate_nonce<R: CryptoRng + RngCore>(
&self,
secret_key_package_bytes: &[u8],
mut rng: R
) -> Result<(Vec<u8>, Vec<u8>), FrostError> {
with_ciphersuite!(self, |f| {
let signing_share = f::keys::KeyPackage::deserialize(secret_key_package_bytes)
.map(|key_package| *key_package.signing_share())
.map_err(|_| FrostError::DeserializationError)?;
let (signing_nonces, signing_commitments) =
f::round1::commit(&signing_share, &mut rng);
let signing_nonces_bytes = signing_nonces.serialize()
.map_err(|_| FrostError::SerializationError)?;
let signing_commitments_bytes = signing_commitments.serialize()
.map_err(|_| FrostError::SerializationError)?;
Ok((signing_nonces_bytes, signing_commitments_bytes))
})
}
pub fn generate_signing_package(
&self,
commitments_map_bytes: &BTreeMap<u16, Vec<u8>>,
message: &[u8],
) -> Result<Vec<u8>, FrostError> {
with_ciphersuite!(self, |f| {
let mut commitments_map = BTreeMap::new();
for (&index, commitment_bytes) in commitments_map_bytes.iter() {
let identifier = index.try_into().map_err(|_| FrostError::InvalidParticipantId)?;
let commitment = f::round1::SigningCommitments::deserialize(commitment_bytes)
.map_err(|_| FrostError::DeserializationError)?;
commitments_map.insert(identifier, commitment);
}
f::SigningPackage::new(commitments_map, message)
.serialize()
.map_err(|_| FrostError::SerializationError)
})
}
pub fn sign_message(
&self,
signing_package_bytes: &[u8],
signer_nonces_bytes: &[u8],
secret_key_share_bytes: &[u8]
) -> Result<Vec<u8>, FrostError> {
with_ciphersuite!(self, |f| {
let signing_package = f::SigningPackage::deserialize(signing_package_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let signer_nonces = f::round1::SigningNonces::deserialize(signer_nonces_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let secret_key_share = f::keys::KeyPackage::deserialize(secret_key_share_bytes)
.map_err(|_| FrostError::DeserializationError)?;
let signature_share_bytes = f::round2::sign(&signing_package, &signer_nonces, &secret_key_share)
.map(|signature_share| signature_share.serialize())
.map_err(|err| match err {
f::Error::IncorrectNumberOfCommitments => FrostError::IncorrectNumberOfCommitments,
f::Error::MissingCommitment => FrostError::MissingCommitment,
f::Error::IncorrectCommitment => FrostError::IncorrectCommitment,
f::Error::SerializationError => FrostError::SerializationError,
f::Error::UnknownIdentifier => FrostError::UnknownIdentifier,
f::Error::IdentityCommitment => FrostError::IdentityCommitment,
f::Error::DuplicatedIdentifier => FrostError::DuplicatedIdentifier,
f::Error::IncorrectNumberOfIdentifiers => FrostError::IncorrectNumberOfIdentifiers,
_ => FrostError::Unknown,
})?;
Ok(signature_share_bytes)
})
}
}

View File

@ -46,7 +46,7 @@ use ghost_traits::{
},
exodus::{
MerkleTreeBuilder, DistributedKeyGeneration, EllipticCurveDiffieHellman,
FlexibleRoundOptimizedSchnorrThresholdSignature,
FlexibleRoundOptimizedSchnorrThresholdSignature, EvmGovernanceRegistrar,
},
networks::{
NetworkDataBasicHandler, NetworkDataInspectHandler,
@ -108,7 +108,7 @@ const EXODUS_PREFIX_SHARES: &[u8] = b"exodus-shares";
const EXODUS_PREFIX_BLENDS: &[u8] = b"exodus-blends";
const EXODUS_PREFIX_EXILES: &[u8] = b"exodus-exiles";
const MAX_MESSAGE_SIZE : u32 = 420;
const MAX_MESSAGE_SIZE : u32 = 512;
const HEADER_MAX_BYTES : u32 = 1 + 4;
const ELEMENT_MAX_BYTES : u32 = 33;
const SCALAR_MAX_BYTES : u32 = 32;
@ -506,6 +506,7 @@ pub mod pallet {
pub enum Error<T> {
DkgWrongRound,
TooManyEntries,
BridgeOverflow,
TooManyPackages,
WrongNetworkType,
InvalidMerkleProof,
@ -2135,12 +2136,13 @@ pub mod pallet {
}
impl<T: Config> Pallet<T> {
fn do_register_evm_bridge_out_exodus(
fn do_register_evm_exodus<F>(
network_id: NetworkIdOf<T>,
amount: BalanceOf<T>,
bounty: Perbill,
receiver: EvmAddress,
) -> DispatchResult {
request_builder: F,
) -> DispatchResult
where
F: FnOnce(ExodusSession) -> ExodusRequest<NetworkIdOf<T>, BalanceOf<T>>,
{
let network = T::NetworkDataHandler::get(&network_id)
.ok_or(Error::<T>::NetworkDoesNotExist)?;
@ -2152,13 +2154,7 @@ impl<T: Config> Pallet<T> {
ensure!(network.r#type.is_evm(), Error::<T>::WrongNetworkType);
let exodus_session = CurrentExodus::<T>::get();
let request = ExodusRequest::evm_bridge_out(
exodus_session,
network_id,
amount,
bounty,
receiver
);
let request = request_builder(exodus_session);
ExodusRequests::<T>::insert(&network.curve, &exodus_session, request);
CurrentExodus::<T>::put(exodus_session.saturating_add(1));
@ -2166,6 +2162,42 @@ impl<T: Config> Pallet<T> {
Ok(())
}
fn do_register_evm_bridge_out_exodus(
network_id: NetworkIdOf<T>,
amount: BalanceOf<T>,
bounty: Perbill,
receiver: EvmAddress,
) -> DispatchResult {
let out_amount =
T::NetworkDataHandler::register_outgoing(&network_id, amount)
.map_err(|_| Error::<T>::BridgeOverflow)?;
Self::do_register_evm_exodus(network_id, |exodus_session| {
ExodusRequest::evm_bridge_out(
exodus_session,
network_id,
out_amount,
bounty,
receiver,
)
})
}
fn do_register_evm_governance(
network_id: NetworkIdOf<T>,
target_address: EvmAddress,
governance_action: GovernanceAction,
) -> DispatchResult {
Self::do_register_evm_exodus(network_id, |exodus_session| {
ExodusRequest::evm_governance(
exodus_session,
network_id,
target_address,
governance_action,
)
})
}
fn prepare_round_storage<ClearFn, CompleteFn>(
network_curve: NetworkCurve,
maybe_cursor: Option<BoundedVec<u8, T::MaxCursorLen>>,
@ -4875,6 +4907,20 @@ impl<T: Config> BlockNumberProvider for Pallet<T> {
}
}
impl<T: Config> EvmGovernanceRegistrar<NetworkIdOf<T>, EvmAddress, GovernanceAction> for Pallet<T> {
fn register_evm_governance_action(
network_id: NetworkIdOf<T>,
target_address: EvmAddress,
governance_action: GovernanceAction,
) -> DispatchResult {
Self::do_register_evm_governance(
network_id,
target_address,
governance_action,
)
}
}
impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
type Key = T::AuthorityId;

View File

@ -181,7 +181,7 @@ pub fn new_test_ext() -> (
let networks = vec![
NetworkInitiationBuilder::<MockedNetworkId, u64>::default()
.with_network_id(31_337)
.with_network_id(420)
.with_gatekeeper_amount(0)
.with_network_data(network_data)
.build(),

View File

@ -8,6 +8,7 @@ use sp_std::{
};
use frame_support::{assert_ok, assert_err, traits::Hooks};
use sp_runtime::testing::UintAuthorityId;
use ghost_helpers::networks::NetworkDataBuilder;
use rand::Rng;
use rand_chacha::rand_core::SeedableRng;
@ -1036,16 +1037,55 @@ fn test_all_validators_can_execute_initial_dkg() {
fn test_all_validators_can_execute_dkg() {
let curve = NetworkCurve::Secp256k1;
let authorities_1 = FixedAuthorities::get();
let dummy_address = EvmAddress::repeat_byte(1);
let network_id = 31_337;
let (mut ext, tx_pool_state) = run_initial_dkg_session(&authorities_1, curve);
ext.execute_with(|| {
let network_data = NetworkDataBuilder::default()
.with_network_curve(curve)
.with_network_type(NetworkType::Evm)
.with_outgoing_share(500_000_000)
.build();
let _ = <Runtime as Config>::NetworkDataHandler::register(network_id, network_data).unwrap();
let _ = <Runtime as Config>::NetworkDataHandler::register_incoming(&network_id, 1337).unwrap();
Exodus::do_register_evm_bridge_out_exodus(
31_337,
network_id,
69,
Default::default(),
EvmAddress::from_low_u64_be(1),
).unwrap();
let set_distributor = GovernanceAction::SetDistributor { distributor: dummy_address };
let set_warmup = GovernanceAction::SetWarmupPeriod { warmup_period: 69 };
let update_gatekeeper = GovernanceAction::UpdateGatekeeperAddress { new_gatekeeper: dummy_address };
let set_bounty = GovernanceAction::SetBounty { bounty: 69 };
let set_adjustment = GovernanceAction::SetAdjustment { rate: 69, target: 420, add: true };
let add_pool = GovernanceAction::AddPool { address: dummy_address };
let remove_pool = GovernanceAction::RemovePool { index: 1337 };
let close = GovernanceAction::Close { id: 420 };
let create = GovernanceAction::Create {
market: [69, 420, 1337],
terms: [420, 1337],
token: dummy_address,
intervals: [34, 35],
booleans: [true, true],
};
Exodus::do_register_evm_governance(network_id, dummy_address, set_distributor).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, set_warmup).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, set_bounty).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, set_adjustment).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, update_gatekeeper).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, add_pool).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, remove_pool).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, close).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, create).unwrap();
});
let mut authorities_2 = authorities_1.clone();
@ -1058,11 +1098,25 @@ fn test_all_validators_can_execute_dkg() {
ext.execute_with(|| {
Exodus::do_register_evm_bridge_out_exodus(
31_337,
network_id,
420,
Perbill::from_percent(50),
EvmAddress::from_low_u64_be(2),
).unwrap();
let enable = GovernanceAction::Enable { status: GovernanceStatus::ReserveToken, address: dummy_address, calculator: dummy_address };
let disable = GovernanceAction::Disable { status: GovernanceStatus::LiquidityToken, address: dummy_address };
let forfeit = GovernanceAction::ForfeitReserves { router: dummy_address, liquidity: 420, destroyer_mode: true };
let redeem = GovernanceAction::RedeemReserves { router: dummy_address, amount: 420 };
let withdraw = GovernanceAction::Withdraw { token: dummy_address, amount: 420 };
let audit = GovernanceAction::AuditReserves;
Exodus::do_register_evm_governance(network_id, dummy_address, enable).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, disable).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, forfeit).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, redeem).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, withdraw).unwrap();
Exodus::do_register_evm_governance(network_id, dummy_address, audit).unwrap();
});
let mut authorities_3 = FixedAuthorities::get();
@ -1078,8 +1132,13 @@ fn test_all_validators_can_execute_dkg() {
ExodusSignedBridges::<Runtime>::iter().count()
});
let governances_count = ext.execute_with(|| {
ExodusSignedGovernance::<Runtime>::iter().count()
});
assert_eq!(rotations_count, 3);
assert_eq!(bridges_count, 2);
assert_eq!(governances_count, 15);
}
#[test]

View File

@ -71,10 +71,70 @@ macro_rules! impl_evm_encodable {
}
)*
};
(const_array: $( [ $inner_ty:ty ; $len:expr ] ),* $(,)? ) => {
$(
impl EvmAbiEncode for [ $inner_ty ; $len ] {
#[inline(always)]
fn size(&self) -> usize {
$len * 32
}
#[inline(always)]
fn abi_encode(&self, buffer: &mut [u8], cursor: &mut usize) -> Option<()> {
for item in self.iter() {
EvmAbiEncode::abi_encode(item, buffer, cursor)?;
}
Some(())
}
}
)*
};
(bytes_slice: ) => {
impl EvmAbiEncode for [u8] {
#[inline(always)]
fn size(&self) -> usize {
let content_len = self.len();
let remainder = content_len % 32;
let alignment = if remainder == 0 { 0 } else { 32 - remainder };
32 + content_len + alignment
}
#[inline(always)]
fn abi_encode(&self, buffer: &mut [u8], cursor: &mut usize) -> Option<()> {
if self.size() >= MAX_MESSAGE_SIZE as usize { return None; }
let pointer = cursor.checked_sub(4).map(|x| x.saturating_add(32))?;
let head_pointer = pointer as u32;
EvmAbiEncode::abi_encode(&head_pointer, buffer, cursor);
let content_len = self.len() as u32;
EvmAbiEncode::abi_encode(&content_len, buffer, cursor)?;
let value_slice = buffer.get_mut(*cursor..*cursor + self.len())?;
value_slice.copy_from_slice(self);
*cursor += self.len();
let remainder = self.len() % 32;
if remainder != 0 {
let alignment = 32 - remainder;
let alignment_slice = buffer.get_mut(*cursor..*cursor + alignment)?;
alignment_slice.fill(0);
*cursor += alignment;
}
Some(())
}
}
};
}
impl_evm_encodable!(numeric: u8, u16, u32, u64, u128);
impl_evm_encodable!(bytes_fixed: EvmAddress, EvmBytes32);
impl_evm_encodable!(const_array: [u128; 3], [u128; 2], [u32; 2], [u8; 2]);
impl_evm_encodable!(bytes_slice:);
macro_rules! abi_encode_evm_message {
($buffer:expr, $sig:expr, [ $( $val:expr ),* $(,)? ]) => {{
@ -102,6 +162,152 @@ macro_rules! abi_encode_evm_message {
}};
}
#[derive(Encode, Decode, Clone, Copy, PartialEq, TypeInfo, RuntimeDebug)]
#[repr(u8)]
pub enum GovernanceStatus {
ReserveDepositor = 0,
ReserveToken = 1,
LiquidityDepositor = 2,
LiquidityToken = 3,
RewardManager = 4,
}
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
pub enum GovernanceAction {
SetDistributor { distributor: EvmAddress },
SetWarmupPeriod { warmup_period: u128 },
UpdateGatekeeperAddress { new_gatekeeper: EvmAddress },
SetBounty { bounty: u128 },
AddPool { address: EvmAddress },
RemovePool { index: u128 },
SetAdjustment { rate: u128, target: u128, add: bool },
Enable { status: GovernanceStatus, address: EvmAddress, calculator: EvmAddress },
Disable { status: GovernanceStatus, address: EvmAddress },
ForfeitReserves { router: EvmAddress, liquidity: u128, destroyer_mode: bool },
RedeemReserves { router: EvmAddress, amount: u128 },
Withdraw { token: EvmAddress, amount: u128 },
AuditReserves,
Close { id: u128 },
Create {
market: [u128; 3],
terms: [u128; 2],
token: EvmAddress,
intervals: [u32; 2],
booleans: [bool; 2],
},
}
impl GovernanceAction {
pub fn get_message<'a>(
&self,
message_buffer: &'a mut [u8; MAX_MESSAGE_SIZE as usize],
) -> Option<&'a [u8]> {
match &self {
Self::SetDistributor { distributor } => {
abi_encode_evm_message!(
message_buffer,
"setDistributor(address)",
[distributor]
)
},
Self::SetWarmupPeriod { warmup_period } => {
abi_encode_evm_message!(
message_buffer,
"setWarmupPeriod(uint256)",
[warmup_period]
)
},
Self::UpdateGatekeeperAddress { new_gatekeeper } => {
abi_encode_evm_message!(
message_buffer,
"updateGatekeeperAddress(address)",
[new_gatekeeper]
)
},
Self::SetBounty { bounty } => {
abi_encode_evm_message!(
message_buffer,
"setBounty(uint256)",
[bounty]
)
},
Self::AddPool { address } => {
abi_encode_evm_message!(
message_buffer,
"addPool(address)",
[address]
)
},
Self::RemovePool { index } => {
abi_encode_evm_message!(
message_buffer,
"removePool(uint256)",
[index]
)
},
Self::SetAdjustment { rate, target, add } => {
abi_encode_evm_message!(
message_buffer,
"setAdjustment(uint256,uint256,bool)",
[rate, target, &(*add as u8)]
)
},
Self::Enable { status, address, calculator } => {
abi_encode_evm_message!(
message_buffer,
"enable(uint8,address,address)",
[&(*status as u8), address, calculator]
)
},
Self::Disable { status, address } => {
abi_encode_evm_message!(
message_buffer,
"disable(uint8,address)",
[&(*status as u8), address]
)
},
Self::ForfeitReserves { router, liquidity, destroyer_mode } => {
abi_encode_evm_message!(
message_buffer,
"forfeitReserves(address,uint256,bool)",
[router, liquidity, &(*destroyer_mode as u8)]
)
},
Self::RedeemReserves { router, amount } => {
abi_encode_evm_message!(
message_buffer,
"redeemReserve(address,uint256)",
[router, amount]
)
},
Self::Withdraw { token, amount } => {
abi_encode_evm_message!(
message_buffer,
"withdraw(address,uint256)",
[token, amount]
)
},
Self::AuditReserves => {
abi_encode_evm_message!(message_buffer, "auditReserves()", [])
},
Self::Close { id } => {
abi_encode_evm_message!(message_buffer, "close(uint256)", [id])
},
Self::Create { market, terms, token, intervals, booleans } => {
let booleans_u8 = [booleans[0] as u8, booleans[1] as u8];
abi_encode_evm_message!(
message_buffer,
"create(uint256[3],uint256[2],address,uint32[2],bool[2])",
[market, terms, token, intervals, &booleans_u8]
)
},
}
}
}
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
pub struct ExodusRequest<NetworkId, Balance> {
pub r#type: ExodusRequestType<NetworkId, Balance>,
@ -123,7 +329,12 @@ pub enum ExodusRequestType<NetworkId, Balance> {
bounty: Perbill,
receiver: EvmAddress,
},
EvmGovernance { network_id: NetworkId },
EvmGovernance {
exodus_session: ExodusSession,
network_id: NetworkId,
target: EvmAddress,
action: GovernanceAction,
},
UtxoBridgeOut { network_id: NetworkId },
}
@ -144,6 +355,24 @@ where
[exodus_session, public_key, parity]
)
},
ExodusRequestType::EvmGovernance { exodus_session, network_id, target, action } => {
let mut action_buffer = [0u8; MAX_MESSAGE_SIZE as usize];
let action_payload = action.get_message(&mut action_buffer)?;
let mut metadata_buffer = [0u8; 32];
let chain_id_u64: u64 = (*network_id).unique_saturated_into();
metadata_buffer[0..8].copy_from_slice(&chain_id_u64.to_be_bytes());
metadata_buffer[8..28].copy_from_slice(target.as_ref());
let packed_metadata = EvmBytes32::from(&metadata_buffer);
abi_encode_evm_message!(
message_buffer,
"govern(uint256,uint256,bytes)",
[exodus_session, &packed_metadata, action_payload]
)
},
ExodusRequestType::EvmBridgeOut { exodus_session, network_id, amount, bounty, receiver } => {
let mut buffer = [0u8; 32];
buffer[0..20].copy_from_slice(receiver.as_ref());
@ -170,7 +399,7 @@ where
abi_encode_evm_message!(
message_buffer,
"materialize(uint256,uint256,uint256)",
"recall(uint256,uint256,uint256)",
[exodus_session, &amount_u256, &packed_metadata]
)
}
@ -221,6 +450,21 @@ where
Self::default_request_for(evm_bridge_out)
}
pub fn evm_governance(
exodus_session: ExodusSession,
network_id: NetworkId,
target: EvmAddress,
action: GovernanceAction,
) -> Self {
let evm_governance = ExodusRequestType::EvmGovernance {
exodus_session,
network_id,
target,
action,
};
Self::default_request_for(evm_governance)
}
pub fn is_rotation(&self) -> bool {
match &self.r#type {
ExodusRequestType::EvmRotation { .. } | ExodusRequestType::UtxoRotation { .. } => true,
@ -234,3 +478,255 @@ where
Self { r#type: request_type, next_roast_session: Default::default() }
}
}
#[cfg(test)]
mod tests {
use super::*;
use sp_io::hashing::keccak_256;
#[test]
fn test_rotation_message_valid() {
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
let public_key = EvmBytes32::repeat_byte(0x11);
let session = 69u64;
let rotation_request = ExodusRequest::<u64, u128>::evm_rotation(
session,
public_key.clone(),
1,
);
let calldata = rotation_request.get_message(&mut buffer).unwrap();
assert_eq!(calldata.len(), 100);
let expected_hash = keccak_256("rotate(uint256,bytes32,uint8)".as_bytes());
assert_eq!(calldata[0..4], expected_hash[0..4]);
assert_eq!(calldata[35], 0x45);
assert_eq!(&calldata[4..35], &[0u8; 31]);
assert_eq!(&calldata[36..68], public_key.as_ref());
assert_eq!(calldata[99], 1);
assert_eq!(&calldata[68..99], &[0u8; 31]);
}
#[test]
fn test_bridge_out_message_valid() {
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
let receiver = EvmAddress::repeat_byte(0xAA);
let network_id = 420u64;
let session = 69u64;
let bridge_request = ExodusRequest::<u64, u128>::evm_bridge_out(
session,
network_id,
1_000_000u128,
sp_runtime::Perbill::from_percent(1),
receiver.clone()
);
let calldata = bridge_request.get_message(&mut buffer).unwrap();
assert_eq!(calldata.len(), 100);
let expected_hash = keccak_256("recall(uint256,uint256,uint256)".as_bytes());
assert_eq!(calldata[0..4], expected_hash[0..4]);
assert_eq!(calldata[35], 69);
assert_eq!(calldata[67], 0x40);
assert_eq!(calldata[66], 0x42);
assert_eq!(calldata[65], 0x0F);
let metadata_slot = &calldata[68..100];
assert_eq!(&metadata_slot[0..20], receiver.as_ref());
assert_eq!(metadata_slot[27], 0xA4);
assert_eq!(metadata_slot[26], 0x01);
assert_eq!(metadata_slot[31], 0x28);
assert_eq!(metadata_slot[30], 0x5C);
assert_eq!(metadata_slot[29], 0x8F);
assert_eq!(metadata_slot[28], 0x02);
}
#[test]
fn test_governance_message_valid() {
let mut buffer = [0u8; MAX_MESSAGE_SIZE as usize];
let target = EvmAddress::repeat_byte(0xAA);
let network_id = 420u64;
let session = 69u64;
let actions = vec![
GovernanceAction::SetDistributor { distributor: EvmAddress::repeat_byte(0x11) },
GovernanceAction::SetWarmupPeriod { warmup_period: 3600 },
GovernanceAction::UpdateGatekeeperAddress { new_gatekeeper: EvmAddress::repeat_byte(0x22) },
GovernanceAction::SetBounty { bounty: 500 },
GovernanceAction::AddPool { address: EvmAddress::repeat_byte(0x22) },
GovernanceAction::RemovePool { index: 2 },
GovernanceAction::SetAdjustment { rate: 10, target: 100, add: true },
GovernanceAction::Enable {
status: GovernanceStatus::ReserveDepositor,
address: EvmAddress::repeat_byte(0x33),
calculator: EvmAddress::repeat_byte(0x44)
},
GovernanceAction::Disable {
status: GovernanceStatus::ReserveToken,
address: EvmAddress::repeat_byte(0x55)
},
GovernanceAction::ForfeitReserves {
router: EvmAddress::repeat_byte(0x66),
liquidity: 5000,
destroyer_mode: false
},
GovernanceAction::RedeemReserves { router: EvmAddress::repeat_byte(0x77), amount: 10000 },
GovernanceAction::Withdraw { token: EvmAddress::repeat_byte(0x88), amount: 2500 },
GovernanceAction::AuditReserves,
GovernanceAction::Close { id: 99 },
GovernanceAction::Create {
market: [69, 420, 1337],
terms: [69, 420],
token: EvmAddress::repeat_byte(0x99),
intervals: [69, 1337],
booleans: [true, false],
},
];
for (index, action) in actions.into_iter().enumerate() {
let action_clone = action.clone();
let governance_request = ExodusRequest::<u64, u128>::evm_governance(
session,
network_id,
target,
action,
);
let message = governance_request
.get_message(&mut buffer)
.get_or_insert(&[])
.to_vec();
assert!(!message.is_empty(), "Failed to encode action at index {}", index);
let expected_master_hash = keccak_256("govern(uint256,uint256,bytes)".as_bytes());
assert_eq!(message[0..4], expected_master_hash[0..4]);
assert_eq!(message[35], 69);
assert_eq!(&message[4..35], &[0u8; 31]);
assert_eq!(message[43], 0xA4);
assert_eq!(message[42], 0x01);
assert_eq!(&message[44..64], target.as_ref());
assert_eq!(&message[64..68], &[0u8; 4]);
assert_eq!(message[99], 96);
let inner_payload_len = u32::from_be_bytes(message[128..132].try_into().unwrap()) as usize;
let inner_payload = &message[132..132 + inner_payload_len];
assert_eq!((message.len() - 4) % 32, 0);
match action_clone {
GovernanceAction::SetDistributor { distributor } => {
let hash = keccak_256("setDistributor(address)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(&inner_payload[16..36], distributor.as_ref());
},
GovernanceAction::SetWarmupPeriod { warmup_period } => {
let hash = keccak_256("setWarmupPeriod(uint256)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(inner_payload[inner_payload.len() - 1], warmup_period as u8);
},
GovernanceAction::UpdateGatekeeperAddress { new_gatekeeper } => {
let hash = keccak_256("updateGatekeeperAddress(address)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(&inner_payload[16..36], new_gatekeeper.as_ref());
},
GovernanceAction::SetBounty { bounty } => {
let hash = keccak_256("setBounty(uint256)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(inner_payload[inner_payload.len() - 1], bounty as u8);
},
GovernanceAction::AddPool { address } => {
let hash = keccak_256("addPool(address)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(&inner_payload[16..36], address.as_ref());
},
GovernanceAction::RemovePool { index } => {
let hash = keccak_256("removePool(uint256)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(inner_payload[inner_payload.len() - 1], index as u8);
},
GovernanceAction::SetAdjustment { rate, target, add } => {
let hash = keccak_256("setAdjustment(uint256,uint256,bool)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(inner_payload[35], rate as u8);
assert_eq!(inner_payload[67], target as u8);
assert_eq!(inner_payload[99], add as u8);
},
GovernanceAction::Enable { status, address, calculator } => {
let hash = keccak_256("enable(uint8,address,address)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(inner_payload[35], status as u8);
assert_eq!(&inner_payload[48..68], address.as_ref());
assert_eq!(&inner_payload[80..100], calculator.as_ref());
},
GovernanceAction::Disable { status, address } => {
let hash = keccak_256("disable(uint8,address)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(inner_payload[35], status as u8);
assert_eq!(&inner_payload[48..68], address.as_ref());
},
GovernanceAction::ForfeitReserves { router, liquidity, destroyer_mode } => {
let hash = keccak_256("forfeitReserves(address,uint256,bool)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(&inner_payload[16..36], router.as_ref());
assert_eq!(inner_payload[67], liquidity as u8);
assert_eq!(inner_payload[99], destroyer_mode as u8);
},
GovernanceAction::RedeemReserves { router, amount } => {
let hash = keccak_256("redeemReserve(address,uint256)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(&inner_payload[16..36], router.as_ref());
assert_eq!(inner_payload[67], amount as u8);
},
GovernanceAction::Withdraw { token, amount } => {
let hash = keccak_256("withdraw(address,uint256)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(&inner_payload[16..36], token.as_ref());
assert_eq!(inner_payload[67], amount as u8);
},
GovernanceAction::AuditReserves => {
let hash = keccak_256("auditReserves()".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(inner_payload.len(), 4);
},
GovernanceAction::Close { id } => {
let hash = keccak_256("close(uint256)".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(inner_payload[inner_payload.len() - 1], id as u8);
},
GovernanceAction::Create { market, terms, token, intervals, booleans } => {
let hash = keccak_256("create(uint256[3],uint256[2],address,uint32[2],bool[2])".as_bytes());
assert_eq!(inner_payload[0..4], hash[0..4]);
assert_eq!(inner_payload.len(), 324);
assert_eq!(inner_payload[35], 69);
assert_eq!(u128::from_be_bytes(inner_payload[20..36].try_into().unwrap()), market[0]);
assert_eq!(u128::from_be_bytes(inner_payload[52..68].try_into().unwrap()), market[1]);
assert_eq!(u128::from_be_bytes(inner_payload[84..100].try_into().unwrap()), market[2]);
assert_eq!(u128::from_be_bytes(inner_payload[116..132].try_into().unwrap()), terms[0]);
assert_eq!(u128::from_be_bytes(inner_payload[148..164].try_into().unwrap()), terms[1]);
assert_eq!(&inner_payload[176..196], token.as_ref());
assert_eq!(u32::from_be_bytes(inner_payload[224..228].try_into().unwrap()), intervals[0]);
assert_eq!(u32::from_be_bytes(inner_payload[256..260].try_into().unwrap()), intervals[1]);
assert_eq!(inner_payload[291], booleans[0] as u8);
assert_eq!(inner_payload[323], booleans[1] as u8);
}
}
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-governance"
version = "0.3.2"
version = "0.3.4"
description = "Full-chain and cross-chain governance pallet with early adopter share claims"
license.workspace = true
authors.workspace = true

View File

@ -31,7 +31,7 @@ mod benchmarks {
evm_addr_bytes.copy_from_slice(&pubkey_hash.as_ref()[12..32]);
let dummy_evm_address = EvmAddress::from(evm_addr_bytes);
let target_index = 0u32;
let target_index = max_proof_depth - 1;
let claim_package_init = ClaimPackage {
shares: dummy_shares,
merkle_proof: Default::default(),
@ -40,7 +40,8 @@ mod benchmarks {
};
let preimage_init = claim_package_init.get_preimage(&dummy_evm_address, network_id);
let mut current_hash = SubstrateKeccakHasher::hash(&preimage_init);
let some_hash = SubstrateKeccakHasher::hash(&preimage_init);
let mut current_hash = some_hash;
let mut proof_hashes = Vec::with_capacity(max_proof_depth as usize);
let mut current_index = target_index as usize;
@ -48,21 +49,15 @@ mod benchmarks {
let hash_len = SubstrateKeccakHasher::hash_len();
let mut combined = sp_std::vec![0u8; hash_len * 2];
for i in 0..max_proof_depth {
let mut sibling_bytes = [0u8; 32];
sibling_bytes[24..32].copy_from_slice(&(i as u64).to_be_bytes());
let sibling_hash = EvmHash::from_slice(&sibling_bytes);
proof_hashes.push(sibling_hash);
let sibling_bytes_ref = sibling_hash.as_ref();
let hash_bytes = current_hash.as_ref();
for _ in 0..max_proof_depth {
proof_hashes.push(some_hash);
if current_index % 2 == 0 {
combined[..hash_len].copy_from_slice(hash_bytes);
combined[hash_len..].copy_from_slice(sibling_bytes_ref);
combined[..hash_len].copy_from_slice(&current_hash.to_fixed_bytes());
combined[hash_len..].copy_from_slice(&some_hash.to_fixed_bytes());
} else {
combined[..hash_len].copy_from_slice(sibling_bytes_ref);
combined[hash_len..].copy_from_slice(hash_bytes);
combined[..hash_len].copy_from_slice(&some_hash.to_fixed_bytes());
combined[hash_len..].copy_from_slice(&current_hash.to_fixed_bytes());
}
current_hash = SubstrateKeccakHasher::hash(&combined);
@ -89,7 +84,7 @@ mod benchmarks {
GlobalShares::<T>::put(global_state);
let claim_package = ClaimPackage {
index: 0,
index: target_index,
merkle_proof: BoundedVec::try_from(proof_hashes).unwrap(),
shares: dummy_shares,
token_id: 0

View File

@ -13,10 +13,10 @@
// You should have received a copy of the GNU General Public License
// along with Ghost Network. If not, see <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `ghost_claims`
//! Autogenerated weights for `ghost_governance`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2024-08-02, 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`
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
@ -28,12 +28,12 @@
// --chain=casper-dev
// --steps=50
// --repeat=20
// --pallet=ghost_claims
// --pallet=ghost_governance
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --header=./file_header.txt
// --output=./runtime/casper/src/weights/ghost_claims.rs
// --output=./runtime/casper/src/weights/ghost_governance.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
@ -52,26 +52,25 @@ pub trait WeightInfo {
}
impl WeightInfo for () {
/// Storage: `System::Account` (r:2 w:2)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `GhostClaims::Total` (r:1 w:1)
/// Proof: `GhostClaims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `CultCollective::Members` (r:2 w:2)
/// Proof: `CultCollective::Members` (`max_values`: None, `max_size`: Some(42), added: 2517, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::MemberCount` (r:6 w:6)
/// Proof: `CultCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::IdToIndex` (r:6 w:12)
/// Proof: `CultCollective::IdToIndex` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
/// Storage: `CultCollective::IndexToId` (r:0 w:6)
/// Proof: `CultCollective::IndexToId` (`max_values`: None, `max_size`: Some(54), added: 2529, mode: `MaxEncodedLen`)
fn claim(_p: u32) -> Weight {
/// Storage: `GhostGovernance::MemberShares` (r:1 w:1)
/// Proof: `GhostGovernance::MemberShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostGovernance::ClaimedHashes` (r:1 w:1)
/// Proof: `GhostGovernance::ClaimedHashes` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostGovernance::NetworkShares` (r:1 w:1)
/// Proof: `GhostGovernance::NetworkShares` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostGovernance::GlobalShares` (r:1 w:1)
/// Proof: `GhostGovernance::GlobalShares` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// The range of component `p` is `[1, 20]`.
fn claim(p: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `896`
// Estimated: `16164`
// Minimum execution time: 754_086_000 picoseconds.
Weight::from_parts(756_147_000, 0)
.saturating_add(Weight::from_parts(0, 16164))
.saturating_add(RocksDbWeight::get().reads(17))
.saturating_add(RocksDbWeight::get().writes(29))
// Measured: `283`
// Estimated: `3748`
// Minimum execution time: 216_452_000 picoseconds.
Weight::from_parts(217_152_474, 0)
.saturating_add(Weight::from_parts(0, 3748))
// Standard Error: 17_182
.saturating_add(Weight::from_parts(1_614_265, 0).saturating_mul(p.into()))
.saturating_add(RocksDbWeight::get().reads(4))
.saturating_add(RocksDbWeight::get().writes(4))
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-networks"
version = "0.2.8"
version = "0.2.9"
description = "Registry and lifecycle management for external network metadata and cryptographic profiles."
license.workspace = true
authors.workspace = true

View File

@ -16,7 +16,7 @@
//! Autogenerated weights for `ghost_networks`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2026-02-26, 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`
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
@ -30,6 +30,7 @@
// --repeat=20
// --pallet=ghost_networks
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --header=./file_header.txt
// --output=./runtime/casper/src/weights/ghost_networks.rs
@ -57,10 +58,8 @@ pub trait WeightInfo {
fn update_network_type() -> Weight;
fn update_network_curve() -> Weight;
fn update_network_gatekeeper() -> Weight;
fn update_network_topic_name() -> Weight;
fn update_incoming_network_share() -> Weight;
fn update_outgoing_network_share() -> Weight;
fn update_avg_block_speed() -> Weight;
fn remove_network() -> Weight;
}
@ -69,48 +68,53 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NetworkIndexes` (r:1 w:1)
/// Proof: `GhostNetworks::NetworkIndexes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// The range of component `i` is `[1, 20]`.
/// The range of component `j` is `[1, 150]`.
/// The range of component `k` is `[1, 20]`.
fn register_network(_i: u32, j: u32, k: u32, ) -> Weight {
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:1)
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NetworkCurvesVec` (r:1 w:1)
/// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// The range of component `i` is `[1, 65]`.
/// The range of component `j` is `[1, 128]`.
/// The range of component `k` is `[1, 10]`.
fn register_network(i: u32, j: u32, k: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `109`
// Estimated: `3574`
// Minimum execution time: 48_419_000 picoseconds.
Weight::from_parts(35_655_823, 0)
.saturating_add(Weight::from_parts(0, 3574))
// Standard Error: 1_212
.saturating_add(Weight::from_parts(96_762, 0).saturating_mul(j.into()))
// Standard Error: 9_235
.saturating_add(Weight::from_parts(1_460_410, 0).saturating_mul(k.into()))
.saturating_add(RocksDbWeight::get().reads(2))
.saturating_add(RocksDbWeight::get().writes(2))
// Measured: `6`
// Estimated: `3471`
// Minimum execution time: 60_167_000 picoseconds.
Weight::from_parts(56_015_384, 0)
.saturating_add(Weight::from_parts(0, 3471))
// Standard Error: 1_219
.saturating_add(Weight::from_parts(6_146, 0).saturating_mul(i.into()))
// Standard Error: 617
.saturating_add(Weight::from_parts(37_564, 0).saturating_mul(j.into()))
// Standard Error: 8_216
.saturating_add(Weight::from_parts(864_641, 0).saturating_mul(k.into()))
.saturating_add(RocksDbWeight::get().reads(4))
.saturating_add(RocksDbWeight::get().writes(4))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `n` is `[1, 20]`.
fn update_network_selector() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 48_422_000 picoseconds.
Weight::from_parts(49_987_541, 0)
.saturating_add(Weight::from_parts(0, 3804))
// Measured: `166`
// Estimated: `3631`
// Minimum execution time: 43_957_000 picoseconds.
Weight::from_parts(44_541_000, 0)
.saturating_add(Weight::from_parts(0, 3631))
.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`)
/// The range of component `n` is `[1, 150]`.
/// The range of component `n` is `[1, 128]`.
fn update_network_endpoint(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 48_651_000 picoseconds.
Weight::from_parts(50_776_912, 0)
.saturating_add(Weight::from_parts(0, 3804))
// Standard Error: 1_062
.saturating_add(Weight::from_parts(838, 0).saturating_mul(n.into()))
// Measured: `166`
// Estimated: `3631`
// Minimum execution time: 44_092_000 picoseconds.
Weight::from_parts(45_181_439, 0)
.saturating_add(Weight::from_parts(0, 3631))
// Standard Error: 402
.saturating_add(Weight::from_parts(16_387, 0).saturating_mul(n.into()))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
@ -118,11 +122,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_finality_delay() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 48_080_000 picoseconds.
Weight::from_parts(51_781_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
// Measured: `166`
// Estimated: `3631`
// Minimum execution time: 45_603_000 picoseconds.
Weight::from_parts(46_116_000, 0)
.saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
@ -130,11 +134,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_rate_limit_delay() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 47_950_000 picoseconds.
Weight::from_parts(48_925_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
// Measured: `166`
// Estimated: `3631`
// Minimum execution time: 45_607_000 picoseconds.
Weight::from_parts(46_615_000, 0)
.saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
@ -142,11 +146,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_block_deviation() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 48_324_000 picoseconds.
Weight::from_parts(50_801_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
// Measured: `166`
// Estimated: `3631`
// Minimum execution time: 43_510_000 picoseconds.
Weight::from_parts(43_840_000, 0)
.saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
@ -154,38 +158,39 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_type() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 46_962_000 picoseconds.
Weight::from_parts(47_729_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
// Measured: `166`
// Estimated: `3631`
// Minimum execution time: 43_737_000 picoseconds.
Weight::from_parts(44_347_000, 0)
.saturating_add(Weight::from_parts(0, 3631))
.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`)
/// Storage: `GhostNetworks::NetworkCurves` (r:2 w:2)
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NetworkCurvesVec` (r:1 w:1)
/// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn update_network_curve() -> Weight {
Default::default()
// Proof Size summary in bytes:
// Measured: `179`
// Estimated: `6119`
// Minimum execution time: 85_784_000 picoseconds.
Weight::from_parts(86_768_000, 0)
.saturating_add(Weight::from_parts(0, 6119))
.saturating_add(RocksDbWeight::get().reads(4))
.saturating_add(RocksDbWeight::get().writes(4))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_network_gatekeeper() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 48_728_000 picoseconds.
Weight::from_parts(53_054_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
.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_topic_name() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 48_632_000 picoseconds.
Weight::from_parts(49_954_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
// Measured: `166`
// Estimated: `3631`
// Minimum execution time: 44_801_000 picoseconds.
Weight::from_parts(45_240_000, 0)
.saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
@ -193,11 +198,11 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_incoming_network_share() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 47_660_000 picoseconds.
Weight::from_parts(53_763_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
// Measured: `166`
// Estimated: `3631`
// Minimum execution time: 45_404_000 picoseconds.
Weight::from_parts(46_161_000, 0)
.saturating_add(Weight::from_parts(0, 3631))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
@ -205,38 +210,30 @@ impl WeightInfo for () {
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn update_outgoing_network_share() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 48_164_000 picoseconds.
Weight::from_parts(48_953_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
// Measured: `166`
// Estimated: `3631`
// Minimum execution time: 45_476_000 picoseconds.
Weight::from_parts(46_312_000, 0)
.saturating_add(Weight::from_parts(0, 3631))
.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_avg_block_speed() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 47_789_000 picoseconds.
Weight::from_parts(52_131_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
}
/// Storage: `GhostNetworks::NetworkCurves` (r:1 w:1)
/// Proof: `GhostNetworks::NetworkCurves` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NetworkIndexes` (r:1 w:1)
/// Proof: `GhostNetworks::NetworkIndexes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::Networks` (r:1 w:1)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NetworkCurvesVec` (r:1 w:1)
/// Proof: `GhostNetworks::NetworkCurvesVec` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn remove_network() -> Weight {
// Proof Size summary in bytes:
// Measured: `339`
// Estimated: `3804`
// Minimum execution time: 49_720_000 picoseconds.
Weight::from_parts(50_526_000, 0)
.saturating_add(Weight::from_parts(0, 3804))
.saturating_add(RocksDbWeight::get().reads(2))
.saturating_add(RocksDbWeight::get().writes(2))
// Measured: `179`
// Estimated: `3644`
// Minimum execution time: 78_480_000 picoseconds.
Weight::from_parts(79_105_000, 0)
.saturating_add(Weight::from_parts(0, 3644))
.saturating_add(RocksDbWeight::get().reads(4))
.saturating_add(RocksDbWeight::get().writes(4))
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-nomination-pools"
version = "25.0.0"
version = "25.0.1"
authors.workspace = true
edition.workspace = true
license = "Apache-2.0"

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-sudo"
version = "0.0.2"
version = "0.0.3"
description = "Port of the sudo pallet because of dependencies issue"
license.workspace = true
authors.workspace = true

View File

@ -16,7 +16,7 @@
//! Autogenerated weights for `ghost_sudo`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2025-07-28, 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`
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
@ -28,7 +28,7 @@
// --chain=casper-dev
// --steps=50
// --repeat=20
// --pallet=ghost-sudo
// --pallet=ghost_sudo
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
@ -61,10 +61,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn set_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Measured: `98`
// Estimated: `1517`
// Minimum execution time: 40_014_000 picoseconds.
Weight::from_parts(40_856_000, 0)
// Minimum execution time: 38_841_000 picoseconds.
Weight::from_parts(39_982_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
@ -73,10 +73,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Measured: `98`
// Estimated: `1517`
// Minimum execution time: 44_086_000 picoseconds.
Weight::from_parts(45_920_000, 0)
// Minimum execution time: 42_412_000 picoseconds.
Weight::from_parts(43_446_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
}
@ -84,10 +84,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Measured: `98`
// Estimated: `1517`
// Minimum execution time: 44_106_000 picoseconds.
Weight::from_parts(44_650_000, 0)
// Minimum execution time: 43_006_000 picoseconds.
Weight::from_parts(43_886_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
}
@ -95,10 +95,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn remove_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Measured: `98`
// Estimated: `1517`
// Minimum execution time: 36_416_000 picoseconds.
Weight::from_parts(37_373_000, 0)
// Minimum execution time: 35_731_000 picoseconds.
Weight::from_parts(36_443_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
@ -111,10 +111,10 @@ impl WeightInfo for () {
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn set_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Measured: `98`
// Estimated: `1517`
// Minimum execution time: 40_014_000 picoseconds.
Weight::from_parts(40_856_000, 0)
// Minimum execution time: 38_841_000 picoseconds.
Weight::from_parts(39_982_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))
@ -123,10 +123,10 @@ impl WeightInfo for () {
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Measured: `98`
// Estimated: `1517`
// Minimum execution time: 44_086_000 picoseconds.
Weight::from_parts(45_920_000, 0)
// Minimum execution time: 42_412_000 picoseconds.
Weight::from_parts(43_446_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(RocksDbWeight::get().reads(1))
}
@ -134,10 +134,10 @@ impl WeightInfo for () {
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn sudo_as() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Measured: `98`
// Estimated: `1517`
// Minimum execution time: 44_106_000 picoseconds.
Weight::from_parts(44_650_000, 0)
// Minimum execution time: 43_006_000 picoseconds.
Weight::from_parts(43_886_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(RocksDbWeight::get().reads(1))
}
@ -145,10 +145,10 @@ impl WeightInfo for () {
/// Proof: `GhostSudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn remove_key() -> Weight {
// Proof Size summary in bytes:
// Measured: `165`
// Measured: `98`
// Estimated: `1517`
// Minimum execution time: 36_416_000 picoseconds.
Weight::from_parts(37_373_000, 0)
// Minimum execution time: 35_731_000 picoseconds.
Weight::from_parts(36_443_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(RocksDbWeight::get().reads(1))
.saturating_add(RocksDbWeight::get().writes(1))

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-traits"
version = "0.4.3"
version = "0.4.4"
description = "Shared traits including `GhostHasher`, `NetworkDataBasicHandler`, `BoundedBTreeMap`, `MerkleTree` and more."
license.workspace = true
authors.workspace = true

View File

@ -118,3 +118,11 @@ pub trait MerkleTreeBuilder<A, E>: IdentifierConverter<A, E> {
authority_index: A,
) -> Result<(), E>;
}
pub trait EvmGovernanceRegistrar<NetworkId, EvmAddress, GovernanceAction> {
fn register_evm_governance_action(
network_id: NetworkId,
target_address: EvmAddress,
governance_action: GovernanceAction
) -> frame_support::dispatch::DispatchResult;
}

View File

@ -1,8 +0,0 @@
[package]
name = "ghost-types"
version = "0.0.1"
license.workspace = true
authors.workspace = true
edition.workspace = true
homepage.workspace = true
repository.workspace = true

View File

@ -1 +0,0 @@
pub

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-weaver"
version = "0.0.2"
version = "0.0.3"
description = "Weaving a secure cryptographic tapestry across different external chains."
license.workspace = true
authors.workspace = true

View File

@ -3,6 +3,7 @@
use super::*;
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;
use sp_runtime::AccountId32;
use sp_std::vec;
use ghost_helpers::networks::NetworkDataBuilder;
@ -135,40 +136,17 @@ mod benchmarks {
#[benchmark]
fn pull_utxo_thread(
a: Linear<1, { T::MaxAuthorities::get() as u32 }>,
a: Linear<1, { crate::types::UTXO_MAX_HISTORY_DEPTH }>,
) -> Result<(), BenchmarkError> {
let session = 69;
let max_history_depth = a as usize;
let (network_id, _, _) = prepare_pallet::<T>(1);
// https://blockstream.info/tx/6fdcb55eaeddae87fdbbd3e6fd8c2b80c1e7e7c1214e1a6e35c06a70e5f21fba?expand
// NOTE: this is the best transaction that matches the max sizes I found,
// would be nice to find exact edge case
let root_string =
hex::decode("00000000000000000000662f626dbc3c06161a324d879fadcd0293d8e0884a1d")
.expect("Bitcoin Root hex should be valid");
let expected_root = H256::from_slice(&root_string);
LoomStates::<T>::insert(&network_id, &session, expected_root);
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 = sp_runtime::AccountId32::from(receiver_32);
let transfer_amount: BalanceOf<T> = 140_693u64.unique_saturated_into();
let payload = ThreadPayload::new(12, transfer_amount, receiver_account);
let utxo_thread_proof = UtxoThreadProof::new(
1,
0,
transfer_amount,
payload,
hex::decode("008008201643a05d24fe1f015bf472fdedd8ef39dd8247568d3901000000000000000000569ac8f0aed0c5b632dd1dcc031f3d826a170e13cd8176430a2873a33d4694c2501f6a6ad43a02178dbac0d66b1600000e88be94dbcedc3f32bce789eb4512c68b39b91b54c4f2913e84baf7bae21bdc466d954b10876c1e8ad6591461027236c9a471883f96c028a7d1f08deb833f56fa18f457a6faa9c41340be484af67e444f8565b03085e1392fa2d56962f89919c4fcfff99fc6e92be067d01028fb54e8dc1e8425f0ef6bf1cc64220a2ba22163666eb01f99648e8c2af1bb1a0e1ba297f0244a09aa6a6ff87092312b02e8d75aef61e5c08f5b59184a45855e987c5ea114e5da61e55337bfae99f3a2e9601e72ae6036633dc97631609813a30d1185f98e7d6effc4a0330db0394da388c0058e9a730a62d8c679c35bf8d270ca8b95cec7d848729cdfd94a284f060f353b379bfc36310ac78306183a056a04156efd7e77661ce7ba50a4ef9f9e6b3681dfb39d8d0161ad0d2ec46834b5f270b67aa63a8a5b69287e8606b8a438785f8a5af66f84a2641438ba4a5fa22029227e9c2ddb6f23867b112c027d2fc2cf031a46c874701768b5c4983959b98d98736a2ed5ab0dd064ee24e49a3a7dac63e8b857ad4c8b5aa0cf22a7eac3180f3a54630b486de928ecf590e807d2e821818e2fe7e86610187d6673a6f95c639af80a7a7710b0088d44057ca61bdf5f4d5ba68d46b88e4304ffb70000").expect("Bytes32 from UTXO should be valid"),
hex::decode("020000000001029ee4235efd4a3cb183d4c311ce858eeee7748263a28afd3d861bac1cb4a8d368010000000001000000d7c5869bfffaa1877d0ecd37e46dc70c232a16f7955e635d57f926d1b3e640bf0100000000ffffffff02ff490b0000000000160014f635b17877709ba3c5acbe153f38a47a733f5b169525020000000000160014c6e4e0f822c31540b4b05903ce3c67b6cff8e6d40247304402200f2f3763fad59d38b4e101b9675450c0a54d45fe17e2b1babde0d0ce6051ea5b0220643e71d66752c0f1bd30dc0897305da77f223d14c781e86063ac181ad7fb90b6012102aad4cca3dab6427bc754a5a123de32cd037e7177fade9f72d83088b00066cffc0247304402200c8f1ff8230813e5e4ab8ec802c614bc8705c407c5958d64dd79cc8422d85a6202203ea832d581c404200b5974fd1a11abfe1ebac213842083cb02eba3f253c8c2aa012102d70df1d4d58701adab82b4816e0640c27403d1fab859ca9f47cb6eccca3dd96200000000").expect("Bytes32 from UTXO should be valid"),
vec![
let historical_hashes = vec![
hex::decode("00a01520c1d508977a3787523a0f959e14a8df763dc87927c7910000000000000000000036303f2bcf94f752a1d4b0641d1adbc2d80aa89628feefd7f837a74792e26ab8bb276a6ad43a0217bece2e64").expect("Bytes32 from UTXO should be valid"),
hex::decode("0400e020702ff95ecc1b8575cff205bfc24592c87ba09280bd84000000000000000000008ca9c40d5ab762f160661635cade50fd14571dcf5fdf8c463b617caf9b07dc5a3b296a6ad43a02171340d661").expect("Bytes32 from UTXO should be valid"),
hex::decode("000000345457ca4006ddc376db24b7a37db04dfa0b46c1d99267010000000000000000009409d64eb06a6dd83ae2937f70d07222d75505a07f12e756b61a27189851e3bbfe2c6a6ad43a0217a06575b5").expect("Bytes32 from UTXO should be valid"),
@ -313,7 +291,49 @@ mod benchmarks {
hex::decode("00e02c3ade01a429e0f5c328824f4ee063b98f24ff3b0dc0db08000000000000000000009d0b402f41ab9c16e08f95de962044b206413f878608abca2015ee2074713078606d6b6ad43a0217c0650150").expect("Bytes32 from UTXO should be valid"),
hex::decode("00008f2604b952dcd44dfcb61080ad77c5b626efd760e5f8ac8401000000000000000000ee81697e6cf7f41db37b63a9680906d3023be7a905785ef1b5ebd03fd22dd8bb2d6f6b6ad43a0217287aa17f").expect("Bytes32 from UTXO should be valid"),
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
.iter()
.take(max_history_depth)
.cloned()
.collect();
let gettxproof_bytes = hex::decode("008008201643a05d24fe1f015bf472fdedd8ef39dd8247568d3901000000000000000000569ac8f0aed0c5b632dd1dcc031f3d826a170e13cd8176430a2873a33d4694c2501f6a6ad43a02178dbac0d66b1600000e88be94dbcedc3f32bce789eb4512c68b39b91b54c4f2913e84baf7bae21bdc466d954b10876c1e8ad6591461027236c9a471883f96c028a7d1f08deb833f56fa18f457a6faa9c41340be484af67e444f8565b03085e1392fa2d56962f89919c4fcfff99fc6e92be067d01028fb54e8dc1e8425f0ef6bf1cc64220a2ba22163666eb01f99648e8c2af1bb1a0e1ba297f0244a09aa6a6ff87092312b02e8d75aef61e5c08f5b59184a45855e987c5ea114e5da61e55337bfae99f3a2e9601e72ae6036633dc97631609813a30d1185f98e7d6effc4a0330db0394da388c0058e9a730a62d8c679c35bf8d270ca8b95cec7d848729cdfd94a284f060f353b379bfc36310ac78306183a056a04156efd7e77661ce7ba50a4ef9f9e6b3681dfb39d8d0161ad0d2ec46834b5f270b67aa63a8a5b69287e8606b8a438785f8a5af66f84a2641438ba4a5fa22029227e9c2ddb6f23867b112c027d2fc2cf031a46c874701768b5c4983959b98d98736a2ed5ab0dd064ee24e49a3a7dac63e8b857ad4c8b5aa0cf22a7eac3180f3a54630b486de928ecf590e807d2e821818e2fe7e86610187d6673a6f95c639af80a7a7710b0088d44057ca61bdf5f4d5ba68d46b88e4304ffb70000").expect("Bytes32 from UTXO should be valid");
let dynamic_trusted_root = if ancestry_headers_vec.is_empty() {
let first_sha = sp_io::hashing::sha2_256(&gettxproof_bytes[..80]);
let mut native_le = sp_io::hashing::sha2_256(&first_sha);
native_le.reverse();
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);
let payload = ThreadPayload::new(12, transfer_amount, receiver_account);
let utxo_thread_proof = UtxoThreadProof::new(
1,
0,
transfer_amount,
payload,
gettxproof_bytes,
hex::decode("020000000001029ee4235efd4a3cb183d4c311ce858eeee7748263a28afd3d861bac1cb4a8d368010000000001000000d7c5869bfffaa1877d0ecd37e46dc70c232a16f7955e635d57f926d1b3e640bf0100000000ffffffff02ff490b0000000000160014f635b17877709ba3c5acbe153f38a47a733f5b169525020000000000160014c6e4e0f822c31540b4b05903ce3c67b6cff8e6d40247304402200f2f3763fad59d38b4e101b9675450c0a54d45fe17e2b1babde0d0ce6051ea5b0220643e71d66752c0f1bd30dc0897305da77f223d14c781e86063ac181ad7fb90b6012102aad4cca3dab6427bc754a5a123de32cd037e7177fade9f72d83088b00066cffc0247304402200c8f1ff8230813e5e4ab8ec802c614bc8705c407c5958d64dd79cc8422d85a6202203ea832d581c404200b5974fd1a11abfe1ebac213842083cb02eba3f253c8c2aa012102d70df1d4d58701adab82b4816e0640c27403d1fab859ca9f47cb6eccca3dd96200000000").expect("Bytes32 from UTXO should be valid"),
ancestry_headers_vec,
);
let thread_proof = ThreadProof::UtxoThreadProof(utxo_thread_proof);

View File

@ -306,7 +306,9 @@ pub mod pallet {
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight((
T::WeightInfo::extend_warp(),
T::WeightInfo::extend_warp(
Authorities::<T>::decode_len().unwrap_or(1) as u32,
),
DispatchClass::Normal,
Pays::No,
))]
@ -359,7 +361,9 @@ pub mod pallet {
#[pallet::call_index(1)]
#[pallet::weight((
T::WeightInfo::weave_weft(),
T::WeightInfo::weave_weft(
Authorities::<T>::decode_len().unwrap_or(1) as u32,
),
DispatchClass::Normal,
Pays::No,
))]
@ -415,7 +419,9 @@ pub mod pallet {
#[pallet::call_index(2)]
#[pallet::weight((
match &thread_proof {
ThreadProof::UtxoThreadProof(_) => T::WeightInfo::pull_utxo_thread(),
ThreadProof::UtxoThreadProof(thread) => T::WeightInfo::pull_utxo_thread(
thread.ancestry_headers_len(),
),
ThreadProof::EvmThreadProof(_) => T::WeightInfo::pull_evm_thread(),
},
DispatchClass::Normal,

View File

@ -21,11 +21,16 @@ use crate::{ExternalBlockNumber, ThreadId, WeavingSession};
const EVM_MERKLE_DEPTH: u32 = 8;
const EVM_VALUES_DEPTH: u32 = 8;
const UTXO_MAX_HISTORY_DEPTH_VALUE: u32 = 144;
const UTXO_MAX_PROOF_BYTES: u32 = 1024;
const UTXO_MAX_HEADER_BYTES: u32 = 80;
const UTXO_MAX_HISTORY_DEPTH: u32 = 144;
const UTXO_MAX_TX_BYTES: u32 = ghost_helpers::utxo::MAX_TX_LEN as u32;
#[cfg(not(feature = "runtime-benchmarks"))]
const UTXO_MAX_HISTORY_DEPTH: u32 = UTXO_MAX_HISTORY_DEPTH_VALUE;
#[cfg(feature = "runtime-benchmarks")]
pub const UTXO_MAX_HISTORY_DEPTH: u32 = UTXO_MAX_HISTORY_DEPTH_VALUE;
pub enum WeavingOk<NetworkId> {
Block(ExternalBlockNumber, NetworkId),
Hash(ExternalBlockNumber, H256, WeavingSession, NetworkId),
@ -474,6 +479,9 @@ impl<Balance> UtxoThreadProof<Balance>
where
Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>,
{
pub fn ancestry_headers_len(&self) -> u32 {
self.ancestry_headers.len() as u32
}
pub fn amount(&self) -> Balance {
self.expected_amount
}
@ -487,9 +495,7 @@ where
pub fn verify_proof(&self, root_hash: H256, gatekeeper_ref: &[u8]) -> Option<AccountId32> {
use ghost_helpers::utxo::{Header, Transaction};
if self.gettxproof_bytes.len() < 85 {
return None;
}
if self.gettxproof_bytes.len() < 85 { return None; }
let header_bytes = &self.gettxproof_bytes[..80];
let is_chain_valid = verify_hash_ancestry::<UtxoSha2Hasher, _>(
@ -497,9 +503,8 @@ where
self.ancestry_headers.iter(),
root_hash,
);
if !is_chain_valid {
return None;
}
if !is_chain_valid { return None; }
let transaction =
Transaction::<UtxoSha2Hasher>::try_from(self.getrawtransaction_bytes.as_ref()).ok()?;

View File

@ -1,23 +1,152 @@
use frame_support::weights::Weight;
// This file is part of Ghost Network.
// Ghost Network is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Ghost Network is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Ghost Network. If not, see <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `ghost_weaver`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2026-09-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `ghostown`, CPU: `Intel(R) Core(TM) i3-2310M CPU @ 2.10GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("casper-dev")`, DB CACHE: 1024
// Executed Command:
// ./target/release/ghost
// benchmark
// pallet
// --chain=casper-dev
// --steps=50
// --repeat=20
// --pallet=ghost_weaver
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --header=./file_header.txt
// --output=./runtime/casper/src/weights/ghost_weaver.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
use frame_support::{
traits::Get,
weights::{Weight, constants::RocksDbWeight},
};
use core::marker::PhantomData;
pub trait WeightInfo {
fn extend_warp() -> Weight;
fn weave_weft() -> Weight;
fn extend_warp(a: u32,) -> Weight;
fn weave_weft(a: u32,) -> Weight;
fn pull_evm_thread() -> Weight;
fn pull_utxo_thread() -> Weight;
fn pull_utxo_thread(a: u32) -> Weight;
}
impl WeightInfo for () {
fn extend_warp() -> Weight {
Default::default()
/// Storage: `GhostWeaver::DisabledAuthorities` (r:1 w:0)
/// Proof: `GhostWeaver::DisabledAuthorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::Authorities` (r:1 w:0)
/// Proof: `GhostWeaver::Authorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::TapestryDrafts` (r:1 w:0)
/// Proof: `GhostWeaver::TapestryDrafts` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::NetworkAttestations` (r:1 w:1)
/// Proof: `GhostWeaver::NetworkAttestations` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `a` is `[1, 300]`.
fn extend_warp(a: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `223 + a * (32 ±0)`
// Estimated: `3687 + a * (32 ±0)`
// Minimum execution time: 215_336_000 picoseconds.
Weight::from_parts(218_119_120, 0)
.saturating_add(Weight::from_parts(0, 3687))
// Standard Error: 1_412
.saturating_add(Weight::from_parts(47_848, 0).saturating_mul(a.into()))
.saturating_add(RocksDbWeight::get().reads(5))
.saturating_add(RocksDbWeight::get().writes(1))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
}
fn weave_weft() -> Weight {
Default::default()
/// Storage: `GhostWeaver::DisabledAuthorities` (r:1 w:0)
/// Proof: `GhostWeaver::DisabledAuthorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::Authorities` (r:1 w:0)
/// Proof: `GhostWeaver::Authorities` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::TapestryDrafts` (r:1 w:0)
/// Proof: `GhostWeaver::TapestryDrafts` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::TapestryStrands` (r:1 w:1)
/// Proof: `GhostWeaver::TapestryStrands` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::WeavingStates` (r:1 w:1)
/// Proof: `GhostWeaver::WeavingStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `a` is `[1, 300]`.
fn weave_weft(a: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `518 + a * (32 ±0)`
// Estimated: `3982 + a * (32 ±0)`
// Minimum execution time: 244_811_000 picoseconds.
Weight::from_parts(250_046_200, 0)
.saturating_add(Weight::from_parts(0, 3982))
// Standard Error: 1_958
.saturating_add(Weight::from_parts(26_347, 0).saturating_mul(a.into()))
.saturating_add(RocksDbWeight::get().reads(6))
.saturating_add(RocksDbWeight::get().writes(2))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(a.into()))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::LoomStates` (r:1 w:0)
/// Proof: `GhostWeaver::LoomStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::PulledThreads` (r:1 w:1)
/// Proof: `GhostWeaver::PulledThreads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::GatekeeperAmounts` (r:1 w:1)
/// Proof: `GhostNetworks::GatekeeperAmounts` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NetworkImbalance` (r:1 w:1)
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:0)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// The range of component `a` is `[1, 300]`.
fn pull_utxo_thread(_a: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `358`
// Estimated: `3823`
// Minimum execution time: 650_006_000 picoseconds.
Weight::from_parts(663_001_690, 0)
.saturating_add(Weight::from_parts(0, 3823))
.saturating_add(RocksDbWeight::get().reads(6))
.saturating_add(RocksDbWeight::get().writes(3))
}
/// Storage: `GhostNetworks::Networks` (r:1 w:0)
/// Proof: `GhostNetworks::Networks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::LoomStates` (r:1 w:0)
/// Proof: `GhostWeaver::LoomStates` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostWeaver::PulledThreads` (r:1 w:1)
/// Proof: `GhostWeaver::PulledThreads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::GatekeeperAmounts` (r:1 w:1)
/// Proof: `GhostNetworks::GatekeeperAmounts` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `GhostNetworks::NetworkImbalance` (r:1 w:1)
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:0)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
fn pull_evm_thread() -> Weight {
Default::default()
}
fn pull_utxo_thread() -> Weight {
Default::default()
// Proof Size summary in bytes:
// Measured: `358`
// Estimated: `3823`
// Minimum execution time: 138_199_000 picoseconds.
Weight::from_parts(162_645_000, 0)
.saturating_add(Weight::from_parts(0, 3823))
.saturating_add(RocksDbWeight::get().reads(6))
.saturating_add(RocksDbWeight::get().writes(3))
}
}

View File

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

View File

@ -1,6 +1,6 @@
[package]
name = "casper-runtime-constants"
version = "0.4.3"
version = "0.4.4"
authors.workspace = true
edition.workspace = true
homepage.workspace = true

View File

@ -37,19 +37,19 @@ use sp_core::parameter_types;
use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight};
parameter_types! {
/// Time to execute an empty block.
/// Calculated by multiplying the *Average* with `1.0` and adding `0`.
///
/// Stats nanoseconds:
/// Min, Max: 1_042_579, 1_101_962
/// Average: 1_054_295
/// Median: 1_051_534
/// Std-Dev: 9476.68
///
/// Percentiles nanoseconds:
/// 99th: 1_091_162
/// 95th: 1_069_117
/// 75th: 1_057_964
// Time to execute an empty block.
// Calculated by multiplying the *Average* with `1.0` and adding `0`.
//
// Stats nanoseconds:
// Min, Max: 1_042_579, 1_101_962
// Average: 1_054_295
// Median: 1_051_534
// Std-Dev: 9476.68
//
// Percentiles nanoseconds:
// 99th: 1_091_162
// 95th: 1_069_117
// 75th: 1_057_964
pub const BlockExecutionWeight: Weight =
Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(1_054_295), 0);
}

View File

@ -37,19 +37,19 @@ use sp_core::parameter_types;
use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight};
parameter_types! {
/// Time to execute a NO-OP extrinsic, for example `System::remark`.
/// Calculated by multiplying the *Average* with `1.0` and adding `0`.
///
/// Stats nanoseconds:
/// Min, Max: 378_590, 384_849
/// Average: 380_658
/// Median: 380_461
/// Std-Dev: 1202.24
///
/// Percentiles nanoseconds:
/// 99th: 383_191
/// 95th: 382_552
/// 75th: 381_384
// Time to execute a NO-OP extrinsic, for example `System::remark`.
// Calculated by multiplying the *Average* with `1.0` and adding `0`.
//
// Stats nanoseconds:
// Min, Max: 378_590, 384_849
// Average: 380_658
// Median: 380_461
// Std-Dev: 1202.24
//
// Percentiles nanoseconds:
// 99th: 383_191
// 95th: 382_552
// 75th: 381_384
pub const ExtrinsicBaseWeight: Weight =
Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(380_658), 0);
}

View File

@ -45,34 +45,34 @@ pub mod constants {
/// `ParityDB` can be enabled with a feature flag, but is still experimental. These weights
/// are available for brave runtime engineers who may want to try this out as default.
pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight {
/// Time to read one storage item.
/// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`.
///
/// Stats nanoseconds:
/// Min, Max: 3_485, 2_000_385
/// Average: 26_775
/// Median: 4_870
/// Std-Dev: 205784.16
///
/// Percentiles nanoseconds:
/// 99th: 2_000_385
/// 95th: 6_002
/// 75th: 5_246
// Time to read one storage item.
// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`.
//
// Stats nanoseconds:
// Min, Max: 3_485, 2_000_385
// Average: 26_775
// Median: 4_870
// Std-Dev: 205784.16
//
// Percentiles nanoseconds:
// 99th: 2_000_385
// 95th: 6_002
// 75th: 5_246
read: 29_453 * constants::WEIGHT_REF_TIME_PER_NANOS,
/// Time to write one storage item.
/// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`.
///
/// Stats nanoseconds:
/// Min, Max: 16_322, 25_965_124
/// Average: 308_302
/// Median: 29_481
/// Std-Dev: 2674917.65
///
/// Percentiles nanoseconds:
/// 99th: 25_965_124
/// 95th: 42_210
/// 75th: 33_525
// Time to write one storage item.
// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`.
//
// Stats nanoseconds:
// Min, Max: 16_322, 25_965_124
// Average: 308_302
// Median: 29_481
// Std-Dev: 2674917.65
//
// Percentiles nanoseconds:
// 99th: 25_965_124
// 95th: 42_210
// 75th: 33_525
write: 339_133 * constants::WEIGHT_REF_TIME_PER_NANOS,
};
}

View File

@ -44,34 +44,34 @@ pub mod constants {
/// By default, Substrate uses `RocksDB`, so this will be the weight used throughout
/// the runtime.
pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight {
/// Time to read one storage item.
/// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`.
///
/// Stats nanoseconds:
/// Min, Max: 6_726, 2_902_682
/// Average: 41_735
/// Median: 10_059
/// Std-Dev: 298297.77
///
/// Percentiles nanoseconds:
/// 99th: 2_902_682
/// 95th: 14_199
/// 75th: 11_422
// Time to read one storage item.
// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`.
//
// Stats nanoseconds:
// Min, Max: 6_726, 2_902_682
// Average: 41_735
// Median: 10_059
// Std-Dev: 298297.77
//
// Percentiles nanoseconds:
// 99th: 2_902_682
// 95th: 14_199
// 75th: 11_422
read: 45_909 * constants::WEIGHT_REF_TIME_PER_NANOS,
/// Time to write one storage item.
/// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`.
///
/// Stats nanoseconds:
/// Min, Max: 31_214, 45_912_915
/// Average: 545_878
/// Median: 51_543
/// Std-Dev: 4729852.98
///
/// Percentiles nanoseconds:
/// 99th: 45_912_915
/// 95th: 68_658
/// 75th: 58_683
// Time to write one storage item.
// Calculated by multiplying the *Average* of all values with `1.1` and adding `0`.
//
// Stats nanoseconds:
// Min, Max: 31_214, 45_912_915
// Average: 545_878
// Median: 51_543
// Std-Dev: 4729852.98
//
// Percentiles nanoseconds:
// 99th: 45_912_915
// 95th: 68_658
// 75th: 58_683
write: 600_466 * constants::WEIGHT_REF_TIME_PER_NANOS,
};
}

View File

@ -131,7 +131,7 @@ impl<T: frame_system::Config> ghost_weaver::WeightInfo for WeightInfo<T> {
/// Proof: `GhostNetworks::NetworkImbalance` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:0)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
fn pull_evm_thread() -> Weight {
fn pull_evm_thread(_a: u32) -> Weight {
// Proof Size summary in bytes:
// Measured: `358`
// Estimated: `3823`

View File

@ -67,7 +67,7 @@ impl<T: frame_system::Config> pallet_babe::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().writes((6_u64).saturating_mul(max_nominators_per_validator.into())))
.saturating_add(Weight::from_parts(0, 3774).saturating_mul(max_nominators_per_validator.into()));
/// The range of component `x` is `[0, 1]`.
// The range of component `x` is `[0, 1]`.
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`