From 3402f169a7cf83587b171bdab3414b69ce1b8e77 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 23 Jan 2018 15:24:17 +0100 Subject: [PATCH] Introduce basic skeleton for Polkadot runtime. (#32) * Introduce basic skeleton for Polkador runtime. * Clean up the runtime skeleton. * Make initial runtime skeleton compile. * Compile polkadot-runtime both for Wasm ad native, allowing for testing and direct usage. * More fleshing out on runtime. * Update native support. * Fix warning. * Update gitignore * Update path. * Fix path. * Remove accidentally committed files. * Add wasm binaries. * Fix test. * Native storage support API. * Add environmental module * Add native environment to make native source-code compatible with wasm. Also tests. * Finish up & polish environment stuff. * Avoid using reentrancy issues. * Add some docs and a test. * Remove unneeded function. * Documentation * Tweak docs * Remove TODOs. * Balance transfers + util methods. * Rejig tests and ensure authorities are addressed consistently. * Add marshaller for xfer function * Transaction dispatch test. * Minor fix. * Add test for ser/de transaction. * Add ser/de for header. * Add tests for header ser/de * Introduce basic block decoding/execution framework. * Introduce block decoding/execution framework (p2) * Big refactor. * Split out joiner. * Hide away support modules. * Fix up wasm runtime. * use externalities for chain_id * Clean up (Test)Externalities. * Repot and introduce keccak-256 external. * Signing with crypto. * fix unsafety hole in environmental using function * Introduce Ed25519 crypto. * Repotting. * Add ed25519_verify external. * Introduce Ed25519 verify as an external. * fix unsafety hole around unwinding * Compile fixes. * use new environmental API * Tests for ed25519 verify. * Polish * Introduce UncheckedTransaction & test. * Implement basic block and tx processing * Introduce static hex and valid signature for block test. * Repot session. * comments. * Refactor and timestamp test * Remove fluff * Remove fluff. * Staking eras and tests. * Implement sessions. * Polish * Test sessions. * Introduce better hashing. - Blake2 for secure hashing - XX for fast hashing * Fix tests. * Introduce staking. * Tests for simple staking system. * Build fix for wasm. * Fix tests. * Repotting and docs. * Docs and licence. * Documentation. * Remove superfluous code. * Remove dummy key. * Remove other superfluous file. * Optimise with swap_remove --- substrate/.gitignore | 2 +- substrate/Cargo.lock | 150 ++++- substrate/Cargo.toml | 4 +- substrate/environmental/Cargo.toml | 4 + substrate/environmental/src/lib.rs | 272 +++++++++ substrate/executor/Cargo.toml | 1 + substrate/executor/src/lib.rs | 1 + substrate/executor/src/wasm_executor.rs | 168 ++++-- substrate/executor/src/wasm_utils.rs | 14 +- substrate/native-runtime/Cargo.toml | 13 + substrate/native-runtime/src | 1 + substrate/native-runtime/support/Cargo.toml | 14 + substrate/native-runtime/support/src/lib.rs | 149 +++++ substrate/primitives/Cargo.toml | 6 +- substrate/primitives/src/block.rs | 2 +- substrate/primitives/src/ed25519.rs | 235 ++++++++ substrate/primitives/src/hash.rs | 4 +- substrate/primitives/src/hashing.rs | 106 ++++ substrate/primitives/src/hexdisplay.rs | 60 ++ substrate/primitives/src/lib.rs | 14 +- substrate/primitives/src/parachain.rs | 2 +- substrate/runtime/polkadot/src/lib.rs | 36 -- substrate/runtime/support/src/lib.rs | 125 ----- .../release/runtime_polkadot.compact.wasm | Bin 3042 -> 0 bytes .../release/runtime_polkadot.wasm | Bin 3130 -> 0 bytes .../release/runtime_test.compact.wasm | Bin 3042 -> 0 bytes .../release/runtime_test.wasm | Bin 3130 -> 0 bytes substrate/runtime/test/src/lib.rs | 36 -- substrate/state_machine/Cargo.toml | 1 - substrate/state_machine/src/ext.rs | 4 + substrate/state_machine/src/lib.rs | 50 +- .../{runtime => wasm-runtime}/Cargo.lock | 0 .../{runtime => wasm-runtime}/Cargo.toml | 0 substrate/{runtime => wasm-runtime}/build.sh | 0 substrate/{runtime => wasm-runtime}/init.sh | 0 .../polkadot/Cargo.toml | 5 + .../polkadot/src/codec/endiansensitive.rs | 50 ++ .../wasm-runtime/polkadot/src/codec/joiner.rs | 32 ++ .../polkadot/src/codec/keyedvec.rs | 56 ++ .../wasm-runtime/polkadot/src/codec/mod.rs | 23 + .../polkadot/src/codec/slicable.rs | 88 +++ .../polkadot/src/codec/streamreader.rs | 74 +++ substrate/wasm-runtime/polkadot/src/lib.rs | 54 ++ .../polkadot/src/runtime/consensus.rs | 44 ++ .../wasm-runtime/polkadot/src/runtime/mod.rs | 30 + .../polkadot/src/runtime/session.rs | 229 ++++++++ .../polkadot/src/runtime/staking.rs | 363 ++++++++++++ .../polkadot/src/runtime/system.rs | 154 ++++++ .../polkadot/src/runtime/timestamp.rs | 54 ++ .../polkadot/src/support/environment.rs | 78 +++ .../polkadot/src/support/function.rs | 74 +++ .../wasm-runtime/polkadot/src/support/mod.rs | 28 + .../polkadot/src/support/primitives.rs | 515 ++++++++++++++++++ .../polkadot/src/support/statichex.rs | 52 ++ .../polkadot/src/support/storable.rs | 87 +++ .../polkadot/src/support/testing.rs | 106 ++++ .../pwasm-alloc/Cargo.toml | 0 .../pwasm-alloc/README.md | 0 .../pwasm-alloc/src/lib.rs | 0 .../pwasm-libc/Cargo.toml | 0 .../pwasm-libc/README.md | 0 .../pwasm-libc/src/lib.rs | 0 .../support/Cargo.toml | 0 substrate/wasm-runtime/support/src/lib.rs | 144 +++++ .../release/runtime_polkadot.compact.wasm | Bin 0 -> 37802 bytes .../release/runtime_polkadot.wasm | Bin 0 -> 37859 bytes .../release/runtime_test.compact.wasm | Bin 0 -> 1460 bytes .../release/runtime_test.wasm | Bin 0 -> 1576 bytes .../{runtime => wasm-runtime}/test/Cargo.toml | 0 substrate/wasm-runtime/test/src/lib.rs | 46 ++ 70 files changed, 3578 insertions(+), 282 deletions(-) create mode 100644 substrate/environmental/Cargo.toml create mode 100644 substrate/environmental/src/lib.rs create mode 100644 substrate/native-runtime/Cargo.toml create mode 120000 substrate/native-runtime/src create mode 100644 substrate/native-runtime/support/Cargo.toml create mode 100644 substrate/native-runtime/support/src/lib.rs create mode 100644 substrate/primitives/src/ed25519.rs create mode 100644 substrate/primitives/src/hashing.rs create mode 100644 substrate/primitives/src/hexdisplay.rs delete mode 100644 substrate/runtime/polkadot/src/lib.rs delete mode 100644 substrate/runtime/support/src/lib.rs delete mode 100644 substrate/runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm delete mode 100644 substrate/runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm delete mode 100644 substrate/runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm delete mode 100644 substrate/runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm delete mode 100644 substrate/runtime/test/src/lib.rs rename substrate/{runtime => wasm-runtime}/Cargo.lock (100%) rename substrate/{runtime => wasm-runtime}/Cargo.toml (100%) rename substrate/{runtime => wasm-runtime}/build.sh (100%) rename substrate/{runtime => wasm-runtime}/init.sh (100%) rename substrate/{runtime => wasm-runtime}/polkadot/Cargo.toml (75%) create mode 100644 substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs create mode 100644 substrate/wasm-runtime/polkadot/src/codec/joiner.rs create mode 100644 substrate/wasm-runtime/polkadot/src/codec/keyedvec.rs create mode 100644 substrate/wasm-runtime/polkadot/src/codec/mod.rs create mode 100644 substrate/wasm-runtime/polkadot/src/codec/slicable.rs create mode 100644 substrate/wasm-runtime/polkadot/src/codec/streamreader.rs create mode 100644 substrate/wasm-runtime/polkadot/src/lib.rs create mode 100644 substrate/wasm-runtime/polkadot/src/runtime/consensus.rs create mode 100644 substrate/wasm-runtime/polkadot/src/runtime/mod.rs create mode 100644 substrate/wasm-runtime/polkadot/src/runtime/session.rs create mode 100644 substrate/wasm-runtime/polkadot/src/runtime/staking.rs create mode 100644 substrate/wasm-runtime/polkadot/src/runtime/system.rs create mode 100644 substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs create mode 100644 substrate/wasm-runtime/polkadot/src/support/environment.rs create mode 100644 substrate/wasm-runtime/polkadot/src/support/function.rs create mode 100644 substrate/wasm-runtime/polkadot/src/support/mod.rs create mode 100644 substrate/wasm-runtime/polkadot/src/support/primitives.rs create mode 100644 substrate/wasm-runtime/polkadot/src/support/statichex.rs create mode 100644 substrate/wasm-runtime/polkadot/src/support/storable.rs create mode 100644 substrate/wasm-runtime/polkadot/src/support/testing.rs rename substrate/{runtime => wasm-runtime}/pwasm-alloc/Cargo.toml (100%) rename substrate/{runtime => wasm-runtime}/pwasm-alloc/README.md (100%) rename substrate/{runtime => wasm-runtime}/pwasm-alloc/src/lib.rs (100%) rename substrate/{runtime => wasm-runtime}/pwasm-libc/Cargo.toml (100%) rename substrate/{runtime => wasm-runtime}/pwasm-libc/README.md (100%) rename substrate/{runtime => wasm-runtime}/pwasm-libc/src/lib.rs (100%) rename substrate/{runtime => wasm-runtime}/support/Cargo.toml (100%) create mode 100644 substrate/wasm-runtime/support/src/lib.rs create mode 100644 substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm create mode 100644 substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm create mode 100644 substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm create mode 100644 substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm rename substrate/{runtime => wasm-runtime}/test/Cargo.toml (100%) create mode 100644 substrate/wasm-runtime/test/src/lib.rs diff --git a/substrate/.gitignore b/substrate/.gitignore index cd789637f9..c7a3830779 100644 --- a/substrate/.gitignore +++ b/substrate/.gitignore @@ -1,5 +1,5 @@ /target/ **/*.rs.bk *.swp -runtime/**/target/ +wasm-runtime/**/target/ **/._* diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index f570676f20..a05893e615 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -20,6 +20,14 @@ dependencies = [ "odds 0.2.25 (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 = "assert_matches" version = "1.1.0" @@ -90,6 +98,15 @@ name = "bitflags" version = "0.9.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.1.0" @@ -129,6 +146,20 @@ dependencies = [ "yaml-rust 0.3.5 (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" @@ -153,6 +184,11 @@ name = "dtoa" version = "0.4.2" source = "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" @@ -170,6 +206,10 @@ dependencies = [ "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "environmental" +version = "0.1.0" + [[package]] name = "error-chain" version = "0.11.0" @@ -257,6 +297,11 @@ dependencies = [ "num_cpus 1.7.0 (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 = "globset" version = "0.1.4" @@ -425,6 +470,11 @@ name = "lazy_static" version = "0.2.9" 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 = "lazycell" version = "0.5.1" @@ -499,6 +549,14 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "native-runtime" +version = "0.1.0" +dependencies = [ + "runtime-support 0.1.0", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "net2" version = "0.2.31" @@ -561,6 +619,15 @@ dependencies = [ "parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot" +version = "0.5.3" +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.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot_core" version = "0.2.6" @@ -663,6 +730,7 @@ dependencies = [ "polkadot-primitives 0.1.0", "polkadot-serializer 0.1.0", "polkadot-state-machine 0.1.0", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -671,15 +739,19 @@ dependencies = [ name = "polkadot-primitives" version = "0.1.0" dependencies = [ + "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.1.0 (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.0 (git+https://github.com/paritytech/primitives.git)", "polkadot-serializer 0.1.0", "pretty_assertions 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "twox-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.1.0 (git+https://github.com/paritytech/primitives.git)", + "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -719,7 +791,6 @@ version = "0.1.0" dependencies = [ "byteorder 1.1.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)", "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)", "polkadot-primitives 0.1.0", @@ -759,6 +830,26 @@ dependencies = [ "libc 0.2.33 (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.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.1.31" @@ -797,6 +888,18 @@ dependencies = [ "futures 0.1.17 (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.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (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" @@ -809,6 +912,17 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "runtime-support" +version = "0.1.0" +dependencies = [ + "environmental 0.1.0", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "polkadot-primitives 0.1.0", + "polkadot-state-machine 0.1.0", +] + [[package]] name = "rustc-demangle" version = "0.1.5" @@ -845,6 +959,11 @@ name = "scoped-tls" version = "0.1.0" source = "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.1.20" @@ -1063,6 +1182,14 @@ dependencies = [ "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.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "uint" version = "0.1.0" @@ -1099,6 +1226,11 @@ 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" @@ -1142,6 +1274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum arrayvec 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e003cbf6e0e1c43a0fc8df2ea8ea24174514d35cbcf60c35ca6112e0139f65e2" +"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum assert_matches 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e772942dccdf11b368c31e044e4fca9189f80a773d2f0808379de65894cbf57" "checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860" "checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" @@ -1150,15 +1283,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5442186ef6560f30f1ee4b9c1e4c87a35a6879d3644550cc248ec2b955eb5fcd" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" +"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b8c532887f1a292d17de05ae858a8fe50a301e196f9ef0ddb7ccd0d1d00f180" +"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 dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" +"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 error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" @@ -1171,6 +1308,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" "checksum futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "118b49cac82e04121117cbd3121ede3147e885627d82c4546b87c702debb90c1" "checksum futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e86f49cc0d92fe1b97a5980ec32d56208272cbb00f15044ea9e2799dde766fdf" +"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90d069fe6beb9be359ef505650b3f73228c5591a3c4b1f32be2f4f44459ffa3a" "checksum hashdb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d97be07c358c5b461268b4ce60304024c5fa5acfd4bd8cd743639f0252003cf5" "checksum heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "54fab2624374e5137ae4df13bf32b0b269cb804df42d13a51221bbd431d1a237" @@ -1188,6 +1326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9e5e58fa1a4c3b915a561a78a22ee0cac6ab97dca2504428bc1cb074375f8d5" +"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" "checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" @@ -1204,6 +1343,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parity-wasm 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "235801e9531998c4bb307f4ea6833c9f40a4cf132895219ac8c2cd25a9b310f7" "checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" +"checksum parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e7f7c9857874e54afeb950eebeae662b1e51a2493666d2ea4c0a5d91dcf0412" "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595" "checksum patricia-trie 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1e2f638d79aba5c4a71a4f373df6e3cd702250a53b7f0ed4da1e2a7be9737ae" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" @@ -1211,11 +1351,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pretty_assertions 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94b6bbc8a323d89a019c4cdde21850522fb8405e97add70827177fc2f86c1495" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" +"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.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5" +"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-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e" @@ -1223,6 +1366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9743a7670d88d5d52950408ecdb7c71d8986251ab604d4689dd2ca25c9bca69" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" +"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" "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" @@ -1250,11 +1394,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" "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.0 (git+https://github.com/paritytech/primitives.git)" = "" "checksum unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e01da42520092d0cd2d6ac3ae69eb21a22ad43ff195676b86f8c37f487d6b80" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "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 vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index a0f6303a67..21232d39ef 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -12,14 +12,16 @@ members = [ "candidate-agreement", "client", "collator", + "environmental", "executor", "primitives", "rpc", "rpc_servers", + "native-runtime", "serializer", "state_machine", "validator", ] exclude = [ - "runtime" + "wasm-runtime" ] diff --git a/substrate/environmental/Cargo.toml b/substrate/environmental/Cargo.toml new file mode 100644 index 0000000000..52c3337f8a --- /dev/null +++ b/substrate/environmental/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "environmental" +version = "0.1.0" +authors = ["Parity Technologies "] diff --git a/substrate/environmental/src/lib.rs b/substrate/environmental/src/lib.rs new file mode 100644 index 0000000000..ef5b5967be --- /dev/null +++ b/substrate/environmental/src/lib.rs @@ -0,0 +1,272 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Safe global references to stack variables. +//! +//! Set up a global reference with environmental! macro giving it a name and type. +//! Use the `using` function scoped under its name to name a reference and call a function that +//! takes no parameters yet can access said reference through the similarly placed `with` function. +//! +//! # Examples +//! +//! ``` +//! #[macro_use] extern crate environmental; +//! // create a place for the global reference to exist. +//! environmental!(counter: u32); +//! fn stuff() { +//! // do some stuff, accessing the named reference as desired. +//! counter::with(|i| *i += 1); +//! } +//! fn main() { +//! // declare a stack variable of the same type as our global declaration. +//! let mut counter_value = 41u32; +//! // call stuff, setting up our `counter` environment as a refrence to our counter_value var. +//! counter::using(&mut counter_value, stuff); +//! println!("The answer is {:?}", counter_value); // will print 42! +//! stuff(); // safe! doesn't do anything. +//! } +//! ``` + +use std::cell::RefCell; +use std::thread::LocalKey; + +#[doc(hidden)] +pub fn using R>( + global: &'static LocalKey>>, + protected: &mut T, + f: F +) -> R { + // store the `protected` reference as a pointer so we can provide it to logic running within + // `f`. + // while we record this pointer (while it's non-zero) we guarantee: + // - it will only be used once at any time (no reentrancy); + // - that no other thread will use it; and + // - that we do not use the original mutating reference while the pointer. + // exists. + global.with(|r| { + let original = { + let mut global = r.borrow_mut(); + ::std::mem::replace(&mut *global, Some(protected as _)) + }; + + // even if `f` panics the original will be replaced. + struct ReplaceOriginal<'a, T: 'a + ?Sized> { + original: Option<*mut T>, + global: &'a RefCell>, + } + + impl<'a, T: 'a + ?Sized> Drop for ReplaceOriginal<'a, T> { + fn drop(&mut self) { + *self.global.borrow_mut() = self.original.take(); + } + } + + let _guard = ReplaceOriginal { + original, + global: r, + }; + + f() + }) +} + +#[doc(hidden)] +pub fn with R>( + global: &'static LocalKey>>, + mutator: F, +) -> Option { + global.with(|r| unsafe { + let ptr = r.borrow_mut(); + match *ptr { + Some(ptr) => { + // safe because it's only non-zero when it's being called from using, which + // is holding on to the underlying reference (and not using it itself) safely. + Some(mutator(&mut *ptr)) + } + None => None, + } + }) +} + +/// Declare a new global reference module whose underlying value does not contain references. +/// +/// Will create a module of a given name that contains two functions: +/// * `pub fn using R>(protected: &mut $t, f: F) -> R` +/// This executes `f`, returning its value. During the call, the module's reference is set to +/// be equal to `protected`. +/// * `pub fn with R>(f: F) -> Option` +/// This executes `f`, returning `Some` of its value if called from code that is being executed +/// as part of a `using` call. If not, it returns `None`. `f` is provided with one argument: the +/// same reference as provided to the most recent `using` call. +/// +/// # Examples +/// +/// Initializing the global context with a given value. +/// +/// ```rust +/// #[macro_use] extern crate environmental; +/// environmental!(counter: u32); +/// fn main() { +/// let mut counter_value = 41u32; +/// counter::using(&mut counter_value, || { +/// let odd = counter::with(|value| +/// if *value % 2 == 1 { +/// *value += 1; true +/// } else { +/// *value -= 3; false +/// }).unwrap(); // safe because we're inside a counter::using +/// println!("counter was {}", match odd { true => "odd", _ => "even" }); +/// }); +/// +/// println!("The answer is {:?}", counter_value); // 42 +/// } +/// ``` +/// +/// Roughly the same, but with a trait object: +/// +/// ```rust +/// #[macro_use] extern crate environmental; +/// +/// trait Increment { fn increment(&mut self); } +/// +/// impl Increment for i32 { +/// fn increment(&mut self) { *self += 1 } +/// } +/// +/// environmental!(val: Increment + 'static); +/// +/// fn main() { +/// let mut local = 0i32; +/// val::using(&mut local, || { +/// val::with(|v| for _ in 0..5 { v.increment() }); +/// }); +/// +/// assert_eq!(local, 5); +/// } +/// ``` +#[macro_export] +macro_rules! environmental { + ($name:ident : $t:ty) => { + #[allow(non_camel_case_types)] + struct $name { __private_field: () } + + thread_local!(static GLOBAL: ::std::cell::RefCell> + = ::std::cell::RefCell::new(None)); + + impl $name { + #[allow(unused_imports)] + + pub fn using R>( + protected: &mut $t, + f: F + ) -> R { + $crate::using(&GLOBAL, protected, f) + } + + pub fn with R>( + f: F + ) -> Option { + $crate::with(&GLOBAL, |x| f(x)) + } + } + }; +} + +#[cfg(test)] +mod tests { + + #[test] + fn simple_works() { + environmental!(counter: u32); + + fn stuff() { counter::with(|value| *value += 1); }; + + // declare a stack variable of the same type as our global declaration. + let mut local = 41u32; + + // call stuff, setting up our `counter` environment as a refrence to our local counter var. + counter::using(&mut local, stuff); + assert_eq!(local, 42); + stuff(); // safe! doesn't do anything. + } + + #[test] + fn overwrite_with_lesser_lifetime() { + environmental!(items: Vec); + + let mut local_items = vec![1, 2, 3]; + items::using(&mut local_items, || { + let dies_at_end = vec![4, 5, 6]; + items::with(|items| *items = dies_at_end); + }); + + assert_eq!(local_items, vec![4, 5, 6]); + } + + #[test] + fn declare_with_trait_object() { + trait Foo { + fn get(&self) -> i32; + fn set(&mut self, x: i32); + } + + impl Foo for i32 { + fn get(&self) -> i32 { *self } + fn set(&mut self, x: i32) { *self = x } + } + + environmental!(foo: Foo + 'static); + + fn stuff() { + foo::with(|value| { + let new_val = value.get() + 1; + value.set(new_val); + }); + } + + let mut local = 41i32; + foo::using(&mut local, stuff); + + assert_eq!(local, 42); + + stuff(); // doesn't do anything. + } + + #[test] + fn unwind_recursive() { + use std::panic; + + environmental!(items: Vec); + + let panicked = panic::catch_unwind(|| { + let mut local_outer = vec![1, 2, 3]; + + items::using(&mut local_outer, || { + let mut local_inner = vec![4, 5, 6]; + items::using(&mut local_inner, || { + panic!("are you unsafe?"); + }) + }); + }).is_err(); + + assert!(panicked); + + let mut was_cleared = true; + items::with(|_items| was_cleared = false); + + assert!(was_cleared); + } +} diff --git a/substrate/executor/Cargo.toml b/substrate/executor/Cargo.toml index 8aa72f4327..0401bd4c77 100644 --- a/substrate/executor/Cargo.toml +++ b/substrate/executor/Cargo.toml @@ -12,6 +12,7 @@ serde = "1.0" serde_derive = "1.0" parity-wasm = "0.15.0" byteorder = "1.1" +rustc-hex = "1.0.0" [dev-dependencies] assert_matches = "1.1" diff --git a/substrate/executor/src/lib.rs b/substrate/executor/src/lib.rs index 8bf7f42b62..f1da582538 100644 --- a/substrate/executor/src/lib.rs +++ b/substrate/executor/src/lib.rs @@ -33,6 +33,7 @@ extern crate polkadot_state_machine as state_machine; extern crate serde; extern crate parity_wasm; extern crate byteorder; +extern crate rustc_hex; #[macro_use] extern crate error_chain; diff --git a/substrate/executor/src/wasm_executor.rs b/substrate/executor/src/wasm_executor.rs index f52b2cbf71..7fc9a741f8 100644 --- a/substrate/executor/src/wasm_executor.rs +++ b/substrate/executor/src/wasm_executor.rs @@ -26,6 +26,7 @@ use state_machine::{Externalities, CodeExecutor}; use error::{Error, ErrorKind, Result}; use wasm_utils::{MemoryInstance, UserDefinedElements, AddModuleWithoutFullDependentInstance}; +use primitives::{ed25519, blake2_256, twox_128, twox_256}; struct Heap { end: u32, @@ -76,7 +77,7 @@ impl WritePrimitive for MemoryInstance { } impl_function_executor!(this: FunctionExecutor<'e, E>, - ext_print(utf8_data: *const u8, utf8_len: i32) => { + ext_print(utf8_data: *const u8, utf8_len: u32) => { if let Ok(utf8) = this.memory.get(utf8_data, utf8_len as usize) { if let Ok(message) = String::from_utf8(utf8) { println!("Runtime: {}", message); @@ -96,7 +97,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, println!("memmove {} from {}, {} bytes", dest, src, count); dest }, - ext_memset(dest: *mut u8, val: i32, count: usize) -> *mut u8 => { + ext_memset(dest: *mut u8, val: u32, count: usize) -> *mut u8 => { let _ = this.memory.clear(dest as usize, val as u8, count as usize); println!("memset {} with {}, {} bytes", dest, val, count); dest @@ -110,12 +111,12 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, this.heap.deallocate(addr); println!("free {}", addr) }, - ext_set_storage(key_data: *const u8, key_len: i32, value_data: *const u8, value_len: i32) => { + ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32) => { if let (Ok(key), Ok(value)) = (this.memory.get(key_data, key_len as usize), this.memory.get(value_data, value_len as usize)) { this.ext.set_storage(key, value); } }, - ext_get_allocated_storage(key_data: *const u8, key_len: i32, written_out: *mut i32) -> *mut u8 => { + ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8 => { let (offset, written) = if let Ok(key) = this.memory.get(key_data, key_len as usize) { if let Ok(value) = this.ext.storage(&key) { let offset = this.heap.allocate(value.len() as u32) as u32; @@ -126,6 +127,63 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, this.memory.write_primitive(written_out, written); offset as u32 + }, + ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32) -> u32 => { + if let Ok(key) = this.memory.get(key_data, key_len as usize) { + if let Ok(value) = this.ext.storage(&key) { + let written = ::std::cmp::min(value_len as usize, value.len()); + let _ = this.memory.set(value_data, &value[0..written]); + written as u32 + } else { 0 } + } else { 0 } + }, + ext_chain_id() -> u64 => { + this.ext.chain_id() + }, + ext_twox_128(data: *const u8, len: u32, out: *mut u8) => { + let result = + if let Ok(value) = this.memory.get(data, len as usize) { + twox_128(&value) + } else { + [0; 16] + }; + let _ = this.memory.set(out, &result); + }, + ext_twox_256(data: *const u8, len: u32, out: *mut u8) => { + let result = + if let Ok(value) = this.memory.get(data, len as usize) { + twox_256(&value) + } else { + [0; 32] + }; + let _ = this.memory.set(out, &result); + }, + ext_blake2_256(data: *const u8, len: u32, out: *mut u8) => { + let result = + if let Ok(value) = this.memory.get(data, len as usize) { + blake2_256(&value) + } else { + [0; 32] + }; + let _ = this.memory.set(out, &result); + }, + ext_ed25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32 => { + (||{ + let mut sig = [0u8; 64]; + if let Err(_) = this.memory.get_into(sig_data, &mut sig[..]) { + return 0; + }; + let mut pubkey = [0u8; 32]; + if let Err(_) = this.memory.get_into(pubkey_data, &mut pubkey[..]) { + return 0; + }; + + if let Ok(msg) = this.memory.get(msg_data, msg_len as usize) { + if ed25519::Signature::from(sig).verify(&msg, &ed25519::Public::from(pubkey)) { 1 } else { 0 } + } else { + 0 + } + })() } => <'e, E: Externalities + 'e> ); @@ -181,6 +239,7 @@ impl CodeExecutor for WasmExecutor { mod tests { use super::*; + use rustc_hex::FromHex; #[derive(Debug, Default)] struct TestExternalities { @@ -196,53 +255,82 @@ mod tests { fn set_storage(&mut self, key: Vec, value: Vec) { self.storage.insert(key, value); } + + fn chain_id(&self) -> u64 { 42 } } #[test] - fn should_pass_externalities_at_call() { + fn storage_should_work() { let mut ext = TestExternalities::default(); - ext.set_storage(b"\0code".to_vec(), b"The code".to_vec()); + ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); + let test_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); - let program = ProgramInstance::new().unwrap(); - - let test_module = include_bytes!("../../runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); - let module = deserialize_buffer(test_module.to_vec()).expect("Failed to load module"); - let module = program.add_module_by_sigs("test", module, map!["env" => FunctionExecutor::::SIGNATURES]).expect("Failed to initialize module"); - - let output = { - let memory = module.memory(ItemIndex::Internal(0)).unwrap(); - let mut fec = FunctionExecutor::new(&memory, &mut ext); - - let data = b"Hello world"; - let size = data.len() as u32; - let offset = fec.heap.allocate(size); - memory.set(offset, data).unwrap(); - - let returned = program - .params_with_external("env", &mut fec) - .map(|p| p - .add_argument(I32(offset as i32)) - .add_argument(I32(size as i32))) - .and_then(|p| module.execute_export("test_data_in", p)) - .map_err(|_| -> Error { ErrorKind::Runtime.into() }).expect("function should be callable"); - - if let Some(I64(r)) = returned { - println!("returned {:?} ({:?}, {:?})", r, r as u32, (r >> 32) as u32 as usize); - memory.get(r as u32, (r >> 32) as u32 as usize).expect("memory address should be reasonable.") - } else { - panic!("bad return value, not u64"); - } - }; + let output = WasmExecutor.call(&mut ext, &test_code[..], "test_data_in", &CallData(b"Hello world".to_vec())).unwrap(); assert_eq!(output, b"all ok!".to_vec()); let expected: HashMap<_, _> = map![ - b"\0code".to_vec() => b"Hello world".to_vec(), b"input".to_vec() => b"Hello world".to_vec(), - b"code".to_vec() => b"The code".to_vec(), - b"\0validator_count".to_vec() => vec![1], - b"\0validator".to_vec() => b"Hello world".to_vec() + b"foo".to_vec() => b"bar".to_vec(), + b"baz".to_vec() => b"bar".to_vec() ]; assert_eq!(expected, ext.storage); } + + #[test] + fn blake2_256_should_work() { + let mut ext = TestExternalities::default(); + let test_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + assert_eq!( + WasmExecutor.call(&mut ext, &test_code[..], "test_blake2_256", &CallData(b"".to_vec())).unwrap(), + FromHex::from_hex("0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8").unwrap() + ); + assert_eq!( + WasmExecutor.call(&mut ext, &test_code[..], "test_blake2_256", &CallData(b"Hello world!".to_vec())).unwrap(), + FromHex::from_hex("3fbc092db9350757e2ab4f7ee9792bfcd2f5220ada5a4bc684487f60c6034369").unwrap() + ); + } + + #[test] + fn twox_256_should_work() { + let mut ext = TestExternalities::default(); + let test_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + assert_eq!( + WasmExecutor.call(&mut ext, &test_code[..], "test_twox_256", &CallData(b"".to_vec())).unwrap(), + FromHex::from_hex("99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a").unwrap() + ); + assert_eq!( + WasmExecutor.call(&mut ext, &test_code[..], "test_twox_256", &CallData(b"Hello world!".to_vec())).unwrap(), + FromHex::from_hex("b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74").unwrap() + ); + } + + #[test] + fn twox_128_should_work() { + let mut ext = TestExternalities::default(); + let test_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + assert_eq!( + WasmExecutor.call(&mut ext, &test_code[..], "test_twox_128", &CallData(b"".to_vec())).unwrap(), + FromHex::from_hex("99e9d85137db46ef4bbea33613baafd5").unwrap() + ); + assert_eq!( + WasmExecutor.call(&mut ext, &test_code[..], "test_twox_128", &CallData(b"Hello world!".to_vec())).unwrap(), + FromHex::from_hex("b27dfd7f223f177f2a13647b533599af").unwrap() + ); + } + + #[test] + fn ed25519_verify_should_work() { + let mut ext = TestExternalities::default(); + let test_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let key = ed25519::Pair::from_seed(&blake2_256(b"test")); + let sig = key.sign(b"all ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(sig.as_ref()); + assert_eq!( + WasmExecutor.call(&mut ext, &test_code[..], "test_ed25519_verify", &CallData(calldata)).unwrap(), + vec![1] + ); + } } diff --git a/substrate/executor/src/wasm_utils.rs b/substrate/executor/src/wasm_utils.rs index 577e6ab0b2..f6440628b9 100644 --- a/substrate/executor/src/wasm_utils.rs +++ b/substrate/executor/src/wasm_utils.rs @@ -75,13 +75,13 @@ macro_rules! reverse_params { #[macro_export] macro_rules! marshall { - ( $context:ident, $self:ident, ( $( $names:ident : $params:ty ),* ) -> $returns:ty => $body:tt ) => ({ - let r : <$returns as $crate::wasm_utils::ConvertibleToWasm>::NativeType = reverse_params!($body, $self, $context, $( $names : $params ),*); - Ok(Some({ use $crate::wasm_utils::ConvertibleToWasm; r.to_runtime_value() })) - }); ( $context:ident, $self:ident, ( $( $names:ident : $params:ty ),* ) => $body:tt ) => ({ reverse_params!($body, $self, $context, $( $names : $params ),*); Ok(None) + }); + ( $context:ident, $self:ident, ( $( $names:ident : $params:ty ),* ) -> $returns:ty => $body:tt ) => ({ + let r : <$returns as $crate::wasm_utils::ConvertibleToWasm>::NativeType = reverse_params!($body, $self, $context, $( $names : $params ),*); + Ok(Some({ use $crate::wasm_utils::ConvertibleToWasm; r.to_runtime_value() })) }) } @@ -119,13 +119,13 @@ pub trait IntoUserDefinedElements { #[macro_export] macro_rules! impl_function_executor { ( $objectname:ident : $structname:ty, $( $name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt ),* => $($pre:tt)+ ) => ( - impl $( $pre ) + $crate::wasm_utils::UserFunctionExecutor<$crate::wasm_utils::DummyUserError> for $structname { + impl $($pre)+ $crate::wasm_utils::UserFunctionExecutor<$crate::wasm_utils::DummyUserError> for $structname { dispatch!($objectname, $( $name( $( $names : $params ),* ) $( -> $returns )* => $body ),*); } - impl $( $pre ) + $structname { + impl $($pre)+ $structname { signatures!($( $name( $( $params ),* ) $( -> $returns )* ),*); } - impl $( $pre ) + $crate::wasm_utils::IntoUserDefinedElements for $structname { + impl $($pre)+ $crate::wasm_utils::IntoUserDefinedElements for $structname { fn into_user_defined_elements(&mut self) -> UserDefinedElements<$crate::wasm_utils::DummyUserError> { $crate::wasm_utils::UserDefinedElements { executor: Some(self), diff --git a/substrate/native-runtime/Cargo.toml b/substrate/native-runtime/Cargo.toml new file mode 100644 index 0000000000..eb5eb82408 --- /dev/null +++ b/substrate/native-runtime/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "native-runtime" +version = "0.1.0" +authors = ["Parity Technologies "] + +[features] +default = ["with-std"] +with-std = [] +without-std = [] + +[dependencies] +runtime-support = { path = "./support", version = "0.1" } +rustc-hex = "1.0" diff --git a/substrate/native-runtime/src b/substrate/native-runtime/src new file mode 120000 index 0000000000..12e3333860 --- /dev/null +++ b/substrate/native-runtime/src @@ -0,0 +1 @@ +../wasm-runtime/polkadot/src \ No newline at end of file diff --git a/substrate/native-runtime/support/Cargo.toml b/substrate/native-runtime/support/Cargo.toml new file mode 100644 index 0000000000..1c24c014e6 --- /dev/null +++ b/substrate/native-runtime/support/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "runtime-support" +version = "0.1.0" +authors = ["Parity Technologies "] + +[features] +strict = [] + +[dependencies] +lazy_static = "1.0.0" +parking_lot = "0.5" +polkadot-state-machine = { path = "../../state_machine" , version = "0.1" } +environmental = { path = "../../environmental", version = "0.1.0" } +polkadot-primitives = { path = "../../primitives", version = "0.1.0" } diff --git a/substrate/native-runtime/support/src/lib.rs b/substrate/native-runtime/support/src/lib.rs new file mode 100644 index 0000000000..348c0b17a9 --- /dev/null +++ b/substrate/native-runtime/support/src/lib.rs @@ -0,0 +1,149 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! The with-std support functions for the runtime. + +#[macro_use] +extern crate environmental; +extern crate polkadot_state_machine; +extern crate polkadot_primitives as primitives; + +use std::fmt; +use primitives::ed25519; + +pub use std::vec::Vec; +pub use std::rc::Rc; +pub use std::cell::RefCell; +pub use std::boxed::Box; +pub use std::slice; +pub use std::mem::{size_of, transmute, swap, uninitialized}; + +pub use polkadot_state_machine::Externalities; + +// TODO: use the real error, not NoError. + +#[derive(Debug)] +/// As it says - an empty type we use for errors. +pub struct NoError; +impl fmt::Display for NoError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "") } +} + +environmental!(ext : Externalities + 'static); + +/// Get `key` from storage and return a `Vec`, empty if there's a problem. +pub fn storage(key: &[u8]) -> Vec { + ext::with(|ext| ext.storage(key).ok().map(|s| s.to_vec())) + .unwrap_or(None) + .unwrap_or_else(|| vec![]) +} + +/// Get `key` from storage, placing the value into `value_out` (as much as possible) and return +/// the number of bytes that the key in storage was. +pub fn read_storage(key: &[u8], value_out: &mut [u8]) -> usize { + ext::with(|ext| { + if let Ok(value) = ext.storage(key) { + let written = ::std::cmp::min(value.len(), value_out.len()); + value_out[0..written].copy_from_slice(&value[0..written]); + value.len() + } else { + 0 + } + }).unwrap_or(0) +} + +pub fn set_storage(key: &[u8], value: &[u8]) { + ext::with(|ext| + ext.set_storage(key.to_vec(), value.to_vec()) + ); +} + +/// The current relay chain identifier. +pub fn chain_id() -> u64 { + ext::with(|ext| + ext.chain_id() + ).unwrap_or(0) +} + +/// Conduct a Keccak-256 hash of the given data. +pub use primitives::{blake2_256, twox_128, twox_256}; + +/// Verify a ed25519 signature. +pub fn ed25519_verify(sig: &[u8; 64], msg: &[u8], pubkey: &[u8; 32]) -> bool { + ed25519::verify(&sig[..], msg, &pubkey[..]) +} + +/// Execute the given closure with global function available whose functionality routes into the +/// externalities `ext`. Forwards the value that the closure returns. +pub fn with_externalities R>(ext: &mut (Externalities + 'static), f: F) -> R { + ext::using(ext, f) +} + +#[macro_export] +macro_rules! impl_stubs { + ($( $name:ident ),*) => {} +} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashMap; + + #[derive(Debug, Default)] + struct TestExternalities { + storage: HashMap, Vec>, + } + impl Externalities for TestExternalities { + type Error = NoError; + + fn storage(&self, key: &[u8]) -> Result<&[u8], NoError> { + Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice)) + } + + fn set_storage(&mut self, key: Vec, value: Vec) { + self.storage.insert(key, value); + } + + fn chain_id(&self) -> u64 { 42 } + } + + macro_rules! map { + ($( $name:expr => $value:expr ),*) => ( + vec![ $( ( $name, $value ) ),* ].into_iter().collect() + ) + } + + #[test] + fn storage_works() { + let mut t = TestExternalities { storage: map![], }; + assert!(with_externalities(&mut t, || { + assert_eq!(storage(b"hello"), b"".to_vec()); + set_storage(b"hello", b"world"); + assert_eq!(storage(b"hello"), b"world".to_vec()); + assert_eq!(storage(b"foo"), b"".to_vec()); + set_storage(b"foo", &[1, 2, 3][..]); + true + })); + + t.storage = map![b"foo".to_vec() => b"bar".to_vec()]; + + assert!(!with_externalities(&mut t, || { + assert_eq!(storage(b"hello"), b"".to_vec()); + assert_eq!(storage(b"foo"), b"bar".to_vec()); + false + })); + } +} diff --git a/substrate/primitives/Cargo.toml b/substrate/primitives/Cargo.toml index f31afccf5b..77eccdea88 100644 --- a/substrate/primitives/Cargo.toml +++ b/substrate/primitives/Cargo.toml @@ -9,8 +9,12 @@ fixed-hash = { git = "https://github.com/paritytech/primitives.git" } rustc-hex = "1.0" serde = "1.0" serde_derive = "1.0" -tiny-keccak = "1.3" uint = { git = "https://github.com/paritytech/primitives.git" } +ring = "0.12" +untrusted = "0.5" +twox-hash = "1.1.0" +byteorder = "1.1" +blake2-rfc = "0.2.18" [dev-dependencies] polkadot-serializer = { path = "../serializer", version = "0.1" } diff --git a/substrate/primitives/src/block.rs b/substrate/primitives/src/block.rs index 740b0c4cda..8cd077fd78 100644 --- a/substrate/primitives/src/block.rs +++ b/substrate/primitives/src/block.rs @@ -97,7 +97,7 @@ mod tests { "candidates": [ { "parachainIndex": 10, - "collatorSignature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "collatorSignature": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "unprocessedIngress": [], "block": "0x01030508" } diff --git a/substrate/primitives/src/ed25519.rs b/substrate/primitives/src/ed25519.rs new file mode 100644 index 0000000000..b28e0bde6e --- /dev/null +++ b/substrate/primitives/src/ed25519.rs @@ -0,0 +1,235 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Simple Ed25519 API. + +use untrusted; +use ring::{rand, signature}; +use rustc_hex::FromHex; + +/// 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); + let msg = untrusted::Input::from(message); + let sig = untrusted::Input::from(sig); + + match signature::verify(&signature::ED25519, public_key, msg, sig) { + Ok(_) => true, + _ => false, + } +} + +/// A public key. +#[derive(PartialEq, Clone, Debug)] +pub struct Public ([u8; 32]); + +/// A key pair. +pub struct Pair(signature::Ed25519KeyPair); + +/// A signature. +#[derive(Clone)] +pub struct Signature ([u8; 64]); + +impl Signature { + /// A new signature from the given 64-byte `data`. + pub fn from(data: [u8; 64]) -> Self { + Signature(data) + } + + /// A new signature from the given slice that should be 64 bytes long. + pub fn from_slice(data: &[u8]) -> Self { + let mut r = [0u8; 64]; + r.copy_from_slice(data); + Signature(r) + } +} + +impl AsRef<[u8; 64]> for Signature { + fn as_ref(&self) -> &[u8; 64] { + &self.0 + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl Public { + /// A new instance from the given 32-byte `data`. + pub fn from(data: [u8; 32]) -> Self { + Public(data) + } + + /// A new instance from the given slice that should be 32 bytes long. + pub fn from_slice(data: &[u8]) -> Self { + let mut r = [0u8; 32]; + r.copy_from_slice(data); + Public(r) + } +} + +impl AsRef<[u8; 32]> for Public { + fn as_ref(&self) -> &[u8; 32] { + &self.0 + } +} + +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl Pair { + /// Generate new secure (random) key pair. + pub fn new() -> Pair { + let rng = rand::SystemRandom::new(); + let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap(); + Pair(signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).unwrap()) + } + /// Make a new key pair from a seed phrase. + pub fn from_seed(seed: &[u8; 32]) -> Pair { + Pair(signature::Ed25519KeyPair::from_seed_unchecked(untrusted::Input::from(&seed[..])).unwrap()) + } + /// Make a new key pair from the raw secret. + pub fn from_secret(secret: &[u8; 32]) -> Pair { + let mut pkcs8_bytes = FromHex::from_hex("302e020100300506032b657004220420").unwrap(); + pkcs8_bytes.extend_from_slice(&secret[..]); + Pair(signature::Ed25519KeyPair::from_pkcs8_maybe_unchecked(untrusted::Input::from(&pkcs8_bytes)).unwrap()) + } + /// Make a new key pair from the raw secret and public key (it will check to make sure + /// they correspond to each other). + pub fn from_both(secret_public: &[u8; 64]) -> Option { + let mut pkcs8_bytes = FromHex::from_hex("3053020101300506032b657004220420").unwrap(); + pkcs8_bytes.extend_from_slice(&secret_public[0..32]); + pkcs8_bytes.extend_from_slice(&[0xa1u8, 0x23, 0x03, 0x21, 0x00]); + pkcs8_bytes.extend_from_slice(&secret_public[32..64]); + signature::Ed25519KeyPair::from_pkcs8_maybe_unchecked(untrusted::Input::from(&pkcs8_bytes)).ok().map(Pair) + } + /// Sign a message. + pub fn sign(&self, message: &[u8]) -> Signature { + let mut r = [0u8; 64]; + r.copy_from_slice(self.0.sign(message).as_ref()); + Signature(r) + } + /// Get the public key. + pub fn public(&self) -> Public { + let mut r = [0u8; 32]; + let pk = self.0.public_key_bytes(); + r.copy_from_slice(pk); + Public(r) + } +} +impl Signature { + /// Verify a message. + pub fn verify(&self, message: &[u8], public: &Public) -> bool { + let peer_public_key = untrusted::Input::from(&public.0[..]); + let msg = untrusted::Input::from(message); + let sig = untrusted::Input::from(&self.0[..]); + + match signature::verify(&signature::ED25519, peer_public_key, msg, sig) { + Ok(_) => true, + _ => false, + } + } +} +impl From<&'static str> for Public { + fn from(hex: &'static str) -> Self { + let mut r = [0u8; 32]; + r.copy_from_slice(&FromHex::from_hex(hex).unwrap()[0..32]); + Public(r) + } +} +impl From<&'static str> for Pair { + fn from(hex: &'static str) -> Self { + let data = FromHex::from_hex(hex).expect("Key pair given is static so hex should be good."); + match data.len() { + 32 => { + let mut r = [0u8; 32]; + r.copy_from_slice(&data[0..32]); + Pair::from_secret(&r) + } + 64 => { + let mut r = [0u8; 64]; + r.copy_from_slice(&data[0..64]); + Pair::from_both(&r).expect("Key pair given is static so should be good.") + } + _ => { + panic!("Key pair given is static so should be correct length."); + } + } + } +} +impl From<&'static str> for Signature { + fn from(hex: &'static str) -> Self { + let mut r = [0u8; 64]; + r.copy_from_slice(&FromHex::from_hex(hex).unwrap()[0..64]); + Signature(r) + } +} + +impl PartialEq for Signature { + fn eq(&self, other: &Signature) -> bool { + self.0.iter().eq(other.0.iter()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_vector_should_work() { + let pair: Pair = "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60".into(); + let public = pair.public(); + assert_eq!(public, "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a".into()); + let message = b""; + let signature: Signature = "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b".into(); + assert!(&pair.sign(&message[..]) == &signature); + assert!(signature.verify(&message[..], &public)); + } + + #[test] + fn generated_pair_should_work() { + let pair = Pair::new(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(signature.verify(&message[..], &public)); + } + + #[test] + fn seeded_pair_should_work() { + let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let public = pair.public(); + assert_eq!(public, "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee".into()); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(signature.verify(&message[..], &public)); + } + + #[test] + fn can_sign_transaction() { + let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let public = pair.public(); + assert_eq!(public, "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee".into()); + let message = FromHex::from_hex("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000").unwrap(); + let signature = pair.sign(&message[..]); + assert!(signature.verify(&message[..], &public)); + } +} diff --git a/substrate/primitives/src/hash.rs b/substrate/primitives/src/hash.rs index cef573f6f2..0b56d5757f 100644 --- a/substrate/primitives/src/hash.rs +++ b/substrate/primitives/src/hash.rs @@ -41,8 +41,8 @@ impl_hash!(H160, 20); impl_serde!(H160, 20); impl_hash!(H256, 32); impl_serde!(H256, 32); -impl_hash!(H520, 65); -impl_serde!(H520, 65); +impl_hash!(H512, 64); +impl_serde!(H512, 64); #[cfg(test)] mod tests { diff --git a/substrate/primitives/src/hashing.rs b/substrate/primitives/src/hashing.rs new file mode 100644 index 0000000000..f82ec7ef8b --- /dev/null +++ b/substrate/primitives/src/hashing.rs @@ -0,0 +1,106 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Hashing functions. + +use blake2_rfc; +use twox_hash; + +/// Do a Blake2 512-bit hash and place result in `dest`. +pub fn blake2_512_into(data: &[u8], dest: &mut[u8; 64]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(64, &[], data).as_bytes()); +} + +/// Do a Blake2 512-bit hash and return result. +pub fn blake2_512(data: &[u8]) -> [u8; 64] { + let mut r: [u8; 64] = unsafe { ::std::mem::uninitialized() }; + blake2_512_into(data, &mut r); + r +} + +/// Do a Blake2 256-bit hash and place result in `dest`. +pub fn blake2_256_into(data: &[u8], dest: &mut[u8; 32]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); +} + +/// Do a Blake2 256-bit hash and return result. +pub fn blake2_256(data: &[u8]) -> [u8; 32] { + let mut r: [u8; 32] = unsafe { ::std::mem::uninitialized() }; + blake2_256_into(data, &mut r); + r +} + +/// Do a Blake2 128-bit hash and place result in `dest`. +pub fn blake2_128_into(data: &[u8], dest: &mut[u8; 16]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], data).as_bytes()); +} + +/// Do a Blake2 128-bit hash and return result. +pub fn blake2_128(data: &[u8]) -> [u8; 16] { + let mut r: [u8; 16] = unsafe { ::std::mem::uninitialized() }; + blake2_128_into(data, &mut r); + r +} + +/// Do a XX 128-bit hash and place result in `dest`. +pub fn twox_128_into(data: &[u8], dest: &mut [u8; 16]) { + use ::std::hash::Hasher; + let mut h0 = twox_hash::XxHash::with_seed(0); + let mut h1 = twox_hash::XxHash::with_seed(1); + h0.write(data); + h1.write(data); + let r0 = h0.finish(); + let r1 = h1.finish(); + use byteorder::{ByteOrder, LittleEndian}; + LittleEndian::write_u64(&mut dest[0..8], r0); + LittleEndian::write_u64(&mut dest[8..16], r1); +} + +/// Do a XX 128-bit hash and return result. +pub fn twox_128(data: &[u8]) -> [u8; 16] { + let mut r: [u8; 16] = unsafe { ::std::mem::uninitialized() }; + twox_128_into(data, &mut r); + r +} + +/// Do a XX 256-bit hash and place result in `dest`. +pub fn twox_256_into(data: &[u8], dest: &mut [u8; 32]) { + use ::std::hash::Hasher; + use byteorder::{ByteOrder, LittleEndian}; + let mut h0 = twox_hash::XxHash::with_seed(0); + let mut h1 = twox_hash::XxHash::with_seed(1); + let mut h2 = twox_hash::XxHash::with_seed(2); + let mut h3 = twox_hash::XxHash::with_seed(3); + h0.write(data); + h1.write(data); + h2.write(data); + h3.write(data); + let r0 = h0.finish(); + let r1 = h1.finish(); + let r2 = h2.finish(); + let r3 = h3.finish(); + LittleEndian::write_u64(&mut dest[0..8], r0); + LittleEndian::write_u64(&mut dest[8..16], r1); + LittleEndian::write_u64(&mut dest[16..24], r2); + LittleEndian::write_u64(&mut dest[24..32], r3); +} + +/// Do a XX 256-bit hash and return result. +pub fn twox_256(data: &[u8]) -> [u8; 32] { + let mut r: [u8; 32] = unsafe { ::std::mem::uninitialized() }; + twox_256_into(data, &mut r); + r +} diff --git a/substrate/primitives/src/hexdisplay.rs b/substrate/primitives/src/hexdisplay.rs new file mode 100644 index 0000000000..d6299a2e41 --- /dev/null +++ b/substrate/primitives/src/hexdisplay.rs @@ -0,0 +1,60 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Wrapper type for byte collections that outputs hex. + +/// Simple wrapper to display hex representation of bytes. +pub struct HexDisplay<'a>(&'a [u8]); + +impl<'a> HexDisplay<'a> { + /// Create new instance that will display `d` as a hex string when displayed. + pub fn from(d: &'a AsBytesRef) -> Self { HexDisplay(d.as_bytes_ref()) } +} + +impl<'a> ::std::fmt::Display for HexDisplay<'a> { + fn fmt(&self, fmtr: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + for byte in self.0 { + try!( fmtr.write_fmt(format_args!("{:02x}", byte))); + } + Ok(()) + } +} + +/// Simple trait to transferm various types to `&[u8]` +pub trait AsBytesRef { + /// Transferm `self` into `&[u8]`. + fn as_bytes_ref(&self) -> &[u8]; +} + +impl AsBytesRef for [u8] { + fn as_bytes_ref(&self) -> &[u8] { &self } +} + +impl AsBytesRef for Vec { + fn as_bytes_ref(&self) -> &[u8] { &self } +} + +macro_rules! impl_non_endians { + ( $( $t:ty ),* ) => { $( + impl AsBytesRef for $t { + fn as_bytes_ref(&self) -> &[u8] { &self[..] } + } + )* } +} + +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]); diff --git a/substrate/primitives/src/lib.rs b/substrate/primitives/src/lib.rs index ca32f302f3..c774ec7f42 100644 --- a/substrate/primitives/src/lib.rs +++ b/substrate/primitives/src/lib.rs @@ -20,7 +20,11 @@ extern crate rustc_hex; extern crate serde; -extern crate tiny_keccak; +extern crate ring; +extern crate untrusted; +extern crate twox_hash; +extern crate byteorder; +extern crate blake2_rfc; #[macro_use] extern crate crunchy; @@ -46,16 +50,20 @@ pub mod hash; pub mod parachain; pub mod uint; pub mod validator; +pub mod ed25519; +pub mod hexdisplay; +pub mod hashing; /// Alias to 160-bit hash when used in the context of an account address. pub type Address = hash::H160; /// Alias to 520-bit hash when used in the context of a signature. -pub type Signature = hash::H520; +pub type Signature = hash::H512; pub use self::hash::{H160, H256}; pub use self::uint::{U256, U512}; +pub use hashing::{blake2_256, twox_128, twox_256}; /// A hash function. pub fn hash(data: &[u8]) -> hash::H256 { - tiny_keccak::keccak256(data).into() + blake2_256(data).into() } diff --git a/substrate/primitives/src/parachain.rs b/substrate/primitives/src/parachain.rs index 1d64f3c824..ed44134ce2 100644 --- a/substrate/primitives/src/parachain.rs +++ b/substrate/primitives/src/parachain.rs @@ -118,7 +118,7 @@ mod tests { block: BlockData(vec![1, 2, 3]), }), r#"{ "parachainIndex": 5, - "collatorSignature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a", + "collatorSignature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a", "unprocessedIngress": [ [ 1, diff --git a/substrate/runtime/polkadot/src/lib.rs b/substrate/runtime/polkadot/src/lib.rs deleted file mode 100644 index ec3fabb89c..0000000000 --- a/substrate/runtime/polkadot/src/lib.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![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, code, set_code, storage, validators, set_validators, print}; - -impl_stub!(test_data_in); -fn test_data_in(input: Vec) -> Vec { - 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"validators" as &[u8]); - let mut v = validators(); - v.push(copy); - - print(b"set_validators" as &[u8]); - set_validators(&v.iter().map(Vec::as_slice).collect::>()); - - print(b"finished!" as &[u8]); - b"all ok!".to_vec() -} diff --git a/substrate/runtime/support/src/lib.rs b/substrate/runtime/support/src/lib.rs deleted file mode 100644 index 472497d284..0000000000 --- a/substrate/runtime/support/src/lib.rs +++ /dev/null @@ -1,125 +0,0 @@ -#![no_std] -#![feature(lang_items)] -#![cfg_attr(feature = "strict", deny(warnings))] - -#![feature(alloc)] - -extern crate alloc; -use alloc::vec::Vec; - -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: i32); - fn ext_print_num(value: u64); - fn ext_set_storage(key_data: *const u8, key_len: i32, value_data: *const u8, value_len: i32); - fn ext_get_allocated_storage(key_data: *const u8, key_len: i32, written_out: *mut i32) -> *mut u8; -} - -pub fn storage(key: &[u8]) -> Vec { - let mut length: i32 = 0; - unsafe { - let ptr = ext_get_allocated_storage(&key[0], key.len() as i32, &mut length); - Vec::from_raw_parts(ptr, length as usize, length as usize) - } -} - -pub fn set_storage(key: &[u8], value: &[u8]) { - unsafe { - ext_set_storage( - &key[0] as *const u8, key.len() as i32, - &value[0] as *const u8, value.len() as i32 - ); - } -} - -pub fn code() -> Vec { - storage(b"\0code") -} - -pub fn set_code(new: &[u8]) { - set_storage(b"\0code", new) -} - -fn value_vec(mut value: usize, initial: Vec) -> Vec { - let mut acc = initial; - while value > 0 { - acc.push(value as u8); - value /= 256; - } - acc -} - -pub fn set_validator(index: usize, validator: &[u8]) { - set_storage(&value_vec(index, b"\0validator".to_vec()), validator); -} - -pub fn validator(index: usize) -> Vec { - storage(&value_vec(index, b"\0validator".to_vec())) -} - -pub fn set_validator_count(count: usize) { - (count..validator_count()).for_each(|i| set_validator(i, &[])); - set_storage(b"\0validator_count", &value_vec(count, Vec::new())); -} - -pub fn validator_count() -> usize { - storage(b"\0validator_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize)) -} - -pub fn validators() -> Vec> { - (0..validator_count()).into_iter().map(validator).collect() -} - -pub fn set_validators(validators: &[&[u8]]) { - set_validator_count(validators.len()); - validators.iter().enumerate().for_each(|(v, i)| set_validator(v, i)); -} - -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 i32); - } - } -} - -impl Printable for u64 { - fn print(self) { - unsafe { ext_print_num(self); } - } -} - -pub fn print(value: T) { - value.print(); -} - -#[macro_export] -macro_rules! impl_stub { - ($name:ident) => { - pub mod _internal { - extern crate alloc; - - #[no_mangle] - pub fn $name(input_data: *mut u8, input_len: usize) -> u64 { - let input = unsafe { - ::alloc::vec::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) - } - } - } -} diff --git a/substrate/runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm b/substrate/runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm deleted file mode 100644 index 6ce8afb77ce2136b71e41d74bf115b4c8f918264..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3042 zcmcgu&2ke*5T2Qx{n5_MY6S+%fX(b;h)F?05@J%JQst(~xH#|zRM`d#B4NueS$5zM zltU`#yhM(<=A1|10dnM+LyoDO^7SmTb#N+`OQe!|x@Wql=j)#tv3yc=P$F*As%-1!iCL#+%!_yZg_!$Gx4+ z!}0!T`$bPkp3ixHFH8z`D(LM!J9yo!Xz_}JQGYlV5ie*ne+Y|HJ37iz5hp?_p|v~^ zB95f!q+i9!UT<%I^jZl!?j4RdcecmdoBg3kJEJ48PkS%=!_A}NH~ry`$ddOy7#)1K zEh+M!=F%Uej3=b4SglRJUXUKFC{fFGC%nL@ioGPeTSp+>-CAup>ElXUW#~?+YVDK| z#w#BB*hgOR@A2g_uau8V;nliR2D)-w#l{P-R}~Cn7awEPHqid7Bg+X1!giYc%euV^ zYRQzEx)ei4mN9wK;6;`DHi=bLvVh(R%(tl=l(Kfdy`su8_O2APOc_>(=|=q)rKO&# zveiZlr(>-uqq~%!F8EVWIbGqV*v!(P6+nvCyz_EElfi8vd`{VT1Ro{%S~?&DZyH6P zGo;NQ00m$SjnAvZO2cx6(HQvHdWwD+k4r6JfDk}^)Y|^`Rmr{(4Gvf;cKEV)*$T%bsNbn+XnKxty z6^#1)k%IxR0%G2-stjDh3T?cVp>UYDgIf7w1G&vWa702m&X!DptvEi@0^uxpUm$5H5Z-KBAcz{` z>K=27HpwpkIoW5j8ykb`at0`jLm5;kgGx3jt`VZfxh}#W??ojqMY^3Vm7&UTG@uAP zHe8J0asW{ZB?nl5AixO-0<5djL~l+D;r|`^vZzpYS9KI8Y1Yb(EnK@icYf}|#rf{S zrOQ_qmwcx)Taed-|M&l;AZv?~II|#YRMbgzFZ1#37bnKhUj$d#z^7c@2?fGz+{H0K{$uato>`HDnLFGlXIkeq3t&#$-Zd()=%W*0 z&Tf0l_S%`i6m|*n08CRc+~aU5FfJ}A6_hsuI){BeY`WZe3~!#aN8_^%H&1gAt{5M) z;}ALeY5Ak&zgc3k=TRd%|r~^)0e8-?BR@9SKj6#Dd zd<2X+BA&X?UFJ*O?xH0iFKGc1oRC`xR`HrkkN_wN7EW9Shd_ju#l2*V*5(%J3dG1F z9dwpx5$x6Ggi9C#8t8_k;1=o!+zQj5AAE<;AL4tw9r*P?DVAO`xCBbOz@56ZUGCJS zoo_1mVpGo-LIvBork>B6kZ9*jfURRfK9z>9La%MegA^u&))^|n*@i>YV=gz;0cja( zgJgy{BB=>6N=(2U*99BHb-|}ZH(`v>O&AJv6FwkXXeOeyaBX}m_2jgpgcs6#yhZa4 zQ)tNijH)$1!BiEoF^zCW{B+QGl1U)RJn}_)+z(!dcNi7}MFb9ajPMZ`Zg_w3ODw#< z0Adaq6jT|R1jAA_1P=a!R}5*Re?%w*;Vztgol@7t{o%pUSdcgR+5S!sPcM`4l7_iu z(&i+0Z;1)9lFPxRV6{hvPKkOfV-P@@I{U%I`*R$V$3Fe(Jv1qLR T&JLgG3A7Ybp7PlGXgK~GM3S9O diff --git a/substrate/runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm b/substrate/runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm deleted file mode 100644 index 9fe583e7e40eeab56bf09d407ddd10c4e9070248..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3130 zcmcguPj6dA5Z~SR*Kc>9pWC!?+9uuinwAu`P@trUUNV)^sE2+4B%~y5++sI&BIhO0 z12qT4nLD3>D;F+&gnj^yJ#yfPIPsf(wH>4XS?99&W&i>}luGl>qN+E>2k?hEc z*a;?+iJV}FKQ)0Mga8C%`D#Z9^@B`<-smLleN}Hi8~1ubFuTO;^IpBZyT5<%bhqy9 zZ6DPKyA$dOI`JtZ_YA)yvpB}z!G_=>~4TlFOf3xWgk9u{Z(qfgvaeq{cfY)d< zkJ;H)VUV>%6bmV(5@9G0g@^(vI>~2gJnRh*#xIpHb?>O&-rKErxBDZ}>Wq)UKIuL0 zkG79TU-n0PB4b_l%On_he=LjGk34>Rh<4}?U$msieqLyOCuKCDu#D8k^y>tLgEb{8 zxoL$H7?qKeWcI57q`P0KEh}AAhDK?+Q>ZGmN(k)~4_)K}r}+2ya$!p4qCz;eX_bbp ztjkC{;lg!=g|Ul^FluX9|Jjkngal!`klc%^y$)(f7cq4yf{iQ^auk9WW#-x>)>Xj* zdLuC3reaXY%DVQNDvHF}LeMIu(Du`f`7KI{cxuY4HdZ(tTa_u@rEIS7hoEArVW-%f zrryef6l^%_{05@k5&#ttr5=ktPWedWcNW00!I`KH$bX3+=xMyLTDOJ_zpx9F|kdVzR&tM0|dn zjtPPu_~Wuq3L}&pK(sDpx2!J~5O68|A}B|$qAUl9V2GpEO=WWi7yb|Y+4|Q8scgnbBZ>}F8?{%Ph~eY2G`{bP#F6% zC{YHbY*IW#h#Kd*2!p&A6s(GLo2g1)WjGp81Rh&9LU1{ND20LpEI<(87z6uY3RR|4Ttu1|@N3 zK~|`!S#_`S@y#c*#n4{_SJ}WNT-^xkNtM`TbLGs%wBLlQTT+uKoE-@&7MZYVD@w8W z$8a7M+`{lK`X(}$^QS~a3-gh7NccgSB4s%)xE&z<5QUCA1N{~RH8f42k_=`)z%1u3 zjsfx?dnfnIk}Q_F!;SJ(>%3+F%)ISgqZ~@_&44+(?X8+?X9AO(705j>O~r7J!==Eu zSZ|b5)(Gev_IbDIa_2F;IctyFrCWB979d>HE@Hu3?;>o^F-fabP%(nK-zIPLHqgPK@VpRZ%&8&vKBV9XJ5)P?OTU+QKbEdhB+OOW7% z+(MwmI+q{;P!cShxC{<~@GXmbNsZQKm+1<`$fD5Otk5#ptIY{lFa$KP^+~}k)D5^5 zCOw|G17>wyxeUedS(3bVwWx-ebt)P-4WD)?ek&lh|Jn}w#H&ugD(=d_2d zqkTRVny$jGt;vDp+K1L^D!`eBL(^j})6@ZJX=;O{nm8hf_A!dJ#~jxMFNW)aPl;~A z7@?am6zC>=K(x?Q1RMU^_*#aOc}MXtq_=pB<{hTckog%^h5Q6lWx$Jt2xq`ghY(LP z2_%_EzDO7H&%eW<3=|PK+%duhT)6)I#V;}c{sM>@WH3-gFdv5VVWeXy6sjR``zO3@ zDAeKi2#_G$kf&d?)YVacba-3~ayoo^u-C(bOsA~UFt>CveQ48Not^CN_wlwp7#|7T zZ8~Sg)3Vn>x1RM!{i82>d!?XXg--A&cLy)Pyb(GQ&8olgF=loGjYb!99$O!e>c0R6 CpR&{d diff --git a/substrate/runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm b/substrate/runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm deleted file mode 100644 index 6ce8afb77ce2136b71e41d74bf115b4c8f918264..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3042 zcmcgu&2ke*5T2Qx{n5_MY6S+%fX(b;h)F?05@J%JQst(~xH#|zRM`d#B4NueS$5zM zltU`#yhM(<=A1|10dnM+LyoDO^7SmTb#N+`OQe!|x@Wql=j)#tv3yc=P$F*As%-1!iCL#+%!_yZg_!$Gx4+ z!}0!T`$bPkp3ixHFH8z`D(LM!J9yo!Xz_}JQGYlV5ie*ne+Y|HJ37iz5hp?_p|v~^ zB95f!q+i9!UT<%I^jZl!?j4RdcecmdoBg3kJEJ48PkS%=!_A}NH~ry`$ddOy7#)1K zEh+M!=F%Uej3=b4SglRJUXUKFC{fFGC%nL@ioGPeTSp+>-CAup>ElXUW#~?+YVDK| z#w#BB*hgOR@A2g_uau8V;nliR2D)-w#l{P-R}~Cn7awEPHqid7Bg+X1!giYc%euV^ zYRQzEx)ei4mN9wK;6;`DHi=bLvVh(R%(tl=l(Kfdy`su8_O2APOc_>(=|=q)rKO&# zveiZlr(>-uqq~%!F8EVWIbGqV*v!(P6+nvCyz_EElfi8vd`{VT1Ro{%S~?&DZyH6P zGo;NQ00m$SjnAvZO2cx6(HQvHdWwD+k4r6JfDk}^)Y|^`Rmr{(4Gvf;cKEV)*$T%bsNbn+XnKxty z6^#1)k%IxR0%G2-stjDh3T?cVp>UYDgIf7w1G&vWa702m&X!DptvEi@0^uxpUm$5H5Z-KBAcz{` z>K=27HpwpkIoW5j8ykb`at0`jLm5;kgGx3jt`VZfxh}#W??ojqMY^3Vm7&UTG@uAP zHe8J0asW{ZB?nl5AixO-0<5djL~l+D;r|`^vZzpYS9KI8Y1Yb(EnK@icYf}|#rf{S zrOQ_qmwcx)Taed-|M&l;AZv?~II|#YRMbgzFZ1#37bnKhUj$d#z^7c@2?fGz+{H0K{$uato>`HDnLFGlXIkeq3t&#$-Zd()=%W*0 z&Tf0l_S%`i6m|*n08CRc+~aU5FfJ}A6_hsuI){BeY`WZe3~!#aN8_^%H&1gAt{5M) z;}ALeY5Ak&zgc3k=TRd%|r~^)0e8-?BR@9SKj6#Dd zd<2X+BA&X?UFJ*O?xH0iFKGc1oRC`xR`HrkkN_wN7EW9Shd_ju#l2*V*5(%J3dG1F z9dwpx5$x6Ggi9C#8t8_k;1=o!+zQj5AAE<;AL4tw9r*P?DVAO`xCBbOz@56ZUGCJS zoo_1mVpGo-LIvBork>B6kZ9*jfURRfK9z>9La%MegA^u&))^|n*@i>YV=gz;0cja( zgJgy{BB=>6N=(2U*99BHb-|}ZH(`v>O&AJv6FwkXXeOeyaBX}m_2jgpgcs6#yhZa4 zQ)tNijH)$1!BiEoF^zCW{B+QGl1U)RJn}_)+z(!dcNi7}MFb9ajPMZ`Zg_w3ODw#< z0Adaq6jT|R1jAA_1P=a!R}5*Re?%w*;Vztgol@7t{o%pUSdcgR+5S!sPcM`4l7_iu z(&i+0Z;1)9lFPxRV6{hvPKkOfV-P@@I{U%I`*R$V$3Fe(Jv1qLR T&JLgG3A7Ybp7PlGXgK~GM3S9O diff --git a/substrate/runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm b/substrate/runtime/target/wasm32-unknown-unknown/release/runtime_test.wasm deleted file mode 100644 index 9fe583e7e40eeab56bf09d407ddd10c4e9070248..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3130 zcmcguPj6dA5Z~SR*Kc>9pWC!?+9uuinwAu`P@trUUNV)^sE2+4B%~y5++sI&BIhO0 z12qT4nLD3>D;F+&gnj^yJ#yfPIPsf(wH>4XS?99&W&i>}luGl>qN+E>2k?hEc z*a;?+iJV}FKQ)0Mga8C%`D#Z9^@B`<-smLleN}Hi8~1ubFuTO;^IpBZyT5<%bhqy9 zZ6DPKyA$dOI`JtZ_YA)yvpB}z!G_=>~4TlFOf3xWgk9u{Z(qfgvaeq{cfY)d< zkJ;H)VUV>%6bmV(5@9G0g@^(vI>~2gJnRh*#xIpHb?>O&-rKErxBDZ}>Wq)UKIuL0 zkG79TU-n0PB4b_l%On_he=LjGk34>Rh<4}?U$msieqLyOCuKCDu#D8k^y>tLgEb{8 zxoL$H7?qKeWcI57q`P0KEh}AAhDK?+Q>ZGmN(k)~4_)K}r}+2ya$!p4qCz;eX_bbp ztjkC{;lg!=g|Ul^FluX9|Jjkngal!`klc%^y$)(f7cq4yf{iQ^auk9WW#-x>)>Xj* zdLuC3reaXY%DVQNDvHF}LeMIu(Du`f`7KI{cxuY4HdZ(tTa_u@rEIS7hoEArVW-%f zrryef6l^%_{05@k5&#ttr5=ktPWedWcNW00!I`KH$bX3+=xMyLTDOJ_zpx9F|kdVzR&tM0|dn zjtPPu_~Wuq3L}&pK(sDpx2!J~5O68|A}B|$qAUl9V2GpEO=WWi7yb|Y+4|Q8scgnbBZ>}F8?{%Ph~eY2G`{bP#F6% zC{YHbY*IW#h#Kd*2!p&A6s(GLo2g1)WjGp81Rh&9LU1{ND20LpEI<(87z6uY3RR|4Ttu1|@N3 zK~|`!S#_`S@y#c*#n4{_SJ}WNT-^xkNtM`TbLGs%wBLlQTT+uKoE-@&7MZYVD@w8W z$8a7M+`{lK`X(}$^QS~a3-gh7NccgSB4s%)xE&z<5QUCA1N{~RH8f42k_=`)z%1u3 zjsfx?dnfnIk}Q_F!;SJ(>%3+F%)ISgqZ~@_&44+(?X8+?X9AO(705j>O~r7J!==Eu zSZ|b5)(Gev_IbDIa_2F;IctyFrCWB979d>HE@Hu3?;>o^F-fabP%(nK-zIPLHqgPK@VpRZ%&8&vKBV9XJ5)P?OTU+QKbEdhB+OOW7% z+(MwmI+q{;P!cShxC{<~@GXmbNsZQKm+1<`$fD5Otk5#ptIY{lFa$KP^+~}k)D5^5 zCOw|G17>wyxeUedS(3bVwWx-ebt)P-4WD)?ek&lh|Jn}w#H&ugD(=d_2d zqkTRVny$jGt;vDp+K1L^D!`eBL(^j})6@ZJX=;O{nm8hf_A!dJ#~jxMFNW)aPl;~A z7@?am6zC>=K(x?Q1RMU^_*#aOc}MXtq_=pB<{hTckog%^h5Q6lWx$Jt2xq`ghY(LP z2_%_EzDO7H&%eW<3=|PK+%duhT)6)I#V;}c{sM>@WH3-gFdv5VVWeXy6sjR``zO3@ zDAeKi2#_G$kf&d?)YVacba-3~ayoo^u-C(bOsA~UFt>CveQ48Not^CN_wlwp7#|7T zZ8~Sg)3Vn>x1RM!{i82>d!?XXg--A&cLy)Pyb(GQ&8olgF=loGjYb!99$O!e>c0R6 CpR&{d diff --git a/substrate/runtime/test/src/lib.rs b/substrate/runtime/test/src/lib.rs deleted file mode 100644 index ec3fabb89c..0000000000 --- a/substrate/runtime/test/src/lib.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![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, code, set_code, storage, validators, set_validators, print}; - -impl_stub!(test_data_in); -fn test_data_in(input: Vec) -> Vec { - 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"validators" as &[u8]); - let mut v = validators(); - v.push(copy); - - print(b"set_validators" as &[u8]); - set_validators(&v.iter().map(Vec::as_slice).collect::>()); - - print(b"finished!" as &[u8]); - b"all ok!".to_vec() -} diff --git a/substrate/state_machine/Cargo.toml b/substrate/state_machine/Cargo.toml index a0d25c821c..458bae8e1e 100644 --- a/substrate/state_machine/Cargo.toml +++ b/substrate/state_machine/Cargo.toml @@ -7,7 +7,6 @@ description = "Polkadot State Machine" [dependencies] polkadot-primitives = { path = "../primitives", version = "0.1.0" } hashdb = "0.1.1" -keccak-hash = "0.1.0" patricia-trie = "0.1.0" memorydb = "0.1.1" triehash = "0.1" diff --git a/substrate/state_machine/src/ext.rs b/substrate/state_machine/src/ext.rs index ce7b9a0268..1452558ccd 100644 --- a/substrate/state_machine/src/ext.rs +++ b/substrate/state_machine/src/ext.rs @@ -73,4 +73,8 @@ impl<'a, B: 'a> Externalities for Ext<'a, B> fn set_storage(&mut self, key: Vec, value: Vec) { self.overlay.set_storage(key, value); } + + fn chain_id(&self) -> u64 { + 42 + } } diff --git a/substrate/state_machine/src/lib.rs b/substrate/state_machine/src/lib.rs index 58ba558322..cd25cdcb90 100644 --- a/substrate/state_machine/src/lib.rs +++ b/substrate/state_machine/src/lib.rs @@ -22,7 +22,6 @@ extern crate polkadot_primitives as primitives; extern crate hashdb; extern crate memorydb; -extern crate keccak_hash; extern crate patricia_trie; extern crate triehash; @@ -114,13 +113,9 @@ impl OverlayedChanges { pub trait Error: 'static + fmt::Debug + fmt::Display + Send {} impl Error for E where E: 'static + fmt::Debug + fmt::Display + Send {} -fn value_vec(mut value: usize, initial: Vec) -> Vec { - let mut acc = initial; - while value > 0 { - acc.push(value as u8); - value /= 256; - } - acc +fn to_keyed_vec(value: u32, mut prepend: Vec) -> Vec { + prepend.extend((0..::std::mem::size_of::()).into_iter().map(|i| (value >> (i * 8)) as u8)); + prepend } /// Externalities: pinned to specific active address. @@ -134,12 +129,15 @@ pub trait Externalities { /// Set storage of current contract being called (effective immediately). fn set_storage(&mut self, key: Vec, value: Vec); - /// Get the current set of validators. - fn validators(&self) -> Result, Self::Error> { - (0..self.storage(b"\0validator_count")?.into_iter() + /// Get the identity of the chain. + fn chain_id(&self) -> u64; + + /// Get the current set of authorities from storage. + fn authorities(&self) -> Result, Self::Error> { + (0..self.storage(b"con:aut:len")?.into_iter() .rev() - .fold(0, |acc, &i| (acc << 8) + (i as usize))) - .map(|i| self.storage(&value_vec(i, b"\0validator".to_vec()))) + .fold(0, |acc, &i| (acc << 8) + (i as u32))) + .map(|i| self.storage(&to_keyed_vec(i, b"con:aut:".to_vec()))) .collect() } } @@ -179,7 +177,7 @@ pub fn execute( overlay: &mut *overlay }; // make a copy. - let code = externalities.storage(b"\0code").unwrap_or(&[]).to_vec(); + let code = externalities.storage(b":code").unwrap_or(&[]).to_vec(); exec.call( &mut externalities, @@ -245,25 +243,27 @@ mod tests { fn set_storage(&mut self, key: Vec, value: Vec) { self.storage.insert(key, value); } + + fn chain_id(&self) -> u64 { 42 } } #[test] - fn validators_call_works() { + fn authorities_call_works() { let mut ext = TestExternalities::default(); - assert_eq!(ext.validators(), Ok(vec![])); + assert_eq!(ext.authorities(), Ok(vec![])); - ext.set_storage(b"\0validator_count".to_vec(), vec![]); - assert_eq!(ext.validators(), Ok(vec![])); + ext.set_storage(b"con:aut:len".to_vec(), vec![0u8; 4]); + assert_eq!(ext.authorities(), Ok(vec![])); - ext.set_storage(b"\0validator_count".to_vec(), vec![1]); - assert_eq!(ext.validators(), Ok(vec![&[][..]])); + ext.set_storage(b"con:aut:len".to_vec(), vec![1u8, 0, 0, 0]); + assert_eq!(ext.authorities(), Ok(vec![&[][..]])); - ext.set_storage(b"\0validator".to_vec(), b"first".to_vec()); - assert_eq!(ext.validators(), Ok(vec![&b"first"[..]])); + ext.set_storage(b"con:aut:\0\0\0\0".to_vec(), b"first".to_vec()); + assert_eq!(ext.authorities(), Ok(vec![&b"first"[..]])); - ext.set_storage(b"\0validator_count".to_vec(), vec![2]); - ext.set_storage(b"\0validator\x01".to_vec(), b"second".to_vec()); - assert_eq!(ext.validators(), Ok(vec![&b"first"[..], &b"second"[..]])); + ext.set_storage(b"con:aut:len".to_vec(), vec![2u8, 0, 0, 0]); + ext.set_storage(b"con:aut:\x01\0\0\0".to_vec(), b"second".to_vec()); + assert_eq!(ext.authorities(), Ok(vec![&b"first"[..], &b"second"[..]])); } } diff --git a/substrate/runtime/Cargo.lock b/substrate/wasm-runtime/Cargo.lock similarity index 100% rename from substrate/runtime/Cargo.lock rename to substrate/wasm-runtime/Cargo.lock diff --git a/substrate/runtime/Cargo.toml b/substrate/wasm-runtime/Cargo.toml similarity index 100% rename from substrate/runtime/Cargo.toml rename to substrate/wasm-runtime/Cargo.toml diff --git a/substrate/runtime/build.sh b/substrate/wasm-runtime/build.sh similarity index 100% rename from substrate/runtime/build.sh rename to substrate/wasm-runtime/build.sh diff --git a/substrate/runtime/init.sh b/substrate/wasm-runtime/init.sh similarity index 100% rename from substrate/runtime/init.sh rename to substrate/wasm-runtime/init.sh diff --git a/substrate/runtime/polkadot/Cargo.toml b/substrate/wasm-runtime/polkadot/Cargo.toml similarity index 75% rename from substrate/runtime/polkadot/Cargo.toml rename to substrate/wasm-runtime/polkadot/Cargo.toml index a313da2a1e..ce2d9909a7 100644 --- a/substrate/runtime/polkadot/Cargo.toml +++ b/substrate/wasm-runtime/polkadot/Cargo.toml @@ -8,3 +8,8 @@ crate-type = ["cdylib"] [dependencies] runtime-support = { path = "../support", version = "0.1" } + +[features] +default = ["without-std"] +with-std = [] +without-std = [] diff --git a/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs b/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs new file mode 100644 index 0000000000..a157628422 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs @@ -0,0 +1,50 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Endian manager. + +/// Trait to allow conversion to a know endian representation when sensitive. +pub trait EndianSensitive: Sized { + fn to_le(self) -> Self { self } + fn to_be(self) -> Self { self } + fn from_le(self) -> Self { self } + fn from_be(self) -> Self { self } + fn as_be_then T>(&self, f: F) -> T { f(&self) } + fn as_le_then T>(&self, f: F) -> T { f(&self) } +} + +macro_rules! impl_endians { + ( $( $t:ty ),* ) => { $( + impl EndianSensitive for $t { + fn to_le(self) -> Self { <$t>::to_le(self) } + fn to_be(self) -> Self { <$t>::to_be(self) } + fn from_le(self) -> Self { <$t>::from_le(self) } + fn from_be(self) -> Self { <$t>::from_be(self) } + fn as_be_then T>(&self, f: F) -> T { let d = self.to_be(); f(&d) } + fn as_le_then T>(&self, f: F) -> T { let d = self.to_le(); f(&d) } + } + )* } +} +macro_rules! impl_non_endians { + ( $( $t:ty ),* ) => { $( + impl EndianSensitive for $t {} + )* } +} + +impl_endians!(u16, u32, u64, usize, i16, i32, i64, isize); +impl_non_endians!(u8, i8, [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]); diff --git a/substrate/wasm-runtime/polkadot/src/codec/joiner.rs b/substrate/wasm-runtime/polkadot/src/codec/joiner.rs new file mode 100644 index 0000000000..92a5aa87fc --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/codec/joiner.rs @@ -0,0 +1,32 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Vec serialiser. + +use runtime_support::Vec; +use slicable::Slicable; + +/// Trait to allow itself to be serialised into a `Vec` +pub trait Joiner { + fn join(self, value: &T) -> Self; +} + +impl Joiner for Vec { + fn join(mut self, value: &T) -> Vec { + value.as_slice_then(|s| self.extend_from_slice(s)); + self + } +} diff --git a/substrate/wasm-runtime/polkadot/src/codec/keyedvec.rs b/substrate/wasm-runtime/polkadot/src/codec/keyedvec.rs new file mode 100644 index 0000000000..1f803b7c62 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/codec/keyedvec.rs @@ -0,0 +1,56 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Serialiser and prepender. + +use runtime_support::Vec; +use slicable::Slicable; + +/// Trait to allow itselg to be serialised and prepended by a given slice. +pub trait KeyedVec { + fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec; +} + +macro_rules! impl_non_endians { + ( $( $t:ty ),* ) => { $( + impl KeyedVec for $t { + fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec { + let mut r = prepend_key.to_vec(); + r.extend_from_slice(&self[..]); + r + } + } + )* } +} + +macro_rules! impl_endians { + ( $( $t:ty ),* ) => { $( + impl KeyedVec for $t { + fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec { + self.as_slice_then(|slice| { + let mut r = prepend_key.to_vec(); + r.extend_from_slice(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]); diff --git a/substrate/wasm-runtime/polkadot/src/codec/mod.rs b/substrate/wasm-runtime/polkadot/src/codec/mod.rs new file mode 100644 index 0000000000..7d9bc90c4f --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/codec/mod.rs @@ -0,0 +1,23 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Codec utils. + +pub mod endiansensitive; +pub mod streamreader; +pub mod joiner; +pub mod slicable; +pub mod keyedvec; diff --git a/substrate/wasm-runtime/polkadot/src/codec/slicable.rs b/substrate/wasm-runtime/polkadot/src/codec/slicable.rs new file mode 100644 index 0000000000..5ec042ec9b --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/codec/slicable.rs @@ -0,0 +1,88 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Serialisation. + +use runtime_support::{Vec, size_of, transmute, uninitialized, slice}; +use joiner::Joiner; +use endiansensitive::EndianSensitive; + +/// Trait that allows zero-copy read/write of value-references to/from slices in LE format. +pub trait Slicable: Sized { + fn from_slice(value: &[u8]) -> Option { + Self::set_as_slice(|out| if value.len() == out.len() { + out.copy_from_slice(&value); + true + } else { + false + }) + } + fn to_vec(&self) -> Vec { + self.as_slice_then(|s| s.to_vec()) + } + fn set_as_slice bool>(set_slice: F) -> Option; + fn as_slice_then R>(&self, f: F) -> R { + f(&self.to_vec()) + } + fn size_of(_value: &[u8]) -> Option; +} + +/// Trait to mark that a type is not trivially (essentially "in place") serialisable. +pub trait NonTrivialSlicable: Slicable {} + +impl Slicable for T { + fn set_as_slice bool>(fill_slice: F) -> Option { + let size = size_of::(); + let mut result: T = unsafe { uninitialized() }; + let result_slice = unsafe { + slice::from_raw_parts_mut(transmute::<*mut T, *mut u8>(&mut result), size) + }; + if fill_slice(result_slice) { + Some(result.from_le()) + } else { + None + } + } + fn as_slice_then R>(&self, f: F) -> R { + let size = size_of::(); + self.as_le_then(|le| { + let value_slice = unsafe { + slice::from_raw_parts(transmute::<*const Self, *const u8>(le), size) + }; + f(value_slice) + }) + } + fn size_of(_value: &[u8]) -> Option { + Some(size_of::()) + } +} + +impl Slicable for Vec { + fn from_slice(value: &[u8]) -> Option { + Some(value[4..].to_vec()) + } + fn set_as_slice bool>(_fill_slice: F) -> Option { + unimplemented!(); + } + fn to_vec(&self) -> Vec { + let mut r: Vec = Vec::new().join(&(self.len() as u32)); + r.extend_from_slice(&self); + r + } + fn size_of(data: &[u8]) -> Option { + u32::from_slice(&data[0..4]).map(|i| (i + 4) as usize) + } +} diff --git a/substrate/wasm-runtime/polkadot/src/codec/streamreader.rs b/substrate/wasm-runtime/polkadot/src/codec/streamreader.rs new file mode 100644 index 0000000000..371ceed4ee --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/codec/streamreader.rs @@ -0,0 +1,74 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Deserialiser. + +use slicable::Slicable; + +/// Simple deserialiser. +pub struct StreamReader<'a> { + data: &'a[u8], + offset: usize, +} + +impl<'a> StreamReader<'a> { + /// Create a new deserialiser based on the `data`. + pub fn new(data: &'a[u8]) -> Self { + StreamReader { + data: data, + offset: 0, + } + } + + /// Deserialise a single item from the data stream. + pub fn read(&mut self) -> Option { + let size = T::size_of(&self.data[self.offset..])?; + let new_offset = self.offset + size; + let slice = &self.data[self.offset..new_offset]; + self.offset = new_offset; + Slicable::from_slice(slice) + } +} +/* +// Not in use yet +// TODO: introduce fn size_will_be(&self) -> usize; to Slicable trait and implement +struct StreamWriter<'a> { + data: &'a mut[u8], + offset: usize, +} + +impl<'a> StreamWriter<'a> { + pub fn new(data: &'a mut[u8]) -> Self { + StreamWriter { + data: data, + offset: 0, + } + } + pub fn write(&mut self, value: &T) -> bool { + value.as_slice_then(|s| { + let new_offset = self.offset + s.len(); + if self.data.len() <= new_offset { + let slice = &mut self.data[self.offset..new_offset]; + self.offset = new_offset; + slice.copy_from_slice(s); + true + } else { + false + } + }) + } +} +*/ diff --git a/substrate/wasm-runtime/polkadot/src/lib.rs b/substrate/wasm-runtime/polkadot/src/lib.rs new file mode 100644 index 0000000000..7a96b6cee4 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/lib.rs @@ -0,0 +1,54 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! The Polkadot runtime. This can be compiled with #[no_std], ready for Wasm. + +#![cfg_attr(feature = "without-std", no_std)] +#![cfg_attr(feature = "strict", deny(warnings))] + +#[macro_use] +extern crate runtime_support; + +#[cfg(test)] +extern crate rustc_hex; + +mod codec; +#[macro_use] +mod support; +mod runtime; +pub use codec::{endiansensitive, streamreader, joiner, slicable, keyedvec}; +pub use support::{primitives, function, environment, storable}; +#[cfg(test)] +pub use support::{testing, statichex}; + +use runtime_support::Vec; +use slicable::Slicable; +use primitives::{Block, UncheckedTransaction}; + +/// Execute a block, with `input` being the canonical serialisation of the block. Returns the +/// empty vector. +pub fn execute_block(input: Vec) -> Vec { + runtime::system::execute_block(Block::from_slice(&input).unwrap()); + Vec::new() +} + +/// Execute a given, serialised, transaction. Returns the empty vector. +pub fn execute_transaction(input: Vec) -> Vec { + runtime::system::execute_transaction(&UncheckedTransaction::from_slice(&input).unwrap()); + Vec::new() +} + +impl_stubs!(execute_block, execute_transaction); diff --git a/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs b/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs new file mode 100644 index 0000000000..1e12135806 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs @@ -0,0 +1,44 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Conensus module for runtime; manages the authority set ready for the native code. + +use runtime_support::Vec; +use storable::StorageVec; +use primitives::SessionKey; + +struct AuthorityStorageVec {} +impl StorageVec for AuthorityStorageVec { + type Item = SessionKey; + const PREFIX: &'static[u8] = b"con:aut:"; +} + +/// Get the current set of authorities. These are the session keys. +pub fn authorities() -> Vec { + AuthorityStorageVec::items() +} + +/// 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); +} diff --git a/substrate/wasm-runtime/polkadot/src/runtime/mod.rs b/substrate/wasm-runtime/polkadot/src/runtime/mod.rs new file mode 100644 index 0000000000..f83922c42f --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/runtime/mod.rs @@ -0,0 +1,30 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! The Polkadot 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; + +// TODO: governance, polkadao diff --git a/substrate/wasm-runtime/polkadot/src/runtime/session.rs b/substrate/wasm-runtime/polkadot/src/runtime/session.rs new file mode 100644 index 0000000000..907b3e16b1 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/runtime/session.rs @@ -0,0 +1,229 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Session manager: is told the validators and allows them to manage their session keys for the +//! consensus module. + +use runtime_support::Vec; +use keyedvec::KeyedVec; +use storable::{kill, Storable, StorageVec}; +use primitives::{AccountID, SessionKey, BlockNumber}; +use runtime::{system, staking, consensus}; + +struct ValidatorStorageVec {} +impl StorageVec for ValidatorStorageVec { + type Item = AccountID; + const PREFIX: &'static[u8] = b"ses:val:"; +} + +// TRANSACTION API (available to all transactors) + +/// 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 + key.store(&validator.to_keyed_vec(b"ses:nxt:")); +} + +// PUBLIC API (available to other runtime modules) + +/// Get the current set of authorities. These are the session keys. +pub fn validators() -> Vec { + ValidatorStorageVec::items() +} + +/// 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::set_authorities(new); +} + +/// The number of blocks in each session. +pub fn length() -> BlockNumber { + Storable::lookup_default(b"ses:len") +} + +/// The current era index. +pub fn current_index() -> BlockNumber { + Storable::lookup_default(b"ses:ind") +} + +/// Set the current era index. +pub fn set_current_index(new: BlockNumber) { + new.store(b"ses:ind"); +} + +/// The block number at which the era length last changed. +pub fn last_length_change() -> BlockNumber { + Storable::lookup_default(b"ses:llc") +} + +/// Set a new era length. Won't kick in until the next era change (at current length). +pub fn set_length(new: BlockNumber) { + new.store(b"ses:nln"); +} + +/// 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(); + } +} + +// PRIVATE (not available for use externally) + +/// Move onto next session: register the new authority set. +fn rotate_session() { + // Increment current session index. + set_current_index(current_index() + 1); + + // Enact era length change. + if let Some(next_len) = u64::lookup(b"ses:nln") { + next_len.store(b"ses:len"); + system::block_number().store(b"ses:llc"); + kill(b"ses:nln"); + } + + // Update any changes in session keys. + validators().iter().enumerate().for_each(|(i, v)| { + let k = v.to_keyed_vec(b"ses:nxt:"); + if let Some(n) = Storable::lookup(&k) { + consensus::set_authority(i as u32, &n); + kill(&k); + } + }); +} + +#[cfg(test)] +mod tests { + use runtime_support::{with_externalities, twox_128}; + use keyedvec::KeyedVec; + use joiner::Joiner; + use testing::{one, two, TestExternalities}; + use primitives::AccountID; + use runtime::{consensus, session}; + use environment::with_env; + + fn simple_setup() -> TestExternalities { + TestExternalities { storage: map![ + twox_128(b"ses:len").to_vec() => vec![].join(&2u64), + // the validators (10, 20, ...) + twox_128(b"ses:val:len").to_vec() => vec![].join(&2u32), + twox_128(&0u32.to_keyed_vec(b"ses:val:")).to_vec() => vec![10; 32], + twox_128(&1u32.to_keyed_vec(b"ses:val:")).to_vec() => vec![20; 32], + // initial session keys (11, 21, ...) + twox_128(b"con:aut:len").to_vec() => vec![].join(&2u32), + twox_128(&0u32.to_keyed_vec(b"con:aut:")).to_vec() => vec![11; 32], + twox_128(&1u32.to_keyed_vec(b"con:aut:")).to_vec() => 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!(session::length(), 2u64); + assert_eq!(session::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); + session::set_length(3); + session::check_rotate_session(); + assert_eq!(session::length(), 2); + assert_eq!(session::current_index(), 0); + + // Block 2: Length now changed to 3. Index incremented. + with_env(|e| e.block_number = 2); + session::set_length(3); + session::check_rotate_session(); + assert_eq!(session::length(), 3); + assert_eq!(session::current_index(), 1); + + // Block 3: Length now changed to 3. Index incremented. + with_env(|e| e.block_number = 3); + session::check_rotate_session(); + assert_eq!(session::length(), 3); + assert_eq!(session::current_index(), 1); + + // Block 4: Change to length 2; no visible change. + with_env(|e| e.block_number = 4); + session::set_length(2); + session::check_rotate_session(); + assert_eq!(session::length(), 3); + assert_eq!(session::current_index(), 1); + + // Block 5: Length now changed to 2. Index incremented. + with_env(|e| e.block_number = 5); + session::check_rotate_session(); + assert_eq!(session::length(), 2); + assert_eq!(session::current_index(), 2); + + // Block 6: No change. + with_env(|e| e.block_number = 6); + session::check_rotate_session(); + assert_eq!(session::length(), 2); + assert_eq!(session::current_index(), 2); + + // Block 7: Next index. + with_env(|e| e.block_number = 7); + session::check_rotate_session(); + assert_eq!(session::length(), 2); + assert_eq!(session::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); + session::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); + session::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); + session::set_key(&[20; 32], &[22; 32]); + assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]); + + session::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); + session::check_rotate_session(); + assert_eq!(consensus::authorities(), vec![[11u8; 32], [22u8; 32]]); + }); + } +} diff --git a/substrate/wasm-runtime/polkadot/src/runtime/staking.rs b/substrate/wasm-runtime/polkadot/src/runtime/staking.rs new file mode 100644 index 0000000000..fc7c12798e --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/runtime/staking.rs @@ -0,0 +1,363 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Staking manager: Handles balances and periodically determines the best set of validators. + +use runtime_support::Vec; +use keyedvec::KeyedVec; +use storable::{Storable, StorageVec}; +use 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; + +struct IntentionStorageVec {} +impl StorageVec for IntentionStorageVec { + type Item = AccountID; + const PREFIX: &'static[u8] = b"ses:wil:"; +} + +// 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. + +/// The length of the bonding duration in eras. +pub fn bonding_duration() -> BlockNumber { + Storable::lookup_default(b"sta:loc") +} + +/// The length of a staking era in sessions. +pub fn validator_count() -> usize { + u32::lookup_default(b"sta:vac") 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 { + Storable::lookup_default(b"sta:spe") +} + +/// The current era index. +pub fn current_era() -> BlockNumber { + Storable::lookup_default(b"sta:era") +} + +/// The block number at which the era length last changed. +pub fn last_era_length_change() -> BlockNumber { + Storable::lookup_default(b"sta:lec") +} + +/// The balance of a given account. +pub fn balance(who: &AccountID) -> Balance { + Storable::lookup_default(&who.to_keyed_vec(b"sta:bal:")) +} + +/// The liquidity-state of a given account. +pub fn bondage(who: &AccountID) -> Bondage { + Storable::lookup_default(&who.to_keyed_vec(b"sta:bon:")) +} + +/// Transfer some unlocked staking balance to another staker. +pub fn transfer(transactor: &AccountID, dest: &AccountID, value: Balance) { + let from_key = transactor.to_keyed_vec(b"sta:bal:"); + let from_balance = Balance::lookup_default(&from_key); + assert!(from_balance >= value); + let to_key = dest.to_keyed_vec(b"sta:bal:"); + let to_balance: Balance = Storable::lookup_default(&to_key); + assert!(bondage(transactor) <= bondage(dest)); + assert!(to_balance + value > to_balance); // no overflow + (from_balance - value).store(&from_key); + (to_balance + value).store(&to_key); +} + +/// 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); + u64::max_value().store(&transactor.to_keyed_vec(b"sta:bon:")); +} + +/// 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); + (current_era() + bonding_duration()).store(&transactor.to_keyed_vec(b"sta:bon:")); +} + +/// 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(); + } +} + +// PRIVATE + +/// The era has changed - enact new staking set. +/// +/// NOTE: This always happens on a session change. +fn new_era() { + // Increment current era. + (current_era() + 1).store(b"sta:era"); + + // Enact era length change. + let next_spe: u64 = Storable::lookup_default(b"sta:nse"); + if next_spe > 0 && next_spe != sessions_per_era() { + next_spe.store(b"sta:spe"); + system::block_number().store(b"sta:lec"); + } + + // TODO: evaluate desired staking amounts and nominations and optimise to find the best + // combination of validators, then use session::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::>(); + intentions.sort_unstable_by(|&(b1, _), &(b2, _)| b2.cmp(&b1)); + session::set_validators( + &intentions.into_iter() + .map(|(_, v)| v) + .take(validator_count()) + .collect::>() + ); +} + +/// Set a new era length. Won't kick in until the next era change (at current length). +fn set_sessions_per_era(new: BlockNumber) { + new.store(b"sta:nse"); +} + +#[cfg(test)] +mod tests { + use runtime_support::{with_externalities, twox_128}; + use keyedvec::KeyedVec; + use joiner::Joiner; + use testing::{one, two, TestExternalities}; + use primitives::AccountID; + use runtime::{staking, session}; + use environment::with_env; + + #[test] + fn staking_should_work() { + let one = one(); + let two = two(); + let three = [3u8; 32]; + let four = [4u8; 32]; + + let mut t = TestExternalities { storage: map![ + twox_128(b"ses:len").to_vec() => vec![].join(&1u64), + twox_128(b"ses:val:len").to_vec() => vec![].join(&2u32), + twox_128(&0u32.to_keyed_vec(b"ses:val:")).to_vec() => vec![10; 32], + twox_128(&1u32.to_keyed_vec(b"ses:val:")).to_vec() => vec![20; 32], + twox_128(b"sta:spe").to_vec() => vec![].join(&2u64), + twox_128(b"sta:vac").to_vec() => vec![].join(&2u32), + twox_128(b"sta:loc").to_vec() => vec![].join(&3u64), + twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].join(&10u64), + twox_128(&two.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].join(&20u64), + twox_128(&three.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].join(&30u64), + twox_128(&four.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].join(&40u64) + ], }; + + with_externalities(&mut t, || { + assert_eq!(staking::era_length(), 2u64); + assert_eq!(staking::validator_count(), 2usize); + assert_eq!(staking::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); + staking::stake(&one); + staking::stake(&two); + staking::stake(&four); + staking::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); + staking::check_new_era(); + assert_eq!(session::validators(), vec![four.clone(), two.clone()]); + + // Block 3: Unstake highest, introduce another staker. No change yet. + with_env(|e| e.block_number = 3); + staking::stake(&three); + staking::unstake(&four); + staking::check_new_era(); + + // Block 4: New era - validators change. + with_env(|e| e.block_number = 4); + staking::check_new_era(); + assert_eq!(session::validators(), vec![three.clone(), two.clone()]); + + // Block 5: Transfer stake from highest to lowest. No change yet. + with_env(|e| e.block_number = 5); + staking::transfer(&four, &one, 40); + staking::check_new_era(); + + // Block 6: Lowest now validator. + with_env(|e| e.block_number = 6); + staking::check_new_era(); + assert_eq!(session::validators(), vec![one.clone(), three.clone()]); + + // Block 7: Unstake three. No change yet. + with_env(|e| e.block_number = 7); + staking::unstake(&three); + staking::check_new_era(); + assert_eq!(session::validators(), vec![one.clone(), three.clone()]); + + // Block 8: Back to one and two. + with_env(|e| e.block_number = 8); + staking::check_new_era(); + assert_eq!(session::validators(), vec![one.clone(), two.clone()]); + }); + } + + #[test] + fn staking_eras_work() { + let mut t = TestExternalities { storage: map![ + twox_128(b"ses:len").to_vec() => vec![].join(&1u64), + twox_128(b"sta:spe").to_vec() => vec![].join(&2u64) + ], }; + with_externalities(&mut t, || { + assert_eq!(staking::era_length(), 2u64); + assert_eq!(staking::sessions_per_era(), 2u64); + assert_eq!(staking::last_era_length_change(), 0u64); + assert_eq!(staking::current_era(), 0u64); + + // Block 1: No change. + with_env(|e| e.block_number = 1); + staking::check_new_era(); + assert_eq!(staking::sessions_per_era(), 2u64); + assert_eq!(staking::last_era_length_change(), 0u64); + assert_eq!(staking::current_era(), 0u64); + + // Block 2: Simple era change. + with_env(|e| e.block_number = 2); + staking::check_new_era(); + assert_eq!(staking::sessions_per_era(), 2u64); + assert_eq!(staking::last_era_length_change(), 0u64); + assert_eq!(staking::current_era(), 1u64); + + // Block 3: Schedule an era length change; no visible changes. + with_env(|e| e.block_number = 3); + staking::set_sessions_per_era(3); + staking::check_new_era(); + assert_eq!(staking::sessions_per_era(), 2u64); + assert_eq!(staking::last_era_length_change(), 0u64); + assert_eq!(staking::current_era(), 1u64); + + // Block 4: Era change kicks in. + with_env(|e| e.block_number = 4); + staking::check_new_era(); + assert_eq!(staking::sessions_per_era(), 3u64); + assert_eq!(staking::last_era_length_change(), 4u64); + assert_eq!(staking::current_era(), 2u64); + + // Block 5: No change. + with_env(|e| e.block_number = 5); + staking::check_new_era(); + assert_eq!(staking::sessions_per_era(), 3u64); + assert_eq!(staking::last_era_length_change(), 4u64); + assert_eq!(staking::current_era(), 2u64); + + // Block 6: No change. + with_env(|e| e.block_number = 6); + staking::check_new_era(); + assert_eq!(staking::sessions_per_era(), 3u64); + assert_eq!(staking::last_era_length_change(), 4u64); + assert_eq!(staking::current_era(), 2u64); + + // Block 7: Era increment. + with_env(|e| e.block_number = 7); + staking::check_new_era(); + assert_eq!(staking::sessions_per_era(), 3u64); + assert_eq!(staking::last_era_length_change(), 4u64); + assert_eq!(staking::current_era(), 3u64); + }); + } + + #[test] + fn staking_balance_works() { + let one = one(); + let two = two(); + + let mut t = TestExternalities { storage: map![ + twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].join(&42u64) + ], }; + + with_externalities(&mut t, || { + assert_eq!(staking::balance(&one), 42); + assert_eq!(staking::balance(&two), 0); + }); + } + + #[test] + fn staking_balance_transfer_works() { + let one = one(); + let two = two(); + + let mut t = TestExternalities { storage: map![ + twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].join(&111u64) + ], }; + + with_externalities(&mut t, || { + staking::transfer(&one, &two, 69); + assert_eq!(staking::balance(&one), 42); + assert_eq!(staking::balance(&two), 69); + }); + } + + #[test] + #[should_panic] + fn staking_balance_transfer_when_bonded_doesnt_work() { + let one = one(); + let two = two(); + + let mut t = TestExternalities { storage: map![ + twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].join(&111u64) + ], }; + + with_externalities(&mut t, || { + staking::stake(&one); + staking::transfer(&one, &two, 69); + }); + } +} diff --git a/substrate/wasm-runtime/polkadot/src/runtime/system.rs b/substrate/wasm-runtime/polkadot/src/runtime/system.rs new file mode 100644 index 0000000000..5ffa03ed81 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/runtime/system.rs @@ -0,0 +1,154 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! System manager: Handles all of the top-level stuff; executing block/transaction, setting code +//! and depositing logs. + +use primitives::{Block, BlockNumber, Hash, UncheckedTransaction, TxOrder, Hashable}; +use runtime_support::{Vec, swap}; +use storable::Storable; +use keyedvec::KeyedVec; +use environment::with_env; +use runtime::{staking, session}; + +/// 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 { + Storable::lookup_default(&number.to_keyed_vec(b"sys:old:")) +} + +/// Deposits a log and ensures it matches the blocks log data. +pub fn deposit_log(log: &[u8]) { + with_env(|e| { + assert_eq!(log, &e.digest.logs[e.next_log_index][..]); + e.next_log_index += 1; + }); +} + +pub fn execute_block(mut block: Block) { + // populate environment from header. + with_env(|e| { + e.block_number = block.header.number; + swap(&mut e.digest, &mut block.header.digest); + e.next_log_index = 0; + }); + + 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." + ); + + // TODO: check transaction trie root represents the transactions. + // this requires non-trivial changes to the externals API or compiling trie rooting into wasm + // so will wait until a little later. + + // store the header hash in storage. + let header_hash_key = header.number.to_keyed_vec(b"sys:old:"); + header.blake2_256().store(&header_hash_key); + + // execute transactions + block.transactions.iter().for_each(execute_transaction); + + staking::check_new_era(); + session::check_rotate_session(); + + // any final checks + final_checks(&block); + + // TODO: check storage root. + // this requires non-trivial changes to the externals API or compiling trie rooting into wasm + // so will wait until a little later. +} + +/// Execute a given transaction. +pub fn execute_transaction(utx: &UncheckedTransaction) { + // Verify the signature is good. + assert!(utx.ed25519_verify(), "All transactions should be properly signed"); + + let ref tx = utx.transaction; + + // check nonce + let nonce_key = tx.signed.to_keyed_vec(b"sys:non:"); + let expected_nonce: TxOrder = Storable::lookup_default(&nonce_key); + assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce"); + + // increment nonce in storage + (expected_nonce + 1).store(&nonce_key); + + // decode parameters and dispatch + tx.function.dispatch(&tx.signed, &tx.input_data); +} + +/// Set the new code. +pub fn set_code(new: &[u8]) { + new.store(b":code"); +} + +fn final_checks(_block: &Block) { + with_env(|e| { + assert_eq!(e.next_log_index, e.digest.logs.len()); + }); +} + +#[cfg(test)] +mod tests { + use joiner::Joiner; + use function::Function; + use keyedvec::KeyedVec; + use slicable::Slicable; + use runtime_support::{with_externalities, twox_128}; + use primitives::{UncheckedTransaction, Transaction}; + use statichex::StaticHexInto; + use runtime::{system, staking}; + use testing::{TestExternalities, HexDisplay, one, two}; + + #[test] + fn staking_balance_transfer_dispatch_works() { + let one = one(); + let two = two(); + + let mut t = TestExternalities { storage: map![ + twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] + ], }; + + let tx = UncheckedTransaction { + transaction: Transaction { + signed: one.clone(), + nonce: 0, + function: Function::StakingTransfer, + input_data: vec![].join(&two).join(&69u64), + }, + signature: "679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a".convert(), + }; + // tx: 2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000 + // sig: 679fcf0a846b4224c84ecad7d91a26241c46d00cb53d6480a363274e8965ee34b0b80b4b2e3836d3d8f8f12c0c1aef7350af587d9aee3883561d11726068ac0a + + println!("tx is {}", HexDisplay::from(&tx.transaction.to_vec())); + + with_externalities(&mut t, || { + system::execute_transaction(&tx); + assert_eq!(staking::balance(&one), 42); + assert_eq!(staking::balance(&two), 69); + }); + } +} diff --git a/substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs b/substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs new file mode 100644 index 0000000000..7040473b1a --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs @@ -0,0 +1,54 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Timestamp manager: just handles the current timestamp. + +use storable::Storable; + +/// Representation of a time. +pub type Timestamp = u64; + +/// Get the current time. +pub fn get() -> Timestamp { + Storable::lookup_default(b"tim:val") +} + +/// Set the current time. +pub fn set(now: Timestamp) { + now.store(b"tim:val") +} + +#[cfg(test)] +mod tests { + use joiner::Joiner; + use keyedvec::KeyedVec; + use runtime_support::{with_externalities, twox_128}; + use runtime::timestamp; + use testing::TestExternalities; + + #[test] + fn timestamp_works() { + let mut t = TestExternalities { storage: map![ + twox_128(b"tim:val").to_vec() => vec![].join(&42u64) + ], }; + + with_externalities(&mut t, || { + assert_eq!(timestamp::get(), 42); + timestamp::set(69); + assert_eq!(timestamp::get(), 69); + }); + } +} diff --git a/substrate/wasm-runtime/polkadot/src/support/environment.rs b/substrate/wasm-runtime/polkadot/src/support/environment.rs new file mode 100644 index 0000000000..c01a1f4e92 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/support/environment.rs @@ -0,0 +1,78 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Environment API: Allows certain information to be accessed throughout the runtime. + +use runtime_support::{Rc, RefCell, transmute, Box}; +use primitives::{BlockNumber, Digest}; + +#[derive(Default)] +/// The information that can be accessed globally. +pub struct Environment { + /// The current block number. + pub block_number: BlockNumber, + /// The current block digest. + pub digest: Digest, + /// The number of log items in this block that have been accounted for so far. + pub next_log_index: usize, +} + +/// Do something with the environment and return its value. Keep the function short. +pub fn with_env T>(f: F) -> T { + let e = env(); + let mut eb = e.borrow_mut(); + f(&mut *eb) +} + +#[cfg(not(test))] +fn env() -> Rc> { + // Initialize it to a null value + static mut SINGLETON: *const Rc> = 0 as *const Rc>; + + unsafe { + if SINGLETON == 0 as *const Rc> { + // Make it + let singleton: Rc> = Rc::new(RefCell::new(Default::default())); + + // Put it in the heap so it can outlive this call + SINGLETON = transmute(Box::new(singleton)); + } + + // Now we give out a copy of the data that is safe to use concurrently. + (*SINGLETON).clone() + } +} + +#[cfg(test)] +fn env() -> Rc> { + // Initialize it to a null value + thread_local!{ + static SINGLETON: RefCell<*const Rc>> = RefCell::new(0 as *const Rc>); + } + + SINGLETON.with(|s| unsafe { + if *s.borrow() == 0 as *const Rc> { + // Make it + let singleton: Rc> = Rc::new(RefCell::new(Default::default())); + + // Put it in the heap so it can outlive this call + *s.borrow_mut() = transmute(Box::new(singleton)); + } + + // Now we give out a copy of the data that is safe to use concurrently. + (**s.borrow()).clone() + }) +} diff --git a/substrate/wasm-runtime/polkadot/src/support/function.rs b/substrate/wasm-runtime/polkadot/src/support/function.rs new file mode 100644 index 0000000000..f4ee9c79e6 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/support/function.rs @@ -0,0 +1,74 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Function data: This describes a function that can be called from an external transaction. + +use primitives::AccountID; +use streamreader::StreamReader; +use runtime::{staking, session, timestamp}; + +/// The functions that a transaction can call (and be dispatched to). +#[cfg_attr(test, derive(PartialEq, Debug))] +#[derive(Clone, Copy)] +pub enum Function { + StakingStake, + StakingUnstake, + StakingTransfer, + SessionSetKey, + TimestampSet, +} + +impl Function { + /// Derive `Some` value from a `u8`, or `None` if it's invalid. + pub fn from_u8(value: u8) -> Option { + match value { + x if x == Function::StakingStake as u8 => Some(Function::StakingStake), + x if x == Function::StakingUnstake as u8 => Some(Function::StakingUnstake), + x if x == Function::StakingTransfer as u8 => Some(Function::StakingTransfer), + x if x == Function::SessionSetKey as u8 => Some(Function::SessionSetKey), + x if x == Function::TimestampSet as u8 => Some(Function::TimestampSet), + _ => None, + } + } +} + +impl Function { + /// Dispatch the function. + pub fn dispatch(&self, transactor: &AccountID, data: &[u8]) { + let mut params = StreamReader::new(data); + match *self { + Function::StakingStake => { + staking::stake(transactor); + } + Function::StakingUnstake => { + staking::unstake(transactor); + } + Function::StakingTransfer => { + let dest = params.read().unwrap(); + let value = params.read().unwrap(); + staking::transfer(transactor, &dest, value); + } + Function::SessionSetKey => { + let session = params.read().unwrap(); + session::set_key(transactor, &session); + } + Function::TimestampSet => { + let t = params.read().unwrap(); + timestamp::set(t); + } + } + } +} diff --git a/substrate/wasm-runtime/polkadot/src/support/mod.rs b/substrate/wasm-runtime/polkadot/src/support/mod.rs new file mode 100644 index 0000000000..56ad3a355c --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/support/mod.rs @@ -0,0 +1,28 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Support code for the runtime. + +pub mod primitives; +pub mod function; +pub mod environment; +pub mod storable; + +#[cfg(test)] +pub mod statichex; +#[cfg(test)] +#[macro_use] +pub mod testing; diff --git a/substrate/wasm-runtime/polkadot/src/support/primitives.rs b/substrate/wasm-runtime/polkadot/src/support/primitives.rs new file mode 100644 index 0000000000..3ab385d488 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/support/primitives.rs @@ -0,0 +1,515 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Primitive types. + +use runtime_support::Vec; +use streamreader::StreamReader; +use joiner::Joiner; +use slicable::{Slicable, NonTrivialSlicable}; +use function::Function; +use runtime_support::{size_of, blake2_256, twox_128, twox_256, ed25519_verify}; + +#[cfg(test)] +use std::fmt; + +/// The Ed25519 pubkey that identifies an account. +pub type AccountID = [u8; 32]; +/// The Ed25519 pub key of an session that belongs to an authority. This is used as what the +/// external environment/consensus algorithm calls an "authority". +pub type SessionKey = AccountID; +/// Indentifier for a chain. +pub type ChainID = u64; +/// Index of a block in the chain. +pub type BlockNumber = u64; +/// Index of a transaction. +pub type TxOrder = u64; +/// A hash of some data. +pub type Hash = [u8; 32]; + +#[derive(Clone, Default)] +#[cfg_attr(test, derive(PartialEq, Debug))] +/// The digest of a block, useful for light-clients. +pub struct Digest { + /// All logs that have happened in the block. + pub logs: Vec>, +} + +#[derive(Clone)] +#[cfg_attr(test, derive(PartialEq, Debug))] +/// The header for a block. +pub struct Header { + /// The parent block's "hash" (actually the Blake2-256 hash of its serialised header). + pub parent_hash: Hash, + /// The block's number (how many ancestors does it have?). + pub number: BlockNumber, + /// The root of the trie that represents this block's final storage map. + pub state_root: Hash, + /// The root of the trie that represents this block's transactions, indexed by a 32-bit integer. + pub transaction_root: Hash, + /// The digest for this block. + pub digest: Digest, +} + +impl Slicable for Header { + fn from_slice(value: &[u8]) -> Option { + let mut reader = StreamReader::new(value); + Some(Header { + parent_hash: reader.read()?, + number: reader.read()?, + state_root: reader.read()?, + transaction_root: reader.read()?, + digest: Digest { logs: reader.read()?, }, + }) + } + + fn set_as_slice bool>(_fill_slice: F) -> Option { + unimplemented!(); + } + + fn to_vec(&self) -> Vec { + Vec::new() + .join(&self.parent_hash) + .join(&self.number) + .join(&self.state_root) + .join(&self.transaction_root) + .join(&self.digest.logs) + } + + fn size_of(data: &[u8]) -> Option { + let first_part = size_of::() + size_of::() + size_of::() + size_of::(); + let second_part = >>::size_of(&data[first_part..])?; + Some(first_part + second_part) + } +} + +impl NonTrivialSlicable for Header {} + +#[cfg_attr(test, derive(PartialEq, Debug))] +/// A vetted and verified transaction from the external world. +pub struct Transaction { + /// Who signed it (note this is not a signature). + pub signed: AccountID, + /// The number of transactions have come before from the same signer. + pub nonce: TxOrder, + /// The function that should be called. + pub function: Function, + /// Serialised input data to the function. + pub input_data: Vec, +} + +impl Slicable for Transaction { + fn from_slice(value: &[u8]) -> Option { + let mut reader = StreamReader::new(value); + Some(Transaction { + signed: reader.read()?, + nonce: reader.read()?, + function: Function::from_u8(reader.read()?)?, + input_data: reader.read()?, + }) + } + + fn set_as_slice bool>(_fill_slice: F) -> Option { + unimplemented!(); + } + + fn to_vec(&self) -> Vec { + Vec::new() + .join(&self.signed) + .join(&self.nonce) + .join(&(self.function as u8)) + .join(&self.input_data) + } + + fn size_of(data: &[u8]) -> Option { + let first_part = size_of::() + size_of::() + size_of::(); + let second_part = >::size_of(&data[first_part..])?; + Some(first_part + second_part) + } +} + +pub trait Hashable: Sized { + fn blake2_256(&self) -> [u8; 32]; + fn twox_128(&self) -> [u8; 16]; + fn twox_256(&self) -> [u8; 32]; +} + +impl Hashable for T { + fn blake2_256(&self) -> [u8; 32] { + blake2_256(&self.to_vec()) + } + fn twox_128(&self) -> [u8; 16] { + twox_128(&self.to_vec()) + } + fn twox_256(&self) -> [u8; 32] { + twox_256(&self.to_vec()) + } +} + +impl NonTrivialSlicable for Transaction {} + +/// A transactions right from the external world. Unchecked. +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: [u8; 64], +} + +impl UncheckedTransaction { + /// Verify the signature. + pub fn ed25519_verify(&self) -> bool { + let msg = self.transaction.to_vec(); + ed25519_verify(&self.signature, &msg, &self.transaction.signed) + } +} + +#[cfg(test)] +impl PartialEq for UncheckedTransaction { + fn eq(&self, other: &Self) -> bool { + self.signature.iter().eq(other.signature.iter()) && self.transaction == other.transaction + } +} + +#[cfg(test)] +impl fmt::Debug for UncheckedTransaction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "UncheckedTransaction({:?})", self.transaction) + } +} + +impl Slicable for UncheckedTransaction { + fn from_slice(value: &[u8]) -> Option { + let mut reader = StreamReader::new(value); + Some(UncheckedTransaction { + signature: reader.read()?, + transaction: reader.read()?, + }) + } + + fn set_as_slice bool>(_fill_slice: F) -> Option { + unimplemented!(); + } + + fn to_vec(&self) -> Vec { + Vec::new() + .join(&self.signature) + .join(&self.transaction) + } + + fn size_of(data: &[u8]) -> Option { + let first_part = size_of::<[u8; 64]>(); + let second_part = ::size_of(&data[first_part..])?; + Some(first_part + second_part) + } +} + +impl NonTrivialSlicable for UncheckedTransaction {} + +#[cfg_attr(test, derive(PartialEq, Debug))] +/// A Polkadot relay chain block. +pub struct Block { + /// The header of the block. + pub header: Header, + /// All transactions. + pub transactions: Vec, +} + +impl Slicable for Block { + fn from_slice(value: &[u8]) -> Option { + let mut reader = StreamReader::new(value); + Some(Block { + header: reader.read()?, + transactions: reader.read()?, + }) + } + + fn set_as_slice bool>(_fill_slice: F) -> Option { + unimplemented!(); + } + + fn to_vec(&self) -> Vec { + Vec::new() + .join(&self.header) + .join(&self.transactions) + } + + fn size_of(data: &[u8]) -> Option { + let first_part = Header::size_of(data)?; + let second_part = >::size_of(&data[first_part..])?; + Some(first_part + second_part) + } +} + +impl NonTrivialSlicable for Block {} + +impl NonTrivialSlicable for Vec where Vec: Slicable {} + +impl Slicable for Vec { + fn from_slice(value: &[u8]) -> Option { + let len = Self::size_of(&value[0..4])?; + let mut off = 4; + let mut r = Vec::new(); + while off < len { + let element_len = T::size_of(&value[off..])?; + r.push(T::from_slice(&value[off..off + element_len])?); + off += element_len; + } + Some(r) + } + + fn set_as_slice bool>(_fill_slice: F) -> Option { + unimplemented!(); + } + + fn to_vec(&self) -> Vec { + let vecs = self.iter().map(Slicable::to_vec).collect::>(); + let len = vecs.iter().fold(0, |mut a, v| {a += v.len(); a}); + let mut r = Vec::new().join(&(len as u32)); + vecs.iter().for_each(|v| r.extend_from_slice(v)); + r + } + + fn size_of(data: &[u8]) -> Option { + u32::from_slice(&data[0..4]).map(|i| (i + 4) as usize) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use joiner::Joiner; + use function::Function; + + #[test] + fn serialise_transaction_works() { + let one: AccountID = [1u8; 32]; + let two: AccountID = [2u8; 32]; + let tx = Transaction { + signed: one.clone(), + nonce: 69, + function: Function::StakingTransfer, + input_data: Vec::new().join(&two).join(&69u64), + }; + let serialised = tx.to_vec(); + assert_eq!(serialised, vec![ + 1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 69, 0, 0, 0, 0, 0, 0, 0, + 2, + 40, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 69, 0, 0, 0, 0, 0, 0, 0 + ]); + } + + #[test] + fn deserialise_transaction_works() { + let one: AccountID = [1u8; 32]; + let two: AccountID = [2u8; 32]; + let tx = Transaction { + signed: one.clone(), + nonce: 69, + function: Function::StakingTransfer, + input_data: Vec::new().join(&two).join(&69u64), + }; + let data = [ + 1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 69, 0, 0, 0, 0, 0, 0, 0, + 2, + 40, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 69, 0, 0, 0, 0, 0, 0, 0 + ]; + let deserialised = Transaction::from_slice(&data).unwrap(); + assert_eq!(deserialised, tx); + } + + #[test] + fn serialise_header_works() { + let h = Header { + parent_hash: [4u8; 32], + number: 42, + state_root: [5u8; 32], + transaction_root: [6u8; 32], + digest: Digest { logs: vec![ b"one log".to_vec(), b"another log".to_vec() ], }, + }; + let serialised = h.to_vec(); + assert_eq!(serialised, vec![ + 4u8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 42, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 26, 0, 0, 0, + 7, 0, 0, 0, + 111, 110, 101, 32, 108, 111, 103, + 11, 0, 0, 0, + 97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103 + ]); + } + + #[test] + fn deserialise_header_works() { + let h = Header { + parent_hash: [4u8; 32], + number: 42, + state_root: [5u8; 32], + transaction_root: [6u8; 32], + digest: Digest { logs: vec![ b"one log".to_vec(), b"another log".to_vec() ], }, + }; + let data = [ + 4u8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 42, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 26, 0, 0, 0, + 7, 0, 0, 0, + 111, 110, 101, 32, 108, 111, 103, + 11, 0, 0, 0, + 97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103 + ]; + let deserialised = Header::from_slice(&data).unwrap(); + assert_eq!(deserialised, h); + } + + #[test] + fn serialise_block_works() { + let one: AccountID = [1u8; 32]; + let two: AccountID = [2u8; 32]; + let tx1 = UncheckedTransaction { + transaction: Transaction { + signed: one.clone(), + nonce: 69, + function: Function::StakingTransfer, + input_data: Vec::new().join(&two).join(&69u64), + }, + signature: [1u8; 64], + }; + let tx2 = UncheckedTransaction { + transaction: Transaction { + signed: two.clone(), + nonce: 42, + function: Function::StakingStake, + input_data: Vec::new(), + }, + signature: [2u8; 64], + }; + let h = Header { + parent_hash: [4u8; 32], + number: 42, + state_root: [5u8; 32], + transaction_root: [6u8; 32], + digest: Digest { logs: vec![ b"one log".to_vec(), b"another log".to_vec() ], }, + }; + let b = Block { + header: h, + transactions: vec![tx1, tx2], + }; + let serialised = b.to_vec(); + assert_eq!(serialised, vec![ + // header + 4u8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 42, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 26, 0, 0, 0, + 7, 0, 0, 0, + 111, 110, 101, 32, 108, 111, 103, + 11, 0, 0, 0, + 97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103, + // transactions + 2, 1, 0, 0, + // tx1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 69, 0, 0, 0, 0, 0, 0, 0, + 2, + 40, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 69, 0, 0, 0, 0, 0, 0, 0, + // tx2 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 42, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, 0, 0, 0 + ]); + } + + #[test] + fn deserialise_block_works() { + let one: AccountID = [1u8; 32]; + let two: AccountID = [2u8; 32]; + let tx1 = UncheckedTransaction { + transaction: Transaction { + signed: one.clone(), + nonce: 69, + function: Function::StakingTransfer, + input_data: Vec::new().join(&two).join(&69u64), + }, + signature: [1u8; 64], + }; + let tx2 = UncheckedTransaction { + transaction: Transaction { + signed: two.clone(), + nonce: 42, + function: Function::StakingStake, + input_data: Vec::new(), + }, + signature: [2u8; 64], + }; + let h = Header { + parent_hash: [4u8; 32], + number: 42, + state_root: [5u8; 32], + transaction_root: [6u8; 32], + digest: Digest { logs: vec![ b"one log".to_vec(), b"another log".to_vec() ], }, + }; + let b = Block { + header: h, + transactions: vec![tx1, tx2], + }; + let data = [ + // header + 4u8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 42, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 26, 0, 0, 0, + 7, 0, 0, 0, + 111, 110, 101, 32, 108, 111, 103, + 11, 0, 0, 0, + 97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103, + // transactions + 2, 1, 0, 0, + // tx1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 69, 0, 0, 0, 0, 0, 0, 0, + 2, + 40, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 69, 0, 0, 0, 0, 0, 0, 0, + // tx2 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 42, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, 0, 0, 0 + ]; + let deserialised = Block::from_slice(&data).unwrap(); + assert_eq!(deserialised, b); + } +} diff --git a/substrate/wasm-runtime/polkadot/src/support/statichex.rs b/substrate/wasm-runtime/polkadot/src/support/statichex.rs new file mode 100644 index 0000000000..152ceadc0b --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/support/statichex.rs @@ -0,0 +1,52 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Interpret a static string of hex as a desired type. + +use rustc_hex::FromHex; + +/// Trait to allow conversion from a static hex string to an instance. +pub trait StaticHexConversion: Sized { + /// Convert the static str into Self. Use just like `From::from`. + fn from_static_hex(hex: &'static str) -> Self; +} + +macro_rules! impl_sizes { + ( $( $t:expr ),* ) => { $( + impl StaticHexConversion for [u8; $t] { + fn from_static_hex(hex: &'static str) -> Self { + let mut r = [0u8; $t]; + r.copy_from_slice(&FromHex::from_hex(hex).unwrap()); + r + } + } + )* } +} + +impl_sizes!(1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128); + +/// Trait to allow converting from itself (only implemented for a static str) into some useful +/// type (which must implement `StaticHexConversion`). +pub trait StaticHexInto { + /// Convert self (i.e. a static str) into the appropriate type. Use just like `Into::into`. + fn convert(self) -> T; +} + +impl StaticHexInto for &'static str { + fn convert(self) -> T { + T::from_static_hex(self) + } +} diff --git a/substrate/wasm-runtime/polkadot/src/support/storable.rs b/substrate/wasm-runtime/polkadot/src/support/storable.rs new file mode 100644 index 0000000000..3caf3ed19b --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/support/storable.rs @@ -0,0 +1,87 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Stuff to do with the runtime's storage. + +use slicable::Slicable; +use endiansensitive::EndianSensitive; +use keyedvec::KeyedVec; +use runtime_support::{self, twox_128, Vec}; + +/// Trait for a value which may be stored in the storage DB. +pub trait Storable { + /// Lookup the value in storage and deserialise, giving a default value if not found. + fn lookup_default(key: &[u8]) -> Self where Self: Sized + Default { Self::lookup(key).unwrap_or_else(Default::default) } + /// Lookup `Some` value in storage and deserialise; `None` if it's not there. + fn lookup(_key: &[u8]) -> Option where Self: Sized { unimplemented!() } + /// Place the value in storage under `key`. + fn store(&self, key: &[u8]); +} + +// TODO: consider using blake256 to avoid possible eclipse attack. + +/// Remove `key` from storage. +pub fn kill(key: &[u8]) { runtime_support::set_storage(&twox_128(key)[..], b""); } + +impl Storable for T { + fn lookup(key: &[u8]) -> Option { + Slicable::set_as_slice(|out| runtime_support::read_storage(&twox_128(key)[..], out) == out.len()) + } + fn store(&self, key: &[u8]) { + self.as_slice_then(|slice| runtime_support::set_storage(&twox_128(key)[..], slice)); + } +} + +impl Storable for [u8] { + fn store(&self, key: &[u8]) { + runtime_support::set_storage(&twox_128(key)[..], self) + } +} + +/// A trait to conveniently store a vector of storable data. +// TODO: add iterator support +pub trait StorageVec { + type Item: Default + Sized + Storable; + const PREFIX: &'static [u8]; + + /// Get the current set of items. + fn items() -> Vec { + (0..Self::count()).into_iter().map(Self::item).collect() + } + + /// Set the current set of items. + fn set_items(items: &[Self::Item]) { + Self::set_count(items.len() as u32); + items.iter().enumerate().for_each(|(v, ref i)| Self::set_item(v as u32, i)); + } + + fn set_item(index: u32, item: &Self::Item) { + item.store(&index.to_keyed_vec(Self::PREFIX)); + } + + fn item(index: u32) -> Self::Item { + Storable::lookup_default(&index.to_keyed_vec(Self::PREFIX)) + } + + fn set_count(count: u32) { + (count..Self::count()).for_each(|i| Self::set_item(i, &Self::Item::default())); + count.store(&b"len".to_keyed_vec(Self::PREFIX)); + } + + fn count() -> u32 { + Storable::lookup_default(&b"len".to_keyed_vec(Self::PREFIX)) + } +} diff --git a/substrate/wasm-runtime/polkadot/src/support/testing.rs b/substrate/wasm-runtime/polkadot/src/support/testing.rs new file mode 100644 index 0000000000..e2e7b40562 --- /dev/null +++ b/substrate/wasm-runtime/polkadot/src/support/testing.rs @@ -0,0 +1,106 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Testing helpers. + +use runtime_support::{NoError, Externalities}; +use std::collections::HashMap; +use primitives::AccountID; +use statichex::StaticHexInto; + +#[derive(Debug, Default)] +/// Simple externaties implementation. +pub struct TestExternalities { + /// The storage map. + pub storage: HashMap, Vec>, +} + +impl Externalities for TestExternalities { + type Error = NoError; + + fn storage(&self, key: &[u8]) -> Result<&[u8], NoError> { + Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice)) + } + + fn set_storage(&mut self, key: Vec, value: Vec) { + self.storage.insert(key, value); + } + + fn chain_id(&self) -> u64 { 42 } +} + +#[macro_export] +macro_rules! map { + ($( $name:expr => $value:expr ),*) => ( + vec![ $( ( $name, $value ) ),* ].into_iter().collect() + ) +} + +/// One account (to which we know the secret key). +pub fn one() -> AccountID { + "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee".convert() +} +/// Another account (secret key known). +pub fn two() -> AccountID { + "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a".convert() +} + +/// Hex display, this time for no_std. See main codebase for documentation. +pub struct HexDisplay<'a>(&'a [u8]); + +impl<'a> HexDisplay<'a> { + /// See main codebase for documentation. + pub fn from(d: &'a AsBytesRef) -> Self { HexDisplay(d.as_bytes_ref()) } +} + +impl<'a> ::std::fmt::Display for HexDisplay<'a> { + fn fmt(&self, fmtr: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + for byte in self.0 { + try!( fmtr.write_fmt(format_args!("{:02x}", byte))); + } + Ok(()) + } +} + +/// See main codebase for documentation. +pub trait AsBytesRef { + /// See main codebase for documentation. + fn as_bytes_ref(&self) -> &[u8]; +} + +impl AsBytesRef for [u8] { + fn as_bytes_ref(&self) -> &[u8] { &self } +} + +impl<'a> AsBytesRef for &'a[u8] { + fn as_bytes_ref(&self) -> &[u8] { self } +} + +impl AsBytesRef for Vec { + fn as_bytes_ref(&self) -> &[u8] { &self[..] } +} + +macro_rules! impl_non_endians { + ( $( $t:ty ),* ) => { $( + impl AsBytesRef for $t { + fn as_bytes_ref(&self) -> &[u8] { &self[..] } + } + )* } +} + +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]); diff --git a/substrate/runtime/pwasm-alloc/Cargo.toml b/substrate/wasm-runtime/pwasm-alloc/Cargo.toml similarity index 100% rename from substrate/runtime/pwasm-alloc/Cargo.toml rename to substrate/wasm-runtime/pwasm-alloc/Cargo.toml diff --git a/substrate/runtime/pwasm-alloc/README.md b/substrate/wasm-runtime/pwasm-alloc/README.md similarity index 100% rename from substrate/runtime/pwasm-alloc/README.md rename to substrate/wasm-runtime/pwasm-alloc/README.md diff --git a/substrate/runtime/pwasm-alloc/src/lib.rs b/substrate/wasm-runtime/pwasm-alloc/src/lib.rs similarity index 100% rename from substrate/runtime/pwasm-alloc/src/lib.rs rename to substrate/wasm-runtime/pwasm-alloc/src/lib.rs diff --git a/substrate/runtime/pwasm-libc/Cargo.toml b/substrate/wasm-runtime/pwasm-libc/Cargo.toml similarity index 100% rename from substrate/runtime/pwasm-libc/Cargo.toml rename to substrate/wasm-runtime/pwasm-libc/Cargo.toml diff --git a/substrate/runtime/pwasm-libc/README.md b/substrate/wasm-runtime/pwasm-libc/README.md similarity index 100% rename from substrate/runtime/pwasm-libc/README.md rename to substrate/wasm-runtime/pwasm-libc/README.md diff --git a/substrate/runtime/pwasm-libc/src/lib.rs b/substrate/wasm-runtime/pwasm-libc/src/lib.rs similarity index 100% rename from substrate/runtime/pwasm-libc/src/lib.rs rename to substrate/wasm-runtime/pwasm-libc/src/lib.rs diff --git a/substrate/runtime/support/Cargo.toml b/substrate/wasm-runtime/support/Cargo.toml similarity index 100% rename from substrate/runtime/support/Cargo.toml rename to substrate/wasm-runtime/support/Cargo.toml diff --git a/substrate/wasm-runtime/support/src/lib.rs b/substrate/wasm-runtime/support/src/lib.rs new file mode 100644 index 0000000000..b65b574351 --- /dev/null +++ b/substrate/wasm-runtime/support/src/lib.rs @@ -0,0 +1,144 @@ +#![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; +pub use alloc::boxed::Box; +pub use alloc::rc::Rc; +pub use core::mem::{transmute, size_of, uninitialized, swap}; +pub use core::slice; +pub use core::cell::{RefCell, Ref, RefMut}; + +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_chain_id() -> u64; + fn ext_blake2_256(data: *const u8, len: u32, out: *mut u8); + fn ext_twox_128(data: *const u8, len: u32, out: *mut u8); + fn ext_twox_256(data: *const u8, len: u32, out: *mut u8); + fn ext_ed25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32; +} + +pub fn storage(key: &[u8]) -> Vec { + 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 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 read_storage(key: &[u8], value_out: &mut [u8]) -> usize { + unsafe { + ext_get_storage_into(&key[0], key.len() as u32, &mut value_out[0], value_out.len() as u32) as usize + } +} + +/// The current relay chain identifier. +pub fn chain_id() -> u64 { + unsafe { + ext_chain_id() + } +} + +/// Conduct a 256-bit Blake2 hash. +pub fn blake2_256(data: &[u8]) -> [u8; 32] { + unsafe { + let mut result: [u8; 32] = uninitialized(); + // guaranteed to write into result. + ext_blake2_256(&data[0], data.len() as u32, &mut result[0]); + result + } +} + +/// Conduct four XX hashes to give a 256-bit result. +pub fn twox_256(data: &[u8]) -> [u8; 32] { + unsafe { + let mut result: [u8; 32] = uninitialized(); + // guaranteed to write into result. + ext_twox_256(&data[0], data.len() as u32, &mut result[0]); + result + } +} + +/// Conduct two XX hashes to give a 256-bit result. +pub fn twox_128(data: &[u8]) -> [u8; 16] { + unsafe { + let mut result: [u8; 16] = uninitialized(); + // guaranteed to write into result. + ext_twox_128(&data[0], data.len() as u32, &mut result[0]); + result + } +} + +/// Verify a ed25519 signature. +pub fn ed25519_verify(sig: &[u8], msg: &[u8], pubkey: &[u8]) -> bool { + sig.len() != 64 || pubkey.len() != 32 || unsafe { + ext_ed25519_verify(&msg[0], msg.len() as u32, &sig[0], &pubkey[0]) + } == 0 +} + +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(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) + } + )* + } + } +} diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm new file mode 100644 index 0000000000000000000000000000000000000000..ddd9dc70e64e3b02e101f88ad65bd0a5af897e86 GIT binary patch literal 37802 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 l%ICi)EdL}0AhR)4Uko=-o_{d)t literal 0 HcmV?d00001 diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8d3d3fb1ee5ffba092f881fdbe5e5c3780f7d23b GIT binary patch literal 37859 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 literal 0 HcmV?d00001 diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm new file mode 100644 index 0000000000000000000000000000000000000000..5c717847a5a2dfb1d4b0e0db128b5a2cb9c57aaf GIT binary patch literal 1460 zcmd^9y>in)5Z?RIUrvcHAq8}2S5Cp;c=87fGd^b0Q`5)_mV@M2%Gk! zM%&$kdPnzEy~)7$=iAHbS>_lpf#rA7w~R=#`wH^%tPf`vAh zR*za@564Zbv}28R3>c2pfU*F*K3qCd!fcngt zv)Jz~j9M;DLQUgZlWD-=CuH_<)~Xq_wgC3|+@Z4;uco5>1BairMD6ew4&!ct+2=jv zQ4sgC#qXq0#xZ;WF&J|(hZx3txFjaPED}H@?Bj1T)G~4bbY`3d@UvPJr`>15wYRXG ziW~V)sqp`!RD5Baq5~FM4|fC9o0>H_>N3<7bTshH9MY+vf(v@0_D;SSr1&Pw?0^@IR^D9+deadD0JdA{irH)iT@SxAHtRB!32`ER z_`(PzvkzSW{*#5mrWX(FRURFm^@g?`wfFV`2;3mh_S<`VJI|vFJBbI^z{n7gVKA{4 zIH^xaJ+*n%J3Grxdb#aK(>$B>PAv$sSIItdM(~z^9i5D?3lHf$>}Zr-+>5cJsm%+Q z3b~9YahgMkIBKM$b&<*^G$b^?%&wxH_F?fCOQ`s|>LzvrX9`$>9FN#wLYffFM&)S+pTqdG@u%c7u+NQJrQ9QLiIY-)Kdm5+Fd3qVA zeORZQREUi-3a$W~1ksOg`FB-&=(%b?sxYYjD9dk*@tFYwP3{>rY>0haw~SPQ(Waz9 zGgUE7Q&xc%2KISqT1KE4CQ8(~7EK=3*~p#!n19g^d?L ziigTGrd~P)Q-?Svnk%jWU#7SLOra9oi)LS6-{A8LKGr0F{KQ#lvEN%5HhgkIPVF0= zD8S`AB<69_C=isk0S@@wpppi6u1J5+5F`yz7=ndC``e%ocn5JL#Jz0uJ1V3pX}(Y~ z7;7*g{Z*Yb_jv9aPH>x(2%r{eJpDNe`dIhdv_&o5ikl46i$ WV0NWA?!5Kyzy2GM3oUE_ literal 0 HcmV?d00001 diff --git a/substrate/runtime/test/Cargo.toml b/substrate/wasm-runtime/test/Cargo.toml similarity index 100% rename from substrate/runtime/test/Cargo.toml rename to substrate/wasm-runtime/test/Cargo.toml diff --git a/substrate/wasm-runtime/test/src/lib.rs b/substrate/wasm-runtime/test/src/lib.rs new file mode 100644 index 0000000000..1cf1934976 --- /dev/null +++ b/substrate/wasm-runtime/test/src/lib.rs @@ -0,0 +1,46 @@ +#![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, blake2_256, twox_128, twox_256, ed25519_verify}; + +fn test_blake2_256(input: Vec) -> Vec { + blake2_256(&input).to_vec() +} + +fn test_twox_256(input: Vec) -> Vec { + twox_256(&input).to_vec() +} + +fn test_twox_128(input: Vec) -> Vec { + twox_128(&input).to_vec() +} + +fn test_ed25519_verify(input: Vec) -> Vec { + let sig = &input[0..64]; + let pubkey = &input[64..96]; + let msg = b"all ok!"; + [ed25519_verify(sig, &msg[..], pubkey) as u8].to_vec() +} + +fn test_data_in(input: Vec) -> Vec { + print(b"set_storage" as &[u8]); + set_storage(b"input", &input); + + print(b"storage" as &[u8]); + let foo = storage(b"foo"); + + print(b"set_storage" as &[u8]); + set_storage(b"baz", &foo); + + print(b"finished!" as &[u8]); + b"all ok!".to_vec() +} + +impl_stubs!(test_data_in, test_blake2_256, test_twox_256, test_twox_128, test_ed25519_verify);