mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-03 09:29:46 +00:00
add oraclize values tests
This commit is contained in:
parent
06bfd5b6a3
commit
78983b28af
4 changed files with 141 additions and 8 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -8199,8 +8199,11 @@ dependencies = [
|
||||||
name = "serai-genesis-liquidity-pallet"
|
name = "serai-genesis-liquidity-pallet"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ciphersuite",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
|
"frost-schnorrkel",
|
||||||
|
"modular-frost",
|
||||||
"pallet-babe",
|
"pallet-babe",
|
||||||
"pallet-grandpa",
|
"pallet-grandpa",
|
||||||
"pallet-timestamp",
|
"pallet-timestamp",
|
||||||
|
@ -8219,6 +8222,7 @@ dependencies = [
|
||||||
"sp-io",
|
"sp-io",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"sp-std",
|
"sp-std",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -47,6 +47,11 @@ pallet-timestamp = { git = "https://github.com/serai-dex/substrate", default-fea
|
||||||
sp-io = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
sp-io = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||||
|
|
||||||
|
ciphersuite = { path = "../../../crypto/ciphersuite", features = ["ristretto"] }
|
||||||
|
frost = { package = "modular-frost", path = "../../../crypto/frost", features = ["tests"] }
|
||||||
|
schnorrkel = { path = "../../../crypto/schnorrkel", package = "frost-schnorrkel" }
|
||||||
|
|
||||||
|
zeroize = "^1.5"
|
||||||
rand_core = "0.6"
|
rand_core = "0.6"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -437,9 +437,7 @@ pub mod pallet {
|
||||||
Err(InvalidTransaction::Custom(1))?;
|
Err(InvalidTransaction::Custom(1))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure signers settings the value at the end of the genesis period.
|
// check we waited for a month before setting the values
|
||||||
// we don't need this check for tests.
|
|
||||||
#[cfg(not(feature = "fast-epoch"))]
|
|
||||||
if <frame_system::Pallet<T>>::block_number().saturated_into::<u64>() < MONTHS {
|
if <frame_system::Pallet<T>>::block_number().saturated_into::<u64>() < MONTHS {
|
||||||
Err(InvalidTransaction::Custom(2))?;
|
Err(InvalidTransaction::Custom(2))?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,28 @@
|
||||||
use crate::{mock::*, primitives::*};
|
use crate::{mock::*, pallet, primitives::*};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use ciphersuite::{Ciphersuite, Ristretto};
|
||||||
|
use frost::dkg::musig::musig;
|
||||||
|
use schnorrkel::Schnorrkel;
|
||||||
|
|
||||||
use rand_core::{RngCore, OsRng};
|
use rand_core::{RngCore, OsRng};
|
||||||
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use frame_system::RawOrigin;
|
use frame_system::RawOrigin;
|
||||||
use frame_support::{assert_noop, assert_ok, traits::Hooks};
|
use frame_support::{
|
||||||
|
assert_noop, assert_ok,
|
||||||
|
pallet_prelude::{TransactionSource, InvalidTransaction},
|
||||||
|
traits::Hooks,
|
||||||
|
};
|
||||||
|
|
||||||
use sp_core::Pair;
|
use sp_core::{
|
||||||
use sp_runtime::BoundedVec;
|
sr25519::{Pair, Signature},
|
||||||
|
Pair as PairTrait,
|
||||||
|
};
|
||||||
|
use sp_runtime::{traits::ValidateUnsigned, BoundedVec};
|
||||||
|
|
||||||
use validator_sets_primitives::{ValidatorSet, Session, KeyPair};
|
use validator_sets_primitives::{ValidatorSet, Session, KeyPair, musig_context};
|
||||||
use serai_primitives::*;
|
use serai_primitives::*;
|
||||||
|
|
||||||
fn set_up_genesis(
|
fn set_up_genesis(
|
||||||
|
@ -139,6 +151,56 @@ fn make_networks_reach_economic_security(block_number: u64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn oraclize_values_signature(set: ValidatorSet, values: &Values, pairs: &[Pair]) -> Signature {
|
||||||
|
let mut pub_keys = vec![];
|
||||||
|
for pair in pairs {
|
||||||
|
let public_key =
|
||||||
|
<Ristretto as Ciphersuite>::read_G::<&[u8]>(&mut pair.public().0.as_ref()).unwrap();
|
||||||
|
pub_keys.push(public_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut threshold_keys = vec![];
|
||||||
|
for i in 0 .. pairs.len() {
|
||||||
|
let secret_key = <Ristretto as Ciphersuite>::read_F::<&[u8]>(
|
||||||
|
&mut pairs[i].as_ref().secret.to_bytes()[.. 32].as_ref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(Ristretto::generator() * secret_key, pub_keys[i]);
|
||||||
|
|
||||||
|
threshold_keys.push(
|
||||||
|
musig::<Ristretto>(&musig_context(set), &Zeroizing::new(secret_key), &pub_keys).unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut musig_keys = HashMap::new();
|
||||||
|
for tk in threshold_keys {
|
||||||
|
musig_keys.insert(tk.params().i(), tk.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let sig = frost::tests::sign_without_caching(
|
||||||
|
&mut OsRng,
|
||||||
|
frost::tests::algorithm_machines(&mut OsRng, &Schnorrkel::new(b"substrate"), &musig_keys),
|
||||||
|
&oraclize_values_message(&set, values),
|
||||||
|
);
|
||||||
|
|
||||||
|
Signature(sig.to_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ordered_keys(network: NetworkId, participants: &[Pair]) -> Vec<Pair> {
|
||||||
|
// retrieve the current session validators so that we know the order of the keys
|
||||||
|
// that is necessary for the correct musig signature.
|
||||||
|
let validators = ValidatorSets::participants_for_latest_decided_set(network).unwrap();
|
||||||
|
|
||||||
|
// collect the pairs of the validators
|
||||||
|
let mut pairs = vec![];
|
||||||
|
for (v, _) in validators {
|
||||||
|
let p = participants.iter().find(|pair| pair.public() == v).unwrap().clone();
|
||||||
|
pairs.push(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
pairs
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn genesis_liquidity() {
|
fn genesis_liquidity() {
|
||||||
new_test_ext().execute_with(|| {
|
new_test_ext().execute_with(|| {
|
||||||
|
@ -332,3 +394,67 @@ fn remove_coin_liquidity_after_genesis_period() {
|
||||||
assert!(Coins::balance(account, coin.into()).0 > account_coin_balance);
|
assert!(Coins::balance(account, coin.into()).0 > account_coin_balance);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_oraclize_values_already_done() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let values = Values { monero: 184100, ether: 4785000, dai: 1500 };
|
||||||
|
|
||||||
|
// set the oraclization
|
||||||
|
GenesisLiquidity::oraclize_values(RawOrigin::None.into(), values, Signature([0u8; 64]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// trying to oraclize again should fail
|
||||||
|
let call = pallet::Call::<Test>::oraclize_values { values, signature: Signature([0u8; 64]) };
|
||||||
|
assert_eq!(
|
||||||
|
GenesisLiquidity::validate_unsigned(TransactionSource::External, &call),
|
||||||
|
InvalidTransaction::Custom(1).into()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_oraclize_values_submit_before_a_month() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let values = Values { monero: 184100, ether: 4785000, dai: 1500 };
|
||||||
|
let call = pallet::Call::<Test>::oraclize_values { values, signature: Signature([0u8; 64]) };
|
||||||
|
|
||||||
|
// we should wait for a month before setting the values
|
||||||
|
assert_eq!(
|
||||||
|
GenesisLiquidity::validate_unsigned(TransactionSource::External, &call),
|
||||||
|
InvalidTransaction::Custom(2).into()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_oraclize_values_invalid_signature() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let genesis_participants = vec![
|
||||||
|
insecure_pair_from_name("Alice"),
|
||||||
|
insecure_pair_from_name("Bob"),
|
||||||
|
insecure_pair_from_name("Charlie"),
|
||||||
|
insecure_pair_from_name("Dave"),
|
||||||
|
insecure_pair_from_name("Eve"),
|
||||||
|
insecure_pair_from_name("Ferdie"),
|
||||||
|
];
|
||||||
|
let network = NetworkId::Serai;
|
||||||
|
let values = Values { monero: 184100, ether: 4785000, dai: 1500 };
|
||||||
|
|
||||||
|
// invalid signature should fail
|
||||||
|
System::set_block_number(MONTHS);
|
||||||
|
let call = pallet::Call::<Test>::oraclize_values { values, signature: Signature([0u8; 64]) };
|
||||||
|
assert_eq!(
|
||||||
|
GenesisLiquidity::validate_unsigned(TransactionSource::External, &call),
|
||||||
|
InvalidTransaction::BadProof.into()
|
||||||
|
);
|
||||||
|
|
||||||
|
let pairs = get_ordered_keys(network, &genesis_participants);
|
||||||
|
let signature =
|
||||||
|
oraclize_values_signature(ValidatorSet { session: Session(0), network }, &values, &pairs);
|
||||||
|
let call = pallet::Call::<Test>::oraclize_values { values, signature };
|
||||||
|
|
||||||
|
// valid signature should pass
|
||||||
|
GenesisLiquidity::validate_unsigned(TransactionSource::External, &call).unwrap();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue