Unverified Commit be79c5dc authored by Gavin Wood's avatar Gavin Wood Committed by GitHub
Browse files

Parachain auctions (#239)



* Slots module

* Integrate slots

* More drafting

* Minor updates

* Update parachains to use trati

* More build fixes

* Full code now compiles

* Add renew bid function

* Implement calculate_winner

* Warning remove

* Update gitignore

* Test framework

* Tests

* Further testing

* More tests, new parameterisation.

* Fix and new test

* Thread-safe tests

* Test off-boarding and a fix.

* Test onboarding

* Allow late onboarding.

* Another test and fix

* Avoid println in nostd

* Compact representation of paraids

* Introduce documentation.

* Introduce events.

* Additional test and fix

* Additional test

* Tidy up line lengths.

* Remove printlns

* Use later substrate utils.

* Fix build/test

* Make slots work with latest substrate

* Update runtime/src/slot_range.rs

Co-Authored-By: asynchronous rob's avatarRobert Habermeier <rphmeier@gmail.com>

* Update runtime/src/slots.rs

Co-Authored-By: Shawn Tabrizi's avatarShawn Tabrizi <shawntabrizi@gmail.com>

* Update runtime/src/slots.rs

Co-Authored-By: Shawn Tabrizi's avatarShawn Tabrizi <shawntabrizi@gmail.com>

* Polish logic

* Rewind to earlier substrate master

* Remove dead code.
parent dc73c4f3
......@@ -1362,10 +1362,10 @@ dependencies = [
"libp2p-ping 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-plaintext 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-ratelimit 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-secio 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-secio 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-tcp 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-uds 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-wasm-ext 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-wasm-ext 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-websocket 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-yamux 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-multiaddr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1603,7 +1603,7 @@ dependencies = [
[[package]]
name = "libp2p-secio"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1616,11 +1616,11 @@ dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-core 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"protobuf 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rw-stream-sink 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1658,13 +1658,13 @@ dependencies = [
[[package]]
name = "libp2p-wasm-ext"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"js-sys 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
"libp2p-core 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-futures 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -2095,6 +2095,11 @@ dependencies = [
"unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-send-wrapper"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parity-wasm"
version = "0.31.3"
......@@ -5120,10 +5125,10 @@ dependencies = [
"checksum libp2p-ping 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b3bb3328d206ad3061e863f179a211fc978d7bce05f90440ed6b8a6a9d17ced"
"checksum libp2p-plaintext 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b23a8ece138f448572c5ff781d62323a954f1f681c303e6553368026764b0ae"
"checksum libp2p-ratelimit 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55918f058f118d72d83f9a976f12e02e54c8616ddfc795c779c4801a5042a44f"
"checksum libp2p-secio 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9bff57806e0f71832cc02b5dea1010e5f1a9d16393fd104a4b64e4aaae40d885"
"checksum libp2p-secio 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea5c0636053e01575d6269b6112f9239e9d35ca861e3e5c7d6970a07f9e1682a"
"checksum libp2p-tcp 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3629f9a667d9f5acb5876df59cf3b547250e340131c47587f9ace7c517f21327"
"checksum libp2p-uds 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d65c15f89c0607d4a334664d759e54e847e1856a73ea78e7bb6a75e6f4039010"
"checksum libp2p-wasm-ext 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dff6c81d0f46261a6327219349753aefd3a92021a1e6102185fa112cfcddca97"
"checksum libp2p-wasm-ext 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "318d727d5e8e0fe3bb70aacbf99bde57334eae9559deff447edd993422dc0f03"
"checksum libp2p-websocket 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04451aa166aa2040293f44c1c27144b65500e4a2ebbb723dfe732f39436eccbd"
"checksum libp2p-yamux 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5369165359bea84e7ebe73f37b6240f31f8d924ce6710be3d8e1fa678985c9b8"
"checksum librocksdb-sys 5.17.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfb546562f9b450237bb8df7a31961849ee9fb1186d9e356db1d7a6b7609ff2"
......@@ -5170,6 +5175,7 @@ dependencies = [
"checksum parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00a486fd383382ddcb2de928364b1f82571c1e48274fc43b7667a4738ee4056c"
"checksum parity-multiaddr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18a130a727008cfcd1068a28439fe939897ccad28664422aeca65b384d6de6d0"
"checksum parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e8eab0287ccde7821e337a124dc5a4f1d6e4c25d10cc91e3f9361615dd95076"
"checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f"
"checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc"
"checksum parity-ws 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2fec5048fba72a2e01baeb0d08089db79aead4b57e2443df172fb1840075a233"
"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac"
......
......@@ -5,8 +5,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
description = "Types and utilities for creating and working with parachains"
[dependencies]
parity-codec = { version = "3.0", default-features = false }
parity-codec-derive = { version = "3.0", default-features = false }
parity-codec = { version = "3.5", default-features = false }
parity-codec-derive = { version = "3.3", default-features = false }
wasmi = { version = "0.4.3", optional = true }
error-chain = { version = "0.12", optional = true }
serde = { version = "1.0", default-features = false }
......
......@@ -77,6 +77,21 @@ pub mod wasm_executor;
#[cfg(feature = "wasm-api")]
pub mod wasm_api;
use codec::{Encode, Decode};
struct TrailingZeroInput<'a>(&'a [u8]);
impl<'a> codec::Input for TrailingZeroInput<'a> {
fn read(&mut self, into: &mut [u8]) -> usize {
let len = into.len().min(self.0.len());
into[..len].copy_from_slice(&self.0[..len]);
for i in &mut into[len..] {
*i = 0;
}
self.0 = &self.0[len..];
len
}
}
/// Validation parameters for evaluating the parachain validity function.
// TODO: balance downloads (https://github.com/paritytech/polkadot/issues/220)
#[derive(PartialEq, Eq, Decode)]
......@@ -100,10 +115,56 @@ pub struct ValidationResult {
}
/// Unique identifier of a parachain.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Encode, Decode)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Default, Clone, Copy, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Id(u32);
impl codec::CompactAs for Id {
type As = u32;
fn encode_as(&self) -> &u32 {
&self.0
}
fn decode_from(x: u32) -> Self {
Self(x)
}
}
impl From<codec::Compact<Id>> for Id {
fn from(x: codec::Compact<Id>) -> Id {
x.0
}
}
/// This type can be converted into and possibly from an AccountId (which itself is generic).
pub trait AccountIdConversion<AccountId>: Sized {
/// Convert into an account ID. This is infallible.
fn into_account(&self) -> AccountId;
/// Try to convert an account ID into this type. Might not succeed.
fn try_from_account(a: &AccountId) -> Option<Self>;
}
/// Format is b"para" ++ encode(parachain ID) ++ 00.... where 00... is indefinite trailing zeroes to fill AccountId.
impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
fn into_account(&self) -> T {
(b"para", self).using_encoded(|b|
T::decode(&mut TrailingZeroInput(b))
).unwrap_or_default()
}
fn try_from_account(x: &T) -> Option<Self> {
x.using_encoded(|d| {
if &d[0..4] != b"para" { return None }
let mut cursor = &d[4..];
let result = Decode::decode(&mut cursor)?;
if cursor.iter().all(|x| *x == 0) {
Some(result)
} else {
None
}
})
}
}
impl From<Id> for u32 {
fn from(x: Id) -> Self { x.0 }
}
......
......@@ -24,7 +24,7 @@ use super::Hash;
use primitives::bytes;
use primitives::ed25519;
pub use polkadot_parachain::Id;
pub use polkadot_parachain::{Id, AccountIdConversion};
/// Identity that collators use.
pub type CollatorId = ed25519::Public;
......
......@@ -50,6 +50,7 @@ impl EcdsaSignature {
r[64] = self.2 as u8;
r
}
#[cfg(test)]
pub fn from_blob(blob: &[u8; 65]) -> Self {
let mut r = Self([0u8; 32], [0u8; 32], 0);
r.0[..].copy_from_slice(&blob[0..32]);
......@@ -148,7 +149,7 @@ mod tests {
use tiny_keccak::keccak256;
use super::*;
use sr_io::{self as runtime_io, with_externalities};
use sr_io::with_externalities;
use substrate_primitives::{H256, Blake2Hasher};
use codec::{Decode, Encode};
// The testing primitives are very useful for avoiding having to work with signatures
......
......@@ -76,6 +76,8 @@ extern crate substrate_trie;
mod curated_grandpa;
mod parachains;
mod claims;
mod slot_range;
mod slots;
use rstd::prelude::*;
use substrate_primitives::u32_trait::{_2, _4};
......@@ -252,6 +254,19 @@ impl grandpa::Trait for Runtime {
impl parachains::Trait for Runtime {}
parameter_types!{
pub const LeasePeriod: BlockNumber = 100000;
pub const EndingPeriod: BlockNumber = 1000;
}
impl slots::Trait for Runtime {
type Event = Event;
type Currency = balances::Module<Self>;
type Parachains = parachains::Module<Self>;
type LeasePeriod = LeasePeriod;
type EndingPeriod = EndingPeriod;
}
impl curated_grandpa::Trait for Runtime { }
impl sudo::Trait for Runtime {
......@@ -283,6 +298,7 @@ construct_runtime!(
CouncilSeats: council_seats::{Config<T>},
Treasury: treasury,
Parachains: parachains::{Module, Call, Storage, Config<T>, Inherent},
Slots: slots::{Module, Call, Storage, Event<T>},
Sudo: sudo,
}
);
......
......@@ -17,16 +17,16 @@
//! Main parachains logic. For now this is just the determination of which validators do what.
use rstd::prelude::*;
use codec::Decode;
use codec::{Decode, HasCompact};
use bitvec::BigEndian;
use sr_primitives::traits::{Hash as HashT, BlakeTwo256};
use primitives::Hash;
use primitives::parachain::{Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement};
use sr_primitives::traits::{Hash as HashT, BlakeTwo256, Member};
use primitives::{Hash, parachain::{Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement, AccountIdConversion}};
use {system, session};
use srml_support::{StorageValue, StorageMap, storage::hashed::generator};
use srml_support::dispatch::Result;
use srml_support::{StorageValue, StorageMap, Parameter, dispatch::Result};
#[cfg(feature = "std")]
use srml_support::storage::hashed::generator;
use inherents::{ProvideInherent, InherentData, RuntimeString, MakeFatalError, InherentIdentifier};
......@@ -38,7 +38,64 @@ use rstd::marker::PhantomData;
use system::ensure_none;
pub trait Trait: session::Trait {}
/// Parachain registration API.
pub trait ParachainRegistrar<AccountId> {
/// An identifier for a parachain.
type ParaId: Member + Parameter + Default + AccountIdConversion<AccountId> + Copy + HasCompact;
/// Create a new unique parachain identity for later registration.
fn new_id() -> Self::ParaId;
/// Register a parachain with given `code` and `initial_head_data`. `id` must not yet be registered or it will
/// result in a error.
fn register_parachain(id: Self::ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result;
/// Deregister a parachain with given `id`. If `id` is not currently registered, an error is returned.
fn deregister_parachain(id: Self::ParaId) -> Result;
}
impl<T: Trait> ParachainRegistrar<T::AccountId> for Module<T> {
type ParaId = ParaId;
fn new_id() -> ParaId {
<NextFreeId<T>>::mutate(|n| { let r = *n; *n = ParaId::from(u32::from(*n) + 1); r })
}
fn register_parachain(id: ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
let mut parachains = Self::active_parachains();
match parachains.binary_search(&id) {
Ok(_) => fail!("Parachain already exists"),
Err(idx) => parachains.insert(idx, id),
}
<Code<T>>::insert(id, code);
<Parachains<T>>::put(parachains);
<Heads<T>>::insert(id, initial_head_data);
Ok(())
}
fn deregister_parachain(id: ParaId) -> Result {
let mut parachains = Self::active_parachains();
match parachains.binary_search(&id) {
Ok(idx) => { parachains.remove(idx); }
Err(_) => return Ok(()),
}
<Code<T>>::remove(id);
<Heads<T>>::remove(id);
// clear all routing entries to and from other parachains.
for other in parachains.iter().cloned() {
<Routing<T>>::remove((id, other));
<Routing<T>>::remove((other, id));
}
<Parachains<T>>::put(parachains);
Ok(())
}
}
pub trait Trait: session::Trait {
}
// result of <NodeCodec<Blake2Hasher> as trie_db::NodeCodec<Blake2Hasher>>::hashed_null_node()
const EMPTY_TRIE_ROOT: [u8; 32] = [
......@@ -59,6 +116,9 @@ decl_storage! {
// Did the parachain heads get updated in this block?
DidUpdate: bool;
/// The next unused ParaId value.
NextFreeId: ParaId;
}
add_extra_genesis {
config(parachains): Vec<(ParaId, Vec<u8>, Vec<u8>)>;
......@@ -137,39 +197,12 @@ decl_module! {
/// Register a parachain with given code.
/// Fails if given ID is already used.
pub fn register_parachain(id: ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
let mut parachains = Self::active_parachains();
match parachains.binary_search(&id) {
Ok(_) => fail!("Parachain already exists"),
Err(idx) => parachains.insert(idx, id),
}
<Code<T>>::insert(id, code);
<Parachains<T>>::put(parachains);
<Heads<T>>::insert(id, initial_head_data);
Ok(())
<Self as ParachainRegistrar<T::AccountId>>::register_parachain(id, code, initial_head_data)
}
/// Deregister a parachain with given id
pub fn deregister_parachain(id: ParaId) -> Result {
let mut parachains = Self::active_parachains();
match parachains.binary_search(&id) {
Ok(idx) => { parachains.remove(idx); }
Err(_) => return Ok(()),
}
<Code<T>>::remove(id);
<Heads<T>>::remove(id);
// clear all routing entries to and from other parachains.
for other in parachains.iter().cloned() {
<Routing<T>>::remove((id, other));
<Routing<T>>::remove((other, id));
}
<Parachains<T>>::put(parachains);
Ok(())
<Self as ParachainRegistrar<T::AccountId>>::deregister_parachain(id)
}
fn on_finalize(_n: T::BlockNumber) {
......
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! The SlotRange struct which succinctly handles the ten values that
//! represent all sub ranges between 0 and 3 inclusive.
use rstd::{result, ops::Add, convert::{TryFrom, TryInto}};
use sr_primitives::traits::CheckedSub;
/// Total number of possible sub ranges of slots.
pub const SLOT_RANGE_COUNT: usize = 10;
/// A compactly represented sub-range from the series (0, 1, 2, 3).
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode)]
#[repr(u8)]
pub enum SlotRange {
/// Sub range from index 0 to index 0 inclusive.
ZeroZero = 0,
/// Sub range from index 0 to index 1 inclusive.
ZeroOne = 1,
/// Sub range from index 0 to index 2 inclusive.
ZeroTwo = 2,
/// Sub range from index 0 to index 3 inclusive.
ZeroThree = 3,
/// Sub range from index 1 to index 1 inclusive.
OneOne = 4,
/// Sub range from index 1 to index 2 inclusive.
OneTwo = 5,
/// Sub range from index 1 to index 3 inclusive.
OneThree = 6,
/// Sub range from index 2 to index 2 inclusive.
TwoTwo = 7,
/// Sub range from index 2 to index 3 inclusive.
TwoThree = 8,
/// Sub range from index 3 to index 3 inclusive.
ThreeThree = 9, // == SLOT_RANGE_COUNT - 1
}
#[cfg(feature = "std")]
impl std::fmt::Debug for SlotRange {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
let p = self.as_pair();
write!(fmt, "[{}..{}]", p.0, p.1)
}
}
impl SlotRange {
pub fn new_bounded<
Index: Add<Output=Index> + CheckedSub + Copy + Ord + From<u32> + TryInto<u32>
>(
initial: Index,
first: Index,
last: Index
) -> result::Result<Self, &'static str> {
if first > last || first < initial || last > initial + 3.into() {
return Err("Invalid range for this auction")
}
let count: u32 = last.checked_sub(&first)
.ok_or("range ends before it begins")?
.try_into()
.map_err(|_| "range too big")?;
let first: u32 = first.checked_sub(&initial)
.ok_or("range begins too early")?
.try_into()
.map_err(|_| "start too far")?;
match first {
0 => match count {
0 => Some(SlotRange::ZeroZero),
1 => Some(SlotRange::ZeroOne),
2 => Some(SlotRange::ZeroTwo),
3 => Some(SlotRange::ZeroThree),
_ => None,
},
1 => match count {
0 => Some(SlotRange::OneOne),
1 => Some(SlotRange::OneTwo),
2 => Some(SlotRange::OneThree),
_ => None
},
2 => match count { 0 => Some(SlotRange::TwoTwo), 1 => Some(SlotRange::TwoThree), _ => None },
3 => match count { 0 => Some(SlotRange::ThreeThree), _ => None },
_ => return Err("range begins too late"),
}.ok_or("range ends too late")
}
pub fn as_pair(&self) -> (u8, u8) {
match self {
SlotRange::ZeroZero => (0, 0),
SlotRange::ZeroOne => (0, 1),
SlotRange::ZeroTwo => (0, 2),
SlotRange::ZeroThree => (0, 3),
SlotRange::OneOne => (1, 1),
SlotRange::OneTwo => (1, 2),
SlotRange::OneThree => (1, 3),
SlotRange::TwoTwo => (2, 2),
SlotRange::TwoThree => (2, 3),
SlotRange::ThreeThree => (3, 3),
}
}
pub fn intersects(&self, other: SlotRange) -> bool {
let a = self.as_pair();
let b = other.as_pair();
b.0 <= a.1 && a.0 <= b.1
// == !(b.0 > a.1 || a.0 > b.1)
}
pub fn len(&self) -> usize {
match self {
SlotRange::ZeroZero => 1,
SlotRange::ZeroOne => 2,
SlotRange::ZeroTwo => 3,
SlotRange::ZeroThree => 4,
SlotRange::OneOne => 1,
SlotRange::OneTwo => 2,
SlotRange::OneThree => 3,
SlotRange::TwoTwo => 1,
SlotRange::TwoThree => 2,
SlotRange::ThreeThree => 1,
}
}
}
impl TryFrom<usize> for SlotRange {
type Error = ();
fn try_from(x: usize) -> Result<SlotRange, ()> {
Ok(match x {
0 => SlotRange::ZeroZero,
1 => SlotRange::ZeroOne,
2 => SlotRange::ZeroTwo,
3 => SlotRange::ZeroThree,
4 => SlotRange::OneOne,
5 => SlotRange::OneTwo,
6 => SlotRange::OneThree,
7 => SlotRange::TwoTwo,
8 => SlotRange::TwoThree,
9 => SlotRange::ThreeThree,
_ => return Err(()),
})
}
}
This diff is collapsed.
This diff is collapsed.
......@@ -6,6 +6,6 @@ description = "Test parachain which adds to a number as its state transition"
[dependencies]
polkadot-parachain = { path = "../../parachain/", default-features = false }
parity-codec = { version = "3.0", default-features = false }
parity-codec-derive = { version = "3.0", default-features = false }
parity-codec = { version = "3.5", default-features = false }
parity-codec-derive = { version = "3.3", default-features = false }
tiny-keccak = "1.4"
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment