mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
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
This commit is contained in:
committed by
Arkadiy Paronyan
parent
28d84d8ac4
commit
3402f169a7
@@ -1,5 +1,5 @@
|
||||
/target/
|
||||
**/*.rs.bk
|
||||
*.swp
|
||||
runtime/**/target/
|
||||
wasm-runtime/**/target/
|
||||
**/._*
|
||||
|
||||
Generated
+148
-2
@@ -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)" = "<none>"
|
||||
"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"
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[package]
|
||||
name = "environmental"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<T: ?Sized, R, F: FnOnce() -> R>(
|
||||
global: &'static LocalKey<RefCell<Option<*mut T>>>,
|
||||
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<Option<*mut T>>,
|
||||
}
|
||||
|
||||
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<T: ?Sized, R, F: FnOnce(&mut T) -> R>(
|
||||
global: &'static LocalKey<RefCell<Option<*mut T>>>,
|
||||
mutator: F,
|
||||
) -> Option<R> {
|
||||
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, F: FnOnce() -> 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: FnOnce(&mut $t) -> R>(f: F) -> Option<R>`
|
||||
/// 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<Option<*mut $t>>
|
||||
= ::std::cell::RefCell::new(None));
|
||||
|
||||
impl $name {
|
||||
#[allow(unused_imports)]
|
||||
|
||||
pub fn using<R, F: FnOnce() -> R>(
|
||||
protected: &mut $t,
|
||||
f: F
|
||||
) -> R {
|
||||
$crate::using(&GLOBAL, protected, f)
|
||||
}
|
||||
|
||||
pub fn with<R, F: FnOnce(&mut $t) -> R>(
|
||||
f: F
|
||||
) -> Option<R> {
|
||||
$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<u8>);
|
||||
|
||||
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<u8>);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<u32> 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<u8>, value: Vec<u8>) {
|
||||
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::<TestExternalities>::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]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "native-runtime"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[features]
|
||||
default = ["with-std"]
|
||||
with-std = []
|
||||
without-std = []
|
||||
|
||||
[dependencies]
|
||||
runtime-support = { path = "./support", version = "0.1" }
|
||||
rustc-hex = "1.0"
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../wasm-runtime/polkadot/src
|
||||
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "runtime-support"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[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" }
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<Error=NoError> + 'static);
|
||||
|
||||
/// Get `key` from storage and return a `Vec`, empty if there's a problem.
|
||||
pub fn storage(key: &[u8]) -> Vec<u8> {
|
||||
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, F: FnOnce() -> R>(ext: &mut (Externalities<Error=NoError> + '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<u8>, Vec<u8>>,
|
||||
}
|
||||
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<u8>, value: Vec<u8>) {
|
||||
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
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -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" }
|
||||
|
||||
@@ -97,7 +97,7 @@ mod tests {
|
||||
"candidates": [
|
||||
{
|
||||
"parachainIndex": 10,
|
||||
"collatorSignature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"collatorSignature": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"unprocessedIngress": [],
|
||||
"block": "0x01030508"
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<Pair> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<u8> {
|
||||
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]);
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ mod tests {
|
||||
block: BlockData(vec![1, 2, 3]),
|
||||
}), r#"{
|
||||
"parachainIndex": 5,
|
||||
"collatorSignature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a",
|
||||
"collatorSignature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a",
|
||||
"unprocessedIngress": [
|
||||
[
|
||||
1,
|
||||
|
||||
@@ -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<u8>) -> Vec<u8> {
|
||||
print(b"set_storage" as &[u8]);
|
||||
set_storage(b"input", &input);
|
||||
|
||||
print(b"code" as &[u8]);
|
||||
set_storage(b"code", &code());
|
||||
|
||||
print(b"set_code" as &[u8]);
|
||||
set_code(&input);
|
||||
|
||||
print(b"storage" as &[u8]);
|
||||
let copy = storage(b"input");
|
||||
|
||||
print(b"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::<Vec<_>>());
|
||||
|
||||
print(b"finished!" as &[u8]);
|
||||
b"all ok!".to_vec()
|
||||
}
|
||||
@@ -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<u8> {
|
||||
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<u8> {
|
||||
storage(b"\0code")
|
||||
}
|
||||
|
||||
pub fn set_code(new: &[u8]) {
|
||||
set_storage(b"\0code", new)
|
||||
}
|
||||
|
||||
fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
|
||||
let mut acc = initial;
|
||||
while value > 0 {
|
||||
acc.push(value as u8);
|
||||
value /= 256;
|
||||
}
|
||||
acc
|
||||
}
|
||||
|
||||
pub fn set_validator(index: usize, validator: &[u8]) {
|
||||
set_storage(&value_vec(index, b"\0validator".to_vec()), validator);
|
||||
}
|
||||
|
||||
pub fn validator(index: usize) -> Vec<u8> {
|
||||
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<Vec<u8>> {
|
||||
(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<T: Printable + Sized>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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<u8>) -> Vec<u8> {
|
||||
print(b"set_storage" as &[u8]);
|
||||
set_storage(b"input", &input);
|
||||
|
||||
print(b"code" as &[u8]);
|
||||
set_storage(b"code", &code());
|
||||
|
||||
print(b"set_code" as &[u8]);
|
||||
set_code(&input);
|
||||
|
||||
print(b"storage" as &[u8]);
|
||||
let copy = storage(b"input");
|
||||
|
||||
print(b"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::<Vec<_>>());
|
||||
|
||||
print(b"finished!" as &[u8]);
|
||||
b"all ok!".to_vec()
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -73,4 +73,8 @@ impl<'a, B: 'a> Externalities for Ext<'a, B>
|
||||
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
|
||||
self.overlay.set_storage(key, value);
|
||||
}
|
||||
|
||||
fn chain_id(&self) -> u64 {
|
||||
42
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<E> Error for E where E: 'static + fmt::Debug + fmt::Display + Send {}
|
||||
|
||||
fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
|
||||
let mut acc = initial;
|
||||
while value > 0 {
|
||||
acc.push(value as u8);
|
||||
value /= 256;
|
||||
}
|
||||
acc
|
||||
fn to_keyed_vec(value: u32, mut prepend: Vec<u8>) -> Vec<u8> {
|
||||
prepend.extend((0..::std::mem::size_of::<u32>()).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<u8>, value: Vec<u8>);
|
||||
|
||||
/// Get the current set of validators.
|
||||
fn validators(&self) -> Result<Vec<&[u8]>, 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<Vec<&[u8]>, 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<B: backend::Backend, Exec: CodeExecutor>(
|
||||
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<u8>, value: Vec<u8>) {
|
||||
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"[..]]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,3 +8,8 @@ crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
runtime-support = { path = "../support", version = "0.1" }
|
||||
|
||||
[features]
|
||||
default = ["without-std"]
|
||||
with-std = []
|
||||
without-std = []
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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, F: FnOnce(&Self) -> T>(&self, f: F) -> T { f(&self) }
|
||||
fn as_le_then<T, F: FnOnce(&Self) -> 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, F: FnOnce(&Self) -> T>(&self, f: F) -> T { let d = self.to_be(); f(&d) }
|
||||
fn as_le_then<T, F: FnOnce(&Self) -> 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]);
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Vec<u8> serialiser.
|
||||
|
||||
use runtime_support::Vec;
|
||||
use slicable::Slicable;
|
||||
|
||||
/// Trait to allow itself to be serialised into a `Vec<u8>`
|
||||
pub trait Joiner {
|
||||
fn join<T: Slicable + Sized>(self, value: &T) -> Self;
|
||||
}
|
||||
|
||||
impl Joiner for Vec<u8> {
|
||||
fn join<T: Slicable + Sized>(mut self, value: &T) -> Vec<u8> {
|
||||
value.as_slice_then(|s| self.extend_from_slice(s));
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<u8>;
|
||||
}
|
||||
|
||||
macro_rules! impl_non_endians {
|
||||
( $( $t:ty ),* ) => { $(
|
||||
impl KeyedVec for $t {
|
||||
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8> {
|
||||
let mut r = prepend_key.to_vec();
|
||||
r.extend_from_slice(&self[..]);
|
||||
r
|
||||
}
|
||||
}
|
||||
)* }
|
||||
}
|
||||
|
||||
macro_rules! impl_endians {
|
||||
( $( $t:ty ),* ) => { $(
|
||||
impl KeyedVec for $t {
|
||||
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8> {
|
||||
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]);
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Codec utils.
|
||||
|
||||
pub mod endiansensitive;
|
||||
pub mod streamreader;
|
||||
pub mod joiner;
|
||||
pub mod slicable;
|
||||
pub mod keyedvec;
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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> {
|
||||
Self::set_as_slice(|out| if value.len() == out.len() {
|
||||
out.copy_from_slice(&value);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
})
|
||||
}
|
||||
fn to_vec(&self) -> Vec<u8> {
|
||||
self.as_slice_then(|s| s.to_vec())
|
||||
}
|
||||
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(set_slice: F) -> Option<Self>;
|
||||
fn as_slice_then<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||
f(&self.to_vec())
|
||||
}
|
||||
fn size_of(_value: &[u8]) -> Option<usize>;
|
||||
}
|
||||
|
||||
/// Trait to mark that a type is not trivially (essentially "in place") serialisable.
|
||||
pub trait NonTrivialSlicable: Slicable {}
|
||||
|
||||
impl<T: EndianSensitive> Slicable for T {
|
||||
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(fill_slice: F) -> Option<Self> {
|
||||
let size = size_of::<T>();
|
||||
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, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||
let size = size_of::<Self>();
|
||||
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<usize> {
|
||||
Some(size_of::<Self>())
|
||||
}
|
||||
}
|
||||
|
||||
impl Slicable for Vec<u8> {
|
||||
fn from_slice(value: &[u8]) -> Option<Self> {
|
||||
Some(value[4..].to_vec())
|
||||
}
|
||||
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
|
||||
unimplemented!();
|
||||
}
|
||||
fn to_vec(&self) -> Vec<u8> {
|
||||
let mut r: Vec<u8> = Vec::new().join(&(self.len() as u32));
|
||||
r.extend_from_slice(&self);
|
||||
r
|
||||
}
|
||||
fn size_of(data: &[u8]) -> Option<usize> {
|
||||
u32::from_slice(&data[0..4]).map(|i| (i + 4) as usize)
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<T: Slicable>(&mut self) -> Option<T> {
|
||||
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<T: Slicable>(&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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<u8>) -> Vec<u8> {
|
||||
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<u8>) -> Vec<u8> {
|
||||
runtime::system::execute_transaction(&UncheckedTransaction::from_slice(&input).unwrap());
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
impl_stubs!(execute_block, execute_transaction);
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<SessionKey> {
|
||||
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);
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<AccountID> {
|
||||
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]]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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::<Vec<_>>();
|
||||
intentions.sort_unstable_by(|&(b1, _), &(b2, _)| b2.cmp(&b1));
|
||||
session::set_validators(
|
||||
&intentions.into_iter()
|
||||
.map(|(_, v)| v)
|
||||
.take(validator_count())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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: FnOnce(&mut Environment) -> T>(f: F) -> T {
|
||||
let e = env();
|
||||
let mut eb = e.borrow_mut();
|
||||
f(&mut *eb)
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
fn env() -> Rc<RefCell<Environment>> {
|
||||
// Initialize it to a null value
|
||||
static mut SINGLETON: *const Rc<RefCell<Environment>> = 0 as *const Rc<RefCell<Environment>>;
|
||||
|
||||
unsafe {
|
||||
if SINGLETON == 0 as *const Rc<RefCell<Environment>> {
|
||||
// Make it
|
||||
let singleton: Rc<RefCell<Environment>> = Rc::new(RefCell::new(Default::default()));
|
||||
|
||||
// Put it in the heap so it can outlive this call
|
||||
SINGLETON = 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<RefCell<Environment>> {
|
||||
// Initialize it to a null value
|
||||
thread_local!{
|
||||
static SINGLETON: RefCell<*const Rc<RefCell<Environment>>> = RefCell::new(0 as *const Rc<RefCell<Environment>>);
|
||||
}
|
||||
|
||||
SINGLETON.with(|s| unsafe {
|
||||
if *s.borrow() == 0 as *const Rc<RefCell<Environment>> {
|
||||
// Make it
|
||||
let singleton: Rc<RefCell<Environment>> = Rc::new(RefCell::new(Default::default()));
|
||||
|
||||
// Put it in the heap so it can outlive this call
|
||||
*s.borrow_mut() = transmute(Box::new(singleton));
|
||||
}
|
||||
|
||||
// Now we give out a copy of the data that is safe to use concurrently.
|
||||
(**s.borrow()).clone()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<Function> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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;
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[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<Self> {
|
||||
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<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn to_vec(&self) -> Vec<u8> {
|
||||
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<usize> {
|
||||
let first_part = size_of::<Hash>() + size_of::<BlockNumber>() + size_of::<Hash>() + size_of::<Hash>();
|
||||
let second_part = <Vec<Vec<u8>>>::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<u8>,
|
||||
}
|
||||
|
||||
impl Slicable for Transaction {
|
||||
fn from_slice(value: &[u8]) -> Option<Self> {
|
||||
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<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn to_vec(&self) -> Vec<u8> {
|
||||
Vec::new()
|
||||
.join(&self.signed)
|
||||
.join(&self.nonce)
|
||||
.join(&(self.function as u8))
|
||||
.join(&self.input_data)
|
||||
}
|
||||
|
||||
fn size_of(data: &[u8]) -> Option<usize> {
|
||||
let first_part = size_of::<AccountID>() + size_of::<TxOrder>() + size_of::<u8>();
|
||||
let second_part = <Vec<u8>>::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<T: Slicable> 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<Self> {
|
||||
let mut reader = StreamReader::new(value);
|
||||
Some(UncheckedTransaction {
|
||||
signature: reader.read()?,
|
||||
transaction: reader.read()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn to_vec(&self) -> Vec<u8> {
|
||||
Vec::new()
|
||||
.join(&self.signature)
|
||||
.join(&self.transaction)
|
||||
}
|
||||
|
||||
fn size_of(data: &[u8]) -> Option<usize> {
|
||||
let first_part = size_of::<[u8; 64]>();
|
||||
let second_part = <Transaction>::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<UncheckedTransaction>,
|
||||
}
|
||||
|
||||
impl Slicable for Block {
|
||||
fn from_slice(value: &[u8]) -> Option<Self> {
|
||||
let mut reader = StreamReader::new(value);
|
||||
Some(Block {
|
||||
header: reader.read()?,
|
||||
transactions: reader.read()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn to_vec(&self) -> Vec<u8> {
|
||||
Vec::new()
|
||||
.join(&self.header)
|
||||
.join(&self.transactions)
|
||||
}
|
||||
|
||||
fn size_of(data: &[u8]) -> Option<usize> {
|
||||
let first_part = Header::size_of(data)?;
|
||||
let second_part = <Vec<Transaction>>::size_of(&data[first_part..])?;
|
||||
Some(first_part + second_part)
|
||||
}
|
||||
}
|
||||
|
||||
impl NonTrivialSlicable for Block {}
|
||||
|
||||
impl<T: Slicable> NonTrivialSlicable for Vec<T> where Vec<T>: Slicable {}
|
||||
|
||||
impl<T: NonTrivialSlicable> Slicable for Vec<T> {
|
||||
fn from_slice(value: &[u8]) -> Option<Self> {
|
||||
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<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn to_vec(&self) -> Vec<u8> {
|
||||
let vecs = self.iter().map(Slicable::to_vec).collect::<Vec<_>>();
|
||||
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<usize> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<T: StaticHexConversion>(self) -> T;
|
||||
}
|
||||
|
||||
impl StaticHexInto for &'static str {
|
||||
fn convert<T: StaticHexConversion>(self) -> T {
|
||||
T::from_static_hex(self)
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<Self> 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<T: Default + Sized + EndianSensitive> Storable for T {
|
||||
fn lookup(key: &[u8]) -> Option<Self> {
|
||||
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<Self::Item> {
|
||||
(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))
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<u8>, Vec<u8>>,
|
||||
}
|
||||
|
||||
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<u8>, value: Vec<u8>) {
|
||||
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<u8> {
|
||||
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]);
|
||||
@@ -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<u8> {
|
||||
let mut length: u32 = 0;
|
||||
unsafe {
|
||||
let ptr = ext_get_allocated_storage(&key[0], key.len() as u32, &mut length);
|
||||
Vec::from_raw_parts(ptr, length as usize, length as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn 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<T: Printable + Sized>(value: T) {
|
||||
value.print();
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_stubs {
|
||||
( $( $name:ident ),* ) => {
|
||||
pub mod _internal {
|
||||
$(
|
||||
#[no_mangle]
|
||||
pub fn $name(input_data: *mut u8, input_len: usize) -> u64 {
|
||||
let input = unsafe {
|
||||
$crate::Vec::from_raw_parts(input_data, input_len, input_len)
|
||||
};
|
||||
|
||||
let output = super::$name(input);
|
||||
&output[0] as *const u8 as u64 + ((output.len() as u64) << 32)
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -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<u8>) -> Vec<u8> {
|
||||
blake2_256(&input).to_vec()
|
||||
}
|
||||
|
||||
fn test_twox_256(input: Vec<u8>) -> Vec<u8> {
|
||||
twox_256(&input).to_vec()
|
||||
}
|
||||
|
||||
fn test_twox_128(input: Vec<u8>) -> Vec<u8> {
|
||||
twox_128(&input).to_vec()
|
||||
}
|
||||
|
||||
fn test_ed25519_verify(input: Vec<u8>) -> Vec<u8> {
|
||||
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<u8>) -> Vec<u8> {
|
||||
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);
|
||||
Reference in New Issue
Block a user