code/pallets/commitments/src/types.rs

types.rs

456 lines · 14,364 bytes · 74b77d74e5RawGitHub
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use codec::{Codec, Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use frame_support::{
    BoundedVec, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound,
    traits::{ConstU32, Get},
};
use scale_info::{
    Path, Type, TypeInfo,
    build::{Fields, Variants},
};
use sp_runtime::{
    RuntimeDebug,
    traits::{AppendZerosInput, AtLeast32BitUnsigned},
};
use sp_std::{fmt::Debug, iter::once, prelude::*};
use subtensor_macros::freeze_struct;

/// Represents stored data which can be:
/// - `Raw`: a direct blob up to 128 bytes
/// - `BigRaw`: a larger blob up to 512 bytes
/// - A cryptographic hash (BlakeTwo256, Sha256, Keccak256, ShaThree256)
/// - A timelock-encrypted blob with a reveal round
/// - A reset flag (`ResetBondsFlag`)
///   Can also be `None`.
#[derive(Clone, Eq, PartialEq, RuntimeDebug, DecodeWithMemTracking, MaxEncodedLen)]
pub enum Data {
    /// No data here.
    None,
    /// The data is stored directly (up to 128 bytes).
    Raw(BoundedVec<u8, ConstU32<128>>),
    /// Only the Blake2 hash of the data is stored. The preimage of the hash may be retrieved
    /// through some hash-lookup service.
    BlakeTwo256([u8; 32]),
    /// Only the SHA2-256 hash of the data is stored. The preimage of the hash may be retrieved
    /// through some hash-lookup service.
    Sha256([u8; 32]),
    /// Only the Keccak-256 hash of the data is stored. The preimage of the hash may be retrieved
    /// through some hash-lookup service.
    Keccak256([u8; 32]),
    /// Only the SHA3-256 hash of the data is stored. The preimage of the hash may be retrieved
    /// through some hash-lookup service.
    ShaThree256([u8; 32]),
    /// A timelock-encrypted commitment with a reveal round.
    TimelockEncrypted {
        encrypted: BoundedVec<u8, ConstU32<MAX_TIMELOCK_COMMITMENT_SIZE_BYTES>>,
        reveal_round: u64,
    },
    /// Flag to trigger bonds reset for subnet
    ResetBondsFlag,
    /// The data is stored directly (up to 512 bytes).
    BigRaw(BoundedVec<u8, ConstU32<MAX_BIGRAW_COMMITMENT_SIZE_BYTES>>),
}

impl Data {
    pub fn is_none(&self) -> bool {
        self == &Data::None
    }

    /// Check if this is a timelock-encrypted commitment.
    pub fn is_timelock_encrypted(&self) -> bool {
        matches!(self, Data::TimelockEncrypted { .. })
    }

    pub fn len_for_rate_limit(&self) -> u64 {
        match self {
            Data::None => 0,
            Data::Raw(bytes) => bytes.len() as u64,
            Data::BlakeTwo256(arr)
            | Data::Sha256(arr)
            | Data::Keccak256(arr)
            | Data::ShaThree256(arr) => arr.len() as u64,
            Data::TimelockEncrypted { encrypted, .. } => encrypted.len() as u64,
            Data::ResetBondsFlag => 0,
            Data::BigRaw(bytes) => bytes.len() as u64,
        }
    }
}

impl Decode for Data {
    fn decode<I: codec::Input>(input: &mut I) -> sp_std::result::Result<Self, codec::Error> {
        let b = input.read_byte()?;
        Ok(match b {
            0 => Data::None,
            n @ 1..=129 => {
                let mut r: BoundedVec<_, _> = vec![0u8; (n as usize).saturating_sub(1)]
                    .try_into()
                    .map_err(|_| codec::Error::from("bound checked in match arm condition; qed"))?;
                input.read(&mut r[..])?;
                Data::Raw(r)
            }
            130 => Data::BlakeTwo256(<[u8; 32]>::decode(input)?),
            131 => Data::Sha256(<[u8; 32]>::decode(input)?),
            132 => Data::Keccak256(<[u8; 32]>::decode(input)?),
            133 => Data::ShaThree256(<[u8; 32]>::decode(input)?),
            134 => {
                let encrypted =
                    BoundedVec::<u8, ConstU32<MAX_TIMELOCK_COMMITMENT_SIZE_BYTES>>::decode(input)?;
                let reveal_round = u64::decode(input)?;
                Data::TimelockEncrypted {
                    encrypted,
                    reveal_round,
                }
            }
            135 => Data::ResetBondsFlag,
            136 => {
                let bigvec =
                    BoundedVec::<u8, ConstU32<MAX_BIGRAW_COMMITMENT_SIZE_BYTES>>::decode(input)?;
                Data::BigRaw(bigvec)
            }
            _ => return Err(codec::Error::from("invalid leading byte")),
        })
    }
}

impl Encode for Data {
    fn encode(&self) -> Vec<u8> {
        match self {
            Data::None => vec![0u8; 1],
            Data::Raw(x) => {
                let l = x.len().min(128) as u8;
                let mut r = vec![l.saturating_add(1)];
                r.extend_from_slice(&x[..]);
                r
            }
            Data::BlakeTwo256(h) => once(130).chain(h.iter().cloned()).collect(),
            Data::Sha256(h) => once(131).chain(h.iter().cloned()).collect(),
            Data::Keccak256(h) => once(132).chain(h.iter().cloned()).collect(),
            Data::ShaThree256(h) => once(133).chain(h.iter().cloned()).collect(),
            Data::TimelockEncrypted {
                encrypted,
                reveal_round,
            } => {
                let mut r = vec![134];
                r.extend_from_slice(&encrypted.encode());
                r.extend_from_slice(&reveal_round.encode());
                r
            }
            Data::ResetBondsFlag => vec![135],
            Data::BigRaw(bigvec) => {
                let mut r = vec![136];
                r.extend_from_slice(&bigvec.encode());
                r
            }
        }
    }
}
impl codec::EncodeLike for Data {}

/// Add a Raw variant with the given index and a fixed sized byte array
macro_rules! data_raw_variants {
    ($variants:ident, $(($index:literal, $size:literal)),* ) => {
		$variants
		$(
			.variant(concat!("Raw", stringify!($size)), |v| v
				.index($index)
				.fields(Fields::unnamed().field(|f| f.ty::<[u8; $size]>()))
			)
		)*
    }
}

impl TypeInfo for Data {
    type Identity = Self;

    fn type_info() -> Type {
        let variants = Variants::new().variant("None", |v| v.index(0));

        // create a variant for all sizes of Raw data from 0-32
        let variants = data_raw_variants!(
            variants,
            (1, 0),
            (2, 1),
            (3, 2),
            (4, 3),
            (5, 4),
            (6, 5),
            (7, 6),
            (8, 7),
            (9, 8),
            (10, 9),
            (11, 10),
            (12, 11),
            (13, 12),
            (14, 13),
            (15, 14),
            (16, 15),
            (17, 16),
            (18, 17),
            (19, 18),
            (20, 19),
            (21, 20),
            (22, 21),
            (23, 22),
            (24, 23),
            (25, 24),
            (26, 25),
            (27, 26),
            (28, 27),
            (29, 28),
            (30, 29),
            (31, 30),
            (32, 31),
            (33, 32),
            (34, 33),
            (35, 34),
            (36, 35),
            (37, 36),
            (38, 37),
            (39, 38),
            (40, 39),
            (41, 40),
            (42, 41),
            (43, 42),
            (44, 43),
            (45, 44),
            (46, 45),
            (47, 46),
            (48, 47),
            (49, 48),
            (50, 49),
            (51, 50),
            (52, 51),
            (53, 52),
            (54, 53),
            (55, 54),
            (56, 55),
            (57, 56),
            (58, 57),
            (59, 58),
            (60, 59),
            (61, 60),
            (62, 61),
            (63, 62),
            (64, 63),
            (65, 64),
            (66, 65),
            (67, 66),
            (68, 67),
            (69, 68),
            (70, 69),
            (71, 70),
            (72, 71),
            (73, 72),
            (74, 73),
            (75, 74),
            (76, 75),
            (77, 76),
            (78, 77),
            (79, 78),
            (80, 79),
            (81, 80),
            (82, 81),
            (83, 82),
            (84, 83),
            (85, 84),
            (86, 85),
            (87, 86),
            (88, 87),
            (89, 88),
            (90, 89),
            (91, 90),
            (92, 91),
            (93, 92),
            (94, 93),
            (95, 94),
            (96, 95),
            (97, 96),
            (98, 97),
            (99, 98),
            (100, 99),
            (101, 100),
            (102, 101),
            (103, 102),
            (104, 103),
            (105, 104),
            (106, 105),
            (107, 106),
            (108, 107),
            (109, 108),
            (110, 109),
            (111, 110),
            (112, 111),
            (113, 112),
            (114, 113),
            (115, 114),
            (116, 115),
            (117, 116),
            (118, 117),
            (119, 118),
            (120, 119),
            (121, 120),
            (122, 121),
            (123, 122),
            (124, 123),
            (125, 124),
            (126, 125),
            (127, 126),
            (128, 127),
            (129, 128)
        );

        let variants = variants
            .variant("BlakeTwo256", |v| {
                v.index(130)
                    .fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
            })
            .variant("Sha256", |v| {
                v.index(131)
                    .fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
            })
            .variant("Keccak256", |v| {
                v.index(132)
                    .fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
            })
            .variant("ShaThree256", |v| {
                v.index(133)
                    .fields(Fields::unnamed().field(|f| f.ty::<[u8; 32]>()))
            })
            .variant("TimelockEncrypted", |v| {
                v.index(134).fields(
                    Fields::named()
                        .field(|f| {
                            f.name("encrypted")
                                .ty::<BoundedVec<u8, ConstU32<MAX_TIMELOCK_COMMITMENT_SIZE_BYTES>>>(
                                )
                        })
                        .field(|f| f.name("reveal_round").ty::<u64>()),
                )
            })
            .variant("ResetBondsFlag", |v| v.index(135))
            .variant("BigRaw", |v| {
                v.index(136).fields(Fields::unnamed().field(|f| {
                    f.ty::<BoundedVec<u8, ConstU32<MAX_BIGRAW_COMMITMENT_SIZE_BYTES>>>()
                }))
            });

        Type::builder()
            .path(Path::new("Data", module_path!()))
            .variant(variants)
    }
}

impl Default for Data {
    fn default() -> Self {
        Self::None
    }
}

#[freeze_struct("5ca4adbb4d2a2b20")]
#[derive(
    CloneNoBound,
    Encode,
    Decode,
    DecodeWithMemTracking,
    Eq,
    MaxEncodedLen,
    PartialEqNoBound,
    RuntimeDebugNoBound,
    TypeInfo,
)]
#[codec(mel_bound())]
#[derive(frame_support::DefaultNoBound)]
#[scale_info(skip_type_params(FieldLimit))]
pub struct CommitmentInfo<FieldLimit: Get<u32>> {
    pub fields: BoundedVec<Data, FieldLimit>,
}

/// Maximum size of the serialized timelock commitment in bytes
pub const MAX_TIMELOCK_COMMITMENT_SIZE_BYTES: u32 = 1024;
pub const MAX_BIGRAW_COMMITMENT_SIZE_BYTES: u32 = 512;

/// Contains the decrypted data of a revealed commitment.
#[freeze_struct("bf575857b57f9bef")]
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, Debug)]
pub struct RevealedData<Balance, MaxFields: Get<u32>, BlockNumber> {
    pub info: CommitmentInfo<MaxFields>,
    pub revealed_block: BlockNumber,
    pub deposit: Balance,
}

/// Tracks how much “space” each (netuid, who) has used within the current RateLimit block-window.
#[freeze_struct("1f23fb50f96326e4")]
#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, TypeInfo)]
pub struct UsageTracker {
    /// Last epoch block
    pub last_epoch: u64,
    /// Space used
    pub used_space: u64,
}

/// Information concerning the identity of the controller of an account.
///
/// NOTE: This is stored separately primarily to facilitate the addition of extra fields in a
/// backwards compatible way through a specialized `Decode` impl.
#[freeze_struct("632f12850e51c420")]
#[derive(
    CloneNoBound, Encode, Eq, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo,
)]
#[codec(mel_bound())]
#[scale_info(skip_type_params(MaxFields))]
pub struct Registration<
    Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq,
    MaxFields: Get<u32>,
    BlockNumber: Codec + Clone + Ord + Eq + AtLeast32BitUnsigned + MaxEncodedLen + Debug,
> {
    /// Amount held on deposit for this information.
    pub deposit: Balance,

    pub block: BlockNumber,

    /// Information on the identity.
    pub info: CommitmentInfo<MaxFields>,
}

// impl<
//         Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq + Zero + Add,
//         MaxFields: Get<u32>,
//         Block: Codec + Clone + Ord + Eq + AtLeast32BitUnsigned + MaxEncodedLen + Debug,
//     > Registration<Balance, MaxFields, Block>
// {
//     pub(crate) fn total_deposit(&self) -> Balance {
//         self.deposit
//     }
// }

impl<
    Balance: Encode + Decode + MaxEncodedLen + Copy + Clone + Debug + Eq + PartialEq,
    MaxFields: Get<u32>,
    Block: Codec + Clone + Ord + Eq + AtLeast32BitUnsigned + MaxEncodedLen + Debug,
> Decode for Registration<Balance, MaxFields, Block>
{
    fn decode<I: codec::Input>(input: &mut I) -> sp_std::result::Result<Self, codec::Error> {
        let (deposit, block, info) = Decode::decode(&mut AppendZerosInput::new(input))?;
        Ok(Self {
            deposit,
            block,
            info,
        })
    }
}