Compile polkadot-runtime both for Wasm ad native, allowing for testing and direct usage.

This commit is contained in:
Gav
2018-01-09 13:47:28 +01:00
parent 5ab59bb171
commit b104f5e6e4
68 changed files with 98 additions and 23 deletions
+33
View File
@@ -0,0 +1,33 @@
[[package]]
name = "pwasm-alloc"
version = "0.1.0"
dependencies = [
"pwasm-libc 0.1.0",
]
[[package]]
name = "pwasm-libc"
version = "0.1.0"
[[package]]
name = "runtime-polkadot"
version = "0.1.0"
dependencies = [
"runtime-support 0.1.0",
]
[[package]]
name = "runtime-support"
version = "0.1.0"
dependencies = [
"pwasm-alloc 0.1.0",
"pwasm-libc 0.1.0",
]
[[package]]
name = "runtime-test"
version = "0.1.0"
dependencies = [
"runtime-support 0.1.0",
]
+8
View File
@@ -0,0 +1,8 @@
[workspace]
members = [
"test",
"polkadot",
]
[profile.release]
panic = "abort"
+11
View File
@@ -0,0 +1,11 @@
#!/bin/sh
cargo +nightly build --target=wasm32-unknown-unknown --release
dirs=`find * -maxdepth 0 -type d | grep -v pwasm- | grep -v support`
for i in $dirs
do
if [[ -e $i/Cargo.toml ]]
then
wasm-gc target/wasm32-unknown-unknown/release/runtime_$i.wasm target/wasm32-unknown-unknown/release/runtime_$i.compact.wasm
fi
done
+6
View File
@@ -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
@@ -0,0 +1,15 @@
[package]
name = "runtime-polkadot"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[lib]
crate-type = ["cdylib"]
[dependencies]
runtime-support = { path = "../support", version = "0.1" }
[features]
default = ["without-std"]
with-std = []
without-std = []
+314
View File
@@ -0,0 +1,314 @@
#![cfg_attr(feature = "without-std", no_std)]
#![cfg_attr(feature = "strict", deny(warnings))]
#[macro_use]
extern crate runtime_support;
use runtime_support::{set_storage, storage, storage_into, Vec};
/// The hash of an ECDSA pub key which is used to identify an external transactor.
pub type AccountID = [u8; 32];
/// The ECDSA pub key of an authority. This is what the external environment/consensus algorithm
/// refers to as a "authority".
pub type SessionKey = AccountID;
pub type Balance = u64;
pub type ChainID = u64;
pub type Hash = [u8; 32];
pub type BlockNumber = u64;
pub type Timestamp = u64;
pub type TxOrder = u64;
/// The functions that a transaction can call (and be dispatched to).
pub enum Function {
StakingStake(),
StakingUnstake(),
ConsensusSetSessionKey(SessionKey),
}
impl Function {
/// Dispatch the function.
pub fn dispatch(self) -> Vec<u8> { unimplemented!() }
}
pub struct Digest {
pub logs: Vec<Vec<u8>>,
}
pub struct Header {
pub parent_hash: Hash,
pub number: BlockNumber,
pub state_root: Hash,
pub transaction_root: Hash,
pub digest: Digest,
}
pub struct Transaction {
pub senders: Vec<AccountID>,
pub function: Function,
pub input_data: Vec<u8>,
pub nonce: TxOrder,
}
pub struct Block {
pub header: Header,
pub transactions: Vec<Transaction>,
}
impl Header {
pub fn from_rlp(_rlp: &[u8]) -> Self {
unimplemented!()
}
}
impl Transaction {
pub fn from_rlp(_rlp: &[u8]) -> Self {
unimplemented!()
}
}
impl Block {
pub fn from_rlp(_rlp: &[u8]) -> Self {
unimplemented!()
}
}
/*
use std::sync::{rc, RefCell, Once, ONCE_INIT};
use std::mem;
#[derive(Default)]
struct Environment {
header: Option<Header>,
current_user: Option<AccountID>,
}
#[derive(Clone)]
struct EnvironmentHolder {
inner: Rc<RefCell<Environment>>,
}
fn get_environment() -> EnvironmentHolder {
// Initialize it to a null value
static mut SINGLETON: *const EnvironmentHolder = 0 as *const EnvironmentHolder;
static ONCE: Once = ONCE_INIT;
unsafe {
ONCE.call_once(|| {
// Make it
let singleton = EnvironmentHolder {
inner: 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()
}
}
*/
// TODO: include RLP implementation
// TODO: add keccak256 (or some better hashing scheme) & ECDSA-recover (or some better sig scheme)
pub fn execute_block(_input: Vec<u8>) -> Vec<u8> {
let block = Block::from_rlp(&_input);
environment::execute_block(&block)
}
pub fn execute_transaction(_input: Vec<u8>) -> Vec<u8> {
let tx = Transaction::from_rlp(&_input);
environment::execute_transaction(&tx)
}
impl_stubs!(execute_block, execute_transaction);
/// The current relay chain identifier.
fn chain_id() -> ChainID {
// TODO: retrieve from external
unimplemented!()
}
mod environment {
use super::*;
/// The current block number being processed. Set by `execute_block`.
pub fn block_number() -> BlockNumber { unimplemented!() }
/// Get the block hash of a given block.
pub fn block_hash(_number: BlockNumber) -> Hash { unimplemented!() }
/// Get the current user's ID
pub fn current_user() -> AccountID { unimplemented!() }
pub fn execute_block(_block: &Block) -> Vec<u8> {
// TODO: populate environment from header.
staking::pre_transactions();
// TODO: go through each transaction and use execute_transaction to execute.
staking::post_transactions();
// TODO: ensure digest in header is what we expect from transactions.
Vec::new()
}
/// Execute a given transaction.
pub fn execute_transaction(_tx: &Transaction) -> Vec<u8> {
// TODO: decode data and ensure valid
// TODO: ensure signature valid and recover id (use authentication::authenticate)
// TODO: ensure target_function valid
// TODO: decode parameters
// TODO: set `current_user` to the id
// TODO: make call
// TODO: reset `current_user`
// TODO: encode any return
Vec::new()
}
/// Set the new code.
pub fn set_code(new: &[u8]) {
set_storage(b"\0code", new)
}
/// Set the light-client digest for the header.
pub fn set_digest(_preserialised_rlp_digest: &[u8]) {
// TODO: Mention this to the external environment?
unimplemented!()
}
}
mod consensus {
use super::*;
fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
let mut acc = initial;
while value > 0 {
acc.push(value as u8);
value /= 256;
}
acc
}
fn set_authority(index: usize, authority: AccountID) {
set_storage(&value_vec(index, b"\0authority".to_vec()), &authority[..]);
}
fn authority(index: usize) -> AccountID {
storage_into(&value_vec(index, b"\0authority".to_vec())).unwrap()
}
fn set_authority_count(count: usize) {
(count..authority_count()).for_each(|i| set_authority(i, SessionKey::default()));
set_storage(b"\0authority_count", &value_vec(count, Vec::new()));
}
fn authority_count() -> usize {
storage(b"\0authority_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize))
}
/// Get the current set of authorities. These are the session keys.
pub fn authorities() -> Vec<AccountID> {
(0..authority_count()).into_iter().map(authority).collect()
}
/// Set the current set of authorities' session keys.
///
/// Called by `next_session` only.
fn set_authorities(authorities: &[AccountID]) {
set_authority_count(authorities.len());
authorities.iter().enumerate().for_each(|(v, &i)| set_authority(v, i));
}
/// Get the current set of validators. These are the long-term identifiers for the validators
/// and will be mapped to a session key with the most recent `set_next_session_key`.
pub fn validators() -> Vec<AccountID> {
unimplemented!()
}
/// Set the current set of validators.
///
/// Called by staking::next_era() only.
pub fn set_validators(_new: &[AccountID]) {
unimplemented!()
}
/// The number of blocks in each session.
pub fn session_length() -> BlockNumber {
10
}
/// Sets the session key of `_validator` to `_session`. This doesn't take effect until the next
/// session.
pub fn set_session_key(_validator: AccountID, _session: AccountID) {
unimplemented!()
}
/// Move onto next session: register the new authority set.
pub fn next_session() {
// TODO: Call set_authorities().
unimplemented!()
}
/// Hook to be called prior to transaction processing.
pub fn pre_transactions() {}
/// Hook to be called after to transaction processing.
pub fn post_transactions() {
// TODO: check block number and call next_session if necessary.
}
}
mod staking {
use super::*;
/// The length of a staking era in blocks.
pub fn era_length() -> BlockNumber { sessions_per_era() * consensus::session_length() }
/// The length of a staking era in sessions.
pub fn sessions_per_era() -> BlockNumber { 10 }
/// The era has changed - enact new staking set.
///
/// NOTE: This always happens on a session change.
fn next_era() { unimplemented!() }
/// The balance of a given account.
fn balance(_who: AccountID) -> Balance { unimplemented!() }
/// Transfer some unlocked staking balance to another staker.
fn transfer_stake(_who: AccountID, _dest: AccountID, _value: Balance) { unimplemented!() }
/// Declare the desire to stake.
///
/// Effects will be felt at the beginning of the next era.
fn stake() { unimplemented!() }
/// Retract the desire to stake.
///
/// Effects will be felt at the beginning of the next era.
fn unstake() { unimplemented!() }
/// Hook to be called prior to transaction processing.
pub fn pre_transactions() {
consensus::pre_transactions();
}
/// Hook to be called after to transaction processing.
pub fn post_transactions() {
// TODO: check block number and call next_era if necessary.
consensus::post_transactions();
}
}
mod authentication {
use super::*;
fn validate_signature(_tx: Transaction) -> ( AccountID, TxOrder ) { unimplemented!() }
fn nonce(_id: AccountID) -> TxOrder { unimplemented!() }
fn authenticate(_tx: Transaction) -> AccountID { unimplemented!() }
}
mod timestamp {
use super::*;
fn timestamp() -> Timestamp { unimplemented!() }
fn set_timestamp(_now: Timestamp) { unimplemented!() }
}
@@ -0,0 +1,18 @@
[package]
name = "pwasm-alloc"
version = "0.1.0"
authors = ["Nikolay Volf <nikvolf@gmail.com>"]
license = "MIT/Apache-2.0"
readme = "README.md"
repository = "https://github.com/paritytech/pwasm-std"
homepage = "https://github.com/paritytech/pwasm-std"
documentation = "https://paritytech.github.io/pwasm-std/pwasm_std/"
description = "Parity WebAssembly standard library internal allocator"
keywords = ["wasm", "parity", "webassembly", "blockchain"]
categories = ["no-std", "embedded"]
[dependencies]
pwasm-libc = { path = "../pwasm-libc", version = "0.1" }
[features]
strict = []
@@ -0,0 +1,12 @@
# pwasm-libc
Parity WASM contracts standard library libc bindings
[Documentation](https://paritytech.github.io/pwasm-std/pwasm_alloc/)
# License
`pwasm_alloc` is primarily distributed under the terms of both the MIT
license and the Apache License (Version 2.0), at your choice.
See LICENSE-APACHE, and LICENSE-MIT for details.
@@ -0,0 +1,30 @@
#![warn(missing_docs)]
#![cfg_attr(feature = "strict", deny(warnings))]
#![no_std]
#![crate_type = "rlib"]
#![feature(global_allocator)]
#![feature(alloc)]
#![feature(allocator_api)]
//! Custom allocator crate for wasm
extern crate alloc;
extern crate pwasm_libc;
use alloc::heap::{Alloc, Layout, AllocErr};
/// Wasm allocator
pub struct WasmAllocator;
unsafe impl<'a> Alloc for &'a WasmAllocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
Ok(pwasm_libc::malloc(layout.size()))
}
unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) {
pwasm_libc::free(ptr)
}
}
#[global_allocator]
static ALLOCATOR: WasmAllocator = WasmAllocator;
@@ -0,0 +1,15 @@
[package]
name = "pwasm-libc"
version = "0.1.0"
authors = ["Sergey Pepyakin <s.pepyakin@gmail.com>"]
license = "MIT/Apache-2.0"
readme = "README.md"
repository = "https://github.com/paritytech/pwasm-std"
homepage = "https://github.com/paritytech/pwasm-std"
documentation = "https://paritytech.github.io/pwasm-std/pwasm_std/"
description = "Parity WebAssembly standard library libc bindings"
keywords = ["wasm", "parity", "webassembly", "blockchain"]
categories = ["no-std", "embedded"]
[features]
strict = []
@@ -0,0 +1,12 @@
# pwasm-libc
Parity WASM contracts standard library libc bindings
[Documentation](https://paritytech.github.io/pwasm-std/pwasm_libc/)
# License
`pwasm-libc` is primarily distributed under the terms of both the MIT
license and the Apache License (Version 2.0), at your choice.
See LICENSE-APACHE, and LICENSE-MIT for details.
@@ -0,0 +1,46 @@
#![warn(missing_docs)]
#![cfg_attr(feature = "strict", deny(warnings))]
#![no_std]
//! libc externs crate
extern "C" {
fn ext_memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
fn ext_memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
fn ext_memset(dest: *mut u8, c: i32, n: usize) -> *mut u8;
fn ext_malloc(size: usize) -> *mut u8;
fn ext_free(ptr: *mut u8);
}
// Declaring these function here prevents Emscripten from including it's own verisons
// into final binary.
/// memcpy extern
#[no_mangle]
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
ext_memcpy(dest, src, n)
}
/// memmove extern
#[no_mangle]
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
ext_memmove(dest, src, n)
}
/// memset extern
#[no_mangle]
pub unsafe extern "C" fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 {
ext_memset(dest, c, n)
}
/// malloc extern
#[no_mangle]
pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 {
ext_malloc(size)
}
/// free extern
#[no_mangle]
pub unsafe extern "C" fn free(ptr: *mut u8) {
ext_free(ptr);
}
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "runtime-support"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
pwasm-libc = { path = "../pwasm-libc", version = "0.1" }
pwasm-alloc = { path = "../pwasm-alloc", version = "0.1" }
[features]
strict = []
+111
View File
@@ -0,0 +1,111 @@
#![no_std]
#![feature(lang_items)]
#![feature(alloc)]
#![cfg_attr(feature = "strict", deny(warnings))]
#![feature(alloc)]
//#[macro_use]
extern crate alloc;
pub use alloc::vec::Vec;
use core::mem;
extern crate pwasm_libc;
extern crate pwasm_alloc;
#[lang = "panic_fmt"]
#[no_mangle]
pub fn panic_fmt() -> ! {
loop {}
}
extern "C" {
fn ext_print(utf8_data: *const u8, utf8_len: u32);
fn ext_print_num(value: u64);
fn ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32);
fn ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8;
fn ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32) -> u32;
fn ext_deposit_log(log_data: *const u8, log_len: u32);
}
pub fn storage(key: &[u8]) -> Vec<u8> {
let mut length: u32 = 0;
unsafe {
let ptr = ext_get_allocated_storage(&key[0], key.len() as u32, &mut length);
Vec::from_raw_parts(ptr, length as usize, length as usize)
}
}
pub fn storage_into<T: Sized>(key: &[u8]) -> Option<T> {
let mut result: T;
let size = mem::size_of::<T>();
let written;
unsafe {
result = mem::uninitialized();
let result_as_byte_blob = mem::transmute::<*mut T, *mut u8>(&mut result);
written = ext_get_storage_into(&key[0], key.len() as u32, result_as_byte_blob, size as u32) as usize;
}
// Only return a fully written value.
if written == size {
Some(result)
} else {
None
}
}
pub fn set_storage(key: &[u8], value: &[u8]) {
unsafe {
ext_set_storage(
&key[0] as *const u8, key.len() as u32,
&value[0] as *const u8, value.len() as u32
);
}
}
pub fn deposit_log(log: &[u8]) {
unsafe {
ext_deposit_log(
&log[0] as *const u8, log.len() as u32,
)
}
}
pub trait Printable {
fn print(self);
}
impl<'a> Printable for &'a [u8] {
fn print(self) {
unsafe {
ext_print(&self[0] as *const u8, self.len() as u32);
}
}
}
impl Printable for u64 {
fn print(self) {
unsafe { ext_print_num(self); }
}
}
pub fn print<T: Printable + Sized>(value: T) {
value.print();
}
#[macro_export]
macro_rules! impl_stubs {
( $( $name:ident ),* ) => {
pub mod _internal {
$(
#[no_mangle]
pub fn $name(input_data: *mut u8, input_len: usize) -> u64 {
let input = unsafe {
$crate::Vec::from_raw_parts(input_data, input_len, input_len)
};
let output = super::$name(input);
&output[0] as *const u8 as u64 + ((output.len() as u64) << 32)
}
)*
}
}
}
@@ -0,0 +1 @@
{"rustc":8291033049748019918,"features":"[]","target":14441046832906989149,"profile":731176819336294830,"deps":[],"local":[{"MtimeBased":[[1515500307,607755819],"/Users/gav/Core/polkadot/wasm-runtime/target/debug/.fingerprint/pwasm-libc-e72991cbfafd2b71/dep-lib-pwasm_libc-e72991cbfafd2b71"]}],"rustflags":[]}
@@ -0,0 +1,5 @@
/Users/gav/Core/polkadot/wasm-runtime/target/debug/deps/pwasm_libc-b023388293df7da5: /Users/gav/Core/polkadot/wasm-runtime/pwasm-libc/src/lib.rs
/Users/gav/Core/polkadot/wasm-runtime/target/debug/deps/pwasm_libc-b023388293df7da5.d: /Users/gav/Core/polkadot/wasm-runtime/pwasm-libc/src/lib.rs
/Users/gav/Core/polkadot/wasm-runtime/pwasm-libc/src/lib.rs:
@@ -0,0 +1 @@
{"rustc":8294656847287967537,"features":"[]","target":1127969377865045195,"profile":42358739494345872,"deps":[["pwasm-libc v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/pwasm-libc)",6197225601014249845]],"local":[{"MtimeBased":[[1515500743,816953612],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/pwasm-alloc-e37006629c0ab425/dep-lib-pwasm_alloc-e37006629c0ab425"]}],"rustflags":[]}
@@ -0,0 +1 @@
{"rustc":8294656847287967537,"features":"[]","target":14441046832906989149,"profile":42358739494345872,"deps":[],"local":[{"MtimeBased":[[1515500743,598235760],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/pwasm-libc-9375d1aea6d3c98f/dep-lib-pwasm_libc-9375d1aea6d3c98f"]}],"rustflags":[]}
@@ -0,0 +1 @@
{"rustc":8294656847287967537,"features":"[\"default\", \"without-std\"]","target":15371597068611496627,"profile":42358739494345872,"deps":[["runtime-support v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/support)",2223771509741189442]],"local":[{"MtimeBased":[[1515501953,507863132],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/dep-lib-runtime_polkadot"]}],"rustflags":[]}
@@ -0,0 +1 @@
{"rustc":8294656847287967537,"features":"[]","target":14982045766639954252,"profile":42358739494345872,"deps":[["pwasm-alloc v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/pwasm-alloc)",1843871105590971886],["pwasm-libc v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/pwasm-libc)",6197225601014249845]],"local":[{"MtimeBased":[[1515500954,752149165],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/dep-lib-runtime_support-5482fb51bf4d410e"]}],"rustflags":[]}
@@ -0,0 +1 @@
{"rustc":8294656847287967537,"features":"[]","target":11385551307513482501,"profile":42358739494345872,"deps":[["runtime-support v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/support)",2223771509741189442]],"local":[{"MtimeBased":[[1515500955,389693545],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/dep-lib-runtime_test"]}],"rustflags":[]}
@@ -0,0 +1 @@
/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/libpwasm_alloc.rlib: /Users/gav/Core/polkadot/wasm-runtime/pwasm-alloc/src/lib.rs /Users/gav/Core/polkadot/wasm-runtime/pwasm-libc/src/lib.rs
@@ -0,0 +1 @@
/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/libpwasm_libc.rlib: /Users/gav/Core/polkadot/wasm-runtime/pwasm-libc/src/lib.rs
@@ -0,0 +1 @@
/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/libruntime_support.rlib: /Users/gav/Core/polkadot/wasm-runtime/pwasm-libc/src/lib.rs /Users/gav/Core/polkadot/wasm-runtime/support/src/lib.rs /Users/gav/Core/polkadot/wasm-runtime/pwasm-alloc/src/lib.rs
@@ -0,0 +1 @@
/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm: /Users/gav/Core/polkadot/wasm-runtime/pwasm-alloc/src/lib.rs /Users/gav/Core/polkadot/wasm-runtime/support/src/lib.rs /Users/gav/Core/polkadot/wasm-runtime/polkadot/src/lib.rs /Users/gav/Core/polkadot/wasm-runtime/pwasm-libc/src/lib.rs
@@ -0,0 +1 @@
/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm: /Users/gav/Core/polkadot/wasm-runtime/pwasm-alloc/src/lib.rs /Users/gav/Core/polkadot/wasm-runtime/test/src/lib.rs /Users/gav/Core/polkadot/wasm-runtime/pwasm-libc/src/lib.rs /Users/gav/Core/polkadot/wasm-runtime/support/src/lib.rs
+10
View File
@@ -0,0 +1,10 @@
[package]
name = "runtime-test"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[lib]
crate-type = ["cdylib"]
[dependencies]
runtime-support = { path = "../support", version = "0.1" }
+79
View File
@@ -0,0 +1,79 @@
#![no_std]
#![feature(lang_items)]
#![cfg_attr(feature = "strict", deny(warnings))]
#![feature(alloc)]
extern crate alloc;
use alloc::vec::Vec;
#[macro_use]
extern crate runtime_support;
use runtime_support::{set_storage, storage, print};
pub fn code() -> Vec<u8> {
storage(b"\0code")
}
pub fn set_code(new: &[u8]) {
set_storage(b"\0code", new)
}
fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
let mut acc = initial;
while value > 0 {
acc.push(value as u8);
value /= 256;
}
acc
}
pub fn set_authority(index: usize, authority: &[u8]) {
set_storage(&value_vec(index, b"\0authority".to_vec()), authority);
}
pub fn authority(index: usize) -> Vec<u8> {
storage(&value_vec(index, b"\0authority".to_vec()))
}
pub fn set_authority_count(count: usize) {
(count..authority_count()).for_each(|i| set_authority(i, &[]));
set_storage(b"\0authority_count", &value_vec(count, Vec::new()));
}
pub fn authority_count() -> usize {
storage(b"\0authority_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize))
}
pub fn authorities() -> Vec<Vec<u8>> {
(0..authority_count()).into_iter().map(authority).collect()
}
pub fn set_authorities(authorities: &[&[u8]]) {
set_authority_count(authorities.len());
authorities.iter().enumerate().for_each(|(v, i)| set_authority(v, i));
}
impl_stubs!(test_data_in);
fn test_data_in(input: Vec<u8>) -> Vec<u8> {
print(b"set_storage" as &[u8]);
set_storage(b"input", &input);
print(b"code" as &[u8]);
set_storage(b"code", &code());
print(b"set_code" as &[u8]);
set_code(&input);
print(b"storage" as &[u8]);
let copy = storage(b"input");
print(b"authorities" as &[u8]);
let mut v = authorities();
v.push(copy);
print(b"set_authorities" as &[u8]);
set_authorities(&v.iter().map(Vec::as_slice).collect::<Vec<_>>());
print(b"finished!" as &[u8]);
b"all ok!".to_vec()
}