mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-29 05:37:58 +00:00
Merge pull request #79 from paritytech/gav-demo
Substrate demo (a basic blockchain made with substrate)
This commit is contained in:
@@ -5,4 +5,5 @@
|
||||
polkadot/runtime/wasm/target/
|
||||
substrate/executor/wasm/target/
|
||||
substrate/test-runtime/wasm/target/
|
||||
demo/runtime/wasm/target/
|
||||
**/._*
|
||||
|
||||
Generated
+78
@@ -181,6 +181,77 @@ name = "crunchy"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "demo-cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 2.29.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"demo-executor 0.1.0",
|
||||
"demo-primitives 0.1.0",
|
||||
"demo-runtime 0.1.0",
|
||||
"ed25519 0.1.0",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-client 0.1.0",
|
||||
"substrate-codec 0.1.0",
|
||||
"substrate-executor 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-rpc-servers 0.1.0",
|
||||
"substrate-runtime-io 0.1.0",
|
||||
"substrate-state-machine 0.1.0",
|
||||
"triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "demo-executor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"demo-primitives 0.1.0",
|
||||
"demo-runtime 0.1.0",
|
||||
"ed25519 0.1.0",
|
||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-codec 0.1.0",
|
||||
"substrate-executor 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-runtime-io 0.1.0",
|
||||
"substrate-runtime-support 0.1.0",
|
||||
"substrate-state-machine 0.1.0",
|
||||
"triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "demo-primitives"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"pretty_assertions 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-codec 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-runtime-std 0.1.0",
|
||||
"substrate-serializer 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "demo-runtime"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"demo-primitives 0.1.0",
|
||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"integer-sqrt 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-codec 0.1.0",
|
||||
"substrate-keyring 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-runtime-io 0.1.0",
|
||||
"substrate-runtime-std 0.1.0",
|
||||
"substrate-runtime-support 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difference"
|
||||
version = "1.0.0"
|
||||
@@ -617,6 +688,11 @@ dependencies = [
|
||||
"xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "integer-sqrt"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.2"
|
||||
@@ -1524,6 +1600,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"ed25519 0.1.0",
|
||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2077,6 +2154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum hyper 0.11.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4de6edd503089841ebfa88341e1c00fb19b6bf93d820d908db15960fd31226"
|
||||
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
|
||||
"checksum igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "356a0dc23a4fa0f8ce4777258085d00a01ea4923b2efd93538fc44bf5e1bda76"
|
||||
"checksum integer-sqrt 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8833702c315192502093b244e29c6ab9c55454adfe21b879a87a039ea8fe8520"
|
||||
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
|
||||
"checksum ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2134e210e2a024b5684f90e1556d5f71a1ce7f8b12e9ac9924c67fb36f63b336"
|
||||
"checksum isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f2a233726c7bb76995cec749d59582e5664823b7245d4970354408f1d79a7a2"
|
||||
|
||||
@@ -40,9 +40,14 @@ members = [
|
||||
"substrate/serializer",
|
||||
"substrate/state-machine",
|
||||
"substrate/test-runtime",
|
||||
"demo/runtime",
|
||||
"demo/primitives",
|
||||
"demo/executor",
|
||||
"demo/cli",
|
||||
]
|
||||
exclude = [
|
||||
"polkadot/runtime/wasm",
|
||||
"demo/runtime/wasm",
|
||||
"substrate/executor/wasm",
|
||||
"substrate/pwasm-alloc",
|
||||
"substrate/pwasm-libc",
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
cd substrate/executor/wasm && ./build.sh && cd ../../..
|
||||
cd substrate/test-runtime/wasm && ./build.sh && cd ../../..
|
||||
cd polkadot/runtime/wasm && ./build.sh && cd ../../..
|
||||
cd demo/runtime/wasm && ./build.sh && cd ../../..
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "demo-cli"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Substrate Demo node implementation in Rust."
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "2.27", features = ["yaml"] }
|
||||
env_logger = "0.4"
|
||||
error-chain = "0.11"
|
||||
log = "0.3"
|
||||
hex-literal = "0.1"
|
||||
triehash = "0.1"
|
||||
ed25519 = { path = "../../substrate/ed25519" }
|
||||
substrate-client = { path = "../../substrate/client" }
|
||||
substrate-codec = { path = "../../substrate/codec" }
|
||||
substrate-runtime-io = { path = "../../substrate/runtime-io" }
|
||||
substrate-state-machine = { path = "../../substrate/state-machine" }
|
||||
substrate-executor = { path = "../../substrate/executor" }
|
||||
substrate-primitives = { path = "../../substrate/primitives" }
|
||||
substrate-rpc-servers = { path = "../../substrate/rpc-servers" }
|
||||
demo-primitives = { path = "../primitives" }
|
||||
demo-executor = { path = "../executor" }
|
||||
demo-runtime = { path = "../runtime" }
|
||||
@@ -0,0 +1,12 @@
|
||||
name: substrate-demo
|
||||
author: "Parity Team <admin@parity.io>"
|
||||
about: Substrate Demo Node Rust Implementation
|
||||
args:
|
||||
- log:
|
||||
short: l
|
||||
value_name: LOG_PATTERN
|
||||
help: Sets a custom logging
|
||||
takes_value: true
|
||||
subcommands:
|
||||
- validator:
|
||||
about: Run validator node
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Initialization errors.
|
||||
|
||||
use client;
|
||||
|
||||
error_chain! {
|
||||
foreign_links {
|
||||
Io(::std::io::Error) #[doc="IO error"];
|
||||
Cli(::clap::Error) #[doc="CLI error"];
|
||||
}
|
||||
links {
|
||||
Client(client::error::Error, client::error::ErrorKind) #[doc="Client error"];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate Demo CLI library.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate env_logger;
|
||||
extern crate ed25519;
|
||||
extern crate triehash;
|
||||
extern crate substrate_codec as codec;
|
||||
extern crate substrate_state_machine as state_machine;
|
||||
extern crate substrate_client as client;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate substrate_rpc_servers as rpc;
|
||||
extern crate demo_primitives;
|
||||
extern crate demo_executor;
|
||||
extern crate demo_runtime;
|
||||
|
||||
#[macro_use]
|
||||
extern crate hex_literal;
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod error;
|
||||
|
||||
use codec::Slicable;
|
||||
use demo_runtime::genesismap::{additional_storage_with_genesis, GenesisConfig};
|
||||
use client::genesis;
|
||||
|
||||
/// Parse command line arguments and start the node.
|
||||
///
|
||||
/// IANA unassigned port ranges that we could use:
|
||||
/// 6717-6766 Unassigned
|
||||
/// 8504-8553 Unassigned
|
||||
/// 9556-9591 Unassigned
|
||||
/// 9803-9874 Unassigned
|
||||
/// 9926-9949 Unassigned
|
||||
pub fn run<I, T>(args: I) -> error::Result<()> where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<std::ffi::OsString> + Clone,
|
||||
{
|
||||
let yaml = load_yaml!("./cli.yml");
|
||||
let matches = clap::App::from_yaml(yaml).version(crate_version!()).get_matches_from_safe(args)?;
|
||||
|
||||
// TODO [ToDr] Split parameters parsing from actual execution.
|
||||
let log_pattern = matches.value_of("log").unwrap_or("");
|
||||
init_logger(log_pattern);
|
||||
|
||||
// Create client
|
||||
let executor = demo_executor::Executor::new();
|
||||
let mut storage = Default::default();
|
||||
let god_key = hex!["3d866ec8a9190c8343c2fc593d21d8a6d0c5c4763aaab2349de3a6111d64d124"];
|
||||
|
||||
let genesis_config = GenesisConfig {
|
||||
validators: vec![god_key.clone()],
|
||||
authorities: vec![god_key.clone()],
|
||||
balances: vec![(god_key.clone(), 1u64 << 63)].into_iter().collect(),
|
||||
block_time: 5, // 5 second block time.
|
||||
session_length: 720, // that's 1 hour per session.
|
||||
sessions_per_era: 24, // 24 hours per era.
|
||||
bonding_duration: 90, // 90 days per bond.
|
||||
launch_period: 120 * 24 * 14, // 2 weeks per public referendum
|
||||
voting_period: 120 * 24 * 28, // 4 weeks to discuss & vote on an active referendum
|
||||
minimum_deposit: 1000, // 1000 as the minimum deposit for a referendum
|
||||
candidacy_bond: 1000, // 1000 to become a council candidate
|
||||
voter_bond: 100, // 100 down to vote for a candidate
|
||||
present_slash_per_voter: 1, // slash by 1 per voter for an invalid presentation.
|
||||
carry_count: 24, // carry over the 24 runners-up to the next council election
|
||||
presentation_duration: 120 * 24, // one day for presenting winners.
|
||||
council_election_voting_period: 7 * 120 * 24, // one week period between possible council elections.
|
||||
council_term_duration: 180 * 120 * 24, // 180 day term duration for the council.
|
||||
desired_seats: 0, // start with no council: we'll raise this once the stake has been dispersed a bit.
|
||||
inactive_grace_period: 1, // one addition vote should go by before an inactive voter can be reaped.
|
||||
cooloff_period: 90 * 120 * 24, // 90 day cooling off period if council member vetoes a proposal.
|
||||
council_proposal_voting_period: 7 * 120 * 24, // 7 day voting period for council members.
|
||||
};
|
||||
let prepare_genesis = || {
|
||||
storage = genesis_config.genesis_map();
|
||||
let block = genesis::construct_genesis_block(&storage);
|
||||
storage.extend(additional_storage_with_genesis(&block));
|
||||
(primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect())
|
||||
};
|
||||
let client = client::new_in_mem(executor, prepare_genesis)?;
|
||||
|
||||
let address = "127.0.0.1:9933".parse().unwrap();
|
||||
let handler = rpc::rpc_handler(client);
|
||||
let server = rpc::start_http(&address, handler)?;
|
||||
|
||||
if let Some(_) = matches.subcommand_matches("validator") {
|
||||
info!("Starting validator.");
|
||||
server.wait();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("No command given.\n");
|
||||
let _ = clap::App::from_yaml(yaml).print_long_help();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_logger(pattern: &str) {
|
||||
let mut builder = env_logger::LogBuilder::new();
|
||||
// Disable info logging by default for some modules:
|
||||
builder.filter(Some("hyper"), log::LogLevelFilter::Warn);
|
||||
// Enable info for others.
|
||||
builder.filter(None, log::LogLevelFilter::Info);
|
||||
|
||||
if let Ok(lvl) = std::env::var("RUST_LOG") {
|
||||
builder.parse(&lvl);
|
||||
}
|
||||
|
||||
builder.parse(pattern);
|
||||
|
||||
|
||||
builder.init().expect("Logger initialized only once.");
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "demo-executor"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Substrate Demo node implementation in Rust."
|
||||
|
||||
[dependencies]
|
||||
hex-literal = "0.1"
|
||||
triehash = { version = "0.1" }
|
||||
ed25519 = { path = "../../substrate/ed25519" }
|
||||
substrate-codec = { path = "../../substrate/codec" }
|
||||
substrate-runtime-io = { path = "../../substrate/runtime-io" }
|
||||
substrate-runtime-support = { path = "../../substrate/runtime-support" }
|
||||
substrate-state-machine = { path = "../../substrate/state-machine" }
|
||||
substrate-executor = { path = "../../substrate/executor" }
|
||||
substrate-primitives = { path = "../../substrate/primitives" }
|
||||
demo-primitives = { path = "../primitives" }
|
||||
demo-runtime = { path = "../runtime" }
|
||||
|
||||
[dev-dependencies]
|
||||
substrate-keyring = { path = "../../substrate/keyring" }
|
||||
@@ -0,0 +1,248 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! A `CodeExecutor` specialisation which uses natively compiled runtime when the wasm to be
|
||||
//! executed is equivalent to the natively compiled code.
|
||||
|
||||
extern crate demo_runtime;
|
||||
#[macro_use] extern crate substrate_executor;
|
||||
extern crate substrate_codec as codec;
|
||||
extern crate substrate_state_machine as state_machine;
|
||||
extern crate substrate_runtime_io as runtime_io;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate demo_primitives;
|
||||
extern crate ed25519;
|
||||
extern crate triehash;
|
||||
|
||||
#[cfg(test)] extern crate substrate_keyring as keyring;
|
||||
#[cfg(test)] extern crate substrate_runtime_support as runtime_support;
|
||||
#[cfg(test)] #[macro_use] extern crate hex_literal;
|
||||
|
||||
native_executor_instance!(pub Executor, demo_runtime::api::dispatch, include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm"));
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use runtime_io;
|
||||
use super::Executor;
|
||||
use substrate_executor::WasmExecutor;
|
||||
use codec::{KeyedVec, Slicable, Joiner};
|
||||
use keyring::Keyring::{self, Alice, Bob};
|
||||
use runtime_support::Hashable;
|
||||
use demo_runtime::runtime::staking::{self, balance, BALANCE_OF};
|
||||
use state_machine::{CodeExecutor, TestExternalities};
|
||||
use primitives::twox_128;
|
||||
use demo_primitives::{Hash, Header, BlockNumber, Block, Digest, Transaction,
|
||||
UncheckedTransaction, Function};
|
||||
use ed25519::{Public, Pair};
|
||||
|
||||
const BLOATY_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm");
|
||||
const COMPACT_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm");
|
||||
|
||||
// TODO: move into own crate.
|
||||
macro_rules! map {
|
||||
($( $name:expr => $value:expr ),*) => (
|
||||
vec![ $( ( $name, $value ) ),* ].into_iter().collect()
|
||||
)
|
||||
}
|
||||
|
||||
fn tx() -> UncheckedTransaction {
|
||||
let transaction = Transaction {
|
||||
signed: Alice.into(),
|
||||
nonce: 0,
|
||||
function: Function::StakingTransfer(Bob.into(), 69),
|
||||
};
|
||||
let signature = Keyring::from_raw_public(transaction.signed).unwrap()
|
||||
.sign(&transaction.encode());
|
||||
|
||||
UncheckedTransaction { transaction, signature }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn panic_execution_with_foreign_code_gives_error() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0]
|
||||
];
|
||||
|
||||
let r = Executor::new().call(&mut t, BLOATY_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx()));
|
||||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn panic_execution_with_native_equivalent_code_gives_error() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0]
|
||||
];
|
||||
|
||||
let r = Executor::new().call(&mut t, COMPACT_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx()));
|
||||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn successful_execution_with_native_equivalent_code_gives_ok() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
|
||||
];
|
||||
|
||||
let r = Executor::new().call(&mut t, COMPACT_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx()));
|
||||
assert!(r.is_ok());
|
||||
|
||||
runtime_io::with_externalities(&mut t, || {
|
||||
assert_eq!(balance(&Alice), 42);
|
||||
assert_eq!(balance(&Bob), 69);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn successful_execution_with_foreign_code_gives_ok() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
|
||||
];
|
||||
|
||||
let r = Executor::new().call(&mut t, BLOATY_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx()));
|
||||
assert!(r.is_ok());
|
||||
|
||||
runtime_io::with_externalities(&mut t, || {
|
||||
assert_eq!(balance(&Alice), 42);
|
||||
assert_eq!(balance(&Bob), 69);
|
||||
});
|
||||
}
|
||||
|
||||
fn new_test_ext() -> TestExternalities {
|
||||
staking::testing::externalities(2, 2, 0)
|
||||
}
|
||||
|
||||
fn construct_block(number: BlockNumber, parent_hash: Hash, state_root: Hash, txs: Vec<Transaction>) -> (Vec<u8>, Hash) {
|
||||
use triehash::ordered_trie_root;
|
||||
|
||||
let transactions = txs.into_iter().map(|transaction| {
|
||||
let signature = Pair::from(Keyring::from_public(Public::from_raw(transaction.signed)).unwrap())
|
||||
.sign(&transaction.encode());
|
||||
|
||||
UncheckedTransaction { transaction, signature }
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let transaction_root = ordered_trie_root(transactions.iter().map(Slicable::encode)).0.into();
|
||||
|
||||
let header = Header {
|
||||
parent_hash,
|
||||
number,
|
||||
state_root,
|
||||
transaction_root,
|
||||
digest: Digest { logs: vec![], },
|
||||
};
|
||||
let hash = header.blake2_256();
|
||||
|
||||
(Block { header, transactions }.encode(), hash.into())
|
||||
}
|
||||
|
||||
fn block1() -> (Vec<u8>, Hash) {
|
||||
construct_block(
|
||||
1,
|
||||
[69u8; 32].into(),
|
||||
hex!("970ae19447bef129c88ee80c72797fa9dfeda4ca1a26d10102b669d776eb0ccf").into(),
|
||||
vec![Transaction {
|
||||
signed: Alice.into(),
|
||||
nonce: 0,
|
||||
function: Function::StakingTransfer(Bob.into(), 69),
|
||||
}]
|
||||
)
|
||||
}
|
||||
|
||||
fn block2() -> (Vec<u8>, Hash) {
|
||||
construct_block(
|
||||
2,
|
||||
block1().1,
|
||||
hex!("347ece6ef0d193bd7c2bfbda17706b82eb24c0965f415784a44b138f0df034cd").into(),
|
||||
vec![
|
||||
Transaction {
|
||||
signed: Bob.into(),
|
||||
nonce: 0,
|
||||
function: Function::StakingTransfer(Alice.into(), 5),
|
||||
},
|
||||
Transaction {
|
||||
signed: Alice.into(),
|
||||
nonce: 1,
|
||||
function: Function::StakingTransfer(Bob.into(), 15),
|
||||
}
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_native_block_import_works() {
|
||||
let mut t = new_test_ext();
|
||||
|
||||
Executor::new().call(&mut t, COMPACT_CODE, "execute_block", &block1().0).unwrap();
|
||||
|
||||
runtime_io::with_externalities(&mut t, || {
|
||||
assert_eq!(balance(&Alice), 42);
|
||||
assert_eq!(balance(&Bob), 69);
|
||||
});
|
||||
|
||||
Executor::new().call(&mut t, COMPACT_CODE, "execute_block", &block2().0).unwrap();
|
||||
|
||||
runtime_io::with_externalities(&mut t, || {
|
||||
assert_eq!(balance(&Alice), 32);
|
||||
assert_eq!(balance(&Bob), 79);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_wasm_block_import_works() {
|
||||
let mut t = new_test_ext();
|
||||
|
||||
WasmExecutor.call(&mut t, COMPACT_CODE, "execute_block", &block1().0).unwrap();
|
||||
|
||||
runtime_io::with_externalities(&mut t, || {
|
||||
assert_eq!(balance(&Alice), 42);
|
||||
assert_eq!(balance(&Bob), 69);
|
||||
});
|
||||
|
||||
WasmExecutor.call(&mut t, COMPACT_CODE, "execute_block", &block2().0).unwrap();
|
||||
|
||||
runtime_io::with_externalities(&mut t, || {
|
||||
assert_eq!(balance(&Alice), 32);
|
||||
assert_eq!(balance(&Bob), 79);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn panic_execution_gives_error() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0]
|
||||
];
|
||||
|
||||
let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm");
|
||||
let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx()));
|
||||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn successful_execution_gives_ok() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
|
||||
];
|
||||
|
||||
let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm");
|
||||
let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx()));
|
||||
assert!(r.is_ok());
|
||||
|
||||
runtime_io::with_externalities(&mut t, || {
|
||||
assert_eq!(balance(&Alice), 42);
|
||||
assert_eq!(balance(&Bob), 69);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "demo-primitives"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", default_features = false }
|
||||
serde_derive = { version = "1.0", optional = true }
|
||||
substrate-codec = { path = "../../substrate/codec", default_features = false }
|
||||
substrate-primitives = { path = "../../substrate/primitives", default_features = false }
|
||||
substrate-runtime-std = { path = "../../substrate/runtime-std", default_features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
substrate-serializer = { path = "../../substrate/serializer" }
|
||||
pretty_assertions = "0.4"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"substrate-codec/std",
|
||||
"substrate-primitives/std",
|
||||
"substrate-runtime-std/std",
|
||||
"serde_derive",
|
||||
"serde/std",
|
||||
]
|
||||
@@ -0,0 +1,187 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Block and header type definitions.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use primitives::bytes;
|
||||
use primitives::H256;
|
||||
use rstd::vec::Vec;
|
||||
use codec::{Input, Slicable};
|
||||
use transaction::UncheckedTransaction;
|
||||
|
||||
pub use primitives::block::Id;
|
||||
|
||||
/// Used to refer to a block number.
|
||||
pub type Number = u64;
|
||||
|
||||
/// Hash used to refer to a block hash.
|
||||
pub type HeaderHash = H256;
|
||||
|
||||
/// Hash used to refer to a transaction hash.
|
||||
pub type TransactionHash = H256;
|
||||
|
||||
/// Execution log (event)
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
pub struct Log(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
|
||||
|
||||
impl Slicable for Log {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
Vec::<u8>::decode(input).map(Log)
|
||||
}
|
||||
|
||||
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||
self.0.using_encoded(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::codec::NonTrivialSlicable for Log { }
|
||||
|
||||
/// The digest of a block, useful for light-clients.
|
||||
#[derive(Clone, Default, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
pub struct Digest {
|
||||
/// All logs that have happened in the block.
|
||||
pub logs: Vec<Log>,
|
||||
}
|
||||
|
||||
impl Slicable for Digest {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
Vec::<Log>::decode(input).map(|logs| Digest { logs })
|
||||
}
|
||||
|
||||
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||
self.logs.using_encoded(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// The block "body": A bunch of transactions.
|
||||
pub type Body = Vec<UncheckedTransaction>;
|
||||
|
||||
/// A block on the chain.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
pub struct Block {
|
||||
/// The block header.
|
||||
pub header: Header,
|
||||
/// All relay-chain transactions.
|
||||
pub transactions: Body,
|
||||
}
|
||||
|
||||
impl Slicable for Block {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
let (header, transactions) = try_opt!(Slicable::decode(input));
|
||||
Some(Block { header, transactions })
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
v.extend(self.header.encode());
|
||||
v.extend(self.transactions.encode());
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
/// Header for a block.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
|
||||
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
|
||||
pub struct Header {
|
||||
/// Block parent's hash.
|
||||
pub parent_hash: HeaderHash,
|
||||
/// Block number.
|
||||
pub number: Number,
|
||||
/// State root after this transition.
|
||||
pub state_root: H256,
|
||||
/// The root of the trie that represents this block's transactions, indexed by a 32-byte integer.
|
||||
pub transaction_root: H256,
|
||||
/// The digest of activity on the block.
|
||||
pub digest: Digest,
|
||||
}
|
||||
|
||||
impl Header {
|
||||
/// Create a new instance with default fields except `number`, which is given as an argument.
|
||||
pub fn from_block_number(number: Number) -> Self {
|
||||
Header {
|
||||
parent_hash: Default::default(),
|
||||
number,
|
||||
state_root: Default::default(),
|
||||
transaction_root: Default::default(),
|
||||
digest: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Slicable for Header {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
Some(Header {
|
||||
parent_hash: try_opt!(Slicable::decode(input)),
|
||||
number: try_opt!(Slicable::decode(input)),
|
||||
state_root: try_opt!(Slicable::decode(input)),
|
||||
transaction_root: try_opt!(Slicable::decode(input)),
|
||||
digest: try_opt!(Slicable::decode(input)),
|
||||
})
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
self.parent_hash.using_encoded(|s| v.extend(s));
|
||||
self.number.using_encoded(|s| v.extend(s));
|
||||
self.state_root.using_encoded(|s| v.extend(s));
|
||||
self.transaction_root.using_encoded(|s| v.extend(s));
|
||||
self.digest.using_encoded(|s| v.extend(s));
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use codec::Slicable;
|
||||
use substrate_serializer as ser;
|
||||
|
||||
#[test]
|
||||
fn test_header_serialization() {
|
||||
let header = Header {
|
||||
parent_hash: 5.into(),
|
||||
number: 67,
|
||||
state_root: 3.into(),
|
||||
transaction_root: 6.into(),
|
||||
digest: Digest { logs: vec![Log(vec![1])] },
|
||||
};
|
||||
|
||||
assert_eq!(ser::to_string_pretty(&header), r#"{
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000005",
|
||||
"number": 67,
|
||||
"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000003",
|
||||
"transactionRoot": "0x0000000000000000000000000000000000000000000000000000000000000006",
|
||||
"digest": {
|
||||
"logs": [
|
||||
"0x01"
|
||||
]
|
||||
}
|
||||
}"#);
|
||||
|
||||
let v = header.encode();
|
||||
assert_eq!(Header::decode(&mut &v[..]).unwrap(), header);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Low-level types used throughout the Substrate Demo code.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
||||
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate serde;
|
||||
|
||||
extern crate substrate_runtime_std as rstd;
|
||||
extern crate substrate_primitives as primitives;
|
||||
#[cfg(test)]
|
||||
extern crate substrate_serializer;
|
||||
|
||||
extern crate substrate_codec as codec;
|
||||
|
||||
macro_rules! try_opt {
|
||||
($e: expr) => {
|
||||
match $e {
|
||||
Some(x) => x,
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod block;
|
||||
pub mod transaction;
|
||||
|
||||
pub use self::block::{Header, Block, Log, Digest};
|
||||
pub use self::block::Number as BlockNumber;
|
||||
pub use self::transaction::{Transaction, UncheckedTransaction, Function, Proposal, VoteThreshold};
|
||||
|
||||
/// Alias to Ed25519 pubkey that identifies an account on the relay chain. This will almost
|
||||
/// certainly continue to be the same as the substrate's `AuthorityId`.
|
||||
pub type AccountId = primitives::AuthorityId;
|
||||
|
||||
/// The Ed25519 pub key of an session that belongs to an authority of the relay chain. This is
|
||||
/// exactly equivalent to what the substrate calls an "authority".
|
||||
pub type SessionKey = primitives::AuthorityId;
|
||||
|
||||
/// Index of a transaction in the relay chain.
|
||||
pub type TxOrder = u64;
|
||||
|
||||
/// A hash of some data used by the relay chain.
|
||||
pub type Hash = primitives::H256;
|
||||
|
||||
/// Alias to 520-bit hash when used in the context of a signature on the relay chain.
|
||||
pub type Signature = primitives::hash::H512;
|
||||
@@ -0,0 +1,495 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Transaction type.
|
||||
|
||||
use rstd::prelude::*;
|
||||
use codec::{Input, Slicable, NonTrivialSlicable};
|
||||
use {AccountId, SessionKey};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::fmt;
|
||||
|
||||
use block::Number as BlockNumber;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
#[repr(u8)]
|
||||
enum InternalFunctionId {
|
||||
SystemSetCode = 0x00,
|
||||
|
||||
SessionSetLength = 0x10,
|
||||
SessionForceNewSession = 0x11,
|
||||
|
||||
StakingSetSessionsPerEra = 0x20,
|
||||
StakingSetBondingDuration = 0x21,
|
||||
StakingSetValidatorCount = 0x22,
|
||||
StakingForceNewEra = 0x23,
|
||||
|
||||
DemocracyCancelReferendum = 0x30,
|
||||
DemocracyStartReferendum = 0x31,
|
||||
|
||||
CouncilSetDesiredSeats = 0x40,
|
||||
CouncilRemoveMember = 0x41,
|
||||
CouncilSetPresentationDuration = 0x42,
|
||||
CouncilSetTermDuration = 0x43,
|
||||
|
||||
CouncilVoteSetCooloffPeriod = 0x50,
|
||||
CouncilVoteSetVotingPeriod = 0x51,
|
||||
}
|
||||
|
||||
impl InternalFunctionId {
|
||||
/// Derive `Some` value from a `u8`, or `None` if it's invalid.
|
||||
fn from_u8(value: u8) -> Option<InternalFunctionId> {
|
||||
let functions = [
|
||||
InternalFunctionId::SystemSetCode,
|
||||
InternalFunctionId::SessionSetLength,
|
||||
InternalFunctionId::SessionForceNewSession,
|
||||
InternalFunctionId::StakingSetSessionsPerEra,
|
||||
InternalFunctionId::StakingSetBondingDuration,
|
||||
InternalFunctionId::StakingSetValidatorCount,
|
||||
InternalFunctionId::StakingForceNewEra,
|
||||
InternalFunctionId::DemocracyCancelReferendum,
|
||||
InternalFunctionId::DemocracyStartReferendum,
|
||||
InternalFunctionId::CouncilSetDesiredSeats,
|
||||
InternalFunctionId::CouncilRemoveMember,
|
||||
InternalFunctionId::CouncilSetPresentationDuration,
|
||||
InternalFunctionId::CouncilSetTermDuration,
|
||||
InternalFunctionId::CouncilVoteSetCooloffPeriod,
|
||||
InternalFunctionId::CouncilVoteSetVotingPeriod,
|
||||
];
|
||||
functions.iter().map(|&f| f).find(|&f| value == f as u8)
|
||||
}
|
||||
}
|
||||
|
||||
/// A means of determining whether a referendum has gone through or not.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
pub enum VoteThreshold {
|
||||
/// A supermajority of approvals is needed to pass this vote.
|
||||
SuperMajorityApprove,
|
||||
/// A supermajority of rejects is needed to fail this vote.
|
||||
SuperMajorityAgainst,
|
||||
/// A simple majority of approvals is needed to pass this vote.
|
||||
SimpleMajority,
|
||||
}
|
||||
|
||||
impl Slicable for VoteThreshold {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
u8::decode(input).and_then(|v| match v {
|
||||
0 => Some(VoteThreshold::SuperMajorityApprove),
|
||||
1 => Some(VoteThreshold::SuperMajorityAgainst),
|
||||
2 => Some(VoteThreshold::SimpleMajority),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||
match *self {
|
||||
VoteThreshold::SuperMajorityApprove => 0u8,
|
||||
VoteThreshold::SuperMajorityAgainst => 1u8,
|
||||
VoteThreshold::SimpleMajority => 2u8,
|
||||
}.using_encoded(f)
|
||||
}
|
||||
}
|
||||
impl NonTrivialSlicable for VoteThreshold {}
|
||||
|
||||
/// Internal functions that can be dispatched to.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Proposal {
|
||||
SystemSetCode(Vec<u8>),
|
||||
SessionSetLength(BlockNumber),
|
||||
SessionForceNewSession,
|
||||
StakingSetSessionsPerEra(BlockNumber),
|
||||
StakingSetBondingDuration(BlockNumber),
|
||||
StakingSetValidatorCount(u32),
|
||||
StakingForceNewEra,
|
||||
DemocracyStartReferendum(Box<Proposal>, VoteThreshold),
|
||||
DemocracyCancelReferendum(u32),
|
||||
CouncilSetDesiredSeats(u32),
|
||||
CouncilRemoveMember(AccountId),
|
||||
CouncilSetPresentationDuration(BlockNumber),
|
||||
CouncilSetTermDuration(BlockNumber),
|
||||
CouncilVoteSetCooloffPeriod(BlockNumber),
|
||||
CouncilVoteSetVotingPeriod(BlockNumber),
|
||||
}
|
||||
|
||||
impl Slicable for Proposal {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
let id = u8::decode(input).and_then(InternalFunctionId::from_u8)?;
|
||||
let function = match id {
|
||||
InternalFunctionId::SystemSetCode =>
|
||||
Proposal::SystemSetCode(Slicable::decode(input)?),
|
||||
InternalFunctionId::SessionSetLength =>
|
||||
Proposal::SessionSetLength(Slicable::decode(input)?),
|
||||
InternalFunctionId::SessionForceNewSession =>
|
||||
Proposal::SessionForceNewSession,
|
||||
InternalFunctionId::StakingSetSessionsPerEra =>
|
||||
Proposal::StakingSetSessionsPerEra(Slicable::decode(input)?),
|
||||
InternalFunctionId::StakingSetBondingDuration =>
|
||||
Proposal::StakingSetBondingDuration(Slicable::decode(input)?),
|
||||
InternalFunctionId::StakingSetValidatorCount =>
|
||||
Proposal::StakingSetValidatorCount(Slicable::decode(input)?),
|
||||
InternalFunctionId::StakingForceNewEra =>
|
||||
Proposal::StakingForceNewEra,
|
||||
InternalFunctionId::DemocracyStartReferendum => {
|
||||
let a = Slicable::decode(input)?;
|
||||
let b = Slicable::decode(input)?;
|
||||
Proposal::DemocracyStartReferendum(Box::new(a), b)
|
||||
}
|
||||
InternalFunctionId::DemocracyCancelReferendum =>
|
||||
Proposal::DemocracyCancelReferendum(Slicable::decode(input)?),
|
||||
InternalFunctionId::CouncilSetDesiredSeats =>
|
||||
Proposal::CouncilSetDesiredSeats(Slicable::decode(input)?),
|
||||
InternalFunctionId::CouncilRemoveMember =>
|
||||
Proposal::CouncilRemoveMember(Slicable::decode(input)?),
|
||||
InternalFunctionId::CouncilSetPresentationDuration =>
|
||||
Proposal::CouncilSetPresentationDuration(Slicable::decode(input)?),
|
||||
InternalFunctionId::CouncilSetTermDuration =>
|
||||
Proposal::CouncilSetTermDuration(Slicable::decode(input)?),
|
||||
InternalFunctionId::CouncilVoteSetCooloffPeriod =>
|
||||
Proposal::CouncilVoteSetCooloffPeriod(Slicable::decode(input)?),
|
||||
InternalFunctionId::CouncilVoteSetVotingPeriod =>
|
||||
Proposal::CouncilVoteSetVotingPeriod(Slicable::decode(input)?),
|
||||
};
|
||||
|
||||
Some(function)
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
match *self {
|
||||
Proposal::SystemSetCode(ref data) => {
|
||||
(InternalFunctionId::SystemSetCode as u8).using_encoded(|s| v.extend(s));
|
||||
data.using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Proposal::SessionSetLength(ref data) => {
|
||||
(InternalFunctionId::SessionSetLength as u8).using_encoded(|s| v.extend(s));
|
||||
data.using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Proposal::SessionForceNewSession => {
|
||||
(InternalFunctionId::SessionForceNewSession as u8).using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Proposal::StakingSetSessionsPerEra(ref data) => {
|
||||
(InternalFunctionId::StakingSetSessionsPerEra as u8).using_encoded(|s| v.extend(s));
|
||||
data.using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Proposal::StakingSetBondingDuration(ref data) => {
|
||||
(InternalFunctionId::StakingSetBondingDuration as u8).using_encoded(|s| v.extend(s));
|
||||
data.using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Proposal::StakingSetValidatorCount(ref data) => {
|
||||
(InternalFunctionId::StakingSetValidatorCount as u8).using_encoded(|s| v.extend(s));
|
||||
data.using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Proposal::StakingForceNewEra => {
|
||||
(InternalFunctionId::StakingForceNewEra as u8).using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Proposal::DemocracyCancelReferendum(ref data) => {
|
||||
(InternalFunctionId::DemocracyCancelReferendum as u8).using_encoded(|s| v.extend(s));
|
||||
data.using_encoded(|s| v.extend(s));
|
||||
}
|
||||
_ => { unimplemented!() }
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
/// Public functions that can be dispatched to.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
#[repr(u8)]
|
||||
enum FunctionId {
|
||||
TimestampSet = 0x00,
|
||||
|
||||
SessionSetKey = 0x10,
|
||||
|
||||
StakingStake = 0x20,
|
||||
StakingUnstake = 0x21,
|
||||
StakingTransfer = 0x22,
|
||||
|
||||
CouncilVotePropose = 0x30,
|
||||
CouncilVoteVote = 0x31,
|
||||
CouncilVoteVeto = 0x32,
|
||||
|
||||
CouncilSetApprovals = 0x40,
|
||||
CouncilReapInactiveVoter = 0x41,
|
||||
CouncilRetractVoter = 0x42,
|
||||
CouncilSubmitCandidacy = 0x43,
|
||||
CouncilPresentWinner = 0x44,
|
||||
|
||||
DemocracyPropose = 0x50,
|
||||
DemocracySecond = 0x51,
|
||||
DemocracyVote = 0x52,
|
||||
}
|
||||
|
||||
impl FunctionId {
|
||||
/// Derive `Some` value from a `u8`, or `None` if it's invalid.
|
||||
fn from_u8(value: u8) -> Option<FunctionId> {
|
||||
use self::*;
|
||||
let functions = [FunctionId::StakingStake, FunctionId::StakingUnstake,
|
||||
FunctionId::StakingTransfer, FunctionId::SessionSetKey, FunctionId::TimestampSet,
|
||||
FunctionId::CouncilVotePropose, FunctionId::CouncilVoteVote, FunctionId::CouncilVoteVeto,
|
||||
FunctionId::CouncilSetApprovals, FunctionId::CouncilReapInactiveVoter,
|
||||
FunctionId::CouncilRetractVoter, FunctionId::CouncilSubmitCandidacy,
|
||||
FunctionId::CouncilPresentWinner, FunctionId::DemocracyPropose,
|
||||
FunctionId::DemocracySecond, FunctionId::DemocracyVote,
|
||||
];
|
||||
functions.iter().map(|&f| f).find(|&f| value == f as u8)
|
||||
}
|
||||
}
|
||||
|
||||
/// Functions on the runtime.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Function {
|
||||
TimestampSet(u64),
|
||||
|
||||
SessionSetKey(SessionKey),
|
||||
|
||||
StakingStake,
|
||||
StakingUnstake,
|
||||
StakingTransfer(AccountId, u64),
|
||||
|
||||
CouncilVotePropose(Proposal),
|
||||
CouncilVoteVote([u8; 32], bool),
|
||||
CouncilVoteVeto([u8; 32]),
|
||||
|
||||
CouncilSetApprovals(Vec<bool>, u32),
|
||||
CouncilReapInactiveVoter(u32, AccountId, u32, u32),
|
||||
CouncilRetractVoter(u32),
|
||||
CouncilSubmitCandidacy(u32),
|
||||
CouncilPresentWinner(AccountId, u64, u32),
|
||||
|
||||
DemocracyPropose(Proposal, u64),
|
||||
DemocracySecond(u32),
|
||||
DemocracyVote(u32, bool),
|
||||
}
|
||||
|
||||
impl Slicable for Function {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
let id = u8::decode(input).and_then(FunctionId::from_u8)?;
|
||||
Some(match id {
|
||||
FunctionId::TimestampSet =>
|
||||
Function::TimestampSet(Slicable::decode(input)?),
|
||||
FunctionId::SessionSetKey =>
|
||||
Function::SessionSetKey(Slicable::decode(input)?),
|
||||
FunctionId::StakingStake => Function::StakingStake,
|
||||
FunctionId::StakingUnstake => Function::StakingUnstake,
|
||||
FunctionId::StakingTransfer => {
|
||||
let to = Slicable::decode(input)?;
|
||||
let amount = Slicable::decode(input)?;
|
||||
Function::StakingTransfer(to, amount)
|
||||
}
|
||||
FunctionId::CouncilVotePropose => Function::CouncilVotePropose(Slicable::decode(input)?),
|
||||
FunctionId::CouncilVoteVote => {
|
||||
let a = Slicable::decode(input)?;
|
||||
let b = Slicable::decode(input)?;
|
||||
Function::CouncilVoteVote(a, b)
|
||||
}
|
||||
FunctionId::CouncilVoteVeto => Function::CouncilVoteVeto(Slicable::decode(input)?),
|
||||
FunctionId::CouncilSetApprovals => {
|
||||
let a = Slicable::decode(input)?;
|
||||
let b = Slicable::decode(input)?;
|
||||
Function::CouncilSetApprovals(a, b)
|
||||
}
|
||||
FunctionId::CouncilReapInactiveVoter => {
|
||||
let a = Slicable::decode(input)?;
|
||||
let b = Slicable::decode(input)?;
|
||||
let c = Slicable::decode(input)?;
|
||||
let d = Slicable::decode(input)?;
|
||||
Function::CouncilReapInactiveVoter(a, b, c, d)
|
||||
}
|
||||
FunctionId::CouncilRetractVoter => Function::CouncilRetractVoter(Slicable::decode(input)?),
|
||||
FunctionId::CouncilSubmitCandidacy => Function::CouncilSubmitCandidacy(Slicable::decode(input)?),
|
||||
FunctionId::CouncilPresentWinner => {
|
||||
let a = Slicable::decode(input)?;
|
||||
let b = Slicable::decode(input)?;
|
||||
let c = Slicable::decode(input)?;
|
||||
Function::CouncilPresentWinner(a, b, c)
|
||||
}
|
||||
FunctionId::DemocracyPropose => {
|
||||
let a = Slicable::decode(input)?;
|
||||
let b = Slicable::decode(input)?;
|
||||
Function::DemocracyPropose(a, b)
|
||||
}
|
||||
FunctionId::DemocracySecond => Function::DemocracySecond(Slicable::decode(input)?),
|
||||
FunctionId::DemocracyVote => {
|
||||
let a = Slicable::decode(input)?;
|
||||
let b = Slicable::decode(input)?;
|
||||
Function::DemocracyVote(a, b)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
match *self {
|
||||
Function::TimestampSet(ref data) => {
|
||||
(FunctionId::TimestampSet as u8).using_encoded(|s| v.extend(s));
|
||||
data.using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Function::SessionSetKey(ref data) => {
|
||||
(FunctionId::SessionSetKey as u8).using_encoded(|s| v.extend(s));
|
||||
data.using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Function::StakingStake => {
|
||||
(FunctionId::StakingStake as u8).using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Function::StakingUnstake => {
|
||||
(FunctionId::StakingUnstake as u8).using_encoded(|s| v.extend(s));
|
||||
}
|
||||
Function::StakingTransfer(ref to, ref amount) => {
|
||||
(FunctionId::StakingTransfer as u8).using_encoded(|s| v.extend(s));
|
||||
to.using_encoded(|s| v.extend(s));
|
||||
amount.using_encoded(|s| v.extend(s));
|
||||
}
|
||||
_ => { unimplemented!() }
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||
f(self.encode().as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
/// A vetted and verified transaction from the external world.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
pub struct Transaction {
|
||||
/// Who signed it (note this is not a signature).
|
||||
pub signed: super::AccountId,
|
||||
/// The number of transactions have come before from the same signer.
|
||||
pub nonce: super::TxOrder,
|
||||
/// The function that should be called.
|
||||
pub function: Function,
|
||||
}
|
||||
|
||||
impl Slicable for Transaction {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
Some(Transaction {
|
||||
signed: try_opt!(Slicable::decode(input)),
|
||||
nonce: try_opt!(Slicable::decode(input)),
|
||||
function: try_opt!(Slicable::decode(input)),
|
||||
})
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
self.signed.using_encoded(|s| v.extend(s));
|
||||
self.nonce.using_encoded(|s| v.extend(s));
|
||||
self.function.using_encoded(|s| v.extend(s));
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl ::codec::NonTrivialSlicable for Transaction {}
|
||||
|
||||
/// A transactions right from the external world. Unchecked.
|
||||
#[derive(Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
||||
pub struct UncheckedTransaction {
|
||||
/// The actual transaction information.
|
||||
pub transaction: Transaction,
|
||||
/// The signature; should be an Ed25519 signature applied to the serialised `transaction` field.
|
||||
pub signature: super::Signature,
|
||||
}
|
||||
|
||||
impl Slicable for UncheckedTransaction {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
// This is a little more complicated than usual since the binary format must be compatible
|
||||
// with substrate's generic `Vec<u8>` type. Basically this just means accepting that there
|
||||
// will be a prefix of u32, which has the total number of bytes following (we don't need
|
||||
// to use this).
|
||||
let _length_do_not_remove_me_see_above: u32 = try_opt!(Slicable::decode(input));
|
||||
|
||||
Some(UncheckedTransaction {
|
||||
transaction: try_opt!(Slicable::decode(input)),
|
||||
signature: try_opt!(Slicable::decode(input)),
|
||||
})
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
// need to prefix with the total length as u32 to ensure it's binary comptible with
|
||||
// Vec<u8>. we'll make room for it here, then overwrite once we know the length.
|
||||
v.extend(&[0u8; 4]);
|
||||
|
||||
self.transaction.signed.using_encoded(|s| v.extend(s));
|
||||
self.transaction.nonce.using_encoded(|s| v.extend(s));
|
||||
self.transaction.function.using_encoded(|s| v.extend(s));
|
||||
self.signature.using_encoded(|s| v.extend(s));
|
||||
|
||||
let length = (v.len() - 4) as u32;
|
||||
length.using_encoded(|s| v[0..4].copy_from_slice(s));
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl ::codec::NonTrivialSlicable for UncheckedTransaction {}
|
||||
|
||||
impl PartialEq for UncheckedTransaction {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.signature.iter().eq(other.signature.iter()) && self.transaction == other.transaction
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl fmt::Debug for UncheckedTransaction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "UncheckedTransaction({:?})", self.transaction)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use primitives;
|
||||
use ::codec::Slicable;
|
||||
use primitives::hexdisplay::HexDisplay;
|
||||
|
||||
#[test]
|
||||
fn serialize_unchecked() {
|
||||
let tx = UncheckedTransaction {
|
||||
transaction: Transaction {
|
||||
signed: [1; 32],
|
||||
nonce: 999u64,
|
||||
function: Function::TimestampSet(135135),
|
||||
},
|
||||
signature: primitives::hash::H512([0; 64]),
|
||||
};
|
||||
// 71000000
|
||||
// 0101010101010101010101010101010101010101010101010101010101010101
|
||||
// e703000000000000
|
||||
// 00
|
||||
// df0f0200
|
||||
// 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
let v = Slicable::encode(&tx);
|
||||
println!("{}", HexDisplay::from(&v));
|
||||
assert_eq!(UncheckedTransaction::decode(&mut &v[..]).unwrap(), tx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "demo-runtime"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
rustc-hex = "1.0"
|
||||
hex-literal = "0.1.0"
|
||||
log = { version = "0.3", optional = true }
|
||||
substrate-codec = { path = "../../substrate/codec" }
|
||||
substrate-runtime-std = { path = "../../substrate/runtime-std" }
|
||||
substrate-runtime-io = { path = "../../substrate/runtime-io" }
|
||||
substrate-runtime-support = { path = "../../substrate/runtime-support" }
|
||||
substrate-primitives = { path = "../../substrate/primitives" }
|
||||
substrate-keyring = { path = "../../substrate/keyring" }
|
||||
demo-primitives = { path = "../primitives" }
|
||||
integer-sqrt = "0.1.0"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"substrate-codec/std",
|
||||
"substrate-runtime-std/std",
|
||||
"substrate-runtime-io/std",
|
||||
"substrate-runtime-support/std",
|
||||
"substrate-primitives/std",
|
||||
"demo-primitives/std",
|
||||
"log"
|
||||
]
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use runtime::{system, consensus, session};
|
||||
|
||||
impl_stubs!(
|
||||
execute_block => |block| system::internal::execute_block(block),
|
||||
execute_transaction => |(header, utx)| system::internal::execute_transaction(utx, header),
|
||||
finalise_block => |header| system::internal::finalise_block(header),
|
||||
validator_count => |()| session::validator_count(),
|
||||
validators => |()| session::validators(),
|
||||
authorities => |()| consensus::authorities()
|
||||
);
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Dispatch system. Just dispatches calls.
|
||||
|
||||
use demo_primitives::{Function, Proposal, AccountId};
|
||||
use runtime::{staking, system, session, democracy, council, council_vote, timestamp};
|
||||
|
||||
/// Dispatch a proposal.
|
||||
pub fn proposal(proposal: Proposal) {
|
||||
match proposal {
|
||||
Proposal::SystemSetCode(ref a) =>
|
||||
system::privileged::set_code(a),
|
||||
Proposal::SessionSetLength(a) =>
|
||||
session::privileged::set_length(a),
|
||||
Proposal::SessionForceNewSession =>
|
||||
session::privileged::force_new_session(),
|
||||
Proposal::StakingSetSessionsPerEra(a) =>
|
||||
staking::privileged::set_sessions_per_era(a),
|
||||
Proposal::StakingSetBondingDuration(a) =>
|
||||
staking::privileged::set_bonding_duration(a),
|
||||
Proposal::StakingSetValidatorCount(a) =>
|
||||
staking::privileged::set_validator_count(a),
|
||||
Proposal::StakingForceNewEra =>
|
||||
staking::privileged::force_new_era(),
|
||||
Proposal::DemocracyCancelReferendum(a) =>
|
||||
democracy::privileged::cancel_referendum(a),
|
||||
Proposal::DemocracyStartReferendum(a, b) =>
|
||||
democracy::privileged::start_referendum(*a, b),
|
||||
Proposal::CouncilSetDesiredSeats(a) =>
|
||||
council::privileged::set_desired_seats(a),
|
||||
Proposal::CouncilRemoveMember(a) =>
|
||||
council::privileged::remove_member(&a),
|
||||
Proposal::CouncilSetPresentationDuration(a) =>
|
||||
council::privileged::set_presentation_duration(a),
|
||||
Proposal::CouncilSetTermDuration(a) =>
|
||||
council::privileged::set_term_duration(a),
|
||||
Proposal::CouncilVoteSetCooloffPeriod(a) =>
|
||||
council_vote::privileged::set_cooloff_period(a),
|
||||
Proposal::CouncilVoteSetVotingPeriod(a) =>
|
||||
council_vote::privileged::set_voting_period(a),
|
||||
}
|
||||
}
|
||||
|
||||
/// Dispatch a function.
|
||||
pub fn function(function: &Function, transactor: &AccountId) {
|
||||
match *function {
|
||||
Function::StakingStake =>
|
||||
staking::public::stake(transactor),
|
||||
Function::StakingUnstake =>
|
||||
staking::public::unstake(transactor),
|
||||
Function::StakingTransfer(dest, value) =>
|
||||
staking::public::transfer(transactor, &dest, value),
|
||||
Function::SessionSetKey(session) =>
|
||||
session::public::set_key(transactor, &session),
|
||||
Function::TimestampSet(t) =>
|
||||
timestamp::public::set(t),
|
||||
Function::CouncilVotePropose(ref a) =>
|
||||
council_vote::public::propose(transactor, a),
|
||||
Function::CouncilVoteVote(ref a, b) =>
|
||||
council_vote::public::vote(transactor, a, b),
|
||||
Function::CouncilVoteVeto(ref a) =>
|
||||
council_vote::public::veto(transactor, a),
|
||||
Function::CouncilSetApprovals(ref a, b) =>
|
||||
council::public::set_approvals(transactor, a, b),
|
||||
Function::CouncilReapInactiveVoter(a, ref b, c, d) =>
|
||||
council::public::reap_inactive_voter(transactor, a, b, c, d),
|
||||
Function::CouncilRetractVoter(a) =>
|
||||
council::public::retract_voter(transactor, a),
|
||||
Function::CouncilSubmitCandidacy(a) =>
|
||||
council::public::submit_candidacy(transactor, a),
|
||||
Function::CouncilPresentWinner(ref a, b, c) =>
|
||||
council::public::present_winner(transactor, a, b, c),
|
||||
Function::DemocracyPropose(ref a, b) =>
|
||||
democracy::public::propose(transactor, a, b),
|
||||
Function::DemocracySecond(a) =>
|
||||
democracy::public::second(transactor, a),
|
||||
Function::DemocracyVote(a, b) =>
|
||||
democracy::public::vote(transactor, a, b),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Environment API: Allows certain information to be accessed throughout the runtime.
|
||||
|
||||
use rstd::boxed::Box;
|
||||
use rstd::mem;
|
||||
use rstd::cell::RefCell;
|
||||
use rstd::rc::Rc;
|
||||
|
||||
use demo_primitives::{BlockNumber, Digest, Hash};
|
||||
|
||||
#[derive(Default)]
|
||||
/// The information that can be accessed globally.
|
||||
pub struct Environment {
|
||||
/// The current block number.
|
||||
pub block_number: BlockNumber,
|
||||
/// The current block's parent hash.
|
||||
pub parent_hash: Hash,
|
||||
/// The current block digest.
|
||||
pub digest: Digest,
|
||||
}
|
||||
|
||||
/// Do something with the environment and return its value. Keep the function short.
|
||||
pub fn with_env<T, F: FnOnce(&mut Environment) -> T>(f: F) -> T {
|
||||
let e = env();
|
||||
let mut eb = e.borrow_mut();
|
||||
f(&mut *eb)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn env() -> Rc<RefCell<Environment>> {
|
||||
// Initialize it to a null value
|
||||
static mut SINGLETON: *const Rc<RefCell<Environment>> = 0 as *const Rc<RefCell<Environment>>;
|
||||
|
||||
unsafe {
|
||||
if SINGLETON == 0 as *const Rc<RefCell<Environment>> {
|
||||
// Make it
|
||||
let singleton: Rc<RefCell<Environment>> = Rc::new(RefCell::new(Default::default()));
|
||||
|
||||
// Put it in the heap so it can outlive this call
|
||||
SINGLETON = mem::transmute(Box::new(singleton));
|
||||
}
|
||||
|
||||
// Now we give out a copy of the data that is safe to use concurrently.
|
||||
(*SINGLETON).clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn env() -> Rc<RefCell<Environment>> {
|
||||
// Initialize it to a null value
|
||||
thread_local!{
|
||||
static SINGLETON: RefCell<*const Rc<RefCell<Environment>>> = RefCell::new(0 as *const Rc<RefCell<Environment>>);
|
||||
}
|
||||
|
||||
SINGLETON.with(|s| unsafe {
|
||||
if *s.borrow() == 0 as *const Rc<RefCell<Environment>> {
|
||||
// Make it
|
||||
let singleton: Rc<RefCell<Environment>> = Rc::new(RefCell::new(Default::default()));
|
||||
|
||||
// Put it in the heap so it can outlive this call
|
||||
*s.borrow_mut() = mem::transmute(Box::new(singleton));
|
||||
}
|
||||
|
||||
// Now we give out a copy of the data that is safe to use concurrently.
|
||||
(**s.borrow()).clone()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Tool for creating the genesis block.
|
||||
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use std::collections::HashMap;
|
||||
use runtime_io::twox_128;
|
||||
use runtime_support::Hashable;
|
||||
use primitives::Block;
|
||||
use demo_primitives::{BlockNumber, AccountId};
|
||||
use runtime::staking::Balance;
|
||||
use runtime::{staking, session, consensus, system, democracy, council, council_vote};
|
||||
|
||||
/// Configuration of a general Substrate Demo genesis block.
|
||||
pub struct GenesisConfig {
|
||||
pub validators: Vec<AccountId>,
|
||||
pub authorities: Vec<AccountId>,
|
||||
pub balances: Vec<(AccountId, Balance)>,
|
||||
pub block_time: u64,
|
||||
pub session_length: BlockNumber,
|
||||
pub sessions_per_era: BlockNumber,
|
||||
pub bonding_duration: BlockNumber,
|
||||
pub launch_period: BlockNumber,
|
||||
pub voting_period: BlockNumber,
|
||||
pub minimum_deposit: Balance,
|
||||
pub candidacy_bond: Balance,
|
||||
pub voter_bond: Balance,
|
||||
pub present_slash_per_voter: Balance,
|
||||
pub carry_count: u32,
|
||||
pub presentation_duration: BlockNumber,
|
||||
pub council_election_voting_period: BlockNumber,
|
||||
pub council_term_duration: BlockNumber,
|
||||
pub desired_seats: u32,
|
||||
pub inactive_grace_period: BlockNumber,
|
||||
pub cooloff_period: BlockNumber,
|
||||
pub council_proposal_voting_period: BlockNumber,
|
||||
}
|
||||
|
||||
impl GenesisConfig {
|
||||
pub fn new_simple(authorities_validators: Vec<AccountId>, balance: Balance) -> Self {
|
||||
GenesisConfig {
|
||||
validators: authorities_validators.clone(),
|
||||
authorities: authorities_validators.clone(),
|
||||
balances: authorities_validators.iter().map(|v| (v.clone(), balance)).collect(),
|
||||
block_time: 30, // 30 second block time.
|
||||
session_length: 120, // that's 1 hour per session.
|
||||
sessions_per_era: 24, // 24 hours per era.
|
||||
bonding_duration: 90, // 90 days per bond.
|
||||
launch_period: 120 * 24 * 14, // 2 weeks per public referendum
|
||||
voting_period: 120 * 24 * 28, // 4 weeks to discuss & vote on an active referendum
|
||||
minimum_deposit: 1000, // 1000 as the minimum deposit for a referendum
|
||||
candidacy_bond: 1000, // 1000 to become a council candidate
|
||||
voter_bond: 100, // 100 down to vote for a candidate
|
||||
present_slash_per_voter: 1, // slash by 1 per voter for an invalid presentation.
|
||||
carry_count: 24, // carry over the 24 runners-up to the next council election
|
||||
presentation_duration: 120 * 24, // one day for presenting winners.
|
||||
council_election_voting_period: 7 * 120 * 24, // one week period between possible council elections.
|
||||
council_term_duration: 180 * 120 * 24, // 180 day term duration for the council.
|
||||
desired_seats: 0, // start with no council: we'll raise this once the stake has been dispersed a bit.
|
||||
inactive_grace_period: 1, // one addition vote should go by before an inactive voter can be reaped.
|
||||
cooloff_period: 90 * 120 * 24, // 90 day cooling off period if council member vetoes a proposal.
|
||||
council_proposal_voting_period: 7 * 120 * 24, // 7 day voting period for council members.
|
||||
}
|
||||
}
|
||||
|
||||
pub fn genesis_map(&self) -> HashMap<Vec<u8>, Vec<u8>> {
|
||||
let wasm_runtime = include_bytes!("../wasm/genesis.wasm").to_vec();
|
||||
vec![
|
||||
(&session::SESSION_LENGTH[..], vec![].and(&self.session_length)),
|
||||
(&session::VALIDATOR_COUNT[..], vec![].and(&(self.validators.len() as u32))),
|
||||
|
||||
(&staking::INTENTION_COUNT[..], vec![].and(&0u32)),
|
||||
(&staking::SESSIONS_PER_ERA[..], vec![].and(&self.sessions_per_era)),
|
||||
(&staking::CURRENT_ERA[..], vec![].and(&0u64)),
|
||||
|
||||
(&democracy::LAUNCH_PERIOD[..], vec![].and(&self.launch_period)),
|
||||
(&democracy::VOTING_PERIOD[..], vec![].and(&self.voting_period)),
|
||||
(&democracy::MINIMUM_DEPOSIT[..], vec![].and(&self.minimum_deposit)),
|
||||
|
||||
(&council::CANDIDACY_BOND[..], vec![].and(&self.candidacy_bond)),
|
||||
(&council::VOTING_BOND[..], vec![].and(&self.voter_bond)),
|
||||
(&council::PRESENT_SLASH_PER_VOTER[..], vec![].and(&self.present_slash_per_voter)),
|
||||
(&council::CARRY_COUNT[..], vec![].and(&self.carry_count)),
|
||||
(&council::PRESENTATION_DURATION[..], vec![].and(&self.presentation_duration)),
|
||||
(&council::VOTING_PERIOD[..], vec![].and(&self.council_election_voting_period)),
|
||||
(&council::TERM_DURATION[..], vec![].and(&self.council_term_duration)),
|
||||
(&council::DESIRED_SEATS[..], vec![].and(&self.desired_seats)),
|
||||
(&council::INACTIVE_GRACE_PERIOD[..], vec![].and(&self.inactive_grace_period)),
|
||||
|
||||
(&council_vote::COOLOFF_PERIOD[..], vec![].and(&self.cooloff_period)),
|
||||
(&council_vote::VOTING_PERIOD[..], vec![].and(&self.council_proposal_voting_period))
|
||||
].into_iter()
|
||||
.map(|(k, v)| (k.into(), v))
|
||||
.chain(self.validators.iter()
|
||||
.enumerate()
|
||||
.map(|(i, account)| ((i as u32).to_keyed_vec(session::VALIDATOR_AT), vec![].and(account)))
|
||||
).chain(self.balances.iter()
|
||||
.map(|&(account, balance)| (account.to_keyed_vec(staking::BALANCE_OF), vec![].and(&balance)))
|
||||
)
|
||||
.map(|(k, v)| (twox_128(&k[..])[..].to_vec(), v.to_vec()))
|
||||
.chain(vec![
|
||||
(system::CODE[..].into(), wasm_runtime),
|
||||
(consensus::AUTHORITY_COUNT[..].into(), vec![].and(&(self.authorities.len() as u32))),
|
||||
].into_iter())
|
||||
.chain(self.authorities.iter()
|
||||
.enumerate()
|
||||
.map(|(i, account)| ((i as u32).to_keyed_vec(consensus::AUTHORITY_AT), vec![].and(account)))
|
||||
)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn additional_storage_with_genesis(genesis_block: &Block) -> HashMap<Vec<u8>, Vec<u8>> {
|
||||
use codec::Slicable;
|
||||
map![
|
||||
twox_128(&0u64.to_keyed_vec(system::BLOCK_HASH_AT)).to_vec() => genesis_block.header.blake2_256().encode()
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! The Substrate Demo runtime. This can be compiled with #[no_std], ready for Wasm.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[allow(unused_imports)] #[macro_use] extern crate substrate_runtime_std as rstd;
|
||||
#[macro_use] extern crate substrate_runtime_io as runtime_io;
|
||||
extern crate substrate_runtime_support as runtime_support;
|
||||
#[cfg(any(feature = "std", test))] extern crate substrate_keyring as keyring;
|
||||
|
||||
#[cfg(feature = "std")] extern crate rustc_hex;
|
||||
|
||||
extern crate substrate_codec as codec;
|
||||
#[cfg(feature = "std")] #[macro_use] extern crate substrate_primitives as primitives;
|
||||
extern crate demo_primitives;
|
||||
|
||||
#[cfg(test)] #[macro_use] extern crate hex_literal;
|
||||
|
||||
extern crate integer_sqrt;
|
||||
|
||||
pub mod environment;
|
||||
pub mod runtime;
|
||||
pub mod api;
|
||||
pub mod dispatch;
|
||||
|
||||
#[cfg(feature = "std")] pub mod genesismap;
|
||||
|
||||
/// Type definitions and helpers for transactions.
|
||||
pub mod transaction {
|
||||
use rstd::ops;
|
||||
use demo_primitives::Signature;
|
||||
pub use demo_primitives::{Transaction, UncheckedTransaction};
|
||||
|
||||
/// A type-safe indicator that a transaction has been checked.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub struct CheckedTransaction(UncheckedTransaction);
|
||||
|
||||
impl CheckedTransaction {
|
||||
/// Get a reference to the checked signature.
|
||||
pub fn signature(&self) -> &Signature {
|
||||
&self.0.signature
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for CheckedTransaction {
|
||||
type Target = Transaction;
|
||||
|
||||
fn deref(&self) -> &Transaction {
|
||||
&self.0.transaction
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the signature on a transaction.
|
||||
///
|
||||
/// On failure, return the transaction back.
|
||||
pub fn check(tx: UncheckedTransaction) -> Result<CheckedTransaction, UncheckedTransaction> {
|
||||
let msg = ::codec::Slicable::encode(&tx.transaction);
|
||||
if ::runtime_io::ed25519_verify(&tx.signature.0, &msg, &tx.transaction.signed) {
|
||||
Ok(CheckedTransaction(tx))
|
||||
} else {
|
||||
Err(tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Conensus module for runtime; manages the authority set ready for the native code.
|
||||
|
||||
use rstd::prelude::*;
|
||||
use runtime_support::storage::unhashed::StorageVec;
|
||||
use demo_primitives::SessionKey;
|
||||
|
||||
pub const AUTHORITY_AT: &'static[u8] = b":auth:";
|
||||
pub const AUTHORITY_COUNT: &'static[u8] = b":auth:len";
|
||||
|
||||
struct AuthorityStorageVec {}
|
||||
impl StorageVec for AuthorityStorageVec {
|
||||
type Item = SessionKey;
|
||||
const PREFIX: &'static[u8] = AUTHORITY_AT;
|
||||
}
|
||||
|
||||
/// Get the current set of authorities. These are the session keys.
|
||||
pub fn authorities() -> Vec<SessionKey> {
|
||||
AuthorityStorageVec::items()
|
||||
}
|
||||
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
|
||||
/// Set the current set of authorities' session keys.
|
||||
///
|
||||
/// Called by `next_session` only.
|
||||
pub fn set_authorities(authorities: &[SessionKey]) {
|
||||
AuthorityStorageVec::set_items(authorities);
|
||||
}
|
||||
|
||||
/// Set a single authority by index.
|
||||
pub fn set_authority(index: u32, key: &SessionKey) {
|
||||
AuthorityStorageVec::set_item(index, key);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,485 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Council voting system.
|
||||
|
||||
use rstd::prelude::*;
|
||||
use codec::{KeyedVec, Slicable, Input, NonTrivialSlicable};
|
||||
use runtime_support::Hashable;
|
||||
use runtime_support::storage;
|
||||
use demo_primitives::{Proposal, AccountId, Hash, BlockNumber};
|
||||
use runtime::{system, democracy, council};
|
||||
use runtime::staking::Balance;
|
||||
|
||||
type ProposalHash = [u8; 32];
|
||||
|
||||
pub const COOLOFF_PERIOD: &[u8] = b"cov:cooloff"; // BlockNumber
|
||||
pub const VOTING_PERIOD: &[u8] = b"cov:period"; // BlockNumber
|
||||
|
||||
pub const PROPOSALS: &[u8] = b"cov:prs"; // Vec<(expiry: BlockNumber, ProposalHash)> ordered by expiry.
|
||||
pub const PROPOSAL_OF: &[u8] = b"cov:pro"; // ProposalHash -> Proposal
|
||||
pub const PROPOSAL_VOTERS: &[u8] = b"cov:voters:"; // ProposalHash -> Vec<AccountId>
|
||||
pub const COUNCIL_VOTE_OF: &[u8] = b"cov:vote:"; // (ProposalHash, AccountId) -> bool
|
||||
pub const VETOED_PROPOSAL: &[u8] = b"cov:veto:"; // ProposalHash -> (BlockNumber, sorted_vetoers: Vec<AccountId>)
|
||||
|
||||
pub fn cooloff_period() -> BlockNumber {
|
||||
storage::get(COOLOFF_PERIOD).expect("all parameters must be defined")
|
||||
}
|
||||
|
||||
pub fn voting_period() -> BlockNumber {
|
||||
storage::get(VOTING_PERIOD).expect("all parameters must be defined")
|
||||
}
|
||||
|
||||
pub fn proposals() -> Vec<(BlockNumber, ProposalHash)> {
|
||||
storage::get_or_default(PROPOSALS)
|
||||
}
|
||||
|
||||
pub fn is_vetoed(proposal: &ProposalHash) -> bool {
|
||||
storage::get(&proposal.to_keyed_vec(VETOED_PROPOSAL))
|
||||
.map(|(expiry, _): (BlockNumber, Vec<AccountId>)| system::block_number() < expiry)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn veto_of(proposal: &ProposalHash) -> Option<(BlockNumber, Vec<AccountId>)> {
|
||||
storage::get(&proposal.to_keyed_vec(VETOED_PROPOSAL))
|
||||
}
|
||||
|
||||
fn set_veto_of(proposal: &ProposalHash, expiry: BlockNumber, vetoers: Vec<AccountId>) {
|
||||
storage::put(&proposal.to_keyed_vec(VETOED_PROPOSAL), &(expiry, vetoers))
|
||||
}
|
||||
|
||||
fn kill_veto_of(proposal: &ProposalHash) {
|
||||
storage::kill(&proposal.to_keyed_vec(VETOED_PROPOSAL))
|
||||
}
|
||||
|
||||
pub fn will_still_be_councillor_at(who: &AccountId, n: BlockNumber) -> bool {
|
||||
council::active_council().iter()
|
||||
.find(|&&(ref a, _)| a == who)
|
||||
.map(|&(_, expires)| expires > n)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_councillor(who: &AccountId) -> bool {
|
||||
council::active_council().iter()
|
||||
.any(|&(ref a, _)| a == who)
|
||||
}
|
||||
|
||||
pub fn vote_of(who: &AccountId, proposal: &ProposalHash) -> Option<bool> {
|
||||
storage::get(&(*proposal, *who).to_keyed_vec(COUNCIL_VOTE_OF))
|
||||
}
|
||||
|
||||
pub fn proposal_voters(proposal: &ProposalHash) -> Vec<AccountId> {
|
||||
storage::get_or_default(&proposal.to_keyed_vec(PROPOSAL_VOTERS))
|
||||
}
|
||||
|
||||
pub fn tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) {
|
||||
generic_tally(proposal_hash, |w: &AccountId, p: &ProposalHash| storage::get(&(*p, *w).to_keyed_vec(COUNCIL_VOTE_OF)))
|
||||
}
|
||||
|
||||
fn take_tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) {
|
||||
generic_tally(proposal_hash, |w: &AccountId, p: &ProposalHash| storage::get(&(*p, *w).to_keyed_vec(COUNCIL_VOTE_OF)))
|
||||
}
|
||||
|
||||
fn generic_tally<F: Fn(&AccountId, &ProposalHash) -> Option<bool>>(proposal_hash: &ProposalHash, vote_of: F) -> (u32, u32, u32) {
|
||||
let c = council::active_council();
|
||||
let (approve, reject) = c.iter()
|
||||
.filter_map(|&(ref a, _)| vote_of(a, proposal_hash))
|
||||
.map(|approve| if approve { (1, 0) } else { (0, 1) })
|
||||
.fold((0, 0), |(a, b), (c, d)| (a + c, b + d));
|
||||
(approve, reject, c.len() as u32 - approve - reject)
|
||||
}
|
||||
|
||||
fn set_proposals(p: &Vec<(BlockNumber, ProposalHash)>) {
|
||||
storage::put(PROPOSALS, p)
|
||||
}
|
||||
|
||||
fn take_proposal_if_expiring_at(n: BlockNumber) -> Option<(Proposal, ProposalHash)> {
|
||||
let mut proposals = proposals();
|
||||
match proposals.first() {
|
||||
Some(&(expiry, hash)) if expiry == n => {
|
||||
// yes this is horrible, but fixing it will need substantial work in storage.
|
||||
set_proposals(&proposals[1..].to_vec());
|
||||
let proposal = storage::take(&hash.to_keyed_vec(PROPOSAL_OF)).expect("all queued proposal hashes must have associated proposals");
|
||||
Some((proposal, hash))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod public {
|
||||
use super::*;
|
||||
|
||||
pub fn propose(signed: &AccountId, proposal: &Proposal) {
|
||||
let expiry = system::block_number() + voting_period();
|
||||
assert!(will_still_be_councillor_at(signed, expiry));
|
||||
|
||||
let proposal_hash = proposal.blake2_256();
|
||||
|
||||
assert!(!is_vetoed(&proposal_hash));
|
||||
|
||||
let mut proposals = proposals();
|
||||
proposals.push((expiry, proposal_hash));
|
||||
proposals.sort_by_key(|&(expiry, _)| expiry);
|
||||
set_proposals(&proposals);
|
||||
|
||||
storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_OF), proposal);
|
||||
storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS), &vec![*signed]);
|
||||
storage::put(&(proposal_hash, *signed).to_keyed_vec(COUNCIL_VOTE_OF), &true);
|
||||
}
|
||||
|
||||
pub fn vote(signed: &AccountId, proposal: &ProposalHash, approve: bool) {
|
||||
if vote_of(signed, proposal).is_none() {
|
||||
let mut voters = proposal_voters(proposal);
|
||||
voters.push(*signed);
|
||||
storage::put(&proposal.to_keyed_vec(PROPOSAL_VOTERS), &voters);
|
||||
}
|
||||
storage::put(&(*proposal, *signed).to_keyed_vec(COUNCIL_VOTE_OF), &approve);
|
||||
}
|
||||
|
||||
pub fn veto(signed: &AccountId, proposal_hash: &ProposalHash) {
|
||||
assert!(is_councillor(signed), "only councillors may veto council proposals");
|
||||
assert!(storage::exists(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS)), "proposal must exist to be vetoed");
|
||||
|
||||
let mut existing_vetoers = veto_of(&proposal_hash)
|
||||
.map(|pair| pair.1)
|
||||
.unwrap_or_else(Vec::new);
|
||||
let insert_position = existing_vetoers.binary_search(signed)
|
||||
.expect_err("a councillor may not veto a proposal twice");
|
||||
existing_vetoers.insert(insert_position, *signed);
|
||||
set_veto_of(&proposal_hash, system::block_number() + cooloff_period(), existing_vetoers);
|
||||
|
||||
set_proposals(&proposals().into_iter().filter(|&(_, h)| h != *proposal_hash).collect::<Vec<_>>());
|
||||
storage::kill(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS));
|
||||
storage::kill(&proposal_hash.to_keyed_vec(PROPOSAL_OF));
|
||||
for (c, _) in council::active_council() {
|
||||
storage::kill(&(*proposal_hash, c).to_keyed_vec(COUNCIL_VOTE_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod privileged {
|
||||
use super::*;
|
||||
|
||||
pub fn set_cooloff_period(blocks: BlockNumber) {
|
||||
storage::put(COOLOFF_PERIOD, &blocks);
|
||||
}
|
||||
|
||||
pub fn set_voting_period(blocks: BlockNumber) {
|
||||
storage::put(VOTING_PERIOD, &blocks);
|
||||
}
|
||||
}
|
||||
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
use runtime::democracy::privileged::start_referendum;
|
||||
use demo_primitives::VoteThreshold;
|
||||
|
||||
pub fn end_block(now: BlockNumber) {
|
||||
while let Some((proposal, proposal_hash)) = take_proposal_if_expiring_at(now) {
|
||||
let tally = take_tally(&proposal_hash);
|
||||
if let &Proposal::DemocracyCancelReferendum(ref_index) = &proposal {
|
||||
if let (_, 0, 0) = tally {
|
||||
democracy::privileged::cancel_referendum(ref_index);
|
||||
}
|
||||
} else {
|
||||
if tally.0 > tally.1 + tally.2 {
|
||||
kill_veto_of(&proposal_hash);
|
||||
match tally {
|
||||
(_, 0, 0) => start_referendum(proposal, VoteThreshold::SuperMajorityAgainst),
|
||||
_ => start_referendum(proposal, VoteThreshold::SimpleMajority),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod testing {
|
||||
use super::*;
|
||||
use runtime_io::{twox_128, TestExternalities};
|
||||
use keyring::Keyring::{Alice, Bob, Charlie};
|
||||
use codec::Joiner;
|
||||
use runtime::{council, democracy};
|
||||
|
||||
pub fn externalities() -> TestExternalities {
|
||||
let expiry: BlockNumber = 10;
|
||||
let extras: TestExternalities = map![
|
||||
twox_128(council::ACTIVE_COUNCIL).to_vec() => vec![].and(&vec![
|
||||
(Alice.to_raw_public(), expiry),
|
||||
(Bob.into(), expiry),
|
||||
(Charlie.into(), expiry)
|
||||
]),
|
||||
twox_128(COOLOFF_PERIOD).to_vec() => vec![].and(&2u64),
|
||||
twox_128(VOTING_PERIOD).to_vec() => vec![].and(&1u64),
|
||||
twox_128(democracy::VOTING_PERIOD).to_vec() => vec![].and(&3u64)
|
||||
];
|
||||
council::testing::externalities()
|
||||
.into_iter().chain(extras.into_iter()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use runtime_io::{with_externalities, twox_128, TestExternalities};
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use keyring::Keyring::{Alice, Bob, Charlie, Dave};
|
||||
use environment::with_env;
|
||||
use demo_primitives::{AccountId, Proposal, VoteThreshold};
|
||||
use runtime::{staking, council, democracy};
|
||||
|
||||
fn new_test_ext() -> TestExternalities {
|
||||
testing::externalities()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_environment_works() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
assert_eq!(staking::bonding_duration(), 0);
|
||||
assert_eq!(cooloff_period(), 2);
|
||||
assert_eq!(voting_period(), 1);
|
||||
assert_eq!(will_still_be_councillor_at(&Alice, 1), true);
|
||||
assert_eq!(will_still_be_councillor_at(&Alice, 10), false);
|
||||
assert_eq!(will_still_be_councillor_at(&Dave, 10), false);
|
||||
assert_eq!(is_councillor(&Alice), true);
|
||||
assert_eq!(is_councillor(&Dave), false);
|
||||
assert_eq!(proposals(), Vec::<(BlockNumber, ProposalHash)>::new());
|
||||
assert_eq!(proposal_voters(&ProposalHash::default()), Vec::<AccountId>::new());
|
||||
assert_eq!(is_vetoed(&ProposalHash::default()), false);
|
||||
assert_eq!(vote_of(&Alice, &ProposalHash::default()), None);
|
||||
assert_eq!(tally(&ProposalHash::default()), (0, 0, 3));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn referendum_cancellation_should_work_when_unanimous() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||
democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove);
|
||||
assert_eq!(democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]);
|
||||
|
||||
let cancellation = Proposal::DemocracyCancelReferendum(0);
|
||||
let hash = cancellation.blake2_256();
|
||||
public::propose(&Alice, &cancellation);
|
||||
public::vote(&Bob, &hash, true);
|
||||
public::vote(&Charlie, &hash, true);
|
||||
assert_eq!(proposals(), vec![(2, hash)]);
|
||||
internal::end_block(1);
|
||||
|
||||
with_env(|e| e.block_number = 2);
|
||||
internal::end_block(2);
|
||||
assert_eq!(democracy::active_referendums(), vec![]);
|
||||
assert_eq!(staking::bonding_duration(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn referendum_cancellation_should_fail_when_not_unanimous() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||
democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove);
|
||||
|
||||
let cancellation = Proposal::DemocracyCancelReferendum(0);
|
||||
let hash = cancellation.blake2_256();
|
||||
public::propose(&Alice, &cancellation);
|
||||
public::vote(&Bob, &hash, true);
|
||||
public::vote(&Charlie, &hash, false);
|
||||
internal::end_block(1);
|
||||
|
||||
with_env(|e| e.block_number = 2);
|
||||
internal::end_block(2);
|
||||
assert_eq!(democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn referendum_cancellation_should_fail_when_abstentions() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||
democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove);
|
||||
|
||||
let cancellation = Proposal::DemocracyCancelReferendum(0);
|
||||
let hash = cancellation.blake2_256();
|
||||
public::propose(&Alice, &cancellation);
|
||||
public::vote(&Bob, &hash, true);
|
||||
internal::end_block(1);
|
||||
|
||||
with_env(|e| e.block_number = 2);
|
||||
internal::end_block(2);
|
||||
assert_eq!(democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn veto_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||
let hash = proposal.blake2_256();
|
||||
public::propose(&Alice, &proposal);
|
||||
public::veto(&Bob, &hash);
|
||||
assert_eq!(proposals().len(), 0);
|
||||
assert_eq!(democracy::active_referendums().len(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn double_veto_should_panic() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||
let hash = proposal.blake2_256();
|
||||
public::propose(&Alice, &proposal);
|
||||
public::veto(&Bob, &hash);
|
||||
|
||||
with_env(|e| e.block_number = 3);
|
||||
public::propose(&Alice, &proposal);
|
||||
public::veto(&Bob, &hash);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn retry_in_cooloff_should_panic() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||
let hash = proposal.blake2_256();
|
||||
public::propose(&Alice, &proposal);
|
||||
public::veto(&Bob, &hash);
|
||||
|
||||
with_env(|e| e.block_number = 2);
|
||||
public::propose(&Alice, &proposal);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retry_after_cooloff_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||
let hash = proposal.blake2_256();
|
||||
public::propose(&Alice, &proposal);
|
||||
public::veto(&Bob, &hash);
|
||||
|
||||
with_env(|e| e.block_number = 3);
|
||||
public::propose(&Alice, &proposal);
|
||||
public::vote(&Bob, &hash, false);
|
||||
public::vote(&Charlie, &hash, true);
|
||||
internal::end_block(3);
|
||||
|
||||
with_env(|e| e.block_number = 4);
|
||||
internal::end_block(4);
|
||||
assert_eq!(proposals().len(), 0);
|
||||
assert_eq!(democracy::active_referendums(), vec![(0, 7, Proposal::StakingSetBondingDuration(42), VoteThreshold::SimpleMajority)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alternative_double_veto_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||
let hash = proposal.blake2_256();
|
||||
public::propose(&Alice, &proposal);
|
||||
public::veto(&Bob, &hash);
|
||||
|
||||
with_env(|e| e.block_number = 3);
|
||||
public::propose(&Alice, &proposal);
|
||||
public::veto(&Charlie, &hash);
|
||||
assert_eq!(proposals().len(), 0);
|
||||
assert_eq!(democracy::active_referendums().len(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_propose_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||
let hash = proposal.blake2_256();
|
||||
public::propose(&Alice, &proposal);
|
||||
assert_eq!(proposals().len(), 1);
|
||||
assert_eq!(proposal_voters(&hash), vec![Alice.to_raw_public()]);
|
||||
assert_eq!(vote_of(&Alice, &hash), Some(true));
|
||||
assert_eq!(tally(&hash), (1, 0, 2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unvoted_proposal_should_expire_without_action() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Alice, &Proposal::StakingSetBondingDuration(42));
|
||||
assert_eq!(tally(&Proposal::StakingSetBondingDuration(42).blake2_256()), (1, 0, 2));
|
||||
internal::end_block(1);
|
||||
|
||||
with_env(|e| e.block_number = 2);
|
||||
internal::end_block(2);
|
||||
assert_eq!(proposals().len(), 0);
|
||||
assert_eq!(democracy::active_referendums().len(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unanimous_proposal_should_expire_with_biased_referendum() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Alice, &Proposal::StakingSetBondingDuration(42));
|
||||
public::vote(&Bob, &Proposal::StakingSetBondingDuration(42).blake2_256(), true);
|
||||
public::vote(&Charlie, &Proposal::StakingSetBondingDuration(42).blake2_256(), true);
|
||||
assert_eq!(tally(&Proposal::StakingSetBondingDuration(42).blake2_256()), (3, 0, 0));
|
||||
internal::end_block(1);
|
||||
|
||||
with_env(|e| e.block_number = 2);
|
||||
internal::end_block(2);
|
||||
assert_eq!(proposals().len(), 0);
|
||||
assert_eq!(democracy::active_referendums(), vec![(0, 5, Proposal::StakingSetBondingDuration(42), VoteThreshold::SuperMajorityAgainst)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn majority_proposal_should_expire_with_unbiased_referendum() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Alice, &Proposal::StakingSetBondingDuration(42));
|
||||
public::vote(&Bob, &Proposal::StakingSetBondingDuration(42).blake2_256(), true);
|
||||
public::vote(&Charlie, &Proposal::StakingSetBondingDuration(42).blake2_256(), false);
|
||||
assert_eq!(tally(&Proposal::StakingSetBondingDuration(42).blake2_256()), (2, 1, 0));
|
||||
internal::end_block(1);
|
||||
|
||||
with_env(|e| e.block_number = 2);
|
||||
internal::end_block(2);
|
||||
assert_eq!(proposals().len(), 0);
|
||||
assert_eq!(democracy::active_referendums(), vec![(0, 5, Proposal::StakingSetBondingDuration(42), VoteThreshold::SimpleMajority)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn propose_by_public_should_panic() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Dave, &Proposal::StakingSetBondingDuration(42));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,579 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Democratic system: Handles administration of general stakeholder voting.
|
||||
|
||||
use rstd::prelude::*;
|
||||
use integer_sqrt::IntegerSquareRoot;
|
||||
use codec::{KeyedVec, Slicable, Input, NonTrivialSlicable};
|
||||
use runtime_support::storage;
|
||||
use demo_primitives::{Proposal, AccountId, Hash, BlockNumber, VoteThreshold};
|
||||
use runtime::{staking, system, session};
|
||||
use runtime::staking::Balance;
|
||||
|
||||
pub type PropIndex = u32;
|
||||
pub type ReferendumIndex = u32;
|
||||
|
||||
trait Approved {
|
||||
/// Given `approve` votes for and `against` votes against from a total electorate size of
|
||||
/// `electorate` (`electorate - (approve + against)` are abstainers), then returns true if the
|
||||
/// overall outcome is in favour of approval.
|
||||
fn approved(&self, approve: Balance, against: Balance, electorate: Balance) -> bool;
|
||||
}
|
||||
|
||||
impl Approved for VoteThreshold {
|
||||
/// Given `approve` votes for and `against` votes against from a total electorate size of
|
||||
/// `electorate` (`electorate - (approve + against)` are abstainers), then returns true if the
|
||||
/// overall outcome is in favour of approval.
|
||||
fn approved(&self, approve: Balance, against: Balance, electorate: Balance) -> bool {
|
||||
let voters = approve + against;
|
||||
match *self {
|
||||
VoteThreshold::SuperMajorityApprove =>
|
||||
voters.integer_sqrt() * approve / electorate.integer_sqrt() > against,
|
||||
VoteThreshold::SuperMajorityAgainst =>
|
||||
approve > voters.integer_sqrt() * against / electorate.integer_sqrt(),
|
||||
VoteThreshold::SimpleMajority => approve > against,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public proposals
|
||||
pub const PUBLIC_PROP_COUNT: &[u8] = b"dem:ppc"; // PropIndex
|
||||
pub const PUBLIC_PROPS: &[u8] = b"dem:pub"; // Vec<(PropIndex, Proposal)>
|
||||
pub const DEPOSIT_OF: &[u8] = b"dem:dep:"; // PropIndex -> (Balance, Vec<AccountId>)
|
||||
pub const LAUNCH_PERIOD: &[u8] = b"dem:lau"; // BlockNumber
|
||||
pub const MINIMUM_DEPOSIT: &[u8] = b"dem:min"; // Balance
|
||||
|
||||
// referenda
|
||||
pub const VOTING_PERIOD: &[u8] = b"dem:per"; // BlockNumber
|
||||
pub const REFERENDUM_COUNT: &[u8] = b"dem:rco"; // ReferendumIndex
|
||||
pub const NEXT_TALLY: &[u8] = b"dem:nxt"; // ReferendumIndex
|
||||
pub const REFERENDUM_INFO_OF: &[u8] = b"dem:pro:"; // ReferendumIndex -> (BlockNumber, Proposal, VoteThreshold)
|
||||
pub const VOTERS_FOR: &[u8] = b"dem:vtr:"; // ReferendumIndex -> Vec<AccountId>
|
||||
pub const VOTE_OF: &[u8] = b"dem:vot:"; // (ReferendumIndex, AccountId) -> bool
|
||||
|
||||
/// The minimum amount to be used as a deposit for a public referendum proposal.
|
||||
pub fn minimum_deposit() -> Balance {
|
||||
storage::get(MINIMUM_DEPOSIT)
|
||||
.expect("all core parameters of council module must be in place")
|
||||
}
|
||||
|
||||
/// How often (in blocks) to check for new votes.
|
||||
pub fn voting_period() -> BlockNumber {
|
||||
storage::get(VOTING_PERIOD)
|
||||
.expect("all core parameters of council module must be in place")
|
||||
}
|
||||
|
||||
/// How often (in blocks) new public referenda are launched.
|
||||
pub fn launch_period() -> BlockNumber {
|
||||
storage::get(LAUNCH_PERIOD)
|
||||
.expect("all core parameters of council module must be in place")
|
||||
}
|
||||
|
||||
/// The public proposals. Unsorted.
|
||||
pub fn public_props() -> Vec<(PropIndex, Proposal, AccountId)> {
|
||||
storage::get_or_default(PUBLIC_PROPS)
|
||||
}
|
||||
|
||||
/// Those who have locked a deposit.
|
||||
pub fn deposit_lockers(proposal: PropIndex) -> Option<(Balance, Vec<AccountId>)> {
|
||||
storage::get(&proposal.to_keyed_vec(DEPOSIT_OF))
|
||||
}
|
||||
|
||||
/// Get the amount locked in support of `proposal`; false if proposal isn't a valid proposal
|
||||
/// index.
|
||||
pub fn locked_for(proposal: PropIndex) -> Option<Balance> {
|
||||
deposit_lockers(proposal).map(|(d, l)| d * (l.len() as Balance))
|
||||
}
|
||||
|
||||
/// Return true if `ref_index` is an on-going referendum.
|
||||
pub fn is_active_referendum(ref_index: ReferendumIndex) -> bool {
|
||||
storage::exists(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF))
|
||||
}
|
||||
|
||||
/// Get the voters for the current proposal.
|
||||
pub fn voters_for(ref_index: ReferendumIndex) -> Vec<AccountId> {
|
||||
storage::get_or_default(&ref_index.to_keyed_vec(VOTERS_FOR))
|
||||
}
|
||||
|
||||
/// Get the vote, if Some, of `who`.
|
||||
pub fn vote_of(who: &AccountId, ref_index: ReferendumIndex) -> Option<bool> {
|
||||
storage::get(&(*who, ref_index).to_keyed_vec(VOTE_OF))
|
||||
}
|
||||
|
||||
/// Get the info concerning the next referendum.
|
||||
pub fn referendum_info(ref_index: ReferendumIndex) -> Option<(BlockNumber, Proposal, VoteThreshold)> {
|
||||
storage::get(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF))
|
||||
}
|
||||
|
||||
/// Get all referendums currently active.
|
||||
pub fn active_referendums() -> Vec<(ReferendumIndex, BlockNumber, Proposal, VoteThreshold)> {
|
||||
let next: ReferendumIndex = storage::get_or_default(NEXT_TALLY);
|
||||
let last: ReferendumIndex = storage::get_or_default(REFERENDUM_COUNT);
|
||||
(next..last).into_iter()
|
||||
.filter_map(|i| referendum_info(i).map(|(n, p, t)| (i, n, p, t)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get all referendums ready for tally at block `n`.
|
||||
pub fn maturing_referendums_at(n: BlockNumber) -> Vec<(ReferendumIndex, BlockNumber, Proposal, VoteThreshold)> {
|
||||
let next: ReferendumIndex = storage::get_or_default(NEXT_TALLY);
|
||||
let last: ReferendumIndex = storage::get_or_default(REFERENDUM_COUNT);
|
||||
(next..last).into_iter()
|
||||
.filter_map(|i| referendum_info(i).map(|(n, p, t)| (i, n, p, t)))
|
||||
.take_while(|&(_, block_number, _, _)| block_number == n)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get the voters for the current proposal.
|
||||
pub fn tally(ref_index: ReferendumIndex) -> (staking::Balance, staking::Balance) {
|
||||
voters_for(ref_index).iter()
|
||||
.map(|a| (staking::balance(a), vote_of(a, ref_index).expect("all items come from `voters`; for an item to be in `voters` there must be a vote registered; qed")))
|
||||
.map(|(bal, vote)| if vote { (bal, 0) } else { (0, bal) })
|
||||
.fold((0, 0), |(a, b), (c, d)| (a + c, b + d))
|
||||
}
|
||||
|
||||
/// Get the next free referendum index, aka the number of referendums started so far.
|
||||
pub fn next_free_ref_index() -> ReferendumIndex {
|
||||
storage::get_or_default(REFERENDUM_COUNT)
|
||||
}
|
||||
|
||||
pub mod public {
|
||||
use super::*;
|
||||
|
||||
/// Propose a sensitive action to be taken.
|
||||
pub fn propose(signed: &AccountId, proposal: &Proposal, value: Balance) {
|
||||
assert!(value >= minimum_deposit());
|
||||
assert!(staking::internal::deduct_unbonded(signed, value));
|
||||
|
||||
let index: PropIndex = storage::get_or_default(PUBLIC_PROP_COUNT);
|
||||
storage::put(PUBLIC_PROP_COUNT, &(index + 1));
|
||||
storage::put(&index.to_keyed_vec(DEPOSIT_OF), &(value, vec![*signed]));
|
||||
|
||||
let mut props = public_props();
|
||||
props.push((index, proposal.clone(), *signed));
|
||||
storage::put(PUBLIC_PROPS, &props);
|
||||
}
|
||||
|
||||
/// Propose a sensitive action to be taken.
|
||||
pub fn second(signed: &AccountId, proposal: PropIndex) {
|
||||
let key = proposal.to_keyed_vec(DEPOSIT_OF);
|
||||
let mut deposit: (Balance, Vec<AccountId>) =
|
||||
storage::get(&key).expect("can only second an existing proposal");
|
||||
assert!(staking::internal::deduct_unbonded(signed, deposit.0));
|
||||
|
||||
deposit.1.push(*signed);
|
||||
storage::put(&key, &deposit);
|
||||
}
|
||||
|
||||
/// Vote in a referendum. If `approve_proposal` is true, the vote is to enact the proposal;
|
||||
/// false would be a vote to keep the status quo..
|
||||
pub fn vote(signed: &AccountId, ref_index: ReferendumIndex, approve_proposal: bool) {
|
||||
if !is_active_referendum(ref_index) {
|
||||
panic!("vote given for invalid referendum.")
|
||||
}
|
||||
if staking::balance(signed) == 0 {
|
||||
panic!("transactor must have balance to signal approval.");
|
||||
}
|
||||
let key = (*signed, ref_index).to_keyed_vec(VOTE_OF);
|
||||
if !storage::exists(&key) {
|
||||
let mut voters = voters_for(ref_index);
|
||||
voters.push(signed.clone());
|
||||
storage::put(&ref_index.to_keyed_vec(VOTERS_FOR), &voters);
|
||||
}
|
||||
storage::put(&key, &approve_proposal);
|
||||
}
|
||||
}
|
||||
|
||||
pub mod privileged {
|
||||
use super::*;
|
||||
|
||||
/// Can be called directly by the council.
|
||||
pub fn start_referendum(proposal: Proposal, vote_threshold: VoteThreshold) {
|
||||
inject_referendum(system::block_number() + voting_period(), proposal, vote_threshold);
|
||||
}
|
||||
|
||||
/// Remove a referendum.
|
||||
pub fn cancel_referendum(ref_index: ReferendumIndex) {
|
||||
clear_referendum(ref_index);
|
||||
}
|
||||
}
|
||||
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
use demo_primitives::Proposal;
|
||||
use dispatch;
|
||||
|
||||
/// Current era is ending; we should finish up any proposals.
|
||||
pub fn end_block(now: BlockNumber) {
|
||||
// pick out another public referendum if it's time.
|
||||
if now % launch_period() == 0 {
|
||||
let mut public_props = public_props();
|
||||
if let Some((winner_index, _)) = public_props.iter()
|
||||
.enumerate()
|
||||
.max_by_key(|x| locked_for((x.1).0).expect("All current public proposals have an amount locked"))
|
||||
{
|
||||
let (prop_index, proposal, _) = public_props.swap_remove(winner_index);
|
||||
let (deposit, depositors): (Balance, Vec<AccountId>) =
|
||||
storage::take(&prop_index.to_keyed_vec(DEPOSIT_OF))
|
||||
.expect("depositors always exist for current proposals");
|
||||
// refund depositors
|
||||
for d in &depositors {
|
||||
staking::internal::refund(d, deposit);
|
||||
}
|
||||
storage::put(PUBLIC_PROPS, &public_props);
|
||||
inject_referendum(now + voting_period(), proposal, VoteThreshold::SuperMajorityApprove);
|
||||
}
|
||||
}
|
||||
|
||||
// tally up votes for any expiring referenda.
|
||||
for (index, _, proposal, vote_threshold) in maturing_referendums_at(now) {
|
||||
let (approve, against) = tally(index);
|
||||
let total_stake = staking::total_stake();
|
||||
clear_referendum(index);
|
||||
if vote_threshold.approved(approve, against, total_stake) {
|
||||
dispatch::proposal(proposal);
|
||||
}
|
||||
storage::put(NEXT_TALLY, &(index + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Start a referendum
|
||||
fn inject_referendum(
|
||||
end: BlockNumber,
|
||||
proposal: Proposal,
|
||||
vote_threshold: VoteThreshold
|
||||
) -> ReferendumIndex {
|
||||
let ref_index = next_free_ref_index();
|
||||
if ref_index > 0 && referendum_info(ref_index - 1).map(|i| i.0 > end).unwrap_or(false) {
|
||||
panic!("Cannot inject a referendum that ends earlier than preceeding referendum");
|
||||
}
|
||||
|
||||
storage::put(REFERENDUM_COUNT, &(ref_index + 1));
|
||||
storage::put(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF), &(end, proposal, vote_threshold));
|
||||
ref_index
|
||||
}
|
||||
|
||||
/// Remove all info on a referendum.
|
||||
fn clear_referendum(ref_index: ReferendumIndex) {
|
||||
storage::kill(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF));
|
||||
storage::kill(&ref_index.to_keyed_vec(VOTERS_FOR));
|
||||
for v in voters_for(ref_index) {
|
||||
storage::kill(&(v, ref_index).to_keyed_vec(VOTE_OF));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod testing {
|
||||
use super::*;
|
||||
use runtime_io::{twox_128, TestExternalities};
|
||||
use codec::Joiner;
|
||||
use keyring::Keyring::*;
|
||||
use runtime::{session, staking};
|
||||
|
||||
pub fn externalities() -> TestExternalities {
|
||||
map![
|
||||
twox_128(session::SESSION_LENGTH).to_vec() => vec![].and(&1u64),
|
||||
twox_128(session::VALIDATOR_COUNT).to_vec() => vec![].and(&3u32),
|
||||
twox_128(&0u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => Alice.to_raw_public_vec(),
|
||||
twox_128(&1u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => Bob.to_raw_public_vec(),
|
||||
twox_128(&2u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => Charlie.to_raw_public_vec(),
|
||||
twox_128(staking::INTENTION_COUNT).to_vec() => vec![].and(&3u32),
|
||||
twox_128(&0u32.to_keyed_vec(staking::INTENTION_AT)).to_vec() => Alice.to_raw_public_vec(),
|
||||
twox_128(&1u32.to_keyed_vec(staking::INTENTION_AT)).to_vec() => Bob.to_raw_public_vec(),
|
||||
twox_128(&2u32.to_keyed_vec(staking::INTENTION_AT)).to_vec() => Charlie.to_raw_public_vec(),
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&10u64),
|
||||
twox_128(&Bob.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&20u64),
|
||||
twox_128(&Charlie.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&30u64),
|
||||
twox_128(&Dave.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&40u64),
|
||||
twox_128(&Eve.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&50u64),
|
||||
twox_128(&Ferdie.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&60u64),
|
||||
twox_128(&One.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&1u64),
|
||||
twox_128(staking::TOTAL_STAKE).to_vec() => vec![].and(&210u64),
|
||||
twox_128(staking::SESSIONS_PER_ERA).to_vec() => vec![].and(&1u64),
|
||||
twox_128(staking::VALIDATOR_COUNT).to_vec() => vec![].and(&3u64),
|
||||
twox_128(staking::CURRENT_ERA).to_vec() => vec![].and(&1u64),
|
||||
|
||||
twox_128(LAUNCH_PERIOD).to_vec() => vec![].and(&1u64),
|
||||
twox_128(VOTING_PERIOD).to_vec() => vec![].and(&1u64),
|
||||
twox_128(MINIMUM_DEPOSIT).to_vec() => vec![].and(&1u64)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use runtime_io::{with_externalities, twox_128, TestExternalities};
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use keyring::Keyring::*;
|
||||
use environment::with_env;
|
||||
use demo_primitives::{AccountId, Proposal};
|
||||
use runtime::{staking, session, democracy};
|
||||
|
||||
fn new_test_ext() -> TestExternalities {
|
||||
testing::externalities()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn params_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
assert_eq!(launch_period(), 1u64);
|
||||
assert_eq!(voting_period(), 1u64);
|
||||
assert_eq!(minimum_deposit(), 1u64);
|
||||
assert_eq!(next_free_ref_index(), 0u32);
|
||||
assert_eq!(staking::sessions_per_era(), 1u64);
|
||||
assert_eq!(staking::total_stake(), 210u64);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: test VoteThreshold
|
||||
|
||||
#[test]
|
||||
fn locked_for_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 2u64);
|
||||
public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(4), 4u64);
|
||||
public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(3), 3u64);
|
||||
assert_eq!(locked_for(0), Some(2));
|
||||
assert_eq!(locked_for(1), Some(4));
|
||||
assert_eq!(locked_for(2), Some(3));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_proposal_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 1u64);
|
||||
democracy::internal::end_block(system::block_number());
|
||||
|
||||
with_env(|e| e.block_number = 2);
|
||||
let r = 0;
|
||||
public::vote(&Alice, r, true);
|
||||
|
||||
assert_eq!(next_free_ref_index(), 1);
|
||||
assert_eq!(voters_for(r), vec![Alice.to_raw_public()]);
|
||||
assert_eq!(vote_of(&Alice, r), Some(true));
|
||||
assert_eq!(tally(r), (10, 0));
|
||||
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
|
||||
assert_eq!(staking::era_length(), 2u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deposit_for_proposals_should_be_taken() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 5u64);
|
||||
public::second(&Bob, 0);
|
||||
public::second(&Eve, 0);
|
||||
public::second(&Eve, 0);
|
||||
public::second(&Eve, 0);
|
||||
assert_eq!(staking::balance(&Alice), 5u64);
|
||||
assert_eq!(staking::balance(&Bob), 15u64);
|
||||
assert_eq!(staking::balance(&Eve), 35u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deposit_for_proposals_should_be_returned() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 5u64);
|
||||
public::second(&Bob, 0);
|
||||
public::second(&Eve, 0);
|
||||
public::second(&Eve, 0);
|
||||
public::second(&Eve, 0);
|
||||
democracy::internal::end_block(system::block_number());
|
||||
assert_eq!(staking::balance(&Alice), 10u64);
|
||||
assert_eq!(staking::balance(&Bob), 20u64);
|
||||
assert_eq!(staking::balance(&Eve), 50u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn proposal_with_deposit_below_minimum_should_panic() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 0u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn poor_proposer_should_panic() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 11u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn poor_seconder_should_panic() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::propose(&Bob, &Proposal::StakingSetSessionsPerEra(2), 11u64);
|
||||
public::second(&Alice, 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runners_up_should_come_after() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 0);
|
||||
public::propose(&Alice, &Proposal::StakingSetBondingDuration(2), 2u64);
|
||||
public::propose(&Alice, &Proposal::StakingSetBondingDuration(4), 4u64);
|
||||
public::propose(&Alice, &Proposal::StakingSetBondingDuration(3), 3u64);
|
||||
democracy::internal::end_block(system::block_number());
|
||||
|
||||
with_env(|e| e.block_number = 1);
|
||||
public::vote(&Alice, 0, true);
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::bonding_duration(), 4u64);
|
||||
|
||||
with_env(|e| e.block_number = 2);
|
||||
public::vote(&Alice, 1, true);
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::bonding_duration(), 3u64);
|
||||
|
||||
with_env(|e| e.block_number = 3);
|
||||
public::vote(&Alice, 2, true);
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::bonding_duration(), 2u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_passing_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove);
|
||||
public::vote(&Alice, r, true);
|
||||
|
||||
assert_eq!(voters_for(r), vec![Alice.to_raw_public()]);
|
||||
assert_eq!(vote_of(&Alice, r), Some(true));
|
||||
assert_eq!(tally(r), (10, 0));
|
||||
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
|
||||
assert_eq!(staking::era_length(), 2u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancel_referendum_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove);
|
||||
public::vote(&Alice, r, true);
|
||||
privileged::cancel_referendum(r);
|
||||
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
|
||||
assert_eq!(staking::era_length(), 1u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_failing_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove);
|
||||
public::vote(&Alice, r, false);
|
||||
|
||||
assert_eq!(voters_for(r), vec![Alice.to_raw_public()]);
|
||||
assert_eq!(vote_of(&Alice, r), Some(false));
|
||||
assert_eq!(tally(r), (0, 10));
|
||||
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
|
||||
assert_eq!(staking::era_length(), 1u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn controversial_voting_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove);
|
||||
public::vote(&Alice, r, true);
|
||||
public::vote(&Bob, r, false);
|
||||
public::vote(&Charlie, r, false);
|
||||
public::vote(&Dave, r, true);
|
||||
public::vote(&Eve, r, false);
|
||||
public::vote(&Ferdie, r, true);
|
||||
|
||||
assert_eq!(tally(r), (110, 100));
|
||||
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
|
||||
assert_eq!(staking::era_length(), 2u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn controversial_low_turnout_voting_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove);
|
||||
public::vote(&Eve, r, false);
|
||||
public::vote(&Ferdie, r, true);
|
||||
|
||||
assert_eq!(tally(r), (60, 50));
|
||||
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
|
||||
assert_eq!(staking::era_length(), 1u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn passing_low_turnout_voting_should_work() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
assert_eq!(staking::era_length(), 1u64);
|
||||
assert_eq!(staking::total_stake(), 210u64);
|
||||
|
||||
with_env(|e| e.block_number = 1);
|
||||
let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove);
|
||||
public::vote(&Dave, r, true);
|
||||
public::vote(&Eve, r, false);
|
||||
public::vote(&Ferdie, r, true);
|
||||
|
||||
assert_eq!(tally(r), (100, 50));
|
||||
|
||||
democracy::internal::end_block(system::block_number());
|
||||
staking::internal::check_new_era();
|
||||
|
||||
assert_eq!(staking::era_length(), 2u64);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! The Substrate Demo runtime.
|
||||
|
||||
#[allow(unused)]
|
||||
pub mod system;
|
||||
#[allow(unused)]
|
||||
pub mod consensus;
|
||||
#[allow(unused)]
|
||||
pub mod staking;
|
||||
#[allow(unused)]
|
||||
pub mod timestamp;
|
||||
#[allow(unused)]
|
||||
pub mod session;
|
||||
#[allow(unused)]
|
||||
pub mod democracy;
|
||||
#[allow(unused)]
|
||||
pub mod council;
|
||||
#[allow(unused)]
|
||||
pub mod council_vote;
|
||||
@@ -0,0 +1,276 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Session manager: is told the validators and allows them to manage their session keys for the
|
||||
//! consensus module.
|
||||
|
||||
use rstd::prelude::*;
|
||||
use codec::KeyedVec;
|
||||
use runtime_support::{storage, StorageVec};
|
||||
use demo_primitives::{AccountId, SessionKey, BlockNumber};
|
||||
use runtime::{system, staking, consensus};
|
||||
|
||||
pub const SESSION_LENGTH: &[u8] = b"ses:len";
|
||||
pub const CURRENT_INDEX: &[u8] = b"ses:ind";
|
||||
pub const LAST_LENGTH_CHANGE: &[u8] = b"ses:llc";
|
||||
pub const NEXT_KEY_FOR: &[u8] = b"ses:nxt:";
|
||||
pub const NEXT_SESSION_LENGTH: &[u8] = b"ses:nln";
|
||||
pub const VALIDATOR_AT: &[u8] = b"ses:val:";
|
||||
pub const VALIDATOR_COUNT: &[u8] = b"ses:val:len";
|
||||
|
||||
struct ValidatorStorageVec {}
|
||||
impl StorageVec for ValidatorStorageVec {
|
||||
type Item = AccountId;
|
||||
const PREFIX: &'static[u8] = VALIDATOR_AT;
|
||||
}
|
||||
|
||||
/// Get the current set of validators.
|
||||
pub fn validators() -> Vec<AccountId> {
|
||||
ValidatorStorageVec::items()
|
||||
}
|
||||
|
||||
/// The number of blocks in each session.
|
||||
pub fn length() -> BlockNumber {
|
||||
storage::get_or(SESSION_LENGTH, 0)
|
||||
}
|
||||
|
||||
/// The number of validators currently.
|
||||
pub fn validator_count() -> u32 {
|
||||
ValidatorStorageVec::count() as u32
|
||||
}
|
||||
|
||||
/// The current era index.
|
||||
pub fn current_index() -> BlockNumber {
|
||||
storage::get_or(CURRENT_INDEX, 0)
|
||||
}
|
||||
|
||||
/// The block number at which the era length last changed.
|
||||
pub fn last_length_change() -> BlockNumber {
|
||||
storage::get_or(LAST_LENGTH_CHANGE, 0)
|
||||
}
|
||||
|
||||
pub mod public {
|
||||
use super::*;
|
||||
|
||||
/// Sets the session key of `_validator` to `_key`. This doesn't take effect until the next
|
||||
/// session.
|
||||
pub fn set_key(validator: &AccountId, key: &SessionKey) {
|
||||
// set new value for next session
|
||||
storage::put(&validator.to_keyed_vec(NEXT_KEY_FOR), key);
|
||||
}
|
||||
}
|
||||
|
||||
pub mod privileged {
|
||||
use super::*;
|
||||
|
||||
/// Set a new era length. Won't kick in until the next era change (at current length).
|
||||
pub fn set_length(new: BlockNumber) {
|
||||
storage::put(NEXT_SESSION_LENGTH, &new);
|
||||
}
|
||||
|
||||
/// Forces a new session.
|
||||
pub fn force_new_session() {
|
||||
rotate_session();
|
||||
}
|
||||
}
|
||||
|
||||
// INTERNAL API (available to other runtime modules)
|
||||
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
|
||||
/// Set the current set of validators.
|
||||
///
|
||||
/// Called by staking::next_era() only. `next_session` should be called after this in order to
|
||||
/// update the session keys to the next validator set.
|
||||
pub fn set_validators(new: &[AccountId]) {
|
||||
ValidatorStorageVec::set_items(new);
|
||||
consensus::internal::set_authorities(new);
|
||||
}
|
||||
|
||||
/// Hook to be called after transaction processing.
|
||||
pub fn check_rotate_session() {
|
||||
// do this last, after the staking system has had chance to switch out the authorities for the
|
||||
// new set.
|
||||
// check block number and call next_session if necessary.
|
||||
if (system::block_number() - last_length_change()) % length() == 0 {
|
||||
rotate_session();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Move onto next session: register the new authority set.
|
||||
fn rotate_session() {
|
||||
// Increment current session index.
|
||||
storage::put(CURRENT_INDEX, &(current_index() + 1));
|
||||
|
||||
// Enact era length change.
|
||||
if let Some(next_len) = storage::get::<u64>(NEXT_SESSION_LENGTH) {
|
||||
storage::put(SESSION_LENGTH, &next_len);
|
||||
storage::put(LAST_LENGTH_CHANGE, &system::block_number());
|
||||
storage::kill(NEXT_SESSION_LENGTH);
|
||||
}
|
||||
|
||||
// Update any changes in session keys.
|
||||
validators().iter().enumerate().for_each(|(i, v)| {
|
||||
let k = v.to_keyed_vec(NEXT_KEY_FOR);
|
||||
if let Some(n) = storage::take(&k) {
|
||||
consensus::internal::set_authority(i as u32, &n);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", test))]
|
||||
pub mod testing {
|
||||
use super::*;
|
||||
use runtime_io::{twox_128, TestExternalities};
|
||||
use codec::{Joiner, KeyedVec};
|
||||
use keyring::Keyring;
|
||||
use runtime::system;
|
||||
|
||||
pub fn externalities(session_length: u64) -> TestExternalities {
|
||||
let one = Keyring::One.to_raw_public();
|
||||
let two = Keyring::Two.to_raw_public();
|
||||
let three = [3u8; 32];
|
||||
|
||||
let extras: TestExternalities = map![
|
||||
twox_128(SESSION_LENGTH).to_vec() => vec![].and(&session_length),
|
||||
twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&3u32),
|
||||
twox_128(&0u32.to_keyed_vec(VALIDATOR_AT)).to_vec() => one.to_vec(),
|
||||
twox_128(&1u32.to_keyed_vec(VALIDATOR_AT)).to_vec() => two.to_vec(),
|
||||
twox_128(&2u32.to_keyed_vec(VALIDATOR_AT)).to_vec() => three.to_vec()
|
||||
];
|
||||
system::testing::externalities().into_iter().chain(extras.into_iter()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::public::*;
|
||||
use super::privileged::*;
|
||||
use super::internal::*;
|
||||
use runtime_io::{with_externalities, twox_128, TestExternalities};
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use keyring::Keyring;
|
||||
use environment::with_env;
|
||||
use demo_primitives::AccountId;
|
||||
use runtime::{consensus, session};
|
||||
|
||||
fn simple_setup() -> TestExternalities {
|
||||
map![
|
||||
twox_128(SESSION_LENGTH).to_vec() => vec![].and(&2u64),
|
||||
// the validators (10, 20, ...)
|
||||
twox_128(b"ses:val:len").to_vec() => vec![].and(&2u32),
|
||||
twox_128(&0u32.to_keyed_vec(ValidatorStorageVec::PREFIX)).to_vec() => vec![10; 32],
|
||||
twox_128(&1u32.to_keyed_vec(ValidatorStorageVec::PREFIX)).to_vec() => vec![20; 32],
|
||||
// initial session keys (11, 21, ...)
|
||||
b":auth:len".to_vec() => vec![].and(&2u32),
|
||||
0u32.to_keyed_vec(b":auth:") => vec![11; 32],
|
||||
1u32.to_keyed_vec(b":auth:") => vec![21; 32]
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_setup_should_work() {
|
||||
let mut t = simple_setup();
|
||||
with_externalities(&mut t, || {
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
|
||||
assert_eq!(length(), 2u64);
|
||||
assert_eq!(validators(), vec![[10u8; 32], [20u8; 32]]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn session_length_change_should_work() {
|
||||
let mut t = simple_setup();
|
||||
with_externalities(&mut t, || {
|
||||
// Block 1: Change to length 3; no visible change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
set_length(3);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 2);
|
||||
assert_eq!(current_index(), 0);
|
||||
|
||||
// Block 2: Length now changed to 3. Index incremented.
|
||||
with_env(|e| e.block_number = 2);
|
||||
set_length(3);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 3);
|
||||
assert_eq!(current_index(), 1);
|
||||
|
||||
// Block 3: Length now changed to 3. Index incremented.
|
||||
with_env(|e| e.block_number = 3);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 3);
|
||||
assert_eq!(current_index(), 1);
|
||||
|
||||
// Block 4: Change to length 2; no visible change.
|
||||
with_env(|e| e.block_number = 4);
|
||||
set_length(2);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 3);
|
||||
assert_eq!(current_index(), 1);
|
||||
|
||||
// Block 5: Length now changed to 2. Index incremented.
|
||||
with_env(|e| e.block_number = 5);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 2);
|
||||
assert_eq!(current_index(), 2);
|
||||
|
||||
// Block 6: No change.
|
||||
with_env(|e| e.block_number = 6);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 2);
|
||||
assert_eq!(current_index(), 2);
|
||||
|
||||
// Block 7: Next index.
|
||||
with_env(|e| e.block_number = 7);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 2);
|
||||
assert_eq!(current_index(), 3);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn session_change_should_work() {
|
||||
let mut t = simple_setup();
|
||||
with_externalities(&mut t, || {
|
||||
// Block 1: No change
|
||||
with_env(|e| e.block_number = 1);
|
||||
check_rotate_session();
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
|
||||
|
||||
// Block 2: Session rollover, but no change.
|
||||
with_env(|e| e.block_number = 2);
|
||||
check_rotate_session();
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
|
||||
|
||||
// Block 3: Set new key for validator 2; no visible change.
|
||||
with_env(|e| e.block_number = 3);
|
||||
set_key(&[20; 32], &[22; 32]);
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
|
||||
|
||||
check_rotate_session();
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
|
||||
|
||||
// Block 4: Session rollover, authority 2 changes.
|
||||
with_env(|e| e.block_number = 4);
|
||||
check_rotate_session();
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [22u8; 32]]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,878 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Staking manager: Handles balances and periodically determines the best set of validators.
|
||||
|
||||
use rstd::prelude::*;
|
||||
use rstd::cmp;
|
||||
use rstd::cell::RefCell;
|
||||
use rstd::collections::btree_map::{BTreeMap, Entry};
|
||||
use runtime_io::{print, blake2_256};
|
||||
use codec::KeyedVec;
|
||||
use runtime_support::{storage, StorageVec};
|
||||
use demo_primitives::{BlockNumber, AccountId};
|
||||
use runtime::{system, session};
|
||||
|
||||
/// The balance of an account.
|
||||
pub type Balance = u64;
|
||||
|
||||
/// The amount of bonding period left in an account. Measured in eras.
|
||||
pub type Bondage = u64;
|
||||
|
||||
pub const BONDING_DURATION: &[u8] = b"sta:loc";
|
||||
pub const VALIDATOR_COUNT: &[u8] = b"sta:vac";
|
||||
pub const SESSIONS_PER_ERA: &[u8] = b"sta:spe";
|
||||
pub const NEXT_SESSIONS_PER_ERA: &[u8] = b"sta:nse";
|
||||
pub const CURRENT_ERA: &[u8] = b"sta:era";
|
||||
pub const LAST_ERA_LENGTH_CHANGE: &[u8] = b"sta:lec";
|
||||
pub const TOTAL_STAKE: &[u8] = b"sta:tot";
|
||||
pub const INTENTION_AT: &[u8] = b"sta:wil:";
|
||||
pub const INTENTION_COUNT: &[u8] = b"sta:wil:len";
|
||||
|
||||
pub const BALANCE_OF: &[u8] = b"sta:bal:";
|
||||
pub const RESERVED_BALANCE_OF: &[u8] = b"sta:lbo:";
|
||||
pub const BONDAGE_OF: &[u8] = b"sta:bon:";
|
||||
pub const CODE_OF: &[u8] = b"sta:cod:";
|
||||
pub const STORAGE_OF: &[u8] = b"sta:sto:";
|
||||
|
||||
pub struct IntentionStorageVec {}
|
||||
impl StorageVec for IntentionStorageVec {
|
||||
type Item = AccountId;
|
||||
const PREFIX: &'static[u8] = INTENTION_AT;
|
||||
}
|
||||
|
||||
/// The length of the bonding duration in eras.
|
||||
pub fn bonding_duration() -> BlockNumber {
|
||||
storage::get_or_default(BONDING_DURATION)
|
||||
}
|
||||
|
||||
/// The length of a staking era in sessions.
|
||||
pub fn validator_count() -> usize {
|
||||
storage::get_or_default::<u32>(VALIDATOR_COUNT) as usize
|
||||
}
|
||||
|
||||
/// The length of a staking era in blocks.
|
||||
pub fn era_length() -> BlockNumber {
|
||||
sessions_per_era() * session::length()
|
||||
}
|
||||
|
||||
/// The length of a staking era in sessions.
|
||||
pub fn sessions_per_era() -> BlockNumber {
|
||||
storage::get_or_default(SESSIONS_PER_ERA)
|
||||
}
|
||||
|
||||
/// The current era index.
|
||||
pub fn current_era() -> BlockNumber {
|
||||
storage::get_or_default(CURRENT_ERA)
|
||||
}
|
||||
|
||||
/// The block number at which the era length last changed.
|
||||
pub fn last_era_length_change() -> BlockNumber {
|
||||
storage::get_or_default(LAST_ERA_LENGTH_CHANGE)
|
||||
}
|
||||
|
||||
/// The balance of a given account.
|
||||
pub fn balance(who: &AccountId) -> Balance {
|
||||
free_balance(who) + reserved_balance(who)
|
||||
}
|
||||
|
||||
/// The balance of a given account.
|
||||
pub fn free_balance(who: &AccountId) -> Balance {
|
||||
storage::get_or_default(&who.to_keyed_vec(BALANCE_OF))
|
||||
}
|
||||
|
||||
/// The amount of the balance of a given account that is exterally reserved; this can still get
|
||||
/// slashed, but gets slashed last of all.
|
||||
pub fn reserved_balance(who: &AccountId) -> Balance {
|
||||
storage::get_or_default(&who.to_keyed_vec(RESERVED_BALANCE_OF))
|
||||
}
|
||||
|
||||
/// Some result as `slash(who, value)` (but without the side-effects) asuming there are no
|
||||
/// balance changes in the meantime.
|
||||
pub fn can_slash(who: &AccountId, value: Balance) -> bool {
|
||||
balance(who) >= value
|
||||
}
|
||||
|
||||
/// The block at which the `who`'s funds become entirely liquid.
|
||||
pub fn bondage(who: &AccountId) -> Bondage {
|
||||
storage::get_or_default(&who.to_keyed_vec(BONDAGE_OF))
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
pub enum LockStatus {
|
||||
Liquid,
|
||||
LockedUntil(BlockNumber),
|
||||
Staked,
|
||||
}
|
||||
|
||||
/// The block at which the `who`'s funds become entirely liquid.
|
||||
pub fn unlock_block(who: &AccountId) -> LockStatus {
|
||||
match bondage(who) {
|
||||
i if i == Bondage::max_value() => LockStatus::Staked,
|
||||
i if i <= system::block_number() => LockStatus::Liquid,
|
||||
i => LockStatus::LockedUntil(i),
|
||||
}
|
||||
}
|
||||
|
||||
/// The total amount of stake on the system.
|
||||
pub fn total_stake() -> Balance {
|
||||
storage::get_or(TOTAL_STAKE, 0)
|
||||
}
|
||||
|
||||
// Each identity's stake may be in one of three bondage states, given by an integer:
|
||||
// - n | n <= current_era(): inactive: free to be transferred.
|
||||
// - ~0: active: currently representing a validator.
|
||||
// - n | n > current_era(): deactivating: recently representing a validator and not yet
|
||||
// ready for transfer.
|
||||
|
||||
pub mod public {
|
||||
use super::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct ChangeEntry {
|
||||
balance: Option<Balance>,
|
||||
code: Option<Vec<u8>>,
|
||||
storage: BTreeMap<Vec<u8>, Option<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl ChangeEntry {
|
||||
pub fn balance_changed(b: Balance) -> Self {
|
||||
ChangeEntry { balance: Some(b), code: None, storage: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
type State = BTreeMap<AccountId, ChangeEntry>;
|
||||
|
||||
trait Externalities {
|
||||
fn get_storage(&self, account: &AccountId, location: &[u8]) -> Option<Vec<u8>>;
|
||||
fn get_code(&self, account: &AccountId) -> Vec<u8>;
|
||||
fn get_balance(&self, account: &AccountId) -> Balance;
|
||||
}
|
||||
|
||||
struct Ext<F1, F3, F5> where
|
||||
F1 : Fn(&AccountId, &[u8]) -> Option<Vec<u8>>,
|
||||
F3 : Fn(&AccountId) -> Vec<u8>,
|
||||
F5 : Fn(&AccountId) -> Balance
|
||||
{
|
||||
do_get_storage: F1,
|
||||
do_get_code: F3,
|
||||
do_get_balance: F5,
|
||||
}
|
||||
|
||||
struct DirectExt;
|
||||
impl Externalities for DirectExt {
|
||||
fn get_storage(&self, account: &AccountId, location: &[u8]) -> Option<Vec<u8>> {
|
||||
let mut v = account.to_keyed_vec(STORAGE_OF);
|
||||
v.extend(location);
|
||||
storage::get_raw(&v)
|
||||
}
|
||||
fn get_code(&self, account: &AccountId) -> Vec<u8> {
|
||||
storage::get_raw(&account.to_keyed_vec(CODE_OF)).unwrap_or_default()
|
||||
}
|
||||
fn get_balance(&self, account: &AccountId) -> Balance {
|
||||
storage::get_or_default::<Balance>(&account.to_keyed_vec(BALANCE_OF))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F1, F3, F5> Externalities for Ext<F1, F3, F5> where
|
||||
F1 : Fn(&AccountId, &[u8]) -> Option<Vec<u8>>,
|
||||
F3 : Fn(&AccountId) -> Vec<u8>,
|
||||
F5 : Fn(&AccountId) -> Balance
|
||||
{
|
||||
fn get_storage(&self, account: &AccountId, location: &[u8]) -> Option<Vec<u8>> {
|
||||
(self.do_get_storage)(account, location)
|
||||
}
|
||||
fn get_code(&self, account: &AccountId) -> Vec<u8> {
|
||||
(self.do_get_code)(account)
|
||||
}
|
||||
fn get_balance(&self, account: &AccountId) -> Balance {
|
||||
(self.do_get_balance)(account)
|
||||
}
|
||||
}
|
||||
|
||||
fn commit_state(s: State) {
|
||||
for (address, changed) in s.into_iter() {
|
||||
if let Some(balance) = changed.balance {
|
||||
storage::put(&address.to_keyed_vec(BALANCE_OF), &balance);
|
||||
}
|
||||
if let Some(code) = changed.code {
|
||||
storage::put(&address.to_keyed_vec(CODE_OF), &code);
|
||||
}
|
||||
let storage_key = address.to_keyed_vec(STORAGE_OF);
|
||||
for (k, v) in changed.storage.into_iter() {
|
||||
let mut key = storage_key.clone();
|
||||
key.extend(k);
|
||||
if let Some(value) = v {
|
||||
storage::put_raw(&key, &value);
|
||||
} else {
|
||||
storage::kill(&key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_state(commit_state: State, local: &mut State) {
|
||||
for (address, changed) in commit_state.into_iter() {
|
||||
match local.entry(address) {
|
||||
Entry::Occupied(e) => {
|
||||
let mut value = e.into_mut();
|
||||
if changed.balance.is_some() {
|
||||
value.balance = changed.balance;
|
||||
}
|
||||
if changed.code.is_some() {
|
||||
value.code = changed.code;
|
||||
}
|
||||
value.storage.extend(changed.storage.into_iter());
|
||||
}
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a smart-contract account.
|
||||
pub fn create(transactor: &AccountId, code: &[u8], value: Balance) {
|
||||
// commit anything that made it this far to storage
|
||||
if let Some(commit) = effect_create(transactor, code, value, DirectExt) {
|
||||
commit_state(commit);
|
||||
}
|
||||
}
|
||||
|
||||
fn effect_create<E: Externalities>(
|
||||
transactor: &AccountId,
|
||||
code: &[u8],
|
||||
value: Balance,
|
||||
ext: E
|
||||
) -> Option<State> {
|
||||
let from_balance = ext.get_balance(transactor);
|
||||
// TODO: a fee.
|
||||
assert!(from_balance >= value);
|
||||
|
||||
let mut dest_pre = blake2_256(code).to_vec();
|
||||
dest_pre.extend(&transactor[..]);
|
||||
let dest = blake2_256(&dest_pre);
|
||||
|
||||
// early-out if degenerate.
|
||||
if &dest == transactor {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut local = BTreeMap::new();
|
||||
|
||||
// two inserts are safe
|
||||
assert!(&dest != transactor);
|
||||
local.insert(dest, ChangeEntry { balance: Some(value), code: Some(code.to_vec()), storage: Default::default() });
|
||||
local.insert(transactor.clone(), ChangeEntry::balance_changed(from_balance - value));
|
||||
|
||||
Some(local)
|
||||
}
|
||||
|
||||
/// Transfer some unlocked staking balance to another staker.
|
||||
/// TODO: probably want to state gas-limit and gas-price.
|
||||
pub fn transfer(transactor: &AccountId, dest: &AccountId, value: Balance) {
|
||||
// commit anything that made it this far to storage
|
||||
if let Some(commit) = effect_transfer(transactor, dest, value, DirectExt) {
|
||||
commit_state(commit);
|
||||
}
|
||||
}
|
||||
|
||||
fn effect_transfer<E: Externalities>(
|
||||
transactor: &AccountId,
|
||||
dest: &AccountId,
|
||||
value: Balance,
|
||||
ext: E
|
||||
) -> Option<State> {
|
||||
let from_balance = ext.get_balance(transactor);
|
||||
assert!(from_balance >= value);
|
||||
|
||||
let to_balance = ext.get_balance(dest);
|
||||
assert!(bondage(transactor) <= bondage(dest));
|
||||
assert!(to_balance + value > to_balance); // no overflow
|
||||
|
||||
// TODO: a fee, based upon gaslimit/gasprice.
|
||||
// TODO: consider storing upper-bound for contract's gas limit in fixed-length runtime
|
||||
// code in contract itself and use that.
|
||||
|
||||
let local: RefCell<State> = RefCell::new(BTreeMap::new());
|
||||
|
||||
if transactor != dest {
|
||||
let mut local = local.borrow_mut();
|
||||
local.insert(transactor.clone(), ChangeEntry::balance_changed(from_balance - value));
|
||||
local.insert(dest.clone(), ChangeEntry::balance_changed(to_balance + value));
|
||||
}
|
||||
|
||||
let should_commit = {
|
||||
// Our local ext: Should be used for any transfers and creates that happen internally.
|
||||
let ext = || Ext {
|
||||
do_get_storage: |account: &AccountId, location: &[u8]|
|
||||
local.borrow().get(account)
|
||||
.and_then(|a| a.storage.get(location))
|
||||
.cloned()
|
||||
.unwrap_or_else(|| ext.get_storage(account, location)),
|
||||
do_get_code: |account: &AccountId|
|
||||
local.borrow().get(account)
|
||||
.and_then(|a| a.code.clone())
|
||||
.unwrap_or_else(|| ext.get_code(account)),
|
||||
do_get_balance: |account: &AccountId|
|
||||
local.borrow().get(account)
|
||||
.and_then(|a| a.balance)
|
||||
.unwrap_or_else(|| ext.get_balance(account)),
|
||||
};
|
||||
let mut transfer = |inner_dest: &AccountId, value: Balance| {
|
||||
if let Some(commit_state) = effect_transfer(dest, inner_dest, value, ext()) {
|
||||
merge_state(commit_state, &mut *local.borrow_mut());
|
||||
}
|
||||
};
|
||||
let mut create = |code: &[u8], value: Balance| {
|
||||
if let Some(commit_state) = effect_create(dest, code, value, ext()) {
|
||||
merge_state(commit_state, &mut *local.borrow_mut());
|
||||
}
|
||||
};
|
||||
let mut put_storage = |location: Vec<u8>, value: Option<Vec<u8>>| {
|
||||
local.borrow_mut()
|
||||
.entry(dest.clone())
|
||||
.or_insert(Default::default())
|
||||
.storage.insert(location, value);
|
||||
};
|
||||
|
||||
// TODO: logging (logs are just appended into a notable storage-based vector and cleared every
|
||||
// block).
|
||||
// TODO: execute code with ext(), put_storage, create and transfer as externalities.
|
||||
true
|
||||
};
|
||||
|
||||
if should_commit {
|
||||
Some(local.into_inner())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare the desire to stake for the transactor.
|
||||
///
|
||||
/// Effects will be felt at the beginning of the next era.
|
||||
pub fn stake(transactor: &AccountId) {
|
||||
let mut intentions = IntentionStorageVec::items();
|
||||
// can't be in the list twice.
|
||||
assert!(intentions.iter().find(|t| *t == transactor).is_none(), "Cannot stake if already staked.");
|
||||
intentions.push(transactor.clone());
|
||||
IntentionStorageVec::set_items(&intentions);
|
||||
storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &u64::max_value());
|
||||
}
|
||||
|
||||
/// Retract the desire to stake for the transactor.
|
||||
///
|
||||
/// Effects will be felt at the beginning of the next era.
|
||||
pub fn unstake(transactor: &AccountId) {
|
||||
let mut intentions = IntentionStorageVec::items();
|
||||
if let Some(position) = intentions.iter().position(|t| t == transactor) {
|
||||
intentions.swap_remove(position);
|
||||
} else {
|
||||
panic!("Cannot unstake if not already staked.");
|
||||
}
|
||||
IntentionStorageVec::set_items(&intentions);
|
||||
storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &(current_era() + bonding_duration()));
|
||||
}
|
||||
}
|
||||
|
||||
pub mod privileged {
|
||||
use super::*;
|
||||
|
||||
/// Set the number of sessions in an era.
|
||||
pub fn set_sessions_per_era(new: BlockNumber) {
|
||||
storage::put(NEXT_SESSIONS_PER_ERA, &new);
|
||||
}
|
||||
|
||||
/// The length of the bonding duration in eras.
|
||||
pub fn set_bonding_duration(new: BlockNumber) {
|
||||
storage::put(BONDING_DURATION, &new);
|
||||
}
|
||||
|
||||
/// The length of a staking era in sessions.
|
||||
pub fn set_validator_count(new: u32) {
|
||||
storage::put(VALIDATOR_COUNT, &new);
|
||||
}
|
||||
|
||||
/// Force there to be a new era. This also forces a new session immediately after.
|
||||
pub fn force_new_era() {
|
||||
new_era();
|
||||
session::privileged::force_new_session();
|
||||
}
|
||||
}
|
||||
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
|
||||
/// Set the balance of an account.
|
||||
/// Needless to say, this is super low-level and accordingly dangerous. Ensure any modules that
|
||||
/// use it are auditted to the hilt.
|
||||
pub fn set_free_balance(who: &AccountId, value: Balance) {
|
||||
storage::put(&who.to_keyed_vec(BALANCE_OF), &value);
|
||||
}
|
||||
|
||||
/// Hook to be called after to transaction processing.
|
||||
pub fn check_new_era() {
|
||||
// check block number and call new_era if necessary.
|
||||
if (system::block_number() - last_era_length_change()) % era_length() == 0 {
|
||||
new_era();
|
||||
}
|
||||
}
|
||||
|
||||
/// Deduct from an unbonded balance. true if it happened.
|
||||
pub fn deduct_unbonded(who: &AccountId, value: Balance) -> bool {
|
||||
if let LockStatus::Liquid = unlock_block(who) {
|
||||
let b = free_balance(who);
|
||||
if b >= value {
|
||||
set_free_balance(who, b - value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Refund some balance.
|
||||
pub fn refund(who: &AccountId, value: Balance) {
|
||||
set_free_balance(who, free_balance(who) + value)
|
||||
}
|
||||
|
||||
/// Will slash any balance, but prefer free over reserved.
|
||||
pub fn slash(who: &AccountId, value: Balance) -> bool {
|
||||
let free_balance = free_balance(who);
|
||||
let free_slash = cmp::min(free_balance, value);
|
||||
set_free_balance(who, free_balance - free_slash);
|
||||
if free_slash < value {
|
||||
slash_reserved(who, value - free_slash)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Moves `value` from balance to reserved balance.
|
||||
pub fn reserve_balance(who: &AccountId, value: Balance) {
|
||||
let b = free_balance(who);
|
||||
assert!(b >= value);
|
||||
set_free_balance(who, b - value);
|
||||
set_reserved_balance(who, reserved_balance(who) + value);
|
||||
}
|
||||
|
||||
/// Moves `value` from reserved balance to balance.
|
||||
pub fn unreserve_balance(who: &AccountId, value: Balance) {
|
||||
let b = reserved_balance(who);
|
||||
let value = cmp::min(b, value);
|
||||
set_reserved_balance(who, b - value);
|
||||
set_free_balance(who, free_balance(who) + value);
|
||||
}
|
||||
|
||||
/// Moves `value` from reserved balance to balance.
|
||||
pub fn slash_reserved(who: &AccountId, value: Balance) -> bool {
|
||||
let b = reserved_balance(who);
|
||||
let slash = cmp::min(b, value);
|
||||
set_reserved_balance(who, b - slash);
|
||||
value == slash
|
||||
}
|
||||
|
||||
/// Moves `value` from reserved balance to balance.
|
||||
pub fn transfer_reserved_balance(slashed: &AccountId, beneficiary: &AccountId, value: Balance) -> bool {
|
||||
let b = reserved_balance(slashed);
|
||||
let slash = cmp::min(b, value);
|
||||
set_reserved_balance(slashed, b - slash);
|
||||
set_free_balance(beneficiary, free_balance(beneficiary) + slash);
|
||||
slash == value
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the reserved portion of `who`'s balance.
|
||||
fn set_reserved_balance(who: &AccountId, value: Balance) {
|
||||
storage::put(&who.to_keyed_vec(RESERVED_BALANCE_OF), &value);
|
||||
}
|
||||
|
||||
/// The era has changed - enact new staking set.
|
||||
///
|
||||
/// NOTE: This always happens immediately before a session change to ensure that new validators
|
||||
/// get a chance to set their session keys.
|
||||
fn new_era() {
|
||||
// Increment current era.
|
||||
storage::put(CURRENT_ERA, &(current_era() + 1));
|
||||
|
||||
// Enact era length change.
|
||||
let next_spe: u64 = storage::get_or_default(NEXT_SESSIONS_PER_ERA);
|
||||
if next_spe > 0 && next_spe != sessions_per_era() {
|
||||
storage::put(SESSIONS_PER_ERA, &next_spe);
|
||||
storage::put(LAST_ERA_LENGTH_CHANGE, &system::block_number());
|
||||
}
|
||||
|
||||
// evaluate desired staking amounts and nominations and optimise to find the best
|
||||
// combination of validators, then use session::internal::set_validators().
|
||||
// for now, this just orders would-be stakers by their balances and chooses the top-most
|
||||
// validator_count() of them.
|
||||
let mut intentions = IntentionStorageVec::items()
|
||||
.into_iter()
|
||||
.map(|v| (balance(&v), v))
|
||||
.collect::<Vec<_>>();
|
||||
intentions.sort_unstable_by(|&(b1, _), &(b2, _)| b2.cmp(&b1));
|
||||
session::internal::set_validators(
|
||||
&intentions.into_iter()
|
||||
.map(|(_, v)| v)
|
||||
.take(validator_count())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", test))]
|
||||
pub mod testing {
|
||||
use super::*;
|
||||
use runtime_io::{twox_128, TestExternalities};
|
||||
use codec::{Joiner, KeyedVec};
|
||||
use keyring::Keyring::*;
|
||||
use runtime::session;
|
||||
|
||||
pub fn externalities(session_length: u64, sessions_per_era: u64, current_era: u64) -> TestExternalities {
|
||||
let extras: TestExternalities = map![
|
||||
twox_128(INTENTION_COUNT).to_vec() => vec![].and(&3u32),
|
||||
twox_128(&0u32.to_keyed_vec(INTENTION_AT)).to_vec() => Alice.to_raw_public_vec(),
|
||||
twox_128(&1u32.to_keyed_vec(INTENTION_AT)).to_vec() => Bob.to_raw_public_vec(),
|
||||
twox_128(&2u32.to_keyed_vec(INTENTION_AT)).to_vec() => Charlie.to_raw_public_vec(),
|
||||
twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&sessions_per_era),
|
||||
twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&3u64),
|
||||
twox_128(CURRENT_ERA).to_vec() => vec![].and(¤t_era),
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
|
||||
];
|
||||
session::testing::externalities(session_length).into_iter().chain(extras.into_iter()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::internal::*;
|
||||
use super::public::*;
|
||||
use super::privileged::*;
|
||||
|
||||
use runtime_io::{with_externalities, twox_128, TestExternalities};
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use keyring::Keyring::*;
|
||||
use environment::with_env;
|
||||
use demo_primitives::AccountId;
|
||||
use runtime::{staking, session};
|
||||
|
||||
#[test]
|
||||
fn staking_should_work() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(session::SESSION_LENGTH).to_vec() => vec![].and(&1u64),
|
||||
twox_128(session::VALIDATOR_COUNT).to_vec() => vec![].and(&2u32),
|
||||
twox_128(&0u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => vec![10; 32],
|
||||
twox_128(&1u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => vec![20; 32],
|
||||
twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&2u64),
|
||||
twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&2u32),
|
||||
twox_128(BONDING_DURATION).to_vec() => vec![].and(&3u64),
|
||||
twox_128(TOTAL_STAKE).to_vec() => vec![].and(&100u64),
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&10u64),
|
||||
twox_128(&Bob.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&20u64),
|
||||
twox_128(&Charlie.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&30u64),
|
||||
twox_128(&Dave.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&40u64)
|
||||
];
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
assert_eq!(era_length(), 2u64);
|
||||
assert_eq!(validator_count(), 2usize);
|
||||
assert_eq!(bonding_duration(), 3u64);
|
||||
assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]);
|
||||
|
||||
// Block 1: Add three validators. No obvious change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
stake(&Alice);
|
||||
stake(&Bob);
|
||||
stake(&Dave);
|
||||
check_new_era();
|
||||
assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]);
|
||||
|
||||
// Block 2: New validator set now.
|
||||
with_env(|e| e.block_number = 2);
|
||||
check_new_era();
|
||||
assert_eq!(session::validators(), vec![Dave.to_raw_public(), Bob.into()]);
|
||||
|
||||
// Block 3: Unstake highest, introduce another staker. No change yet.
|
||||
with_env(|e| e.block_number = 3);
|
||||
stake(&Charlie);
|
||||
unstake(&Dave);
|
||||
check_new_era();
|
||||
|
||||
// Block 4: New era - validators change.
|
||||
with_env(|e| e.block_number = 4);
|
||||
check_new_era();
|
||||
assert_eq!(session::validators(), vec![Charlie.to_raw_public(), Bob.into()]);
|
||||
|
||||
// Block 5: Transfer stake from highest to lowest. No change yet.
|
||||
with_env(|e| e.block_number = 5);
|
||||
transfer(&Dave, &Alice, 40);
|
||||
check_new_era();
|
||||
|
||||
// Block 6: Lowest now validator.
|
||||
with_env(|e| e.block_number = 6);
|
||||
check_new_era();
|
||||
assert_eq!(session::validators(), vec![Alice.to_raw_public(), Charlie.into()]);
|
||||
|
||||
// Block 7: Unstake three. No change yet.
|
||||
with_env(|e| e.block_number = 7);
|
||||
unstake(&Charlie);
|
||||
check_new_era();
|
||||
assert_eq!(session::validators(), vec![Alice.to_raw_public(), Charlie.into()]);
|
||||
|
||||
// Block 8: Back to one and two.
|
||||
with_env(|e| e.block_number = 8);
|
||||
check_new_era();
|
||||
assert_eq!(session::validators(), vec![Alice.to_raw_public(), Bob.into()]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn staking_eras_work() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(session::SESSION_LENGTH).to_vec() => vec![].and(&1u64),
|
||||
twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&2u64)
|
||||
];
|
||||
with_externalities(&mut t, || {
|
||||
assert_eq!(era_length(), 2u64);
|
||||
assert_eq!(sessions_per_era(), 2u64);
|
||||
assert_eq!(last_era_length_change(), 0u64);
|
||||
assert_eq!(current_era(), 0u64);
|
||||
|
||||
// Block 1: No change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
check_new_era();
|
||||
assert_eq!(sessions_per_era(), 2u64);
|
||||
assert_eq!(last_era_length_change(), 0u64);
|
||||
assert_eq!(current_era(), 0u64);
|
||||
|
||||
// Block 2: Simple era change.
|
||||
with_env(|e| e.block_number = 2);
|
||||
check_new_era();
|
||||
assert_eq!(sessions_per_era(), 2u64);
|
||||
assert_eq!(last_era_length_change(), 0u64);
|
||||
assert_eq!(current_era(), 1u64);
|
||||
|
||||
// Block 3: Schedule an era length change; no visible changes.
|
||||
with_env(|e| e.block_number = 3);
|
||||
set_sessions_per_era(3);
|
||||
check_new_era();
|
||||
assert_eq!(sessions_per_era(), 2u64);
|
||||
assert_eq!(last_era_length_change(), 0u64);
|
||||
assert_eq!(current_era(), 1u64);
|
||||
|
||||
// Block 4: Era change kicks in.
|
||||
with_env(|e| e.block_number = 4);
|
||||
check_new_era();
|
||||
assert_eq!(sessions_per_era(), 3u64);
|
||||
assert_eq!(last_era_length_change(), 4u64);
|
||||
assert_eq!(current_era(), 2u64);
|
||||
|
||||
// Block 5: No change.
|
||||
with_env(|e| e.block_number = 5);
|
||||
check_new_era();
|
||||
assert_eq!(sessions_per_era(), 3u64);
|
||||
assert_eq!(last_era_length_change(), 4u64);
|
||||
assert_eq!(current_era(), 2u64);
|
||||
|
||||
// Block 6: No change.
|
||||
with_env(|e| e.block_number = 6);
|
||||
check_new_era();
|
||||
assert_eq!(sessions_per_era(), 3u64);
|
||||
assert_eq!(last_era_length_change(), 4u64);
|
||||
assert_eq!(current_era(), 2u64);
|
||||
|
||||
// Block 7: Era increment.
|
||||
with_env(|e| e.block_number = 7);
|
||||
check_new_era();
|
||||
assert_eq!(sessions_per_era(), 3u64);
|
||||
assert_eq!(last_era_length_change(), 4u64);
|
||||
assert_eq!(current_era(), 3u64);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn staking_balance_works() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 42);
|
||||
assert_eq!(free_balance(&Alice), 42);
|
||||
assert_eq!(reserved_balance(&Alice), 0);
|
||||
assert_eq!(balance(&Alice), 42);
|
||||
assert_eq!(free_balance(&Bob), 0);
|
||||
assert_eq!(reserved_balance(&Bob), 0);
|
||||
assert_eq!(balance(&Bob), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn staking_balance_transfer_works() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
transfer(&Alice, &Bob, 69);
|
||||
assert_eq!(balance(&Alice), 42);
|
||||
assert_eq!(balance(&Bob), 69);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn staking_balance_transfer_when_bonded_panics() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
stake(&Alice);
|
||||
transfer(&Alice, &Bob, 69);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reserving_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
|
||||
assert_eq!(balance(&Alice), 111);
|
||||
assert_eq!(free_balance(&Alice), 111);
|
||||
assert_eq!(reserved_balance(&Alice), 0);
|
||||
|
||||
reserve_balance(&Alice, 69);
|
||||
|
||||
assert_eq!(balance(&Alice), 111);
|
||||
assert_eq!(free_balance(&Alice), 42);
|
||||
assert_eq!(reserved_balance(&Alice), 69);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn staking_balance_transfer_when_reserved_panics() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
reserve_balance(&Alice, 69);
|
||||
transfer(&Alice, &Bob, 69);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deducting_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
assert!(deduct_unbonded(&Alice, 69));
|
||||
assert_eq!(free_balance(&Alice), 42);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deducting_balance_should_fail_when_bonded() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&111u64),
|
||||
twox_128(&Alice.to_raw_public().to_keyed_vec(BONDAGE_OF)).to_vec() => vec![].and(&2u64)
|
||||
];
|
||||
with_externalities(&mut t, || {
|
||||
with_env(|e| e.block_number = 1);
|
||||
assert_eq!(unlock_block(&Alice), LockStatus::LockedUntil(2));
|
||||
assert!(!deduct_unbonded(&Alice, 69));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refunding_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 42);
|
||||
refund(&Alice, 69);
|
||||
assert_eq!(free_balance(&Alice), 111);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slashing_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
reserve_balance(&Alice, 69);
|
||||
assert!(slash(&Alice, 69));
|
||||
assert_eq!(free_balance(&Alice), 0);
|
||||
assert_eq!(reserved_balance(&Alice), 42);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slashing_incomplete_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 42);
|
||||
reserve_balance(&Alice, 21);
|
||||
assert!(!slash(&Alice, 69));
|
||||
assert_eq!(free_balance(&Alice), 0);
|
||||
assert_eq!(reserved_balance(&Alice), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unreserving_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
reserve_balance(&Alice, 111);
|
||||
unreserve_balance(&Alice, 42);
|
||||
assert_eq!(reserved_balance(&Alice), 69);
|
||||
assert_eq!(free_balance(&Alice), 42);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slashing_reserved_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
reserve_balance(&Alice, 111);
|
||||
assert!(slash_reserved(&Alice, 42));
|
||||
assert_eq!(reserved_balance(&Alice), 69);
|
||||
assert_eq!(free_balance(&Alice), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slashing_incomplete_reserved_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
reserve_balance(&Alice, 42);
|
||||
assert!(!slash_reserved(&Alice, 69));
|
||||
assert_eq!(free_balance(&Alice), 69);
|
||||
assert_eq!(reserved_balance(&Alice), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transferring_reserved_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
reserve_balance(&Alice, 111);
|
||||
assert!(transfer_reserved_balance(&Alice, &Bob, 42));
|
||||
assert_eq!(reserved_balance(&Alice), 69);
|
||||
assert_eq!(free_balance(&Alice), 0);
|
||||
assert_eq!(reserved_balance(&Bob), 0);
|
||||
assert_eq!(free_balance(&Bob), 42);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transferring_incomplete_reserved_balance_should_work() {
|
||||
with_externalities(&mut TestExternalities::default(), || {
|
||||
set_free_balance(&Alice, 111);
|
||||
reserve_balance(&Alice, 42);
|
||||
assert!(!transfer_reserved_balance(&Alice, &Bob, 69));
|
||||
assert_eq!(reserved_balance(&Alice), 0);
|
||||
assert_eq!(free_balance(&Alice), 69);
|
||||
assert_eq!(reserved_balance(&Bob), 0);
|
||||
assert_eq!(free_balance(&Bob), 42);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! System manager: Handles all of the top-level stuff; executing block/transaction, setting code
|
||||
//! and depositing logs.
|
||||
|
||||
use rstd::prelude::*;
|
||||
use rstd::mem;
|
||||
use runtime_io::{print, storage_root, enumerated_trie_root};
|
||||
use codec::{KeyedVec, Slicable};
|
||||
use runtime_support::{Hashable, storage};
|
||||
use environment::with_env;
|
||||
use demo_primitives::{AccountId, Hash, TxOrder, BlockNumber, Block, Header,
|
||||
UncheckedTransaction, Function, Log};
|
||||
use runtime::{staking, session};
|
||||
use dispatch;
|
||||
|
||||
pub const NONCE_OF: &[u8] = b"sys:non:";
|
||||
pub const BLOCK_HASH_AT: &[u8] = b"sys:old:";
|
||||
pub const CODE: &[u8] = b"sys:cod";
|
||||
|
||||
/// The current block number being processed. Set by `execute_block`.
|
||||
pub fn block_number() -> BlockNumber {
|
||||
with_env(|e| e.block_number)
|
||||
}
|
||||
|
||||
/// Get the block hash of a given block (uses storage).
|
||||
pub fn block_hash(number: BlockNumber) -> Hash {
|
||||
storage::get_or_default(&number.to_keyed_vec(BLOCK_HASH_AT))
|
||||
}
|
||||
|
||||
pub mod privileged {
|
||||
use super::*;
|
||||
|
||||
/// Set the new code.
|
||||
pub fn set_code(new: &[u8]) {
|
||||
storage::unhashed::put_raw(b":code", new);
|
||||
}
|
||||
}
|
||||
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
|
||||
struct CheckedTransaction(UncheckedTransaction);
|
||||
|
||||
/// Deposits a log and ensures it matches the blocks log data.
|
||||
pub fn deposit_log(log: Log) {
|
||||
with_env(|e| e.digest.logs.push(log));
|
||||
}
|
||||
|
||||
/// Actually execute all transitioning for `block`.
|
||||
pub fn execute_block(mut block: Block) {
|
||||
// populate environment from header.
|
||||
with_env(|e| {
|
||||
e.block_number = block.header.number;
|
||||
e.parent_hash = block.header.parent_hash;
|
||||
});
|
||||
|
||||
// any initial checks
|
||||
initial_checks(&block);
|
||||
|
||||
// execute transactions
|
||||
block.transactions.iter().cloned().for_each(super::execute_transaction);
|
||||
|
||||
// post-transactional book-keeping.
|
||||
staking::internal::check_new_era();
|
||||
session::internal::check_rotate_session();
|
||||
|
||||
// any final checks
|
||||
final_checks(&block);
|
||||
|
||||
// any stuff that we do after taking the storage root.
|
||||
post_finalise(&block.header);
|
||||
}
|
||||
|
||||
/// Execute a transaction outside of the block execution function.
|
||||
/// This doesn't attempt to validate anything regarding the block.
|
||||
pub fn execute_transaction(utx: UncheckedTransaction, mut header: Header) -> Header {
|
||||
// populate environment from header.
|
||||
with_env(|e| {
|
||||
e.block_number = header.number;
|
||||
e.parent_hash = header.parent_hash;
|
||||
mem::swap(&mut header.digest, &mut e.digest);
|
||||
});
|
||||
|
||||
super::execute_transaction(utx);
|
||||
|
||||
with_env(|e| {
|
||||
mem::swap(&mut header.digest, &mut e.digest);
|
||||
});
|
||||
header
|
||||
}
|
||||
|
||||
/// Finalise the block - it is up the caller to ensure that all header fields are valid
|
||||
/// except state-root.
|
||||
pub fn finalise_block(mut header: Header) -> Header {
|
||||
// populate environment from header.
|
||||
with_env(|e| {
|
||||
e.block_number = header.number;
|
||||
e.parent_hash = header.parent_hash;
|
||||
mem::swap(&mut header.digest, &mut e.digest);
|
||||
});
|
||||
|
||||
staking::internal::check_new_era();
|
||||
session::internal::check_rotate_session();
|
||||
|
||||
header.state_root = storage_root().into();
|
||||
with_env(|e| {
|
||||
mem::swap(&mut header.digest, &mut e.digest);
|
||||
});
|
||||
|
||||
post_finalise(&header);
|
||||
|
||||
header
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_transaction(utx: UncheckedTransaction) {
|
||||
use ::transaction;
|
||||
|
||||
// Verify the signature is good.
|
||||
let tx = match transaction::check(utx) {
|
||||
Ok(tx) => tx,
|
||||
Err(_) => panic!("All transactions should be properly signed"),
|
||||
};
|
||||
|
||||
// check nonce
|
||||
let nonce_key = tx.signed.to_keyed_vec(NONCE_OF);
|
||||
let expected_nonce: TxOrder = storage::get_or(&nonce_key, 0);
|
||||
assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce");
|
||||
|
||||
// increment nonce in storage
|
||||
storage::put(&nonce_key, &(expected_nonce + 1));
|
||||
|
||||
// decode parameters and dispatch
|
||||
dispatch::function(&tx.function, &tx.signed);
|
||||
}
|
||||
|
||||
fn initial_checks(block: &Block) {
|
||||
let ref header = block.header;
|
||||
|
||||
// check parent_hash is correct.
|
||||
assert!(
|
||||
header.number > 0 && block_hash(header.number - 1) == header.parent_hash,
|
||||
"Parent hash should be valid."
|
||||
);
|
||||
|
||||
// check transaction trie root represents the transactions.
|
||||
let txs = block.transactions.iter().map(Slicable::encode).collect::<Vec<_>>();
|
||||
let txs = txs.iter().map(Vec::as_slice).collect::<Vec<_>>();
|
||||
let txs_root = enumerated_trie_root(&txs).into();
|
||||
info_expect_equal_hash(&header.transaction_root, &txs_root);
|
||||
assert!(header.transaction_root == txs_root, "Transaction trie root must be valid.");
|
||||
}
|
||||
|
||||
fn final_checks(block: &Block) {
|
||||
let ref header = block.header;
|
||||
|
||||
// check digest
|
||||
with_env(|e| {
|
||||
assert!(header.digest == e.digest);
|
||||
});
|
||||
|
||||
// check storage root.
|
||||
let storage_root = storage_root().into();
|
||||
info_expect_equal_hash(&header.state_root, &storage_root);
|
||||
assert!(header.state_root == storage_root, "Storage root must match that calculated.");
|
||||
}
|
||||
|
||||
fn post_finalise(header: &Header) {
|
||||
// store the header hash in storage; we can't do it before otherwise there would be a
|
||||
// cyclic dependency.
|
||||
storage::put(&header.number.to_keyed_vec(BLOCK_HASH_AT), &header.blake2_256());
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn info_expect_equal_hash(given: &Hash, expected: &Hash) {
|
||||
use primitives::hexdisplay::HexDisplay;
|
||||
if given != expected {
|
||||
println!("Hash: given={}, expected={}", HexDisplay::from(&given.0), HexDisplay::from(&expected.0));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn info_expect_equal_hash(given: &Hash, expected: &Hash) {
|
||||
if given != expected {
|
||||
print("Hash not equal");
|
||||
print(&given.0[..]);
|
||||
print(&expected.0[..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", test))]
|
||||
pub mod testing {
|
||||
use super::*;
|
||||
use runtime_io::{twox_128, TestExternalities};
|
||||
use codec::Joiner;
|
||||
|
||||
pub fn externalities() -> TestExternalities {
|
||||
map![
|
||||
twox_128(&0u64.to_keyed_vec(BLOCK_HASH_AT)).to_vec() => [69u8; 32].encode()
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::internal::*;
|
||||
|
||||
use runtime_io::{with_externalities, twox_128, TestExternalities};
|
||||
use codec::{Joiner, KeyedVec, Slicable};
|
||||
use keyring::Keyring::*;
|
||||
use environment::with_env;
|
||||
use primitives::hexdisplay::HexDisplay;
|
||||
use demo_primitives::{Header, Digest, UncheckedTransaction, Transaction, Function};
|
||||
use runtime::staking;
|
||||
|
||||
#[test]
|
||||
fn staking_balance_transfer_dispatch_works() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(&One.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
|
||||
];
|
||||
|
||||
let tx = UncheckedTransaction {
|
||||
transaction: Transaction {
|
||||
signed: One.into(),
|
||||
nonce: 0,
|
||||
function: Function::StakingTransfer(Two.into(), 69),
|
||||
},
|
||||
signature: hex!("5f9832c5a4a39e2dd4a3a0c5b400e9836beb362cb8f7d845a8291a2ae6fe366612e080e4acd0b5a75c3d0b6ee69614a68fb63698c1e76bf1f2dcd8fa617ddf05").into(),
|
||||
};
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
internal::execute_transaction(tx, Header::from_block_number(1));
|
||||
assert_eq!(staking::balance(&One), 42);
|
||||
assert_eq!(staking::balance(&Two), 69);
|
||||
});
|
||||
}
|
||||
|
||||
fn new_test_ext() -> TestExternalities {
|
||||
staking::testing::externalities(2, 2, 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_import_works() {
|
||||
let mut t = new_test_ext();
|
||||
|
||||
let h = Header {
|
||||
parent_hash: [69u8; 32].into(),
|
||||
number: 1,
|
||||
state_root: hex!("f4f6408fe3ce1d78d30bb7ed625b32f91e45b8b566023df309cfd93c6f4af9a4").into(),
|
||||
transaction_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
|
||||
digest: Digest { logs: vec![], },
|
||||
};
|
||||
|
||||
let b = Block {
|
||||
header: h,
|
||||
transactions: vec![],
|
||||
};
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
execute_block(b);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn block_import_of_bad_state_root_fails() {
|
||||
let mut t = new_test_ext();
|
||||
|
||||
let h = Header {
|
||||
parent_hash: [69u8; 32].into(),
|
||||
number: 1,
|
||||
state_root: [0u8; 32].into(),
|
||||
transaction_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
|
||||
digest: Digest { logs: vec![], },
|
||||
};
|
||||
|
||||
let b = Block {
|
||||
header: h,
|
||||
transactions: vec![],
|
||||
};
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
execute_block(b);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn block_import_of_bad_transaction_root_fails() {
|
||||
let mut t = new_test_ext();
|
||||
|
||||
let h = Header {
|
||||
parent_hash: [69u8; 32].into(),
|
||||
number: 1,
|
||||
state_root: hex!("1ab2dbb7d4868a670b181327b0b6a58dc64b10cfb9876f737a5aa014b8da31e0").into(),
|
||||
transaction_root: [0u8; 32].into(),
|
||||
digest: Digest { logs: vec![], },
|
||||
};
|
||||
|
||||
let b = Block {
|
||||
header: h,
|
||||
transactions: vec![],
|
||||
};
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
execute_block(b);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Timestamp manager: just handles the current timestamp.
|
||||
|
||||
use runtime_support::storage;
|
||||
|
||||
pub type Timestamp = u64;
|
||||
|
||||
pub const CURRENT_TIMESTAMP: &[u8] = b"tim:val";
|
||||
|
||||
/// Get the current time.
|
||||
pub fn get() -> Timestamp {
|
||||
storage::get_or_default(CURRENT_TIMESTAMP)
|
||||
}
|
||||
|
||||
pub mod public {
|
||||
use super::*;
|
||||
|
||||
/// Set the current time.
|
||||
pub fn set(now: Timestamp) {
|
||||
storage::put(CURRENT_TIMESTAMP, &now);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::public::*;
|
||||
|
||||
use runtime_io::{with_externalities, twox_128, TestExternalities};
|
||||
use runtime::timestamp;
|
||||
use codec::{Joiner, KeyedVec};
|
||||
|
||||
#[test]
|
||||
fn timestamp_works() {
|
||||
let mut t: TestExternalities = map![
|
||||
twox_128(CURRENT_TIMESTAMP).to_vec() => vec![].and(&42u64)
|
||||
];
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
assert_eq!(get(), 42);
|
||||
set(69);
|
||||
assert_eq!(get(), 69);
|
||||
});
|
||||
}
|
||||
}
|
||||
Generated
+900
@@ -0,0 +1,900 @@
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"odds 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bigint"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "blake2-rfc"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "coco"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "demo-primitives"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-codec 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-runtime-std 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "demo-runtime"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"demo-primitives 0.1.0",
|
||||
"integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)",
|
||||
"substrate-codec 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-runtime-io 0.1.0",
|
||||
"substrate-runtime-std 0.1.0",
|
||||
"substrate-runtime-support 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-primitives 0.1.0",
|
||||
"untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "elastic-array"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "environmental"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "ethcore-bigint"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ethcore-bytes"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ethcore-logger"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixed-hash"
|
||||
version = "0.1.3"
|
||||
source = "git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm#8dc457899afdaf968ff7f16140b03d1e37b01d71"
|
||||
dependencies = [
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hashdb"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapsize"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hex-literal-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal-impl"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "integer-sqrt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/paritytech/integer-sqrt-rs.git#f4cf61482096dc98c1273f46a10849d182b4c23c"
|
||||
|
||||
[[package]]
|
||||
name = "isatty"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keccak-hash"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tiny-keccak 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memorydb"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashdb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keccak-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "odds"
|
||||
version = "0.2.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "patricia-trie"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-logger 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashdb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keccak-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memorydb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plain_hasher"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack-impl"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pwasm-alloc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"pwasm-libc 0.1.0",
|
||||
"rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pwasm-libc"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_termios"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rlp"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hex"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hex"
|
||||
version = "2.0.0"
|
||||
source = "git+https://github.com/rphmeier/rustc-hex.git#ee2ec40b9062ac7769ccb9dc891d6dc2cc9009d7"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "substrate-codec"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"substrate-runtime-std 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-primitives"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fixed-hash 0.1.3 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)",
|
||||
"rustc-hex 2.0.0 (git+https://github.com/rphmeier/rustc-hex.git)",
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-codec 0.1.0",
|
||||
"substrate-runtime-std 0.1.0",
|
||||
"twox-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uint 0.1.2 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-runtime-io"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ed25519 0.1.0",
|
||||
"environmental 0.1.0",
|
||||
"rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-codec 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-runtime-std 0.1.0",
|
||||
"substrate-state-machine 0.1.0",
|
||||
"triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-runtime-std"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"pwasm-alloc 0.1.0",
|
||||
"pwasm-libc 0.1.0",
|
||||
"rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-runtime-support"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ed25519 0.1.0",
|
||||
"environmental 0.1.0",
|
||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-codec 0.1.0",
|
||||
"substrate-primitives 0.1.0",
|
||||
"substrate-runtime-io 0.1.0",
|
||||
"substrate-runtime-std 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-state-machine"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashdb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memorydb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"patricia-trie 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-primitives 0.1.0",
|
||||
"triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.11.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synom"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "triehash"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keccak-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "twox-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uint"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm#8dc457899afdaf968ff7f16140b03d1e37b01d71"
|
||||
dependencies = [
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
|
||||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||
"checksum arrayvec 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "06f59fe10306bb78facd90d28c2038ad23ffaaefa85bac43c8a434cde383334f"
|
||||
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
|
||||
"checksum bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5442186ef6560f30f1ee4b9c1e4c87a35a6879d3644550cc248ec2b955eb5fcd"
|
||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||
"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
|
||||
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||
"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
|
||||
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
|
||||
"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
|
||||
"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
|
||||
"checksum elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "258ff6a9a94f648d0379dbd79110e057edbb53eb85cc237e33eadf8e5a30df85"
|
||||
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
|
||||
"checksum ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb5af77e74a8f70e9c3337e069c37bc82178ef1b459c02091f73c4ad5281eb5"
|
||||
"checksum ethcore-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3977c772cd6c5c22e1c7cfa208e4c3b746bd6c3a6c8eeec0999a6b2103015ad5"
|
||||
"checksum ethcore-logger 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fd5813e49546030be7d134e775088d56b8ff4ab60617b90e93d4f0513da4c5b"
|
||||
"checksum fixed-hash 0.1.3 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)" = "<none>"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
||||
"checksum hashdb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d97be07c358c5b461268b4ce60304024c5fa5acfd4bd8cd743639f0252003cf5"
|
||||
"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461"
|
||||
"checksum hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd546ef520ab3745f1aae5f2cdc6de9e6498e94d1ab138b9eb3ddfbf335847fb"
|
||||
"checksum hex-literal-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2ea76da4c7f1a54d01d54985566d3fdd960b2bbd7b970da024821c883c2d9631"
|
||||
"checksum integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)" = "<none>"
|
||||
"checksum isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f2a233726c7bb76995cec749d59582e5664823b7245d4970354408f1d79a7a2"
|
||||
"checksum keccak-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f300c1f149cd9ca5214eed24f6e713a597517420fb8b15499824aa916259ec1"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||
"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121"
|
||||
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2"
|
||||
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
|
||||
"checksum memorydb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "013b7e4c5e10c764936ebc6bd3662d8e3c92292d267bf6a42ef3f5cad9c793ee"
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||
"checksum odds 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "4eae0151b9dacf24fcc170d9995e511669a082856a91f958a2fe380bfab3fb22"
|
||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||
"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
|
||||
"checksum parking_lot_core 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "9f35048d735bb93dd115a0030498785971aab3234d311fbe273d020084d26bd8"
|
||||
"checksum patricia-trie 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1e2f638d79aba5c4a71a4f373df6e3cd702250a53b7f0ed4da1e2a7be9737ae"
|
||||
"checksum plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83ae80873992f511142c07d0ec6c44de5636628fdb7e204abd655932ea79d995"
|
||||
"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0"
|
||||
"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
||||
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
||||
"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8"
|
||||
"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53"
|
||||
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
|
||||
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
|
||||
"checksum ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6f7d28b30a72c01b458428e0ae988d4149c20d902346902be881e3edc4bb325c"
|
||||
"checksum rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "babe6fce20c0ca9b1582998734c4569082d0ad08e43772a1c6c40aef4f106ef9"
|
||||
"checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e"
|
||||
"checksum rustc-hex 2.0.0 (git+https://github.com/rphmeier/rustc-hex.git)" = "<none>"
|
||||
"checksum rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9743a7670d88d5d52950408ecdb7c71d8986251ab604d4689dd2ca25c9bca69"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
|
||||
"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0"
|
||||
"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5"
|
||||
"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
|
||||
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
|
||||
"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
|
||||
"checksum tiny-keccak 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e9241752647ca572f12c9b520a5d360d9099360c527770647e694001646a1d0"
|
||||
"checksum triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9291c7f0fae44858b5e087dd462afb382354120003778f1695b44aab98c7abd7"
|
||||
"checksum twox-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "475352206e7a290c5fccc27624a163e8d0d115f7bb60ca18a64fc9ce056d7435"
|
||||
"checksum uint 0.1.2 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)" = "<none>"
|
||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
@@ -0,0 +1,33 @@
|
||||
[package]
|
||||
name = "demo-runtime"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
substrate-codec = { path = "../../../substrate/codec", default-features = false }
|
||||
substrate-runtime-std = { path = "../../../substrate/runtime-std", default-features = false }
|
||||
substrate-runtime-io = { path = "../../../substrate/runtime-io", default-features = false }
|
||||
substrate-runtime-support = { path = "../../../substrate/runtime-support", default-features = false }
|
||||
substrate-primitives = { path = "../../../substrate/primitives", default-features = false }
|
||||
demo-primitives = { path = "../../primitives", default-features = false }
|
||||
integer-sqrt = { git = "https://github.com/paritytech/integer-sqrt-rs.git", branch = "master" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
std = [
|
||||
"substrate-codec/std",
|
||||
"substrate-runtime-io/std",
|
||||
"substrate-runtime-std/std",
|
||||
"substrate-runtime-support/std",
|
||||
"substrate-primitives/std",
|
||||
"demo-primitives/std",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
[workspace]
|
||||
members = []
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
cargo +nightly build --target=wasm32-unknown-unknown --release
|
||||
for i in demo_runtime
|
||||
do
|
||||
wasm-gc target/wasm32-unknown-unknown/release/$i.wasm target/wasm32-unknown-unknown/release/$i.compact.wasm
|
||||
done
|
||||
Binary file not shown.
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
rustup update nightly
|
||||
rustup target add wasm32-unknown-unknown --toolchain nightly
|
||||
rustup update stable
|
||||
cargo install --git https://github.com/alexcrichton/wasm-gc
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../src
|
||||
BIN
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate Demo.
|
||||
|
||||
// Substrate Demo 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.
|
||||
|
||||
// Substrate Demo 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 Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate Demo CLI
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate demo_cli as cli;
|
||||
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
quick_main!(run);
|
||||
|
||||
fn run() -> cli::error::Result<()> {
|
||||
cli::run(::std::env::args())
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Strongly typed API for Polkadot based around the locally-compiled native
|
||||
//! runtime.
|
||||
|
||||
extern crate polkadot_executor as polkadot_executor;
|
||||
extern crate polkadot_executor;
|
||||
extern crate polkadot_runtime;
|
||||
extern crate polkadot_primitives as primitives;
|
||||
extern crate substrate_client as client;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: polkadot
|
||||
author: "Parity Team <admin@polkadot.io>"
|
||||
author: "Parity Team <admin@parity.io>"
|
||||
about: Polkadot Node Rust Implementation
|
||||
args:
|
||||
- log:
|
||||
|
||||
@@ -40,6 +40,7 @@ const SESSIONS_PER_ERA: &[u8] = b"sta:spe";
|
||||
const NEXT_SESSIONS_PER_ERA: &[u8] = b"sta:nse";
|
||||
const CURRENT_ERA: &[u8] = b"sta:era";
|
||||
const LAST_ERA_LENGTH_CHANGE: &[u8] = b"sta:lec";
|
||||
const TOTAL_STAKE: &[u8] = b"sta:tot";
|
||||
const BALANCE_OF: &[u8] = b"sta:bal:";
|
||||
const BONDAGE_OF: &[u8] = b"sta:bon:";
|
||||
|
||||
@@ -295,6 +296,7 @@ mod tests {
|
||||
twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&2u64),
|
||||
twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&2u32),
|
||||
twox_128(BONDING_DURATION).to_vec() => vec![].and(&3u64),
|
||||
twox_128(TOTAL_STAKE).to_vec() => vec![].and(&100u64),
|
||||
twox_128(&one.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&10u64),
|
||||
twox_128(&two.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&20u64),
|
||||
twox_128(&three.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&30u64),
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -25,33 +25,12 @@ pub trait KeyedVec {
|
||||
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8>;
|
||||
}
|
||||
|
||||
macro_rules! impl_non_endians {
|
||||
( $( $t:ty ),* ) => { $(
|
||||
impl KeyedVec for $t {
|
||||
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8> {
|
||||
let mut r = prepend_key.to_vec();
|
||||
r.extend(&self[..]);
|
||||
r
|
||||
}
|
||||
}
|
||||
)* }
|
||||
impl<T: Slicable> KeyedVec for T {
|
||||
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8> {
|
||||
self.using_encoded(|slice| {
|
||||
let mut r = prepend_key.to_vec();
|
||||
r.extend(slice);
|
||||
r
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_endians {
|
||||
( $( $t:ty ),* ) => { $(
|
||||
impl KeyedVec for $t {
|
||||
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8> {
|
||||
self.using_encoded(|slice| {
|
||||
let mut r = prepend_key.to_vec();
|
||||
r.extend(slice);
|
||||
r
|
||||
})
|
||||
}
|
||||
}
|
||||
)* }
|
||||
}
|
||||
|
||||
impl_endians!(u8, i8, u16, u32, u64, usize, i16, i32, i64, isize);
|
||||
impl_non_endians!([u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8],
|
||||
[u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40],
|
||||
[u8; 48], [u8; 56], [u8; 64], [u8; 80], [u8; 96], [u8; 112], [u8; 128]);
|
||||
|
||||
@@ -89,6 +89,26 @@ impl<T: EndianSensitive> Slicable for T {
|
||||
}
|
||||
}
|
||||
|
||||
impl Slicable for Option<bool> {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
u8::decode(input).and_then(|v| match v {
|
||||
0 => Some(Some(false)),
|
||||
1 => Some(Some(true)),
|
||||
2 => Some(None),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||
match *self {
|
||||
Some(false) => 0u8,
|
||||
Some(true) => 1u8,
|
||||
None => 2u8,
|
||||
}.using_encoded(f)
|
||||
}
|
||||
}
|
||||
impl NonTrivialSlicable for Option<bool> {}
|
||||
|
||||
impl Slicable for Vec<u8> {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
u32::decode(input).and_then(move |len| {
|
||||
@@ -112,6 +132,43 @@ impl Slicable for Vec<u8> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: implement for all primitives.
|
||||
impl Slicable for Vec<u64> {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
u32::decode(input).and_then(move |len| {
|
||||
let len = len as usize;
|
||||
let mut vec = Vec::with_capacity(len);
|
||||
for _ in 0..len {
|
||||
vec.push(u64::decode(input)?);
|
||||
}
|
||||
Some(vec)
|
||||
})
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let len = self.len();
|
||||
assert!(len <= u32::max_value() as usize, "Attempted to serialize vec with too many elements.");
|
||||
|
||||
// TODO: optimise - no need to create a new vec and copy - can just reserve and encode in place
|
||||
let mut r: Vec<u8> = Vec::new().and(&(len as u32));
|
||||
for i in self.iter() {
|
||||
r.extend(&i.encode());
|
||||
}
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: use a BitVec-like representation.
|
||||
impl Slicable for Vec<bool> {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
<Vec<u8>>::decode(input).map(|a| a.into_iter().map(|b| b != 0).collect())
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
<Vec<u8>>::encode(&self.iter().map(|&b| if b {1} else {0}).collect())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_vec_simple_array {
|
||||
($($size:expr),*) => {
|
||||
$(
|
||||
|
||||
@@ -37,8 +37,8 @@ pub struct LocalizedSignature {
|
||||
}
|
||||
|
||||
/// Verify a message without type checking the parameters' types for the right size.
|
||||
pub fn verify(sig: &[u8], message: &[u8], public: &[u8]) -> bool {
|
||||
let public_key = untrusted::Input::from(public);
|
||||
pub fn verify<P: AsRef<[u8]>>(sig: &[u8], message: &[u8], public: P) -> bool {
|
||||
let public_key = untrusted::Input::from(public.as_ref());
|
||||
let msg = untrusted::Input::from(message);
|
||||
let sig = untrusted::Input::from(sig);
|
||||
|
||||
@@ -104,6 +104,18 @@ impl Into<[u8; 32]> for Public {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Public> for Public {
|
||||
fn as_ref(&self) -> &Public {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Pair> for Pair {
|
||||
fn as_ref(&self) -> &Pair {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
impl Pair {
|
||||
/// Generate new secure (random) key pair.
|
||||
pub fn new() -> Pair {
|
||||
@@ -144,8 +156,8 @@ impl Pair {
|
||||
}
|
||||
|
||||
/// Verify a signature on a message.
|
||||
pub fn verify_strong(sig: &Signature, message: &[u8], pubkey: &Public) -> bool {
|
||||
let public_key = untrusted::Input::from(&pubkey.0[..]);
|
||||
pub fn verify_strong<P: AsRef<Public>>(sig: &Signature, message: &[u8], pubkey: P) -> bool {
|
||||
let public_key = untrusted::Input::from(&pubkey.as_ref().0[..]);
|
||||
let msg = untrusted::Input::from(message);
|
||||
let sig = untrusted::Input::from(&sig.0[..]);
|
||||
|
||||
@@ -157,19 +169,19 @@ pub fn verify_strong(sig: &Signature, message: &[u8], pubkey: &Public) -> bool {
|
||||
|
||||
pub trait Verifiable {
|
||||
/// Verify something that acts like a signature.
|
||||
fn verify(&self, message: &[u8], pubkey: &Public) -> bool;
|
||||
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool;
|
||||
}
|
||||
|
||||
impl Verifiable for Signature {
|
||||
/// Verify something that acts like a signature.
|
||||
fn verify(&self, message: &[u8], pubkey: &Public) -> bool {
|
||||
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool {
|
||||
verify_strong(&self, message, pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
impl Verifiable for LocalizedSignature {
|
||||
fn verify(&self, message: &[u8], pubkey: &Public) -> bool {
|
||||
pubkey == &self.signer && self.signature.verify(message, pubkey)
|
||||
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool {
|
||||
pubkey.as_ref() == &self.signer && self.signature.verify(message, pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -6,3 +6,4 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
[dependencies]
|
||||
ed25519 = { path = "../ed25519" }
|
||||
hex-literal = { version = "0.1.0" }
|
||||
lazy_static = { version = "1.0" }
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
//! Support code for the runtime.
|
||||
|
||||
#[macro_use] extern crate hex_literal;
|
||||
#[macro_use] extern crate lazy_static;
|
||||
pub extern crate ed25519;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use ed25519::{Pair, Public, Signature};
|
||||
|
||||
/// Set of test accounts.
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Keyring {
|
||||
Alice,
|
||||
Bob,
|
||||
@@ -65,6 +68,19 @@ impl Keyring {
|
||||
pub fn sign(self, msg: &[u8]) -> Signature {
|
||||
Pair::from(self).sign(msg)
|
||||
}
|
||||
|
||||
pub fn pair(self) -> Pair {
|
||||
match self {
|
||||
Keyring::Alice => Pair::from_seed(b"Alice "),
|
||||
Keyring::Bob => Pair::from_seed(b"Bob "),
|
||||
Keyring::Charlie => Pair::from_seed(b"Charlie "),
|
||||
Keyring::Dave => Pair::from_seed(b"Dave "),
|
||||
Keyring::Eve => Pair::from_seed(b"Eve "),
|
||||
Keyring::Ferdie => Pair::from_seed(b"Ferdie "),
|
||||
Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"),
|
||||
Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Keyring> for &'static str {
|
||||
@@ -82,32 +98,65 @@ impl From<Keyring> for &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Keyring> for Pair {
|
||||
fn from(k: Keyring) -> Self {
|
||||
match k {
|
||||
Keyring::Alice => Pair::from_seed(b"Alice "),
|
||||
Keyring::Bob => Pair::from_seed(b"Bob "),
|
||||
Keyring::Charlie => Pair::from_seed(b"Charlie "),
|
||||
Keyring::Dave => Pair::from_seed(b"Dave "),
|
||||
Keyring::Eve => Pair::from_seed(b"Eve "),
|
||||
Keyring::Ferdie => Pair::from_seed(b"Ferdie "),
|
||||
Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"),
|
||||
Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")),
|
||||
}
|
||||
}
|
||||
lazy_static! {
|
||||
static ref PRIVATE_KEYS: HashMap<Keyring, Pair> = {
|
||||
[
|
||||
Keyring::Alice,
|
||||
Keyring::Bob,
|
||||
Keyring::Charlie,
|
||||
Keyring::Dave,
|
||||
Keyring::Eve,
|
||||
Keyring::Ferdie,
|
||||
Keyring::One,
|
||||
Keyring::Two,
|
||||
].iter().map(|&i| (i, i.pair())).collect()
|
||||
};
|
||||
|
||||
static ref PUBLIC_KEYS: HashMap<Keyring, Public> = {
|
||||
PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect()
|
||||
};
|
||||
}
|
||||
|
||||
impl From<Keyring> for Public {
|
||||
fn from(k: Keyring) -> Self {
|
||||
let pair: Pair = k.into();
|
||||
pair.public()
|
||||
(*PUBLIC_KEYS).get(&k).unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Keyring> for Pair {
|
||||
fn from(k: Keyring) -> Self {
|
||||
k.pair()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Keyring> for [u8; 32] {
|
||||
fn from(k: Keyring) -> Self {
|
||||
let pair: Pair = k.into();
|
||||
*pair.public().as_array_ref()
|
||||
*(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Keyring> for &'static [u8; 32] {
|
||||
fn from(k: Keyring) -> Self {
|
||||
(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for Keyring {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
(*PUBLIC_KEYS).get(self).unwrap().as_array_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Public> for Keyring {
|
||||
fn as_ref(&self) -> &Public {
|
||||
(*PUBLIC_KEYS).get(self).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Keyring {
|
||||
type Target = [u8; 32];
|
||||
fn deref(&self) -> &[u8; 32] {
|
||||
(*PUBLIC_KEYS).get(self).unwrap().as_array_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,8 +167,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn should_work() {
|
||||
assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", &Keyring::Alice.into()));
|
||||
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", &Keyring::Alice.into()));
|
||||
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", &Keyring::Bob.into()));
|
||||
assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Alice));
|
||||
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", Keyring::Alice));
|
||||
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Bob));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ use rstd::vec::Vec;
|
||||
#[cfg(feature = "std")]
|
||||
use bytes;
|
||||
use Hash;
|
||||
use codec::{Input, Slicable};
|
||||
use codec::{Input, Slicable, NonTrivialSlicable};
|
||||
|
||||
/// Used to refer to a block number.
|
||||
pub type Number = u64;
|
||||
@@ -47,7 +47,9 @@ impl Slicable for Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
impl ::codec::NonTrivialSlicable for Transaction { }
|
||||
impl NonTrivialSlicable for Transaction { }
|
||||
|
||||
|
||||
|
||||
/// Execution log (event)
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
@@ -64,7 +66,9 @@ impl Slicable for Log {
|
||||
}
|
||||
}
|
||||
|
||||
impl ::codec::NonTrivialSlicable for Log { }
|
||||
impl NonTrivialSlicable for Log { }
|
||||
|
||||
|
||||
|
||||
/// The digest of a block, useful for light-clients.
|
||||
#[derive(Clone, Default, PartialEq, Eq)]
|
||||
@@ -84,40 +88,49 @@ impl Slicable for Digest {
|
||||
}
|
||||
}
|
||||
|
||||
impl NonTrivialSlicable for Digest { }
|
||||
|
||||
/// Generic types to be specialised later.
|
||||
pub mod generic {
|
||||
use super::{Header, Slicable, Input, NonTrivialSlicable, Vec};
|
||||
|
||||
/// A Block - this is generic for later specialisation in particular runtimes.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
pub struct Block<Transaction: PartialEq + Eq + Clone> {
|
||||
/// The block header.
|
||||
pub header: Header,
|
||||
/// All relay-chain transactions.
|
||||
pub transactions: Vec<Transaction>,
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq + Clone> Slicable for Block<T> where Vec<T>: Slicable {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
Some(Block {
|
||||
header: try_opt!(Slicable::decode(input)),
|
||||
transactions: try_opt!(Slicable::decode(input)),
|
||||
})
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let mut v: Vec<u8> = Vec::new();
|
||||
v.extend(self.header.encode());
|
||||
v.extend(self.transactions.encode());
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq + Clone> NonTrivialSlicable for Block<T> where Vec<T>: Slicable { }
|
||||
}
|
||||
|
||||
/// The body of a block is just a bunch of transactions.
|
||||
pub type Body = Vec<Transaction>;
|
||||
/// The header and body of a concrete, but unspecialised, block. Used by substrate to represent a
|
||||
/// block some fields of which the runtime alone knows how to interpret (e.g. the transactions).
|
||||
pub type Block = generic::Block<Transaction>;
|
||||
|
||||
/// A Substrate relay chain block.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
pub struct Block {
|
||||
/// The block header.
|
||||
pub header: Header,
|
||||
/// All relay-chain transactions.
|
||||
pub transactions: Body,
|
||||
}
|
||||
|
||||
impl Slicable for Block {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
Some(Block {
|
||||
header: try_opt!(Slicable::decode(input)),
|
||||
transactions: try_opt!(Slicable::decode(input)),
|
||||
})
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
v.extend(self.header.encode());
|
||||
v.extend(self.transactions.encode());
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
/// A relay chain block header.
|
||||
///
|
||||
/// https://github.com/w3f/polkadot-spec/blob/master/spec.md#header
|
||||
/// A substrate chain block header.
|
||||
// TODO: split out into light-client-specific fields and runtime-specific fields.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
|
||||
@@ -131,6 +144,9 @@ pub struct Header {
|
||||
pub state_root: Hash,
|
||||
/// The root of the trie that represents this block's transactions, indexed by a 32-byte integer.
|
||||
pub transaction_root: Hash,
|
||||
// TODO...
|
||||
// /// The root of the trie that represents the receipts from this block's transactions
|
||||
// pub receipts_root: Hash,
|
||||
/// The digest of activity on the block.
|
||||
pub digest: Digest,
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ pub fn enumerated_trie_root(serialised_values: &[&[u8]]) -> [u8; 32] {
|
||||
}
|
||||
|
||||
/// Verify a ed25519 signature.
|
||||
pub fn ed25519_verify(sig: &[u8; 64], msg: &[u8], pubkey: &[u8; 32]) -> bool {
|
||||
pub fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
|
||||
ed25519::verify(sig, msg, pubkey)
|
||||
}
|
||||
|
||||
|
||||
@@ -161,9 +161,9 @@ pub fn twox_128(data: &[u8]) -> [u8; 16] {
|
||||
}
|
||||
|
||||
/// Verify a ed25519 signature.
|
||||
pub fn ed25519_verify(sig: &[u8; 64], msg: &[u8], pubkey: &[u8; 32]) -> bool {
|
||||
pub fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
|
||||
unsafe {
|
||||
ext_ed25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ptr()) == 0
|
||||
ext_ed25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,3 +26,6 @@ pub use std::ptr;
|
||||
pub use std::rc;
|
||||
pub use std::slice;
|
||||
pub use std::vec;
|
||||
pub mod collections {
|
||||
pub use std::collections::btree_map;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ extern crate pwasm_alloc;
|
||||
pub use alloc::boxed;
|
||||
pub use alloc::rc;
|
||||
pub use alloc::vec;
|
||||
pub mod collections {
|
||||
pub use alloc::btree_map;
|
||||
}
|
||||
pub use core::borrow;
|
||||
pub use core::cell;
|
||||
pub use core::cmp;
|
||||
|
||||
@@ -322,7 +322,6 @@ pub mod unhashed {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use primitives::hexdisplay;
|
||||
use runtime_io::{twox_128, TestExternalities, with_externalities};
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate 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.
|
||||
|
||||
// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! A toy unchecked transaction complete with signature.
|
||||
|
||||
use rstd::prelude::*;
|
||||
use codec::{Input, Slicable, Joiner};
|
||||
use super::{Header, UncheckedTransaction};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
/// A coupling between a header and a list of transactions.
|
||||
pub struct Block {
|
||||
/// The block header.
|
||||
pub header: Header,
|
||||
/// The list of transactions in the block.
|
||||
pub transactions: Vec<UncheckedTransaction>,
|
||||
}
|
||||
|
||||
impl Slicable for Block {
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
Some(Block {
|
||||
header: Slicable::decode(input)?,
|
||||
transactions: Slicable::decode(input)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
Vec::new()
|
||||
.and(&self.header)
|
||||
.and(&self.transactions)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::codec::NonTrivialSlicable for Block {}
|
||||
@@ -31,19 +31,20 @@ extern crate substrate_codec as codec;
|
||||
pub mod system;
|
||||
mod transaction;
|
||||
mod unchecked_transaction;
|
||||
mod block;
|
||||
|
||||
use rstd::prelude::*;
|
||||
use codec::Slicable;
|
||||
|
||||
use primitives::AuthorityId;
|
||||
use primitives::hash::H512;
|
||||
use primitives::block::generic;
|
||||
pub use primitives::hash::H256;
|
||||
pub use primitives::block::{Header, Number as BlockNumber, Digest};
|
||||
pub use transaction::Transaction;
|
||||
pub use unchecked_transaction::UncheckedTransaction;
|
||||
pub use block::Block;
|
||||
|
||||
/// A test block.
|
||||
pub type Block = generic::Block<UncheckedTransaction>;
|
||||
/// An identifier for an account on this system.
|
||||
pub type AccountId = AuthorityId;
|
||||
/// Signature for our transactions.
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Reference in New Issue
Block a user