use core::ops::{Add, AddAssign};
use crate::simple::{MaxImports, MaxWorkItems};
use super::*;
use simple::OpaqueBlsPublic;
#[derive(Copy, Clone, Encode, Decode, Debug, Eq, PartialEq)]
pub struct OpaqueValKeyset {
pub ed25519: OpaqueEd25519Public,
pub bandersnatch: OpaqueBandersnatchPublic,
pub bls: OpaqueBlsPublic,
pub metadata: OpaqueValidatorMetadata,
}
impl Default for OpaqueValKeyset {
fn default() -> Self {
Self {
ed25519: OpaqueEd25519Public::zero(),
bandersnatch: OpaqueBandersnatchPublic::zero(),
bls: OpaqueBlsPublic::zero(),
metadata: OpaqueValidatorMetadata::zero(),
}
}
}
pub type OpaqueValKeysets = FixedVec<OpaqueValKeyset, ValCount>;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum RootIdentifier {
Direct(SegmentTreeRoot),
Indirect(WorkPackageHash),
}
impl From<SegmentTreeRoot> for RootIdentifier {
fn from(root: SegmentTreeRoot) -> Self {
Self::Direct(root)
}
}
impl From<WorkPackageHash> for RootIdentifier {
fn from(hash: WorkPackageHash) -> Self {
Self::Indirect(hash)
}
}
impl TryFrom<RootIdentifier> for SegmentTreeRoot {
type Error = WorkPackageHash;
fn try_from(root: RootIdentifier) -> Result<Self, Self::Error> {
match root {
RootIdentifier::Direct(root) => Ok(root),
RootIdentifier::Indirect(hash) => Err(hash),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ImportSpec {
pub root: RootIdentifier,
pub index: u16,
}
impl Encode for ImportSpec {
fn encode_to<T: scale::Output + ?Sized>(&self, dest: &mut T) {
let off = match &self.root {
RootIdentifier::Direct(root) => {
root.encode_to(dest);
0
},
RootIdentifier::Indirect(hash) => {
hash.encode_to(dest);
1 << 15
},
};
(self.index + off).encode_to(dest);
}
}
impl Decode for ImportSpec {
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
let h = Hash::decode(input)?;
let i = u16::decode(input)?;
let root = if i & (1 << 15) == 0 {
SegmentTreeRoot::from(h).into()
} else {
WorkPackageHash::from(h).into()
};
Ok(Self { root, index: i & !(1 << 15) })
}
}
#[derive(Clone, Encode, Decode, Debug)]
pub struct ExtrinsicSpec {
pub hash: ExtrinsicHash,
pub len: u32,
}
pub type WorkItems = BoundedVec<WorkItem, MaxWorkItems>;
#[derive(Clone, Encode, Decode, Debug)]
pub struct WorkItem {
pub service: ServiceId,
pub code_hash: CodeHash,
pub payload: WorkPayload,
pub refine_gas_limit: UnsignedGas,
pub accumulate_gas_limit: UnsignedGas,
pub import_segments: WorkItemImportsVec,
pub extrinsics: Vec<ExtrinsicSpec>,
pub export_count: u16,
}
pub type WorkItemImportsVec = BoundedVec<ImportSpec, MaxImports>;
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
pub struct RefineContext {
pub anchor: HeaderHash,
pub state_root: StateRootHash,
pub beefy_root: MmrPeakHash,
pub lookup_anchor: HeaderHash,
pub lookup_anchor_slot: Slot,
pub prerequisites: VecSet<WorkPackageHash>,
}
#[derive(Clone, Encode, Decode, Debug)]
pub struct WorkPackage {
pub authorization: Authorization,
pub auth_code_host: ServiceId,
pub authorizer: Authorizer,
pub context: RefineContext,
pub items: WorkItems,
}
#[derive(Clone, Encode, Decode, Debug)]
pub struct Authorizer {
pub code_hash: CodeHash,
pub param: AuthParam,
}
impl Authorizer {
pub fn any() -> Self {
Self { code_hash: CodeHash::zero(), param: Default::default() }
}
pub fn with_concat<R>(&self, f: impl Fn(&[u8]) -> R) -> R {
f(&[&self.code_hash.0[..], &self.param[..]].concat()[..])
}
}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub enum WorkError {
OutOfGas = 1,
Panic = 2,
BadExports = 3,
BadCode = 4,
CodeOversize = 5,
}
#[derive(Copy, Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
#[doc(hidden)]
pub struct RefineLoad {
#[codec(compact)]
pub gas_used: UnsignedGas,
#[codec(compact)]
pub imports: u16,
#[codec(compact)]
pub extrinsic_count: u16,
#[codec(compact)]
pub extrinsic_size: u32,
#[codec(compact)]
pub exports: u16,
}
impl Add for RefineLoad {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self {
gas_used: self.gas_used + rhs.gas_used,
imports: self.imports + rhs.imports,
extrinsic_count: self.extrinsic_count + rhs.extrinsic_count,
extrinsic_size: self.extrinsic_size + rhs.extrinsic_size,
exports: self.exports + rhs.exports,
}
}
}
impl AddAssign for RefineLoad {
fn add_assign(&mut self, rhs: Self) {
self.gas_used += rhs.gas_used;
self.imports += rhs.imports;
self.extrinsic_count += rhs.extrinsic_count;
self.extrinsic_size += rhs.extrinsic_size;
self.exports += rhs.exports;
}
}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub struct WorkResult {
pub service: ServiceId,
pub code_hash: CodeHash,
pub payload_hash: PayloadHash,
pub accumulate_gas: UnsignedGas,
#[codec(encoded_as = "CompactRefineResult")]
pub result: Result<WorkOutput, WorkError>,
pub refine_load: RefineLoad,
}
#[derive(Debug, Encode, Decode)]
pub struct AccumulateItem {
pub package: WorkPackageHash,
pub exports_root: SegmentTreeRoot,
pub authorizer_hash: AuthorizerHash,
pub auth_output: AuthOutput,
pub payload: PayloadHash,
#[codec(encoded_as = "CompactRefineResult")]
pub result: Result<WorkOutput, WorkError>,
}
#[derive(Debug, Encode, Decode)]
#[doc(hidden)]
pub struct AccumulateParams {
pub slot: Slot,
pub id: ServiceId,
pub results: Vec<AccumulateItem>,
}
#[derive(Debug, Clone, Encode, Decode, Default)]
pub struct TransferRecord {
pub source: ServiceId,
pub destination: ServiceId,
pub amount: Balance,
pub memo: Memo,
pub gas_limit: UnsignedGas,
}
#[derive(Debug, Encode, Decode)]
#[doc(hidden)]
pub struct OnTransferParams {
pub slot: Slot,
pub id: ServiceId,
pub transfers: Vec<TransferRecord>,
}
#[derive(Debug, Encode, Decode)]
#[doc(hidden)]
pub struct RefineParams {
pub id: ServiceId,
pub payload: WorkPayload,
pub package_hash: WorkPackageHash,
pub context: RefineContext,
pub auth_code_hash: CodeHash,
}
#[derive(Debug, Encode)]
#[doc(hidden)]
pub struct RefineParamsRef<'a> {
pub id: ServiceId,
pub payload: &'a WorkPayload,
pub package_hash: &'a WorkPackageHash,
pub context: &'a RefineContext,
pub auth_code_hash: &'a CodeHash,
}
#[derive(Debug, Encode)]
#[doc(hidden)]
pub struct OnTransferParamsRef<'a> {
pub slot: Slot,
pub id: ServiceId,
pub transfers: &'a [TransferRecord],
}
#[derive(Debug, Clone, Encode, Decode, MaxEncodedLen)]
pub struct ServiceInfo {
pub code_hash: CodeHash,
pub balance: Balance,
pub threshold: Balance,
pub min_item_gas: UnsignedGas,
pub min_memo_gas: UnsignedGas,
pub bytes: u64,
pub items: u32,
}
impl scale::ConstEncodedLen for ServiceInfo {}
struct CompactRefineResult(Result<WorkOutput, WorkError>);
struct CompactRefineResultRef<'a>(&'a Result<WorkOutput, WorkError>);
impl From<CompactRefineResult> for Result<WorkOutput, WorkError> {
fn from(value: CompactRefineResult) -> Self {
value.0
}
}
impl<'a> From<&'a Result<WorkOutput, WorkError>> for CompactRefineResultRef<'a> {
fn from(value: &'a Result<WorkOutput, WorkError>) -> Self {
CompactRefineResultRef(value)
}
}
impl<'a> scale::EncodeAsRef<'a, Result<WorkOutput, WorkError>> for CompactRefineResult {
type RefType = CompactRefineResultRef<'a>;
}
impl Encode for CompactRefineResult {
fn encode_to<T: scale::Output + ?Sized>(&self, dest: &mut T) {
CompactRefineResultRef(&self.0).encode_to(dest)
}
}
impl Encode for CompactRefineResultRef<'_> {
fn encode_to<T: scale::Output + ?Sized>(&self, dest: &mut T) {
match &self.0 {
Ok(o) => {
dest.push_byte(0);
o.encode_to(dest)
},
Err(e) => e.encode_to(dest),
}
}
}
impl Decode for CompactRefineResult {
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
match input.read_byte()? {
0 => Ok(Self(Ok(WorkOutput::decode(input)?))),
e => Ok(Self(Err(WorkError::decode(&mut &[e][..])?))),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compact_refine_result_codec() {
let enc_dec = |exp_res, exp_buf: &[u8]| {
let buf = CompactRefineResultRef(&exp_res).encode();
assert_eq!(buf, exp_buf);
let res = CompactRefineResult::decode(&mut &buf[..]).unwrap();
assert_eq!(res.0, exp_res);
};
enc_dec(Ok(vec![1, 2, 3].into()), &[0, 3, 1, 2, 3]);
enc_dec(Err(WorkError::OutOfGas), &[1]);
enc_dec(Err(WorkError::Panic), &[2]);
enc_dec(Err(WorkError::BadExports), &[3]);
enc_dec(Err(WorkError::BadCode), &[4]);
enc_dec(Err(WorkError::CodeOversize), &[5]);
}
}