use ark_serialize::CanonicalSerialize;
use codec::{Decode, DecodeWithMemTracking, Encode};
use frame_support::parameter_types;
use pallet_idn_manager::{
primitives::{
CreateSubParams as MngCreateSubParams, Quote as MngQuote, QuoteRequest as MngQuoteRequest,
QuoteSubParams as MngQuoteSubParams, SubInfoRequest as MngSubInfoRequest,
SubInfoResponse as MngSubInfoResponse, SubscriptionMetadata,
},
Subscription as MngSubscription, SubscriptionDetails as MngSubscriptionDetails,
UpdateSubParams as MngUpdateSubParams,
};
use scale_info::TypeInfo;
use sha2::{Digest, Sha256};
use sp_core::crypto::Ss58Codec;
use sp_idn_crypto::prelude::*;
use sp_idn_traits::pulse::Pulse as TPulse;
use sp_runtime::{
traits::{IdentifyAccount, Verify},
MultiSignature, Vec,
};
pub use pallet_idn_manager::{
primitives::{OriginKind, RequestReference, SubscriptionCallData},
SubscriptionState,
};
pub use sp_consensus_randomness_beacon::types::*;
pub mod xcm {
pub use pallet_idn_manager::primitives::{Junction, Junctions, Location};
}
#[derive(Encode, Decode, Debug, Clone, TypeInfo, PartialEq, DecodeWithMemTracking)]
pub struct RuntimePulse {
signature: OpaqueSignature,
start: RoundNumber,
end: RoundNumber,
}
impl Default for RuntimePulse {
fn default() -> Self {
Self { signature: [0; 48], start: 0, end: 0 }
}
}
impl RuntimePulse {
pub fn new(signature: OpaqueSignature, start: RoundNumber, end: RoundNumber) -> Self {
Self { signature, start, end }
}
}
impl TPulse for RuntimePulse {
type Rand = Randomness;
type RoundNumber = RoundNumber;
type Sig = OpaqueSignature;
type Pubkey = OpaquePublicKey;
fn rand(&self) -> Self::Rand {
let mut hasher = Sha256::default();
hasher.update(self.signature);
hasher.finalize().into()
}
fn message(&self) -> Self::Sig {
let msg = (self.start..self.end + 1)
.map(|r| compute_round_on_g1(r).unwrap_or(zero_on_g1()))
.fold(zero_on_g1(), |amsg, val| (amsg + val).into());
let mut bytes = Vec::new();
msg.serialize_compressed(&mut bytes)
.expect("The message should be well formed.");
bytes.try_into().unwrap_or([0u8; 48])
}
fn start(&self) -> Self::RoundNumber {
self.start
}
fn end(&self) -> Self::RoundNumber {
self.end
}
fn sig(&self) -> Self::Sig {
self.signature
}
fn authenticate(&self, pubkey: Self::Pubkey) -> bool {
QuicknetVerifier::verify(
pubkey.as_ref().to_vec(),
self.sig().as_ref().to_vec(),
self.message().as_ref().to_vec(),
)
.is_ok()
}
}
parameter_types! {
pub TreasuryAccount: AccountId =
AccountId::from_ss58check("1LX9m9Ee8u653hU1sxvvRNpV1ZjYExa7K8r9zjDws9GDLvp")
.expect("Invalid Treasury Account");
pub const SDMultiplier: u64 = 100;
pub const MaxSubscriptions: u32 = 2_000;
pub const MaxTerminatableSubs: u32 = 200;
pub const MaxMetadataLen: u32 = 8;
pub const MaxCallDataLen: u32 = 256;
}
pub type Credits = u64;
pub type SubscriptionId = [u8; 32];
pub type BlockNumber = u32;
pub type Balance = u128;
pub type Signature = MultiSignature;
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
pub type Metadata = SubscriptionMetadata<MaxMetadataLen>;
pub type CallData = SubscriptionCallData<MaxCallDataLen>;
pub type CreateSubParams =
MngCreateSubParams<Credits, BlockNumber, Metadata, SubscriptionId, CallData>;
pub type UpdateSubParams = MngUpdateSubParams<SubscriptionId, Credits, BlockNumber, Metadata>;
pub type QuoteSubParams = MngQuoteSubParams<CreateSubParams, BlockNumber, CallData>;
pub type QuoteRequest = MngQuoteRequest<CreateSubParams, BlockNumber>;
pub type Quote = MngQuote<Balance>;
pub type Subscription =
MngSubscription<AccountId, BlockNumber, Credits, Metadata, SubscriptionId, CallData>;
pub type SubInfoResponse = MngSubInfoResponse<Subscription>;
pub type SubInfoRequest = MngSubInfoRequest<SubscriptionId, CallData>;
pub type SubscriptionDetails = MngSubscriptionDetails<AccountId, CallData>;
#[cfg(test)]
mod test {
use super::*;
use sp_idn_crypto::test_utils::*;
#[test]
fn test_runtime_pulse_can_authenticate_valid_pulse() {
let beacon_pk_bytes = get_beacon_pk();
let (asig, _amsg, _pulses) = get(vec![PULSE1000, PULSE1001]);
let valid_pulse = RuntimePulse::new(asig.try_into().unwrap(), 1000, 1001);
let validity = valid_pulse.authenticate(beacon_pk_bytes.try_into().unwrap());
assert!(validity);
}
#[test]
fn test_runtime_pulse_can_handle_invalid_pulse() {
let beacon_pk_bytes = get_beacon_pk();
let (asig, _amsg, _pulses) = get(vec![PULSE1000, PULSE1001]);
let valid_pulse = RuntimePulse::new(asig.try_into().unwrap(), 1000, 1004);
let validity = valid_pulse.authenticate(beacon_pk_bytes.try_into().unwrap());
assert!(!validity);
}
}