mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 04:41:02 +00:00
Refactor key management (#3296)
* Add Call type to extensible transactions. Cleanup some naming * Merge Resource and BlockExhausted into just Exhausted * Fix * Another fix * Call * Some fixes * Fix srml tests. * Fix all tests. * Refactor crypto so each application of it has its own type. * Introduce new AuthorityProvider API into Aura This will eventually allow for dynamic determination of authority keys and avoid having to set them directly on CLI. * Introduce authority determinator for Babe. Experiment with modular consensus API. * Work in progress to introduce KeyTypeId and avoid polluting API with validator IDs * Finish up drafting imonline * Rework offchain workers API. * Rework API implementation. * Make it compile for wasm, simplify app_crypto. * Fix compilation of im-online. * Fix compilation of im-online. * Fix more compilation errors. * Make it compile. * Fixing tests. * Rewrite `keystore` * Fix session tests * Bring back `TryFrom`'s' * Fix `srml-grandpa` * Fix `srml-aura` * Fix consensus babe * More fixes * Make service generate keys from dev_seed * Build fixes * Remove offchain tests * More fixes and cleanups * Fixes finality grandpa * Fix `consensus-aura` * Fix cli * Fix `node-cli` * Fix chain_spec builder * Fix doc tests * Add authority getter for grandpa. * Test fix * Fixes * Make keystore accessible from the runtime * Move app crypto to its own crate * Update `Cargo.lock` * Make the crypto stuff usable from the runtime * Adds some runtime crypto tests * Use last finalized block for grandpa authority * Fix warning * Adds `SessionKeys` runtime api * Remove `FinalityPair` and `ConsensusPair` * Minor governance tweaks to get it inline with docs. * Make the governance be up to date with the docs. * Build fixes. * Generate the inital session keys * Failing keystore is a hard error * Make babe work again * Fix grandpa * Fix tests * Disable `keystore` in consensus critical stuff * Build fix. * ImOnline supports multiple authorities at once. * Update core/application-crypto/src/ed25519.rs * Merge branch 'master' into gav-in-progress * Remove unneeded code for now. * Some `session` testing * Support querying the public keys * Cleanup offchain * Remove warnings * More cleanup * Apply suggestions from code review Co-Authored-By: Benjamin Kampmann <ben.kampmann@googlemail.com> * More cleanups * JSONRPC API for setting keys. Also, rename traits::KeyStore* -> traits::BareCryptoStore* * Bad merge * Fix integration tests * Fix test build * Test fix * Fixes * Warnings * Another warning * Bump version.
This commit is contained in:
Generated
+109
-27
@@ -695,6 +695,19 @@ dependencies = [
|
||||
"syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difference"
|
||||
version = "2.0.0"
|
||||
@@ -2264,7 +2277,9 @@ dependencies = [
|
||||
"srml-balances 2.0.0",
|
||||
"srml-contracts 2.0.0",
|
||||
"srml-finality-tracker 2.0.0",
|
||||
"srml-im-online 0.1.0",
|
||||
"srml-indices 2.0.0",
|
||||
"srml-support 2.0.0",
|
||||
"srml-system 2.0.0",
|
||||
"srml-timestamp 2.0.0",
|
||||
"structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2285,6 +2300,7 @@ dependencies = [
|
||||
"substrate-service-test 2.0.0",
|
||||
"substrate-telemetry 2.0.0",
|
||||
"substrate-transaction-pool 2.0.0",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"transaction-factory 0.0.1",
|
||||
]
|
||||
@@ -2369,6 +2385,7 @@ dependencies = [
|
||||
"srml-grandpa 2.0.0",
|
||||
"srml-im-online 0.1.0",
|
||||
"srml-indices 2.0.0",
|
||||
"srml-membership 2.0.0",
|
||||
"srml-session 2.0.0",
|
||||
"srml-staking 2.0.0",
|
||||
"srml-sudo 2.0.0",
|
||||
@@ -2382,6 +2399,7 @@ dependencies = [
|
||||
"substrate-keyring 2.0.0",
|
||||
"substrate-offchain-primitives 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-session 2.0.0",
|
||||
"substrate-wasm-builder-runner 1.0.2",
|
||||
]
|
||||
|
||||
@@ -2396,13 +2414,15 @@ dependencies = [
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"node-template-runtime 2.0.0",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"substrate-basic-authorship 2.0.0",
|
||||
"substrate-cli 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-aura 2.0.0",
|
||||
"substrate-consensus-aura-primitives 2.0.0",
|
||||
"substrate-executor 2.0.0",
|
||||
"substrate-finality-grandpa-primitives 2.0.0",
|
||||
"substrate-inherents 2.0.0",
|
||||
"substrate-network 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
@@ -2436,6 +2456,7 @@ dependencies = [
|
||||
"substrate-consensus-aura-primitives 2.0.0",
|
||||
"substrate-offchain-primitives 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-session 2.0.0",
|
||||
"substrate-wasm-builder-runner 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -3631,10 +3652,12 @@ dependencies = [
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"primitive-types 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
@@ -3689,7 +3712,7 @@ version = "2.0.0"
|
||||
dependencies = [
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-primitives 2.0.0",
|
||||
@@ -3699,6 +3722,7 @@ dependencies = [
|
||||
"srml-support 2.0.0",
|
||||
"srml-system 2.0.0",
|
||||
"srml-timestamp 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-consensus-aura-primitives 2.0.0",
|
||||
"substrate-inherents 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
@@ -3724,7 +3748,7 @@ dependencies = [
|
||||
"hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-primitives 2.0.0",
|
||||
@@ -3918,6 +3942,7 @@ dependencies = [
|
||||
"srml-session 2.0.0",
|
||||
"srml-support 2.0.0",
|
||||
"srml-system 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
@@ -3938,6 +3963,20 @@ dependencies = [
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "srml-membership"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"srml-support 2.0.0",
|
||||
"srml-system 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "srml-metadata"
|
||||
version = "2.0.0"
|
||||
@@ -3962,6 +4001,7 @@ dependencies = [
|
||||
"srml-support 2.0.0",
|
||||
"srml-system 2.0.0",
|
||||
"srml-timestamp 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-trie 2.0.0",
|
||||
]
|
||||
@@ -4214,6 +4254,19 @@ dependencies = [
|
||||
"vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-application-crypto"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-test-runtime-client 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-basic-authorship"
|
||||
version = "2.0.0"
|
||||
@@ -4291,7 +4344,7 @@ dependencies = [
|
||||
"kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-api-macros 2.0.0",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
@@ -4319,7 +4372,7 @@ dependencies = [
|
||||
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-common 2.0.0",
|
||||
@@ -4342,12 +4395,13 @@ dependencies = [
|
||||
"futures-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-version 2.0.0",
|
||||
"srml-aura 2.0.0",
|
||||
"srml-support 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-aura-primitives 2.0.0",
|
||||
"substrate-consensus-common 2.0.0",
|
||||
@@ -4355,6 +4409,7 @@ dependencies = [
|
||||
"substrate-executor 2.0.0",
|
||||
"substrate-inherents 2.0.0",
|
||||
"substrate-keyring 2.0.0",
|
||||
"substrate-keystore 2.0.0",
|
||||
"substrate-network 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-service 2.0.0",
|
||||
@@ -4370,8 +4425,8 @@ dependencies = [
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4389,7 +4444,7 @@ dependencies = [
|
||||
"num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
@@ -4397,6 +4452,7 @@ dependencies = [
|
||||
"sr-version 2.0.0",
|
||||
"srml-babe 2.0.0",
|
||||
"srml-support 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-babe-primitives 2.0.0",
|
||||
"substrate-consensus-common 2.0.0",
|
||||
@@ -4404,11 +4460,13 @@ dependencies = [
|
||||
"substrate-executor 2.0.0",
|
||||
"substrate-inherents 2.0.0",
|
||||
"substrate-keyring 2.0.0",
|
||||
"substrate-keystore 2.0.0",
|
||||
"substrate-network 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-service 2.0.0",
|
||||
"substrate-telemetry 2.0.0",
|
||||
"substrate-test-runtime-client 2.0.0",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -4420,9 +4478,9 @@ dependencies = [
|
||||
"schnorrkel 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-slots 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4435,7 +4493,7 @@ dependencies = [
|
||||
"libp2p 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"sr-version 2.0.0",
|
||||
@@ -4463,7 +4521,7 @@ dependencies = [
|
||||
"futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rhododendron 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-primitives 2.0.0",
|
||||
@@ -4486,7 +4544,7 @@ dependencies = [
|
||||
"futures-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-common 2.0.0",
|
||||
@@ -4508,7 +4566,7 @@ dependencies = [
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-version 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
@@ -4535,21 +4593,24 @@ dependencies = [
|
||||
"futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"srml-finality-tracker 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-babe-primitives 2.0.0",
|
||||
"substrate-consensus-common 2.0.0",
|
||||
"substrate-finality-grandpa-primitives 2.0.0",
|
||||
"substrate-inherents 2.0.0",
|
||||
"substrate-keyring 2.0.0",
|
||||
"substrate-keystore 2.0.0",
|
||||
"substrate-network 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-service 2.0.0",
|
||||
"substrate-telemetry 2.0.0",
|
||||
"substrate-test-runtime-client 2.0.0",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -4563,8 +4624,8 @@ dependencies = [
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4572,7 +4633,7 @@ name = "substrate-inherents"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
]
|
||||
@@ -4592,10 +4653,12 @@ dependencies = [
|
||||
name = "substrate-keystore"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -4622,7 +4685,7 @@ dependencies = [
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quickcheck 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -4633,6 +4696,7 @@ dependencies = [
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-babe-primitives 2.0.0",
|
||||
"substrate-consensus-common 2.0.0",
|
||||
"substrate-keyring 2.0.0",
|
||||
"substrate-peerset 2.0.0",
|
||||
@@ -4656,10 +4720,11 @@ dependencies = [
|
||||
"futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-client-db 2.0.0",
|
||||
"substrate-keystore 2.0.0",
|
||||
"substrate-network 2.0.0",
|
||||
"substrate-offchain-primitives 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
@@ -4714,7 +4779,7 @@ dependencies = [
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"primitive-types 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -4746,7 +4811,7 @@ dependencies = [
|
||||
"jsonrpc-pubsub 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -4755,6 +4820,7 @@ dependencies = [
|
||||
"sr-version 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-executor 2.0.0",
|
||||
"substrate-keystore 2.0.0",
|
||||
"substrate-network 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-state-machine 2.0.0",
|
||||
@@ -4810,22 +4876,26 @@ dependencies = [
|
||||
"node-runtime 2.0.0",
|
||||
"parity-multiaddr 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
"sr-primitives 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-client-db 2.0.0",
|
||||
"substrate-consensus-babe-primitives 2.0.0",
|
||||
"substrate-consensus-common 2.0.0",
|
||||
"substrate-executor 2.0.0",
|
||||
"substrate-finality-grandpa 2.0.0",
|
||||
"substrate-finality-grandpa-primitives 2.0.0",
|
||||
"substrate-keystore 2.0.0",
|
||||
"substrate-network 2.0.0",
|
||||
"substrate-offchain 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-rpc-servers 2.0.0",
|
||||
"substrate-session 2.0.0",
|
||||
"substrate-telemetry 2.0.0",
|
||||
"substrate-test-runtime-client 2.0.0",
|
||||
"substrate-transaction-pool 2.0.0",
|
||||
@@ -4853,6 +4923,16 @@ dependencies = [
|
||||
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-session"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "substrate-state-db"
|
||||
version = "2.0.0"
|
||||
@@ -4860,7 +4940,7 @@ dependencies = [
|
||||
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
@@ -4873,7 +4953,7 @@ dependencies = [
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-panic-handler 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
"substrate-trie 2.0.0",
|
||||
@@ -4891,7 +4971,7 @@ dependencies = [
|
||||
"futures-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libp2p 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -4937,6 +5017,7 @@ dependencies = [
|
||||
"srml-support 2.0.0",
|
||||
"srml-system 2.0.0",
|
||||
"srml-timestamp 2.0.0",
|
||||
"substrate-application-crypto 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-aura-primitives 2.0.0",
|
||||
"substrate-consensus-babe-primitives 2.0.0",
|
||||
@@ -4972,7 +5053,7 @@ dependencies = [
|
||||
"futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"substrate-primitives 2.0.0",
|
||||
@@ -4987,7 +5068,7 @@ dependencies = [
|
||||
"futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-scale-codec 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-primitives 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-keyring 2.0.0",
|
||||
@@ -6075,6 +6156,7 @@ dependencies = [
|
||||
"checksum curve25519-dalek 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5d4b820e8711c211745880150f5fac78ab07d6e3851d8ce9f5a02cedc199174c"
|
||||
"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97"
|
||||
"checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839"
|
||||
"checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe"
|
||||
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
"checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a"
|
||||
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
|
||||
@@ -19,6 +19,7 @@ vergen = "3"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"core/application-crypto",
|
||||
"core/cli",
|
||||
"core/client",
|
||||
"core/client/db",
|
||||
@@ -42,6 +43,7 @@ members = [
|
||||
"core/serializer",
|
||||
"core/service",
|
||||
"core/service/test",
|
||||
"core/session",
|
||||
"core/sr-api-macros",
|
||||
"core/sr-io",
|
||||
"core/sr-primitives",
|
||||
@@ -79,6 +81,7 @@ members = [
|
||||
"srml/grandpa",
|
||||
"srml/im-online",
|
||||
"srml/indices",
|
||||
"srml/membership",
|
||||
"srml/metadata",
|
||||
"srml/session",
|
||||
"srml/staking",
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "substrate-application-crypto"
|
||||
version = "2.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
description = "Provides facilities for generating application specific crypto wrapper types."
|
||||
|
||||
[dependencies]
|
||||
primitives = { package = "substrate-primitives", path = "../primitives", default-features = false }
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||
rstd = { package = "sr-std", path = "../sr-std", default-features = false }
|
||||
rio = { package = "sr-io", path = "../sr-io", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client" }
|
||||
sr-primitives = { path = "../sr-primitives" }
|
||||
|
||||
[features]
|
||||
default = [ "std" ]
|
||||
std = [ "primitives/std", "codec/std", "serde", "rstd/std", "rio/std" ]
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Ed25519 crypto types.
|
||||
|
||||
use crate::{RuntimePublic, KeyTypeId};
|
||||
|
||||
pub use primitives::ed25519::*;
|
||||
|
||||
mod app {
|
||||
use crate::key_types::ED25519;
|
||||
crate::app_crypto!(super, ED25519);
|
||||
}
|
||||
|
||||
pub use app::Public as AppPublic;
|
||||
pub use app::Signature as AppSignature;
|
||||
#[cfg(feature="std")]
|
||||
pub use app::Pair as AppPair;
|
||||
|
||||
impl RuntimePublic for Public {
|
||||
type Signature = Signature;
|
||||
|
||||
fn all(key_type: KeyTypeId) -> crate::Vec<Self> {
|
||||
rio::ed25519_public_keys(key_type)
|
||||
}
|
||||
|
||||
fn generate_pair(key_type: KeyTypeId, seed: Option<&str>) -> Self {
|
||||
rio::ed25519_generate(key_type, seed)
|
||||
}
|
||||
|
||||
fn sign<M: AsRef<[u8]>>(&self, key_type: KeyTypeId, msg: &M) -> Option<Self::Signature> {
|
||||
rio::ed25519_sign(key_type, self, msg)
|
||||
}
|
||||
|
||||
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool {
|
||||
rio::ed25519_verify(&signature, msg.as_ref(), self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi};
|
||||
use primitives::{testing::KeyStore, crypto::Pair, traits::BareCryptoStore as _};
|
||||
use test_client::{
|
||||
TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt,
|
||||
runtime::{TestAPI, app_crypto::ed25519::{AppPair, AppPublic}},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn ed25519_works_in_runtime() {
|
||||
let keystore = KeyStore::new();
|
||||
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
|
||||
let (signature, public) = test_client.runtime_api()
|
||||
.test_ed25519_crypto(&BlockId::Number(0))
|
||||
.expect("Tests `ed25519` crypto.");
|
||||
|
||||
let key_pair = keystore.read().ed25519_key_pair(crate::key_types::ED25519, &public.as_ref())
|
||||
.expect("There should be at a `ed25519` key in the keystore for the given public key.");
|
||||
|
||||
assert!(AppPair::verify(&signature, "ed25519", &AppPublic::from(key_pair.public())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Traits and macros for constructing application specific strongly typed crypto wrappers.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use primitives::{self, crypto::{CryptoType, Public, Derive, IsWrappedBy, Wraps}};
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "std")]
|
||||
pub use primitives::crypto::{SecretStringError, DeriveJunction, Ss58Codec, Pair};
|
||||
pub use primitives::{crypto::{KeyTypeId, key_types}};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use codec;
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "std")]
|
||||
pub use serde;
|
||||
#[doc(hidden)]
|
||||
pub use rstd::{ops::Deref, vec::Vec};
|
||||
|
||||
pub mod ed25519;
|
||||
pub mod sr25519;
|
||||
mod traits;
|
||||
|
||||
pub use traits::*;
|
||||
|
||||
/// Declares Public, Pair, Signature types which are functionally equivalent to `$pair`, but are new
|
||||
/// Application-specific types whose identifier is `$key_type`.
|
||||
///
|
||||
/// ```rust
|
||||
///# use substrate_application_crypto::{app_crypto, wrap, ed25519, KeyTypeId};
|
||||
/// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId`
|
||||
/// // of value `b"fuba"`.
|
||||
/// app_crypto!(ed25519, KeyTypeId(*b"_uba"));
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! app_crypto {
|
||||
($module:ident, $key_type:expr) => {
|
||||
#[cfg(feature="std")]
|
||||
$crate::app_crypto!($module::Pair, $module::Public, $module::Signature, $key_type);
|
||||
#[cfg(not(feature="std"))]
|
||||
$crate::app_crypto!($module::Public, $module::Signature, $key_type);
|
||||
};
|
||||
($pair:ty, $public:ty, $sig:ty, $key_type:expr) => {
|
||||
$crate::app_crypto!($public, $sig, $key_type);
|
||||
|
||||
$crate::wrap!{
|
||||
/// A generic `AppPublic` wrapper type over $pair crypto; this has no specific App.
|
||||
#[derive(Clone)]
|
||||
pub struct Pair($pair);
|
||||
}
|
||||
|
||||
impl $crate::CryptoType for Pair {
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl $crate::Pair for Pair {
|
||||
type Public = Public;
|
||||
type Seed = <$pair as $crate::Pair>::Seed;
|
||||
type Signature = Signature;
|
||||
type DeriveError = <$pair as $crate::Pair>::DeriveError;
|
||||
fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) {
|
||||
let r = <$pair>::generate_with_phrase(password);
|
||||
(Self(r.0), r.1, r.2)
|
||||
}
|
||||
fn from_phrase(phrase: &str, password: Option<&str>)
|
||||
-> Result<(Self, Self::Seed), $crate::SecretStringError>
|
||||
{
|
||||
<$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1))
|
||||
}
|
||||
fn derive<
|
||||
Iter: Iterator<Item=$crate::DeriveJunction>
|
||||
>(&self, path: Iter) -> Result<Self, Self::DeriveError> {
|
||||
self.0.derive(path).map(Self)
|
||||
}
|
||||
fn from_seed(seed: &Self::Seed) -> Self { Self(<$pair>::from_seed(seed)) }
|
||||
fn from_seed_slice(seed: &[u8]) -> Result<Self, $crate::SecretStringError> {
|
||||
<$pair>::from_seed_slice(seed).map(Self)
|
||||
}
|
||||
fn from_standard_components<
|
||||
I: Iterator<Item=$crate::DeriveJunction>
|
||||
>(
|
||||
seed: &str,
|
||||
password: Option<&str>,
|
||||
path: I,
|
||||
) -> Result<Self, $crate::SecretStringError> {
|
||||
<$pair>::from_standard_components::<I>(seed, password, path).map(Self)
|
||||
}
|
||||
fn sign(&self, msg: &[u8]) -> Self::Signature {
|
||||
Signature(self.0.sign(msg))
|
||||
}
|
||||
fn verify<M: AsRef<[u8]>>(
|
||||
sig: &Self::Signature,
|
||||
message: M,
|
||||
pubkey: &Self::Public,
|
||||
) -> bool {
|
||||
<$pair>::verify(&sig.0, message, pubkey.as_ref())
|
||||
}
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(
|
||||
sig: &[u8],
|
||||
message: M,
|
||||
pubkey: P,
|
||||
) -> bool {
|
||||
<$pair>::verify_weak(sig, message, pubkey)
|
||||
}
|
||||
fn public(&self) -> Self::Public { Public(self.0.public()) }
|
||||
fn to_raw_vec(&self) -> Vec<u8> { self.0.to_raw_vec() }
|
||||
}
|
||||
impl $crate::AppKey for Pair {
|
||||
type UntypedGeneric = $pair;
|
||||
type Public = Public;
|
||||
type Pair = Pair;
|
||||
type Signature = Signature;
|
||||
const ID: $crate::KeyTypeId = $key_type;
|
||||
}
|
||||
impl $crate::AppPair for Pair {
|
||||
type Generic = $pair;
|
||||
}
|
||||
};
|
||||
($public:ty, $sig:ty, $key_type:expr) => {
|
||||
$crate::wrap!{
|
||||
/// A generic `AppPublic` wrapper type over $public crypto; this has no specific App.
|
||||
#[derive(
|
||||
Clone, Default, Eq, PartialEq, Ord, PartialOrd, $crate::codec::Encode,
|
||||
$crate::codec::Decode,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Hash))]
|
||||
pub struct Public($public);
|
||||
}
|
||||
|
||||
impl $crate::Derive for Public {
|
||||
#[cfg(feature = "std")]
|
||||
fn derive<Iter: Iterator<Item=$crate::DeriveJunction>>(&self,
|
||||
path: Iter
|
||||
) -> Option<Self> {
|
||||
self.0.derive(path).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
use $crate::Ss58Codec;
|
||||
write!(f, "{}", self.0.to_ss58check())
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
impl $crate::serde::Serialize for Public {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where
|
||||
S: $crate::serde::Serializer
|
||||
{
|
||||
use $crate::Ss58Codec;
|
||||
serializer.serialize_str(&self.to_ss58check())
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de> $crate::serde::Deserialize<'de> for Public {
|
||||
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> where
|
||||
D: $crate::serde::Deserializer<'de>
|
||||
{
|
||||
use $crate::Ss58Codec;
|
||||
Public::from_ss58check(&String::deserialize(deserializer)?)
|
||||
.map_err(|e| $crate::serde::de::Error::custom(format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Public {
|
||||
fn as_ref(&self) -> &[u8] { self.0.as_ref() }
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Public {
|
||||
fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut() }
|
||||
}
|
||||
|
||||
impl $crate::CryptoType for Public {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
impl $crate::Public for Public {
|
||||
fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) }
|
||||
}
|
||||
|
||||
impl $crate::AppKey for Public {
|
||||
type UntypedGeneric = $public;
|
||||
type Public = Public;
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
type Signature = Signature;
|
||||
const ID: $crate::KeyTypeId = $key_type;
|
||||
}
|
||||
|
||||
impl $crate::AppPublic for Public {
|
||||
type Generic = $public;
|
||||
}
|
||||
|
||||
impl $crate::RuntimeAppPublic for Public where $public: $crate::RuntimePublic<Signature=$sig> {
|
||||
type Signature = Signature;
|
||||
|
||||
fn all() -> $crate::Vec<Self> {
|
||||
<$public as $crate::RuntimePublic>::all($key_type).into_iter().map(Self).collect()
|
||||
}
|
||||
|
||||
fn generate_pair(seed: Option<&str>) -> Self {
|
||||
Self(<$public as $crate::RuntimePublic>::generate_pair($key_type, seed))
|
||||
}
|
||||
|
||||
fn sign<M: AsRef<[u8]>>(&self, msg: &M) -> Option<Self::Signature> {
|
||||
<$public as $crate::RuntimePublic>::sign(
|
||||
self.as_ref(),
|
||||
$key_type,
|
||||
msg,
|
||||
).map(Signature)
|
||||
}
|
||||
|
||||
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool {
|
||||
<$public as $crate::RuntimePublic>::verify(self.as_ref(), msg, &signature.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
$crate::wrap! {
|
||||
/// A generic `AppPublic` wrapper type over $public crypto; this has no specific App.
|
||||
#[derive(Clone, Default, Eq, PartialEq, $crate::codec::Encode, $crate::codec::Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Hash))]
|
||||
pub struct Signature($sig);
|
||||
}
|
||||
|
||||
impl $crate::Deref for Signature {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target { self.0.as_ref() }
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Signature {
|
||||
fn as_ref(&self) -> &[u8] { self.0.as_ref() }
|
||||
}
|
||||
|
||||
impl $crate::CryptoType for Signature {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
impl $crate::AppKey for Signature {
|
||||
type UntypedGeneric = $sig;
|
||||
type Public = Public;
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
type Signature = Signature;
|
||||
const ID: $crate::KeyTypeId = $key_type;
|
||||
}
|
||||
|
||||
impl $crate::AppSignature for Signature {
|
||||
type Generic = $sig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement bidirectional `From` and on-way `AsRef`/`AsMut` for two types, `$inner` and `$outer`.
|
||||
///
|
||||
/// ```rust
|
||||
/// substrate_application_crypto::wrap! {
|
||||
/// pub struct Wrapper(u32);
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! wrap {
|
||||
($( #[ $attr:meta ] )* struct $outer:ident($inner:ty);) => {
|
||||
$( #[ $attr ] )*
|
||||
struct $outer( $inner );
|
||||
$crate::wrap!($inner, $outer);
|
||||
};
|
||||
($( #[ $attr:meta ] )* pub struct $outer:ident($inner:ty);) => {
|
||||
$( #[ $attr ] )*
|
||||
pub struct $outer( $inner );
|
||||
$crate::wrap!($inner, $outer);
|
||||
};
|
||||
($inner:ty, $outer:ty) => {
|
||||
impl $crate::Wraps for $outer {
|
||||
type Inner = $inner;
|
||||
}
|
||||
impl From<$inner> for $outer {
|
||||
fn from(inner: $inner) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
impl From<$outer> for $inner {
|
||||
fn from(outer: $outer) -> Self {
|
||||
outer.0
|
||||
}
|
||||
}
|
||||
impl AsRef<$inner> for $outer {
|
||||
fn as_ref(&self) -> &$inner {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl AsMut<$inner> for $outer {
|
||||
fn as_mut(&mut self) -> &mut $inner {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Sr25519 crypto types.
|
||||
|
||||
use crate::{RuntimePublic, KeyTypeId};
|
||||
|
||||
pub use primitives::sr25519::*;
|
||||
|
||||
mod app {
|
||||
use crate::key_types::SR25519;
|
||||
crate::app_crypto!(super, SR25519);
|
||||
}
|
||||
|
||||
pub use app::Public as AppPublic;
|
||||
pub use app::Signature as AppSignature;
|
||||
#[cfg(feature="std")]
|
||||
pub use app::Pair as AppPair;
|
||||
|
||||
impl RuntimePublic for Public {
|
||||
type Signature = Signature;
|
||||
|
||||
fn all(key_type: KeyTypeId) -> crate::Vec<Self> {
|
||||
rio::sr25519_public_keys(key_type)
|
||||
}
|
||||
|
||||
fn generate_pair(key_type: KeyTypeId, seed: Option<&str>) -> Self {
|
||||
rio::sr25519_generate(key_type, seed)
|
||||
}
|
||||
|
||||
fn sign<M: AsRef<[u8]>>(&self, key_type: KeyTypeId, msg: &M) -> Option<Self::Signature> {
|
||||
rio::sr25519_sign(key_type, self, msg)
|
||||
}
|
||||
|
||||
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool {
|
||||
rio::sr25519_verify(&signature, msg.as_ref(), self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi};
|
||||
use primitives::{testing::KeyStore, crypto::Pair, traits::BareCryptoStore as _};
|
||||
use test_client::{
|
||||
TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt,
|
||||
runtime::{TestAPI, app_crypto::sr25519::{AppPair, AppPublic}},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn sr25519_works_in_runtime() {
|
||||
let keystore = KeyStore::new();
|
||||
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
|
||||
let (signature, public) = test_client.runtime_api()
|
||||
.test_sr25519_crypto(&BlockId::Number(0))
|
||||
.expect("Tests `sr25519` crypto.");
|
||||
|
||||
let key_pair = keystore.read().sr25519_key_pair(crate::key_types::SR25519, public.as_ref())
|
||||
.expect("There should be at a `sr25519` key in the keystore for the given public key.");
|
||||
|
||||
assert!(AppPair::verify(&signature, "sr25519", &AppPublic::from(key_pair.public())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use primitives::crypto::{KeyTypeId, CryptoType, IsWrappedBy, Public};
|
||||
#[cfg(feature = "std")]
|
||||
use primitives::crypto::Pair;
|
||||
|
||||
/// An application-specific key.
|
||||
pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone {
|
||||
/// The corresponding type as a generic crypto type.
|
||||
type UntypedGeneric: IsWrappedBy<Self>;
|
||||
|
||||
/// The corresponding public key type in this application scheme.
|
||||
type Public: AppPublic;
|
||||
|
||||
/// The corresponding key pair type in this application scheme.
|
||||
#[cfg(feature="std")]
|
||||
type Pair: AppPair;
|
||||
|
||||
/// The corresponding signature type in this application scheme.
|
||||
type Signature: AppSignature;
|
||||
|
||||
/// An identifier for this application-specific key type.
|
||||
const ID: KeyTypeId;
|
||||
}
|
||||
|
||||
/// Type which implements Debug and Hash in std, not when no-std (std variant).
|
||||
#[cfg(feature = "std")]
|
||||
pub trait MaybeDebugHash: std::fmt::Debug + std::hash::Hash {}
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: std::fmt::Debug + std::hash::Hash> MaybeDebugHash for T {}
|
||||
|
||||
/// Type which implements Debug and Hash in std, not when no-std (no-std variant).
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub trait MaybeDebugHash {}
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T> MaybeDebugHash for T {}
|
||||
|
||||
/// A application's public key.
|
||||
pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec {
|
||||
/// The wrapped type which is just a plain instance of `Public`.
|
||||
type Generic:
|
||||
IsWrappedBy<Self> + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec;
|
||||
}
|
||||
|
||||
/// A application's key pair.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait AppPair: AppKey + Pair<Public=<Self as AppKey>::Public> {
|
||||
/// The wrapped type which is just a plain instance of `Pair`.
|
||||
type Generic: IsWrappedBy<Self> + Pair<Public=<<Self as AppKey>::Public as AppPublic>::Generic>;
|
||||
}
|
||||
|
||||
/// A application's signature.
|
||||
pub trait AppSignature: AppKey + Eq + PartialEq + MaybeDebugHash {
|
||||
/// The wrapped type which is just a plain instance of `Signature`.
|
||||
type Generic: IsWrappedBy<Self> + Eq + PartialEq + MaybeDebugHash;
|
||||
}
|
||||
|
||||
/// A runtime interface for a public key.
|
||||
pub trait RuntimePublic: Sized {
|
||||
/// The signature that will be generated when signing with the corresponding private key.
|
||||
type Signature;
|
||||
|
||||
/// Returns all public keys for the given key type in the keystore.
|
||||
fn all(key_type: KeyTypeId) -> crate::Vec<Self>;
|
||||
|
||||
/// Generate a public/private pair for the given key type and store it in the keystore.
|
||||
///
|
||||
/// Returns the generated public key.
|
||||
fn generate_pair(key_type: KeyTypeId, seed: Option<&str>) -> Self;
|
||||
|
||||
/// Sign the given message with the corresponding private key of this public key.
|
||||
///
|
||||
/// The private key will be requested from the keystore using the given key type.
|
||||
///
|
||||
/// Returns the signature or `None` if the private key could not be found or some other error
|
||||
/// occurred.
|
||||
fn sign<M: AsRef<[u8]>>(&self, key_type: KeyTypeId, msg: &M) -> Option<Self::Signature>;
|
||||
|
||||
/// Verify that the given signature matches the given message using this public key.
|
||||
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool;
|
||||
}
|
||||
|
||||
/// A runtime interface for an application's public key.
|
||||
pub trait RuntimeAppPublic: Sized {
|
||||
/// The signature that will be generated when signing with the corresponding private key.
|
||||
type Signature;
|
||||
|
||||
/// Returns all public keys for this application in the keystore.
|
||||
fn all() -> crate::Vec<Self>;
|
||||
|
||||
/// Generate a public/private pair and store it in the keystore.
|
||||
///
|
||||
/// Returns the generated public key.
|
||||
fn generate_pair(seed: Option<&str>) -> Self;
|
||||
|
||||
/// Sign the given message with the corresponding private key of this public key.
|
||||
///
|
||||
/// The private key will be requested from the keystore.
|
||||
///
|
||||
/// Returns the signature or `None` if the private key could not be found or some other error
|
||||
/// occurred.
|
||||
fn sign<M: AsRef<[u8]>>(&self, msg: &M) -> Option<Self::Signature>;
|
||||
|
||||
/// Verify that the given signature matches the given message using this public key.
|
||||
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool;
|
||||
}
|
||||
@@ -366,6 +366,24 @@ fn input_keystore_password() -> Result<String, String> {
|
||||
.map_err(|e| format!("{:?}", e))
|
||||
}
|
||||
|
||||
/// Fill the password field of the given config instance.
|
||||
fn fill_config_keystore_password<C, G>(
|
||||
config: &mut service::Configuration<C, G>,
|
||||
cli: &RunCmd,
|
||||
) -> Result<(), String> {
|
||||
config.keystore_password = if cli.password_interactive {
|
||||
Some(input_keystore_password()?.into())
|
||||
} else if let Some(ref file) = cli.password_filename {
|
||||
Some(fs::read_to_string(file).map_err(|e| format!("{}", e))?.into())
|
||||
} else if let Some(ref password) = cli.password {
|
||||
Some(password.clone().into())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_run_node_config<F, S>(
|
||||
cli: RunCmd, spec_factory: S, impl_name: &'static str, version: &VersionInfo
|
||||
) -> error::Result<FactoryFullConfiguration<F>>
|
||||
@@ -375,9 +393,8 @@ where
|
||||
{
|
||||
let spec = load_spec(&cli.shared_params, spec_factory)?;
|
||||
let mut config = service::Configuration::default_with_spec(spec.clone());
|
||||
if cli.interactive_password {
|
||||
config.password = input_keystore_password()?.into()
|
||||
}
|
||||
|
||||
fill_config_keystore_password(&mut config, &cli)?;
|
||||
|
||||
config.impl_name = impl_name;
|
||||
config.impl_commit = version.commit;
|
||||
@@ -401,7 +418,9 @@ where
|
||||
|
||||
let base_path = base_path(&cli.shared_params, version);
|
||||
|
||||
config.keystore_path = cli.keystore_path.or_else(|| Some(keystore_path(&base_path, config.chain_spec.id())));
|
||||
config.keystore_path = cli.keystore_path.unwrap_or_else(
|
||||
|| keystore_path(&base_path, config.chain_spec.id())
|
||||
);
|
||||
|
||||
config.database_path = db_path(&base_path, config.chain_spec.id());
|
||||
config.database_cache_size = cli.database_cache_size;
|
||||
@@ -462,17 +481,13 @@ where
|
||||
cli.pool_config,
|
||||
)?;
|
||||
|
||||
if let Some(key) = cli.key {
|
||||
config.keys.push(key);
|
||||
|
||||
if cli.shared_params.dev {
|
||||
config.dev_key_seed = cli.keyring.account
|
||||
.map(|a| format!("//{}", a))
|
||||
.or_else(|| Some("//Alice".into()));
|
||||
}
|
||||
|
||||
if cli.shared_params.dev && cli.keyring.account.is_none() {
|
||||
config.keys.push("//Alice".into());
|
||||
}
|
||||
|
||||
if let Some(account) = cli.keyring.account {
|
||||
config.keys.push(format!("//{}", account));
|
||||
}
|
||||
|
||||
let rpc_interface: &str = if cli.rpc_external { "0.0.0.0" } else { "127.0.0.1" };
|
||||
let ws_interface: &str = if cli.ws_external { "0.0.0.0" } else { "127.0.0.1" };
|
||||
|
||||
@@ -36,9 +36,13 @@ arg_enum! {
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ExecutionStrategy {
|
||||
// Execute with native build (if available, WebAssembly otherwise).
|
||||
Native,
|
||||
// Only execute with the WebAssembly build.
|
||||
Wasm,
|
||||
// Execute with both native (where available) and WebAssembly builds.
|
||||
Both,
|
||||
// Execute with the native build if possible; if it fails, then execute with WebAssembly.
|
||||
NativeElseWasm,
|
||||
}
|
||||
}
|
||||
@@ -55,7 +59,8 @@ impl Into<client::ExecutionStrategy> for ExecutionStrategy {
|
||||
}
|
||||
|
||||
arg_enum! {
|
||||
/// How to execute blocks
|
||||
/// Whether off-chain workers are enabled.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum OffchainWorkerEnabled {
|
||||
Always,
|
||||
@@ -306,14 +311,6 @@ pub struct ExecutionStrategies {
|
||||
/// The `run` command used to run a node.
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
pub struct RunCmd {
|
||||
/// Specify custom keystore path
|
||||
#[structopt(long = "keystore-path", value_name = "PATH", parse(from_os_str))]
|
||||
pub keystore_path: Option<PathBuf>,
|
||||
|
||||
/// Specify additional key seed
|
||||
#[structopt(long = "key", value_name = "STRING")]
|
||||
pub key: Option<String>,
|
||||
|
||||
/// Enable validator mode
|
||||
#[structopt(long = "validator")]
|
||||
pub validator: bool,
|
||||
@@ -422,9 +419,32 @@ pub struct RunCmd {
|
||||
#[structopt(long = "force-authoring")]
|
||||
pub force_authoring: bool,
|
||||
|
||||
/// Interactive password for validator key.
|
||||
#[structopt(short = "i")]
|
||||
pub interactive_password: bool,
|
||||
/// Specify custom keystore path.
|
||||
#[structopt(long = "keystore-path", value_name = "PATH", parse(from_os_str))]
|
||||
pub keystore_path: Option<PathBuf>,
|
||||
|
||||
/// Use interactive shell for entering the password used by the keystore.
|
||||
#[structopt(
|
||||
long = "password-interactive",
|
||||
raw(conflicts_with_all = "&[ \"password\", \"password_filename\" ]")
|
||||
)]
|
||||
pub password_interactive: bool,
|
||||
|
||||
/// Password used by the keystore.
|
||||
#[structopt(
|
||||
long = "password",
|
||||
raw(conflicts_with_all = "&[ \"password_interactive\", \"password_filename\" ]")
|
||||
)]
|
||||
pub password: Option<String>,
|
||||
|
||||
/// File that contains the password used by the keystore.
|
||||
#[structopt(
|
||||
long = "password-filename",
|
||||
value_name = "PATH",
|
||||
parse(from_os_str),
|
||||
raw(conflicts_with_all = "&[ \"password_interactive\", \"password\" ]")
|
||||
)]
|
||||
pub password_filename: Option<PathBuf>
|
||||
}
|
||||
|
||||
/// Stores all required Cli values for a keyring test account.
|
||||
@@ -443,7 +463,7 @@ lazy_static::lazy_static! {
|
||||
let conflicts_with = keyring::Sr25519Keyring::iter()
|
||||
.filter(|b| a != *b)
|
||||
.map(|b| b.to_string().to_lowercase())
|
||||
.chain(["name", "key"].iter().map(ToString::to_string))
|
||||
.chain(std::iter::once("name".to_string()))
|
||||
.collect::<Vec<_>>();
|
||||
let name = a.to_string().to_lowercase();
|
||||
|
||||
@@ -485,6 +505,7 @@ impl AugmentClap for Keyring {
|
||||
.long(&a.name)
|
||||
.help(&a.help)
|
||||
.conflicts_with_all(&conflicts_with_strs)
|
||||
.requires("dev")
|
||||
.takes_value(false)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@ edition = "2018"
|
||||
derive_more = { version = "0.14.0", optional = true }
|
||||
fnv = { version = "1.0", optional = true }
|
||||
log = { version = "0.4", optional = true }
|
||||
parking_lot = { version = "0.8.0", optional = true }
|
||||
parking_lot = { version = "0.9.0", optional = true }
|
||||
hex = { package = "hex-literal", version = "0.2", optional = true }
|
||||
futures-preview = { version = "0.3.0-alpha.17", optional = true }
|
||||
consensus = { package = "substrate-consensus-common", path = "../consensus/common", optional = true }
|
||||
|
||||
@@ -5,7 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
parking_lot = "0.8"
|
||||
parking_lot = "0.9.0"
|
||||
log = "0.4"
|
||||
kvdb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" }
|
||||
# FIXME replace with release as soon as our rocksdb changes are released upstream https://github.com/paritytech/parity-common/issues/88
|
||||
|
||||
@@ -195,6 +195,7 @@ pub fn new_client<E, S, Block, RA>(
|
||||
executor: E,
|
||||
genesis_storage: S,
|
||||
execution_strategies: ExecutionStrategies,
|
||||
keystore: Option<primitives::traits::BareCryptoStorePtr>,
|
||||
) -> Result<
|
||||
client::Client<Backend<Block>,
|
||||
client::LocalCallExecutor<Backend<Block>, E>, Block, RA>, client::error::Error
|
||||
@@ -205,7 +206,7 @@ pub fn new_client<E, S, Block, RA>(
|
||||
S: BuildStorage,
|
||||
{
|
||||
let backend = Arc::new(Backend::new(settings, CANONICALIZATION_DELAY)?);
|
||||
let executor = client::LocalCallExecutor::new(backend.clone(), executor);
|
||||
let executor = client::LocalCallExecutor::new(backend.clone(), executor, keystore);
|
||||
Ok(client::Client::new(backend, executor, genesis_storage, execution_strategies)?)
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ where
|
||||
native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
proof_recorder: &Option<Rc<RefCell<ProofRecorder<B>>>>,
|
||||
enable_keystore: bool,
|
||||
) -> error::Result<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone;
|
||||
|
||||
/// Extract RuntimeVersion of given block
|
||||
@@ -150,14 +151,20 @@ where
|
||||
pub struct LocalCallExecutor<B, E> {
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
keystore: Option<primitives::traits::BareCryptoStorePtr>,
|
||||
}
|
||||
|
||||
impl<B, E> LocalCallExecutor<B, E> {
|
||||
/// Creates new instance of local call executor.
|
||||
pub fn new(backend: Arc<B>, executor: E) -> Self {
|
||||
pub fn new(
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
keystore: Option<primitives::traits::BareCryptoStorePtr>,
|
||||
) -> Self {
|
||||
LocalCallExecutor {
|
||||
backend,
|
||||
executor,
|
||||
keystore,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,6 +174,7 @@ impl<B, E> Clone for LocalCallExecutor<B, E> where E: Clone {
|
||||
LocalCallExecutor {
|
||||
backend: self.backend.clone(),
|
||||
executor: self.executor.clone(),
|
||||
keystore: self.keystore.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,6 +205,7 @@ where
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
self.keystore.clone(),
|
||||
).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
|
||||
strategy.get_manager(),
|
||||
false,
|
||||
@@ -229,6 +238,7 @@ where
|
||||
native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
|
||||
enable_keystore: bool,
|
||||
) -> Result<NativeOrEncoded<R>, error::Error> where ExecutionManager<EM>: Clone {
|
||||
match initialize_block {
|
||||
InitializeBlock::Do(ref init_block)
|
||||
@@ -239,6 +249,12 @@ where
|
||||
_ => {},
|
||||
}
|
||||
|
||||
let keystore = if enable_keystore {
|
||||
self.keystore.clone()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut state = self.backend.state_at(*at)?;
|
||||
|
||||
let result = match recorder {
|
||||
@@ -262,6 +278,7 @@ where
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
keystore,
|
||||
)
|
||||
.execute_using_consensus_failure_handler(
|
||||
execution_manager,
|
||||
@@ -279,6 +296,7 @@ where
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
keystore,
|
||||
)
|
||||
.execute_using_consensus_failure_handler(
|
||||
execution_manager,
|
||||
@@ -294,7 +312,14 @@ where
|
||||
fn runtime_version(&self, id: &BlockId<Block>) -> error::Result<RuntimeVersion> {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
let state = self.backend.state_at(*id)?;
|
||||
let mut ext = Ext::new(&mut overlay, &state, self.backend.changes_trie_storage(), NeverOffchainExt::new());
|
||||
|
||||
let mut ext = Ext::new(
|
||||
&mut overlay,
|
||||
&state,
|
||||
self.backend.changes_trie_storage(),
|
||||
NeverOffchainExt::new(),
|
||||
None,
|
||||
);
|
||||
let version = self.executor.runtime_version(&mut ext);
|
||||
self.backend.destroy_state(state)?;
|
||||
version.ok_or(error::Error::VersionInvalid.into())
|
||||
@@ -330,6 +355,7 @@ where
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
self.keystore.clone(),
|
||||
).execute_using_consensus_failure_handler(
|
||||
manager,
|
||||
true,
|
||||
@@ -356,6 +382,7 @@ where
|
||||
&self.executor,
|
||||
method,
|
||||
call_data,
|
||||
self.keystore.clone(),
|
||||
)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -20,66 +20,59 @@ use std::{
|
||||
marker::PhantomData, collections::{HashSet, BTreeMap, HashMap}, sync::Arc,
|
||||
panic::UnwindSafe, result, cell::RefCell, rc::Rc,
|
||||
};
|
||||
use crate::error::Error;
|
||||
use log::{info, trace, warn};
|
||||
use futures::channel::mpsc;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use primitives::NativeOrEncoded;
|
||||
use sr_primitives::{
|
||||
Justification,
|
||||
generic::{BlockId, SignedBlock},
|
||||
};
|
||||
use consensus::{
|
||||
Error as ConsensusError, BlockImportParams,
|
||||
ImportResult, BlockOrigin, ForkChoiceStrategy,
|
||||
well_known_cache_keys::Id as CacheKeyId,
|
||||
SelectChain, self,
|
||||
};
|
||||
use sr_primitives::traits::{
|
||||
Block as BlockT, Header as HeaderT, Zero, NumberFor,
|
||||
ApiRef, ProvideRuntimeApi, SaturatedConversion, One, DigestFor,
|
||||
};
|
||||
use sr_primitives::generic::DigestItem;
|
||||
use sr_primitives::BuildStorage;
|
||||
use crate::runtime_api::{
|
||||
CallRuntimeAt, ConstructRuntimeApi, Core as CoreApi, ProofRecorder,
|
||||
InitializeBlock,
|
||||
};
|
||||
use codec::{Encode, Decode};
|
||||
use hash_db::{Hasher, Prefix};
|
||||
use primitives::{
|
||||
Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash,
|
||||
NeverNativeValue, ExecutionContext
|
||||
NeverNativeValue, ExecutionContext,
|
||||
storage::{StorageKey, StorageData, well_known_keys}, NativeOrEncoded
|
||||
};
|
||||
use substrate_telemetry::{telemetry, SUBSTRATE_INFO};
|
||||
use sr_primitives::{
|
||||
Justification, BuildStorage,
|
||||
generic::{BlockId, SignedBlock, DigestItem},
|
||||
traits::{
|
||||
Block as BlockT, Header as HeaderT, Zero, NumberFor,
|
||||
ApiRef, ProvideRuntimeApi, SaturatedConversion, One, DigestFor,
|
||||
},
|
||||
};
|
||||
use primitives::storage::{StorageKey, StorageData};
|
||||
use primitives::storage::well_known_keys;
|
||||
use codec::{Encode, Decode};
|
||||
use state_machine::{
|
||||
DBValue, Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId,
|
||||
ExecutionStrategy, ExecutionManager, prove_read, prove_child_read,
|
||||
ChangesTrieRootsStorage, ChangesTrieStorage,
|
||||
key_changes, key_changes_proof, OverlayedChanges, NeverOffchainExt,
|
||||
};
|
||||
use hash_db::{Hasher, Prefix};
|
||||
|
||||
use crate::backend::{
|
||||
self, BlockImportOperation, PrunableStateChangesTrieStorage,
|
||||
StorageCollection, ChildStorageCollection
|
||||
};
|
||||
use crate::blockchain::{
|
||||
self, Info as ChainInfo, Backend as ChainBackend,
|
||||
HeaderBackend as ChainHeaderBackend, ProvideCache, Cache,
|
||||
};
|
||||
use crate::call_executor::{CallExecutor, LocalCallExecutor};
|
||||
use executor::{RuntimeVersion, RuntimeInfo};
|
||||
use crate::notifications::{StorageNotifications, StorageEventStream};
|
||||
use crate::light::{call_executor::prove_execution, fetcher::ChangesProof};
|
||||
use crate::cht;
|
||||
use crate::error;
|
||||
use crate::in_mem;
|
||||
use crate::block_builder::{self, api::BlockBuilder as BlockBuilderAPI};
|
||||
use crate::genesis;
|
||||
use substrate_telemetry::{telemetry, SUBSTRATE_INFO};
|
||||
|
||||
use log::{info, trace, warn};
|
||||
use consensus::{
|
||||
Error as ConsensusError, BlockImportParams,
|
||||
ImportResult, BlockOrigin, ForkChoiceStrategy,
|
||||
well_known_cache_keys::Id as CacheKeyId,
|
||||
SelectChain, self,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
runtime_api::{
|
||||
CallRuntimeAt, ConstructRuntimeApi, Core as CoreApi, ProofRecorder,
|
||||
InitializeBlock,
|
||||
},
|
||||
backend::{
|
||||
self, BlockImportOperation, PrunableStateChangesTrieStorage,
|
||||
StorageCollection, ChildStorageCollection
|
||||
},
|
||||
blockchain::{
|
||||
self, Info as ChainInfo, Backend as ChainBackend,
|
||||
HeaderBackend as ChainHeaderBackend, ProvideCache, Cache,
|
||||
},
|
||||
call_executor::{CallExecutor, LocalCallExecutor},
|
||||
notifications::{StorageNotifications, StorageEventStream},
|
||||
light::{call_executor::prove_execution, fetcher::ChangesProof},
|
||||
block_builder::{self, api::BlockBuilder as BlockBuilderAPI},
|
||||
error::Error,
|
||||
cht, error, in_mem, genesis
|
||||
};
|
||||
|
||||
/// Type that implements `futures::Stream` of block import events.
|
||||
pub type ImportNotifications<Block> = mpsc::UnboundedReceiver<BlockImportNotification<Block>>;
|
||||
@@ -260,6 +253,7 @@ impl<H> PrePostHeader<H> {
|
||||
pub fn new_in_mem<E, Block, S, RA>(
|
||||
executor: E,
|
||||
genesis_storage: S,
|
||||
keystore: Option<primitives::traits::BareCryptoStorePtr>,
|
||||
) -> error::Result<Client<
|
||||
in_mem::Backend<Block, Blake2Hasher>,
|
||||
LocalCallExecutor<in_mem::Backend<Block, Blake2Hasher>, E>,
|
||||
@@ -270,7 +264,7 @@ pub fn new_in_mem<E, Block, S, RA>(
|
||||
S: BuildStorage,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
new_with_backend(Arc::new(in_mem::Backend::new()), executor, genesis_storage)
|
||||
new_with_backend(Arc::new(in_mem::Backend::new()), executor, genesis_storage, keystore)
|
||||
}
|
||||
|
||||
/// Create a client with the explicitly provided backend.
|
||||
@@ -279,6 +273,7 @@ pub fn new_with_backend<B, E, Block, S, RA>(
|
||||
backend: Arc<B>,
|
||||
executor: E,
|
||||
build_genesis_storage: S,
|
||||
keystore: Option<primitives::traits::BareCryptoStorePtr>,
|
||||
) -> error::Result<Client<B, LocalCallExecutor<B, E>, Block, RA>>
|
||||
where
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
@@ -286,10 +281,24 @@ pub fn new_with_backend<B, E, Block, S, RA>(
|
||||
Block: BlockT<Hash=H256>,
|
||||
B: backend::LocalBackend<Block, Blake2Hasher>
|
||||
{
|
||||
let call_executor = LocalCallExecutor::new(backend.clone(), executor);
|
||||
let call_executor = LocalCallExecutor::new(backend.clone(), executor, keystore);
|
||||
Client::new(backend, call_executor, build_genesis_storage, Default::default())
|
||||
}
|
||||
|
||||
/// Figure out the block type for a given type (for now, just a `Client`).
|
||||
pub trait BlockOf {
|
||||
/// The type of the block.
|
||||
type Type: BlockT<Hash=H256>;
|
||||
}
|
||||
|
||||
impl<B, E, Block, RA> BlockOf for Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type Type = Block;
|
||||
}
|
||||
|
||||
impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
@@ -362,7 +371,8 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
pub fn storage(&self, id: &BlockId<Block>, key: &StorageKey) -> error::Result<Option<StorageData>> {
|
||||
Ok(self.state_at(id)?
|
||||
.storage(&key.0).map_err(|e| error::Error::from_state(Box::new(e)))?
|
||||
.map(StorageData))
|
||||
.map(StorageData)
|
||||
)
|
||||
}
|
||||
|
||||
/// Given a `BlockId` and a key, return the value under the hash in that block.
|
||||
@@ -1414,6 +1424,8 @@ impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
|
||||
context: ExecutionContext,
|
||||
recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
|
||||
) -> error::Result<NativeOrEncoded<R>> {
|
||||
let enable_keystore = context.enable_keystore();
|
||||
|
||||
let manager = match context {
|
||||
ExecutionContext::BlockConstruction =>
|
||||
self.execution_strategies.block_construction.get_manager(),
|
||||
@@ -1443,6 +1455,7 @@ impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
|
||||
native_call,
|
||||
offchain_extensions.as_mut(),
|
||||
recorder,
|
||||
enable_keystore,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ mod tests {
|
||||
&executor(),
|
||||
"Core_initialize_block",
|
||||
&header.encode(),
|
||||
None,
|
||||
).execute(
|
||||
ExecutionStrategy::NativeElseWasm,
|
||||
).unwrap();
|
||||
@@ -109,6 +110,7 @@ mod tests {
|
||||
&executor(),
|
||||
"BlockBuilder_apply_extrinsic",
|
||||
&tx.encode(),
|
||||
None,
|
||||
).execute(
|
||||
ExecutionStrategy::NativeElseWasm,
|
||||
).unwrap();
|
||||
@@ -122,6 +124,7 @@ mod tests {
|
||||
&executor(),
|
||||
"BlockBuilder_finalize_block",
|
||||
&[],
|
||||
None,
|
||||
).execute(
|
||||
ExecutionStrategy::NativeElseWasm,
|
||||
).unwrap();
|
||||
@@ -148,7 +151,7 @@ mod tests {
|
||||
#[test]
|
||||
fn construct_genesis_should_work_with_native() {
|
||||
let mut storage = GenesisConfig::new(false,
|
||||
vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()],
|
||||
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
|
||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||
1000,
|
||||
None,
|
||||
@@ -170,6 +173,7 @@ mod tests {
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
None,
|
||||
).execute(
|
||||
ExecutionStrategy::NativeElseWasm,
|
||||
).unwrap();
|
||||
@@ -178,7 +182,7 @@ mod tests {
|
||||
#[test]
|
||||
fn construct_genesis_should_work_with_wasm() {
|
||||
let mut storage = GenesisConfig::new(false,
|
||||
vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()],
|
||||
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
|
||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||
1000,
|
||||
None,
|
||||
@@ -200,6 +204,7 @@ mod tests {
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
None,
|
||||
).execute(
|
||||
ExecutionStrategy::AlwaysWasm,
|
||||
).unwrap();
|
||||
@@ -208,7 +213,7 @@ mod tests {
|
||||
#[test]
|
||||
fn construct_genesis_with_bad_transaction_should_panic() {
|
||||
let mut storage = GenesisConfig::new(false,
|
||||
vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()],
|
||||
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
|
||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||
68,
|
||||
None,
|
||||
@@ -230,6 +235,7 @@ mod tests {
|
||||
&executor(),
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
None,
|
||||
).execute(
|
||||
ExecutionStrategy::NativeElseWasm,
|
||||
);
|
||||
|
||||
@@ -62,7 +62,8 @@
|
||||
//! backend.clone(),
|
||||
//! LocalCallExecutor::new(
|
||||
//! backend.clone(),
|
||||
//! NativeExecutor::<LocalExecutor>::new(None)
|
||||
//! NativeExecutor::<LocalExecutor>::new(None),
|
||||
//! None,
|
||||
//! ),
|
||||
//! // This parameter provides the storage for the chain genesis.
|
||||
//! <(StorageOverlay, ChildrenStorageOverlay)>::default(),
|
||||
@@ -114,7 +115,7 @@ pub use crate::client::{
|
||||
new_in_mem,
|
||||
BlockBody, BlockStatus, ImportNotifications, FinalityNotifications, BlockchainEvents,
|
||||
BlockImportNotification, Client, ClientInfo, ExecutionStrategies, FinalityNotification,
|
||||
LongestChain,
|
||||
LongestChain, BlockOf,
|
||||
utils,
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
|
||||
@@ -94,8 +94,8 @@ where
|
||||
call_data: &[u8],
|
||||
_strategy: ExecutionStrategy,
|
||||
_side_effects_handler: Option<&mut O>,
|
||||
)
|
||||
-> ClientResult<Vec<u8>> {
|
||||
) -> ClientResult<Vec<u8>>
|
||||
{
|
||||
let block_hash = self.blockchain.expect_block_hash_from_id(id)?;
|
||||
let block_header = self.blockchain.expect_header(id.clone())?;
|
||||
|
||||
@@ -130,6 +130,7 @@ where
|
||||
_native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
_recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
|
||||
_enable_keystore: bool,
|
||||
) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone {
|
||||
let block_initialized = match initialize_block {
|
||||
InitializeBlock::Do(ref init_block) => {
|
||||
@@ -143,11 +144,23 @@ where
|
||||
return Err(ClientError::NotAvailableOnLightClient.into());
|
||||
}
|
||||
|
||||
self.call(at, method, call_data, (&execution_manager).into(), side_effects_handler).map(NativeOrEncoded::Encoded)
|
||||
self.call(
|
||||
at,
|
||||
method,
|
||||
call_data,
|
||||
(&execution_manager).into(),
|
||||
side_effects_handler,
|
||||
).map(NativeOrEncoded::Encoded)
|
||||
}
|
||||
|
||||
fn runtime_version(&self, id: &BlockId<Block>) -> ClientResult<RuntimeVersion> {
|
||||
let call_result = self.call(id, "Core_version", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new())?;
|
||||
let call_result = self.call(
|
||||
id,
|
||||
"Core_version",
|
||||
&[],
|
||||
ExecutionStrategy::NativeElseWasm,
|
||||
NeverOffchainExt::new()
|
||||
)?;
|
||||
RuntimeVersion::decode(&mut call_result.as_slice())
|
||||
.map_err(|_| ClientError::VersionInvalid.into())
|
||||
}
|
||||
@@ -270,6 +283,7 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
native_call: Option<NC>,
|
||||
side_effects_handler: Option<&mut O>,
|
||||
recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>,
|
||||
enable_keystore: bool,
|
||||
) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone {
|
||||
// there's no actual way/need to specify native/wasm execution strategy on light node
|
||||
// => we can safely ignore passed values
|
||||
@@ -296,6 +310,7 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
native_call,
|
||||
side_effects_handler,
|
||||
recorder,
|
||||
enable_keystore,
|
||||
).map_err(|e| ClientError::Execution(Box::new(e.to_string()))),
|
||||
false => CallExecutor::contextual_call::<
|
||||
_,
|
||||
@@ -318,6 +333,7 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for
|
||||
native_call,
|
||||
side_effects_handler,
|
||||
recorder,
|
||||
enable_keystore,
|
||||
).map_err(|e| ClientError::Execution(Box::new(e.to_string()))),
|
||||
}
|
||||
}
|
||||
@@ -463,6 +479,7 @@ pub fn check_execution_proof<Header, E, H>(
|
||||
executor,
|
||||
"Core_initialize_block",
|
||||
&next_block.encode(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
// execute method
|
||||
@@ -472,6 +489,7 @@ pub fn check_execution_proof<Header, E, H>(
|
||||
executor,
|
||||
&request.method,
|
||||
&request.call_data,
|
||||
None,
|
||||
)?;
|
||||
|
||||
Ok(local_result)
|
||||
|
||||
@@ -424,7 +424,6 @@ impl<E, Block, H, S, F> FetchChecker<Block> for LightDataChecker<E, H, Block, S,
|
||||
request: &RemoteBodyRequest<Block::Header>,
|
||||
body: Vec<Block::Extrinsic>
|
||||
) -> ClientResult<Vec<Block::Extrinsic>> {
|
||||
|
||||
// TODO: #2621
|
||||
let extrinsics_root = HashFor::<Block>::ordered_trie_root(body.iter().map(Encode::encode));
|
||||
if *request.header.extrinsics_root() == extrinsics_root {
|
||||
|
||||
@@ -73,7 +73,7 @@ pub fn new_light<B, S, F, GS, RA, E>(
|
||||
E: CodeExecutor<Blake2Hasher> + RuntimeInfo,
|
||||
{
|
||||
let remote_executor = RemoteCallExecutor::new(backend.blockchain().clone(), fetcher);
|
||||
let local_executor = LocalCallExecutor::new(backend.clone(), code_executor);
|
||||
let local_executor = LocalCallExecutor::new(backend.clone(), code_executor, None);
|
||||
let executor = RemoteOrLocalCallExecutor::new(backend.clone(), remote_executor, local_executor);
|
||||
Client::new(backend, executor, genesis_storage, Default::default())
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0" }
|
||||
primitives = { package = "substrate-primitives", path = "../../primitives" }
|
||||
app-crypto = { package = "substrate-application-crypto", path = "../../application-crypto" }
|
||||
runtime_support = { package = "srml-support", path = "../../../srml/support" }
|
||||
runtime_version = { package = "sr-version", path = "../../sr-version" }
|
||||
runtime_io = { package = "sr-io", path = "../../sr-io" }
|
||||
@@ -17,12 +18,13 @@ inherents = { package = "substrate-inherents", path = "../../inherents" }
|
||||
srml-aura = { path = "../../../srml/aura" }
|
||||
client = { package = "substrate-client", path = "../../client" }
|
||||
substrate-telemetry = { path = "../../telemetry" }
|
||||
substrate-keystore = { path = "../../keystore" }
|
||||
consensus_common = { package = "substrate-consensus-common", path = "../common" }
|
||||
sr-primitives = { path = "../../sr-primitives" }
|
||||
futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] }
|
||||
futures01 = { package = "futures", version = "0.1" }
|
||||
futures-timer = "0.2.1"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
log = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -8,7 +8,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false }
|
||||
substrate-client = { path = "../../../client", default-features = false }
|
||||
primitives = { package = "substrate-primitives", path = "../../../primitives", default-features = false }
|
||||
app-crypto = { package = "substrate-application-crypto", path = "../../../application-crypto", default-features = false }
|
||||
rstd = { package = "sr-std", path = "../../../sr-std", default-features = false }
|
||||
sr-primitives = { path = "../../../sr-primitives", default-features = false }
|
||||
|
||||
@@ -19,5 +19,5 @@ std = [
|
||||
"codec/std",
|
||||
"sr-primitives/std",
|
||||
"substrate-client/std",
|
||||
"primitives/std",
|
||||
"app-crypto/std",
|
||||
]
|
||||
|
||||
@@ -23,6 +23,40 @@ use substrate_client::decl_runtime_apis;
|
||||
use rstd::vec::Vec;
|
||||
use sr_primitives::ConsensusEngineId;
|
||||
|
||||
mod app_sr25519 {
|
||||
use app_crypto::{app_crypto, key_types::AURA, sr25519};
|
||||
app_crypto!(sr25519, AURA);
|
||||
}
|
||||
|
||||
pub mod sr25519 {
|
||||
/// An Aura authority keypair using S/R 25519 as its crypto.
|
||||
#[cfg(feature = "std")]
|
||||
pub type AuthorityPair = super::app_sr25519::Pair;
|
||||
|
||||
/// An Aura authority signature using S/R 25519 as its crypto.
|
||||
pub type AuthoritySignature = super::app_sr25519::Signature;
|
||||
|
||||
/// An Aura authority identifier using S/R 25519 as its crypto.
|
||||
pub type AuthorityId = super::app_sr25519::Public;
|
||||
}
|
||||
|
||||
mod app_ed25519 {
|
||||
use app_crypto::{app_crypto, key_types::AURA, ed25519};
|
||||
app_crypto!(ed25519, AURA);
|
||||
}
|
||||
|
||||
pub mod ed25519 {
|
||||
/// An Aura authority keypair using Ed25519 as its crypto.
|
||||
#[cfg(feature = "std")]
|
||||
pub type AuthorityPair = super::app_ed25519::Pair;
|
||||
|
||||
/// An Aura authority signature using Ed25519 as its crypto.
|
||||
pub type AuthoritySignature = super::app_ed25519::Signature;
|
||||
|
||||
/// An Aura authority identifier using Ed25519 as its crypto.
|
||||
pub type AuthorityId = super::app_ed25519::Public;
|
||||
}
|
||||
|
||||
/// The `ConsensusEngineId` of AuRa.
|
||||
pub const AURA_ENGINE_ID: ConsensusEngineId = [b'a', b'u', b'r', b'a'];
|
||||
|
||||
|
||||
@@ -44,12 +44,13 @@ use client::{
|
||||
runtime_api::ApiExt,
|
||||
error::Result as CResult,
|
||||
backend::AuxStore,
|
||||
BlockOf
|
||||
};
|
||||
|
||||
use sr_primitives::{generic::{self, BlockId, OpaqueDigestItemId}, Justification};
|
||||
use sr_primitives::traits::{Block as BlockT, Header, DigestItemFor, ProvideRuntimeApi, Zero, Member};
|
||||
|
||||
use primitives::Pair;
|
||||
use primitives::crypto::Pair;
|
||||
use inherents::{InherentDataProviders, InherentData};
|
||||
|
||||
use futures::{prelude::*, future};
|
||||
@@ -141,7 +142,7 @@ pub fn start_aura<B, C, SC, E, I, P, SO, Error, H>(
|
||||
force_authoring: bool,
|
||||
) -> Result<impl futures01::Future<Item = (), Error = ()>, consensus_common::Error> where
|
||||
B: BlockT<Header=H>,
|
||||
C: ProvideRuntimeApi + ProvideCache<B> + AuxStore + Send + Sync,
|
||||
C: ProvideRuntimeApi + BlockOf + ProvideCache<B> + AuxStore + Send + Sync,
|
||||
C::Api: AuraApi<B, AuthorityId<P>>,
|
||||
SC: SelectChain<B>,
|
||||
E::Proposer: Proposer<B, Error=Error>,
|
||||
@@ -188,7 +189,7 @@ struct AuraWorker<C, E, I, P, SO> {
|
||||
|
||||
impl<H, B, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, SO> where
|
||||
B: BlockT<Header=H>,
|
||||
C: ProvideRuntimeApi + ProvideCache<B> + Sync,
|
||||
C: ProvideRuntimeApi + BlockOf + ProvideCache<B> + Sync,
|
||||
C::Api: AuraApi<B, AuthorityId<P>>,
|
||||
E: Environment<B, Error=Error>,
|
||||
E::Proposer: Proposer<B, Error=Error>,
|
||||
@@ -397,7 +398,7 @@ fn check_header<C, B: BlockT, P: Pair>(
|
||||
DigestItemFor<B>: CompatibleDigestItem<P>,
|
||||
P::Signature: Decode,
|
||||
C: client::backend::AuxStore,
|
||||
P::Public: AsRef<P::Public> + Encode + Decode + PartialEq + Clone,
|
||||
P::Public: Encode + Decode + PartialEq + Clone,
|
||||
{
|
||||
let seal = match header.digest_mut().pop() {
|
||||
Some(x) => x,
|
||||
@@ -507,11 +508,11 @@ impl<C, P> AuraVerifier<C, P>
|
||||
|
||||
#[forbid(deprecated)]
|
||||
impl<B: BlockT, C, P> Verifier<B> for AuraVerifier<C, P> where
|
||||
C: ProvideRuntimeApi + Send + Sync + client::backend::AuxStore + ProvideCache<B>,
|
||||
C: ProvideRuntimeApi + Send + Sync + client::backend::AuxStore + ProvideCache<B> + BlockOf,
|
||||
C::Api: BlockBuilderApi<B> + AuraApi<B, AuthorityId<P>>,
|
||||
DigestItemFor<B>: CompatibleDigestItem<P>,
|
||||
P: Pair + Send + Sync + 'static,
|
||||
P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + AsRef<P::Public> + 'static,
|
||||
P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + 'static,
|
||||
P::Signature: Encode + Decode,
|
||||
{
|
||||
fn verify(
|
||||
@@ -610,7 +611,7 @@ impl<B: BlockT, C, P> Verifier<B> for AuraVerifier<C, P> where
|
||||
fn initialize_authorities_cache<A, B, C>(client: &C) -> Result<(), ConsensusError> where
|
||||
A: Codec,
|
||||
B: BlockT,
|
||||
C: ProvideRuntimeApi + ProvideCache<B>,
|
||||
C: ProvideRuntimeApi + BlockOf + ProvideCache<B>,
|
||||
C::Api: AuraApi<B, A>,
|
||||
{
|
||||
// no cache => no initialization
|
||||
@@ -644,7 +645,7 @@ fn initialize_authorities_cache<A, B, C>(client: &C) -> Result<(), ConsensusErro
|
||||
fn authorities<A, B, C>(client: &C, at: &BlockId<B>) -> Result<Vec<A>, ConsensusError> where
|
||||
A: Codec,
|
||||
B: BlockT,
|
||||
C: ProvideRuntimeApi + ProvideCache<B>,
|
||||
C: ProvideRuntimeApi + BlockOf + ProvideCache<B>,
|
||||
C::Api: AuraApi<B, A>,
|
||||
{
|
||||
client
|
||||
@@ -685,11 +686,11 @@ pub fn import_queue<B, C, P>(
|
||||
inherent_data_providers: InherentDataProviders,
|
||||
) -> Result<AuraImportQueue<B>, consensus_common::Error> where
|
||||
B: BlockT,
|
||||
C: 'static + ProvideRuntimeApi + ProvideCache<B> + Send + Sync + AuxStore,
|
||||
C: 'static + ProvideRuntimeApi + BlockOf + ProvideCache<B> + Send + Sync + AuxStore,
|
||||
C::Api: BlockBuilderApi<B> + AuraApi<B, AuthorityId<P>>,
|
||||
DigestItemFor<B>: CompatibleDigestItem<P>,
|
||||
P: Pair + Send + Sync + 'static,
|
||||
P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode + AsRef<P::Public>,
|
||||
P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode,
|
||||
P::Signature: Encode + Decode,
|
||||
{
|
||||
register_aura_inherent_data_provider(&inherent_data_providers, slot_duration.get())?;
|
||||
@@ -721,9 +722,9 @@ mod tests {
|
||||
use parking_lot::Mutex;
|
||||
use tokio::runtime::current_thread;
|
||||
use keyring::sr25519::Keyring;
|
||||
use primitives::sr25519;
|
||||
use client::{LongestChain, BlockchainEvents};
|
||||
use test_client;
|
||||
use aura_primitives::sr25519::AuthorityPair;
|
||||
|
||||
type Error = client::error::Error;
|
||||
|
||||
@@ -771,7 +772,7 @@ mod tests {
|
||||
|
||||
impl TestNetFactory for AuraTestNet {
|
||||
type Specialization = DummySpecialization;
|
||||
type Verifier = AuraVerifier<PeersFullClient, sr25519::Pair>;
|
||||
type Verifier = AuraVerifier<PeersFullClient, AuthorityPair>;
|
||||
type PeerData = ();
|
||||
|
||||
/// Create new test network with peers and given config.
|
||||
@@ -855,9 +856,9 @@ mod tests {
|
||||
&inherent_data_providers, slot_duration.get()
|
||||
).expect("Registers aura inherent data provider");
|
||||
|
||||
let aura = start_aura::<_, _, _, _, _, sr25519::Pair, _, _, _>(
|
||||
let aura = start_aura::<_, _, _, _, _, AuthorityPair, _, _, _>(
|
||||
slot_duration,
|
||||
Arc::new(key.clone().into()),
|
||||
Arc::new(key.clone().pair().into()),
|
||||
client.clone(),
|
||||
select_chain,
|
||||
client,
|
||||
@@ -885,9 +886,9 @@ mod tests {
|
||||
|
||||
assert_eq!(client.info().chain.best_number, 0);
|
||||
assert_eq!(authorities(&client, &BlockId::Number(0)).unwrap(), vec![
|
||||
Keyring::Alice.into(),
|
||||
Keyring::Bob.into(),
|
||||
Keyring::Charlie.into()
|
||||
Keyring::Alice.public().into(),
|
||||
Keyring::Bob.public().into(),
|
||||
Keyring::Charlie.public().into()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,24 +9,26 @@ edition = "2018"
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] }
|
||||
babe_primitives = { package = "substrate-consensus-babe-primitives", path = "primitives" }
|
||||
primitives = { package = "substrate-primitives", path = "../../primitives" }
|
||||
app-crypto = { package = "substrate-application-crypto", path = "../../application-crypto" }
|
||||
num-bigint = "0.2"
|
||||
num-rational = "0.2"
|
||||
num-traits = "0.2"
|
||||
runtime_support = { package = "srml-support", path = "../../../srml/support" }
|
||||
runtime_version = { package = "sr-version", path = "../../sr-version" }
|
||||
runtime_io = { package = "sr-io", path = "../../sr-io" }
|
||||
runtime-support = { package = "srml-support", path = "../../../srml/support" }
|
||||
runtime-version = { package = "sr-version", path = "../../sr-version" }
|
||||
runtime-io = { package = "sr-io", path = "../../sr-io" }
|
||||
inherents = { package = "substrate-inherents", path = "../../inherents" }
|
||||
substrate-telemetry = { path = "../../telemetry" }
|
||||
keystore = { package = "substrate-keystore", path = "../../keystore" }
|
||||
srml-babe = { path = "../../../srml/babe" }
|
||||
client = { package = "substrate-client", path = "../../client" }
|
||||
consensus_common = { package = "substrate-consensus-common", path = "../common" }
|
||||
consensus-common = { package = "substrate-consensus-common", path = "../common" }
|
||||
slots = { package = "substrate-consensus-slots", path = "../slots" }
|
||||
sr-primitives = { path = "../../sr-primitives" }
|
||||
fork-tree = { path = "../../utils/fork-tree" }
|
||||
futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] }
|
||||
futures01 = { package = "futures", version = "0.1" }
|
||||
futures-timer = "0.2.1"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
log = "0.4.6"
|
||||
schnorrkel = { version = "0.8.4", features = ["preaudit_deprecated"] }
|
||||
rand = "0.6.5"
|
||||
@@ -40,6 +42,7 @@ service = { package = "substrate-service", path = "../../service" }
|
||||
test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" }
|
||||
tokio = "0.1.18"
|
||||
env_logger = "0.6.1"
|
||||
tempfile = "3.1"
|
||||
|
||||
[features]
|
||||
test-helpers = []
|
||||
|
||||
@@ -9,7 +9,7 @@ edition = "2018"
|
||||
substrate-client = { path = "../../../client", default-features = false }
|
||||
rstd = { package = "sr-std", path = "../../../sr-std", default-features = false }
|
||||
sr-primitives = { path = "../../../sr-primitives", default-features = false }
|
||||
primitives = { package = "substrate-primitives", path = "../../../primitives", default-features = false }
|
||||
app-crypto = { package = "substrate-application-crypto", path = "../../../application-crypto", default-features = false }
|
||||
slots = { package = "substrate-consensus-slots", path = "../../slots", optional = true }
|
||||
schnorrkel = { version = "0.8.4", features = ["preaudit_deprecated"], optional = true }
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false }
|
||||
@@ -23,4 +23,5 @@ std = [
|
||||
"codec/std",
|
||||
"schnorrkel",
|
||||
"slots",
|
||||
"app-crypto/std",
|
||||
]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Private implementation details of BABE digests.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use primitives::sr25519::Signature;
|
||||
use super::AuthoritySignature;
|
||||
#[cfg(feature = "std")]
|
||||
use super::{BABE_ENGINE_ID, Epoch};
|
||||
#[cfg(not(feature = "std"))]
|
||||
@@ -111,10 +111,10 @@ pub trait CompatibleDigestItem: Sized {
|
||||
fn as_babe_pre_digest(&self) -> Option<BabePreDigest>;
|
||||
|
||||
/// Construct a digest item which contains a BABE seal.
|
||||
fn babe_seal(signature: Signature) -> Self;
|
||||
fn babe_seal(signature: AuthoritySignature) -> Self;
|
||||
|
||||
/// If this item is a BABE signature, return the signature.
|
||||
fn as_babe_seal(&self) -> Option<Signature>;
|
||||
fn as_babe_seal(&self) -> Option<AuthoritySignature>;
|
||||
|
||||
/// If this item is a BABE epoch, return it.
|
||||
fn as_babe_epoch(&self) -> Option<Epoch>;
|
||||
@@ -132,11 +132,11 @@ impl<Hash> CompatibleDigestItem for DigestItem<Hash> where
|
||||
self.try_to(OpaqueDigestItemId::PreRuntime(&BABE_ENGINE_ID))
|
||||
}
|
||||
|
||||
fn babe_seal(signature: Signature) -> Self {
|
||||
fn babe_seal(signature: AuthoritySignature) -> Self {
|
||||
DigestItem::Seal(BABE_ENGINE_ID, signature.encode())
|
||||
}
|
||||
|
||||
fn as_babe_seal(&self) -> Option<Signature> {
|
||||
fn as_babe_seal(&self) -> Option<AuthoritySignature> {
|
||||
self.try_to(OpaqueDigestItemId::Seal(&BABE_ENGINE_ID))
|
||||
}
|
||||
|
||||
|
||||
@@ -24,21 +24,28 @@ mod digest;
|
||||
use codec::{Encode, Decode};
|
||||
use rstd::vec::Vec;
|
||||
use sr_primitives::ConsensusEngineId;
|
||||
use primitives::sr25519;
|
||||
use substrate_client::decl_runtime_apis;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use digest::{BabePreDigest, CompatibleDigestItem};
|
||||
pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest};
|
||||
|
||||
mod app {
|
||||
use app_crypto::{app_crypto, key_types::BABE, sr25519};
|
||||
app_crypto!(sr25519, BABE);
|
||||
}
|
||||
|
||||
/// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in
|
||||
/// the main Babe module. If that ever changes, then this must, too.
|
||||
#[cfg(feature = "std")]
|
||||
pub type AuthorityPair = sr25519::Pair;
|
||||
pub type AuthorityPair = app::Pair;
|
||||
|
||||
/// A Babe authority signature.
|
||||
pub type AuthoritySignature = app::Signature;
|
||||
|
||||
/// A Babe authority identifier. Necessarily equivalent to the schnorrkel public key used in
|
||||
/// the main Babe module. If that ever changes, then this must, too.
|
||||
pub type AuthorityId = sr25519::Public;
|
||||
pub type AuthorityId = app::Public;
|
||||
|
||||
/// The `ConsensusEngineId` of BABE.
|
||||
pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE";
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
//!
|
||||
//! BABE (Blind Assignment for Blockchain Extension) consensus in Substrate.
|
||||
|
||||
#![forbid(unsafe_code, missing_docs, unused_must_use, unused_imports, unused_variables)]
|
||||
#![forbid(unsafe_code, missing_docs)]
|
||||
pub use babe_primitives::*;
|
||||
pub use consensus_common::SyncOracle;
|
||||
use std::{collections::HashMap, sync::Arc, u64, fmt::{Debug, Display}, pin::Pin, time::{Instant, Duration}};
|
||||
use babe_primitives;
|
||||
use consensus_common::ImportResult;
|
||||
use consensus_common::import_queue::{
|
||||
BoxJustificationImport, BoxFinalityProofImport,
|
||||
@@ -31,11 +33,11 @@ use sr_primitives::traits::{
|
||||
Block as BlockT, Header, DigestItemFor, NumberFor, ProvideRuntimeApi,
|
||||
SimpleBitOps, Zero,
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc, u64, fmt::{Debug, Display}, pin::Pin, time::{Instant, Duration}};
|
||||
use keystore::KeyStorePtr;
|
||||
use runtime_support::serde::{Serialize, Deserialize};
|
||||
use codec::{Decode, Encode};
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
use primitives::{Blake2Hasher, H256, Pair, Public, sr25519};
|
||||
use primitives::{Blake2Hasher, H256, Pair, Public};
|
||||
use merlin::Transcript;
|
||||
use inherents::{InherentDataProviders, InherentData};
|
||||
use substrate_telemetry::{
|
||||
@@ -63,12 +65,8 @@ use consensus_common::{SelectChain, well_known_cache_keys};
|
||||
use consensus_common::import_queue::{Verifier, BasicQueue};
|
||||
use client::{
|
||||
block_builder::api::BlockBuilder as BlockBuilderApi,
|
||||
blockchain::{self, HeaderBackend, ProvideCache},
|
||||
BlockchainEvents,
|
||||
CallExecutor, Client,
|
||||
runtime_api::ApiExt,
|
||||
error::Result as ClientResult,
|
||||
backend::{AuxStore, Backend},
|
||||
blockchain::{self, HeaderBackend, ProvideCache}, BlockchainEvents, CallExecutor, Client,
|
||||
runtime_api::ApiExt, error::Result as ClientResult, backend::{AuxStore, Backend},
|
||||
utils::is_descendent_of,
|
||||
};
|
||||
use fork_tree::ForkTree;
|
||||
@@ -135,13 +133,12 @@ impl SlotCompatible for BabeLink {
|
||||
|
||||
/// Parameters for BABE.
|
||||
pub struct BabeParams<C, E, I, SO, SC> {
|
||||
|
||||
/// The configuration for BABE. Includes the slot duration, threshold, and
|
||||
/// other parameters.
|
||||
pub config: Config,
|
||||
|
||||
/// The key of the node we are running on.
|
||||
pub local_key: Arc<sr25519::Pair>,
|
||||
/// The keystore that manages the keys of the node.
|
||||
pub keystore: KeyStorePtr,
|
||||
|
||||
/// The client to use
|
||||
pub client: Arc<C>,
|
||||
@@ -171,8 +168,8 @@ pub struct BabeParams<C, E, I, SO, SC> {
|
||||
/// Start the babe worker. The returned future should be run in a tokio runtime.
|
||||
pub fn start_babe<B, C, SC, E, I, SO, Error, H>(BabeParams {
|
||||
config,
|
||||
local_key,
|
||||
client,
|
||||
keystore,
|
||||
select_chain,
|
||||
block_import,
|
||||
env,
|
||||
@@ -200,10 +197,10 @@ pub fn start_babe<B, C, SC, E, I, SO, Error, H>(BabeParams {
|
||||
client: client.clone(),
|
||||
block_import: Arc::new(Mutex::new(block_import)),
|
||||
env,
|
||||
local_key,
|
||||
sync_oracle: sync_oracle.clone(),
|
||||
force_authoring,
|
||||
c: config.c(),
|
||||
keystore,
|
||||
};
|
||||
register_babe_inherent_data_provider(&inherent_data_providers, config.0.slot_duration())?;
|
||||
Ok(slots::start_slot_worker(
|
||||
@@ -220,10 +217,10 @@ struct BabeWorker<C, E, I, SO> {
|
||||
client: Arc<C>,
|
||||
block_import: Arc<Mutex<I>>,
|
||||
env: E,
|
||||
local_key: Arc<sr25519::Pair>,
|
||||
sync_oracle: SO,
|
||||
force_authoring: bool,
|
||||
c: (u64, u64),
|
||||
keystore: KeyStorePtr,
|
||||
}
|
||||
|
||||
impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> where
|
||||
@@ -248,7 +245,6 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
||||
chain_head: B::Header,
|
||||
slot_info: SlotInfo,
|
||||
) -> Self::OnSlot {
|
||||
let pair = self.local_key.clone();
|
||||
let ref client = self.client;
|
||||
let block_import = self.block_import.clone();
|
||||
|
||||
@@ -288,10 +284,10 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
||||
let proposal_work = if let Some(claim) = claim_slot(
|
||||
slot_info.number,
|
||||
epoch,
|
||||
&pair,
|
||||
self.c,
|
||||
&self.keystore,
|
||||
) {
|
||||
let ((inout, vrf_proof, _batchable_proof), authority_index) = claim;
|
||||
let ((inout, vrf_proof, _batchable_proof), authority_index, key) = claim;
|
||||
|
||||
debug!(
|
||||
target: "babe", "Starting authorship at slot {}; timestamp = {}",
|
||||
@@ -340,7 +336,7 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
||||
Delay::new(remaining_duration)
|
||||
.map_err(|err| consensus_common::Error::FaultyTimer(err).into())
|
||||
).map(|v| match v {
|
||||
futures::future::Either::Left((v, _)) => v,
|
||||
futures::future::Either::Left((v, _)) => v.map(|v| (v, key)),
|
||||
futures::future::Either::Right((Ok(_), _)) =>
|
||||
Err(consensus_common::Error::ClientImport("Timeout in the BaBe proposer".into())),
|
||||
futures::future::Either::Right((Err(err), _)) => Err(err),
|
||||
@@ -349,7 +345,7 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
||||
return Box::pin(future::ready(Ok(())));
|
||||
};
|
||||
|
||||
Box::pin(proposal_work.map_ok(move |b| {
|
||||
Box::pin(proposal_work.map_ok(move |(b, key)| {
|
||||
// minor hack since we don't have access to the timestamp
|
||||
// that is actually set by the proposer.
|
||||
let slot_after_building = SignedDuration::default().slot_now(slot_duration);
|
||||
@@ -372,7 +368,7 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
||||
// sign the pre-sealed hash of the block and then
|
||||
// add it to a digest item.
|
||||
let header_hash = header.hash();
|
||||
let signature = pair.sign(header_hash.as_ref());
|
||||
let signature = key.sign(header_hash.as_ref());
|
||||
let signature_digest_item = DigestItemFor::<B>::babe_seal(signature);
|
||||
|
||||
let import_block = BlockImportParams::<B> {
|
||||
@@ -496,7 +492,7 @@ fn check_header<B: BlockT + Sized, C: AuxStore>(
|
||||
} else {
|
||||
let (pre_hash, author) = (header.hash(), &authorities[authority_index as usize].0);
|
||||
|
||||
if sr25519::Pair::verify(&sig, pre_hash, author.clone()) {
|
||||
if AuthorityPair::verify(&sig, pre_hash, &author) {
|
||||
let (inout, _batchable_proof) = {
|
||||
let transcript = make_transcript(
|
||||
&randomness,
|
||||
@@ -769,8 +765,9 @@ fn register_babe_inherent_data_provider(
|
||||
}
|
||||
}
|
||||
|
||||
fn get_keypair(q: &sr25519::Pair) -> &Keypair {
|
||||
q.as_ref()
|
||||
fn get_keypair(q: &AuthorityPair) -> &Keypair {
|
||||
use primitives::crypto::IsWrappedBy;
|
||||
primitives::sr25519::Pair::from_ref(q).as_ref()
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
@@ -823,11 +820,15 @@ fn calculate_threshold(
|
||||
fn claim_slot(
|
||||
slot_number: u64,
|
||||
Epoch { ref authorities, ref randomness, epoch_index, .. }: Epoch,
|
||||
key: &sr25519::Pair,
|
||||
c: (u64, u64),
|
||||
) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize)> {
|
||||
let public = &key.public();
|
||||
let authority_index = authorities.iter().position(|s| &s.0 == public)?;
|
||||
keystore: &KeyStorePtr,
|
||||
) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize, AuthorityPair)> {
|
||||
let keystore = keystore.read();
|
||||
let (key_pair, authority_index) = authorities.iter()
|
||||
.enumerate()
|
||||
.find_map(|(i, a)| {
|
||||
keystore.key_pair::<AuthorityPair>(&a.0).ok().map(|kp| (kp, i))
|
||||
})?;
|
||||
let transcript = make_transcript(randomness, slot_number, epoch_index);
|
||||
|
||||
// Compute the threshold we will use.
|
||||
@@ -836,9 +837,9 @@ fn claim_slot(
|
||||
// be empty. Therefore, this division in `calculate_threshold` is safe.
|
||||
let threshold = calculate_threshold(c, authorities, authority_index);
|
||||
|
||||
get_keypair(key)
|
||||
get_keypair(&key_pair)
|
||||
.vrf_sign_after_check(transcript, |inout| check(inout, threshold))
|
||||
.map(|s|(s, authority_index))
|
||||
.map(|s|(s, authority_index, key_pair))
|
||||
}
|
||||
|
||||
fn initialize_authorities_cache<B, C>(client: &C) -> Result<(), ConsensusError> where
|
||||
@@ -1201,8 +1202,8 @@ pub mod test_helpers {
|
||||
client: &C,
|
||||
at: &BlockId<B>,
|
||||
slot_number: u64,
|
||||
key: &sr25519::Pair,
|
||||
c: (u64, u64),
|
||||
keystore: &KeyStorePtr,
|
||||
) -> Option<BabePreDigest> where
|
||||
B: BlockT,
|
||||
C: ProvideRuntimeApi + ProvideCache<B>,
|
||||
@@ -1213,9 +1214,9 @@ pub mod test_helpers {
|
||||
super::claim_slot(
|
||||
slot_number,
|
||||
epoch,
|
||||
key,
|
||||
c,
|
||||
).map(|((inout, vrf_proof, _), authority_index)| {
|
||||
keystore,
|
||||
).map(|((inout, vrf_proof, _), authority_index, _)| {
|
||||
BabePreDigest {
|
||||
vrf_proof,
|
||||
vrf_output: inout.to_output(),
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
// https://github.com/paritytech/substrate/issues/2532
|
||||
#![allow(deprecated)]
|
||||
use super::*;
|
||||
use super::generic::DigestItem;
|
||||
|
||||
use babe_primitives::AuthorityPair;
|
||||
use client::{LongestChain, block_builder::BlockBuilder};
|
||||
use consensus_common::NoNetwork as DummyOracle;
|
||||
use network::test::*;
|
||||
@@ -29,7 +31,6 @@ use sr_primitives::traits::{Block as BlockT, DigestFor};
|
||||
use network::config::ProtocolConfig;
|
||||
use tokio::runtime::current_thread;
|
||||
use keyring::sr25519::Keyring;
|
||||
use super::generic::DigestItem;
|
||||
use client::BlockchainEvents;
|
||||
use test_client;
|
||||
use log::debug;
|
||||
@@ -183,15 +184,21 @@ fn run_one_test() {
|
||||
let net = BabeTestNet::new(3);
|
||||
|
||||
let peers = &[
|
||||
(0, Keyring::Alice),
|
||||
(1, Keyring::Bob),
|
||||
(2, Keyring::Charlie),
|
||||
(0, "//Alice"),
|
||||
(1, "//Bob"),
|
||||
(2, "//Charlie"),
|
||||
];
|
||||
|
||||
let net = Arc::new(Mutex::new(net));
|
||||
let mut import_notifications = Vec::new();
|
||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||
for (peer_id, key) in peers {
|
||||
let mut keystore_paths = Vec::new();
|
||||
for (peer_id, seed) in peers {
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore");
|
||||
keystore.write().insert_ephemeral_from_seed::<AuthorityPair>(seed).expect("Generates authority key");
|
||||
keystore_paths.push(keystore_path);
|
||||
|
||||
let client = net.lock().peer(*peer_id).client().as_full().unwrap();
|
||||
let environ = DummyFactory(client.clone());
|
||||
import_notifications.push(
|
||||
@@ -200,21 +207,18 @@ fn run_one_test() {
|
||||
.for_each(move |_| future::ready(()))
|
||||
);
|
||||
|
||||
let config = Config::get_or_compute(&*client)
|
||||
.expect("slot duration available");
|
||||
let config = Config::get_or_compute(&*client).expect("slot duration available");
|
||||
|
||||
let inherent_data_providers = InherentDataProviders::new();
|
||||
register_babe_inherent_data_provider(
|
||||
&inherent_data_providers, config.get()
|
||||
).expect("Registers babe inherent data provider");
|
||||
|
||||
|
||||
#[allow(deprecated)]
|
||||
let select_chain = LongestChain::new(client.backend().clone());
|
||||
|
||||
runtime.spawn(start_babe(BabeParams {
|
||||
config,
|
||||
local_key: Arc::new(key.clone().into()),
|
||||
block_import: client.clone(),
|
||||
select_chain,
|
||||
client,
|
||||
@@ -223,6 +227,7 @@ fn run_one_test() {
|
||||
inherent_data_providers,
|
||||
force_authoring: false,
|
||||
time_source: Default::default(),
|
||||
keystore,
|
||||
}).expect("Starts babe"));
|
||||
}
|
||||
|
||||
@@ -230,7 +235,7 @@ fn run_one_test() {
|
||||
net.lock().poll();
|
||||
Ok::<_, ()>(futures01::Async::NotReady::<()>)
|
||||
}));
|
||||
|
||||
|
||||
runtime.block_on(future::join_all(import_notifications)
|
||||
.map(|_| Ok::<(), ()>(())).compat()).unwrap();
|
||||
}
|
||||
@@ -280,8 +285,8 @@ fn rejects_missing_consensus_digests() {
|
||||
#[test]
|
||||
fn wrong_consensus_engine_id_rejected() {
|
||||
let _ = env_logger::try_init();
|
||||
let sig = sr25519::Pair::generate().0.sign(b"");
|
||||
let bad_seal: Item = DigestItem::Seal([0; 4], sig.0.to_vec());
|
||||
let sig = AuthorityPair::generate().0.sign(b"");
|
||||
let bad_seal: Item = DigestItem::Seal([0; 4], sig.to_vec());
|
||||
assert!(bad_seal.as_babe_pre_digest().is_none());
|
||||
assert!(bad_seal.as_babe_seal().is_none())
|
||||
}
|
||||
@@ -296,8 +301,8 @@ fn malformed_pre_digest_rejected() {
|
||||
#[test]
|
||||
fn sig_is_not_pre_digest() {
|
||||
let _ = env_logger::try_init();
|
||||
let sig = sr25519::Pair::generate().0.sign(b"");
|
||||
let bad_seal: Item = DigestItem::Seal(BABE_ENGINE_ID, sig.0.to_vec());
|
||||
let sig = AuthorityPair::generate().0.sign(b"");
|
||||
let bad_seal: Item = DigestItem::Seal(BABE_ENGINE_ID, sig.to_vec());
|
||||
assert!(bad_seal.as_babe_pre_digest().is_none());
|
||||
assert!(bad_seal.as_babe_seal().is_some())
|
||||
}
|
||||
@@ -305,7 +310,11 @@ fn sig_is_not_pre_digest() {
|
||||
#[test]
|
||||
fn can_author_block() {
|
||||
let _ = env_logger::try_init();
|
||||
let (pair, _) = sr25519::Pair::generate();
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore");
|
||||
let pair = keystore.write().insert_ephemeral_from_seed::<AuthorityPair>("//Alice")
|
||||
.expect("Generates authority pair");
|
||||
|
||||
let mut i = 0;
|
||||
let epoch = Epoch {
|
||||
start_slot: 0,
|
||||
@@ -315,10 +324,10 @@ fn can_author_block() {
|
||||
duration: 100,
|
||||
};
|
||||
loop {
|
||||
match claim_slot(i, epoch.clone(), &pair, (3, 10)) {
|
||||
match claim_slot(i, epoch.clone(), (3, 10), &keystore) {
|
||||
None => i += 1,
|
||||
Some(s) => {
|
||||
debug!(target: "babe", "Authored block {:?}", s);
|
||||
debug!(target: "babe", "Authored block {:?}", s.0);
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -332,8 +341,8 @@ fn authorities_call_works() {
|
||||
|
||||
assert_eq!(client.info().chain.best_number, 0);
|
||||
assert_eq!(epoch(&client, &BlockId::Number(0)).unwrap().authorities, vec![
|
||||
(Keyring::Alice.into(), 1),
|
||||
(Keyring::Bob.into(), 1),
|
||||
(Keyring::Charlie.into(), 1),
|
||||
(Keyring::Alice.public().into(), 1),
|
||||
(Keyring::Bob.public().into(), 1),
|
||||
(Keyring::Charlie.public().into(), 1),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ rstd = { package = "sr-std", path = "../../sr-std" }
|
||||
runtime_version = { package = "sr-version", path = "../../sr-version" }
|
||||
sr-primitives = { path = "../../sr-primitives" }
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] }
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
|
||||
[dev-dependencies]
|
||||
test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" }
|
||||
|
||||
@@ -19,7 +19,7 @@ sr-primitives = { path = "../../sr-primitives" }
|
||||
runtime_version = { package = "sr-version", path = "../../sr-version" }
|
||||
runtime_io = { package = "sr-io", path = "../../sr-io" }
|
||||
tokio = "0.1.7"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
log = "0.4"
|
||||
rhododendron = { version = "0.7.0", features = ["codec"] }
|
||||
exit-future = "0.1"
|
||||
|
||||
@@ -26,7 +26,7 @@ use runtime_io;
|
||||
fn check_message_sig<B: Codec, H: Codec>(
|
||||
message: Message<B, H>,
|
||||
signature: &Signature,
|
||||
from: &AuthorityId
|
||||
from: &AuthorityId,
|
||||
) -> bool {
|
||||
let msg: Vec<u8> = message.encode();
|
||||
runtime_io::ed25519_verify(&signature.0, &msg, from)
|
||||
|
||||
@@ -14,7 +14,7 @@ consensus_common = { package = "substrate-consensus-common", path = "../common"
|
||||
inherents = { package = "substrate-inherents", path = "../../inherents" }
|
||||
futures-preview = "0.3.0-alpha.17"
|
||||
futures-timer = "0.2.1"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
log = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -18,7 +18,7 @@ wasmi = "0.5.0"
|
||||
parity-wasm = "0.31"
|
||||
byteorder = "1.3"
|
||||
lazy_static = "1.3"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
log = "0.4"
|
||||
libsecp256k1 = "0.2.1"
|
||||
tiny-keccak = "1.4.2"
|
||||
|
||||
@@ -11,6 +11,7 @@ use runtime_io::{
|
||||
set_storage, storage, clear_prefix, print, blake2_128, blake2_256,
|
||||
twox_128, twox_256, ed25519_verify, sr25519_verify, enumerated_trie_root
|
||||
};
|
||||
use primitives::{ed25519, sr25519};
|
||||
|
||||
macro_rules! impl_stubs {
|
||||
( $( $new_name:ident => $invoke:expr, )* ) => {
|
||||
@@ -80,7 +81,7 @@ impl_stubs!(
|
||||
sig.copy_from_slice(&input[32..96]);
|
||||
|
||||
let msg = b"all ok!";
|
||||
[ed25519_verify(&sig, &msg[..], &pubkey) as u8].to_vec()
|
||||
[ed25519_verify(&ed25519::Signature(sig), &msg[..], &ed25519::Public(pubkey)) as u8].to_vec()
|
||||
},
|
||||
test_sr25519_verify => |input: &[u8]| {
|
||||
let mut pubkey = [0; 32];
|
||||
@@ -90,7 +91,7 @@ impl_stubs!(
|
||||
sig.copy_from_slice(&input[32..96]);
|
||||
|
||||
let msg = b"all ok!";
|
||||
[sr25519_verify(&sig, &msg[..], &pubkey) as u8].to_vec()
|
||||
[sr25519_verify(&sr25519::Signature(sig), &msg[..], &sr25519::Public(pubkey)) as u8].to_vec()
|
||||
},
|
||||
test_enumerated_trie_root => |_| {
|
||||
enumerated_trie_root::<primitives::Blake2Hasher>(
|
||||
|
||||
@@ -27,11 +27,10 @@ use wasmi::{
|
||||
use state_machine::{Externalities, ChildStorageKey};
|
||||
use crate::error::{Error, Result};
|
||||
use codec::Encode;
|
||||
use primitives::{blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Pair};
|
||||
use primitives::offchain;
|
||||
use primitives::hexdisplay::HexDisplay;
|
||||
use primitives::sandbox as sandbox_primitives;
|
||||
use primitives::{H256, Blake2Hasher};
|
||||
use primitives::{
|
||||
blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Pair, crypto::KeyTypeId,
|
||||
offchain, hexdisplay::HexDisplay, sandbox as sandbox_primitives, H256, Blake2Hasher,
|
||||
};
|
||||
use trie::{TrieConfiguration, trie_types::Layout};
|
||||
use crate::sandbox;
|
||||
use crate::allocator;
|
||||
@@ -641,7 +640,30 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
|
||||
this.memory.set(out, &result).map_err(|_| "Invalid attempt to set result in ext_keccak_256")?;
|
||||
Ok(())
|
||||
},
|
||||
ext_ed25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32 => {
|
||||
ext_ed25519_public_keys(id_data: *const u8, result_len: *mut u32) -> *mut u8 => {
|
||||
let mut id = [0u8; 4];
|
||||
this.memory.get_into(id_data, &mut id[..])
|
||||
.map_err(|_| "Invalid attempt to get id in ext_ed25519_public_keys")?;
|
||||
let key_type = KeyTypeId(id);
|
||||
|
||||
let keys = runtime_io::ed25519_public_keys(key_type).encode();
|
||||
|
||||
let len = keys.len() as u32;
|
||||
let offset = this.heap.allocate(len)? as u32;
|
||||
|
||||
this.memory.set(offset, keys.as_ref())
|
||||
.map_err(|_| "Invalid attempt to set memory in ext_ed25519_public_keys")?;
|
||||
this.memory.write_primitive(result_len, len)
|
||||
.map_err(|_| "Invalid attempt to write result_len in ext_ed25519_public_keys")?;
|
||||
|
||||
Ok(offset)
|
||||
},
|
||||
ext_ed25519_verify(
|
||||
msg_data: *const u8,
|
||||
msg_len: u32,
|
||||
sig_data: *const u8,
|
||||
pubkey_data: *const u8,
|
||||
) -> u32 => {
|
||||
let mut sig = [0u8; 64];
|
||||
this.memory.get_into(sig_data, &mut sig[..])
|
||||
.map_err(|_| "Invalid attempt to get signature in ext_ed25519_verify")?;
|
||||
@@ -657,7 +679,87 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
|
||||
5
|
||||
})
|
||||
},
|
||||
ext_sr25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32 => {
|
||||
ext_ed25519_generate(id_data: *const u8, seed: *const u8, seed_len: u32, out: *mut u8) => {
|
||||
let mut id = [0u8; 4];
|
||||
this.memory.get_into(id_data, &mut id[..])
|
||||
.map_err(|_| "Invalid attempt to get id in ext_ed25519_generate")?;
|
||||
let key_type = KeyTypeId(id);
|
||||
|
||||
let seed = if seed_len == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
this.memory.get(seed, seed_len as usize)
|
||||
.map_err(|_| "Invalid attempt to get seed in ext_ed25519_generate")?
|
||||
)
|
||||
};
|
||||
|
||||
let seed = seed.as_ref()
|
||||
.map(|seed|
|
||||
std::str::from_utf8(&seed)
|
||||
.map_err(|_| "Seed not a valid utf8 string in ext_sr25119_generate")
|
||||
).transpose()?;
|
||||
|
||||
let pubkey = runtime_io::ed25519_generate(key_type, seed);
|
||||
|
||||
this.memory.set(out, pubkey.as_ref())
|
||||
.map_err(|_| "Invalid attempt to set out in ext_ed25519_generate".into())
|
||||
},
|
||||
ext_ed25519_sign(
|
||||
id_data: *const u8,
|
||||
pubkey_data: *const u8,
|
||||
msg_data: *const u8,
|
||||
msg_len: u32,
|
||||
out: *mut u8,
|
||||
) -> u32 => {
|
||||
let mut id = [0u8; 4];
|
||||
this.memory.get_into(id_data, &mut id[..])
|
||||
.map_err(|_| "Invalid attempt to get id in ext_ed25519_sign")?;
|
||||
let key_type = KeyTypeId(id);
|
||||
|
||||
let mut pubkey = [0u8; 32];
|
||||
this.memory.get_into(pubkey_data, &mut pubkey[..])
|
||||
.map_err(|_| "Invalid attempt to get pubkey in ext_ed25519_sign")?;
|
||||
|
||||
let msg = this.memory.get(msg_data, msg_len as usize)
|
||||
.map_err(|_| "Invalid attempt to get message in ext_ed25519_sign")?;
|
||||
|
||||
let signature = runtime_io::ed25519_sign(key_type, &ed25519::Public(pubkey), &msg);
|
||||
|
||||
match signature {
|
||||
Some(signature) => {
|
||||
this.memory
|
||||
.set(out, signature.as_ref())
|
||||
.map_err(|_| "Invalid attempt to set out in ext_ed25519_sign")?;
|
||||
Ok(0)
|
||||
},
|
||||
None => Ok(1),
|
||||
}
|
||||
},
|
||||
ext_sr25519_public_keys(id_data: *const u8, result_len: *mut u32) -> *mut u8 => {
|
||||
let mut id = [0u8; 4];
|
||||
this.memory.get_into(id_data, &mut id[..])
|
||||
.map_err(|_| "Invalid attempt to get id in ext_sr25519_public_keys")?;
|
||||
let key_type = KeyTypeId(id);
|
||||
|
||||
let keys = runtime_io::sr25519_public_keys(key_type).encode();
|
||||
|
||||
let len = keys.len() as u32;
|
||||
let offset = this.heap.allocate(len)? as u32;
|
||||
|
||||
this.memory.set(offset, keys.as_ref())
|
||||
.map_err(|_| "Invalid attempt to set memory in ext_sr25519_public_keys")?;
|
||||
this.memory.write_primitive(result_len, len)
|
||||
.map_err(|_| "Invalid attempt to write result_len in ext_sr25519_public_keys")?;
|
||||
|
||||
Ok(offset)
|
||||
},
|
||||
ext_sr25519_verify(
|
||||
msg_data: *const u8,
|
||||
msg_len: u32,
|
||||
sig_data: *const u8,
|
||||
pubkey_data: *const u8,
|
||||
) -> u32 => {
|
||||
let mut sig = [0u8; 64];
|
||||
this.memory.get_into(sig_data, &mut sig[..])
|
||||
.map_err(|_| "Invalid attempt to get signature in ext_sr25519_verify")?;
|
||||
@@ -673,6 +775,62 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
|
||||
5
|
||||
})
|
||||
},
|
||||
ext_sr25519_generate(id_data: *const u8, seed: *const u8, seed_len: u32, out: *mut u8) => {
|
||||
let mut id = [0u8; 4];
|
||||
this.memory.get_into(id_data, &mut id[..])
|
||||
.map_err(|_| "Invalid attempt to get id in ext_sr25519_generate")?;
|
||||
let key_type = KeyTypeId(id);
|
||||
let seed = if seed_len == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
this.memory.get(seed, seed_len as usize)
|
||||
.map_err(|_| "Invalid attempt to get seed in ext_sr25519_generate")?
|
||||
)
|
||||
};
|
||||
|
||||
let seed = seed.as_ref()
|
||||
.map(|seed|
|
||||
std::str::from_utf8(&seed)
|
||||
.map_err(|_| "Seed not a valid utf8 string in ext_sr25119_generate")
|
||||
)
|
||||
.transpose()?;
|
||||
|
||||
let pubkey = runtime_io::sr25519_generate(key_type, seed);
|
||||
|
||||
this.memory.set(out, pubkey.as_ref())
|
||||
.map_err(|_| "Invalid attempt to set out in ext_sr25519_generate".into())
|
||||
},
|
||||
ext_sr25519_sign(
|
||||
id_data: *const u8,
|
||||
pubkey_data: *const u8,
|
||||
msg_data: *const u8,
|
||||
msg_len: u32,
|
||||
out: *mut u8,
|
||||
) -> u32 => {
|
||||
let mut id = [0u8; 4];
|
||||
this.memory.get_into(id_data, &mut id[..])
|
||||
.map_err(|_| "Invalid attempt to get id in ext_sr25519_sign")?;
|
||||
let key_type = KeyTypeId(id);
|
||||
|
||||
let mut pubkey = [0u8; 32];
|
||||
this.memory.get_into(pubkey_data, &mut pubkey[..])
|
||||
.map_err(|_| "Invalid attempt to get pubkey in ext_sr25519_sign")?;
|
||||
|
||||
let msg = this.memory.get(msg_data, msg_len as usize)
|
||||
.map_err(|_| "Invalid attempt to get message in ext_sr25519_sign")?;
|
||||
|
||||
let signature = runtime_io::sr25519_sign(key_type, &sr25519::Public(pubkey), &msg);
|
||||
|
||||
match signature {
|
||||
Some(signature) => {
|
||||
this.memory.set(out, signature.as_ref())
|
||||
.map_err(|_| "Invalid attempt to set out in ext_sr25519_sign")?;
|
||||
Ok(0)
|
||||
},
|
||||
None => Ok(1),
|
||||
}
|
||||
},
|
||||
ext_secp256k1_ecdsa_recover(msg_data: *const u8, sig_data: *const u8, pubkey_data: *mut u8) -> u32 => {
|
||||
let mut sig = [0u8; 65];
|
||||
this.memory.get_into(sig_data, &mut sig[..])
|
||||
@@ -711,50 +869,6 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
|
||||
|
||||
Ok(if res.is_ok() { 0 } else { 1 })
|
||||
},
|
||||
ext_new_crypto_key(crypto: u32) -> u64 => {
|
||||
let kind = offchain::CryptoKind::try_from(crypto)
|
||||
.map_err(|_| "crypto kind OOB while ext_new_crypto_key: wasm")?;
|
||||
|
||||
let res = this.ext.offchain()
|
||||
.map(|api| api.new_crypto_key(kind))
|
||||
.ok_or_else(|| "Calling unavailable API ext_new_crypto_key: wasm")?;
|
||||
|
||||
match res {
|
||||
Ok(key) => Ok(key.into()),
|
||||
Err(()) => Ok(u64::max_value()),
|
||||
}
|
||||
},
|
||||
ext_encrypt(
|
||||
key: u64,
|
||||
data: *const u8,
|
||||
data_len: u32,
|
||||
msg_len: *mut u32
|
||||
) -> *mut u8 => {
|
||||
let key = offchain::CryptoKey::try_from(key)
|
||||
.map_err(|_| "Key OOB while ext_encrypt: wasm")?;
|
||||
let message = this.memory.get(data, data_len as usize)
|
||||
.map_err(|_| "OOB while ext_encrypt: wasm")?;
|
||||
|
||||
let res = this.ext.offchain()
|
||||
.map(|api| api.encrypt(key, &*message))
|
||||
.ok_or_else(|| "Calling unavailable API ext_encrypt: wasm")?;
|
||||
|
||||
let (offset,len) = match res {
|
||||
Ok(encrypted) => {
|
||||
let len = encrypted.len() as u32;
|
||||
let offset = this.heap.allocate(len)? as u32;
|
||||
this.memory.set(offset, &encrypted)
|
||||
.map_err(|_| "Invalid attempt to set memory in ext_encrypt")?;
|
||||
(offset, len)
|
||||
},
|
||||
Err(()) => (0, u32::max_value()),
|
||||
};
|
||||
|
||||
this.memory.write_primitive(msg_len, len)
|
||||
.map_err(|_| "Invalid attempt to write msg_len in ext_encrypt")?;
|
||||
|
||||
Ok(offset)
|
||||
},
|
||||
ext_network_state(written_out: *mut u32) -> *mut u8 => {
|
||||
let res = this.ext.offchain()
|
||||
.map(|api| api.network_state())
|
||||
@@ -771,111 +885,6 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
|
||||
|
||||
Ok(offset)
|
||||
},
|
||||
ext_pubkey(
|
||||
key: u64,
|
||||
written_out: *mut u32
|
||||
) -> *mut u8 => {
|
||||
let key = offchain::CryptoKey::try_from(key)
|
||||
.map_err(|_| "Key OOB while ext_decrypt: wasm")?;
|
||||
let res = this.ext.offchain()
|
||||
.map(|api| api.pubkey(key))
|
||||
.ok_or_else(|| "Calling unavailable API ext_authority_pubkey: wasm")?;
|
||||
|
||||
let encoded = res.encode();
|
||||
let len = encoded.len() as u32;
|
||||
let offset = this.heap.allocate(len)? as u32;
|
||||
this.memory.set(offset, &encoded)
|
||||
.map_err(|_| "Invalid attempt to set memory in ext_authority_pubkey")?;
|
||||
this.memory.write_primitive(written_out, len)
|
||||
.map_err(|_| "Invalid attempt to write written_out in ext_authority_pubkey")?;
|
||||
Ok(offset)
|
||||
},
|
||||
ext_decrypt(
|
||||
key: u64,
|
||||
data: *const u8,
|
||||
data_len: u32,
|
||||
msg_len: *mut u32
|
||||
) -> *mut u8 => {
|
||||
let key = offchain::CryptoKey::try_from(key)
|
||||
.map_err(|_| "Key OOB while ext_decrypt: wasm")?;
|
||||
let message = this.memory.get(data, data_len as usize)
|
||||
.map_err(|_| "OOB while ext_decrypt: wasm")?;
|
||||
|
||||
let res = this.ext.offchain()
|
||||
.map(|api| api.decrypt(key, &*message))
|
||||
.ok_or_else(|| "Calling unavailable API ext_decrypt: wasm")?;
|
||||
|
||||
let (offset,len) = match res {
|
||||
Ok(decrypted) => {
|
||||
let len = decrypted.len() as u32;
|
||||
let offset = this.heap.allocate(len)? as u32;
|
||||
this.memory.set(offset, &decrypted)
|
||||
.map_err(|_| "Invalid attempt to set memory in ext_decrypt")?;
|
||||
(offset, len)
|
||||
},
|
||||
Err(()) => (0, u32::max_value()),
|
||||
};
|
||||
|
||||
this.memory.write_primitive(msg_len, len)
|
||||
.map_err(|_| "Invalid attempt to write msg_len in ext_decrypt")?;
|
||||
|
||||
Ok(offset)
|
||||
},
|
||||
ext_sign(
|
||||
key: u64,
|
||||
data: *const u8,
|
||||
data_len: u32,
|
||||
sig_data_len: *mut u32
|
||||
) -> *mut u8 => {
|
||||
let key = offchain::CryptoKey::try_from(key)
|
||||
.map_err(|_| "Key OOB while ext_sign: wasm")?;
|
||||
let message = this.memory.get(data, data_len as usize)
|
||||
.map_err(|_| "OOB while ext_sign: wasm")?;
|
||||
|
||||
let res = this.ext.offchain()
|
||||
.map(|api| api.sign(key, &*message))
|
||||
.ok_or_else(|| "Calling unavailable API ext_sign: wasm")?;
|
||||
|
||||
let (offset,len) = match res {
|
||||
Ok(signature) => {
|
||||
let len = signature.len() as u32;
|
||||
let offset = this.heap.allocate(len)? as u32;
|
||||
this.memory.set(offset, &signature)
|
||||
.map_err(|_| "Invalid attempt to set memory in ext_sign")?;
|
||||
(offset, len)
|
||||
},
|
||||
Err(()) => (0, u32::max_value()),
|
||||
};
|
||||
|
||||
this.memory.write_primitive(sig_data_len, len)
|
||||
.map_err(|_| "Invalid attempt to write sig_data_len in ext_sign")?;
|
||||
|
||||
Ok(offset)
|
||||
},
|
||||
ext_verify(
|
||||
key: u64,
|
||||
msg: *const u8,
|
||||
msg_len: u32,
|
||||
signature: *const u8,
|
||||
signature_len: u32
|
||||
) -> u32 => {
|
||||
let key = offchain::CryptoKey::try_from(key)
|
||||
.map_err(|_| "Key OOB while ext_verify: wasm")?;
|
||||
let message = this.memory.get(msg, msg_len as usize)
|
||||
.map_err(|_| "OOB while ext_verify: wasm")?;
|
||||
let signature = this.memory.get(signature, signature_len as usize)
|
||||
.map_err(|_| "OOB while ext_verify: wasm")?;
|
||||
|
||||
let res = this.ext.offchain()
|
||||
.map(|api| api.verify(key, &*message, &*signature))
|
||||
.ok_or_else(|| "Calling unavailable API ext_verify: wasm")?;
|
||||
|
||||
match res {
|
||||
Ok(true) => Ok(0),
|
||||
Ok(false) => Ok(1),
|
||||
Err(()) => Ok(u32::max_value()),
|
||||
}
|
||||
},
|
||||
ext_timestamp() -> u64 => {
|
||||
let timestamp = this.ext.offchain()
|
||||
.map(|api| api.timestamp())
|
||||
|
||||
@@ -217,9 +217,15 @@ macro_rules! dispatch_fn {
|
||||
/// Implements `wasmi::Externals` trait and `Resolver` for given struct.
|
||||
#[macro_export]
|
||||
macro_rules! impl_function_executor {
|
||||
( $objectname:ident : $structname:ty,
|
||||
$( $name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt , )*
|
||||
=> $($pre:tt)+ ) => (
|
||||
(
|
||||
$objectname:ident : $structname:ty,
|
||||
$(
|
||||
$name:ident
|
||||
( $( $names:ident : $params:ty ),* $(,)? )
|
||||
$( -> $returns:ty )? => { $( $body:tt )* },
|
||||
)*
|
||||
=> $( $pre:tt )+
|
||||
) => (
|
||||
impl $( $pre ) + $structname {
|
||||
#[allow(unused)]
|
||||
fn resolver() -> &'static dyn $crate::wasmi::ModuleImportResolver {
|
||||
@@ -230,7 +236,11 @@ macro_rules! impl_function_executor {
|
||||
name: &str,
|
||||
signature: &$crate::wasmi::Signature
|
||||
) -> std::result::Result<$crate::wasmi::FuncRef, $crate::wasmi::Error> {
|
||||
resolve_fn!(signature, name, $( $name( $( $params ),* ) $( -> $returns )* => )*);
|
||||
resolve_fn!(
|
||||
signature,
|
||||
name,
|
||||
$( $name( $( $params ),* ) $( -> $returns )? => )*
|
||||
);
|
||||
|
||||
Err($crate::wasmi::Error::Instantiation(
|
||||
format!("Export {} not found", name),
|
||||
@@ -249,7 +259,12 @@ macro_rules! impl_function_executor {
|
||||
) -> std::result::Result<Option<$crate::wasmi::RuntimeValue>, $crate::wasmi::Trap> {
|
||||
let $objectname = self;
|
||||
let mut args = args.as_ref().iter();
|
||||
dispatch_fn!(index, $objectname, args, $( $name( $( $names : $params ),* ) $( -> $returns )* => $body ),*);
|
||||
dispatch_fn! {
|
||||
index,
|
||||
$objectname,
|
||||
args,
|
||||
$( $name( $( $names : $params ),* ) $( -> $returns )? => { $( $body )* } ),*
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ fork-tree = { path = "../../core/utils/fork-tree" }
|
||||
futures = "0.1"
|
||||
futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] }
|
||||
log = "0.4"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
tokio-executor = "0.1.7"
|
||||
tokio-timer = "0.2.11"
|
||||
rand = "0.6"
|
||||
@@ -18,6 +18,7 @@ sr-primitives = { path = "../sr-primitives" }
|
||||
consensus_common = { package = "substrate-consensus-common", path = "../consensus/common" }
|
||||
primitives = { package = "substrate-primitives", path = "../primitives" }
|
||||
substrate-telemetry = { path = "../telemetry" }
|
||||
keystore = { package = "substrate-keystore", path = "../keystore" }
|
||||
serde_json = "1.0"
|
||||
client = { package = "substrate-client", path = "../client" }
|
||||
inherents = { package = "substrate-inherents", path = "../../core/inherents" }
|
||||
@@ -32,8 +33,10 @@ grandpa = { package = "finality-grandpa", version = "0.9.0", features = ["derive
|
||||
network = { package = "substrate-network", path = "../network", features = ["test-helpers"] }
|
||||
keyring = { package = "substrate-keyring", path = "../keyring" }
|
||||
test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client"}
|
||||
babe_primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" }
|
||||
env_logger = "0.6"
|
||||
tokio = "0.1.17"
|
||||
tempfile = "3.1"
|
||||
|
||||
[features]
|
||||
default = ["service-integration"]
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
client = { package = "substrate-client", path = "../../client", default-features = false }
|
||||
primitives = { package = "substrate-primitives", path = "../../primitives", default-features = false }
|
||||
app-crypto = { package = "substrate-application-crypto", path = "../../application-crypto", default-features = false }
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
sr-primitives = { path = "../../sr-primitives", default-features = false }
|
||||
rstd = { package = "sr-std", path = "../../sr-std", default-features = false }
|
||||
@@ -15,10 +15,10 @@ serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"primitives/std",
|
||||
"client/std",
|
||||
"codec/std",
|
||||
"sr-primitives/std",
|
||||
"rstd/std",
|
||||
"serde",
|
||||
"app-crypto/std",
|
||||
]
|
||||
|
||||
@@ -28,15 +28,20 @@ use sr_primitives::{ConsensusEngineId, traits::{DigestFor, NumberFor}};
|
||||
use client::decl_runtime_apis;
|
||||
use rstd::vec::Vec;
|
||||
|
||||
mod app {
|
||||
use app_crypto::{app_crypto, key_types::GRANDPA, ed25519};
|
||||
app_crypto!(ed25519, GRANDPA);
|
||||
}
|
||||
|
||||
/// The grandpa crypto scheme defined via the keypair type.
|
||||
#[cfg(feature = "std")]
|
||||
pub type AuthorityPair = primitives::ed25519::Pair;
|
||||
pub type AuthorityPair = app::Pair;
|
||||
|
||||
/// Identity of a Grandpa authority.
|
||||
pub type AuthorityId = primitives::ed25519::Public;
|
||||
pub type AuthorityId = app::Public;
|
||||
|
||||
/// Signature for a Grandpa authority.
|
||||
pub type AuthoritySignature = primitives::ed25519::Signature;
|
||||
pub type AuthoritySignature = app::Signature;
|
||||
|
||||
/// The `ConsensusEngineId` of GRANDPA.
|
||||
pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK";
|
||||
|
||||
@@ -431,6 +431,7 @@ impl<H, N: Add<Output=N> + Clone> PendingChange<H, N> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use primitives::crypto::Public;
|
||||
|
||||
fn static_is_descendent_of<A>(value: bool)
|
||||
-> impl Fn(&A, &A) -> Result<bool, std::io::Error>
|
||||
@@ -520,8 +521,8 @@ mod tests {
|
||||
pending_forced_changes: Vec::new(),
|
||||
};
|
||||
|
||||
let set_a = vec![(AuthorityId::from_raw([1; 32]), 5)];
|
||||
let set_b = vec![(AuthorityId::from_raw([2; 32]), 5)];
|
||||
let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)];
|
||||
let set_b = vec![(AuthorityId::from_slice(&[2; 32]), 5)];
|
||||
|
||||
// two competing changes at the same height on different forks
|
||||
let change_a = PendingChange {
|
||||
@@ -585,8 +586,8 @@ mod tests {
|
||||
pending_forced_changes: Vec::new(),
|
||||
};
|
||||
|
||||
let set_a = vec![(AuthorityId::from_raw([1; 32]), 5)];
|
||||
let set_c = vec![(AuthorityId::from_raw([2; 32]), 5)];
|
||||
let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)];
|
||||
let set_c = vec![(AuthorityId::from_slice(&[2; 32]), 5)];
|
||||
|
||||
// two competing changes at the same height on different forks
|
||||
let change_a = PendingChange {
|
||||
@@ -651,7 +652,7 @@ mod tests {
|
||||
pending_forced_changes: Vec::new(),
|
||||
};
|
||||
|
||||
let set_a = vec![(AuthorityId::from_raw([1; 32]), 5)];
|
||||
let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)];
|
||||
|
||||
let change_a = PendingChange {
|
||||
next_authorities: set_a.clone(),
|
||||
@@ -717,8 +718,8 @@ mod tests {
|
||||
pending_forced_changes: Vec::new(),
|
||||
};
|
||||
|
||||
let set_a = vec![(AuthorityId::from_raw([1; 32]), 5)];
|
||||
let set_b = vec![(AuthorityId::from_raw([2; 32]), 5)];
|
||||
let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)];
|
||||
let set_b = vec![(AuthorityId::from_slice(&[2; 32]), 5)];
|
||||
|
||||
let change_a = PendingChange {
|
||||
next_authorities: set_a.clone(),
|
||||
|
||||
@@ -86,7 +86,7 @@ use sr_primitives::traits::{NumberFor, Block as BlockT, Zero};
|
||||
use network::consensus_gossip::{self as network_gossip, MessageIntent, ValidatorContext};
|
||||
use network::{config::Roles, PeerId};
|
||||
use codec::{Encode, Decode};
|
||||
use crate::ed25519::Public as AuthorityId;
|
||||
use fg_primitives::AuthorityId;
|
||||
|
||||
use substrate_telemetry::{telemetry, CONSENSUS_DEBUG};
|
||||
use log::{trace, debug, warn};
|
||||
@@ -1233,13 +1233,14 @@ mod tests {
|
||||
use super::environment::SharedVoterSetState;
|
||||
use network_gossip::Validator as GossipValidatorT;
|
||||
use network::test::Block;
|
||||
use primitives::crypto::Public;
|
||||
|
||||
// some random config (not really needed)
|
||||
fn config() -> crate::Config {
|
||||
crate::Config {
|
||||
gossip_duration: Duration::from_millis(10),
|
||||
justification_period: 256,
|
||||
local_key: None,
|
||||
keystore: None,
|
||||
name: None,
|
||||
}
|
||||
}
|
||||
@@ -1452,7 +1453,7 @@ mod tests {
|
||||
voter_set_state(),
|
||||
);
|
||||
let set_id = 1;
|
||||
let auth = AuthorityId::from_raw([1u8; 32]);
|
||||
let auth = AuthorityId::from_slice(&[1u8; 32]);
|
||||
let peer = PeerId::random();
|
||||
|
||||
val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {});
|
||||
@@ -1468,7 +1469,7 @@ mod tests {
|
||||
target_number: 10,
|
||||
}),
|
||||
signature: Default::default(),
|
||||
id: AuthorityId::from_raw([2u8; 32]),
|
||||
id: AuthorityId::from_slice(&[2u8; 32]),
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1497,7 +1498,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let set_id = 1;
|
||||
let auth = AuthorityId::from_raw([1u8; 32]);
|
||||
let auth = AuthorityId::from_slice(&[1u8; 32]);
|
||||
let peer = PeerId::random();
|
||||
|
||||
val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {});
|
||||
@@ -1562,7 +1563,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let set_id = 1;
|
||||
let auth = AuthorityId::from_raw([1u8; 32]);
|
||||
let auth = AuthorityId::from_slice(&[1u8; 32]);
|
||||
let peer = PeerId::random();
|
||||
|
||||
val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {});
|
||||
|
||||
@@ -29,18 +29,18 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use grandpa::{voter, voter_set::VoterSet};
|
||||
use grandpa::Message::{Prevote, Precommit, PrimaryPropose};
|
||||
use futures::prelude::*;
|
||||
use futures::sync::{oneshot, mpsc};
|
||||
use grandpa::Message::{Prevote, Precommit, PrimaryPropose};
|
||||
use grandpa::{voter, voter_set::VoterSet};
|
||||
use log::{debug, trace};
|
||||
use tokio_executor::Executor;
|
||||
use codec::{Encode, Decode};
|
||||
use primitives::{ed25519, Pair};
|
||||
use substrate_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_INFO};
|
||||
use sr_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT};
|
||||
use network::{consensus_gossip as network_gossip, NetworkService};
|
||||
use network_gossip::ConsensusMessage;
|
||||
use codec::{Encode, Decode};
|
||||
use primitives::Pair;
|
||||
use sr_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT};
|
||||
use substrate_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_INFO};
|
||||
use tokio_executor::Executor;
|
||||
|
||||
use crate::{
|
||||
CatchUp, Commit, CommunicationIn, CommunicationOut, CompactCommit, Error,
|
||||
@@ -50,7 +50,7 @@ use crate::environment::HasVoted;
|
||||
use gossip::{
|
||||
GossipMessage, FullCatchUpMessage, FullCommitMessage, VoteOrPrecommitMessage, GossipValidator
|
||||
};
|
||||
use primitives::ed25519::{Public as AuthorityId, Signature as AuthoritySignature};
|
||||
use fg_primitives::{AuthorityPair, AuthorityId, AuthoritySignature};
|
||||
|
||||
pub mod gossip;
|
||||
mod periodic;
|
||||
@@ -341,7 +341,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
|
||||
round: Round,
|
||||
set_id: SetId,
|
||||
voters: Arc<VoterSet<AuthorityId>>,
|
||||
local_key: Option<Arc<ed25519::Pair>>,
|
||||
local_key: Option<AuthorityPair>,
|
||||
has_voted: HasVoted<B>,
|
||||
) -> (
|
||||
impl Stream<Item=SignedMessage<B>,Error=Error>,
|
||||
@@ -354,8 +354,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
|
||||
);
|
||||
|
||||
let locals = local_key.and_then(|pair| {
|
||||
let public = pair.public();
|
||||
let id = AuthorityId(public.0);
|
||||
let id = pair.public();
|
||||
if voters.contains_key(&id) {
|
||||
Some((pair, id))
|
||||
} else {
|
||||
@@ -633,9 +632,9 @@ pub(crate) fn check_message_sig<Block: BlockT>(
|
||||
round: u64,
|
||||
set_id: u64,
|
||||
) -> Result<(), ()> {
|
||||
let as_public = AuthorityId::from_raw(id.0);
|
||||
let as_public = id.clone();
|
||||
let encoded_raw = localized_payload(round, set_id, message);
|
||||
if ed25519::Pair::verify(signature, &encoded_raw, as_public) {
|
||||
if AuthorityPair::verify(signature, &encoded_raw, &as_public) {
|
||||
Ok(())
|
||||
} else {
|
||||
debug!(target: "afg", "Bad signature on message from {:?}", id);
|
||||
@@ -653,7 +652,7 @@ pub(crate) fn check_message_sig<Block: BlockT>(
|
||||
struct OutgoingMessages<Block: BlockT, N: Network<Block>> {
|
||||
round: u64,
|
||||
set_id: u64,
|
||||
locals: Option<(Arc<ed25519::Pair>, AuthorityId)>,
|
||||
locals: Option<(AuthorityPair, AuthorityId)>,
|
||||
sender: mpsc::UnboundedSender<SignedMessage<Block>>,
|
||||
network: N,
|
||||
has_voted: HasVoted<Block>,
|
||||
|
||||
@@ -133,7 +133,7 @@ fn config() -> crate::Config {
|
||||
crate::Config {
|
||||
gossip_duration: std::time::Duration::from_millis(10),
|
||||
justification_period: 256,
|
||||
local_key: None,
|
||||
keystore: None,
|
||||
name: None,
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,7 @@ fn make_test_network() -> (
|
||||
|
||||
fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> {
|
||||
keys.iter()
|
||||
.map(|key| AuthorityId(key.to_raw_public()))
|
||||
.map(|key| key.clone().public().into())
|
||||
.map(|id| (id, 1))
|
||||
.collect()
|
||||
}
|
||||
@@ -242,7 +242,7 @@ fn good_commit_leads_to_relay() {
|
||||
for (i, key) in private.iter().enumerate() {
|
||||
precommits.push(precommit.clone());
|
||||
|
||||
let signature = key.sign(&payload[..]);
|
||||
let signature = fg_primitives::AuthoritySignature::from(key.sign(&payload[..]));
|
||||
auth_data.push((signature, public[i].0.clone()))
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ fn bad_commit_leads_to_report() {
|
||||
for (i, key) in private.iter().enumerate() {
|
||||
precommits.push(precommit.clone());
|
||||
|
||||
let signature = key.sign(&payload[..]);
|
||||
let signature = fg_primitives::AuthoritySignature::from(key.sign(&payload[..]));
|
||||
auth_data.push((signature, public[i].0.clone()))
|
||||
}
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ use grandpa::{
|
||||
BlockNumberOps, Equivocation, Error as GrandpaError, round::State as RoundState,
|
||||
voter, voter_set::VoterSet,
|
||||
};
|
||||
use primitives::{Blake2Hasher, H256, Pair};
|
||||
use sr_primitives::generic::BlockId;
|
||||
use sr_primitives::traits::{
|
||||
Block as BlockT, Header as HeaderT, NumberFor, One, Zero,
|
||||
};
|
||||
use primitives::{Blake2Hasher, ed25519, H256, Pair};
|
||||
use substrate_telemetry::{telemetry, CONSENSUS_INFO};
|
||||
|
||||
use crate::{
|
||||
@@ -478,7 +478,7 @@ where
|
||||
{
|
||||
type Timer = Box<dyn Future<Item = (), Error = Self::Error> + Send>;
|
||||
type Id = AuthorityId;
|
||||
type Signature = ed25519::Signature;
|
||||
type Signature = AuthoritySignature;
|
||||
|
||||
// regular round message streams
|
||||
type In = Box<dyn Stream<
|
||||
@@ -500,15 +500,25 @@ where
|
||||
let prevote_timer = Delay::new(now + self.config.gossip_duration * 2);
|
||||
let precommit_timer = Delay::new(now + self.config.gossip_duration * 4);
|
||||
|
||||
let local_key = self.config.local_key.as_ref()
|
||||
.filter(|pair| self.voters.contains_key(&pair.public().into()));
|
||||
let local_key = crate::is_voter(&self.voters, &self.config.keystore);
|
||||
|
||||
let has_voted = match self.voter_set_state.has_voted() {
|
||||
HasVoted::Yes(id, vote) => {
|
||||
if local_key.as_ref().map(|k| k.public() == id).unwrap_or(false) {
|
||||
HasVoted::Yes(id, vote)
|
||||
} else {
|
||||
HasVoted::No
|
||||
}
|
||||
},
|
||||
HasVoted::No => HasVoted::No,
|
||||
};
|
||||
|
||||
let (incoming, outgoing) = self.network.round_communication(
|
||||
crate::communication::Round(round),
|
||||
crate::communication::SetId(self.set_id),
|
||||
self.voters.clone(),
|
||||
local_key.cloned(),
|
||||
self.voter_set_state.has_voted(),
|
||||
local_key.clone(),
|
||||
has_voted,
|
||||
);
|
||||
|
||||
// schedule incoming messages from the network to be held until
|
||||
@@ -523,7 +533,7 @@ where
|
||||
let outgoing = Box::new(outgoing.sink_map_err(Into::into));
|
||||
|
||||
voter::RoundData {
|
||||
voter_id: self.config.local_key.as_ref().map(|pair| pair.public().clone()),
|
||||
voter_id: local_key.map(|pair| pair.public()),
|
||||
prevote_timer: Box::new(prevote_timer.map_err(|e| Error::Timer(e).into())),
|
||||
precommit_timer: Box::new(precommit_timer.map_err(|e| Error::Timer(e).into())),
|
||||
incoming,
|
||||
@@ -532,12 +542,10 @@ where
|
||||
}
|
||||
|
||||
fn proposed(&self, _round: u64, propose: PrimaryPropose<Block>) -> Result<(), Self::Error> {
|
||||
let local_id = self.config.local_key.as_ref()
|
||||
.map(|pair| pair.public().into())
|
||||
.filter(|id| self.voters.contains_key(&id));
|
||||
let local_id = crate::is_voter(&self.voters, &self.config.keystore);
|
||||
|
||||
let local_id = match local_id {
|
||||
Some(id) => id,
|
||||
Some(id) => id.public(),
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
@@ -571,12 +579,10 @@ where
|
||||
}
|
||||
|
||||
fn prevoted(&self, _round: u64, prevote: Prevote<Block>) -> Result<(), Self::Error> {
|
||||
let local_id = self.config.local_key.as_ref()
|
||||
.map(|pair| pair.public().into())
|
||||
.filter(|id| self.voters.contains_key(&id));
|
||||
let local_id = crate::is_voter(&self.voters, &self.config.keystore);
|
||||
|
||||
let local_id = match local_id {
|
||||
Some(id) => id,
|
||||
Some(id) => id.public(),
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
@@ -613,12 +619,10 @@ where
|
||||
}
|
||||
|
||||
fn precommitted(&self, _round: u64, precommit: Precommit<Block>) -> Result<(), Self::Error> {
|
||||
let local_id = self.config.local_key.as_ref()
|
||||
.map(|pair| pair.public().into())
|
||||
.filter(|id| self.voters.contains_key(&id));
|
||||
let local_id = crate::is_voter(&self.voters, &self.config.keystore);
|
||||
|
||||
let local_id = match local_id {
|
||||
Some(id) => id,
|
||||
Some(id) => id.public(),
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
|
||||
@@ -582,6 +582,7 @@ pub(crate) mod tests {
|
||||
use test_client::client::{backend::NewBlockState};
|
||||
use test_client::client::in_mem::Blockchain as InMemoryBlockchain;
|
||||
use super::*;
|
||||
use primitives::crypto::Public;
|
||||
|
||||
type FinalityProof = super::FinalityProof<Header>;
|
||||
|
||||
@@ -740,7 +741,7 @@ pub(crate) mod tests {
|
||||
let proof_of_4 = prove_finality::<_, _, TestJustification>(
|
||||
&blockchain,
|
||||
&(
|
||||
|_| Ok(vec![(AuthorityId::from_raw([1u8; 32]), 1u64)]),
|
||||
|_| Ok(vec![(AuthorityId::from_slice(&[1u8; 32]), 1u64)]),
|
||||
|_| unreachable!("authorities didn't change => ProveAuthorities won't be called"),
|
||||
),
|
||||
0,
|
||||
@@ -763,7 +764,7 @@ pub(crate) mod tests {
|
||||
let proof_of_5: FinalityProof = Decode::decode(&mut &prove_finality::<_, _, TestJustification>(
|
||||
&blockchain,
|
||||
&(
|
||||
|_| Ok(vec![(AuthorityId::from_raw([1u8; 32]), 1u64)]),
|
||||
|_| Ok(vec![(AuthorityId::from_slice(&[1u8; 32]), 1u64)]),
|
||||
|_| unreachable!("should return before calling ProveAuthorities"),
|
||||
),
|
||||
0,
|
||||
@@ -789,7 +790,7 @@ pub(crate) mod tests {
|
||||
let proof_of_5: FinalityProof = Decode::decode(&mut &prove_finality::<_, _, TestJustification>(
|
||||
&blockchain,
|
||||
&(
|
||||
|_| Ok(vec![(AuthorityId::from_raw([1u8; 32]), 1u64)]),
|
||||
|_| Ok(vec![(AuthorityId::from_slice(&[1u8; 32]), 1u64)]),
|
||||
|_| unreachable!("should return before calling ProveAuthorities"),
|
||||
),
|
||||
0,
|
||||
@@ -821,10 +822,12 @@ pub(crate) mod tests {
|
||||
&blockchain,
|
||||
&(
|
||||
|block_id| match block_id {
|
||||
BlockId::Hash(h) if h == header(3).hash() => Ok(vec![(AuthorityId::from_raw([3u8; 32]), 1u64)]),
|
||||
BlockId::Number(3) => Ok(vec![(AuthorityId::from_raw([3u8; 32]), 1u64)]),
|
||||
BlockId::Number(4) => Ok(vec![(AuthorityId::from_raw([4u8; 32]), 1u64)]),
|
||||
BlockId::Number(6) => Ok(vec![(AuthorityId::from_raw([6u8; 32]), 1u64)]),
|
||||
BlockId::Hash(h) if h == header(3).hash() => Ok(
|
||||
vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)]
|
||||
),
|
||||
BlockId::Number(3) => Ok(vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)]),
|
||||
BlockId::Number(4) => Ok(vec![(AuthorityId::from_slice(&[4u8; 32]), 1u64)]),
|
||||
BlockId::Number(6) => Ok(vec![(AuthorityId::from_slice(&[6u8; 32]), 1u64)]),
|
||||
_ => unreachable!("no other authorities should be fetched: {:?}", block_id),
|
||||
},
|
||||
|block_id| match block_id {
|
||||
@@ -865,7 +868,7 @@ pub(crate) mod tests {
|
||||
do_check_finality_proof::<_, _, TestJustification>(
|
||||
&blockchain,
|
||||
1,
|
||||
vec![(AuthorityId::from_raw([3u8; 32]), 1u64)],
|
||||
vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)],
|
||||
&ClosureAuthoritySetForFinalityChecker(|_, _, _| unreachable!("returns before CheckAuthoritiesProof")),
|
||||
vec![42],
|
||||
).unwrap_err();
|
||||
@@ -879,7 +882,7 @@ pub(crate) mod tests {
|
||||
do_check_finality_proof::<_, _, TestJustification>(
|
||||
&blockchain,
|
||||
1,
|
||||
vec![(AuthorityId::from_raw([3u8; 32]), 1u64)],
|
||||
vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)],
|
||||
&ClosureAuthoritySetForFinalityChecker(|_, _, _| unreachable!("returns before CheckAuthoritiesProof")),
|
||||
Vec::<TestJustification>::new().encode(),
|
||||
).unwrap_err();
|
||||
@@ -893,7 +896,7 @@ pub(crate) mod tests {
|
||||
do_check_finality_proof::<_, _, TestJustification>(
|
||||
&blockchain,
|
||||
1,
|
||||
vec![(AuthorityId::from_raw([3u8; 32]), 1u64)],
|
||||
vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)],
|
||||
&ClosureAuthoritySetForFinalityChecker(|_, _, _| unreachable!("returns before CheckAuthoritiesProof")),
|
||||
vec![FinalityProofFragment {
|
||||
block: header(4).hash(),
|
||||
@@ -917,7 +920,7 @@ pub(crate) mod tests {
|
||||
do_check_finality_proof::<_, _, TestJustification>(
|
||||
&blockchain,
|
||||
1,
|
||||
vec![(AuthorityId::from_raw([3u8; 32]), 1u64)],
|
||||
vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)],
|
||||
&ClosureAuthoritySetForFinalityChecker(|_, _, _| unreachable!("returns before CheckAuthoritiesProof")),
|
||||
vec![FinalityProofFragment {
|
||||
block: header(4).hash(),
|
||||
@@ -940,8 +943,8 @@ pub(crate) mod tests {
|
||||
let effects = do_check_finality_proof::<_, _, TestJustification>(
|
||||
&blockchain,
|
||||
1,
|
||||
vec![(AuthorityId::from_raw([3u8; 32]), 1u64)],
|
||||
&ClosureAuthoritySetForFinalityChecker(|_, _, _| Ok(vec![(AuthorityId::from_raw([4u8; 32]), 1u64)])),
|
||||
vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)],
|
||||
&ClosureAuthoritySetForFinalityChecker(|_, _, _| Ok(vec![(AuthorityId::from_slice(&[4u8; 32]), 1u64)])),
|
||||
vec![FinalityProofFragment {
|
||||
block: header(2).hash(),
|
||||
justification: TestJustification(true, vec![7]).encode(),
|
||||
@@ -959,7 +962,7 @@ pub(crate) mod tests {
|
||||
block: header(4).hash(),
|
||||
justification: TestJustification(true, vec![8]).encode(),
|
||||
new_set_id: 2,
|
||||
new_authorities: vec![(AuthorityId::from_raw([4u8; 32]), 1u64)],
|
||||
new_authorities: vec![(AuthorityId::from_slice(&[4u8; 32]), 1u64)],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -976,7 +979,7 @@ pub(crate) mod tests {
|
||||
let proof_of_4 = prove_finality::<_, _, TestJustification>(
|
||||
&blockchain,
|
||||
&(
|
||||
|_| Ok(vec![(AuthorityId::from_raw([1u8; 32]), 1u64)]),
|
||||
|_| Ok(vec![(AuthorityId::from_slice(&[1u8; 32]), 1u64)]),
|
||||
|_| unreachable!("should return before calling ProveAuthorities"),
|
||||
),
|
||||
0,
|
||||
|
||||
@@ -55,17 +55,20 @@
|
||||
use futures::prelude::*;
|
||||
use log::{debug, info, warn};
|
||||
use futures::sync::mpsc;
|
||||
use client::{BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError};
|
||||
use client::{
|
||||
BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError,
|
||||
};
|
||||
use client::blockchain::HeaderBackend;
|
||||
use codec::Encode;
|
||||
use sr_primitives::traits::{
|
||||
NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi,
|
||||
};
|
||||
use fg_primitives::GrandpaApi;
|
||||
use inherents::InherentDataProviders;
|
||||
use sr_primitives::generic::BlockId;
|
||||
use sr_primitives::traits::{
|
||||
NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi
|
||||
};
|
||||
use fg_primitives::{GrandpaApi, AuthorityPair};
|
||||
use keystore::KeyStorePtr;
|
||||
use inherents::InherentDataProviders;
|
||||
use consensus_common::SelectChain;
|
||||
use primitives::{ed25519, H256, Pair, Blake2Hasher};
|
||||
use primitives::{H256, Blake2Hasher};
|
||||
use substrate_telemetry::{telemetry, CONSENSUS_INFO, CONSENSUS_DEBUG, CONSENSUS_WARN};
|
||||
use serde_json;
|
||||
|
||||
@@ -198,10 +201,10 @@ pub struct Config {
|
||||
/// at least every justification_period blocks. There are some other events which might cause
|
||||
/// justification generation.
|
||||
pub justification_period: u32,
|
||||
/// The local signing key.
|
||||
pub local_key: Option<Arc<ed25519::Pair>>,
|
||||
/// Some local identifier of the voter.
|
||||
pub name: Option<String>,
|
||||
/// The keystore that manages the keys of this node.
|
||||
pub keystore: Option<keystore::KeyStorePtr>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -396,11 +399,11 @@ where
|
||||
}
|
||||
|
||||
fn global_communication<Block: BlockT<Hash=H256>, B, E, N, RA>(
|
||||
local_key: Option<&Arc<ed25519::Pair>>,
|
||||
set_id: u64,
|
||||
voters: &Arc<VoterSet<AuthorityId>>,
|
||||
client: &Arc<Client<B, E, Block, RA>>,
|
||||
network: &NetworkBridge<Block, N>,
|
||||
keystore: &Option<KeyStorePtr>,
|
||||
) -> (
|
||||
impl Stream<
|
||||
Item = CommunicationInH<Block, H256>,
|
||||
@@ -417,10 +420,7 @@ fn global_communication<Block: BlockT<Hash=H256>, B, E, N, RA>(
|
||||
RA: Send + Sync,
|
||||
NumberFor<Block>: BlockNumberOps,
|
||||
{
|
||||
|
||||
let is_voter = local_key
|
||||
.map(|pair| voters.contains_key(&pair.public().into()))
|
||||
.unwrap_or(false);
|
||||
let is_voter = is_voter(voters, keystore).is_some();
|
||||
|
||||
// verification stream
|
||||
let (global_in, global_out) = network.global_communication(
|
||||
@@ -491,7 +491,7 @@ pub struct GrandpaParams<B, E, Block: BlockT<Hash=H256>, N, RA, SC, X> {
|
||||
/// block import worker that has already been instantiated with `block_import`.
|
||||
pub fn run_grandpa_voter<B, E, Block: BlockT<Hash=H256>, N, RA, SC, X>(
|
||||
grandpa_params: GrandpaParams<B, E, Block, N, RA, SC, X>,
|
||||
) -> ::client::error::Result<impl Future<Item=(),Error=()> + Send + 'static> where
|
||||
) -> client::error::Result<impl Future<Item=(),Error=()> + Send + 'static> where
|
||||
Block::Hash: Ord,
|
||||
B: Backend<Block, Blake2Hasher> + 'static,
|
||||
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + 'static,
|
||||
@@ -568,31 +568,6 @@ pub fn run_grandpa_voter<B, E, Block: BlockT<Hash=H256>, N, RA, SC, X>(
|
||||
voter_set_state: set_state.clone(),
|
||||
});
|
||||
|
||||
initial_environment.update_voter_set_state(|voter_set_state| {
|
||||
match voter_set_state {
|
||||
VoterSetState::Live { current_round: HasVoted::Yes(id, _), completed_rounds } => {
|
||||
let local_id = config.local_key.clone().map(|pair| pair.public());
|
||||
let has_voted = match local_id {
|
||||
Some(local_id) => if *id == local_id {
|
||||
// keep the previous votes
|
||||
return Ok(None);
|
||||
} else {
|
||||
HasVoted::No
|
||||
},
|
||||
_ => HasVoted::No,
|
||||
};
|
||||
|
||||
// NOTE: only updated on disk when the voter first
|
||||
// proposes/prevotes/precommits or completes a round.
|
||||
Ok(Some(VoterSetState::Live {
|
||||
current_round: has_voted,
|
||||
completed_rounds: completed_rounds.clone(),
|
||||
}))
|
||||
},
|
||||
_ => Ok(None),
|
||||
}
|
||||
}).expect("operation inside closure cannot fail; qed");
|
||||
|
||||
let initial_state = (initial_environment, voter_commands_rx.into_future());
|
||||
let voter_work = future::loop_fn(initial_state, move |params| {
|
||||
let (env, voter_commands_rx) = params;
|
||||
@@ -611,20 +586,18 @@ pub fn run_grandpa_voter<B, E, Block: BlockT<Hash=H256>, N, RA, SC, X>(
|
||||
);
|
||||
|
||||
let global_comms = global_communication(
|
||||
config.local_key.as_ref(),
|
||||
env.set_id,
|
||||
&env.voters,
|
||||
&client,
|
||||
&network,
|
||||
&config.keystore,
|
||||
);
|
||||
|
||||
let voters = (*env.voters).clone();
|
||||
|
||||
let last_completed_round = completed_rounds.last();
|
||||
|
||||
Some(voter::Voter::new(
|
||||
env.clone(),
|
||||
voters,
|
||||
(*env.voters).clone(),
|
||||
global_comms,
|
||||
last_completed_round.number,
|
||||
last_completed_round.state.clone(),
|
||||
@@ -777,3 +750,17 @@ pub fn run_grandpa<B, E, Block: BlockT<Hash=H256>, N, RA, SC, X>(
|
||||
{
|
||||
run_grandpa_voter(grandpa_params)
|
||||
}
|
||||
|
||||
/// Checks if this node is a voter in the given voter set.
|
||||
///
|
||||
/// Returns the key pair of the node that is being used in the current voter set or `None`.
|
||||
fn is_voter(
|
||||
voters: &Arc<VoterSet<AuthorityId>>,
|
||||
keystore: &Option<KeyStorePtr>,
|
||||
) -> Option<AuthorityPair> {
|
||||
match keystore {
|
||||
Some(keystore) => voters.voters().iter()
|
||||
.find_map(|(p, _)| keystore.read().key_pair::<AuthorityPair>(&p).ok()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
@@ -538,7 +538,7 @@ fn on_post_finalization_error(error: ClientError, value_type: &str) -> Consensus
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use consensus_common::ForkChoiceStrategy;
|
||||
use primitives::H256;
|
||||
use primitives::{H256, crypto::Public};
|
||||
use test_client::client::in_mem::Blockchain as InMemoryAuxStore;
|
||||
use test_client::runtime::{Block, Header};
|
||||
use crate::tests::TestApi;
|
||||
@@ -637,7 +637,7 @@ pub mod tests {
|
||||
let client = test_client::new_light();
|
||||
let mut import_data = LightImportData {
|
||||
last_finalized: Default::default(),
|
||||
authority_set: LightAuthoritySet::genesis(vec![(AuthorityId::from_raw([1; 32]), 1)]),
|
||||
authority_set: LightAuthoritySet::genesis(vec![(AuthorityId::from_slice(&[1; 32]), 1)]),
|
||||
consensus_changes: ConsensusChanges::empty(),
|
||||
};
|
||||
let block = BlockImportParams {
|
||||
@@ -688,7 +688,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn finality_proof_required_when_consensus_data_changes_and_no_justification_provided() {
|
||||
let mut cache = HashMap::new();
|
||||
cache.insert(well_known_cache_keys::AUTHORITIES, vec![AuthorityId::from_raw([2; 32])].encode());
|
||||
cache.insert(well_known_cache_keys::AUTHORITIES, vec![AuthorityId::from_slice(&[2; 32])].encode());
|
||||
assert_eq!(import_block(cache, None), ImportResult::Imported(ImportedAux {
|
||||
clear_justification_requests: false,
|
||||
needs_justification: false,
|
||||
@@ -701,7 +701,7 @@ pub mod tests {
|
||||
fn finality_proof_required_when_consensus_data_changes_and_incorrect_justification_provided() {
|
||||
let justification = TestJustification(false, Vec::new()).encode();
|
||||
let mut cache = HashMap::new();
|
||||
cache.insert(well_known_cache_keys::AUTHORITIES, vec![AuthorityId::from_raw([2; 32])].encode());
|
||||
cache.insert(well_known_cache_keys::AUTHORITIES, vec![AuthorityId::from_slice(&[2; 32])].encode());
|
||||
assert_eq!(
|
||||
import_block(cache, Some(justification)),
|
||||
ImportResult::Imported(ImportedAux {
|
||||
@@ -717,7 +717,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn aux_data_updated_on_start() {
|
||||
let aux_store = InMemoryAuxStore::<Block>::new();
|
||||
let api = Arc::new(TestApi::new(vec![(AuthorityId::from_raw([1; 32]), 1)]));
|
||||
let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]));
|
||||
|
||||
// when aux store is empty initially
|
||||
assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_none());
|
||||
@@ -732,7 +732,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn aux_data_loaded_on_restart() {
|
||||
let aux_store = InMemoryAuxStore::<Block>::new();
|
||||
let api = Arc::new(TestApi::new(vec![(AuthorityId::from_raw([1; 32]), 1)]));
|
||||
let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]));
|
||||
|
||||
// when aux store is non-empty initially
|
||||
let mut consensus_changes = ConsensusChanges::<H256, u64>::empty();
|
||||
@@ -741,7 +741,9 @@ pub mod tests {
|
||||
&[
|
||||
(
|
||||
LIGHT_AUTHORITY_SET_KEY,
|
||||
LightAuthoritySet::genesis(vec![(AuthorityId::from_raw([42; 32]), 2)]).encode().as_slice(),
|
||||
LightAuthoritySet::genesis(
|
||||
vec![(AuthorityId::from_slice(&[42; 32]), 2)]
|
||||
).encode().as_slice(),
|
||||
),
|
||||
(
|
||||
LIGHT_CONSENSUS_CHANGES_KEY,
|
||||
@@ -753,7 +755,7 @@ pub mod tests {
|
||||
|
||||
// importer uses it on start
|
||||
let data = load_aux_import_data(Default::default(), &aux_store, api).unwrap();
|
||||
assert_eq!(data.authority_set.authorities(), vec![(AuthorityId::from_raw([42; 32]), 2)]);
|
||||
assert_eq!(data.authority_set.authorities(), vec![(AuthorityId::from_slice(&[42; 32]), 2)]);
|
||||
assert_eq!(data.consensus_changes.pending_changes(), &[(42, Default::default())]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,11 +185,11 @@ pub fn run_grandpa_observer<B, E, Block: BlockT<Hash=H256>, N, RA, SC>(
|
||||
|
||||
// start global communication stream for the current set
|
||||
let (global_in, _) = global_communication(
|
||||
None,
|
||||
set_id,
|
||||
&voters,
|
||||
&client,
|
||||
&network,
|
||||
&config.keystore,
|
||||
);
|
||||
|
||||
let last_finalized_number = client.info().chain.finalized_number;
|
||||
|
||||
@@ -37,7 +37,7 @@ use std::result;
|
||||
use codec::Decode;
|
||||
use sr_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT};
|
||||
use sr_primitives::generic::BlockId;
|
||||
use primitives::{NativeOrEncoded, ExecutionContext};
|
||||
use primitives::{NativeOrEncoded, ExecutionContext, crypto::Public};
|
||||
use fg_primitives::AuthorityId;
|
||||
|
||||
use authorities::AuthoritySet;
|
||||
@@ -273,7 +273,7 @@ impl GrandpaApi<Block> for RuntimeApi {
|
||||
_: ExecutionContext,
|
||||
_: Option<()>,
|
||||
_: Vec<u8>,
|
||||
) -> Result<NativeOrEncoded<Vec<(primitives::ed25519::Public, u64)>>> {
|
||||
) -> Result<NativeOrEncoded<Vec<(AuthorityId, u64)>>> {
|
||||
Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native)
|
||||
}
|
||||
|
||||
@@ -342,11 +342,17 @@ impl AuthoritySetForFinalityChecker<Block> for TestApi {
|
||||
|
||||
const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500);
|
||||
|
||||
fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(primitives::ed25519::Public, u64)> {
|
||||
keys.iter()
|
||||
.map(|key| AuthorityId::from_raw(key.to_raw_public()))
|
||||
.map(|id| (id, 1))
|
||||
.collect()
|
||||
fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> {
|
||||
keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect()
|
||||
}
|
||||
|
||||
fn create_keystore(authority: Ed25519Keyring) -> (KeyStorePtr, tempfile::TempDir) {
|
||||
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
|
||||
let keystore = keystore::Store::open(keystore_path.path(), None).expect("Creates keystore");
|
||||
keystore.write().insert_ephemeral_from_seed::<AuthorityPair>(&authority.to_seed())
|
||||
.expect("Creates authority key");
|
||||
|
||||
(keystore, keystore_path)
|
||||
}
|
||||
|
||||
// run the voters to completion. provide a closure to be invoked after
|
||||
@@ -370,7 +376,11 @@ fn run_to_completion_with<F>(
|
||||
wait_for.push(f);
|
||||
};
|
||||
|
||||
let mut keystore_paths = Vec::new();
|
||||
for (peer_id, key) in peers.iter().enumerate() {
|
||||
let (keystore, keystore_path) = create_keystore(*key);
|
||||
keystore_paths.push(keystore_path);
|
||||
|
||||
let highest_finalized = highest_finalized.clone();
|
||||
let (client, net_service, link) = {
|
||||
let net = net.lock();
|
||||
@@ -405,7 +415,7 @@ fn run_to_completion_with<F>(
|
||||
config: Config {
|
||||
gossip_duration: TEST_GOSSIP_DURATION,
|
||||
justification_period: 32,
|
||||
local_key: Some(Arc::new(key.clone().into())),
|
||||
keystore: Some(keystore),
|
||||
name: Some(format!("peer#{}", peer_id)),
|
||||
},
|
||||
link: link,
|
||||
@@ -462,8 +472,10 @@ fn finalize_3_voters_no_observers() {
|
||||
run_to_completion(&mut runtime, 20, net.clone(), peers);
|
||||
|
||||
// normally there's no justification for finalized blocks
|
||||
assert!(net.lock().peer(0).client().justification(&BlockId::Number(20)).unwrap().is_none(),
|
||||
"Extra justification for block#1");
|
||||
assert!(
|
||||
net.lock().peer(0).client().justification(&BlockId::Number(20)).unwrap().is_none(),
|
||||
"Extra justification for block#1",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -482,8 +494,10 @@ fn finalize_3_voters_1_full_observer() {
|
||||
|
||||
let all_peers = peers.iter()
|
||||
.cloned()
|
||||
.map(|key| Some(Arc::new(key.into())))
|
||||
.chain(::std::iter::once(None));
|
||||
.map(Some)
|
||||
.chain(std::iter::once(None));
|
||||
|
||||
let mut keystore_paths = Vec::new();
|
||||
|
||||
for (peer_id, local_key) in all_peers.enumerate() {
|
||||
let (client, net_service, link) = {
|
||||
@@ -502,11 +516,19 @@ fn finalize_3_voters_1_full_observer() {
|
||||
.for_each(move |_| Ok(()))
|
||||
);
|
||||
|
||||
let keystore = if let Some(local_key) = local_key {
|
||||
let (keystore, keystore_path) = create_keystore(local_key);
|
||||
keystore_paths.push(keystore_path);
|
||||
Some(keystore)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let grandpa_params = GrandpaParams {
|
||||
config: Config {
|
||||
gossip_duration: TEST_GOSSIP_DURATION,
|
||||
justification_period: 32,
|
||||
local_key,
|
||||
keystore,
|
||||
name: Some(format!("peer#{}", peer_id)),
|
||||
},
|
||||
link: link,
|
||||
@@ -521,7 +543,7 @@ fn finalize_3_voters_1_full_observer() {
|
||||
}
|
||||
|
||||
// wait for all finalized on each.
|
||||
let wait_for = ::futures::future::join_all(finality_notifications)
|
||||
let wait_for = futures::future::join_all(finality_notifications)
|
||||
.map(|_| ())
|
||||
.map_err(|_| ());
|
||||
|
||||
@@ -640,10 +662,13 @@ fn transition_3_voters_twice_1_full_observer() {
|
||||
.cloned()
|
||||
.collect::<HashSet<_>>() // deduplicate
|
||||
.into_iter()
|
||||
.map(|key| Some(Arc::new(key.into())))
|
||||
.enumerate();
|
||||
|
||||
let mut keystore_paths = Vec::new();
|
||||
for (peer_id, local_key) in all_peers {
|
||||
let (keystore, keystore_path) = create_keystore(local_key);
|
||||
keystore_paths.push(keystore_path);
|
||||
|
||||
let (client, net_service, link) = {
|
||||
let net = net.lock();
|
||||
let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
|
||||
@@ -674,7 +699,7 @@ fn transition_3_voters_twice_1_full_observer() {
|
||||
config: Config {
|
||||
gossip_duration: TEST_GOSSIP_DURATION,
|
||||
justification_period: 32,
|
||||
local_key,
|
||||
keystore: Some(keystore),
|
||||
name: Some(format!("peer#{}", peer_id)),
|
||||
},
|
||||
link: link,
|
||||
@@ -704,7 +729,7 @@ fn justification_is_emitted_when_consensus_data_changes() {
|
||||
let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 3);
|
||||
|
||||
// import block#1 WITH consensus data change
|
||||
let new_authorities = vec![primitives::sr25519::Public::from_raw([42; 32])];
|
||||
let new_authorities = vec![babe_primitives::AuthorityId::from_slice(&[42; 32])];
|
||||
net.peer(0).push_authorities_change_block(new_authorities);
|
||||
net.block_until_sync(&mut runtime);
|
||||
let net = Arc::new(Mutex::new(net));
|
||||
@@ -1080,6 +1105,8 @@ fn voter_persists_its_votes() {
|
||||
|
||||
let (voter_tx, voter_rx) = mpsc::unbounded::<()>();
|
||||
|
||||
let mut keystore_paths = Vec::new();
|
||||
|
||||
// startup a grandpa voter for alice but also listen for messages on a
|
||||
// channel. whenever a message is received the voter is restarted. when the
|
||||
// sender is dropped the voter is stopped.
|
||||
@@ -1087,6 +1114,9 @@ fn voter_persists_its_votes() {
|
||||
let net = net.clone();
|
||||
let client = client.clone();
|
||||
|
||||
let (keystore, keystore_path) = create_keystore(peers[0]);
|
||||
keystore_paths.push(keystore_path);
|
||||
|
||||
let voter = future::loop_fn(voter_rx, move |rx| {
|
||||
let (_block_import, _, _, _, link) = net.lock().make_block_import(client.clone());
|
||||
let link = link.lock().take().unwrap();
|
||||
@@ -1095,10 +1125,10 @@ fn voter_persists_its_votes() {
|
||||
config: Config {
|
||||
gossip_duration: TEST_GOSSIP_DURATION,
|
||||
justification_period: 32,
|
||||
local_key: Some(Arc::new(peers[0].clone().into())),
|
||||
keystore: Some(keystore.clone()),
|
||||
name: Some(format!("peer#{}", 0)),
|
||||
},
|
||||
link: link,
|
||||
link,
|
||||
network: net.lock().peers[0].network_service().clone(),
|
||||
inherent_data_providers: InherentDataProviders::new(),
|
||||
on_exit: Exit,
|
||||
@@ -1144,10 +1174,13 @@ fn voter_persists_its_votes() {
|
||||
// voter. instead we'll listen for the prevote that alice casts
|
||||
// and cast our own manually
|
||||
{
|
||||
let (keystore, keystore_path) = create_keystore(peers[1]);
|
||||
keystore_paths.push(keystore_path);
|
||||
|
||||
let config = Config {
|
||||
gossip_duration: TEST_GOSSIP_DURATION,
|
||||
justification_period: 32,
|
||||
local_key: Some(Arc::new(peers[1].clone().into())),
|
||||
keystore: Some(keystore),
|
||||
name: Some(format!("peer#{}", 1)),
|
||||
};
|
||||
|
||||
@@ -1170,7 +1203,7 @@ fn voter_persists_its_votes() {
|
||||
communication::Round(1),
|
||||
communication::SetId(0),
|
||||
Arc::new(VoterSet::from_iter(voters)),
|
||||
Some(config.local_key.unwrap()),
|
||||
Some(peers[1].pair().into()),
|
||||
HasVoted::No,
|
||||
);
|
||||
|
||||
@@ -1296,7 +1329,7 @@ fn finalize_3_voters_1_light_observer() {
|
||||
Config {
|
||||
gossip_duration: TEST_GOSSIP_DURATION,
|
||||
justification_period: 32,
|
||||
local_key: None,
|
||||
keystore: None,
|
||||
name: Some("observer".to_string()),
|
||||
},
|
||||
link,
|
||||
@@ -1320,7 +1353,7 @@ fn finality_proof_is_fetched_by_light_client_when_consensus_data_changes() {
|
||||
|
||||
// import block#1 WITH consensus data change. Light client ignores justification
|
||||
// && instead fetches finality proof for block #1
|
||||
net.peer(0).push_authorities_change_block(vec![primitives::sr25519::Public::from_raw([42; 32])]);
|
||||
net.peer(0).push_authorities_change_block(vec![babe_primitives::AuthorityId::from_slice(&[42; 32])]);
|
||||
let net = Arc::new(Mutex::new(net));
|
||||
run_to_completion(&mut runtime, 1, net.clone(), peers);
|
||||
net.lock().block_until_sync(&mut runtime);
|
||||
@@ -1383,7 +1416,7 @@ fn empty_finality_proof_is_returned_to_light_client_when_authority_set_is_differ
|
||||
// normally it will reach light client, but because of the forced change, it will not
|
||||
net.lock().peer(0).push_blocks(8, false); // best is #9
|
||||
net.lock().peer(0).push_authorities_change_block(
|
||||
vec![primitives::sr25519::Public::from_raw([42; 32])]
|
||||
vec![babe_primitives::AuthorityId::from_slice(&[42; 32])]
|
||||
); // #10
|
||||
net.lock().peer(0).push_blocks(1, false); // best is #11
|
||||
net.lock().block_until_sync(&mut runtime);
|
||||
@@ -1417,15 +1450,15 @@ fn voter_catches_up_to_latest_round_when_behind() {
|
||||
let net = Arc::new(Mutex::new(net));
|
||||
let mut finality_notifications = Vec::new();
|
||||
|
||||
let voter = |local_key, peer_id, link, net: Arc<Mutex<GrandpaTestNet>>| -> Box<dyn Future<Item=(), Error=()> + Send> {
|
||||
let voter = |keystore, peer_id, link, net: Arc<Mutex<GrandpaTestNet>>| -> Box<dyn Future<Item=(), Error=()> + Send> {
|
||||
let grandpa_params = GrandpaParams {
|
||||
config: Config {
|
||||
gossip_duration: TEST_GOSSIP_DURATION,
|
||||
justification_period: 32,
|
||||
local_key,
|
||||
keystore,
|
||||
name: Some(format!("peer#{}", peer_id)),
|
||||
},
|
||||
link: link,
|
||||
link,
|
||||
network: net.lock().peer(peer_id).network_service().clone(),
|
||||
inherent_data_providers: InherentDataProviders::new(),
|
||||
on_exit: Exit,
|
||||
@@ -1435,6 +1468,8 @@ fn voter_catches_up_to_latest_round_when_behind() {
|
||||
Box::new(run_grandpa_voter(grandpa_params).expect("all in order with client and network"))
|
||||
};
|
||||
|
||||
let mut keystore_paths = Vec::new();
|
||||
|
||||
// spawn authorities
|
||||
for (peer_id, key) in peers.iter().enumerate() {
|
||||
let (client, link) = {
|
||||
@@ -1453,7 +1488,10 @@ fn voter_catches_up_to_latest_round_when_behind() {
|
||||
.for_each(move |_| Ok(()))
|
||||
);
|
||||
|
||||
let voter = voter(Some(Arc::new((*key).into())), peer_id, link, net.clone());
|
||||
let (keystore, keystore_path) = create_keystore(*key);
|
||||
keystore_paths.push(keystore_path);
|
||||
|
||||
let voter = voter(Some(keystore), peer_id, link, net.clone());
|
||||
|
||||
runtime.spawn(voter);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
parking_lot = { version = "0.8.0", optional = true }
|
||||
parking_lot = { version = "0.9.0", optional = true }
|
||||
rstd = { package = "sr-std", path = "../sr-std", default-features = false }
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
sr-primitives = { path = "../sr-primitives", default-features = false }
|
||||
|
||||
@@ -36,18 +36,7 @@ pub enum Keyring {
|
||||
|
||||
impl Keyring {
|
||||
pub fn from_public(who: &Public) -> Option<Keyring> {
|
||||
[
|
||||
Keyring::Alice,
|
||||
Keyring::Bob,
|
||||
Keyring::Charlie,
|
||||
Keyring::Dave,
|
||||
Keyring::Eve,
|
||||
Keyring::Ferdie,
|
||||
Keyring::One,
|
||||
Keyring::Two,
|
||||
].iter()
|
||||
.map(|i| *i)
|
||||
.find(|&k| &Public::from(k) == who)
|
||||
Self::iter().find(|&k| &Public::from(k) == who)
|
||||
}
|
||||
|
||||
pub fn from_raw_public(who: [u8; 32]) -> Option<Keyring> {
|
||||
@@ -83,6 +72,14 @@ impl Keyring {
|
||||
pub fn iter() -> impl Iterator<Item=Keyring> {
|
||||
<Self as strum::IntoEnumIterator>::iter()
|
||||
}
|
||||
|
||||
pub fn public(self) -> Public {
|
||||
self.pair().public()
|
||||
}
|
||||
|
||||
pub fn to_seed(self) -> String {
|
||||
format!("//{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Keyring> for &'static str {
|
||||
@@ -172,8 +169,26 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn should_work() {
|
||||
assert!(Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Alice));
|
||||
assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Bob!", Keyring::Alice));
|
||||
assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Bob));
|
||||
assert!(
|
||||
Pair::verify(
|
||||
&Keyring::Alice.sign(b"I am Alice!"),
|
||||
b"I am Alice!",
|
||||
&Keyring::Alice.public(),
|
||||
)
|
||||
);
|
||||
assert!(
|
||||
!Pair::verify(
|
||||
&Keyring::Alice.sign(b"I am Alice!"),
|
||||
b"I am Bob!",
|
||||
&Keyring::Alice.public(),
|
||||
)
|
||||
);
|
||||
assert!(
|
||||
!Pair::verify(
|
||||
&Keyring::Alice.sign(b"I am Alice!"),
|
||||
b"I am Alice!",
|
||||
&Keyring::Bob.public(),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,18 +37,7 @@ pub enum Keyring {
|
||||
|
||||
impl Keyring {
|
||||
pub fn from_public(who: &Public) -> Option<Keyring> {
|
||||
[
|
||||
Keyring::Alice,
|
||||
Keyring::Bob,
|
||||
Keyring::Charlie,
|
||||
Keyring::Dave,
|
||||
Keyring::Eve,
|
||||
Keyring::Ferdie,
|
||||
Keyring::One,
|
||||
Keyring::Two,
|
||||
].iter()
|
||||
.map(|i| *i)
|
||||
.find(|&k| &Public::from(k) == who)
|
||||
Self::iter().find(|&k| &Public::from(k) == who)
|
||||
}
|
||||
|
||||
pub fn from_raw_public(who: [u8; 32]) -> Option<Keyring> {
|
||||
@@ -84,6 +73,14 @@ impl Keyring {
|
||||
pub fn iter() -> impl Iterator<Item=Keyring> {
|
||||
<Self as strum::IntoEnumIterator>::iter()
|
||||
}
|
||||
|
||||
pub fn public(self) -> Public {
|
||||
self.pair().public()
|
||||
}
|
||||
|
||||
pub fn to_seed(self) -> String {
|
||||
format!("//{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Keyring> for &'static str {
|
||||
@@ -109,16 +106,7 @@ impl From<Keyring> for sr_primitives::MultiSigner {
|
||||
|
||||
lazy_static! {
|
||||
static ref PRIVATE_KEYS: HashMap<Keyring, Pair> = {
|
||||
[
|
||||
Keyring::Alice,
|
||||
Keyring::Bob,
|
||||
Keyring::Charlie,
|
||||
Keyring::Dave,
|
||||
Keyring::Eve,
|
||||
Keyring::Ferdie,
|
||||
Keyring::One,
|
||||
Keyring::Two,
|
||||
].iter().map(|&i| (i, i.pair())).collect()
|
||||
Keyring::iter().map(|i| (i, i.pair())).collect()
|
||||
};
|
||||
|
||||
static ref PUBLIC_KEYS: HashMap<Keyring, Public> = {
|
||||
@@ -182,8 +170,26 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn should_work() {
|
||||
assert!(Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Alice));
|
||||
assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Bob!", Keyring::Alice));
|
||||
assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Bob));
|
||||
assert!(
|
||||
Pair::verify(
|
||||
&Keyring::Alice.sign(b"I am Alice!"),
|
||||
b"I am Alice!",
|
||||
&Keyring::Alice.public(),
|
||||
)
|
||||
);
|
||||
assert!(
|
||||
!Pair::verify(
|
||||
&Keyring::Alice.sign(b"I am Alice!"),
|
||||
b"I am Bob!",
|
||||
&Keyring::Alice.public(),
|
||||
)
|
||||
);
|
||||
assert!(
|
||||
!Pair::verify(
|
||||
&Keyring::Alice.sign(b"I am Alice!"),
|
||||
b"I am Alice!",
|
||||
&Keyring::Bob.public(),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
derive_more = "0.14.0"
|
||||
derive_more = "0.15.0"
|
||||
primitives = { package = "substrate-primitives", path = "../primitives" }
|
||||
app-crypto = { package = "substrate-application-crypto", path = "../application-crypto" }
|
||||
hex = "0.3"
|
||||
rand = "0.6"
|
||||
serde_json = "1.0"
|
||||
subtle = "2.0"
|
||||
parking_lot = "0.9.0"
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
|
||||
@@ -18,12 +18,18 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Write};
|
||||
use std::{collections::HashMap, path::PathBuf, fs::{self, File}, io::{self, Write}, sync::Arc};
|
||||
|
||||
use primitives::crypto::{KeyTypeId, Pair, Public};
|
||||
use primitives::{
|
||||
crypto::{KeyTypeId, Pair as PairT, Public, IsWrappedBy, Protected}, traits::BareCryptoStore,
|
||||
};
|
||||
|
||||
use app_crypto::{AppKey, AppPublic, AppPair, ed25519, sr25519};
|
||||
|
||||
use parking_lot::RwLock;
|
||||
|
||||
/// Keystore pointer
|
||||
pub type KeyStorePtr = Arc<RwLock<Store>>;
|
||||
|
||||
/// Keystore error.
|
||||
#[derive(Debug, derive_more::Display, derive_more::From)]
|
||||
@@ -41,6 +47,9 @@ pub enum Error {
|
||||
/// Invalid seed
|
||||
#[display(fmt="Invalid seed")]
|
||||
InvalidSeed,
|
||||
/// Keystore unavailable
|
||||
#[display(fmt="Keystore unavailable")]
|
||||
Unavailable,
|
||||
}
|
||||
|
||||
/// Keystore Result
|
||||
@@ -57,80 +66,159 @@ impl std::error::Error for Error {
|
||||
}
|
||||
|
||||
/// Key store.
|
||||
///
|
||||
/// Stores key pairs in a file system store + short lived key pairs in memory.
|
||||
///
|
||||
/// Every pair that is being generated by a `seed`, will be placed in memory.
|
||||
pub struct Store {
|
||||
path: PathBuf,
|
||||
additional: HashMap<(KeyTypeId, Vec<u8>), Vec<u8>>,
|
||||
password: Option<Protected<String>>,
|
||||
}
|
||||
|
||||
impl Store {
|
||||
/// Create a new store at the given path.
|
||||
pub fn open(path: PathBuf) -> Result<Self> {
|
||||
/// Open the store at the given path.
|
||||
///
|
||||
/// Optionally takes a password that will be used to encrypt/decrypt the keys.
|
||||
pub fn open<T: Into<PathBuf>>(path: T, password: Option<Protected<String>>) -> Result<KeyStorePtr> {
|
||||
let path = path.into();
|
||||
fs::create_dir_all(&path)?;
|
||||
Ok(Store { path, additional: HashMap::new() })
|
||||
|
||||
let instance = Self { path, additional: HashMap::new(), password };
|
||||
Ok(Arc::new(RwLock::new(instance)))
|
||||
}
|
||||
|
||||
fn get_pair<TPair: Pair>(&self, public: &TPair::Public) -> Result<Option<TPair>> {
|
||||
let key = (TPair::KEY_TYPE, public.to_raw_vec());
|
||||
if let Some(bytes) = self.additional.get(&key) {
|
||||
let pair = TPair::from_seed_slice(bytes)
|
||||
.map_err(|_| Error::InvalidSeed)?;
|
||||
return Ok(Some(pair));
|
||||
}
|
||||
Ok(None)
|
||||
/// Get the public/private key pair for the given public key and key type.
|
||||
fn get_additional_pair<Pair: PairT>(
|
||||
&self,
|
||||
public: &Pair::Public,
|
||||
key_type: KeyTypeId,
|
||||
) -> Result<Option<Pair>> {
|
||||
let key = (key_type, public.to_raw_vec());
|
||||
self.additional
|
||||
.get(&key)
|
||||
.map(|bytes| Pair::from_seed_slice(bytes).map_err(|_| Error::InvalidSeed))
|
||||
.transpose()
|
||||
}
|
||||
|
||||
fn insert_pair<TPair: Pair>(&mut self, pair: &TPair) {
|
||||
let key = (TPair::KEY_TYPE, pair.public().to_raw_vec());
|
||||
/// Insert the given public/private key pair with the given key type.
|
||||
///
|
||||
/// Does not place it into the file system store.
|
||||
fn insert_ephemeral_pair<Pair: PairT>(&mut self, pair: &Pair, key_type: KeyTypeId) {
|
||||
let key = (key_type, pair.public().to_raw_vec());
|
||||
self.additional.insert(key, pair.to_raw_vec());
|
||||
}
|
||||
|
||||
/// Generate a new key, placing it into the store.
|
||||
pub fn generate<TPair: Pair>(&self, password: &str) -> Result<TPair> {
|
||||
let (pair, phrase, _) = TPair::generate_with_phrase(Some(password));
|
||||
let mut file = File::create(self.key_file_path::<TPair>(&pair.public()))?;
|
||||
::serde_json::to_writer(&file, &phrase)?;
|
||||
/// Insert a new key with anonymous crypto.
|
||||
///
|
||||
/// Places it into the file system store.
|
||||
fn insert_unknown(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<()> {
|
||||
let mut file = File::create(self.key_file_path(public, key_type)).map_err(Error::Io)?;
|
||||
serde_json::to_writer(&file, &suri).map_err(Error::Json)?;
|
||||
file.flush().map_err(Error::Io)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Insert a new key.
|
||||
///
|
||||
/// Places it into the file system store.
|
||||
pub fn insert_by_type<Pair: PairT>(&self, key_type: KeyTypeId, suri: &str) -> Result<Pair> {
|
||||
let pair = Pair::from_string(
|
||||
suri,
|
||||
self.password.as_ref().map(|p| &***p)
|
||||
).map_err(|_| Error::InvalidSeed)?;
|
||||
self.insert_unknown(key_type, suri, pair.public().as_slice())
|
||||
.map_err(|_| Error::Unavailable)?;
|
||||
Ok(pair)
|
||||
}
|
||||
|
||||
/// Insert a new key.
|
||||
///
|
||||
/// Places it into the file system store.
|
||||
pub fn insert<Pair: AppPair>(&self, suri: &str) -> Result<Pair> {
|
||||
self.insert_by_type::<Pair::Generic>(Pair::ID, suri).map(Into::into)
|
||||
}
|
||||
|
||||
/// Generate a new key.
|
||||
///
|
||||
/// Places it into the file system store.
|
||||
pub fn generate_by_type<Pair: PairT>(&self, key_type: KeyTypeId) -> Result<Pair> {
|
||||
let (pair, phrase, _) = Pair::generate_with_phrase(self.password.as_ref().map(|p| &***p));
|
||||
let mut file = File::create(self.key_file_path(pair.public().as_slice(), key_type))?;
|
||||
serde_json::to_writer(&file, &phrase)?;
|
||||
file.flush()?;
|
||||
Ok(pair)
|
||||
}
|
||||
|
||||
/// Create a new key from seed. Do not place it into the store.
|
||||
pub fn generate_from_seed<TPair: Pair>(&mut self, seed: &str) -> Result<TPair> {
|
||||
let pair = TPair::from_string(seed, None)
|
||||
.ok().ok_or(Error::InvalidSeed)?;
|
||||
self.insert_pair(&pair);
|
||||
/// Generate a new key.
|
||||
///
|
||||
/// Places it into the file system store.
|
||||
pub fn generate<Pair: AppPair>(&self) -> Result<Pair> {
|
||||
self.generate_by_type::<Pair::Generic>(Pair::ID).map(Into::into)
|
||||
}
|
||||
|
||||
/// Create a new key from seed.
|
||||
///
|
||||
/// Does not place it into the file system store.
|
||||
pub fn insert_ephemeral_from_seed_by_type<Pair: PairT>(
|
||||
&mut self,
|
||||
seed: &str,
|
||||
key_type: KeyTypeId,
|
||||
) -> Result<Pair> {
|
||||
let pair = Pair::from_string(seed, None).map_err(|_| Error::InvalidSeed)?;
|
||||
self.insert_ephemeral_pair(&pair, key_type);
|
||||
Ok(pair)
|
||||
}
|
||||
|
||||
/// Load a key file with given public key.
|
||||
pub fn load<TPair: Pair>(&self, public: &TPair::Public, password: &str) -> Result<TPair> {
|
||||
if let Some(pair) = self.get_pair(public)? {
|
||||
/// Create a new key from seed.
|
||||
///
|
||||
/// Does not place it into the file system store.
|
||||
pub fn insert_ephemeral_from_seed<Pair: AppPair>(&mut self, seed: &str) -> Result<Pair> {
|
||||
self.insert_ephemeral_from_seed_by_type::<Pair::Generic>(seed, Pair::ID).map(Into::into)
|
||||
}
|
||||
|
||||
/// Get a key pair for the given public key and key type.
|
||||
pub fn key_pair_by_type<Pair: PairT>(&self,
|
||||
public: &Pair::Public,
|
||||
key_type: KeyTypeId,
|
||||
) -> Result<Pair> {
|
||||
if let Some(pair) = self.get_additional_pair(public, key_type)? {
|
||||
return Ok(pair)
|
||||
}
|
||||
|
||||
let path = self.key_file_path::<TPair>(public);
|
||||
let path = self.key_file_path(public.as_slice(), key_type);
|
||||
let file = File::open(path)?;
|
||||
|
||||
let phrase: String = ::serde_json::from_reader(&file)?;
|
||||
let (pair, _) = TPair::from_phrase(&phrase, Some(password))
|
||||
.ok().ok_or(Error::InvalidPhrase)?;
|
||||
if &pair.public() != public {
|
||||
return Err(Error::InvalidPassword);
|
||||
let phrase: String = serde_json::from_reader(&file)?;
|
||||
let pair = Pair::from_phrase(
|
||||
&phrase,
|
||||
self.password.as_ref().map(|p| &***p),
|
||||
).map_err(|_| Error::InvalidPhrase)?.0;
|
||||
|
||||
if &pair.public() == public {
|
||||
Ok(pair)
|
||||
} else {
|
||||
Err(Error::InvalidPassword)
|
||||
}
|
||||
Ok(pair)
|
||||
}
|
||||
|
||||
/// Get public keys of all stored keys.
|
||||
pub fn contents<TPublic: Public>(&self) -> Result<Vec<TPublic>> {
|
||||
/// Get a key pair for the given public key.
|
||||
pub fn key_pair<Pair: AppPair>(&self, public: &<Pair as AppKey>::Public) -> Result<Pair> {
|
||||
self.key_pair_by_type::<Pair::Generic>(IsWrappedBy::from_ref(public), Pair::ID).map(Into::into)
|
||||
}
|
||||
|
||||
/// Get public keys of all stored keys that match the given key type.
|
||||
pub fn public_keys_by_type<TPublic: Public>(&self, key_type: KeyTypeId) -> Result<Vec<TPublic>> {
|
||||
let mut public_keys: Vec<TPublic> = self.additional.keys()
|
||||
.filter_map(|(ty, public)| {
|
||||
if *ty != TPublic::KEY_TYPE {
|
||||
return None
|
||||
if *ty == key_type {
|
||||
Some(TPublic::from_slice(public))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Some(TPublic::from_slice(public))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let key_type: [u8; 4] = TPublic::KEY_TYPE.to_le_bytes();
|
||||
for entry in fs::read_dir(&self.path)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
@@ -139,7 +227,7 @@ impl Store {
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
match hex::decode(name) {
|
||||
Ok(ref hex) => {
|
||||
if hex[0..4] != key_type { continue }
|
||||
if &hex[0..4] != &key_type.0 { continue }
|
||||
let public = TPublic::from_slice(&hex[4..]);
|
||||
public_keys.push(public);
|
||||
}
|
||||
@@ -151,48 +239,165 @@ impl Store {
|
||||
Ok(public_keys)
|
||||
}
|
||||
|
||||
fn key_file_path<TPair: Pair>(&self, public: &TPair::Public) -> PathBuf {
|
||||
/// Get public keys of all stored keys that match the key type.
|
||||
///
|
||||
/// This will just use the type of the public key (a list of which to be returned) in order
|
||||
/// to determine the key type. Unless you use a specialised application-type public key, then
|
||||
/// this only give you keys registered under generic cryptography, and will not return keys
|
||||
/// registered under the application type.
|
||||
pub fn public_keys<Public: AppPublic>(&self) -> Result<Vec<Public>> {
|
||||
self.public_keys_by_type::<Public::Generic>(Public::ID)
|
||||
.map(|v| v.into_iter().map(Into::into).collect())
|
||||
}
|
||||
|
||||
/// Returns the file path for the given public key and key type.
|
||||
fn key_file_path(&self, public: &[u8], key_type: KeyTypeId) -> PathBuf {
|
||||
let mut buf = self.path.clone();
|
||||
let bytes: [u8; 4] = TPair::KEY_TYPE.to_le_bytes();
|
||||
let key_type = hex::encode(bytes);
|
||||
let key = hex::encode(public.as_slice());
|
||||
let key_type = hex::encode(key_type.0);
|
||||
let key = hex::encode(public);
|
||||
buf.push(key_type + key.as_str());
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
impl BareCryptoStore for Store {
|
||||
fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec<sr25519::Public> {
|
||||
self.public_keys_by_type::<sr25519::Public>(key_type).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn sr25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> std::result::Result<sr25519::Public, String> {
|
||||
let pair = match seed {
|
||||
Some(seed) => self.insert_ephemeral_from_seed_by_type::<sr25519::Pair>(seed, id),
|
||||
None => self.generate_by_type::<sr25519::Pair>(id),
|
||||
}.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(pair.public())
|
||||
}
|
||||
|
||||
fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option<sr25519::Pair> {
|
||||
self.key_pair_by_type::<sr25519::Pair>(pub_key, id).ok()
|
||||
}
|
||||
|
||||
fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec<ed25519::Public> {
|
||||
self.public_keys_by_type::<ed25519::Public>(key_type).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn ed25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> std::result::Result<ed25519::Public, String> {
|
||||
let pair = match seed {
|
||||
Some(seed) => self.insert_ephemeral_from_seed_by_type::<ed25519::Pair>(seed, id),
|
||||
None => self.generate_by_type::<ed25519::Pair>(id),
|
||||
}.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(pair.public())
|
||||
}
|
||||
|
||||
fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option<ed25519::Pair> {
|
||||
self.key_pair_by_type::<ed25519::Pair>(pub_key, id).ok()
|
||||
}
|
||||
|
||||
fn insert_unknown(&mut self, key_type: KeyTypeId, suri: &str, public: &[u8])
|
||||
-> std::result::Result<(), ()>
|
||||
{
|
||||
Store::insert_unknown(self, key_type, suri, public).map_err(|_| ())
|
||||
}
|
||||
|
||||
fn password(&self) -> Option<&str> {
|
||||
self.password.as_ref().map(|x| x.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tempdir::TempDir;
|
||||
use primitives::ed25519;
|
||||
use primitives::crypto::Ss58Codec;
|
||||
|
||||
#[test]
|
||||
fn basic_store() {
|
||||
let temp_dir = TempDir::new("keystore").unwrap();
|
||||
let store = Store::open(temp_dir.path().to_owned()).unwrap();
|
||||
let store = Store::open(temp_dir.path(), None).unwrap();
|
||||
|
||||
assert!(store.contents::<ed25519::Public>().unwrap().is_empty());
|
||||
assert!(store.read().public_keys::<ed25519::AppPublic>().unwrap().is_empty());
|
||||
|
||||
let key: ed25519::Pair = store.generate("thepassword").unwrap();
|
||||
let key2: ed25519::Pair = store.load(&key.public(), "thepassword").unwrap();
|
||||
|
||||
assert!(store.load::<ed25519::Pair>(&key.public(), "notthepassword").is_err());
|
||||
let key: ed25519::AppPair = store.write().generate().unwrap();
|
||||
let key2: ed25519::AppPair = store.read().key_pair(&key.public()).unwrap();
|
||||
|
||||
assert_eq!(key.public(), key2.public());
|
||||
|
||||
assert_eq!(store.contents::<ed25519::Public>().unwrap()[0], key.public());
|
||||
assert_eq!(store.read().public_keys::<ed25519::AppPublic>().unwrap()[0], key.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_from_seed() {
|
||||
fn test_insert_ephemeral_from_seed() {
|
||||
let temp_dir = TempDir::new("keystore").unwrap();
|
||||
let mut store = Store::open(temp_dir.path().to_owned()).unwrap();
|
||||
let store = Store::open(temp_dir.path(), None).unwrap();
|
||||
|
||||
let pair: ed25519::Pair = store
|
||||
.generate_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc")
|
||||
let pair: ed25519::AppPair = store
|
||||
.write()
|
||||
.insert_ephemeral_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc")
|
||||
.unwrap();
|
||||
assert_eq!("5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HJCA", pair.public().to_ss58check());
|
||||
assert_eq!(
|
||||
"5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HJCA",
|
||||
pair.public().to_ss58check()
|
||||
);
|
||||
|
||||
drop(store);
|
||||
let store = Store::open(temp_dir.path(), None).unwrap();
|
||||
// Keys generated from seed should not be persisted!
|
||||
assert!(store.read().key_pair::<ed25519::AppPair>(&pair.public()).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn password_being_used() {
|
||||
let password = String::from("password");
|
||||
let temp_dir = TempDir::new("keystore").unwrap();
|
||||
let store = Store::open(temp_dir.path(), Some(password.clone().into())).unwrap();
|
||||
|
||||
let pair: ed25519::AppPair = store.write().generate().unwrap();
|
||||
assert_eq!(
|
||||
pair.public(),
|
||||
store.read().key_pair::<ed25519::AppPair>(&pair.public()).unwrap().public(),
|
||||
);
|
||||
|
||||
// Without the password the key should not be retrievable
|
||||
let store = Store::open(temp_dir.path(), None).unwrap();
|
||||
assert!(store.read().key_pair::<ed25519::AppPair>(&pair.public()).is_err());
|
||||
|
||||
let store = Store::open(temp_dir.path(), Some(password.into())).unwrap();
|
||||
assert_eq!(
|
||||
pair.public(),
|
||||
store.read().key_pair::<ed25519::AppPair>(&pair.public()).unwrap().public(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_keys_are_returned() {
|
||||
let temp_dir = TempDir::new("keystore").unwrap();
|
||||
let store = Store::open(temp_dir.path(), None).unwrap();
|
||||
|
||||
let mut public_keys = Vec::new();
|
||||
for i in 0..10 {
|
||||
public_keys.push(store.write().generate::<ed25519::AppPair>().unwrap().public());
|
||||
public_keys.push(store.write().insert_ephemeral_from_seed::<ed25519::AppPair>(
|
||||
&format!("0x3d97c819d68f9bafa7d6e79cb991eebcd7{}d966c5334c0b94d9e1fa7ad0869dc", i),
|
||||
).unwrap().public());
|
||||
}
|
||||
|
||||
// Generate a key of a different type
|
||||
store.write().generate::<sr25519::AppPair>().unwrap();
|
||||
|
||||
public_keys.sort();
|
||||
let mut store_pubs = store.read().public_keys::<ed25519::AppPublic>().unwrap();
|
||||
store_pubs.sort();
|
||||
|
||||
assert_eq!(public_keys, store_pubs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ bytes = "0.4"
|
||||
derive_more = "0.14.0"
|
||||
either = "1.5.2"
|
||||
log = "0.4"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
bitflags = "1.0"
|
||||
fnv = "1.0"
|
||||
futures = "0.1.17"
|
||||
@@ -44,6 +44,7 @@ test-client = { package = "substrate-test-runtime-client", path = "../../core/te
|
||||
erased-serde = "0.3.9"
|
||||
void = "1.0"
|
||||
zeroize = "0.9.0"
|
||||
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = { version = "0.6" }
|
||||
|
||||
@@ -102,6 +102,11 @@ impl Roles {
|
||||
self.intersects(Roles::FULL | Roles::AUTHORITY)
|
||||
}
|
||||
|
||||
/// Does this role represents a client that does not participates in the consensus?
|
||||
pub fn is_authority(&self) -> bool {
|
||||
*self == Roles::AUTHORITY
|
||||
}
|
||||
|
||||
/// Does this role represents a client that does not hold full chain data locally?
|
||||
pub fn is_light(&self) -> bool {
|
||||
!self.is_full()
|
||||
|
||||
@@ -57,7 +57,7 @@ use test_client::{self, AccountKeyring};
|
||||
pub use test_client::runtime::{Block, Extrinsic, Hash, Transfer};
|
||||
pub use test_client::TestClient;
|
||||
|
||||
type AuthorityId = primitives::sr25519::Public;
|
||||
type AuthorityId = babe_primitives::AuthorityId;
|
||||
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
/// A Verifier that accepts all blocks and passes them on with the configured
|
||||
|
||||
@@ -12,11 +12,12 @@ futures = "0.1.25"
|
||||
log = "0.4"
|
||||
offchain-primitives = { package = "substrate-offchain-primitives", path = "./primitives" }
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] }
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
primitives = { package = "substrate-primitives", path = "../../core/primitives" }
|
||||
sr-primitives = { path = "../../core/sr-primitives" }
|
||||
transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" }
|
||||
network = { package = "substrate-network", path = "../../core/network" }
|
||||
keystore = { package = "substrate-keystore", path = "../keystore" }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.6"
|
||||
|
||||
@@ -21,174 +21,32 @@ use std::{
|
||||
time::{SystemTime, Duration},
|
||||
thread::sleep,
|
||||
};
|
||||
|
||||
use client::backend::OffchainStorage;
|
||||
use crate::AuthorityKeyProvider;
|
||||
use futures::{Stream, Future, sync::mpsc};
|
||||
use log::{info, debug, warn, error};
|
||||
use network::{PeerId, Multiaddr, NetworkStateInfo};
|
||||
use codec::{Encode, Decode};
|
||||
use primitives::offchain::{
|
||||
Timestamp,
|
||||
HttpRequestId, HttpRequestStatus, HttpError,
|
||||
Externalities as OffchainExt,
|
||||
CryptoKind, CryptoKey,
|
||||
StorageKind,
|
||||
OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr,
|
||||
};
|
||||
use primitives::crypto::{Pair, Public, Protected};
|
||||
use primitives::{ed25519, sr25519};
|
||||
use sr_primitives::{
|
||||
generic::BlockId,
|
||||
traits::{self, Extrinsic},
|
||||
Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError,
|
||||
OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind,
|
||||
};
|
||||
use sr_primitives::{generic::BlockId, traits::{self, Extrinsic}};
|
||||
use transaction_pool::txpool::{Pool, ChainApi};
|
||||
use network::NetworkStateInfo;
|
||||
use network::{PeerId, Multiaddr};
|
||||
|
||||
/// A message between the offchain extension and the processing thread.
|
||||
enum ExtMessage {
|
||||
SubmitExtrinsic(Vec<u8>),
|
||||
}
|
||||
|
||||
/// A persisted key seed.
|
||||
#[derive(Encode, Decode)]
|
||||
struct StoredKey {
|
||||
kind: CryptoKind,
|
||||
phrase: String,
|
||||
}
|
||||
|
||||
impl StoredKey {
|
||||
fn generate_with_phrase(kind: CryptoKind, password: Option<&str>) -> Self {
|
||||
match kind {
|
||||
CryptoKind::Ed25519 => {
|
||||
let phrase = ed25519::Pair::generate_with_phrase(password).1;
|
||||
Self { kind, phrase }
|
||||
}
|
||||
CryptoKind::Sr25519 => {
|
||||
let phrase = sr25519::Pair::generate_with_phrase(password).1;
|
||||
Self { kind, phrase }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_local_key(&self, password: Option<&str>) -> Result<LocalKey, ()> {
|
||||
match self.kind {
|
||||
CryptoKind::Ed25519 => {
|
||||
ed25519::Pair::from_phrase(&self.phrase, password)
|
||||
.map(|x| LocalKey::Ed25519(x.0))
|
||||
}
|
||||
CryptoKind::Sr25519 => {
|
||||
sr25519::Pair::from_phrase(&self.phrase, password)
|
||||
.map(|x| LocalKey::Sr25519(x.0))
|
||||
}
|
||||
}
|
||||
.map_err(|e| {
|
||||
warn!("Error recovering Offchain Worker key. Password invalid? {:?}", e);
|
||||
()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
enum LocalKey {
|
||||
Ed25519(ed25519::Pair),
|
||||
Sr25519(sr25519::Pair),
|
||||
}
|
||||
|
||||
impl LocalKey {
|
||||
fn public(&self) -> Result<Vec<u8>, ()> {
|
||||
match self {
|
||||
LocalKey::Ed25519(pair) => Ok(pair.public().to_raw_vec()),
|
||||
LocalKey::Sr25519(pair) => Ok(pair.public().to_raw_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
match self {
|
||||
LocalKey::Ed25519(pair) => {
|
||||
let sig = pair.sign(data);
|
||||
let bytes: &[u8] = sig.as_ref();
|
||||
Ok(bytes.to_vec())
|
||||
}
|
||||
LocalKey::Sr25519(pair) => {
|
||||
let sig = pair.sign(data);
|
||||
let bytes: &[u8] = sig.as_ref();
|
||||
Ok(bytes.to_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn verify(&self, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
match self {
|
||||
LocalKey::Ed25519(pair) => {
|
||||
Ok(ed25519::Pair::verify_weak(signature, msg, pair.public()))
|
||||
}
|
||||
LocalKey::Sr25519(pair) => {
|
||||
Ok(sr25519::Pair::verify_weak(signature, msg, pair.public()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A key.
|
||||
enum Key<ConsensusPair, FinalityPair> {
|
||||
LocalKey(LocalKey),
|
||||
AuthorityKey(ConsensusPair),
|
||||
FgAuthorityKey(FinalityPair),
|
||||
}
|
||||
|
||||
impl<ConsensusPair: Pair, FinalityPair: Pair> Key<ConsensusPair, FinalityPair> {
|
||||
fn public(&self) -> Result<Vec<u8>, ()> {
|
||||
match self {
|
||||
Key::LocalKey(local) => {
|
||||
local.public()
|
||||
}
|
||||
Key::AuthorityKey(pair) => {
|
||||
Ok(pair.public().to_raw_vec())
|
||||
}
|
||||
Key::FgAuthorityKey(pair) => {
|
||||
Ok(pair.public().to_raw_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
match self {
|
||||
Key::LocalKey(local) => {
|
||||
local.sign(data)
|
||||
}
|
||||
Key::AuthorityKey(pair) => {
|
||||
Ok(pair.sign(data).as_ref().to_vec())
|
||||
}
|
||||
Key::FgAuthorityKey(pair) => {
|
||||
Ok(pair.sign(data).as_ref().to_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn verify(&self, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
match self {
|
||||
Key::LocalKey(local) => {
|
||||
local.verify(msg, signature)
|
||||
}
|
||||
Key::AuthorityKey(pair) => {
|
||||
Ok(ConsensusPair::verify_weak(signature, msg, pair.public()))
|
||||
}
|
||||
Key::FgAuthorityKey(pair) => {
|
||||
Ok(FinalityPair::verify_weak(signature, msg, pair.public()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Asynchronous offchain API.
|
||||
///
|
||||
/// NOTE this is done to prevent recursive calls into the runtime (which are not supported currently).
|
||||
pub(crate) struct Api<Storage, KeyProvider, Block: traits::Block> {
|
||||
pub(crate) struct Api<Storage, Block: traits::Block> {
|
||||
sender: mpsc::UnboundedSender<ExtMessage>,
|
||||
db: Storage,
|
||||
keys_password: Protected<String>,
|
||||
key_provider: KeyProvider,
|
||||
network_state: Arc<dyn NetworkStateInfo + Send + Sync>,
|
||||
at: BlockId<Block>,
|
||||
_at: BlockId<Block>,
|
||||
}
|
||||
|
||||
fn unavailable_yet<R: Default>(name: &str) -> R {
|
||||
@@ -199,59 +57,10 @@ fn unavailable_yet<R: Default>(name: &str) -> R {
|
||||
|
||||
const LOCAL_DB: &str = "LOCAL (fork-aware) DB";
|
||||
const STORAGE_PREFIX: &[u8] = b"storage";
|
||||
const KEYS_PREFIX: &[u8] = b"keys";
|
||||
|
||||
const NEXT_ID: &[u8] = b"crypto_key_id";
|
||||
|
||||
impl<Storage, KeyProvider, Block> Api<Storage, KeyProvider, Block> where
|
||||
Storage: OffchainStorage,
|
||||
KeyProvider: AuthorityKeyProvider<Block>,
|
||||
Block: traits::Block,
|
||||
{
|
||||
fn password(&self) -> Option<&str> {
|
||||
Some(self.keys_password.as_ref().as_str())
|
||||
}
|
||||
|
||||
fn read_key(
|
||||
&self,
|
||||
key: CryptoKey,
|
||||
) -> Result<Key<KeyProvider::ConsensusPair, KeyProvider::FinalityPair>, ()> {
|
||||
match key {
|
||||
CryptoKey::LocalKey { id, kind } => {
|
||||
let key = self.db.get(KEYS_PREFIX, &id.encode())
|
||||
.and_then(|key| StoredKey::decode(&mut &*key).ok())
|
||||
.ok_or(())?;
|
||||
if key.kind != kind {
|
||||
warn!(
|
||||
"Invalid crypto kind (got: {:?}, expected: {:?}), when requesting key {:?}",
|
||||
key.kind,
|
||||
kind,
|
||||
id
|
||||
);
|
||||
return Err(())
|
||||
}
|
||||
Ok(Key::LocalKey(key.to_local_key(self.password())?))
|
||||
}
|
||||
CryptoKey::AuthorityKey => {
|
||||
let key = self.key_provider
|
||||
.authority_key(&self.at)
|
||||
.ok_or(())?;
|
||||
Ok(Key::AuthorityKey(key))
|
||||
}
|
||||
CryptoKey::FgAuthorityKey => {
|
||||
let key = self.key_provider
|
||||
.fg_authority_key(&self.at)
|
||||
.ok_or(())?;
|
||||
Ok(Key::FgAuthorityKey(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Storage, KeyProvider, Block> OffchainExt for Api<Storage, KeyProvider, Block>
|
||||
impl<Storage, Block> OffchainExt for Api<Storage, Block>
|
||||
where
|
||||
Storage: OffchainStorage,
|
||||
KeyProvider: AuthorityKeyProvider<Block>,
|
||||
Block: traits::Block,
|
||||
{
|
||||
fn submit_transaction(&mut self, ext: Vec<u8>) -> Result<(), ()> {
|
||||
@@ -261,30 +70,6 @@ where
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
fn new_crypto_key(&mut self, kind: CryptoKind) -> Result<CryptoKey, ()> {
|
||||
let key = StoredKey::generate_with_phrase(kind, self.password());
|
||||
let (id, id_encoded) = loop {
|
||||
let encoded = self.db.get(KEYS_PREFIX, NEXT_ID);
|
||||
let encoded_slice = encoded.as_ref().map(|x| x.as_slice());
|
||||
let new_id = encoded_slice.and_then(|mut x| u16::decode(&mut x).ok()).unwrap_or_default()
|
||||
.checked_add(1)
|
||||
.ok_or(())?;
|
||||
let new_id_encoded = new_id.encode();
|
||||
|
||||
if self.db.compare_and_set(KEYS_PREFIX, NEXT_ID, encoded_slice, &new_id_encoded) {
|
||||
break (new_id, new_id_encoded);
|
||||
}
|
||||
};
|
||||
|
||||
self.db.set(KEYS_PREFIX, &id_encoded, &key.encode());
|
||||
|
||||
Ok(CryptoKey::LocalKey { id, kind })
|
||||
}
|
||||
|
||||
fn pubkey(&self, key: CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
self.read_key(key)?.public()
|
||||
}
|
||||
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
|
||||
let external_addresses = self.network_state.external_addresses();
|
||||
|
||||
@@ -295,25 +80,6 @@ where
|
||||
Ok(OpaqueNetworkState::from(state))
|
||||
}
|
||||
|
||||
fn encrypt(&mut self, _key: CryptoKey, _data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
unavailable_yet::<()>("encrypt");
|
||||
Err(())
|
||||
}
|
||||
|
||||
fn decrypt(&mut self, _key: CryptoKey, _data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
unavailable_yet::<()>("decrypt");
|
||||
Err(())
|
||||
|
||||
}
|
||||
|
||||
fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
self.read_key(key)?.sign(data)
|
||||
}
|
||||
|
||||
fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
self.read_key(key)?.verify(msg, signature)
|
||||
}
|
||||
|
||||
fn timestamp(&mut self) -> Timestamp {
|
||||
let now = SystemTime::now();
|
||||
let epoch_duration = now.duration_since(SystemTime::UNIX_EPOCH);
|
||||
@@ -506,23 +272,19 @@ pub(crate) struct AsyncApi<A: ChainApi> {
|
||||
|
||||
impl<A: ChainApi> AsyncApi<A> {
|
||||
/// Creates new Offchain extensions API implementation an the asynchronous processing part.
|
||||
pub fn new<S: OffchainStorage, P: AuthorityKeyProvider<A::Block>>(
|
||||
pub fn new<S: OffchainStorage>(
|
||||
transaction_pool: Arc<Pool<A>>,
|
||||
db: S,
|
||||
keys_password: Protected<String>,
|
||||
key_provider: P,
|
||||
at: BlockId<A::Block>,
|
||||
network_state: Arc<dyn NetworkStateInfo + Send + Sync>,
|
||||
) -> (Api<S, P, A::Block>, AsyncApi<A>) {
|
||||
) -> (Api<S, A::Block>, AsyncApi<A>) {
|
||||
let (sender, rx) = mpsc::unbounded();
|
||||
|
||||
let api = Api {
|
||||
sender,
|
||||
db,
|
||||
keys_password,
|
||||
key_provider,
|
||||
network_state,
|
||||
at,
|
||||
_at: at,
|
||||
};
|
||||
|
||||
let async_api = AsyncApi {
|
||||
@@ -571,7 +333,6 @@ mod tests {
|
||||
use std::convert::TryFrom;
|
||||
use sr_primitives::traits::Zero;
|
||||
use client_db::offchain::LocalStorage;
|
||||
use crate::tests::TestProvider;
|
||||
use network::PeerId;
|
||||
use test_client::runtime::Block;
|
||||
|
||||
@@ -587,7 +348,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn offchain_api() -> (Api<LocalStorage, TestProvider<Block>, Block>, AsyncApi<impl ChainApi>) {
|
||||
fn offchain_api() -> (Api<LocalStorage, Block>, AsyncApi<impl ChainApi>) {
|
||||
let _ = env_logger::try_init();
|
||||
let db = LocalStorage::new_test();
|
||||
let client = Arc::new(test_client::new());
|
||||
@@ -596,7 +357,12 @@ mod tests {
|
||||
);
|
||||
|
||||
let mock = Arc::new(MockNetworkStateInfo());
|
||||
AsyncApi::new(pool, db, "pass".to_owned().into(), TestProvider::default(), BlockId::Number(Zero::zero()), mock)
|
||||
AsyncApi::new(
|
||||
pool,
|
||||
db,
|
||||
BlockId::Number(Zero::zero()),
|
||||
mock,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -680,49 +446,6 @@ mod tests {
|
||||
assert_eq!(api.local_storage_get(kind, key), Some(b"value".to_vec()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_create_a_new_key_and_sign_and_verify_stuff() {
|
||||
let test = |kind: CryptoKind| {
|
||||
// given
|
||||
let mut api = offchain_api().0;
|
||||
let msg = b"Hello world!";
|
||||
|
||||
// when
|
||||
let key = api.new_crypto_key(kind).unwrap();
|
||||
let signature = api.sign(key, msg).unwrap();
|
||||
|
||||
// then
|
||||
let res = api.verify(key, msg, &signature).unwrap();
|
||||
assert_eq!(res, true);
|
||||
let res = api.verify(key, msg, &[]).unwrap();
|
||||
assert_eq!(res, false);
|
||||
let res = api.verify(key, b"Different msg", &signature).unwrap();
|
||||
assert_eq!(res, false);
|
||||
};
|
||||
|
||||
test(CryptoKind::Ed25519);
|
||||
test(CryptoKind::Sr25519);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_sign_and_verify_with_authority_key() {
|
||||
// given
|
||||
let mut api = offchain_api().0;
|
||||
api.key_provider.ed_key = Some(ed25519::Pair::generate().0);
|
||||
let msg = b"Hello world!";
|
||||
|
||||
// when
|
||||
let signature = api.sign(CryptoKey::AuthorityKey, msg).unwrap();
|
||||
|
||||
// then
|
||||
let res = api.verify(CryptoKey::AuthorityKey, msg, &signature).unwrap();
|
||||
assert_eq!(res, true);
|
||||
let res = api.verify(CryptoKey::AuthorityKey, msg, &[]).unwrap();
|
||||
assert_eq!(res, false);
|
||||
let res = api.verify(CryptoKey::AuthorityKey, b"Different msg", &signature).unwrap();
|
||||
assert_eq!(res, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_convert_network_states() {
|
||||
// given
|
||||
|
||||
@@ -40,18 +40,12 @@ use std::{
|
||||
};
|
||||
|
||||
use client::runtime_api::ApiExt;
|
||||
use log::{debug, warn};
|
||||
use primitives::{
|
||||
ExecutionContext,
|
||||
crypto,
|
||||
};
|
||||
use sr_primitives::{
|
||||
generic::BlockId,
|
||||
traits::{self, ProvideRuntimeApi},
|
||||
};
|
||||
use futures::future::Future;
|
||||
use transaction_pool::txpool::{Pool, ChainApi};
|
||||
use log::{debug, warn};
|
||||
use network::NetworkStateInfo;
|
||||
use primitives::ExecutionContext;
|
||||
use sr_primitives::{generic::BlockId, traits::{self, ProvideRuntimeApi}};
|
||||
use transaction_pool::txpool::{Pool, ChainApi};
|
||||
|
||||
mod api;
|
||||
|
||||
@@ -59,61 +53,27 @@ pub mod testing;
|
||||
|
||||
pub use offchain_primitives::OffchainWorkerApi;
|
||||
|
||||
/// Provides currently configured authority key.
|
||||
pub trait AuthorityKeyProvider<Block: traits::Block>: Clone + 'static {
|
||||
/// The crypto used by the block authoring algorithm.
|
||||
type ConsensusPair: crypto::Pair;
|
||||
/// The crypto used by the finality gadget.
|
||||
type FinalityPair: crypto::Pair;
|
||||
|
||||
/// Returns currently configured authority key.
|
||||
fn authority_key(&self, block_id: &BlockId<Block>) -> Option<Self::ConsensusPair>;
|
||||
|
||||
/// Returns currently configured finality gadget authority key.
|
||||
fn fg_authority_key(&self, block_id: &BlockId<Block>) -> Option<Self::FinalityPair>;
|
||||
}
|
||||
|
||||
/// An offchain workers manager.
|
||||
pub struct OffchainWorkers<
|
||||
Client,
|
||||
Storage,
|
||||
KeyProvider,
|
||||
Block: traits::Block,
|
||||
> {
|
||||
pub struct OffchainWorkers<Client, Storage, Block: traits::Block> {
|
||||
client: Arc<Client>,
|
||||
db: Storage,
|
||||
authority_key: KeyProvider,
|
||||
keys_password: crypto::Protected<String>,
|
||||
_block: PhantomData<Block>,
|
||||
}
|
||||
|
||||
impl<Client, Storage, KeyProvider, Block: traits::Block> OffchainWorkers<
|
||||
Client,
|
||||
Storage,
|
||||
KeyProvider,
|
||||
Block,
|
||||
> {
|
||||
impl<Client, Storage, Block: traits::Block> OffchainWorkers<Client, Storage, Block> {
|
||||
/// Creates new `OffchainWorkers`.
|
||||
pub fn new(
|
||||
client: Arc<Client>,
|
||||
db: Storage,
|
||||
authority_key: KeyProvider,
|
||||
keys_password: crypto::Protected<String>,
|
||||
) -> Self {
|
||||
pub fn new(client: Arc<Client>, db: Storage) -> Self {
|
||||
Self {
|
||||
client,
|
||||
db,
|
||||
authority_key,
|
||||
keys_password,
|
||||
_block: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client, Storage, KeyProvider, Block: traits::Block> fmt::Debug for OffchainWorkers<
|
||||
impl<Client, Storage, Block: traits::Block> fmt::Debug for OffchainWorkers<
|
||||
Client,
|
||||
Storage,
|
||||
KeyProvider,
|
||||
Block,
|
||||
> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
@@ -121,16 +81,14 @@ impl<Client, Storage, KeyProvider, Block: traits::Block> fmt::Debug for Offchain
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client, Storage, KeyProvider, Block> OffchainWorkers<
|
||||
impl<Client, Storage, Block> OffchainWorkers<
|
||||
Client,
|
||||
Storage,
|
||||
KeyProvider,
|
||||
Block,
|
||||
> where
|
||||
Block: traits::Block,
|
||||
Client: ProvideRuntimeApi + Send + Sync + 'static,
|
||||
Client::Api: OffchainWorkerApi<Block>,
|
||||
KeyProvider: AuthorityKeyProvider<Block> + Send,
|
||||
Storage: client::backend::OffchainStorage + 'static,
|
||||
{
|
||||
/// Start the offchain workers after given block.
|
||||
@@ -152,8 +110,6 @@ impl<Client, Storage, KeyProvider, Block> OffchainWorkers<
|
||||
let (api, runner) = api::AsyncApi::new(
|
||||
pool.clone(),
|
||||
self.db.clone(),
|
||||
self.keys_password.clone(),
|
||||
self.authority_key.clone(),
|
||||
at.clone(),
|
||||
network_state.clone(),
|
||||
);
|
||||
@@ -167,7 +123,7 @@ impl<Client, Storage, KeyProvider, Block> OffchainWorkers<
|
||||
let run = runtime.offchain_worker_with_context(
|
||||
&at,
|
||||
ExecutionContext::OffchainWorker(api),
|
||||
number
|
||||
number,
|
||||
);
|
||||
if let Err(e) = run {
|
||||
log::error!("Error running offchain workers at {:?}: {:?}", at, e);
|
||||
@@ -197,7 +153,6 @@ fn spawn_worker(f: impl FnOnce() -> () + Send + 'static) {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures::Future;
|
||||
use primitives::{ed25519, sr25519};
|
||||
use network::{Multiaddr, PeerId};
|
||||
|
||||
struct MockNetworkStateInfo();
|
||||
@@ -212,49 +167,19 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct TestProvider<Block> {
|
||||
_marker: PhantomData<Block>,
|
||||
pub(crate) sr_key: Option<sr25519::Pair>,
|
||||
pub(crate) ed_key: Option<ed25519::Pair>,
|
||||
}
|
||||
|
||||
impl<Block: traits::Block> Default for TestProvider<Block> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
_marker: PhantomData,
|
||||
sr_key: None,
|
||||
ed_key: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: traits::Block> AuthorityKeyProvider<Block> for TestProvider<Block> {
|
||||
type ConsensusPair = ed25519::Pair;
|
||||
type FinalityPair = sr25519::Pair;
|
||||
|
||||
fn authority_key(&self, _: &BlockId<Block>) -> Option<Self::ConsensusPair> {
|
||||
self.ed_key.clone()
|
||||
}
|
||||
|
||||
fn fg_authority_key(&self, _: &BlockId<Block>) -> Option<Self::FinalityPair> {
|
||||
self.sr_key.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_call_into_runtime_and_produce_extrinsic() {
|
||||
// given
|
||||
let _ = env_logger::try_init();
|
||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
let client = Arc::new(test_client::new());
|
||||
let pool = Arc::new(Pool::new(Default::default(), ::transaction_pool::ChainApi::new(client.clone())));
|
||||
let pool = Arc::new(Pool::new(Default::default(), transaction_pool::ChainApi::new(client.clone())));
|
||||
let db = client_db::offchain::LocalStorage::new_test();
|
||||
let mock = Arc::new(MockNetworkStateInfo());
|
||||
let network_state = Arc::new(MockNetworkStateInfo());
|
||||
|
||||
// when
|
||||
let offchain = OffchainWorkers::new(client, db, TestProvider::default(), "".to_owned().into());
|
||||
runtime.executor().spawn(offchain.on_block_imported(&0u64, &pool, mock.clone()));
|
||||
let offchain = OffchainWorkers::new(client, db);
|
||||
runtime.executor().spawn(offchain.on_block_imported(&0u64, &pool, network_state.clone()));
|
||||
|
||||
// then
|
||||
runtime.shutdown_on_idle().wait().unwrap();
|
||||
|
||||
@@ -28,8 +28,6 @@ use primitives::offchain::{
|
||||
HttpRequestId as RequestId,
|
||||
HttpRequestStatus as RequestStatus,
|
||||
Timestamp,
|
||||
CryptoKind,
|
||||
CryptoKey,
|
||||
StorageKind,
|
||||
OpaqueNetworkState,
|
||||
};
|
||||
@@ -144,47 +142,6 @@ impl offchain::Externalities for TestOffchainExt {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
fn pubkey(&self, _key: CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
fn new_crypto_key(&mut self, _crypto: CryptoKind) -> Result<CryptoKey, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
fn encrypt(
|
||||
&mut self,
|
||||
_key: CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
&mut self,
|
||||
_key: CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
fn sign(
|
||||
&mut self,
|
||||
_key: CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
fn verify(
|
||||
&mut self,
|
||||
_key: CryptoKey,
|
||||
_msg: &[u8],
|
||||
_signature: &[u8],
|
||||
) -> Result<bool, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
fn timestamp(&mut self) -> Timestamp {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ regex = { version = "1.1", optional = true }
|
||||
num-traits = { version = "0.2", default-features = false }
|
||||
zeroize = { version = "0.9.2", default-features = false }
|
||||
lazy_static = { version = "1.3", optional = true }
|
||||
parking_lot = { version = "0.8", optional = true }
|
||||
parking_lot = { version = "0.9.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
substrate-serializer = { path = "../serializer" }
|
||||
|
||||
@@ -18,13 +18,11 @@
|
||||
//! Cryptographic utilities.
|
||||
// end::description[]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use rstd::convert::{TryFrom, TryInto};
|
||||
#[cfg(feature = "std")]
|
||||
use parking_lot::Mutex;
|
||||
#[cfg(feature = "std")]
|
||||
use rand::{RngCore, rngs::OsRng};
|
||||
#[cfg(feature = "std")]
|
||||
use codec::{Encode, Decode};
|
||||
#[cfg(feature = "std")]
|
||||
use regex::Regex;
|
||||
@@ -33,6 +31,8 @@ use base58::{FromBase58, ToBase58};
|
||||
#[cfg(feature = "std")]
|
||||
use std::hash::Hash;
|
||||
use zeroize::Zeroize;
|
||||
#[doc(hidden)]
|
||||
pub use rstd::ops::Deref;
|
||||
|
||||
/// The root phrase for our publicly known keys.
|
||||
pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
|
||||
@@ -83,6 +83,14 @@ impl<T: Zeroize> AsRef<T> for Protected<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zeroize> rstd::ops::Deref for Protected<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Zeroize> std::fmt::Debug for Protected<T> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
@@ -279,12 +287,12 @@ pub trait Ss58Codec: Sized {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Derivable key trait.
|
||||
pub trait Derive: Sized {
|
||||
/// Derive a child key from a series of given junctions.
|
||||
///
|
||||
/// Will be `None` for public keys if there are any hard junctions in there.
|
||||
#[cfg(feature = "std")]
|
||||
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, _path: Iter) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
@@ -457,8 +465,8 @@ impl<T: AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
|
||||
}
|
||||
|
||||
/// Trait suitable for typical cryptographic PKI key public type.
|
||||
pub trait Public: AsRef<[u8]> + TypedKey + PartialEq + Eq + Clone + Send + Sync {
|
||||
/// A new instance from the given slice that should be 32 bytes long.
|
||||
pub trait Public: AsRef<[u8]> + AsMut<[u8]> + Default + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {
|
||||
/// A new instance from the given slice.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
/// you are certain that the array actually is a pubkey. GIGO!
|
||||
@@ -466,17 +474,85 @@ pub trait Public: AsRef<[u8]> + TypedKey + PartialEq + Eq + Clone + Send + Sync
|
||||
|
||||
/// Return a `Vec<u8>` filled with raw data.
|
||||
#[cfg(feature = "std")]
|
||||
fn to_raw_vec(&self) -> Vec<u8>;
|
||||
fn to_raw_vec(&self) -> Vec<u8> { self.as_slice().to_owned() }
|
||||
|
||||
/// Return a slice filled with raw data.
|
||||
fn as_slice(&self) -> &[u8];
|
||||
fn as_slice(&self) -> &[u8] { self.as_ref() }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::dummy::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod dummy {
|
||||
use super::*;
|
||||
|
||||
/// Dummy cryptography. Doesn't do anything.
|
||||
#[derive(Clone, Hash, Default, Eq, PartialEq)]
|
||||
pub struct Dummy;
|
||||
|
||||
impl AsRef<[u8]> for Dummy {
|
||||
fn as_ref(&self) -> &[u8] { &b""[..] }
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Dummy {
|
||||
fn as_mut(&mut self) -> &mut[u8] {
|
||||
unsafe {
|
||||
#[allow(mutable_transmutes)]
|
||||
rstd::mem::transmute::<_, &'static mut [u8]>(&b""[..])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoType for Dummy {
|
||||
type Pair = Dummy;
|
||||
}
|
||||
|
||||
impl Derive for Dummy {}
|
||||
|
||||
impl Public for Dummy {
|
||||
fn from_slice(_: &[u8]) -> Self { Self }
|
||||
#[cfg(feature = "std")]
|
||||
fn to_raw_vec(&self) -> Vec<u8> { vec![] }
|
||||
fn as_slice(&self) -> &[u8] { b"" }
|
||||
}
|
||||
|
||||
impl Pair for Dummy {
|
||||
type Public = Dummy;
|
||||
type Seed = Dummy;
|
||||
type Signature = Dummy;
|
||||
type DeriveError = ();
|
||||
fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) { Default::default() }
|
||||
fn from_phrase(_: &str, _: Option<&str>)
|
||||
-> Result<(Self, Self::Seed), SecretStringError>
|
||||
{
|
||||
Ok(Default::default())
|
||||
}
|
||||
fn derive<
|
||||
Iter: Iterator<Item=DeriveJunction>
|
||||
>(&self, _: Iter) -> Result<Self, Self::DeriveError> { Ok(Self) }
|
||||
fn from_seed(_: &Self::Seed) -> Self { Self }
|
||||
fn from_seed_slice(_: &[u8]) -> Result<Self, SecretStringError> { Ok(Self) }
|
||||
fn from_standard_components<
|
||||
I: Iterator<Item=DeriveJunction>
|
||||
>(
|
||||
_: &str,
|
||||
_: Option<&str>,
|
||||
_: I
|
||||
) -> Result<Self, SecretStringError> { Ok(Self) }
|
||||
fn sign(&self, _: &[u8]) -> Self::Signature { Self }
|
||||
fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool { true }
|
||||
fn public(&self) -> Self::Public { Self }
|
||||
fn to_raw_vec(&self) -> Vec<u8> { vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait suitable for typical cryptographic PKI key pair type.
|
||||
///
|
||||
/// For now it just specifies how to create a key from a phrase and derivation path.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static {
|
||||
pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
|
||||
/// The type which is used to encode a public key.
|
||||
type Public: Public + Hash;
|
||||
|
||||
@@ -538,7 +614,7 @@ pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static {
|
||||
fn sign(&self, message: &[u8]) -> Self::Signature;
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool;
|
||||
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool;
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool;
|
||||
@@ -603,26 +679,109 @@ pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static {
|
||||
fn to_raw_vec(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
/// One type is wrapped by another.
|
||||
pub trait IsWrappedBy<Outer>: From<Outer> + Into<Outer> {
|
||||
/// Get a reference to the inner from the outer.
|
||||
fn from_ref(outer: &Outer) -> &Self;
|
||||
/// Get a mutable reference to the inner from the outer.
|
||||
fn from_mut(outer: &mut Outer) -> &mut Self;
|
||||
}
|
||||
|
||||
/// Opposite of `IsWrappedBy` - denotes a type which is a simple wrapper around another type.
|
||||
pub trait Wraps: Sized {
|
||||
/// The inner type it is wrapping.
|
||||
type Inner: IsWrappedBy<Self>;
|
||||
}
|
||||
|
||||
impl<T, Outer> IsWrappedBy<Outer> for T where
|
||||
Outer: AsRef<Self> + AsMut<Self> + From<Self>,
|
||||
T: From<Outer>,
|
||||
{
|
||||
/// Get a reference to the inner from the outer.
|
||||
fn from_ref(outer: &Outer) -> &Self { outer.as_ref() }
|
||||
|
||||
/// Get a mutable reference to the inner from the outer.
|
||||
fn from_mut(outer: &mut Outer) -> &mut Self { outer.as_mut() }
|
||||
}
|
||||
|
||||
impl<Inner, Outer, T> UncheckedFrom<T> for Outer where
|
||||
Outer: Wraps<Inner=Inner>,
|
||||
Inner: IsWrappedBy<Outer> + UncheckedFrom<T>,
|
||||
{
|
||||
fn unchecked_from(t: T) -> Self {
|
||||
let inner: Inner = t.unchecked_into();
|
||||
inner.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Type which has a particular kind of crypto associated with it.
|
||||
pub trait CryptoType {
|
||||
/// The pair key type of this crypto.
|
||||
#[cfg(feature="std")]
|
||||
type Pair: Pair;
|
||||
}
|
||||
|
||||
/// An identifier for a type of cryptographic key.
|
||||
///
|
||||
/// 0-1024 are reserved.
|
||||
pub type KeyTypeId = u32;
|
||||
/// To avoid clashes with other modules when distributing your module publically, register your
|
||||
/// `KeyTypeId` on the list here by making a PR.
|
||||
///
|
||||
/// Values whose first character is `_` are reserved for private use and won't conflict with any
|
||||
/// public modules.
|
||||
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub struct KeyTypeId(pub [u8; 4]);
|
||||
|
||||
/// Constant key types.
|
||||
impl From<u32> for KeyTypeId {
|
||||
fn from(x: u32) -> Self {
|
||||
Self(x.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyTypeId> for u32 {
|
||||
fn from(x: KeyTypeId) -> Self {
|
||||
u32::from_le_bytes(x.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for KeyTypeId {
|
||||
type Error = ();
|
||||
fn try_from(x: &'a str) -> Result<Self, ()> {
|
||||
let b = x.as_bytes();
|
||||
if b.len() != 4 {
|
||||
return Err(());
|
||||
}
|
||||
let mut res = KeyTypeId::default();
|
||||
res.0.copy_from_slice(&b[0..4]);
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Known key types; this also functions as a global registry of key types for projects wishing to
|
||||
/// avoid collisions with each other.
|
||||
///
|
||||
/// It's not universal in the sense that *all* key types need to be mentioned here, it's just a
|
||||
/// handy place to put common key types.
|
||||
pub mod key_types {
|
||||
use super::KeyTypeId;
|
||||
|
||||
/// ED25519 public key.
|
||||
pub const ED25519: KeyTypeId = 10;
|
||||
|
||||
/// SR25519 public key.
|
||||
pub const SR25519: KeyTypeId = 20;
|
||||
}
|
||||
|
||||
/// A trait for something that has a key type ID.
|
||||
pub trait TypedKey {
|
||||
/// The type ID of this key.
|
||||
const KEY_TYPE: KeyTypeId;
|
||||
/// Key type for generic S/R 25519 key.
|
||||
pub const SR25519: KeyTypeId = KeyTypeId(*b"sr25");
|
||||
/// Key type for generic Ed25519 key.
|
||||
pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25");
|
||||
/// Key type for Babe module, build-in.
|
||||
pub const BABE: KeyTypeId = KeyTypeId(*b"babe");
|
||||
/// Key type for Grandpa module, build-in.
|
||||
pub const GRANDPA: KeyTypeId = KeyTypeId(*b"gran");
|
||||
/// Key type for controlling an account in a Substrate runtime, built-in.
|
||||
pub const ACCOUNT: KeyTypeId = KeyTypeId(*b"acco");
|
||||
/// Key type for Aura module, built-in.
|
||||
pub const AURA: KeyTypeId = KeyTypeId(*b"aura");
|
||||
/// Key type for ImOnline module, built-in.
|
||||
pub const IM_ONLINE: KeyTypeId = KeyTypeId(*b"imon");
|
||||
/// A key type ID useful for tests.
|
||||
#[cfg(feature = "std")]
|
||||
pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -639,14 +798,31 @@ mod tests {
|
||||
Standard{phrase: String, password: Option<String>, path: Vec<DeriveJunction>},
|
||||
Seed(Vec<u8>),
|
||||
}
|
||||
impl Default for TestPair {
|
||||
fn default() -> Self {
|
||||
TestPair::Generated
|
||||
}
|
||||
}
|
||||
impl CryptoType for TestPair {
|
||||
type Pair = Self;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Default)]
|
||||
struct TestPublic;
|
||||
impl AsRef<[u8]> for TestPublic {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
impl AsMut<[u8]> for TestPublic {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut []
|
||||
}
|
||||
}
|
||||
impl CryptoType for TestPublic {
|
||||
type Pair = TestPair;
|
||||
}
|
||||
impl Derive for TestPublic {}
|
||||
impl Public for TestPublic {
|
||||
fn from_slice(_bytes: &[u8]) -> Self {
|
||||
Self
|
||||
@@ -658,9 +834,6 @@ mod tests {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
impl TypedKey for TestPublic {
|
||||
const KEY_TYPE: u32 = 4242;
|
||||
}
|
||||
impl Pair for TestPair {
|
||||
type Public = TestPublic;
|
||||
type Seed = [u8; 0];
|
||||
@@ -686,11 +859,7 @@ mod tests {
|
||||
}
|
||||
fn from_seed(_seed: &<TestPair as Pair>::Seed) -> Self { TestPair::Seed(vec![]) }
|
||||
fn sign(&self, _message: &[u8]) -> Self::Signature { [] }
|
||||
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(
|
||||
_sig: &Self::Signature,
|
||||
_message: M,
|
||||
_pubkey: P
|
||||
) -> bool { true }
|
||||
fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(
|
||||
_sig: &[u8],
|
||||
_message: M,
|
||||
@@ -717,9 +886,6 @@ mod tests {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
impl TypedKey for TestPair {
|
||||
const KEY_TYPE: u32 = 4242;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interpret_std_seed_should_work() {
|
||||
|
||||
@@ -29,10 +29,10 @@ use substrate_bip39::seed_from_entropy;
|
||||
#[cfg(feature = "std")]
|
||||
use bip39::{Mnemonic, Language, MnemonicType};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Derive, Ss58Codec};
|
||||
use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Ss58Codec};
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
|
||||
use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom};
|
||||
use crate::{crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}};
|
||||
|
||||
/// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys
|
||||
/// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we
|
||||
@@ -77,6 +77,20 @@ impl AsMut<[u8]> for Public {
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Public {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 32 {
|
||||
let mut inner = [0u8; 32];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Public(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for [u8; 32] {
|
||||
fn from(x: Public) -> Self {
|
||||
x.0
|
||||
@@ -90,12 +104,6 @@ impl From<Pair> for Public {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Public> for Public {
|
||||
fn as_ref(&self) -> &Public {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for H256 {
|
||||
fn from(x: Public) -> Self {
|
||||
x.0.into()
|
||||
@@ -115,15 +123,15 @@ impl UncheckedFrom<H256> for Public {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Debug for Public {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Debug for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let s = self.to_ss58check();
|
||||
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])
|
||||
}
|
||||
@@ -145,8 +153,8 @@ impl<'de> Deserialize<'de> for Public {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::hash::Hash for Public {
|
||||
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
|
||||
impl std::hash::Hash for Public {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
@@ -155,6 +163,20 @@ impl ::std::hash::Hash for Public {
|
||||
#[derive(Encode, Decode)]
|
||||
pub struct Signature(pub [u8; 64]);
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Signature {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 64 {
|
||||
let mut inner = [0u8; 64];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Signature(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Signature {
|
||||
fn clone(&self) -> Self {
|
||||
let mut r = [0u8; 64];
|
||||
@@ -171,7 +193,7 @@ impl Default for Signature {
|
||||
|
||||
impl PartialEq for Signature {
|
||||
fn eq(&self, b: &Self) -> bool {
|
||||
&self.0[..] == &b.0[..]
|
||||
self.0[..] == b.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,16 +230,16 @@ impl AsMut<[u8]> for Signature {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Debug for Signature {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Debug for Signature {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::hash::Hash for Signature {
|
||||
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
|
||||
::std::hash::Hash::hash(&self.0[..], state);
|
||||
impl std::hash::Hash for Signature {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
std::hash::Hash::hash(&self.0[..], state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,31 +328,10 @@ impl TraitPublic for Public {
|
||||
r.copy_from_slice(data);
|
||||
Public(r)
|
||||
}
|
||||
|
||||
/// Return a `Vec<u8>` filled with raw data.
|
||||
#[cfg(feature = "std")]
|
||||
fn to_raw_vec(&self) -> Vec<u8> {
|
||||
let r: &[u8; 32] = self.as_ref();
|
||||
r.to_vec()
|
||||
}
|
||||
|
||||
/// Return a slice filled with raw data.
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
let r: &[u8; 32] = self.as_ref();
|
||||
&r[..]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Derive for Public {}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl AsRef<Pair> for Pair {
|
||||
fn as_ref(&self) -> &Pair {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
/// Derive a single hard junction.
|
||||
#[cfg(feature = "std")]
|
||||
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
|
||||
@@ -438,8 +439,8 @@ impl TraitPair for Pair {
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool {
|
||||
Self::verify_weak(&sig.0[..], message.as_ref(), &pubkey.as_ref().0[..])
|
||||
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
|
||||
Self::verify_weak(&sig.0[..], message.as_ref(), pubkey)
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
@@ -488,17 +489,19 @@ impl Pair {
|
||||
}
|
||||
}
|
||||
|
||||
impl TypedKey for Public {
|
||||
const KEY_TYPE: KeyTypeId = key_types::ED25519;
|
||||
impl CryptoType for Public {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
impl TypedKey for Signature {
|
||||
const KEY_TYPE: KeyTypeId = key_types::ED25519;
|
||||
impl CryptoType for Signature {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl TypedKey for Pair {
|
||||
const KEY_TYPE: KeyTypeId = key_types::ED25519;
|
||||
impl CryptoType for Pair {
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -33,11 +33,13 @@ macro_rules! map {
|
||||
|
||||
use rstd::prelude::*;
|
||||
use rstd::ops::Deref;
|
||||
use codec::{Encode, Decode};
|
||||
#[cfg(feature = "std")]
|
||||
use std::borrow::Cow;
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
#[cfg(feature = "std")]
|
||||
pub use serde;// << for macro
|
||||
pub use codec::{Encode, Decode};// << for macro
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use impl_serde::serialize as bytes;
|
||||
@@ -61,6 +63,8 @@ pub mod sandbox;
|
||||
pub mod storage;
|
||||
pub mod uint;
|
||||
mod changes_trie;
|
||||
pub mod traits;
|
||||
pub mod testing;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -77,7 +81,6 @@ pub use hash_db::Hasher;
|
||||
pub use self::hasher::blake2::Blake2Hasher;
|
||||
|
||||
/// Context for executing a call into the runtime.
|
||||
#[repr(u8)]
|
||||
pub enum ExecutionContext {
|
||||
/// Context for general importing (including own blocks).
|
||||
Importing,
|
||||
@@ -91,6 +94,17 @@ pub enum ExecutionContext {
|
||||
Other,
|
||||
}
|
||||
|
||||
impl ExecutionContext {
|
||||
/// Returns if the keystore should be enabled for the current context.
|
||||
pub fn enable_keystore(&self) -> bool {
|
||||
use ExecutionContext::*;
|
||||
match self {
|
||||
Importing | Syncing | BlockConstruction => false,
|
||||
OffchainWorker(_) | Other => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Hex-serialized shim for `Vec<u8>`.
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord))]
|
||||
@@ -147,7 +161,7 @@ impl<R: codec::Encode> ::std::fmt::Debug for NativeOrEncoded<R> {
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: codec::Encode> NativeOrEncoded<R> {
|
||||
/// Return the value as the encoded format.
|
||||
pub fn as_encoded<'a>(&'a self) -> Cow<'a, [u8]> {
|
||||
pub fn as_encoded(&self) -> Cow<'_, [u8]> {
|
||||
match self {
|
||||
NativeOrEncoded::Encoded(e) => Cow::Borrowed(e.as_slice()),
|
||||
NativeOrEncoded::Native(n) => Cow::Owned(n.encode()),
|
||||
@@ -199,3 +213,4 @@ impl codec::Decode for NeverNativeValue {
|
||||
Err("`NeverNativeValue` should never be decoded".into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
//! Offchain workers types
|
||||
|
||||
use crate::crypto;
|
||||
use codec::{Encode, Decode};
|
||||
use rstd::prelude::{Vec, Box};
|
||||
use rstd::convert::TryFrom;
|
||||
|
||||
pub use crate::crypto::KeyTypeId;
|
||||
|
||||
/// A type of supported crypto.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
@@ -58,81 +59,6 @@ impl From<StorageKind> for u32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// A type of supported crypto.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
#[repr(C)]
|
||||
pub enum CryptoKind {
|
||||
/// SR25519 crypto (Schnorrkel)
|
||||
Sr25519 = crypto::key_types::SR25519 as isize,
|
||||
/// ED25519 crypto (Edwards)
|
||||
Ed25519 = crypto::key_types::ED25519 as isize,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for CryptoKind {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(kind: u32) -> Result<Self, Self::Error> {
|
||||
match kind {
|
||||
e if e == CryptoKind::Sr25519 as isize as u32 => Ok(CryptoKind::Sr25519),
|
||||
e if e == CryptoKind::Ed25519 as isize as u32 => Ok(CryptoKind::Ed25519),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CryptoKind> for u32 {
|
||||
fn from(c: CryptoKind) -> Self {
|
||||
c as isize as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Key to use in the offchain worker crypto api.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub enum CryptoKey {
|
||||
/// Use a key from the offchain workers local storage.
|
||||
LocalKey {
|
||||
/// The id of the key.
|
||||
id: u16,
|
||||
/// The kind of the key.
|
||||
kind: CryptoKind,
|
||||
},
|
||||
/// Use the key the block authoring algorithm uses.
|
||||
AuthorityKey,
|
||||
/// Use the key the finality gadget uses.
|
||||
FgAuthorityKey,
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for CryptoKey {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(key: u64) -> Result<Self, Self::Error> {
|
||||
match key & 0xFF {
|
||||
0 => {
|
||||
let id = (key >> 8 & 0xFFFF) as u16;
|
||||
let kind = CryptoKind::try_from((key >> 32) as u32)?;
|
||||
Ok(CryptoKey::LocalKey { id, kind })
|
||||
}
|
||||
1 => Ok(CryptoKey::AuthorityKey),
|
||||
2 => Ok(CryptoKey::FgAuthorityKey),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CryptoKey> for u64 {
|
||||
fn from(key: CryptoKey) -> u64 {
|
||||
match key {
|
||||
CryptoKey::LocalKey { id, kind } => {
|
||||
((kind as u64) << 32) | ((id as u64) << 8)
|
||||
}
|
||||
CryptoKey::AuthorityKey => 1,
|
||||
CryptoKey::FgAuthorityKey => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Opaque type for offchain http requests.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
@@ -314,45 +240,6 @@ pub trait Externalities {
|
||||
/// Returns information about the local node's network state.
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()>;
|
||||
|
||||
/// Create new key(pair) for signing/encryption/decryption.
|
||||
///
|
||||
/// Returns an error if given crypto kind is not supported.
|
||||
fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result<CryptoKey, ()>;
|
||||
|
||||
/// Returns the locally configured authority public key, if available.
|
||||
fn pubkey(&self, key: CryptoKey) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Encrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist,
|
||||
/// or the expected `CryptoKind` does not match.
|
||||
fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Decrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`.
|
||||
///
|
||||
/// Returns an error if data cannot be decrypted or the `key` is not available or does not exist,
|
||||
/// or the expected `CryptoKind` does not match.
|
||||
fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Sign a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key of `CryptoKind`.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist,
|
||||
/// or the expected `CryptoKind` does not match.
|
||||
fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Verifies that `signature` for `msg` matches given `key`.
|
||||
///
|
||||
/// Returns an `Ok` with `true` in case it does, `false` in case it doesn't.
|
||||
/// Returns an error in case the key is not available or does not exist or the parameters
|
||||
/// lengths are incorrect or `CryptoKind` does not match.
|
||||
fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result<bool, ()>;
|
||||
|
||||
/// Returns current UNIX timestamp (in millis)
|
||||
fn timestamp(&mut self) -> Timestamp;
|
||||
|
||||
@@ -466,34 +353,10 @@ impl<T: Externalities + ?Sized> Externalities for Box<T> {
|
||||
(&mut **self).submit_transaction(ex)
|
||||
}
|
||||
|
||||
fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result<CryptoKey, ()> {
|
||||
(&mut **self).new_crypto_key(crypto)
|
||||
}
|
||||
|
||||
fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).encrypt(key, data)
|
||||
}
|
||||
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
|
||||
(& **self).network_state()
|
||||
}
|
||||
|
||||
fn pubkey(&self, key: CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
(&**self).pubkey(key)
|
||||
}
|
||||
|
||||
fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).decrypt(key, data)
|
||||
}
|
||||
|
||||
fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).sign(key, data)
|
||||
}
|
||||
|
||||
fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
(&mut **self).verify(key, msg, signature)
|
||||
}
|
||||
|
||||
fn timestamp(&mut self) -> Timestamp {
|
||||
(&mut **self).timestamp()
|
||||
}
|
||||
@@ -571,27 +434,4 @@ mod tests {
|
||||
assert_eq!(t.sub(Duration::from_millis(10)), Timestamp(0));
|
||||
assert_eq!(t.diff(&Timestamp(3)), Duration(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn crypto_key_to_from_u64() {
|
||||
let key = CryptoKey::AuthorityKey;
|
||||
let uint: u64 = key.clone().into();
|
||||
let key2 = CryptoKey::try_from(uint).unwrap();
|
||||
assert_eq!(key, key2);
|
||||
|
||||
let key = CryptoKey::FgAuthorityKey;
|
||||
let uint: u64 = key.clone().into();
|
||||
let key2 = CryptoKey::try_from(uint).unwrap();
|
||||
assert_eq!(key, key2);
|
||||
|
||||
let key = CryptoKey::LocalKey { id: 0, kind: CryptoKind::Ed25519 };
|
||||
let uint: u64 = key.clone().into();
|
||||
let key2 = CryptoKey::try_from(uint).unwrap();
|
||||
assert_eq!(key, key2);
|
||||
|
||||
let key = CryptoKey::LocalKey { id: 10, kind: CryptoKind::Sr25519 };
|
||||
let uint: u64 = key.clone().into();
|
||||
let key2 = CryptoKey::try_from(uint).unwrap();
|
||||
assert_eq!(key, key2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,10 @@ use substrate_bip39::mini_secret_from_entropy;
|
||||
#[cfg(feature = "std")]
|
||||
use bip39::{Mnemonic, Language, MnemonicType};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::crypto::{Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Derive, Ss58Codec};
|
||||
use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom};
|
||||
use crate::crypto::{
|
||||
Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Ss58Codec
|
||||
};
|
||||
use crate::{crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}};
|
||||
use crate::hash::{H256, H512};
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
@@ -56,19 +58,13 @@ pub struct Pair(Keypair);
|
||||
impl Clone for Pair {
|
||||
fn clone(&self) -> Self {
|
||||
Pair(schnorrkel::Keypair {
|
||||
public: self.0.public.clone(),
|
||||
public: self.0.public,
|
||||
secret: schnorrkel::SecretKey::from_bytes(&self.0.secret.to_bytes()[..])
|
||||
.expect("key is always the correct size; qed")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Public> for Public {
|
||||
fn as_ref(&self) -> &Public {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for Public {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
@@ -99,6 +95,20 @@ impl From<Public> for H256 {
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Public {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 32 {
|
||||
let mut inner = [0u8; 32];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Public(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UncheckedFrom<[u8; 32]> for Public {
|
||||
fn unchecked_from(x: [u8; 32]) -> Self {
|
||||
Public::from_raw(x)
|
||||
@@ -112,15 +122,15 @@ impl UncheckedFrom<H256> for Public {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::fmt::Debug for Public {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
impl std::fmt::Debug for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
let s = self.to_ss58check();
|
||||
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])
|
||||
}
|
||||
@@ -142,8 +152,8 @@ impl<'de> Deserialize<'de> for Public {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::hash::Hash for Public {
|
||||
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
|
||||
impl std::hash::Hash for Public {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
@@ -154,6 +164,20 @@ impl ::std::hash::Hash for Public {
|
||||
#[derive(Encode, Decode)]
|
||||
pub struct Signature(pub [u8; 64]);
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Signature {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 64 {
|
||||
let mut inner = [0u8; 64];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Signature(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Signature {
|
||||
fn clone(&self) -> Self {
|
||||
let mut r = [0u8; 64];
|
||||
@@ -170,7 +194,7 @@ impl Default for Signature {
|
||||
|
||||
impl PartialEq for Signature {
|
||||
fn eq(&self, b: &Self) -> bool {
|
||||
&self.0[..] == &b.0[..]
|
||||
self.0[..] == b.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,11 +292,11 @@ impl Signature {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Derive for Public {
|
||||
/// Derive a child key from a series of given junctions.
|
||||
///
|
||||
/// `None` if there are any hard junctions in there.
|
||||
#[cfg(feature = "std")]
|
||||
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Option<Public> {
|
||||
let mut acc = PublicKey::from_bytes(self.as_ref()).ok()?;
|
||||
for j in path {
|
||||
@@ -318,24 +342,6 @@ impl TraitPublic for Public {
|
||||
r.copy_from_slice(data);
|
||||
Public(r)
|
||||
}
|
||||
|
||||
/// Return a `Vec<u8>` filled with raw data.
|
||||
#[cfg(feature = "std")]
|
||||
fn to_raw_vec(&self) -> Vec<u8> {
|
||||
self.0.to_vec()
|
||||
}
|
||||
|
||||
/// Return a slice filled with raw data.
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl AsRef<Pair> for Pair {
|
||||
fn as_ref(&self) -> &Pair {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@@ -475,20 +481,15 @@ impl TraitPair for Pair {
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool {
|
||||
// Match both schnorrkel 0.1.1 and 0.8.0+ signatures, supporting both wallets
|
||||
// that have not been upgraded and those that have. To swap to 0.8.0 only,
|
||||
// create `schnorrkel::Signature` and pass that into `verify_simple`
|
||||
match PublicKey::from_bytes(pubkey.as_ref().as_slice()) {
|
||||
Ok(pk) => pk.verify_simple_preaudit_deprecated(
|
||||
SIGNING_CTX, message.as_ref(), &sig.as_ref(),
|
||||
).is_ok(),
|
||||
Err(_) => false,
|
||||
}
|
||||
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
|
||||
Self::verify_weak(&sig.0[..], message, pubkey)
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool {
|
||||
// Match both schnorrkel 0.1.1 and 0.8.0+ signatures, supporting both wallets
|
||||
// that have not been upgraded and those that have. To swap to 0.8.0 only,
|
||||
// create `schnorrkel::Signature` and pass that into `verify_simple`
|
||||
match PublicKey::from_bytes(pubkey.as_ref()) {
|
||||
Ok(pk) => pk.verify_simple_preaudit_deprecated(
|
||||
SIGNING_CTX, message.as_ref(), &sig,
|
||||
@@ -518,17 +519,19 @@ impl Pair {
|
||||
}
|
||||
}
|
||||
|
||||
impl TypedKey for Public {
|
||||
const KEY_TYPE: KeyTypeId = key_types::SR25519;
|
||||
impl CryptoType for Public {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
impl TypedKey for Signature {
|
||||
const KEY_TYPE: KeyTypeId = key_types::SR25519;
|
||||
impl CryptoType for Signature {
|
||||
#[cfg(feature="std")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl TypedKey for Pair {
|
||||
const KEY_TYPE: KeyTypeId = key_types::SR25519;
|
||||
impl CryptoType for Pair {
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -713,6 +716,6 @@ mod test {
|
||||
let js_signature = Signature::from_raw(hex!(
|
||||
"28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00"
|
||||
));
|
||||
assert!(Pair::verify(&js_signature, b"SUBSTRATE", public));
|
||||
assert!(Pair::verify(&js_signature, b"SUBSTRATE", &public));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Types that should only be used for testing!
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::{ed25519, sr25519, crypto::{Public, Pair, KeyTypeId}};
|
||||
|
||||
/// A keystore implementation usable in tests.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Default)]
|
||||
pub struct KeyStore {
|
||||
/// `KeyTypeId` maps to public keys and public keys map to private keys.
|
||||
keys: std::collections::HashMap<KeyTypeId, std::collections::HashMap<Vec<u8>, Vec<u8>>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl KeyStore {
|
||||
/// Creates a new instance of `Self`.
|
||||
pub fn new() -> std::sync::Arc<parking_lot::RwLock<Self>> {
|
||||
std::sync::Arc::new(parking_lot::RwLock::new(Self::default()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl crate::traits::BareCryptoStore for KeyStore {
|
||||
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public> {
|
||||
self.keys.get(&id)
|
||||
.map(|keys|
|
||||
keys.values()
|
||||
.map(|s| sr25519::Pair::from_seed_slice(s).expect("`sr25519` seed slice is valid"))
|
||||
.map(|p| p.public())
|
||||
.collect()
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn sr25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<sr25519::Public, String> {
|
||||
match seed {
|
||||
Some(seed) => {
|
||||
let pair = sr25519::Pair::from_string(seed, None).expect("Generates an `sr25519` pair.");
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec());
|
||||
Ok(pair.public())
|
||||
},
|
||||
None => {
|
||||
let (pair, _) = sr25519::Pair::generate();
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec());
|
||||
Ok(pair.public())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option<sr25519::Pair> {
|
||||
self.keys.get(&id)
|
||||
.and_then(|inner|
|
||||
inner.get(pub_key.as_slice())
|
||||
.map(|s| sr25519::Pair::from_seed_slice(s).expect("`sr25519` seed slice is valid"))
|
||||
)
|
||||
}
|
||||
|
||||
fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public> {
|
||||
self.keys.get(&id)
|
||||
.map(|keys|
|
||||
keys.values()
|
||||
.map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid"))
|
||||
.map(|p| p.public())
|
||||
.collect()
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn ed25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ed25519::Public, String> {
|
||||
match seed {
|
||||
Some(seed) => {
|
||||
let pair = ed25519::Pair::from_string(seed, None).expect("Generates an `ed25519` pair.");
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec());
|
||||
Ok(pair.public())
|
||||
},
|
||||
None => {
|
||||
let (pair, _) = ed25519::Pair::generate();
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), pair.to_raw_vec());
|
||||
Ok(pair.public())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option<ed25519::Pair> {
|
||||
self.keys.get(&id)
|
||||
.and_then(|inner|
|
||||
inner.get(pub_key.as_slice())
|
||||
.map(|s| ed25519::Pair::from_seed_slice(s).expect("`ed25519` seed slice is valid"))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Shareable Substrate traits.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::{crypto::KeyTypeId, ed25519, sr25519};
|
||||
|
||||
/// Something that generates, stores and provides access to keys.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait BareCryptoStore: Send + Sync {
|
||||
/// Returns all sr25519 public keys for the given key type.
|
||||
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public>;
|
||||
/// Generate a new sr25519 key pair for the given key type and an optional seed.
|
||||
///
|
||||
/// If the given seed is `Some(_)`, the key pair will only be stored in memory.
|
||||
///
|
||||
/// Returns the public key of the generated key pair.
|
||||
fn sr25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<sr25519::Public, String>;
|
||||
/// Returns the sr25519 key pair for the given key type and public key combination.
|
||||
fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option<sr25519::Pair>;
|
||||
|
||||
/// Returns all ed25519 public keys for the given key type.
|
||||
fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public>;
|
||||
/// Generate a new ed25519 key pair for the given key type and an optional seed.
|
||||
///
|
||||
/// If the given seed is `Some(_)`, the key pair will only be stored in memory.
|
||||
///
|
||||
/// Returns the public key of the generated key pair.
|
||||
fn ed25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ed25519::Public, String>;
|
||||
|
||||
/// Returns the ed25519 key pair for the given key type and public key combination.
|
||||
fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option<ed25519::Pair>;
|
||||
|
||||
/// Insert a new key. This doesn't require any known of the crypto; but a public key must be
|
||||
/// manually provided.
|
||||
///
|
||||
/// Places it into the file system store.
|
||||
///
|
||||
/// `Err` if there's some sort of weird filesystem error, but should generally be `Ok`.
|
||||
fn insert_unknown(&mut self, _key_type: KeyTypeId, _suri: &str, _public: &[u8]) -> Result<(), ()> {
|
||||
Err(())
|
||||
}
|
||||
|
||||
/// Get the password for this store.
|
||||
fn password(&self) -> Option<&str> { None }
|
||||
}
|
||||
|
||||
/// A pointer to the key store.
|
||||
#[cfg(feature = "std")]
|
||||
pub type BareCryptoStorePtr = std::sync::Arc<parking_lot::RwLock<dyn BareCryptoStore>>;
|
||||
@@ -13,7 +13,7 @@ jsonrpc-core-client = "12.0.0"
|
||||
jsonrpc-pubsub = "12.0.0"
|
||||
jsonrpc-derive = "12.0.0"
|
||||
log = "0.4"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
@@ -23,8 +23,9 @@ network = { package = "substrate-network", path = "../network" }
|
||||
primitives = { package = "substrate-primitives", path = "../primitives" }
|
||||
state_machine = { package = "substrate-state-machine", path = "../state-machine" }
|
||||
transaction_pool = { package = "substrate-transaction-pool", path = "../transaction-pool" }
|
||||
sr-primitives = { path = "../sr-primitives" }
|
||||
sr-primitives = { path = "../sr-primitives" }
|
||||
runtime_version = { package = "sr-version", path = "../sr-version" }
|
||||
substrate-keystore = { path = "../keystore" }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.1"
|
||||
|
||||
@@ -37,6 +37,18 @@ pub enum Error {
|
||||
/// Incorrect extrinsic format.
|
||||
#[display(fmt="Invalid extrinsic format: {}", _0)]
|
||||
BadFormat(codec::Error),
|
||||
/// Incorrect seed phrase.
|
||||
#[display(fmt="Invalid seed phrase/SURI")]
|
||||
BadSeedPhrase,
|
||||
/// Key type ID has an unknown format.
|
||||
#[display(fmt="Invalid key type ID format (should be of length four)")]
|
||||
BadKeyType,
|
||||
/// Key type ID has some unsupported crypto.
|
||||
#[display(fmt="The crypto of key type ID is unknown")]
|
||||
UnsupportedKeyType,
|
||||
/// Some random issue with the key store. Shouldn't happen.
|
||||
#[display(fmt="The key store is unavailable")]
|
||||
KeyStoreUnavailable,
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
|
||||
@@ -22,7 +22,7 @@ pub mod hash;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{sync::Arc, convert::TryInto};
|
||||
|
||||
use client::{self, Client};
|
||||
use crate::rpc::futures::{Sink, Stream, Future};
|
||||
@@ -31,9 +31,12 @@ use jsonrpc_derive::rpc;
|
||||
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
|
||||
use log::warn;
|
||||
use codec::{Encode, Decode};
|
||||
use primitives::{Bytes, Blake2Hasher, H256};
|
||||
use primitives::{
|
||||
Bytes, Blake2Hasher, H256, ed25519, sr25519, crypto::{Pair, Public, key_types},
|
||||
traits::BareCryptoStorePtr
|
||||
};
|
||||
use sr_primitives::{generic, traits};
|
||||
use self::error::Result;
|
||||
use self::error::{Error, Result};
|
||||
use transaction_pool::{
|
||||
txpool::{
|
||||
ChainApi as PoolChainApi,
|
||||
@@ -57,21 +60,46 @@ pub trait AuthorApi<Hash, BlockHash> {
|
||||
#[rpc(name = "author_submitExtrinsic")]
|
||||
fn submit_extrinsic(&self, extrinsic: Bytes) -> Result<Hash>;
|
||||
|
||||
/// Insert a key into the keystore.
|
||||
#[rpc(name = "author_insertKey")]
|
||||
fn insert_key(&self,
|
||||
key_type: String,
|
||||
suri: String,
|
||||
maybe_public: Option<Bytes>
|
||||
) -> Result<Bytes>;
|
||||
|
||||
/// Returns all pending extrinsics, potentially grouped by sender.
|
||||
#[rpc(name = "author_pendingExtrinsics")]
|
||||
fn pending_extrinsics(&self) -> Result<Vec<Bytes>>;
|
||||
|
||||
/// Remove given extrinsic from the pool and temporarily ban it to prevent reimporting.
|
||||
#[rpc(name = "author_removeExtrinsic")]
|
||||
fn remove_extrinsic(&self, bytes_or_hash: Vec<hash::ExtrinsicOrHash<Hash>>) -> Result<Vec<Hash>>;
|
||||
fn remove_extrinsic(&self,
|
||||
bytes_or_hash: Vec<hash::ExtrinsicOrHash<Hash>>
|
||||
) -> Result<Vec<Hash>>;
|
||||
|
||||
/// Submit an extrinsic to watch.
|
||||
#[pubsub(subscription = "author_extrinsicUpdate", subscribe, name = "author_submitAndWatchExtrinsic")]
|
||||
fn watch_extrinsic(&self, metadata: Self::Metadata, subscriber: Subscriber<Status<Hash, BlockHash>>, bytes: Bytes);
|
||||
#[pubsub(
|
||||
subscription = "author_extrinsicUpdate",
|
||||
subscribe,
|
||||
name = "author_submitAndWatchExtrinsic"
|
||||
)]
|
||||
fn watch_extrinsic(&self,
|
||||
metadata: Self::Metadata,
|
||||
subscriber: Subscriber<Status<Hash, BlockHash>>,
|
||||
bytes: Bytes
|
||||
);
|
||||
|
||||
/// Unsubscribe from extrinsic watching.
|
||||
#[pubsub(subscription = "author_extrinsicUpdate", unsubscribe, name = "author_unwatchExtrinsic")]
|
||||
fn unwatch_extrinsic(&self, metadata: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool>;
|
||||
#[pubsub(
|
||||
subscription = "author_extrinsicUpdate",
|
||||
unsubscribe,
|
||||
name = "author_unwatchExtrinsic"
|
||||
)]
|
||||
fn unwatch_extrinsic(&self,
|
||||
metadata: Option<Self::Metadata>,
|
||||
id: SubscriptionId
|
||||
) -> Result<bool>;
|
||||
}
|
||||
|
||||
/// Authoring API
|
||||
@@ -82,6 +110,8 @@ pub struct Author<B, E, P, RA> where P: PoolChainApi + Sync + Send + 'static {
|
||||
pool: Arc<Pool<P>>,
|
||||
/// Subscriptions manager
|
||||
subscriptions: Subscriptions,
|
||||
/// The key store.
|
||||
keystore: BareCryptoStorePtr,
|
||||
}
|
||||
|
||||
impl<B, E, P, RA> Author<B, E, P, RA> where P: PoolChainApi + Sync + Send + 'static {
|
||||
@@ -90,11 +120,13 @@ impl<B, E, P, RA> Author<B, E, P, RA> where P: PoolChainApi + Sync + Send + 'sta
|
||||
client: Arc<Client<B, E, <P as PoolChainApi>::Block, RA>>,
|
||||
pool: Arc<Pool<P>>,
|
||||
subscriptions: Subscriptions,
|
||||
keystore: BareCryptoStorePtr,
|
||||
) -> Self {
|
||||
Author {
|
||||
client,
|
||||
pool,
|
||||
subscriptions,
|
||||
keystore,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,10 +137,38 @@ impl<B, E, P, RA> AuthorApi<ExHash<P>, BlockHash<P>> for Author<B, E, P, RA> whe
|
||||
P: PoolChainApi + Sync + Send + 'static,
|
||||
P::Block: traits::Block<Hash=H256>,
|
||||
P::Error: 'static,
|
||||
RA: Send + Sync + 'static
|
||||
RA: Send + Sync + 'static,
|
||||
{
|
||||
type Metadata = crate::metadata::Metadata;
|
||||
|
||||
fn insert_key(&self,
|
||||
key_type: String,
|
||||
suri: String,
|
||||
maybe_public: Option<Bytes>,
|
||||
) -> Result<Bytes> {
|
||||
let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?;
|
||||
let mut keystore = self.keystore.write();
|
||||
let maybe_password = keystore.password();
|
||||
let public = match maybe_public {
|
||||
Some(public) => public.0,
|
||||
None => {
|
||||
let maybe_public = match key_type {
|
||||
key_types::BABE | key_types::IM_ONLINE | key_types::SR25519 =>
|
||||
sr25519::Pair::from_string(&suri, maybe_password)
|
||||
.map(|pair| pair.public().to_raw_vec()),
|
||||
key_types::GRANDPA | key_types::ED25519 =>
|
||||
ed25519::Pair::from_string(&suri, maybe_password)
|
||||
.map(|pair| pair.public().to_raw_vec()),
|
||||
_ => Err(Error::UnsupportedKeyType)?,
|
||||
};
|
||||
maybe_public.map_err(|_| Error::BadSeedPhrase)?
|
||||
}
|
||||
};
|
||||
keystore.insert_unknown(key_type, &suri, &public[..])
|
||||
.map_err(|_| Error::KeyStoreUnavailable)?;
|
||||
Ok(public.into())
|
||||
}
|
||||
|
||||
fn submit_extrinsic(&self, ext: Bytes) -> Result<ExHash<P>> {
|
||||
let xt = Decode::decode(&mut &ext[..])?;
|
||||
let best_block_hash = self.client.info().chain.best_hash;
|
||||
@@ -124,7 +184,9 @@ impl<B, E, P, RA> AuthorApi<ExHash<P>, BlockHash<P>> for Author<B, E, P, RA> whe
|
||||
Ok(self.pool.ready().map(|tx| tx.data.encode().into()).collect())
|
||||
}
|
||||
|
||||
fn remove_extrinsic(&self, bytes_or_hash: Vec<hash::ExtrinsicOrHash<ExHash<P>>>) -> Result<Vec<ExHash<P>>> {
|
||||
fn remove_extrinsic(&self,
|
||||
bytes_or_hash: Vec<hash::ExtrinsicOrHash<ExHash<P>>>
|
||||
) -> Result<Vec<ExHash<P>>> {
|
||||
let hashes = bytes_or_hash.into_iter()
|
||||
.map(|x| match x {
|
||||
hash::ExtrinsicOrHash::Hash(h) => Ok(h),
|
||||
@@ -143,7 +205,11 @@ impl<B, E, P, RA> AuthorApi<ExHash<P>, BlockHash<P>> for Author<B, E, P, RA> whe
|
||||
)
|
||||
}
|
||||
|
||||
fn watch_extrinsic(&self, _metadata: Self::Metadata, subscriber: Subscriber<Status<ExHash<P>, BlockHash<P>>>, xt: Bytes) {
|
||||
fn watch_extrinsic(&self,
|
||||
_metadata: Self::Metadata,
|
||||
subscriber: Subscriber<Status<ExHash<P>, BlockHash<P>>>,
|
||||
xt: Bytes
|
||||
) {
|
||||
let submit = || -> Result<_> {
|
||||
let best_block_hash = self.client.info().chain.best_hash;
|
||||
let dxt = <<P as PoolChainApi>::Block as traits::Block>::Extrinsic::decode(&mut &xt[..])?;
|
||||
|
||||
@@ -23,9 +23,12 @@ use transaction_pool::{
|
||||
txpool::Pool,
|
||||
ChainApi,
|
||||
};
|
||||
use primitives::{H256, blake2_256, hexdisplay::HexDisplay};
|
||||
use primitives::{H256, blake2_256, hexdisplay::HexDisplay, traits::BareCryptoStore};
|
||||
use test_client::{self, AccountKeyring, runtime::{Extrinsic, Transfer}};
|
||||
use tokio::runtime;
|
||||
use std::collections::HashMap;
|
||||
use sr_primitives::KeyTypeId;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic {
|
||||
let tx = Transfer {
|
||||
@@ -37,14 +40,55 @@ fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic {
|
||||
tx.into_signed_tx()
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TestKeyStore {
|
||||
keys: HashMap<KeyTypeId, HashMap<Vec<u8>, String>>,
|
||||
}
|
||||
|
||||
impl BareCryptoStore for TestKeyStore {
|
||||
fn sr25519_public_keys(&self, _id: KeyTypeId) -> Vec<sr25519::Public> { vec![] }
|
||||
fn sr25519_generate_new(&mut self, _id: KeyTypeId, _seed: Option<&str>)
|
||||
-> std::result::Result<sr25519::Public, String>
|
||||
{
|
||||
Err("unimplemented".into())
|
||||
}
|
||||
fn sr25519_key_pair(&self, _id: KeyTypeId, _pub_key: &sr25519::Public) -> Option<sr25519::Pair> {
|
||||
None
|
||||
}
|
||||
fn ed25519_public_keys(&self, _id: KeyTypeId) -> Vec<ed25519::Public> { vec![] }
|
||||
fn ed25519_generate_new(&mut self, _id: KeyTypeId, _seed: Option<&str>)
|
||||
-> std::result::Result<ed25519::Public, String>
|
||||
{
|
||||
Err("unimplemented".into())
|
||||
}
|
||||
fn ed25519_key_pair(&self, _id: KeyTypeId, _pub_key: &ed25519::Public) -> Option<ed25519::Pair> {
|
||||
None
|
||||
}
|
||||
|
||||
fn insert_unknown(&mut self, key_type: KeyTypeId, suri: &str, public: &[u8])
|
||||
-> std::result::Result<(), ()>
|
||||
{
|
||||
self.keys
|
||||
.entry(key_type)
|
||||
.or_default()
|
||||
.insert(public.to_owned(), suri.to_owned());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn password(&self) -> Option<&str> { None }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn submit_transaction_should_not_cause_error() {
|
||||
let runtime = runtime::Runtime::new().unwrap();
|
||||
let client = Arc::new(test_client::new());
|
||||
let keystore = TestKeyStore::default();
|
||||
let keystore = Arc::new(RwLock::new(keystore));
|
||||
let p = Author {
|
||||
client: client.clone(),
|
||||
pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client))),
|
||||
subscriptions: Subscriptions::new(Arc::new(runtime.executor())),
|
||||
keystore: keystore.clone(),
|
||||
};
|
||||
let xt = uxt(AccountKeyring::Alice, 1).encode();
|
||||
let h: H256 = blake2_256(&xt).into();
|
||||
@@ -62,10 +106,12 @@ fn submit_transaction_should_not_cause_error() {
|
||||
fn submit_rich_transaction_should_not_cause_error() {
|
||||
let runtime = runtime::Runtime::new().unwrap();
|
||||
let client = Arc::new(test_client::new());
|
||||
let keystore = Arc::new(RwLock::new(TestKeyStore::default()));
|
||||
let p = Author {
|
||||
client: client.clone(),
|
||||
pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone()))),
|
||||
subscriptions: Subscriptions::new(Arc::new(runtime.executor())),
|
||||
keystore: keystore.clone(),
|
||||
};
|
||||
let xt = uxt(AccountKeyring::Alice, 0).encode();
|
||||
let h: H256 = blake2_256(&xt).into();
|
||||
@@ -85,10 +131,12 @@ fn should_watch_extrinsic() {
|
||||
let mut runtime = runtime::Runtime::new().unwrap();
|
||||
let client = Arc::new(test_client::new());
|
||||
let pool = Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone())));
|
||||
let keystore = Arc::new(RwLock::new(TestKeyStore::default()));
|
||||
let p = Author {
|
||||
client,
|
||||
pool: pool.clone(),
|
||||
subscriptions: Subscriptions::new(Arc::new(runtime.executor())),
|
||||
keystore: keystore.clone(),
|
||||
};
|
||||
let (subscriber, id_rx, data) = ::jsonrpc_pubsub::typed::Subscriber::new_test("test");
|
||||
|
||||
@@ -125,10 +173,12 @@ fn should_return_pending_extrinsics() {
|
||||
let runtime = runtime::Runtime::new().unwrap();
|
||||
let client = Arc::new(test_client::new());
|
||||
let pool = Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone())));
|
||||
let keystore = Arc::new(RwLock::new(TestKeyStore::default()));
|
||||
let p = Author {
|
||||
client,
|
||||
pool: pool.clone(),
|
||||
subscriptions: Subscriptions::new(Arc::new(runtime.executor())),
|
||||
keystore: keystore.clone(),
|
||||
};
|
||||
let ex = uxt(AccountKeyring::Alice, 0);
|
||||
AuthorApi::submit_extrinsic(&p, ex.encode().into()).unwrap();
|
||||
@@ -143,10 +193,12 @@ fn should_remove_extrinsics() {
|
||||
let runtime = runtime::Runtime::new().unwrap();
|
||||
let client = Arc::new(test_client::new());
|
||||
let pool = Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone())));
|
||||
let keystore = Arc::new(RwLock::new(TestKeyStore::default()));
|
||||
let p = Author {
|
||||
client,
|
||||
pool: pool.clone(),
|
||||
subscriptions: Subscriptions::new(Arc::new(runtime.executor())),
|
||||
keystore: keystore.clone(),
|
||||
};
|
||||
let ex1 = uxt(AccountKeyring::Alice, 0);
|
||||
p.submit_extrinsic(ex1.encode().into()).unwrap();
|
||||
|
||||
@@ -8,7 +8,7 @@ edition = "2018"
|
||||
derive_more = "0.14.0"
|
||||
futures = "0.1.17"
|
||||
futures03 = { package = "futures-preview", version = "0.3.0-alpha.17", features = ["compat"] }
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
lazy_static = "1.0"
|
||||
log = "0.4"
|
||||
slog = {version = "^2", features = ["nested-values"]}
|
||||
@@ -22,7 +22,9 @@ target_info = "0.1"
|
||||
keystore = { package = "substrate-keystore", path = "../../core/keystore" }
|
||||
sr-io = { path = "../../core/sr-io" }
|
||||
sr-primitives = { path = "../../core/sr-primitives" }
|
||||
primitives = { package = "substrate-primitives", path = "../../core/primitives" }
|
||||
primitives = { package = "substrate-primitives", path = "../primitives" }
|
||||
app-crypto = { package = "substrate-application-crypto", path = "../application-crypto" }
|
||||
substrate-session = { path = "../session" }
|
||||
consensus_common = { package = "substrate-consensus-common", path = "../../core/consensus/common" }
|
||||
network = { package = "substrate-network", path = "../../core/network" }
|
||||
client = { package = "substrate-client", path = "../../core/client" }
|
||||
@@ -40,4 +42,6 @@ substrate-test-runtime-client = { path = "../test-runtime/client" }
|
||||
node-executor = { path = "../../node/executor" }
|
||||
node-primitives = { path = "../../node/primitives" }
|
||||
node-runtime = { path = "../../node/runtime" }
|
||||
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives" }
|
||||
grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality-grandpa" }
|
||||
grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = "../../core/finality-grandpa/primitives" }
|
||||
|
||||
@@ -34,7 +34,7 @@ enum GenesisSource<G> {
|
||||
Factory(fn() -> G),
|
||||
}
|
||||
|
||||
impl<G: RuntimeGenesis> Clone for GenesisSource<G> {
|
||||
impl<G> Clone for GenesisSource<G> {
|
||||
fn clone(&self) -> Self {
|
||||
match *self {
|
||||
GenesisSource::File(ref path) => GenesisSource::File(path.clone()),
|
||||
@@ -104,12 +104,12 @@ struct ChainSpecFile {
|
||||
pub type Properties = json::map::Map<String, json::Value>;
|
||||
|
||||
/// A configuration of a chain. Can be used to build a genesis block.
|
||||
pub struct ChainSpec<G: RuntimeGenesis> {
|
||||
pub struct ChainSpec<G> {
|
||||
spec: ChainSpecFile,
|
||||
genesis: GenesisSource<G>,
|
||||
}
|
||||
|
||||
impl<G: RuntimeGenesis> Clone for ChainSpec<G> {
|
||||
impl<G> Clone for ChainSpec<G> {
|
||||
fn clone(&self) -> Self {
|
||||
ChainSpec {
|
||||
spec: self.spec.clone(),
|
||||
|
||||
@@ -19,18 +19,21 @@
|
||||
use std::{sync::Arc, ops::Deref, ops::DerefMut};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use crate::chain_spec::ChainSpec;
|
||||
use keystore::KeyStorePtr;
|
||||
use client_db;
|
||||
use client::{self, Client, runtime_api};
|
||||
use crate::{error, Service, AuthorityKeyProvider};
|
||||
use crate::{error, Service};
|
||||
use consensus_common::{import_queue::ImportQueue, SelectChain};
|
||||
use network::{self, OnDemand, FinalityProofProvider, NetworkStateInfo, config::BoxFinalityProofRequestBuilder};
|
||||
use network::{
|
||||
self, OnDemand, FinalityProofProvider, NetworkStateInfo, config::BoxFinalityProofRequestBuilder
|
||||
};
|
||||
use substrate_executor::{NativeExecutor, NativeExecutionDispatch};
|
||||
use transaction_pool::txpool::{self, Options as TransactionPoolOptions, Pool as TransactionPool};
|
||||
use sr_primitives::{
|
||||
BuildStorage, traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, generic::BlockId
|
||||
};
|
||||
use crate::config::Configuration;
|
||||
use primitives::{Blake2Hasher, H256, Pair};
|
||||
use primitives::{Blake2Hasher, H256, traits::BareCryptoStorePtr};
|
||||
use rpc::{self, apis::system::SystemInfo};
|
||||
use futures::{prelude::*, future::Executor};
|
||||
use futures03::channel::mpsc;
|
||||
@@ -129,16 +132,6 @@ pub type ComponentOffchainStorage<C> = <
|
||||
/// Block type for `Components`
|
||||
pub type ComponentBlock<C> = <<C as Components>::Factory as ServiceFactory>::Block;
|
||||
|
||||
/// ConsensusPair type for `Components`
|
||||
pub type ComponentConsensusPair<C> = <<C as Components>::Factory as ServiceFactory>::ConsensusPair;
|
||||
|
||||
/// FinalityPair type for `Components`
|
||||
pub type ComponentFinalityPair<C> = <<C as Components>::Factory as ServiceFactory>::FinalityPair;
|
||||
|
||||
/// AuthorityKeyProvider type for `Components`
|
||||
pub type ComponentAuthorityKeyProvider<C> =
|
||||
AuthorityKeyProvider<ComponentBlock<C>, ComponentConsensusPair<C>, ComponentFinalityPair<C>>;
|
||||
|
||||
/// Extrinsic hash type for `Components`
|
||||
pub type ComponentExHash<C> = <<C as Components>::TransactionPoolApi as txpool::ChainApi>::Hash;
|
||||
|
||||
@@ -152,6 +145,27 @@ pub type PoolApi<C> = <C as Components>::TransactionPoolApi;
|
||||
pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {}
|
||||
impl<T: Serialize + DeserializeOwned + BuildStorage> RuntimeGenesis for T {}
|
||||
|
||||
/// Something that can create initial session keys from given seeds.
|
||||
pub trait InitialSessionKeys<C: Components> {
|
||||
/// Generate the initial session keys for the given seeds.
|
||||
fn generate_intial_session_keys(
|
||||
client: Arc<ComponentClient<C>>,
|
||||
seeds: Vec<String>,
|
||||
) -> error::Result<()>;
|
||||
}
|
||||
|
||||
impl<C: Components> InitialSessionKeys<Self> for C where
|
||||
ComponentClient<C>: ProvideRuntimeApi,
|
||||
<ComponentClient<C> as ProvideRuntimeApi>::Api: substrate_session::SessionKeys<ComponentBlock<C>>,
|
||||
{
|
||||
fn generate_intial_session_keys(
|
||||
client: Arc<ComponentClient<C>>,
|
||||
seeds: Vec<String>,
|
||||
) -> error::Result<()> {
|
||||
substrate_session::generate_initial_session_keys(client, seeds).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that can start the RPC service.
|
||||
pub trait StartRPC<C: Components> {
|
||||
fn start_rpc(
|
||||
@@ -160,6 +174,7 @@ pub trait StartRPC<C: Components> {
|
||||
system_info: SystemInfo,
|
||||
task_executor: TaskExecutor,
|
||||
transaction_pool: Arc<TransactionPool<C::TransactionPoolApi>>,
|
||||
keystore: KeyStorePtr,
|
||||
) -> rpc::RpcHandler;
|
||||
}
|
||||
|
||||
@@ -173,11 +188,12 @@ impl<C: Components> StartRPC<Self> for C where
|
||||
rpc_system_info: SystemInfo,
|
||||
task_executor: TaskExecutor,
|
||||
transaction_pool: Arc<TransactionPool<C::TransactionPoolApi>>,
|
||||
keystore: KeyStorePtr,
|
||||
) -> rpc::RpcHandler {
|
||||
let subscriptions = rpc::apis::Subscriptions::new(task_executor.clone());
|
||||
let chain = rpc::apis::chain::Chain::new(client.clone(), subscriptions.clone());
|
||||
let state = rpc::apis::state::State::new(client.clone(), subscriptions.clone());
|
||||
let author = rpc::apis::author::Author::new(client, transaction_pool, subscriptions);
|
||||
let author = rpc::apis::author::Author::new(client, transaction_pool, subscriptions, keystore);
|
||||
let system = rpc::apis::system::System::new(rpc_system_info, system_send_back);
|
||||
rpc::rpc_handler::<ComponentBlock<C>, ComponentExHash<C>, _, _, _, _>(
|
||||
state,
|
||||
@@ -242,7 +258,6 @@ pub trait OffchainWorker<C: Components> {
|
||||
offchain: &offchain::OffchainWorkers<
|
||||
ComponentClient<C>,
|
||||
ComponentOffchainStorage<C>,
|
||||
ComponentAuthorityKeyProvider<C>,
|
||||
ComponentBlock<C>
|
||||
>,
|
||||
pool: &Arc<TransactionPool<C::TransactionPoolApi>>,
|
||||
@@ -259,7 +274,6 @@ impl<C: Components> OffchainWorker<Self> for C where
|
||||
offchain: &offchain::OffchainWorkers<
|
||||
ComponentClient<C>,
|
||||
ComponentOffchainStorage<C>,
|
||||
ComponentAuthorityKeyProvider<C>,
|
||||
ComponentBlock<C>
|
||||
>,
|
||||
pool: &Arc<TransactionPool<C::TransactionPoolApi>>,
|
||||
@@ -277,6 +291,7 @@ pub trait ServiceTrait<C: Components>:
|
||||
+ StartRPC<C>
|
||||
+ MaintainTransactionPool<C>
|
||||
+ OffchainWorker<C>
|
||||
+ InitialSessionKeys<C>
|
||||
{}
|
||||
impl<C: Components, T> ServiceTrait<C> for T where
|
||||
T: Deref<Target = Service<C>>
|
||||
@@ -285,6 +300,7 @@ impl<C: Components, T> ServiceTrait<C> for T where
|
||||
+ StartRPC<C>
|
||||
+ MaintainTransactionPool<C>
|
||||
+ OffchainWorker<C>
|
||||
+ InitialSessionKeys<C>
|
||||
{}
|
||||
|
||||
/// Alias for a an implementation of `futures::future::Executor`.
|
||||
@@ -294,10 +310,6 @@ pub type TaskExecutor = Arc<dyn Executor<Box<dyn Future<Item = (), Error = ()> +
|
||||
pub trait ServiceFactory: 'static + Sized {
|
||||
/// Block type.
|
||||
type Block: BlockT<Hash=H256>;
|
||||
/// Consensus crypto type.
|
||||
type ConsensusPair: Pair;
|
||||
/// Finality crypto type.
|
||||
type FinalityPair: Pair;
|
||||
/// The type that implements the runtime API.
|
||||
type RuntimeApi: Send + Sync;
|
||||
/// Network protocol extensions.
|
||||
@@ -412,6 +424,7 @@ pub trait Components: Sized + 'static {
|
||||
fn build_client(
|
||||
config: &FactoryFullConfiguration<Self::Factory>,
|
||||
executor: CodeExecutor<Self::Factory>,
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
) -> Result<
|
||||
(
|
||||
Arc<ComponentClient<Self>>,
|
||||
@@ -498,11 +511,11 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
|
||||
fn build_client(
|
||||
config: &FactoryFullConfiguration<Factory>,
|
||||
executor: CodeExecutor<Self::Factory>,
|
||||
)
|
||||
-> Result<(
|
||||
Arc<ComponentClient<Self>>,
|
||||
Option<Arc<OnDemand<FactoryBlock<Self::Factory>>>>
|
||||
), error::Error>
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
) -> Result<
|
||||
(Arc<ComponentClient<Self>>, Option<Arc<OnDemand<FactoryBlock<Self::Factory>>>>),
|
||||
error::Error,
|
||||
>
|
||||
{
|
||||
let db_settings = client_db::DatabaseSettings {
|
||||
cache_size: config.database_cache_size.map(|u| u as usize),
|
||||
@@ -512,12 +525,19 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
|
||||
path: config.database_path.clone(),
|
||||
pruning: config.pruning.clone(),
|
||||
};
|
||||
Ok((Arc::new(client_db::new_client(
|
||||
db_settings,
|
||||
executor,
|
||||
&config.chain_spec,
|
||||
config.execution_strategies.clone(),
|
||||
)?), None))
|
||||
|
||||
Ok((
|
||||
Arc::new(
|
||||
client_db::new_client(
|
||||
db_settings,
|
||||
executor,
|
||||
&config.chain_spec,
|
||||
config.execution_strategies.clone(),
|
||||
keystore,
|
||||
)?
|
||||
),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
||||
fn build_transaction_pool(
|
||||
@@ -600,6 +620,7 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory> {
|
||||
fn build_client(
|
||||
config: &FactoryFullConfiguration<Factory>,
|
||||
executor: CodeExecutor<Self::Factory>,
|
||||
_: Option<BareCryptoStorePtr>,
|
||||
)
|
||||
-> Result<
|
||||
(
|
||||
@@ -615,9 +636,12 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory> {
|
||||
path: config.database_path.clone(),
|
||||
pruning: config.pruning.clone(),
|
||||
};
|
||||
|
||||
let db_storage = client_db::light::LightStorage::new(db_settings)?;
|
||||
let light_blockchain = client::light::new_light_blockchain(db_storage);
|
||||
let fetch_checker = Arc::new(client::light::new_fetch_checker(light_blockchain.clone(), executor.clone()));
|
||||
let fetch_checker = Arc::new(
|
||||
client::light::new_fetch_checker(light_blockchain.clone(), executor.clone())
|
||||
);
|
||||
let fetcher = Arc::new(network::OnDemand::new(fetch_checker));
|
||||
let client_backend = client::light::new_light_backend(light_blockchain, fetcher.clone());
|
||||
let client = client::light::new_light(client_backend, fetcher.clone(), &config.chain_spec, executor)?;
|
||||
|
||||
@@ -31,7 +31,7 @@ use tel::TelemetryEndpoints;
|
||||
|
||||
/// Service configuration.
|
||||
#[derive(Clone)]
|
||||
pub struct Configuration<C, G: Serialize + DeserializeOwned + BuildStorage> {
|
||||
pub struct Configuration<C, G> {
|
||||
/// Implementation name
|
||||
pub impl_name: &'static str,
|
||||
/// Implementation version
|
||||
@@ -45,7 +45,7 @@ pub struct Configuration<C, G: Serialize + DeserializeOwned + BuildStorage> {
|
||||
/// Network configuration.
|
||||
pub network: NetworkConfiguration,
|
||||
/// Path to key files.
|
||||
pub keystore_path: Option<PathBuf>,
|
||||
pub keystore_path: PathBuf,
|
||||
/// Path to the database.
|
||||
pub database_path: PathBuf,
|
||||
/// Cache Size for internal database in MiB
|
||||
@@ -56,8 +56,6 @@ pub struct Configuration<C, G: Serialize + DeserializeOwned + BuildStorage> {
|
||||
pub state_cache_child_ratio: Option<usize>,
|
||||
/// Pruning settings.
|
||||
pub pruning: PruningMode,
|
||||
/// Additional key seeds.
|
||||
pub keys: Vec<String>,
|
||||
/// Chain configuration.
|
||||
pub chain_spec: ChainSpec<G>,
|
||||
/// Custom configuration.
|
||||
@@ -91,7 +89,13 @@ pub struct Configuration<C, G: Serialize + DeserializeOwned + BuildStorage> {
|
||||
/// running a sentry node in front of a validator, thus needing to forward GRANDPA gossip messages.
|
||||
pub grandpa_voter: bool,
|
||||
/// Node keystore's password
|
||||
pub password: Protected<String>,
|
||||
pub keystore_password: Option<Protected<String>>,
|
||||
/// Development key seed.
|
||||
///
|
||||
/// When running in development mode, the seed will be used to generate authority keys by the keystore.
|
||||
///
|
||||
/// Should only be set when `node` is running development mode.
|
||||
pub dev_key_seed: Option<String>,
|
||||
}
|
||||
|
||||
impl<C: Default, G: Serialize + DeserializeOwned + BuildStorage> Configuration<C, G> {
|
||||
@@ -111,7 +115,6 @@ impl<C: Default, G: Serialize + DeserializeOwned + BuildStorage> Configuration<C
|
||||
database_cache_size: Default::default(),
|
||||
state_cache_size: Default::default(),
|
||||
state_cache_child_ratio: Default::default(),
|
||||
keys: Default::default(),
|
||||
custom: Default::default(),
|
||||
pruning: PruningMode::default(),
|
||||
execution_strategies: Default::default(),
|
||||
@@ -126,7 +129,8 @@ impl<C: Default, G: Serialize + DeserializeOwned + BuildStorage> Configuration<C
|
||||
force_authoring: false,
|
||||
disable_grandpa: false,
|
||||
grandpa_voter: false,
|
||||
password: "".to_string().into(),
|
||||
keystore_password: None,
|
||||
dev_key_seed: None,
|
||||
};
|
||||
configuration.network.boot_nodes = configuration.chain_spec.boot_nodes().to_vec();
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ pub mod chain_ops;
|
||||
pub mod error;
|
||||
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::collections::HashMap;
|
||||
use std::time::{Duration, Instant};
|
||||
@@ -41,9 +40,8 @@ use keystore::Store as Keystore;
|
||||
use network::{NetworkState, NetworkStateInfo};
|
||||
use log::{log, info, warn, debug, error, Level};
|
||||
use codec::{Encode, Decode};
|
||||
use primitives::{Pair, ed25519, sr25519, crypto};
|
||||
use sr_primitives::generic::BlockId;
|
||||
use sr_primitives::traits::{Header, NumberFor, SaturatedConversion, Zero};
|
||||
use sr_primitives::traits::{Header, NumberFor, SaturatedConversion};
|
||||
use substrate_executor::NativeExecutor;
|
||||
use sysinfo::{get_current_pid, ProcessExt, System, SystemExt};
|
||||
use tel::{telemetry, SUBSTRATE_INFO};
|
||||
@@ -57,13 +55,12 @@ pub use transaction_pool::txpool::{
|
||||
pub use client::FinalityNotifications;
|
||||
|
||||
pub use components::{
|
||||
ServiceFactory, FullBackend, FullExecutor, LightBackend, ComponentAuthorityKeyProvider,
|
||||
ServiceFactory, FullBackend, FullExecutor, LightBackend,
|
||||
LightExecutor, Components, PoolApi, ComponentClient, ComponentOffchainStorage,
|
||||
ComponentBlock, FullClient, LightClient, FullComponents, LightComponents,
|
||||
CodeExecutor, NetworkService, FactoryChainSpec, FactoryBlock,
|
||||
FactoryFullConfiguration, RuntimeGenesis, FactoryGenesis,
|
||||
ComponentExHash, ComponentExtrinsic, FactoryExtrinsic,
|
||||
ComponentConsensusPair, ComponentFinalityPair,
|
||||
ComponentExHash, ComponentExtrinsic, FactoryExtrinsic, InitialSessionKeys,
|
||||
};
|
||||
use components::{StartRPC, MaintainTransactionPool, OffchainWorker};
|
||||
#[doc(hidden)]
|
||||
@@ -85,8 +82,7 @@ pub struct Service<Components: components::Components> {
|
||||
NetworkStatus<ComponentBlock<Components>>, NetworkState
|
||||
)>>>>,
|
||||
transaction_pool: Arc<TransactionPool<Components::TransactionPoolApi>>,
|
||||
keystore: ComponentAuthorityKeyProvider<Components>,
|
||||
exit: ::exit_future::Exit,
|
||||
exit: exit_future::Exit,
|
||||
signal: Option<Signal>,
|
||||
/// Sender for futures that must be spawned as background tasks.
|
||||
to_spawn_tx: mpsc::UnboundedSender<Box<dyn Future<Item = (), Error = ()> + Send>>,
|
||||
@@ -105,21 +101,22 @@ pub struct Service<Components: components::Components> {
|
||||
_offchain_workers: Option<Arc<offchain::OffchainWorkers<
|
||||
ComponentClient<Components>,
|
||||
ComponentOffchainStorage<Components>,
|
||||
ComponentAuthorityKeyProvider<Components>,
|
||||
ComponentBlock<Components>>
|
||||
>>,
|
||||
keystore: keystore::KeyStorePtr,
|
||||
}
|
||||
|
||||
/// Creates bare client without any networking.
|
||||
pub fn new_client<Factory: components::ServiceFactory>(config: &FactoryFullConfiguration<Factory>)
|
||||
-> Result<Arc<ComponentClient<components::FullComponents<Factory>>>, error::Error>
|
||||
{
|
||||
pub fn new_client<Factory: components::ServiceFactory>(
|
||||
config: &FactoryFullConfiguration<Factory>,
|
||||
) -> Result<Arc<ComponentClient<components::FullComponents<Factory>>>, error::Error> {
|
||||
let executor = NativeExecutor::new(config.default_heap_pages);
|
||||
let (client, _) = components::FullComponents::<Factory>::build_client(
|
||||
|
||||
components::FullComponents::<Factory>::build_client(
|
||||
config,
|
||||
executor,
|
||||
)?;
|
||||
Ok(client)
|
||||
None,
|
||||
).map(|r| r.0)
|
||||
}
|
||||
|
||||
/// An handle for spawning tasks in the service.
|
||||
@@ -172,43 +169,9 @@ impl<Components: components::Components> Service<Components> {
|
||||
// Create client
|
||||
let executor = NativeExecutor::new(config.default_heap_pages);
|
||||
|
||||
let mut keystore = if let Some(keystore_path) = config.keystore_path.as_ref() {
|
||||
match Keystore::open(keystore_path.clone()) {
|
||||
Ok(ks) => Some(ks),
|
||||
Err(err) => {
|
||||
error!("Failed to initialize keystore: {}", err);
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let keystore = Keystore::open(config.keystore_path.clone(), config.keystore_password.clone())?;
|
||||
|
||||
// Keep the public key for telemetry
|
||||
let public_key: String;
|
||||
|
||||
// This is meant to be for testing only
|
||||
// FIXME #1063 remove this
|
||||
if let Some(keystore) = keystore.as_mut() {
|
||||
for seed in &config.keys {
|
||||
keystore.generate_from_seed::<ed25519::Pair>(seed)?;
|
||||
keystore.generate_from_seed::<sr25519::Pair>(seed)?;
|
||||
}
|
||||
|
||||
public_key = match keystore.contents::<ed25519::Public>()?.get(0) {
|
||||
Some(public_key) => public_key.to_string(),
|
||||
None => {
|
||||
let key: ed25519::Pair = keystore.generate(&config.password.as_ref())?;
|
||||
let public_key = key.public();
|
||||
info!("Generated a new keypair: {:?}", public_key);
|
||||
public_key.to_string()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
public_key = format!("<disabled-keystore>");
|
||||
}
|
||||
|
||||
let (client, on_demand) = Components::build_client(&config, executor)?;
|
||||
let (client, on_demand) = Components::build_client(&config, executor, Some(keystore.clone()))?;
|
||||
let select_chain = Components::build_select_chain(&mut config, client.clone())?;
|
||||
let (import_queue, finality_proof_request_builder) = Components::build_import_queue(
|
||||
&mut config,
|
||||
@@ -219,9 +182,16 @@ impl<Components: components::Components> Service<Components> {
|
||||
let finality_proof_provider = Components::build_finality_proof_provider(client.clone())?;
|
||||
let chain_info = client.info().chain;
|
||||
|
||||
Components::RuntimeServices::generate_intial_session_keys(
|
||||
client.clone(),
|
||||
config.dev_key_seed.clone().map(|s| vec![s]).unwrap_or_default(),
|
||||
)?;
|
||||
|
||||
let version = config.full_version();
|
||||
info!("Highest known block at #{}", chain_info.best_number);
|
||||
telemetry!(SUBSTRATE_INFO; "node.start";
|
||||
telemetry!(
|
||||
SUBSTRATE_INFO;
|
||||
"node.start";
|
||||
"height" => chain_info.best_number.saturated_into::<u64>(),
|
||||
"best" => ?chain_info.best_hash
|
||||
);
|
||||
@@ -234,7 +204,7 @@ impl<Components: components::Components> Service<Components> {
|
||||
imports_external_transactions: !config.roles.is_light(),
|
||||
pool: transaction_pool.clone(),
|
||||
client: client.clone(),
|
||||
});
|
||||
});
|
||||
|
||||
let protocol_id = {
|
||||
let protocol_id_full = match config.chain_spec.protocol_id() {
|
||||
@@ -267,23 +237,11 @@ impl<Components: components::Components> Service<Components> {
|
||||
let network = network_mut.service().clone();
|
||||
let network_status_sinks = Arc::new(Mutex::new(Vec::new()));
|
||||
|
||||
let keystore_authority_key = AuthorityKeyProvider {
|
||||
_marker: PhantomData,
|
||||
roles: config.roles,
|
||||
password: config.password.clone(),
|
||||
keystore: keystore.map(Arc::new),
|
||||
};
|
||||
|
||||
#[allow(deprecated)]
|
||||
let offchain_storage = client.backend().offchain_storage();
|
||||
let offchain_workers = match (config.offchain_worker, offchain_storage) {
|
||||
(true, Some(db)) => {
|
||||
Some(Arc::new(offchain::OffchainWorkers::new(
|
||||
client.clone(),
|
||||
db,
|
||||
keystore_authority_key.clone(),
|
||||
config.password.clone(),
|
||||
)))
|
||||
Some(Arc::new(offchain::OffchainWorkers::new(client.clone(), db)))
|
||||
},
|
||||
(true, None) => {
|
||||
log::warn!("Offchain workers disabled, due to lack of offchain storage support in backend.");
|
||||
@@ -421,6 +379,7 @@ impl<Components: components::Components> Service<Components> {
|
||||
system_info.clone(),
|
||||
Arc::new(SpawnTaskHandle { sender: to_spawn_tx.clone() }),
|
||||
transaction_pool.clone(),
|
||||
keystore.clone(),
|
||||
)
|
||||
};
|
||||
let rpc_handlers = gen_handler();
|
||||
@@ -465,7 +424,6 @@ impl<Components: components::Components> Service<Components> {
|
||||
"version" => version.clone(),
|
||||
"config" => "",
|
||||
"chain" => chain_name.clone(),
|
||||
"pubkey" => &public_key,
|
||||
"authority" => is_authority,
|
||||
"network_id" => network_id.clone()
|
||||
);
|
||||
@@ -491,7 +449,6 @@ impl<Components: components::Components> Service<Components> {
|
||||
to_spawn_tx,
|
||||
to_spawn_rx,
|
||||
to_poll: Vec::new(),
|
||||
keystore: keystore_authority_key,
|
||||
config,
|
||||
exit,
|
||||
rpc_handlers,
|
||||
@@ -499,28 +456,20 @@ impl<Components: components::Components> Service<Components> {
|
||||
_telemetry: telemetry,
|
||||
_offchain_workers: offchain_workers,
|
||||
_telemetry_on_connect_sinks: telemetry_connection_sinks.clone(),
|
||||
keystore,
|
||||
})
|
||||
}
|
||||
|
||||
/// give the authority key, if we are an authority and have a key
|
||||
pub fn authority_key(&self) -> Option<ComponentConsensusPair<Components>> {
|
||||
use offchain::AuthorityKeyProvider;
|
||||
|
||||
self.keystore.authority_key(&BlockId::Number(Zero::zero()))
|
||||
}
|
||||
|
||||
/// give the authority key, if we are an authority and have a key
|
||||
pub fn fg_authority_key(&self) -> Option<ComponentFinalityPair<Components>> {
|
||||
use offchain::AuthorityKeyProvider;
|
||||
|
||||
self.keystore.fg_authority_key(&BlockId::Number(Zero::zero()))
|
||||
}
|
||||
|
||||
/// return a shared instance of Telemetry (if enabled)
|
||||
/// Return a shared instance of Telemetry (if enabled)
|
||||
pub fn telemetry(&self) -> Option<tel::Telemetry> {
|
||||
self._telemetry.as_ref().map(|t| t.clone())
|
||||
}
|
||||
|
||||
/// Returns the keystore instance.
|
||||
pub fn keystore(&self) -> keystore::KeyStorePtr {
|
||||
self.keystore.clone()
|
||||
}
|
||||
|
||||
/// Spawns a task in the background that runs the future passed as parameter.
|
||||
pub fn spawn_task(&self, task: impl Future<Item = (), Error = ()> + Send + 'static) {
|
||||
let _ = self.to_spawn_tx.unbounded_send(Box::new(task));
|
||||
@@ -910,73 +859,6 @@ impl<C: Components> network::TransactionPool<ComponentExHash<C>, ComponentBlock<
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
/// A provider of current authority key.
|
||||
pub struct AuthorityKeyProvider<Block, ConsensusPair, FinalityPair> {
|
||||
_marker: PhantomData<(Block, ConsensusPair, FinalityPair)>,
|
||||
roles: Roles,
|
||||
keystore: Option<Arc<Keystore>>,
|
||||
password: crypto::Protected<String>,
|
||||
}
|
||||
|
||||
impl<Block, ConsensusPair, FinalityPair>
|
||||
offchain::AuthorityKeyProvider<Block>
|
||||
for AuthorityKeyProvider<Block, ConsensusPair, FinalityPair>
|
||||
where
|
||||
Block: sr_primitives::traits::Block,
|
||||
ConsensusPair: Pair,
|
||||
FinalityPair: Pair,
|
||||
{
|
||||
type ConsensusPair = ConsensusPair;
|
||||
type FinalityPair = FinalityPair;
|
||||
|
||||
fn authority_key(&self, _at: &BlockId<Block>) -> Option<Self::ConsensusPair> {
|
||||
if self.roles != Roles::AUTHORITY {
|
||||
return None
|
||||
}
|
||||
|
||||
let keystore = match self.keystore {
|
||||
Some(ref keystore) => keystore,
|
||||
None => return None
|
||||
};
|
||||
|
||||
let loaded_key = keystore
|
||||
.contents()
|
||||
.map(|keys| keys.get(0)
|
||||
.map(|k| keystore.load(k, self.password.as_ref()))
|
||||
);
|
||||
|
||||
if let Ok(Some(Ok(key))) = loaded_key {
|
||||
Some(key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn fg_authority_key(&self, _at: &BlockId<Block>) -> Option<Self::FinalityPair> {
|
||||
if self.roles != Roles::AUTHORITY {
|
||||
return None
|
||||
}
|
||||
|
||||
let keystore = match self.keystore {
|
||||
Some(ref keystore) => keystore,
|
||||
None => return None
|
||||
};
|
||||
|
||||
let loaded_key = keystore
|
||||
.contents()
|
||||
.map(|keys| keys.get(0)
|
||||
.map(|k| keystore.load(k, self.password.as_ref()))
|
||||
);
|
||||
|
||||
if let Ok(Some(Ok(key))) = loaded_key {
|
||||
Some(key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a service factory with the given name that implements the `ServiceFactory` trait.
|
||||
/// The required parameters are required to be given in the exact order. Some parameters are followed
|
||||
/// by `{}` blocks. These blocks are required and used to initialize the given parameter.
|
||||
@@ -998,6 +880,8 @@ where
|
||||
/// # use node_runtime::{GenesisConfig, RuntimeApi};
|
||||
/// # use std::sync::Arc;
|
||||
/// # use node_primitives::Block;
|
||||
/// # use babe_primitives::AuthorityPair as BabePair;
|
||||
/// # use grandpa_primitives::AuthorityPair as GrandpaPair;
|
||||
/// # use sr_primitives::Justification;
|
||||
/// # use sr_primitives::traits::Block as BlockT;
|
||||
/// # use grandpa;
|
||||
@@ -1025,8 +909,6 @@ where
|
||||
/// struct Factory {
|
||||
/// // Declare the block type
|
||||
/// Block = Block,
|
||||
/// ConsensusPair = primitives::ed25519::Pair,
|
||||
/// FinalityPair = primitives::ed25519::Pair,
|
||||
/// RuntimeApi = RuntimeApi,
|
||||
/// // Declare the network protocol and give an initializer.
|
||||
/// NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) },
|
||||
@@ -1070,8 +952,6 @@ macro_rules! construct_service_factory {
|
||||
$(#[$attr:meta])*
|
||||
struct $name:ident {
|
||||
Block = $block:ty,
|
||||
ConsensusPair = $consensus_pair:ty,
|
||||
FinalityPair = $finality_pair:ty,
|
||||
RuntimeApi = $runtime_api:ty,
|
||||
NetworkProtocol = $protocol:ty { $( $protocol_init:tt )* },
|
||||
RuntimeDispatch = $dispatch:ty,
|
||||
@@ -1097,8 +977,6 @@ macro_rules! construct_service_factory {
|
||||
#[allow(unused_variables)]
|
||||
impl $crate::ServiceFactory for $name {
|
||||
type Block = $block;
|
||||
type ConsensusPair = $consensus_pair;
|
||||
type FinalityPair = $finality_pair;
|
||||
type RuntimeApi = $runtime_api;
|
||||
type NetworkProtocol = $protocol;
|
||||
type RuntimeDispatch = $dispatch;
|
||||
|
||||
@@ -135,10 +135,6 @@ fn node_config<F: ServiceFactory> (
|
||||
) -> FactoryFullConfiguration<F>
|
||||
{
|
||||
let root = root.path().join(format!("node-{}", index));
|
||||
let mut keys = Vec::new();
|
||||
if let Some(seed) = key_seed {
|
||||
keys.push(seed);
|
||||
}
|
||||
|
||||
let config_path = Some(String::from(root.join("network").to_str().unwrap()));
|
||||
let net_config_path = config_path.clone();
|
||||
@@ -173,13 +169,13 @@ fn node_config<F: ServiceFactory> (
|
||||
roles: role,
|
||||
transaction_pool: Default::default(),
|
||||
network: network_config,
|
||||
keystore_path: Some(root.join("key")),
|
||||
keystore_path: root.join("key"),
|
||||
keystore_password: None,
|
||||
database_path: root.join("db"),
|
||||
database_cache_size: None,
|
||||
state_cache_size: 16777216,
|
||||
state_cache_child_ratio: None,
|
||||
pruning: Default::default(),
|
||||
keys: keys,
|
||||
chain_spec: (*spec).clone(),
|
||||
custom: Default::default(),
|
||||
name: format!("Node {}", index),
|
||||
@@ -195,7 +191,7 @@ fn node_config<F: ServiceFactory> (
|
||||
force_authoring: false,
|
||||
disable_grandpa: false,
|
||||
grandpa_voter: false,
|
||||
password: "".to_string().into(),
|
||||
dev_key_seed: key_seed,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "substrate-session"
|
||||
version = "2.0.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
client = { package = "substrate-client", path = "../client", default-features = false }
|
||||
rstd = { package = "sr-std", path = "../sr-std", default-features = false }
|
||||
sr-primitives = { path = "../sr-primitives", optional = true }
|
||||
primitives = { package = "substrate-primitives", path = "../primitives", optional = true }
|
||||
|
||||
[features]
|
||||
default = [ "std" ]
|
||||
std = [ "client/std", "rstd/std", "sr-primitives", "primitives" ]
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate core types around sessions.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use rstd::vec::Vec;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use sr_primitives::traits::{ProvideRuntimeApi, Block as BlockT};
|
||||
#[cfg(feature = "std")]
|
||||
use primitives::{H256, Blake2Hasher};
|
||||
|
||||
client::decl_runtime_apis! {
|
||||
/// Session keys runtime api.
|
||||
pub trait SessionKeys {
|
||||
/// Generate a set of session keys with optionally using the given seed.
|
||||
///
|
||||
/// The seed needs to be a valid `utf8` string.
|
||||
///
|
||||
/// Returns the concatenated SCALE encoded public keys.
|
||||
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8>;
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the initial session keys with the given seeds.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn generate_initial_session_keys<B, E, Block, RA>(
|
||||
client: std::sync::Arc<client::Client<B, E, Block, RA>>,
|
||||
seeds: Vec<String>,
|
||||
) -> Result<(), client::error::Error>
|
||||
where
|
||||
B: client::backend::Backend<Block, Blake2Hasher>,
|
||||
E: client::CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT<Hash=H256>,
|
||||
client::Client<B, E, Block, RA>: ProvideRuntimeApi,
|
||||
<client::Client<B, E, Block, RA> as ProvideRuntimeApi>::Api: SessionKeys<Block>,
|
||||
{
|
||||
let info = client.info().chain;
|
||||
let runtime_api = client.runtime_api();
|
||||
|
||||
for seed in seeds {
|
||||
runtime_api.generate_session_keys(
|
||||
&sr_primitives::generic::BlockId::Number(info.best_number),
|
||||
Some(seed.as_bytes().to_vec()),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -190,5 +190,6 @@ fn record_proof_works() {
|
||||
&executor,
|
||||
"Core_execute_block",
|
||||
&block.encode(),
|
||||
None,
|
||||
).expect("Executes block while using the proof backend");
|
||||
}
|
||||
|
||||
@@ -33,12 +33,11 @@ use rstd::vec::Vec;
|
||||
pub use codec;
|
||||
|
||||
pub use primitives::Blake2Hasher;
|
||||
use primitives::offchain::{
|
||||
Timestamp,
|
||||
HttpRequestId, HttpRequestStatus, HttpError,
|
||||
CryptoKind, CryptoKey,
|
||||
StorageKind,
|
||||
OpaqueNetworkState,
|
||||
use primitives::{
|
||||
crypto::KeyTypeId, ed25519, sr25519,
|
||||
offchain::{
|
||||
Timestamp, HttpRequestId, HttpRequestStatus, HttpError, StorageKind, OpaqueNetworkState,
|
||||
},
|
||||
};
|
||||
|
||||
/// Error verifying ECDSA signature
|
||||
@@ -69,7 +68,7 @@ macro_rules! export_api {
|
||||
$( #[$attr:meta] )*
|
||||
fn $name:ident
|
||||
$(< $( $g_name:ident $( : $g_ty:path )? ),+ >)?
|
||||
( $( $arg:ident : $arg_ty:ty ),* )
|
||||
( $( $arg:ident : $arg_ty:ty ),* $(,)? )
|
||||
$( -> $ret:ty )?
|
||||
$( where $( $w_name:path : $w_ty:path ),+ )?;
|
||||
)*
|
||||
@@ -200,11 +199,45 @@ export_api! {
|
||||
|
||||
export_api! {
|
||||
pub(crate) trait CryptoApi {
|
||||
/// Verify a ed25519 signature.
|
||||
fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool;
|
||||
/// Returns all ed25519 public keys for the given key id from the keystore.
|
||||
fn ed25519_public_keys(id: KeyTypeId) -> Vec<ed25519::Public>;
|
||||
/// Generate an ed22519 key for the given key type and store it in the keystore.
|
||||
///
|
||||
/// Returns the raw public key.
|
||||
fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> ed25519::Public;
|
||||
/// Sign the given `msg` with the ed25519 key that corresponds to the given public key and
|
||||
/// key type in the keystore.
|
||||
///
|
||||
/// Returns the raw signature.
|
||||
fn ed25519_sign<M: AsRef<[u8]>>(
|
||||
id: KeyTypeId,
|
||||
pubkey: &ed25519::Public,
|
||||
msg: &M,
|
||||
) -> Option<ed25519::Signature>;
|
||||
/// Verify an ed25519 signature.
|
||||
///
|
||||
/// Returns `true` when the verification in successful.
|
||||
fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pubkey: &ed25519::Public) -> bool;
|
||||
|
||||
/// Returns all sr25519 public keys for the given key id from the keystore.
|
||||
fn sr25519_public_keys(id: KeyTypeId) -> Vec<sr25519::Public>;
|
||||
/// Generate an sr22519 key for the given key type and store it in the keystore.
|
||||
///
|
||||
/// Returns the raw public key.
|
||||
fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> sr25519::Public;
|
||||
/// Sign the given `msg` with the sr25519 key that corresponds to the given public key and
|
||||
/// key type in the keystore.
|
||||
///
|
||||
/// Returns the raw signature.
|
||||
fn sr25519_sign<M: AsRef<[u8]>>(
|
||||
id: KeyTypeId,
|
||||
pubkey: &sr25519::Public,
|
||||
msg: &M,
|
||||
) -> Option<sr25519::Signature>;
|
||||
/// Verify an sr25519 signature.
|
||||
fn sr25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool;
|
||||
///
|
||||
/// Returns `true` when the verification in successful.
|
||||
fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pubkey: &sr25519::Public) -> bool;
|
||||
|
||||
/// Verify and recover a SECP256k1 ECDSA signature.
|
||||
/// - `sig` is passed in RSV format. V should be either 0/1 or 27/28.
|
||||
@@ -245,42 +278,6 @@ export_api! {
|
||||
/// Returns information about the local node's network state.
|
||||
fn network_state() -> Result<OpaqueNetworkState, ()>;
|
||||
|
||||
/// Returns the currently configured authority public key, if available.
|
||||
fn pubkey(key: CryptoKey) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Create new key(pair) for signing/encryption/decryption.
|
||||
///
|
||||
/// Returns an error if given crypto kind is not supported.
|
||||
fn new_crypto_key(crypto: CryptoKind) -> Result<CryptoKey, ()>;
|
||||
|
||||
/// Encrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist.
|
||||
fn encrypt(key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Decrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key.
|
||||
///
|
||||
/// Returns an error if data cannot be decrypted or the `key` is not available or does not exist.
|
||||
fn decrypt(key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Sign a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist.
|
||||
fn sign(key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Verifies that `signature` for `msg` matches given `key`.
|
||||
///
|
||||
/// Returns an `Ok` with `true` in case it does, `false` in case it doesn't.
|
||||
/// Returns an error in case the key is not available or does not exist or the parameters
|
||||
/// lengths are incorrect.
|
||||
fn verify(key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result<bool, ()>;
|
||||
|
||||
/// Returns current UNIX timestamp (in millis)
|
||||
fn timestamp() -> Timestamp;
|
||||
|
||||
|
||||
@@ -15,24 +15,19 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use primitives::{
|
||||
blake2_128, blake2_256, twox_128, twox_256, twox_64, ed25519, Blake2Hasher,
|
||||
sr25519, Pair
|
||||
blake2_128, blake2_256, twox_128, twox_256, twox_64, ed25519, Blake2Hasher, sr25519, Pair,
|
||||
};
|
||||
// Switch to this after PoC-3
|
||||
// pub use primitives::BlakeHasher;
|
||||
pub use substrate_state_machine::{
|
||||
Externalities,
|
||||
BasicExternalities,
|
||||
TestExternalities,
|
||||
ChildStorageKey
|
||||
Externalities, BasicExternalities, TestExternalities, ChildStorageKey,
|
||||
};
|
||||
|
||||
use environmental::environmental;
|
||||
use primitives::{offchain, hexdisplay::HexDisplay, H256};
|
||||
use trie::{TrieConfiguration, trie_types::Layout};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, convert::TryFrom};
|
||||
|
||||
environmental!(ext: trait Externalities<Blake2Hasher>);
|
||||
|
||||
@@ -208,12 +203,82 @@ impl OtherApi for () {
|
||||
}
|
||||
|
||||
impl CryptoApi for () {
|
||||
fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
|
||||
ed25519::Pair::verify_weak(sig, msg, pubkey)
|
||||
fn ed25519_public_keys(id: KeyTypeId) -> Vec<ed25519::Public> {
|
||||
ext::with(|ext| {
|
||||
ext.keystore()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.write()
|
||||
.ed25519_public_keys(id)
|
||||
}).expect("`ed25519_public_keys` cannot be called outside of an Externalities-provided environment.")
|
||||
}
|
||||
|
||||
fn sr25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
|
||||
sr25519::Pair::verify_weak(sig, msg, pubkey)
|
||||
fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> ed25519::Public {
|
||||
ext::with(|ext| {
|
||||
ext.keystore()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.write()
|
||||
.ed25519_generate_new(id, seed)
|
||||
.expect("`ed25519_generate` failed")
|
||||
}).expect("`ed25519_generate` cannot be called outside of an Externalities-provided environment.")
|
||||
}
|
||||
|
||||
fn ed25519_sign<M: AsRef<[u8]>>(
|
||||
id: KeyTypeId,
|
||||
pubkey: &ed25519::Public,
|
||||
msg: &M,
|
||||
) -> Option<ed25519::Signature> {
|
||||
let pub_key = ed25519::Public::try_from(pubkey.as_ref()).ok()?;
|
||||
|
||||
ext::with(|ext| {
|
||||
ext.keystore()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.read()
|
||||
.ed25519_key_pair(id, &pub_key)
|
||||
.map(|k| k.sign(msg.as_ref()).into())
|
||||
}).expect("`ed25519_sign` cannot be called outside of an Externalities-provided environment.")
|
||||
}
|
||||
|
||||
fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pubkey: &ed25519::Public) -> bool {
|
||||
ed25519::Pair::verify(sig, msg, pubkey)
|
||||
}
|
||||
|
||||
fn sr25519_public_keys(id: KeyTypeId) -> Vec<sr25519::Public> {
|
||||
ext::with(|ext| {
|
||||
ext.keystore()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.write()
|
||||
.sr25519_public_keys(id)
|
||||
}).expect("`sr25519_public_keys` cannot be called outside of an Externalities-provided environment.")
|
||||
}
|
||||
|
||||
fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> sr25519::Public {
|
||||
ext::with(|ext| {
|
||||
ext.keystore()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.write()
|
||||
.sr25519_generate_new(id, seed)
|
||||
.expect("`sr25519_generate` failed")
|
||||
}).expect("`sr25519_generate` cannot be called outside of an Externalities-provided environment.")
|
||||
}
|
||||
|
||||
fn sr25519_sign<M: AsRef<[u8]>>(
|
||||
id: KeyTypeId,
|
||||
pubkey: &sr25519::Public,
|
||||
msg: &M,
|
||||
) -> Option<sr25519::Signature> {
|
||||
let pub_key = sr25519::Public::try_from(pubkey.as_ref()).ok()?;
|
||||
|
||||
ext::with(|ext| {
|
||||
ext.keystore()
|
||||
.expect("No `keystore` associated for the current context!")
|
||||
.read()
|
||||
.sr25519_key_pair(id, &pub_key)
|
||||
.map(|k| k.sign(msg.as_ref()).into())
|
||||
}).expect("`sr25519_sign` cannot be called outside of an Externalities-provided environment.")
|
||||
}
|
||||
|
||||
fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pubkey: &sr25519::Public) -> bool {
|
||||
sr25519::Pair::verify(sig, msg, pubkey)
|
||||
}
|
||||
|
||||
fn secp256k1_ecdsa_recover(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 64], EcdsaVerifyError> {
|
||||
@@ -276,55 +341,6 @@ impl OffchainApi for () {
|
||||
}, "network_state can be called only in the offchain worker context")
|
||||
}
|
||||
|
||||
fn pubkey(key: offchain::CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
with_offchain(|ext| {
|
||||
ext.pubkey(key)
|
||||
}, "authority_pubkey can be called only in the offchain worker context")
|
||||
}
|
||||
|
||||
fn new_crypto_key(crypto: offchain::CryptoKind) -> Result<offchain::CryptoKey, ()> {
|
||||
with_offchain(|ext| {
|
||||
ext.new_crypto_key(crypto)
|
||||
}, "new_crypto_key can be called only in the offchain worker context")
|
||||
}
|
||||
|
||||
fn encrypt(
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
with_offchain(|ext| {
|
||||
ext.encrypt(key, data)
|
||||
}, "encrypt can be called only in the offchain worker context")
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
with_offchain(|ext| {
|
||||
ext.decrypt(key, data)
|
||||
}, "decrypt can be called only in the offchain worker context")
|
||||
}
|
||||
|
||||
fn sign(
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
with_offchain(|ext| {
|
||||
ext.sign(key, data)
|
||||
}, "sign can be called only in the offchain worker context")
|
||||
}
|
||||
|
||||
fn verify(
|
||||
key: offchain::CryptoKey,
|
||||
msg: &[u8],
|
||||
signature: &[u8],
|
||||
) -> Result<bool, ()> {
|
||||
with_offchain(|ext| {
|
||||
ext.verify(key, msg, signature)
|
||||
}, "verify can be called only in the offchain worker context")
|
||||
}
|
||||
|
||||
fn timestamp() -> offchain::Timestamp {
|
||||
with_offchain(|ext| {
|
||||
ext.timestamp()
|
||||
|
||||
+149
-197
@@ -19,8 +19,9 @@ pub use rstd;
|
||||
pub use rstd::{mem, slice};
|
||||
|
||||
use core::{intrinsics, panic::PanicInfo};
|
||||
use rstd::{vec::Vec, cell::Cell, convert::TryInto, convert::TryFrom};
|
||||
use rstd::{vec::Vec, cell::Cell, convert::TryInto};
|
||||
use primitives::{offchain, Blake2Hasher};
|
||||
use codec::Decode;
|
||||
|
||||
#[cfg(not(feature = "no_panic_handler"))]
|
||||
#[panic_handler]
|
||||
@@ -158,7 +159,7 @@ pub mod ext {
|
||||
(
|
||||
$(
|
||||
$( #[$attr:meta] )*
|
||||
fn $name:ident ( $( $arg:ident : $arg_ty:ty ),* ) $( -> $ret:ty )?;
|
||||
fn $name:ident ( $( $arg:ident : $arg_ty:ty ),* $(,)? ) $( -> $ret:ty )?;
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
@@ -352,25 +353,72 @@ pub mod ext {
|
||||
fn ext_twox_256(data: *const u8, len: u32, out: *mut u8);
|
||||
/// Keccak256 hash
|
||||
fn ext_keccak_256(data: *const u8, len: u32, out: *mut u8);
|
||||
/// Note: ext_ed25519_verify returns 0 if the signature is correct, nonzero otherwise.
|
||||
|
||||
/// Returns all `ed25519` public keys for the given key type from the keystore.
|
||||
fn ext_ed25519_public_keys(id: *const u8, result_len: *mut u32) -> *mut u8;
|
||||
|
||||
/// Note: `ext_ed25519_verify` returns `0` if the signature is correct, nonzero otherwise.
|
||||
fn ext_ed25519_verify(
|
||||
msg_data: *const u8,
|
||||
msg_len: u32,
|
||||
sig_data: *const u8,
|
||||
pubkey_data: *const u8
|
||||
pubkey_data: *const u8,
|
||||
) -> u32;
|
||||
/// Note: ext_sr25519_verify returns 0 if the signature is correct, nonzero otherwise.
|
||||
|
||||
/// Generate an `ed25519` key pair for the given key type id and store the public key
|
||||
/// in `out`.
|
||||
fn ext_ed25519_generate(id: *const u8, seed: *const u8, seed_len: u32, out: *mut u8);
|
||||
|
||||
/// Sign the given `msg` with the `ed25519` key pair that corresponds to then given key
|
||||
/// type id and public key. The raw signature is stored in `out`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `0` on success
|
||||
/// - nonezero if something failed, e.g. retrieving of the key.
|
||||
fn ext_ed25519_sign(
|
||||
id: *const u8,
|
||||
pubkey: *const u8,
|
||||
msg: *const u8,
|
||||
msg_len: u32,
|
||||
out: *mut u8,
|
||||
) -> u32;
|
||||
|
||||
/// Returns all `sr25519` public keys for the given key type from the keystore.
|
||||
fn ext_sr25519_public_keys(id: *const u8, result_len: *mut u32) -> *mut u8;
|
||||
|
||||
/// Note: `ext_sr25519_verify` returns 0 if the signature is correct, nonzero otherwise.
|
||||
fn ext_sr25519_verify(
|
||||
msg_data: *const u8,
|
||||
msg_len: u32,
|
||||
sig_data: *const u8,
|
||||
pubkey_data: *const u8
|
||||
pubkey_data: *const u8,
|
||||
) -> u32;
|
||||
|
||||
/// Generate an `sr25519` key pair for the given key type id and store the public
|
||||
/// key in `out`.
|
||||
fn ext_sr25519_generate(id: *const u8, seed: *const u8, seed_len: u32, out: *mut u8);
|
||||
|
||||
/// Sign the given `msg` with the `sr25519` key pair that corresponds to then given key
|
||||
/// type id and public key. The raw signature is stored in `out`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `0` on success
|
||||
/// - nonezero if something failed, e.g. retrieving of the key.
|
||||
fn ext_sr25519_sign(
|
||||
id: *const u8,
|
||||
pubkey: *const u8,
|
||||
msg: *const u8,
|
||||
msg_len: u32,
|
||||
out: *mut u8,
|
||||
) -> u32;
|
||||
|
||||
/// Note: ext_secp256k1_ecdsa_recover returns 0 if the signature is correct, nonzero otherwise.
|
||||
fn ext_secp256k1_ecdsa_recover(
|
||||
msg_data: *const u8,
|
||||
sig_data: *const u8,
|
||||
pubkey_data: *mut u8
|
||||
pubkey_data: *mut u8,
|
||||
) -> u32;
|
||||
|
||||
//================================
|
||||
@@ -398,94 +446,6 @@ pub mod ext {
|
||||
/// runtime code can always rely on it.
|
||||
fn ext_network_state(written_out: *mut u32) -> *mut u8;
|
||||
|
||||
/// Returns the locally configured authority public key, if available.
|
||||
/// The `crypto` argument is `offchain::CryptoKind` converted to `u32`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// The encoded `Result<PublicKey encoded to Vec<u8>, ()>`.
|
||||
/// `written_out` contains the length of the message.
|
||||
///
|
||||
/// The ownership of the returned buffer is transferred to the runtime
|
||||
/// code and the runtime is responsible for freeing it. This is always
|
||||
/// a properly allocated pointer (which cannot be NULL), hence the
|
||||
/// runtime code can always rely on it.
|
||||
fn ext_pubkey(key: u64, written_out: *mut u32) -> *mut u8;
|
||||
|
||||
/// Create new key(pair) for signing/encryption/decryption.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - A crypto key id (if the value is less than u16::max_value)
|
||||
/// - `u32::max_value` in case the crypto is not supported
|
||||
fn ext_new_crypto_key(crypto: u32) -> u64;
|
||||
|
||||
/// Encrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `0`, it will attempt to use current authority key of given `kind`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `0` in case the key is invalid, `msg_len` is set to `u32::max_value`
|
||||
/// - Otherwise, pointer to the encrypted message in memory,
|
||||
/// `msg_len` contains the length of the message.
|
||||
fn ext_encrypt(
|
||||
key: u64,
|
||||
data: *const u8,
|
||||
data_len: u32,
|
||||
msg_len: *mut u32
|
||||
) -> *mut u8;
|
||||
|
||||
/// Decrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `0`, it will attempt to use current authority key of given `kind`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `0` in case the key is invalid or data couldn't be decrypted,
|
||||
/// `msg_len` is set to `u32::max_value`
|
||||
/// - Otherwise, pointer to the decrypted message in memory,
|
||||
/// `msg_len` contains the length of the message.
|
||||
fn ext_decrypt(
|
||||
key: u64,
|
||||
data: *const u8,
|
||||
data_len: u32,
|
||||
msg_len: *mut u32
|
||||
) -> *mut u8;
|
||||
|
||||
/// Sign a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `0`, it will attempt to use current authority key of given `kind`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `0` in case the key is invalid,
|
||||
/// `sig_data_len` is set to `u32::max_value`
|
||||
/// - Otherwise, pointer to the signature in memory,
|
||||
/// `sig_data_len` contains the length of the signature.
|
||||
fn ext_sign(
|
||||
key: u64,
|
||||
data: *const u8,
|
||||
data_len: u32,
|
||||
sig_data_len: *mut u32
|
||||
) -> *mut u8;
|
||||
|
||||
/// Verifies that `signature` for `msg` matches given `key`.
|
||||
///
|
||||
/// If `key` is `0`, it will attempt to use current authority key of given `kind`.
|
||||
///
|
||||
/// # Returns
|
||||
/// - `0` in case the signature is correct
|
||||
/// - `1` in case it doesn't match the key
|
||||
/// - `u32::max_value` if the key is invalid.
|
||||
fn ext_verify(
|
||||
key: u64,
|
||||
msg: *const u8,
|
||||
msg_len: u32,
|
||||
signature: *const u8,
|
||||
signature_len: u32
|
||||
) -> u32;
|
||||
|
||||
/// Returns current UNIX timestamp (milliseconds)
|
||||
fn ext_timestamp() -> u64;
|
||||
|
||||
@@ -871,15 +831,105 @@ impl HashingApi for () {
|
||||
}
|
||||
|
||||
impl CryptoApi for () {
|
||||
fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
|
||||
fn ed25519_public_keys(id: KeyTypeId) -> Vec<ed25519::Public> {
|
||||
let mut res_len = 0u32;
|
||||
unsafe {
|
||||
ext_ed25519_verify.get()(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0
|
||||
let res_ptr = ext_ed25519_public_keys.get()(id.0.as_ptr(), &mut res_len);
|
||||
Vec::decode(&mut rstd::slice::from_raw_parts(res_ptr, res_len as usize)).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
fn sr25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
|
||||
fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> ed25519::Public {
|
||||
let mut res = [0u8; 32];
|
||||
let seed = seed.as_ref().map(|s| s.as_bytes()).unwrap_or(&[]);
|
||||
unsafe {
|
||||
ext_sr25519_verify.get()(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0
|
||||
ext_ed25519_generate.get()(id.0.as_ptr(), seed.as_ptr(), seed.len() as u32, res.as_mut_ptr())
|
||||
};
|
||||
ed25519::Public(res)
|
||||
}
|
||||
|
||||
fn ed25519_sign<M: AsRef<[u8]>>(
|
||||
id: KeyTypeId,
|
||||
pubkey: &ed25519::Public,
|
||||
msg: &M,
|
||||
) -> Option<ed25519::Signature> {
|
||||
let mut res = [0u8; 64];
|
||||
let success = unsafe {
|
||||
ext_ed25519_sign.get()(
|
||||
id.0.as_ptr(),
|
||||
pubkey.0.as_ptr(),
|
||||
msg.as_ref().as_ptr(),
|
||||
msg.as_ref().len() as u32,
|
||||
res.as_mut_ptr(),
|
||||
) == 0
|
||||
};
|
||||
|
||||
if success {
|
||||
Some(ed25519::Signature(res))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pubkey: &ed25519::Public) -> bool {
|
||||
unsafe {
|
||||
ext_ed25519_verify.get()(
|
||||
msg.as_ptr(),
|
||||
msg.len() as u32,
|
||||
sig.0.as_ptr(),
|
||||
pubkey.0.as_ptr(),
|
||||
) == 0
|
||||
}
|
||||
}
|
||||
|
||||
fn sr25519_public_keys(id: KeyTypeId) -> Vec<sr25519::Public> {
|
||||
let mut res_len = 0u32;
|
||||
unsafe {
|
||||
let res_ptr = ext_sr25519_public_keys.get()(id.0.as_ptr(), &mut res_len);
|
||||
Vec::decode(&mut rstd::slice::from_raw_parts(res_ptr, res_len as usize)).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> sr25519::Public {
|
||||
let mut res = [0u8;32];
|
||||
let seed = seed.as_ref().map(|s| s.as_bytes()).unwrap_or(&[]);
|
||||
unsafe {
|
||||
ext_sr25519_generate.get()(id.0.as_ptr(), seed.as_ptr(), seed.len() as u32, res.as_mut_ptr())
|
||||
};
|
||||
sr25519::Public(res)
|
||||
}
|
||||
|
||||
fn sr25519_sign<M: AsRef<[u8]>>(
|
||||
id: KeyTypeId,
|
||||
pubkey: &sr25519::Public,
|
||||
msg: &M,
|
||||
) -> Option<sr25519::Signature> {
|
||||
let mut res = [0u8; 64];
|
||||
let success = unsafe {
|
||||
ext_sr25519_sign.get()(
|
||||
id.0.as_ptr(),
|
||||
pubkey.0.as_ptr(),
|
||||
msg.as_ref().as_ptr(),
|
||||
msg.as_ref().len() as u32,
|
||||
res.as_mut_ptr(),
|
||||
) == 0
|
||||
};
|
||||
|
||||
if success {
|
||||
Some(sr25519::Signature(res))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pubkey: &sr25519::Public) -> bool {
|
||||
unsafe {
|
||||
ext_sr25519_verify.get()(
|
||||
msg.as_ptr(),
|
||||
msg.len() as u32,
|
||||
sig.0.as_ptr(),
|
||||
pubkey.0.as_ptr(),
|
||||
) == 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -925,104 +975,6 @@ impl OffchainApi for () {
|
||||
}
|
||||
}
|
||||
|
||||
fn pubkey(key: CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
let mut len = 0u32;
|
||||
let raw_result = unsafe {
|
||||
let ptr = ext_pubkey.get()(
|
||||
key.into(),
|
||||
&mut len,
|
||||
);
|
||||
|
||||
from_raw_parts(ptr, len)
|
||||
};
|
||||
|
||||
match raw_result {
|
||||
Some(raw_result) => codec::Decode::decode(&mut &*raw_result).unwrap_or(Err(())),
|
||||
None => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn new_crypto_key(crypto: offchain::CryptoKind) -> Result<offchain::CryptoKey, ()> {
|
||||
let crypto = crypto.into();
|
||||
let ret = unsafe {
|
||||
ext_new_crypto_key.get()(crypto)
|
||||
};
|
||||
offchain::CryptoKey::try_from(ret)
|
||||
}
|
||||
|
||||
fn encrypt(
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
let mut len = 0_u32;
|
||||
unsafe {
|
||||
let ptr = ext_encrypt.get()(
|
||||
key.into(),
|
||||
data.as_ptr(),
|
||||
data.len() as u32,
|
||||
&mut len
|
||||
);
|
||||
|
||||
from_raw_parts(ptr, len).ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
let mut len = 0_u32;
|
||||
unsafe {
|
||||
let ptr = ext_decrypt.get()(
|
||||
key.into(),
|
||||
data.as_ptr(),
|
||||
data.len() as u32,
|
||||
&mut len
|
||||
);
|
||||
|
||||
from_raw_parts(ptr, len).ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
fn sign(
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
let mut len = 0_u32;
|
||||
unsafe {
|
||||
let ptr = ext_sign.get()(
|
||||
key.into(),
|
||||
data.as_ptr(),
|
||||
data.len() as u32,
|
||||
&mut len
|
||||
);
|
||||
|
||||
from_raw_parts(ptr, len).ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
fn verify(
|
||||
key: offchain::CryptoKey,
|
||||
msg: &[u8],
|
||||
signature: &[u8],
|
||||
) -> Result<bool, ()> {
|
||||
let val = unsafe {
|
||||
ext_verify.get()(
|
||||
key.into(),
|
||||
msg.as_ptr(),
|
||||
msg.len() as u32,
|
||||
signature.as_ptr(),
|
||||
signature.len() as u32,
|
||||
)
|
||||
};
|
||||
|
||||
match val {
|
||||
0 => Ok(true),
|
||||
1 => Ok(false),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn timestamp() -> offchain::Timestamp {
|
||||
offchain::Timestamp::from_unix_millis(unsafe {
|
||||
ext_timestamp.get()()
|
||||
|
||||
@@ -10,10 +10,12 @@ integer-sqrt = { version = "0.1.2" }
|
||||
serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
|
||||
primitives = { package = "substrate-primitives", path = "../primitives", default-features = false }
|
||||
app-crypto = { package = "substrate-application-crypto", path = "../application-crypto", default-features = false }
|
||||
rstd = { package = "sr-std", path = "../sr-std", default-features = false }
|
||||
runtime_io = { package = "sr-io", path = "../sr-io", default-features = false }
|
||||
log = { version = "0.4", optional = true }
|
||||
paste = { version = "0.1"}
|
||||
rand = { version = "0.7.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1.0"
|
||||
@@ -29,4 +31,6 @@ std = [
|
||||
"runtime_io/std",
|
||||
"codec/std",
|
||||
"primitives/std",
|
||||
"app-crypto/std",
|
||||
"rand",
|
||||
]
|
||||
|
||||
@@ -45,11 +45,10 @@ for
|
||||
where
|
||||
AccountId: Member + MaybeDisplay,
|
||||
Call: Member + Dispatchable<Origin=Origin>,
|
||||
Extra: SignedExtension<AccountId=AccountId>,
|
||||
Extra: SignedExtension<AccountId=AccountId, Call=Call>,
|
||||
Origin: From<Option<AccountId>>,
|
||||
{
|
||||
type AccountId = AccountId;
|
||||
|
||||
type Call = Call;
|
||||
|
||||
fn sender(&self) -> Option<&Self::AccountId> {
|
||||
@@ -61,9 +60,9 @@ where
|
||||
len: usize,
|
||||
) -> TransactionValidity {
|
||||
if let Some((ref id, ref extra)) = self.signed {
|
||||
Extra::validate(extra, id, info, len).into()
|
||||
Extra::validate(extra, id, &self.function, info, len).into()
|
||||
} else {
|
||||
match Extra::validate_unsigned(info, len) {
|
||||
match Extra::validate_unsigned(&self.function, info, len) {
|
||||
Ok(extra) => match U::validate_unsigned(&self.function) {
|
||||
TransactionValidity::Valid(v) =>
|
||||
TransactionValidity::Valid(v.combine_with(extra)),
|
||||
@@ -79,10 +78,10 @@ where
|
||||
len: usize,
|
||||
) -> Result<DispatchResult, DispatchError> {
|
||||
let maybe_who = if let Some((id, extra)) = self.signed {
|
||||
Extra::pre_dispatch(extra, &id, info, len)?;
|
||||
Extra::pre_dispatch(extra, &id, &self.function, info, len)?;
|
||||
Some(id)
|
||||
} else {
|
||||
Extra::pre_dispatch_unsigned(info, len)?;
|
||||
Extra::pre_dispatch_unsigned(&self.function, info, len)?;
|
||||
None
|
||||
};
|
||||
Ok(self.function.dispatch(Origin::from(maybe_who)))
|
||||
|
||||
@@ -234,6 +234,7 @@ mod tests {
|
||||
struct TestExtra;
|
||||
impl SignedExtension for TestExtra {
|
||||
type AccountId = u64;
|
||||
type Call = ();
|
||||
type AdditionalSigned = ();
|
||||
fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) }
|
||||
}
|
||||
|
||||
@@ -31,10 +31,13 @@ pub use rstd;
|
||||
#[doc(hidden)]
|
||||
pub use paste;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use app_crypto;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay};
|
||||
|
||||
use rstd::{prelude::*, ops, convert::TryInto};
|
||||
use rstd::{prelude::*, ops, convert::{TryInto, TryFrom}};
|
||||
use primitives::{crypto, ed25519, sr25519, hash::{H256, H512}};
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
@@ -52,7 +55,8 @@ pub mod transaction_validity;
|
||||
pub use generic::{DigestItem, Digest};
|
||||
|
||||
/// Re-export this since it's part of the API of this crate.
|
||||
pub use primitives::crypto::{key_types, KeyTypeId};
|
||||
pub use primitives::crypto::{key_types, KeyTypeId, CryptoType};
|
||||
pub use app_crypto::AppKey;
|
||||
|
||||
/// A message indicating an invalid signature in extrinsic.
|
||||
pub const BAD_SIGNATURE: &str = "bad signature in extrinsic";
|
||||
@@ -660,8 +664,13 @@ pub struct AnySignature(H512);
|
||||
impl Verify for AnySignature {
|
||||
type Signer = sr25519::Public;
|
||||
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &sr25519::Public) -> bool {
|
||||
runtime_io::sr25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0) ||
|
||||
runtime_io::ed25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0)
|
||||
sr25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
|
||||
.map(|s| runtime_io::sr25519_verify(&s, msg.get(), &signer))
|
||||
.unwrap_or(false)
|
||||
|| ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
|
||||
.and_then(|s| ed25519::Public::try_from(signer.0.as_ref()).map(|p| (s, p)))
|
||||
.map(|(s, p)| runtime_io::ed25519_verify(&s, msg.get(), &p))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,46 +20,84 @@ use serde::{Serialize, Serializer, Deserialize, de::Error as DeError, Deserializ
|
||||
use std::{fmt::Debug, ops::Deref, fmt};
|
||||
use crate::codec::{Codec, Encode, Decode};
|
||||
use crate::traits::{
|
||||
self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, TypedKey, DispatchError, DispatchResult,
|
||||
self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, DispatchError, DispatchResult,
|
||||
ValidateUnsigned, SignedExtension, Dispatchable,
|
||||
};
|
||||
use crate::{generic, KeyTypeId};
|
||||
use crate::weights::{GetDispatchInfo, DispatchInfo};
|
||||
pub use primitives::H256;
|
||||
use primitives::U256;
|
||||
use primitives::ed25519::{Public as AuthorityId};
|
||||
use primitives::{crypto::{CryptoType, Dummy, key_types, Public}, U256};
|
||||
use crate::transaction_validity::TransactionValidity;
|
||||
|
||||
/// Authority Id
|
||||
#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
|
||||
#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug, Hash, Serialize, Deserialize)]
|
||||
pub struct UintAuthorityId(pub u64);
|
||||
impl Into<AuthorityId> for UintAuthorityId {
|
||||
fn into(self) -> AuthorityId {
|
||||
|
||||
impl UintAuthorityId {
|
||||
/// Convert this authority id into a public key.
|
||||
pub fn to_public_key<T: Public>(&self) -> T {
|
||||
let bytes: [u8; 32] = U256::from(self.0).into();
|
||||
AuthorityId(bytes)
|
||||
T::from_slice(&bytes)
|
||||
}
|
||||
}
|
||||
|
||||
/// The key-type of the `UintAuthorityId`
|
||||
pub const UINT_DUMMY_KEY: KeyTypeId = 0xdeadbeef;
|
||||
|
||||
impl TypedKey for UintAuthorityId {
|
||||
const KEY_TYPE: KeyTypeId = UINT_DUMMY_KEY;
|
||||
impl CryptoType for UintAuthorityId {
|
||||
type Pair = Dummy;
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for UintAuthorityId {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
let ptr = self.0 as *const _;
|
||||
// It's safe to do this here since `UintAuthorityId` is `u64`.
|
||||
unsafe { std::slice::from_raw_parts(ptr, 8) }
|
||||
unsafe {
|
||||
std::slice::from_raw_parts(&self.0 as *const u64 as *const _, std::mem::size_of::<u64>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl app_crypto::RuntimeAppPublic for UintAuthorityId {
|
||||
type Signature = u64;
|
||||
|
||||
fn all() -> Vec<Self> {
|
||||
unimplemented!("`all()` not available for `UintAuthorityId`.")
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn generate_pair(_: Option<&str>) -> Self {
|
||||
use rand::RngCore;
|
||||
UintAuthorityId(rand::thread_rng().next_u64())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn generate_pair(_: Option<&str>) -> Self {
|
||||
unimplemented!("`generate_pair` not implemented for `UIntAuthorityId` on `no_std`.")
|
||||
}
|
||||
|
||||
fn sign<M: AsRef<[u8]>>(&self, msg: &M) -> Option<Self::Signature> {
|
||||
let mut signature = [0u8; 8];
|
||||
msg.as_ref().iter()
|
||||
.chain(rstd::iter::repeat(&42u8))
|
||||
.take(8)
|
||||
.enumerate()
|
||||
.for_each(|(i, v)| { signature[i] = *v; });
|
||||
|
||||
Some(u64::from_le_bytes(signature))
|
||||
}
|
||||
|
||||
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool {
|
||||
let mut msg_signature = [0u8; 8];
|
||||
msg.as_ref().iter()
|
||||
.chain(rstd::iter::repeat(&42))
|
||||
.take(8)
|
||||
.enumerate()
|
||||
.for_each(|(i, v)| { msg_signature[i] = *v; });
|
||||
|
||||
u64::from_le_bytes(msg_signature) == *signature
|
||||
}
|
||||
}
|
||||
|
||||
impl OpaqueKeys for UintAuthorityId {
|
||||
type KeyTypeIds = std::iter::Cloned<std::slice::Iter<'static, KeyTypeId>>;
|
||||
|
||||
fn key_ids() -> Self::KeyTypeIds { [UINT_DUMMY_KEY].iter().cloned() }
|
||||
fn key_ids() -> Self::KeyTypeIds { [key_types::DUMMY].iter().cloned() }
|
||||
// Unsafe, i know, but it's test code and it's just there because it's really convenient to
|
||||
// keep `UintAuthorityId` as a u64 under the hood.
|
||||
fn get_raw(&self, _: KeyTypeId) -> &[u8] {
|
||||
@@ -155,8 +193,7 @@ impl<Xt> traits::Extrinsic for ExtrinsicWrapper<Xt> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Xt: Encode> serde::Serialize for ExtrinsicWrapper<Xt>
|
||||
{
|
||||
impl<Xt: Encode> serde::Serialize for ExtrinsicWrapper<Xt> {
|
||||
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
|
||||
self.using_encoded(|bytes| seq.serialize_bytes(bytes))
|
||||
}
|
||||
@@ -249,13 +286,13 @@ impl<Call: Codec + Sync + Send, Extra> traits::Extrinsic for TestXt<Call, Extra>
|
||||
|
||||
impl<Origin, Call, Extra> Applyable for TestXt<Call, Extra> where
|
||||
Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable<Origin=Origin>,
|
||||
Extra: SignedExtension<AccountId=u64>,
|
||||
Extra: SignedExtension<AccountId=u64, Call=Call>,
|
||||
Origin: From<Option<u64>>
|
||||
{
|
||||
type AccountId = u64;
|
||||
type Call = Call;
|
||||
|
||||
fn sender(&self) -> Option<&u64> { self.0.as_ref().map(|x| &x.0) }
|
||||
fn sender(&self) -> Option<&Self::AccountId> { self.0.as_ref().map(|x| &x.0) }
|
||||
|
||||
/// Checks to see if this is a valid *transaction*. It returns information on it if so.
|
||||
fn validate<U: ValidateUnsigned<Call=Self::Call>>(&self,
|
||||
@@ -272,10 +309,10 @@ impl<Origin, Call, Extra> Applyable for TestXt<Call, Extra> where
|
||||
len: usize,
|
||||
) -> Result<DispatchResult, DispatchError> {
|
||||
let maybe_who = if let Some((who, extra)) = self.0 {
|
||||
Extra::pre_dispatch(extra, &who, info, len)?;
|
||||
Extra::pre_dispatch(extra, &who, &self.1, info, len)?;
|
||||
Some(who)
|
||||
} else {
|
||||
Extra::pre_dispatch_unsigned(info, len)?;
|
||||
Extra::pre_dispatch_unsigned(&self.1, info, len)?;
|
||||
None
|
||||
};
|
||||
Ok(self.1.dispatch(maybe_who.into()))
|
||||
|
||||
@@ -26,7 +26,6 @@ use crate::codec::{Codec, Encode, Decode, HasCompact};
|
||||
use crate::transaction_validity::{ValidTransaction, TransactionValidity};
|
||||
use crate::generic::{Digest, DigestItem};
|
||||
use crate::weights::DispatchInfo;
|
||||
pub use primitives::crypto::TypedKey;
|
||||
pub use integer_sqrt::IntegerSquareRoot;
|
||||
pub use num_traits::{
|
||||
Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
|
||||
@@ -60,14 +59,14 @@ pub trait Verify {
|
||||
impl Verify for primitives::ed25519::Signature {
|
||||
type Signer = primitives::ed25519::Public;
|
||||
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
|
||||
runtime_io::ed25519_verify(self.as_ref(), msg.get(), signer)
|
||||
runtime_io::ed25519_verify(self, msg.get(), signer)
|
||||
}
|
||||
}
|
||||
|
||||
impl Verify for primitives::sr25519::Signature {
|
||||
type Signer = primitives::sr25519::Public;
|
||||
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
|
||||
runtime_io::sr25519_verify(self.as_ref(), msg.get(), signer)
|
||||
runtime_io::sr25519_verify(self, msg.get(), signer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,7 +744,7 @@ pub enum DispatchError {
|
||||
Payment,
|
||||
|
||||
/// General error to do with the exhaustion of block resources.
|
||||
Resource,
|
||||
Exhausted,
|
||||
|
||||
/// General error to do with the permissions of the sender.
|
||||
NoPermission,
|
||||
@@ -761,16 +760,13 @@ pub enum DispatchError {
|
||||
|
||||
/// General error to do with the transaction's proofs (e.g. signature).
|
||||
BadProof,
|
||||
|
||||
/* /// General error to do with actually executing the dispatched logic.
|
||||
User(&'static str),*/
|
||||
}
|
||||
|
||||
impl From<DispatchError> for i8 {
|
||||
fn from(e: DispatchError) -> i8 {
|
||||
match e {
|
||||
DispatchError::Payment => -64,
|
||||
DispatchError::Resource => -65,
|
||||
DispatchError::Exhausted => -65,
|
||||
DispatchError::NoPermission => -66,
|
||||
DispatchError::BadState => -67,
|
||||
DispatchError::Stale => -68,
|
||||
@@ -805,6 +801,9 @@ pub trait SignedExtension:
|
||||
/// The type which encodes the sender identity.
|
||||
type AccountId;
|
||||
|
||||
/// The type which encodes the call to be dispatched.
|
||||
type Call;
|
||||
|
||||
/// Any additional data that will go into the signed payload. This may be created dynamically
|
||||
/// from the transaction using the `additional_signed` function.
|
||||
type AdditionalSigned: Encode;
|
||||
@@ -813,35 +812,45 @@ pub trait SignedExtension:
|
||||
/// also perform any pre-signature-verification checks and return an error if needed.
|
||||
fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str>;
|
||||
|
||||
/// Validate a signed transaction for the transaction queue.
|
||||
/// Validate a signed transaction for the transaction queue.
|
||||
fn validate(
|
||||
&self,
|
||||
_who: &Self::AccountId,
|
||||
_call: &Self::Call,
|
||||
_info: DispatchInfo,
|
||||
_len: usize,
|
||||
) -> Result<ValidTransaction, DispatchError> { Ok(Default::default()) }
|
||||
) -> Result<ValidTransaction, DispatchError> {
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
/// Do any pre-flight stuff for a signed transaction.
|
||||
fn pre_dispatch(
|
||||
self,
|
||||
who: &Self::AccountId,
|
||||
call: &Self::Call,
|
||||
info: DispatchInfo,
|
||||
len: usize,
|
||||
) -> Result<(), DispatchError> { self.validate(who, info, len).map(|_| ()) }
|
||||
) -> Result<(), DispatchError> {
|
||||
self.validate(who, call, info, len).map(|_| ())
|
||||
}
|
||||
|
||||
/// Validate an unsigned transaction for the transaction queue. Normally the default
|
||||
/// implementation is fine since `ValidateUnsigned` is a better way of recognising and
|
||||
/// validating unsigned transactions.
|
||||
fn validate_unsigned(
|
||||
_call: &Self::Call,
|
||||
_info: DispatchInfo,
|
||||
_len: usize,
|
||||
) -> Result<ValidTransaction, DispatchError> { Ok(Default::default()) }
|
||||
|
||||
/// Do any pre-flight stuff for a unsigned transaction.
|
||||
fn pre_dispatch_unsigned(
|
||||
call: &Self::Call,
|
||||
info: DispatchInfo,
|
||||
len: usize,
|
||||
) -> Result<(), DispatchError> { Self::validate_unsigned(info, len).map(|_| ()) }
|
||||
) -> Result<(), DispatchError> {
|
||||
Self::validate_unsigned(call, info, len).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tuple_impl_indexed {
|
||||
@@ -851,9 +860,11 @@ macro_rules! tuple_impl_indexed {
|
||||
([$($direct:ident)+] ; [$($index:tt,)+]) => {
|
||||
impl<
|
||||
AccountId,
|
||||
$($direct: SignedExtension<AccountId=AccountId>),+
|
||||
Call,
|
||||
$($direct: SignedExtension<AccountId=AccountId, Call=Call>),+
|
||||
> SignedExtension for ($($direct),+,) {
|
||||
type AccountId = AccountId;
|
||||
type Call = Call;
|
||||
type AdditionalSigned = ($($direct::AdditionalSigned,)+);
|
||||
fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str> {
|
||||
Ok(( $(self.$index.additional_signed()?,)+ ))
|
||||
@@ -861,33 +872,37 @@ macro_rules! tuple_impl_indexed {
|
||||
fn validate(
|
||||
&self,
|
||||
who: &Self::AccountId,
|
||||
call: &Self::Call,
|
||||
info: DispatchInfo,
|
||||
len: usize,
|
||||
) -> Result<ValidTransaction, DispatchError> {
|
||||
let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, info, len)?),+];
|
||||
let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, call, info, len)?),+];
|
||||
Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a)))
|
||||
}
|
||||
fn pre_dispatch(
|
||||
self,
|
||||
who: &Self::AccountId,
|
||||
call: &Self::Call,
|
||||
info: DispatchInfo,
|
||||
len: usize,
|
||||
) -> Result<(), DispatchError> {
|
||||
$(self.$index.pre_dispatch(who, info, len)?;)+
|
||||
$(self.$index.pre_dispatch(who, call, info, len)?;)+
|
||||
Ok(())
|
||||
}
|
||||
fn validate_unsigned(
|
||||
call: &Self::Call,
|
||||
info: DispatchInfo,
|
||||
len: usize,
|
||||
) -> Result<ValidTransaction, DispatchError> {
|
||||
let aggregator = vec![$($direct::validate_unsigned(info, len)?),+];
|
||||
let aggregator = vec![$($direct::validate_unsigned(call, info, len)?),+];
|
||||
Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a)))
|
||||
}
|
||||
fn pre_dispatch_unsigned(
|
||||
call: &Self::Call,
|
||||
info: DispatchInfo,
|
||||
len: usize,
|
||||
) -> Result<(), DispatchError> {
|
||||
$($direct::pre_dispatch_unsigned(info, len)?;)+
|
||||
$($direct::pre_dispatch_unsigned(call, info, len)?;)+
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -910,11 +925,12 @@ macro_rules! tuple_impl_indexed {
|
||||
#[allow(non_snake_case)]
|
||||
tuple_impl_indexed!(A, B, C, D, E, F, G, H, I, J, ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,);
|
||||
|
||||
/// Only for base bone testing when you don't care about signed extensions at all.\
|
||||
/// Only for bare bone testing when you don't care about signed extensions at all.
|
||||
#[cfg(feature = "std")]
|
||||
impl SignedExtension for () {
|
||||
type AccountId = u64;
|
||||
type AdditionalSigned = ();
|
||||
type Call = ();
|
||||
fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) }
|
||||
}
|
||||
|
||||
@@ -1208,14 +1224,14 @@ macro_rules! count {
|
||||
/// just the bytes of the key.
|
||||
///
|
||||
/// ```rust
|
||||
/// use sr_primitives::{impl_opaque_keys, key_types, KeyTypeId};
|
||||
/// use sr_primitives::{impl_opaque_keys, key_types, KeyTypeId, app_crypto::{sr25519, ed25519}};
|
||||
///
|
||||
/// impl_opaque_keys! {
|
||||
/// pub struct Keys {
|
||||
/// #[id(key_types::ED25519)]
|
||||
/// pub ed25519: [u8; 32],
|
||||
/// pub ed25519: ed25519::AppPublic,
|
||||
/// #[id(key_types::SR25519)]
|
||||
/// pub sr25519: [u8; 32],
|
||||
/// pub sr25519: sr25519::AppPublic,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@@ -1237,22 +1253,34 @@ macro_rules! impl_opaque_keys {
|
||||
)*
|
||||
}
|
||||
|
||||
impl $name {
|
||||
/// Generate a set of keys with optionally using the given seed.
|
||||
///
|
||||
/// The generated key pairs are stored in the keystore.
|
||||
///
|
||||
/// Returns the concatenated SCALE encoded public keys.
|
||||
pub fn generate(seed: Option<&str>) -> $crate::rstd::vec::Vec<u8> {
|
||||
let keys = Self{
|
||||
$(
|
||||
$field: <$type as $crate::app_crypto::RuntimeAppPublic>::generate_pair(seed),
|
||||
)*
|
||||
};
|
||||
$crate::codec::Encode::encode(&keys)
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::traits::OpaqueKeys for $name {
|
||||
type KeyTypeIds = $crate::rstd::iter::Cloned<
|
||||
$crate::rstd::slice::Iter<'static, $crate::KeyTypeId>
|
||||
>;
|
||||
|
||||
fn key_ids() -> Self::KeyTypeIds {
|
||||
[
|
||||
$($key_id),*
|
||||
].iter().cloned()
|
||||
[ $($key_id),* ].iter().cloned()
|
||||
}
|
||||
|
||||
fn get_raw(&self, i: $crate::KeyTypeId) -> &[u8] {
|
||||
match i {
|
||||
$(
|
||||
i if i == $key_id => self.$field.as_ref(),
|
||||
)*
|
||||
$( i if i == $key_id => self.$field.as_ref(), )*
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
log = "0.4"
|
||||
primitives = { package = "substrate-primitives", path = "../../core/primitives" }
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] }
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
hash-db = "0.15.0"
|
||||
trie-db = "0.15.0"
|
||||
trie-root = "0.15.0"
|
||||
|
||||
@@ -168,7 +168,12 @@ impl<H: Hasher> Externalities<H> for BasicExternalities where H::Out: Ord {
|
||||
}
|
||||
|
||||
fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> {
|
||||
warn!("Call to non-existent out offchain externalities set.");
|
||||
warn!("Call to non-existent offchain externalities set.");
|
||||
None
|
||||
}
|
||||
|
||||
fn keystore(&self) -> Option<primitives::traits::BareCryptoStorePtr> {
|
||||
warn!("Call to non-existent keystore.");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,7 @@ use crate::backend::Backend;
|
||||
use crate::changes_trie::{Storage as ChangesTrieStorage, build_changes_trie};
|
||||
use crate::{Externalities, OverlayedChanges, ChildStorageKey};
|
||||
use hash_db::Hasher;
|
||||
use primitives::offchain;
|
||||
use primitives::storage::well_known_keys::is_child_storage_key;
|
||||
use primitives::{offchain, storage::well_known_keys::is_child_storage_key, traits::BareCryptoStorePtr};
|
||||
use trie::{MemoryDB, default_child_trie_root};
|
||||
use trie::trie_types::Layout;
|
||||
|
||||
@@ -84,6 +83,8 @@ where
|
||||
///
|
||||
/// If None, some methods from the trait might not be supported.
|
||||
offchain_externalities: Option<&'a mut O>,
|
||||
/// The keystore that manages the keys of the node.
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
/// Dummy usage of N arg.
|
||||
_phantom: ::std::marker::PhantomData<N>,
|
||||
}
|
||||
@@ -103,6 +104,7 @@ where
|
||||
backend: &'a B,
|
||||
changes_trie_storage: Option<&'a T>,
|
||||
offchain_externalities: Option<&'a mut O>,
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
) -> Self {
|
||||
Ext {
|
||||
overlay,
|
||||
@@ -111,6 +113,7 @@ where
|
||||
changes_trie_storage,
|
||||
changes_trie_transaction: None,
|
||||
offchain_externalities,
|
||||
keystore,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -333,6 +336,10 @@ where
|
||||
fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> {
|
||||
self.offchain_externalities.as_mut().map(|x| &mut **x as _)
|
||||
}
|
||||
|
||||
fn keystore(&self) -> Option<BareCryptoStorePtr> {
|
||||
self.keystore.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -375,7 +382,7 @@ mod tests {
|
||||
fn storage_changes_root_is_none_when_storage_is_not_provided() {
|
||||
let mut overlay = prepare_overlay_with_changes();
|
||||
let backend = TestBackend::default();
|
||||
let mut ext = TestExt::new(&mut overlay, &backend, None, None);
|
||||
let mut ext = TestExt::new(&mut overlay, &backend, None, None, None);
|
||||
assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), None);
|
||||
}
|
||||
|
||||
@@ -385,7 +392,7 @@ mod tests {
|
||||
overlay.changes_trie_config = None;
|
||||
let storage = TestChangesTrieStorage::with_blocks(vec![(100, Default::default())]);
|
||||
let backend = TestBackend::default();
|
||||
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None);
|
||||
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None);
|
||||
assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), None);
|
||||
}
|
||||
|
||||
@@ -394,11 +401,11 @@ mod tests {
|
||||
let mut overlay = prepare_overlay_with_changes();
|
||||
let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]);
|
||||
let backend = TestBackend::default();
|
||||
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None);
|
||||
let root = hex!("bb0c2ef6e1d36d5490f9766cfcc7dfe2a6ca804504c3bb206053890d6dd02376").into();
|
||||
|
||||
assert_eq!(ext.storage_changes_root(Default::default()).unwrap(),
|
||||
Some(root));
|
||||
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None);
|
||||
assert_eq!(
|
||||
ext.storage_changes_root(Default::default()).unwrap(),
|
||||
Some(hex!("bb0c2ef6e1d36d5490f9766cfcc7dfe2a6ca804504c3bb206053890d6dd02376").into()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -407,10 +414,10 @@ mod tests {
|
||||
overlay.prospective.top.get_mut(&vec![1]).unwrap().value = None;
|
||||
let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]);
|
||||
let backend = TestBackend::default();
|
||||
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None);
|
||||
let root = hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").into();
|
||||
|
||||
assert_eq!(ext.storage_changes_root(Default::default()).unwrap(),
|
||||
Some(root));
|
||||
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None);
|
||||
assert_eq!(
|
||||
ext.storage_changes_root(Default::default()).unwrap(),
|
||||
Some(hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").into()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ use hash_db::Hasher;
|
||||
use codec::{Decode, Encode};
|
||||
use primitives::{
|
||||
storage::well_known_keys, NativeOrEncoded, NeverNativeValue, offchain,
|
||||
traits::BareCryptoStorePtr,
|
||||
};
|
||||
|
||||
pub mod backend;
|
||||
@@ -61,6 +62,7 @@ pub use proving_backend::{
|
||||
pub use trie_backend_essence::{TrieBackendStorage, Storage};
|
||||
pub use trie_backend::TrieBackend;
|
||||
|
||||
|
||||
/// A wrapper around a child storage key.
|
||||
///
|
||||
/// This wrapper ensures that the child storage key is correct and properly used. It is
|
||||
@@ -224,6 +226,9 @@ pub trait Externalities<H: Hasher> {
|
||||
|
||||
/// Returns offchain externalities extension if present.
|
||||
fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities>;
|
||||
|
||||
/// Returns the keystore.
|
||||
fn keystore(&self) -> Option<BareCryptoStorePtr>;
|
||||
}
|
||||
|
||||
/// An implementation of offchain extensions that should never be triggered.
|
||||
@@ -247,53 +252,6 @@ impl offchain::Externalities for NeverOffchainExt {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn pubkey(
|
||||
&self,
|
||||
_key: offchain::CryptoKey,
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn new_crypto_key(
|
||||
&mut self,
|
||||
_crypto: offchain::CryptoKind,
|
||||
) -> Result<offchain::CryptoKey, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn encrypt(
|
||||
&mut self,
|
||||
_key: offchain::CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
&mut self,
|
||||
_key: offchain::CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn sign(
|
||||
&mut self,
|
||||
_key: offchain::CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn verify(
|
||||
&mut self,
|
||||
_key: offchain::CryptoKey,
|
||||
_msg: &[u8],
|
||||
_signature: &[u8],
|
||||
) -> Result<bool, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn timestamp(&mut self) -> offchain::Timestamp {
|
||||
unreachable!()
|
||||
}
|
||||
@@ -481,6 +439,7 @@ pub fn new<'a, H, N, B, T, O, Exec>(
|
||||
exec: &'a Exec,
|
||||
method: &'a str,
|
||||
call_data: &'a [u8],
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
) -> StateMachine<'a, H, N, B, T, O, Exec> {
|
||||
StateMachine {
|
||||
backend,
|
||||
@@ -490,6 +449,7 @@ pub fn new<'a, H, N, B, T, O, Exec>(
|
||||
exec,
|
||||
method,
|
||||
call_data,
|
||||
keystore,
|
||||
_hasher: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -503,6 +463,7 @@ pub struct StateMachine<'a, H, N, B, T, O, Exec> {
|
||||
exec: &'a Exec,
|
||||
method: &'a str,
|
||||
call_data: &'a [u8],
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
_hasher: PhantomData<(H, N)>,
|
||||
}
|
||||
|
||||
@@ -560,6 +521,7 @@ impl<'a, H, N, B, T, O, Exec> StateMachine<'a, H, N, B, T, O, Exec> where
|
||||
self.backend,
|
||||
self.changes_trie_storage,
|
||||
self.offchain_ext.as_mut().map(|x| &mut **x),
|
||||
self.keystore.clone(),
|
||||
);
|
||||
let (result, was_native) = self.exec.call(
|
||||
&mut externalities,
|
||||
@@ -707,6 +669,7 @@ pub fn prove_execution<B, H, Exec>(
|
||||
exec: &Exec,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
) -> Result<(Vec<u8>, Vec<Vec<u8>>), Box<dyn Error>>
|
||||
where
|
||||
B: Backend<H>,
|
||||
@@ -716,7 +679,7 @@ where
|
||||
{
|
||||
let trie_backend = backend.as_trie_backend()
|
||||
.ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box<dyn Error>)?;
|
||||
prove_execution_on_trie_backend(trie_backend, overlay, exec, method, call_data)
|
||||
prove_execution_on_trie_backend(trie_backend, overlay, exec, method, call_data, keystore)
|
||||
}
|
||||
|
||||
/// Prove execution using the given trie backend, overlayed changes, and call executor.
|
||||
@@ -734,6 +697,7 @@ pub fn prove_execution_on_trie_backend<S, H, Exec>(
|
||||
exec: &Exec,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
) -> Result<(Vec<u8>, Vec<Vec<u8>>), Box<dyn Error>>
|
||||
where
|
||||
S: trie_backend_essence::TrieBackendStorage<H>,
|
||||
@@ -750,6 +714,7 @@ where
|
||||
exec,
|
||||
method,
|
||||
call_data,
|
||||
keystore,
|
||||
_hasher: PhantomData,
|
||||
};
|
||||
let (result, _, _) = sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
|
||||
@@ -769,6 +734,7 @@ pub fn execution_proof_check<H, Exec>(
|
||||
exec: &Exec,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
) -> Result<Vec<u8>, Box<dyn Error>>
|
||||
where
|
||||
H: Hasher,
|
||||
@@ -776,7 +742,7 @@ where
|
||||
H::Out: Ord + 'static,
|
||||
{
|
||||
let trie_backend = create_proof_check_backend::<H>(root.into(), proof)?;
|
||||
execution_proof_check_on_trie_backend(&trie_backend, overlay, exec, method, call_data)
|
||||
execution_proof_check_on_trie_backend(&trie_backend, overlay, exec, method, call_data, keystore)
|
||||
}
|
||||
|
||||
/// Check execution proof on proving backend, generated by `prove_execution` call.
|
||||
@@ -786,6 +752,7 @@ pub fn execution_proof_check_on_trie_backend<H, Exec>(
|
||||
exec: &Exec,
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
) -> Result<Vec<u8>, Box<dyn Error>>
|
||||
where
|
||||
H: Hasher,
|
||||
@@ -800,6 +767,7 @@ where
|
||||
exec,
|
||||
method,
|
||||
call_data,
|
||||
keystore,
|
||||
_hasher: PhantomData,
|
||||
};
|
||||
sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
|
||||
@@ -1050,6 +1018,7 @@ mod tests {
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
None,
|
||||
).execute(
|
||||
ExecutionStrategy::NativeWhenPossible
|
||||
).unwrap().0, vec![66]);
|
||||
@@ -1071,6 +1040,7 @@ mod tests {
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
None,
|
||||
).execute(
|
||||
ExecutionStrategy::NativeElseWasm
|
||||
).unwrap().0, vec![66]);
|
||||
@@ -1092,6 +1062,7 @@ mod tests {
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
None,
|
||||
).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
|
||||
ExecutionManager::Both(|we, _ne| {
|
||||
consensus_failed = true;
|
||||
@@ -1114,13 +1085,26 @@ mod tests {
|
||||
|
||||
// fetch execution proof from 'remote' full node
|
||||
let remote_backend = trie_backend::tests::test_trie();
|
||||
let remote_root = remote_backend.storage_root(::std::iter::empty()).0;
|
||||
let (remote_result, remote_proof) = prove_execution(remote_backend,
|
||||
&mut Default::default(), &executor, "test", &[]).unwrap();
|
||||
let remote_root = remote_backend.storage_root(std::iter::empty()).0;
|
||||
let (remote_result, remote_proof) = prove_execution(
|
||||
remote_backend,
|
||||
&mut Default::default(),
|
||||
&executor,
|
||||
"test",
|
||||
&[],
|
||||
None,
|
||||
).unwrap();
|
||||
|
||||
// check proof locally
|
||||
let local_result = execution_proof_check::<Blake2Hasher, _>(remote_root, remote_proof,
|
||||
&mut Default::default(), &executor, "test", &[]).unwrap();
|
||||
let local_result = execution_proof_check::<Blake2Hasher, _>(
|
||||
remote_root,
|
||||
remote_proof,
|
||||
&mut Default::default(),
|
||||
&executor,
|
||||
"test",
|
||||
&[],
|
||||
None,
|
||||
).unwrap();
|
||||
|
||||
// check that both results are correct
|
||||
assert_eq!(remote_result, vec![66]);
|
||||
@@ -1151,7 +1135,13 @@ mod tests {
|
||||
|
||||
{
|
||||
let changes_trie_storage = InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new();
|
||||
let mut ext = Ext::new(&mut overlay, backend, Some(&changes_trie_storage), NeverOffchainExt::new());
|
||||
let mut ext = Ext::new(
|
||||
&mut overlay,
|
||||
backend,
|
||||
Some(&changes_trie_storage),
|
||||
NeverOffchainExt::new(),
|
||||
None,
|
||||
);
|
||||
ext.clear_prefix(b"ab");
|
||||
}
|
||||
overlay.commit_prospective();
|
||||
@@ -1180,7 +1170,8 @@ mod tests {
|
||||
&mut overlay,
|
||||
backend,
|
||||
Some(&changes_trie_storage),
|
||||
NeverOffchainExt::new()
|
||||
NeverOffchainExt::new(),
|
||||
None,
|
||||
);
|
||||
|
||||
ext.set_child_storage(
|
||||
@@ -1252,41 +1243,47 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn cannot_change_changes_trie_config() {
|
||||
assert!(new(
|
||||
&trie_backend::tests::test_trie(),
|
||||
Some(&InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new()),
|
||||
NeverOffchainExt::new(),
|
||||
&mut Default::default(),
|
||||
&DummyCodeExecutor {
|
||||
change_changes_trie_config: true,
|
||||
native_available: false,
|
||||
native_succeeds: true,
|
||||
fallback_succeeds: true,
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
).execute(
|
||||
ExecutionStrategy::NativeWhenPossible
|
||||
).is_err());
|
||||
assert!(
|
||||
new(
|
||||
&trie_backend::tests::test_trie(),
|
||||
Some(&InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new()),
|
||||
NeverOffchainExt::new(),
|
||||
&mut Default::default(),
|
||||
&DummyCodeExecutor {
|
||||
change_changes_trie_config: true,
|
||||
native_available: false,
|
||||
native_succeeds: true,
|
||||
fallback_succeeds: true,
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
.execute(ExecutionStrategy::NativeWhenPossible)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_change_changes_trie_config_with_native_else_wasm() {
|
||||
assert!(new(
|
||||
&trie_backend::tests::test_trie(),
|
||||
Some(&InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new()),
|
||||
NeverOffchainExt::new(),
|
||||
&mut Default::default(),
|
||||
&DummyCodeExecutor {
|
||||
change_changes_trie_config: true,
|
||||
native_available: false,
|
||||
native_succeeds: true,
|
||||
fallback_succeeds: true,
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
).execute(
|
||||
ExecutionStrategy::NativeElseWasm
|
||||
).is_err());
|
||||
assert!(
|
||||
new(
|
||||
&trie_backend::tests::test_trie(),
|
||||
Some(&InMemoryChangesTrieStorage::<Blake2Hasher, u64>::new()),
|
||||
NeverOffchainExt::new(),
|
||||
&mut Default::default(),
|
||||
&DummyCodeExecutor {
|
||||
change_changes_trie_config: true,
|
||||
native_available: false,
|
||||
native_succeeds: true,
|
||||
fallback_succeeds: true,
|
||||
},
|
||||
"test",
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
.execute(ExecutionStrategy::NativeElseWasm)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,6 +371,7 @@ mod tests {
|
||||
&backend,
|
||||
Some(&changes_trie_storage),
|
||||
crate::NeverOffchainExt::new(),
|
||||
None,
|
||||
);
|
||||
const ROOT: [u8; 32] = hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa");
|
||||
|
||||
|
||||
@@ -25,8 +25,9 @@ use crate::changes_trie::{
|
||||
build_changes_trie, InMemoryStorage as ChangesTrieInMemoryStorage,
|
||||
BlockNumber as ChangesTrieBlockNumber,
|
||||
};
|
||||
use primitives::offchain;
|
||||
use primitives::storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES};
|
||||
use primitives::{
|
||||
storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES}, traits::BareCryptoStorePtr, offchain
|
||||
};
|
||||
use codec::Encode;
|
||||
use super::{ChildStorageKey, Externalities, OverlayedChanges};
|
||||
|
||||
@@ -40,6 +41,7 @@ pub struct TestExternalities<H: Hasher, N: ChangesTrieBlockNumber> {
|
||||
backend: InMemory<H>,
|
||||
changes_trie_storage: ChangesTrieInMemoryStorage<H, N>,
|
||||
offchain: Option<Box<dyn offchain::Externalities>>,
|
||||
keystore: Option<BareCryptoStorePtr>,
|
||||
}
|
||||
|
||||
impl<H: Hasher, N: ChangesTrieBlockNumber> TestExternalities<H, N> {
|
||||
@@ -84,6 +86,7 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> TestExternalities<H, N> {
|
||||
changes_trie_storage: ChangesTrieInMemoryStorage::new(),
|
||||
backend: backend.into(),
|
||||
offchain: None,
|
||||
keystore: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,6 +266,10 @@ impl<H, N> Externalities<H> for TestExternalities<H, N>
|
||||
.as_mut()
|
||||
.map(|x| &mut **x as _)
|
||||
}
|
||||
|
||||
fn keystore(&self) -> Option<BareCryptoStorePtr> {
|
||||
self.keystore.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bytes = "0.4"
|
||||
parking_lot = "0.8.0"
|
||||
parking_lot = "0.9.0"
|
||||
futures01 = { package = "futures", version = "0.1" }
|
||||
futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] }
|
||||
futures-timer = "0.2.1"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user