forked from ghostchain/ghost-node
make exodus to change gatekeeped amount after bridge out
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
This commit is contained in:
parent
5243bd7c3d
commit
2387a2fe32
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-exodus"
|
||||
version = "0.0.3"
|
||||
version = "0.0.4"
|
||||
description = "Threshold signature generation with DKG included"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -46,7 +46,7 @@ use ghost_traits::{
|
||||
},
|
||||
exodus::{
|
||||
MerkleTreeBuilder, DistributedKeyGeneration, EllipticCurveDiffieHellman,
|
||||
FlexibleRoundOptimizedSchnorrThresholdSignature,
|
||||
FlexibleRoundOptimizedSchnorrThresholdSignature, EvmGovernanceRegistrar,
|
||||
},
|
||||
networks::{
|
||||
NetworkDataBasicHandler, NetworkDataInspectHandler,
|
||||
@ -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>>,
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user