From a61c218cc3dd03db068f5e4641c39e6706c97164 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 13 Feb 2019 10:10:17 +0100 Subject: [PATCH] Introduce Ristretto signing (#1730) * first draft of ristretto crypto module #1685 * adds better comments and code-style * remove the last evil unwrap * remove a mistakenly committed lockfile * add a fresh new lockfile --will probably need a manual merge later * fix an invalid old test vector * Wire in ristretto * Update comment * Fix use. * new Signature type api alias to be compatible with substrate * Add new keyring, fix node executor tests * Bump version. * Remove all hashes. * Update core/primitives/src/sr25519.rs Co-Authored-By: gavofyork * Revert back to Ed25519 (until JS UI is ready) * Fix test --- substrate/Cargo.lock | 65 ++++ substrate/core/executor/src/wasm_executor.rs | 43 ++- substrate/core/executor/wasm/src/lib.rs | 12 +- substrate/core/keyring/src/ed25519.rs | 173 +++++++++ substrate/core/keyring/src/lib.rs | 161 +-------- substrate/core/keyring/src/sr25519.rs | 173 +++++++++ substrate/core/primitives/Cargo.toml | 6 + substrate/core/primitives/src/lib.rs | 2 + substrate/core/primitives/src/sr25519.rs | 336 ++++++++++++++++++ substrate/core/sr-io/with_std.rs | 7 +- substrate/core/sr-io/without_std.rs | 9 + substrate/core/sr-primitives/src/lib.rs | 18 + substrate/core/test-runtime/wasm/Cargo.lock | 162 +++++++++ .../substrate_test_runtime.compact.wasm | Bin 56872 -> 56839 bytes .../node-template/runtime/wasm/Cargo.lock | 162 +++++++++ substrate/node/executor/src/lib.rs | 212 ++++++----- substrate/node/primitives/src/lib.rs | 17 +- substrate/node/runtime/src/lib.rs | 4 +- substrate/node/runtime/wasm/Cargo.lock | 162 +++++++++ .../release/node_runtime.compact.wasm | Bin 814768 -> 814449 bytes 20 files changed, 1474 insertions(+), 250 deletions(-) create mode 100644 substrate/core/keyring/src/ed25519.rs create mode 100644 substrate/core/keyring/src/sr25519.rs create mode 100644 substrate/core/primitives/src/sr25519.rs diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index b579763b98..10caf9a3d4 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -707,6 +707,18 @@ dependencies = [ "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ed25519-dalek" +version = "1.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "either" version = "1.5.0" @@ -1226,6 +1238,11 @@ dependencies = [ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "keccak-hasher" version = "0.11.0" @@ -1735,6 +1752,18 @@ name = "memory_units" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "merlin" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mime" version = "0.2.6" @@ -2749,6 +2778,22 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "schnorrkel" +version = "0.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scoped-tls" version = "0.1.2" @@ -2866,6 +2911,18 @@ dependencies = [ "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sha3" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "shell32-sys" version = "0.1.2" @@ -3916,10 +3973,13 @@ dependencies = [ "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", "substrate-serializer 0.1.0", "twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4994,6 +5054,7 @@ dependencies = [ "checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" "checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" "checksum ed25519-dalek 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cd66d8a16ef71c23cf5eeb2140d8d3cd293457c6c7fd6804b593397a933fcf1e" +"checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88d4851b005ef16de812ea9acdb7bece2f0a40dd86c07b85631d7dafa54537bb" "checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e" @@ -5052,6 +5113,7 @@ dependencies = [ "checksum jsonrpc-pubsub 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56608ed54b1b2a69f4357cb8bdfbcbd99fe1179383c03a09bb428931bd35f592" "checksum jsonrpc-server-utils 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5521613b31ea22d36d9f95ad642058dccec846a94ed8690957652d479f620707" "checksum jsonrpc-ws-server 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20b8333a5a6e6ccbcf5c90f90919de557cba4929efa164e9bd0e8e497eb20e46" +"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum keccak-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb9d3670023f4c04153d90b8a557a822d1b27ed702bb015a87cf7bffead5b611" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" @@ -5094,6 +5156,7 @@ dependencies = [ "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum memory-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94da53143d45f6bad3753f532e56ad57a6a26c0ca6881794583310c7cb4c885f" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +"checksum merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a9e97b439f6d38cbe2a4a4aa93f6770c5305f62761b78b1851406c09c87ee2a" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" @@ -5188,6 +5251,7 @@ dependencies = [ "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" +"checksum schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe554f318830b48e5da8ab1ccb1ffd02b79228364dac7766b7cd1ec461ca5116" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaccd3a23619349e0878d9a241f34b1982343cdf67367058cd7d078d326b63e" @@ -5202,6 +5266,7 @@ dependencies = [ "checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34a5e54083ce2b934bf059fdf38e7330a154177e029ab6c4e18638f2f624053a" "checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" diff --git a/substrate/core/executor/src/wasm_executor.rs b/substrate/core/executor/src/wasm_executor.rs index a45c0ea39f..200403873f 100644 --- a/substrate/core/executor/src/wasm_executor.rs +++ b/substrate/core/executor/src/wasm_executor.rs @@ -28,7 +28,7 @@ use wasmi::memory_units::{Pages}; use state_machine::Externalities; use crate::error::{Error, ErrorKind, Result}; use crate::wasm_utils::UserError; -use primitives::{blake2_256, twox_128, twox_256, ed25519}; +use primitives::{blake2_256, twox_128, twox_256, ed25519, sr25519}; use primitives::hexdisplay::HexDisplay; use primitives::sandbox as sandbox_primitives; use primitives::{H256, Blake2Hasher}; @@ -480,6 +480,19 @@ 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 => { + let mut sig = [0u8; 64]; + this.memory.get_into(sig_data, &mut sig[..]).map_err(|_| UserError("Invalid attempt to get signature in ext_sr25519_verify"))?; + let mut pubkey = [0u8; 32]; + this.memory.get_into(pubkey_data, &mut pubkey[..]).map_err(|_| UserError("Invalid attempt to get pubkey in ext_sr25519_verify"))?; + let msg = this.memory.get(msg_data, msg_len as usize).map_err(|_| UserError("Invalid attempt to get message in ext_sr25519_verify"))?; + + Ok(if sr25519::verify(&sig, &msg, &pubkey) { + 0 + } else { + 5 + }) + }, 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[..]).map_err(|_| UserError("Invalid attempt to get signature in ext_secp256k1_ecdsa_recover"))?; @@ -884,6 +897,32 @@ mod tests { ); } + #[test] + fn sr25519_verify_should_work() { + let mut ext = TestExternalities::::default(); + let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm"); + let key = sr25519::Pair::from_seed(&blake2_256(b"test")); + let sig = key.sign(b"all ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(sig.as_ref()); + + assert_eq!( + WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata).unwrap(), + vec![1] + ); + + let other_sig = key.sign(b"all is not ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(other_sig.as_ref()); + + assert_eq!( + WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata).unwrap(), + vec![0] + ); + } + #[test] fn enumerated_trie_root_should_work() { let mut ext = TestExternalities::::default(); @@ -893,6 +932,4 @@ mod tests { ordered_trie_root::(vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()].iter()).as_fixed_bytes().encode() ); } - - } diff --git a/substrate/core/executor/wasm/src/lib.rs b/substrate/core/executor/wasm/src/lib.rs index 7d4f1b6f81..dda9c61733 100644 --- a/substrate/core/executor/wasm/src/lib.rs +++ b/substrate/core/executor/wasm/src/lib.rs @@ -8,7 +8,7 @@ use alloc::slice; use runtime_io::{ set_storage, storage, clear_prefix, print, blake2_256, - twox_128, twox_256, ed25519_verify, enumerated_trie_root + twox_128, twox_256, ed25519_verify, sr25519_verify, enumerated_trie_root }; macro_rules! impl_stubs { @@ -80,6 +80,16 @@ impl_stubs!( let msg = b"all ok!"; [ed25519_verify(&sig, &msg[..], &pubkey) as u8].to_vec() }, + test_sr25519_verify => |input: &[u8]| { + let mut pubkey = [0; 32]; + let mut sig = [0; 64]; + + pubkey.copy_from_slice(&input[0..32]); + sig.copy_from_slice(&input[32..96]); + + let msg = b"all ok!"; + [sr25519_verify(&sig, &msg[..], &pubkey) as u8].to_vec() + }, test_enumerated_trie_root => |_| { enumerated_trie_root::(&[&b"zero"[..], &b"one"[..], &b"two"[..]]).to_vec() }, diff --git a/substrate/core/keyring/src/ed25519.rs b/substrate/core/keyring/src/ed25519.rs new file mode 100644 index 0000000000..267da3995c --- /dev/null +++ b/substrate/core/keyring/src/ed25519.rs @@ -0,0 +1,173 @@ +// Copyright 2017-2018 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 . + +//! Support code for the runtime. A set of test accounts. + +use std::collections::HashMap; +use std::ops::Deref; +use lazy_static::lazy_static; +use hex_literal::{hex, hex_impl}; +use substrate_primitives::ed25519::{Pair, Public, Signature}; +pub use substrate_primitives::ed25519; + +/// Set of test accounts. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum Keyring { + Alice, + Bob, + Charlie, + Dave, + Eve, + Ferdie, + One, + Two, +} + +impl Keyring { + pub fn from_public(who: Public) -> Option { + [ + 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) + } + + pub fn from_raw_public(who: [u8; 32]) -> Option { + Self::from_public(Public::from_raw(who)) + } + + pub fn to_raw_public(self) -> [u8; 32] { + *Public::from(self).as_array_ref() + } + + pub fn to_raw_public_vec(self) -> Vec { + Public::from(self).to_raw_vec() + } + + pub fn sign(self, msg: &[u8]) -> Signature { + Pair::from(self).sign(msg) + } + + pub fn pair(self) -> Pair { + match self { + Keyring::Alice => Pair::from_seed(b"Alice "), + Keyring::Bob => Pair::from_seed(b"Bob "), + Keyring::Charlie => Pair::from_seed(b"Charlie "), + Keyring::Dave => Pair::from_seed(b"Dave "), + Keyring::Eve => Pair::from_seed(b"Eve "), + Keyring::Ferdie => Pair::from_seed(b"Ferdie "), + Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"), + Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")), + } + } +} + +impl From for &'static str { + fn from(k: Keyring) -> Self { + match k { + Keyring::Alice => "Alice", + Keyring::Bob => "Bob", + Keyring::Charlie => "Charlie", + Keyring::Dave => "Dave", + Keyring::Eve => "Eve", + Keyring::Ferdie => "Ferdie", + Keyring::One => "one", + Keyring::Two => "two", + } + } +} + +lazy_static! { + static ref PRIVATE_KEYS: HashMap = { + [ + Keyring::Alice, + Keyring::Bob, + Keyring::Charlie, + Keyring::Dave, + Keyring::Eve, + Keyring::Ferdie, + Keyring::One, + Keyring::Two, + ].iter().map(|&i| (i, i.pair())).collect() + }; + + static ref PUBLIC_KEYS: HashMap = { + PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect() + }; +} + +impl From for Public { + fn from(k: Keyring) -> Self { + (*PUBLIC_KEYS).get(&k).unwrap().clone() + } +} + +impl From for Pair { + fn from(k: Keyring) -> Self { + k.pair() + } +} + +impl From for [u8; 32] { + fn from(k: Keyring) -> Self { + *(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() + } +} + +impl From for &'static [u8; 32] { + fn from(k: Keyring) -> Self { + (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() + } +} + +impl AsRef<[u8; 32]> for Keyring { + fn as_ref(&self) -> &[u8; 32] { + (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() + } +} + +impl AsRef for Keyring { + fn as_ref(&self) -> &Public { + (*PUBLIC_KEYS).get(self).unwrap() + } +} + +impl Deref for Keyring { + type Target = [u8; 32]; + fn deref(&self) -> &[u8; 32] { + (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ed25519::Verifiable; + + #[test] + fn should_work() { + assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Alice)); + assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", Keyring::Alice)); + assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Bob)); + } +} diff --git a/substrate/core/keyring/src/lib.rs b/substrate/core/keyring/src/lib.rs index 267da3995c..aa271d8189 100644 --- a/substrate/core/keyring/src/lib.rs +++ b/substrate/core/keyring/src/lib.rs @@ -16,158 +16,13 @@ //! Support code for the runtime. A set of test accounts. -use std::collections::HashMap; -use std::ops::Deref; -use lazy_static::lazy_static; -use hex_literal::{hex, hex_impl}; -use substrate_primitives::ed25519::{Pair, Public, Signature}; -pub use substrate_primitives::ed25519; +/// Test account crypto for sr25519. +pub mod sr25519; -/// Set of test accounts. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub enum Keyring { - Alice, - Bob, - Charlie, - Dave, - Eve, - Ferdie, - One, - Two, -} +/// Test account crypto for ed25519. +pub mod ed25519; -impl Keyring { - pub fn from_public(who: Public) -> Option { - [ - 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) - } - - pub fn from_raw_public(who: [u8; 32]) -> Option { - Self::from_public(Public::from_raw(who)) - } - - pub fn to_raw_public(self) -> [u8; 32] { - *Public::from(self).as_array_ref() - } - - pub fn to_raw_public_vec(self) -> Vec { - Public::from(self).to_raw_vec() - } - - pub fn sign(self, msg: &[u8]) -> Signature { - Pair::from(self).sign(msg) - } - - pub fn pair(self) -> Pair { - match self { - Keyring::Alice => Pair::from_seed(b"Alice "), - Keyring::Bob => Pair::from_seed(b"Bob "), - Keyring::Charlie => Pair::from_seed(b"Charlie "), - Keyring::Dave => Pair::from_seed(b"Dave "), - Keyring::Eve => Pair::from_seed(b"Eve "), - Keyring::Ferdie => Pair::from_seed(b"Ferdie "), - Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"), - Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")), - } - } -} - -impl From for &'static str { - fn from(k: Keyring) -> Self { - match k { - Keyring::Alice => "Alice", - Keyring::Bob => "Bob", - Keyring::Charlie => "Charlie", - Keyring::Dave => "Dave", - Keyring::Eve => "Eve", - Keyring::Ferdie => "Ferdie", - Keyring::One => "one", - Keyring::Two => "two", - } - } -} - -lazy_static! { - static ref PRIVATE_KEYS: HashMap = { - [ - Keyring::Alice, - Keyring::Bob, - Keyring::Charlie, - Keyring::Dave, - Keyring::Eve, - Keyring::Ferdie, - Keyring::One, - Keyring::Two, - ].iter().map(|&i| (i, i.pair())).collect() - }; - - static ref PUBLIC_KEYS: HashMap = { - PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect() - }; -} - -impl From for Public { - fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).unwrap().clone() - } -} - -impl From for Pair { - fn from(k: Keyring) -> Self { - k.pair() - } -} - -impl From for [u8; 32] { - fn from(k: Keyring) -> Self { - *(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() - } -} - -impl From for &'static [u8; 32] { - fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() - } -} - -impl AsRef<[u8; 32]> for Keyring { - fn as_ref(&self) -> &[u8; 32] { - (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() - } -} - -impl AsRef for Keyring { - fn as_ref(&self) -> &Public { - (*PUBLIC_KEYS).get(self).unwrap() - } -} - -impl Deref for Keyring { - type Target = [u8; 32]; - fn deref(&self) -> &[u8; 32] { - (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ed25519::Verifiable; - - #[test] - fn should_work() { - assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Alice)); - assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", Keyring::Alice)); - assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Bob)); - } -} +/// The Ed25519 keyring. +/// +/// This is deprecated: use `ed25519::Keyring` instead. +pub use ed25519::Keyring; diff --git a/substrate/core/keyring/src/sr25519.rs b/substrate/core/keyring/src/sr25519.rs new file mode 100644 index 0000000000..0142ab56f2 --- /dev/null +++ b/substrate/core/keyring/src/sr25519.rs @@ -0,0 +1,173 @@ +// Copyright 2017-2018 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 . + +//! Support code for the runtime. A set of test accounts. + +use std::collections::HashMap; +use std::ops::Deref; +use lazy_static::lazy_static; +use hex_literal::{hex, hex_impl}; +use substrate_primitives::sr25519::{Pair, Public, Signature}; +pub use substrate_primitives::sr25519; + +/// Set of test accounts. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum Keyring { + Alice, + Bob, + Charlie, + Dave, + Eve, + Ferdie, + One, + Two, +} + +impl Keyring { + pub fn from_public(who: Public) -> Option { + [ + 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) + } + + pub fn from_raw_public(who: [u8; 32]) -> Option { + Self::from_public(Public::from_raw(who)) + } + + pub fn to_raw_public(self) -> [u8; 32] { + *Public::from(self).as_array_ref() + } + + pub fn to_raw_public_vec(self) -> Vec { + Public::from(self).to_raw_vec() + } + + pub fn sign(self, msg: &[u8]) -> Signature { + Pair::from(self).sign(msg) + } + + pub fn pair(self) -> Pair { + match self { + Keyring::Alice => Pair::from_seed(b"Alice "), + Keyring::Bob => Pair::from_seed(b"Bob "), + Keyring::Charlie => Pair::from_seed(b"Charlie "), + Keyring::Dave => Pair::from_seed(b"Dave "), + Keyring::Eve => Pair::from_seed(b"Eve "), + Keyring::Ferdie => Pair::from_seed(b"Ferdie "), + Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"), + Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")), + } + } +} + +impl From for &'static str { + fn from(k: Keyring) -> Self { + match k { + Keyring::Alice => "Alice", + Keyring::Bob => "Bob", + Keyring::Charlie => "Charlie", + Keyring::Dave => "Dave", + Keyring::Eve => "Eve", + Keyring::Ferdie => "Ferdie", + Keyring::One => "one", + Keyring::Two => "two", + } + } +} + +lazy_static! { + static ref PRIVATE_KEYS: HashMap = { + [ + Keyring::Alice, + Keyring::Bob, + Keyring::Charlie, + Keyring::Dave, + Keyring::Eve, + Keyring::Ferdie, + Keyring::One, + Keyring::Two, + ].iter().map(|&i| (i, i.pair())).collect() + }; + + static ref PUBLIC_KEYS: HashMap = { + PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect() + }; +} + +impl From for Public { + fn from(k: Keyring) -> Self { + (*PUBLIC_KEYS).get(&k).unwrap().clone() + } +} + +impl From for Pair { + fn from(k: Keyring) -> Self { + k.pair() + } +} + +impl From for [u8; 32] { + fn from(k: Keyring) -> Self { + *(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() + } +} + +impl From for &'static [u8; 32] { + fn from(k: Keyring) -> Self { + (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() + } +} + +impl AsRef<[u8; 32]> for Keyring { + fn as_ref(&self) -> &[u8; 32] { + (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() + } +} + +impl AsRef for Keyring { + fn as_ref(&self) -> &Public { + (*PUBLIC_KEYS).get(self).unwrap() + } +} + +impl Deref for Keyring { + type Target = [u8; 32]; + fn deref(&self) -> &[u8; 32] { + (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sr25519::Verifiable; + + #[test] + fn should_work() { + assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Alice)); + assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", Keyring::Alice)); + assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Bob)); + } +} diff --git a/substrate/core/primitives/Cargo.toml b/substrate/core/primitives/Cargo.toml index ed380f8ade..2cc687fdb5 100644 --- a/substrate/core/primitives/Cargo.toml +++ b/substrate/core/primitives/Cargo.toml @@ -23,6 +23,9 @@ untrusted = { version = "0.6", optional = true } hex-literal = { version = "0.1", optional = true } base58 = { version = "0.1", optional = true } blake2-rfc = { version = "0.2.18", optional = true } +schnorrkel = { version = "0.0", optional = true } +rand = { version = "0.6", optional = true } +sha2 = { version = "0.8", optional = true } [dev-dependencies] substrate-serializer = { path = "../serializer" } @@ -54,4 +57,7 @@ std = [ "base58", "serde_derive", "byteorder/std", + "rand", + "sha2", + "schnorrkel", ] diff --git a/substrate/core/primitives/src/lib.rs b/substrate/core/primitives/src/lib.rs index e52d7b9490..cb1f722043 100644 --- a/substrate/core/primitives/src/lib.rs +++ b/substrate/core/primitives/src/lib.rs @@ -51,6 +51,8 @@ pub use hashing::{blake2_256, twox_128, twox_256}; pub mod hexdisplay; #[cfg(feature = "std")] pub mod ed25519; +#[cfg(feature = "std")] +pub mod sr25519; pub mod u32_trait; diff --git a/substrate/core/primitives/src/sr25519.rs b/substrate/core/primitives/src/sr25519.rs new file mode 100644 index 0000000000..842de7c682 --- /dev/null +++ b/substrate/core/primitives/src/sr25519.rs @@ -0,0 +1,336 @@ +// Copyright 2017-2018 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 . + +// tag::description[] +//! Simple sr25519 (Schnorr-Ristretto) API. +// end::description[] + +use base58::{FromBase58, ToBase58}; +use blake2_rfc; +use rand::rngs::OsRng; +use schnorrkel::{signing_context, Keypair, MiniSecretKey, PublicKey}; +use sha2::Sha512; +use parity_codec_derive::{Encode, Decode}; +use crate::hash::H512; + +#[cfg(feature = "std")] +use serde::{de, Deserialize, Deserializer, Serializer}; + +// signing context +const SIGNING_CTX: &'static [u8] = b"substrate transaction"; + +/// Instead of importing it for the local module, alias it to be available as a public type +pub type Signature = H512; + +/// A localized signature also contains sender information. +/// NOTE: Encode and Decode traits are supported in ed25519 but not possible for now here. +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct LocalizedSignature { + /// The signer of the signature. + pub signer: Public, + /// The signature itself. + pub signature: Signature, +} + +/// A public key. +#[derive(PartialEq, Eq, Clone, Encode, Decode)] +pub struct Public(pub [u8; 32]); + +/// A schnorrkel key pair. +pub struct Pair(Keypair); + +impl ::std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +/// An error type for SS58 decoding. +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum PublicError { + /// Bad alphabet. + BadBase58, + /// Bad length. + BadLength, + /// Unknown version. + UnknownVersion, + /// Invalid checksum. + InvalidChecksum, +} + +impl Public { + /// A new instance from the given 32-byte `data`. + pub fn from_raw(data: [u8; 32]) -> Self { + Public(data) + } + + /// A new instance from the given slice that should be 32 bytes long. + pub fn from_slice(data: &[u8]) -> Self { + let mut r = [0u8; 32]; + r.copy_from_slice(data); + Public(r) + } + + /// Some if the string is a properly encoded SS58Check address. + pub fn from_ss58check(s: &str) -> Result { + let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding. + if d.len() != 35 { + // Invalid length. + return Err(PublicError::BadLength); + } + if d[0] != 42 { + // Invalid version. + return Err(PublicError::UnknownVersion); + } + if d[33..35] != blake2_rfc::blake2b::blake2b(64, &[], &d[0..33]).as_bytes()[0..2] { + // Invalid checksum. + return Err(PublicError::InvalidChecksum); + } + Ok(Self::from_slice(&d[1..33])) + } + + /// Return a `Vec` filled with raw data. + pub fn to_raw_vec(self) -> Vec { + let r: &[u8; 32] = self.as_ref(); + r.to_vec() + } + + /// Return a slice filled with raw data. + pub fn as_slice(&self) -> &[u8] { + let r: &[u8; 32] = self.as_ref(); + &r[..] + } + + /// Return a slice filled with raw data. + pub fn as_array_ref(&self) -> &[u8; 32] { + self.as_ref() + } + + /// Return the ss58-check string for this key. + pub fn to_ss58check(&self) -> String { + let mut v = vec![42u8]; + v.extend(self.as_slice()); + let r = blake2_rfc::blake2b::blake2b(64, &[], &v); + v.extend(&r.as_bytes()[0..2]); + v.to_base58() + } +} + +impl AsRef<[u8; 32]> for Public { + fn as_ref(&self) -> &[u8; 32] { + &self.0 + } +} + +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl Into<[u8; 32]> for Public { + fn into(self) -> [u8; 32] { + self.0 + } +} + +impl AsRef for Public { + fn as_ref(&self) -> &Public { + &self + } +} + +impl AsRef for Pair { + fn as_ref(&self) -> &Pair { + &self + } +} + +impl ::std::fmt::Display for Public { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +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]) + } +} + +impl Pair { + /// Generate new secure (random) key pair. + pub fn generate() -> Pair { + let mut csprng: OsRng = OsRng::new().expect("os random generator works; qed"); + let keypair: Keypair = Keypair::generate(&mut csprng); + Pair(keypair) + } + + /// Make a new key pair from a seed phrase. + /// This is generated using schnorrkel's Mini-Secret-Keys. + /// A MiniSecretKey is literally what Ed25519 calls a SecretKey, which is just 32 random bytes. + pub fn from_seed(seed: &[u8; 32]) -> Pair { + let mini_key: MiniSecretKey = MiniSecretKey::from_bytes(seed) + .expect("32 bytes can always build a key; qed"); + let kp = mini_key.expand_to_keypair::(); + Pair(kp) + } + + /// Sign a message. + pub fn sign(&self, message: &[u8]) -> Signature { + let context = signing_context(SIGNING_CTX); + Signature::from(self.0.sign(context.bytes(message)).to_bytes()) + } + + /// Get the public key. + pub fn public(&self) -> Public { + let mut pk = [0u8; 32]; + pk.copy_from_slice(&self.0.public.to_bytes()); + Public(pk) + } +} + +/// Verify a signature on a message. Returns true if the signature is good. +pub fn verify_strong>(sig: &Signature, message: &[u8], pubkey: P) -> bool { + let signature: schnorrkel::Signature = match schnorrkel::Signature::from_bytes(&sig[..]) { + Ok(some_signature) => some_signature, + Err(_) => return false + }; + match PublicKey::from_bytes(pubkey.as_ref().as_slice()) { + Ok(pk) => pk.verify(signing_context(SIGNING_CTX).bytes(message), &signature), + Err(_) => false, + } +} + +/// Verify a message without type checking the parameters' types for the right size. +/// Returns true if both the pubkey and the signature is good. +pub fn verify>(sig: &[u8], message: &[u8], pubkey: P) -> bool { + let signature = match schnorrkel::Signature::from_bytes(&sig[..]) { + Ok(sig) => sig, + Err(_) => return false, + }; + match PublicKey::from_bytes(pubkey.as_ref()) { + Ok(pk) => pk.verify_simple(SIGNING_CTX, message, &signature), + Err(_) => false, + } +} + +/// Something that acts as a signature allowing a message to be verified. +pub trait Verifiable { + /// Verify something that acts like a signature. + fn verify>(&self, message: &[u8], pubkey: P) -> bool; +} + +impl Verifiable for Signature { + /// Verify something that acts like a signature. + fn verify>(&self, message: &[u8], pubkey: P) -> bool { + verify_strong(&self, message, pubkey) + } +} + +impl Verifiable for LocalizedSignature { + fn verify>(&self, message: &[u8], pubkey: P) -> bool { + pubkey.as_ref() == &self.signer && self.signature.verify(message, pubkey) + } +} + +/// Deserialize from `ss58` into something that can be constructed from `[u8; 32]`. +#[cfg(feature = "std")] +pub fn deserialize<'de, D, T: From<[u8; 32]>>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let ss58 = String::deserialize(deserializer)?; + Public::from_ss58check(&ss58) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + .map(|v| v.0.into()) +} + +/// Serializes something that implements `AsRef<[u8; 32]>` into `ss58`. +#[cfg(feature = "std")] +pub fn serialize>(data: &T, serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_str(&Public(*data.as_ref()).to_ss58check()) +} + +#[cfg(test)] +mod test { + use super::*; + use hex_literal::{hex, hex_impl}; + + #[test] + fn sr_test_vector_should_work() { + let pair: Pair = Pair::from_seed(&hex!( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + )); + let public = pair.public(); + assert_eq!( + public, + Public::from_raw(hex!( + "44a996beb1eef7bdcab976ab6d2ca26104834164ecf28fb375600576fcc6eb0f" + )) + ); + let message = b""; + let signature = pair.sign(message); + assert!(verify(&signature[..], message, &public.0)); + assert!(verify_strong(&signature, &message[..], &public)); + } + + #[test] + fn generated_pair_should_work() { + let pair = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(verify_strong(&signature, &message[..], &public)); + } + + #[test] + fn seeded_pair_should_work() { + + let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let public = pair.public(); + assert_eq!( + public, + Public::from_raw(hex!( + "741c08a06f41c596608f6774259bd9043304adfa5d3eea62760bd9be97634d63" + )) + ); + let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let signature = pair.sign(&message[..]); + assert!(verify_strong(&signature, &message[..], &public)); + } + + #[test] + fn ss58check_roundtrip_works() { + let pair = Pair::generate(); + let public = pair.public(); + let s = public.to_ss58check(); + println!("Correct: {}", s); + let cmp = Public::from_ss58check(&s).unwrap(); + assert_eq!(cmp, public); + } + + #[test] + fn ss58check_known_works() { + let k = "5CGavy93sZgPPjHyziRohwVumxiHXMGmQLyuqQP4ZFx5vRU9"; + let enc = hex!["090fa15cb5b1666222fff584b4cc2b1761fe1e238346b340491b37e25ea183ff"]; + assert_eq!(Public::from_ss58check(k).unwrap(), Public::from_raw(enc)); + } +} diff --git a/substrate/core/sr-io/with_std.rs b/substrate/core/sr-io/with_std.rs index de942c2d3b..562e349ced 100644 --- a/substrate/core/sr-io/with_std.rs +++ b/substrate/core/sr-io/with_std.rs @@ -17,7 +17,7 @@ #[doc(hidden)] pub use parity_codec as codec; // re-export hashing functions. -pub use primitives::{blake2_256, twox_128, twox_256, ed25519, Blake2Hasher}; +pub use primitives::{blake2_256, twox_128, twox_256, ed25519, Blake2Hasher, sr25519}; pub use tiny_keccak::keccak256 as keccak_256; // Switch to this after PoC-3 // pub use primitives::BlakeHasher; @@ -189,6 +189,11 @@ pub fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> ed25519::verify(sig, msg, pubkey) } +/// Verify an sr25519 signature. +pub fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { + sr25519::verify(sig, msg, pubkey) +} + /// Verify and recover a SECP256k1 ECDSA signature. /// - `sig` is passed in RSV format. V should be either 0/1 or 27/28. /// - returns `Err` if the signatue is bad, otherwise the 64-byte pubkey (doesn't include the 0x04 prefix). diff --git a/substrate/core/sr-io/without_std.rs b/substrate/core/sr-io/without_std.rs index cc844845cf..5687812830 100644 --- a/substrate/core/sr-io/without_std.rs +++ b/substrate/core/sr-io/without_std.rs @@ -89,6 +89,8 @@ extern "C" { 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. fn ext_ed25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32; + /// 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) -> 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) -> u32; } @@ -371,6 +373,13 @@ pub fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> } } +/// Verify a sr25519 signature. +pub fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { + unsafe { + ext_sr25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0 + } +} + /// Verify and recover a SECP256k1 ECDSA signature. /// - `sig` is passed in RSV format. V should be either 0/1 or 27/28. /// - returns `None` if the signatue is bad, the 64-byte pubkey (doesn't include the 0x04 prefix). diff --git a/substrate/core/sr-primitives/src/lib.rs b/substrate/core/sr-primitives/src/lib.rs index c315839bbf..39a7cfbac3 100644 --- a/substrate/core/sr-primitives/src/lib.rs +++ b/substrate/core/sr-primitives/src/lib.rs @@ -266,6 +266,24 @@ impl From for Ed25519Signature { } } +/// Sr25519 signature verify. +#[derive(Eq, PartialEq, Clone, Default, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +pub struct Sr25519Signature(pub H512); + +impl Verify for Sr25519Signature { + type Signer = H256; + fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { + runtime_io::sr25519_verify((self.0).as_fixed_bytes(), msg.get(), &signer.as_bytes()) + } +} + +impl From for Sr25519Signature { + fn from(h: H512) -> Sr25519Signature { + Sr25519Signature(h) + } +} + /// Context for executing a call into the runtime. #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Serialize))] diff --git a/substrate/core/test-runtime/wasm/Cargo.lock b/substrate/core/test-runtime/wasm/Cargo.lock index 0a2599c010..984755fc82 100644 --- a/substrate/core/test-runtime/wasm/Cargo.lock +++ b/substrate/core/test-runtime/wasm/Cargo.lock @@ -62,11 +62,35 @@ dependencies = [ "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "block-buffer" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-padding" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "byte-tools" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.2.7" @@ -101,6 +125,14 @@ dependencies = [ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "clear_on_drop" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -168,6 +200,18 @@ dependencies = [ "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "curve25519-dalek" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "digest" version = "0.6.2" @@ -176,6 +220,26 @@ dependencies = [ "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "digest" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "elastic-array" version = "0.10.0" @@ -197,6 +261,11 @@ dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fake-simd" version = "0.1.2" @@ -261,6 +330,14 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "generic-array" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hash-db" version = "0.11.0" @@ -370,6 +447,11 @@ name = "itoa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -462,6 +544,18 @@ name = "memory_units" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "merlin" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mio" version = "0.6.16" @@ -553,6 +647,11 @@ name = "once_cell" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "opaque-debug" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "openssl" version = "0.10.16" @@ -882,6 +981,22 @@ name = "ryu" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "schnorrkel" +version = "0.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scopeguard" version = "0.3.3" @@ -942,6 +1057,29 @@ dependencies = [ "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sha2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha3" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slab" version = "0.4.1" @@ -1250,10 +1388,13 @@ dependencies = [ "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", "twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1340,6 +1481,11 @@ dependencies = [ "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "subtle" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "0.15.22" @@ -1713,12 +1859,16 @@ dependencies = [ "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" +"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" +"checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" +"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" @@ -1728,10 +1878,14 @@ dependencies = [ "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" "checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" +"checksum curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dae47cc3529cdab597dbc8b606e565707209b506e55848f3c15679214a56c956" "checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" +"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86" "checksum elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88d4851b005ef16de812ea9acdb7bece2f0a40dd86c07b85631d7dafa54537bb" "checksum environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db746025e3ea695bfa0ae744dbacd5fcfc8db51b9760cf8bd0ab69708bb93c49" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fixed-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a557e80084b05c32b455963ff565a9de6f2866da023d6671705c6aff6f65e01c" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" @@ -1740,6 +1894,7 @@ dependencies = [ "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fceb69994e330afed50c93524be68c42fa898c2d9fd4ee8da03bd7363acd26f2" "checksum hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b03501f6e1a2a97f1618879aba3156f14ca2847faa530c4e28859638bd11483" "checksum hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5c13dbac3cc50684760f54af18545c9e80fb75e93a3e586d71ebdc13138f6a4" @@ -1755,6 +1910,7 @@ dependencies = [ "checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" @@ -1768,6 +1924,7 @@ dependencies = [ "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum memory-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94da53143d45f6bad3753f532e56ad57a6a26c0ca6881794583310c7cb4c885f" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +"checksum merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a9e97b439f6d38cbe2a4a4aa93f6770c5305f62761b78b1851406c09c87ee2a" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" @@ -1778,6 +1935,7 @@ dependencies = [ "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d7ce3535d54560c937c1652ba4a0da66bfc63e0f8e07bed127483afb6e5ee925" +"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" "checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" "checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" @@ -1816,6 +1974,7 @@ dependencies = [ "checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" +"checksum schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe554f318830b48e5da8ab1ccb1ffd02b79228364dac7766b7cd1ec461ca5116" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -1824,6 +1983,8 @@ dependencies = [ "checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" +"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34a5e54083ce2b934bf059fdf38e7330a154177e029ab6c4e18638f2f624053a" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" "checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" "checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" @@ -1833,6 +1994,7 @@ dependencies = [ "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" +"checksum subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" "checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" diff --git a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 89d3bea7073e5c11f05fce160a75933e5640cc78..9c87a2e56f621549a11f76b865f9cfe95b99f9ac 100644 GIT binary patch delta 8074 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 delta 8100 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" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" @@ -1981,6 +2137,7 @@ dependencies = [ "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum memory-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94da53143d45f6bad3753f532e56ad57a6a26c0ca6881794583310c7cb4c885f" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +"checksum merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a9e97b439f6d38cbe2a4a4aa93f6770c5305f62761b78b1851406c09c87ee2a" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" @@ -1991,6 +2148,7 @@ dependencies = [ "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" "checksum once_cell 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "53075ac5dbd2798cfbcf9f710f2737de031d8076c192d8fe66fb23f639ccbdf4" +"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" "checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" "checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" @@ -2031,6 +2189,7 @@ dependencies = [ "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" +"checksum schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe554f318830b48e5da8ab1ccb1ffd02b79228364dac7766b7cd1ec461ca5116" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -2039,6 +2198,8 @@ dependencies = [ "checksum serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "4b90a9fbe1211e57d3e1c15670f1cb00802988fb23a1a4aad7a2b63544f1920e" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" +"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34a5e54083ce2b934bf059fdf38e7330a154177e029ab6c4e18638f2f624053a" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" "checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" @@ -2048,6 +2209,7 @@ dependencies = [ "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" +"checksum subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" diff --git a/substrate/node/executor/src/lib.rs b/substrate/node/executor/src/lib.rs index 901955b59d..5810756c17 100644 --- a/substrate/node/executor/src/lib.rs +++ b/substrate/node/executor/src/lib.rs @@ -31,11 +31,12 @@ mod tests { use super::Executor; use substrate_executor::{WasmExecutor, NativeExecutionDispatch}; use parity_codec::{Encode, Decode, Joiner}; - use keyring::Keyring; + use keyring::ed25519::Keyring; use runtime_support::{Hashable, StorageValue, StorageMap, traits::Currency}; use state_machine::{CodeExecutor, Externalities, TestExternalities}; use primitives::{ - twox_128, Blake2Hasher, ChangesTrieConfiguration, ed25519::{Public, Pair}, NeverNativeValue + twox_128, Blake2Hasher, ChangesTrieConfiguration, ed25519::{Public, Pair}, NeverNativeValue, + NativeOrEncoded }; use node_primitives::{Hash, BlockNumber, AccountId}; use runtime_primitives::traits::{Header as HeaderT, Digest as DigestT, Hash as HashT}; @@ -72,10 +73,12 @@ mod tests { let era = Era::mortal(256, 0); let payload = (index.into(), xt.function, era, GENESIS_HASH); let pair = Pair::from(Keyring::from_public(Public::from_raw(signed.clone().into())).unwrap()); - let signature = payload.using_encoded(|b| if b.len() > 256 { - pair.sign(&runtime_io::blake2_256(b)) - } else { - pair.sign(b) + let signature = payload.using_encoded(|b| { + if b.len() > 256 { + pair.sign(&runtime_io::blake2_256(b)) + } else { + pair.sign(b) + } }).into(); UncheckedExtrinsic { signature: Some((indices::address::Address::Id(signed), signature, payload.0, era)), @@ -245,7 +248,6 @@ mod tests { } fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities { - use keyring::Keyring::*; let three = [3u8; 32].into(); TestExternalities::new_with_code(code, GenesisConfig { consensus: Some(Default::default()), @@ -273,12 +275,12 @@ mod tests { }), session: Some(SessionConfig { session_length: 2, - validators: vec![One.to_raw_public().into(), Two.to_raw_public().into(), three], + validators: vec![Keyring::One.to_raw_public().into(), Keyring::Two.to_raw_public().into(), three], }), staking: Some(StakingConfig { sessions_per_era: 2, current_era: 0, - intentions: vec![alice(), bob(), Charlie.to_raw_public().into()], + intentions: vec![alice(), bob(), Keyring::Charlie.to_raw_public().into()], validator_count: 3, minimum_validator_count: 0, bonding_duration: 0, @@ -287,7 +289,7 @@ mod tests { current_offline_slash: 0, current_session_reward: 0, offline_slash_grace: 0, - invulnerables: vec![alice(), bob(), Charlie.to_raw_public().into()], + invulnerables: vec![alice(), bob(), Keyring::Charlie.to_raw_public().into()], }), democracy: Some(Default::default()), council_seats: Some(Default::default()), @@ -298,66 +300,79 @@ mod tests { sudo: Some(Default::default()), grandpa: Some(GrandpaConfig { authorities: vec![ // set these so no GRANDPA events fire when session changes - (Alice.to_raw_public().into(), 1), - (Bob.to_raw_public().into(), 1), - (Charlie.to_raw_public().into(), 1), + (Keyring::Alice.to_raw_public().into(), 1), + (Keyring::Bob.to_raw_public().into(), 1), + (Keyring::Charlie.to_raw_public().into(), 1), ], }), }.build_storage().unwrap().0) } - fn changes_trie_log(changes_root: Hash) -> Log { - Log::from(system::RawLog::ChangesTrieRoot::(changes_root)) - } - fn construct_block( + env: &mut TestExternalities, number: BlockNumber, parent_hash: Hash, - state_root: Hash, - logs: Vec, - extrinsics: Vec + extrinsics: Vec, ) -> (Vec, Hash) { use trie::ordered_trie_root; + // sign extrinsics. let extrinsics = extrinsics.into_iter().map(sign).collect::>(); - let extrinsics_root = ordered_trie_root::(extrinsics.iter() - .map(Encode::encode)) - .to_fixed_bytes() - .into(); - let mut digest = generic::Digest::::default(); - for item in logs { - digest.push(item); - } + // calculate the header fields that we can. + let extrinsics_root = ordered_trie_root::( + extrinsics.iter().map(Encode::encode) + ).to_fixed_bytes() + .into(); let header = Header { parent_hash, number, - state_root, extrinsics_root, - digest, + state_root: Default::default(), + digest: Default::default(), }; - let hash = header.blake2_256(); - (Block { header, extrinsics }.encode(), hash.into()) + // execute the block to get the real header. + Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( + env, + "Core_initialise_block", + &header.encode(), + true, + None, + ).0.unwrap(); + + for i in extrinsics.iter() { + Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( + env, + "BlockBuilder_apply_extrinsic", + &i.encode(), + true, + None, + ).0.unwrap(); + } + + let mut correct_header = match Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( + env, + "BlockBuilder_finalise_block", + &[0u8;0], + true, + None, + ).0.unwrap() { + NativeOrEncoded::Native(_) => unreachable!(), + NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), + }; + + + let hash = correct_header.blake2_256(); + (Block { header: correct_header, extrinsics }.encode(), hash.into()) } - fn block1(support_changes_trie: bool) -> (Vec, Hash) { + fn changes_trie_block() -> (Vec, Hash) { construct_block( + &mut new_test_ext(COMPACT_CODE, true), 1, GENESIS_HASH.into(), - if support_changes_trie { - hex!("d8fff70a10e0a00641458190ec32ca5681e1db38c0da9c18bb5abd76b645bb84").into() - } else { - hex!("f1f00968e622ec6f47be5653b741186ef764653c82c42dab4b80d43d3226fa27").into() - }, - if support_changes_trie { - vec![changes_trie_log( - hex!("f254b62df0bfef049e010a7a0d6f176d73cc5d9710fa945b4e48f519c8d3a291").into(), - )] - } else { - vec![] - }, vec![ CheckedExtrinsic { signed: None, @@ -371,18 +386,30 @@ mod tests { ) } - fn block2() -> (Vec, Hash) { - construct_block( + // block 1 and 2 must be created together to ensure transactions are only signed once (since they + // are not guaranteed to be deterministic) and to ensure that the correct state is propagated + // from block1's execution to block2 to derive the correct storage_root. + fn blocks() -> ((Vec, Hash), (Vec, Hash)) { + let mut t = new_test_ext(COMPACT_CODE, false); + let block1 = construct_block( + &mut t, + 1, + GENESIS_HASH.into(), + vec![ + CheckedExtrinsic { + signed: None, + function: Call::Timestamp(timestamp::Call::set(42)), + }, + CheckedExtrinsic { + signed: Some((alice(), 0)), + function: Call::Balances(balances::Call::transfer(bob().into(), 69)), + }, + ] + ); + let block2 = construct_block( + &mut t, 2, - block1(false).1, - hex!("fb05600153a562a78fe12cbbfd97aa18ddf4085505bcacbcfd1d2c0c36bba5ce").into(), - vec![ // session changes here, so we add a grandpa change signal log. - Log::from(::grandpa::RawLog::AuthoritiesChangeSignal(0, vec![ - (Keyring::One.to_raw_public().into(), 1), - (Keyring::Two.to_raw_public().into(), 1), - ([3u8; 32].into(), 1), - ])) - ], + block1.1.clone(), vec![ CheckedExtrinsic { signed: None, @@ -397,15 +424,24 @@ mod tests { function: Call::Balances(balances::Call::transfer(bob().into(), 15)), } ] - ) + ); + + let mut digest = generic::Digest::::default(); + digest.push(Log::from(::grandpa::RawLog::AuthoritiesChangeSignal(0, vec![ + (Keyring::One.to_raw_public().into(), 1), + (Keyring::Two.to_raw_public().into(), 1), + ([3u8; 32].into(), 1), + ]))); + assert_eq!(Header::decode(&mut &block2.0[..]).unwrap().digest, digest); + + (block1, block2) } - fn block1big() -> (Vec, Hash) { + fn big_block() -> (Vec, Hash) { construct_block( + &mut new_test_ext(COMPACT_CODE, false), 1, GENESIS_HASH.into(), - hex!("cd856b66ec5416b8c81d480fa7ed8b8a851afff03fc09c87920f975ae913a581").into(), - vec![], vec![ CheckedExtrinsic { signed: None, @@ -423,10 +459,12 @@ mod tests { fn full_native_block_import_works() { let mut t = new_test_ext(COMPACT_CODE, false); + let (block1, block2) = blocks(); + executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", - &block1(false).0, + &block1.0, true, None, ).0.unwrap(); @@ -446,15 +484,15 @@ mod tests { EventRecord { phase: Phase::ApplyExtrinsic(1), event: Event::balances(balances::RawEvent::NewAccount( - hex!["d7568e5f0a7eda67a82691ff379ac4bba4f9c9b859fe779b5d46363b61ad2db9"].into(), + bob().into(), 69 )) }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: Event::balances(balances::RawEvent::Transfer( - hex!["d172a74cda4c865912c32ba0a80a57ae69abae410e5ccb59dee84e2f4432db4f"].into(), - hex!["d7568e5f0a7eda67a82691ff379ac4bba4f9c9b859fe779b5d46363b61ad2db9"].into(), + alice().into(), + bob().into(), 69, 0 )) @@ -477,11 +515,11 @@ mod tests { } ]); }); - + executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", - &block2().0, + &block2.0, true, None, ).0.unwrap(); @@ -498,8 +536,8 @@ mod tests { phase: Phase::ApplyExtrinsic(1), event: Event::balances( balances::RawEvent::Transfer( - hex!["d7568e5f0a7eda67a82691ff379ac4bba4f9c9b859fe779b5d46363b61ad2db9"].into(), - hex!["d172a74cda4c865912c32ba0a80a57ae69abae410e5ccb59dee84e2f4432db4f"].into(), + bob().into(), + alice().into(), 5, 0 ) @@ -513,8 +551,8 @@ mod tests { phase: Phase::ApplyExtrinsic(2), event: Event::balances( balances::RawEvent::Transfer( - hex!["d172a74cda4c865912c32ba0a80a57ae69abae410e5ccb59dee84e2f4432db4f"].into(), - hex!["d7568e5f0a7eda67a82691ff379ac4bba4f9c9b859fe779b5d46363b61ad2db9"].into(), + alice().into(), + bob().into(), 15, 0 ) @@ -560,14 +598,16 @@ mod tests { fn full_wasm_block_import_works() { let mut t = new_test_ext(COMPACT_CODE, false); - WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(false).0).unwrap(); + let (block1, block2) = blocks(); + + WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0).unwrap(); runtime_io::with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 41); assert_eq!(Balances::total_balance(&bob()), 69); }); - WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2().0).unwrap(); + WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2.0).unwrap(); runtime_io::with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 30); @@ -661,7 +701,6 @@ mod tests { #[test] fn deploying_wasm_contract_should_work() { - let mut t = new_test_ext(COMPACT_CODE, false); let transfer_code = wabt::wat2wasm(CODE_TRANSFER).unwrap(); let transfer_ch = ::Hashing::hash(&transfer_code); @@ -673,10 +712,9 @@ mod tests { ); let b = construct_block( + &mut new_test_ext(COMPACT_CODE, false), 1, GENESIS_HASH.into(), - hex!("2c024da59dcdb62f43669081355830f074c32b3bddab7aebd8bcab14d24353b7").into(), - vec![], vec![ CheckedExtrinsic { signed: None, @@ -703,6 +741,8 @@ mod tests { ] ); + let mut t = new_test_ext(COMPACT_CODE, false); + WasmExecutor::new().call(&mut t, 8, COMPACT_CODE,"Core_execute_block", &b.0).unwrap(); runtime_io::with_externalities(&mut t, || { @@ -721,7 +761,7 @@ mod tests { 8, COMPACT_CODE, "Core_execute_block", - &block1big().0 + &big_block().0 ).is_err() ); } @@ -733,7 +773,7 @@ mod tests { Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", - &block1big().0, + &big_block().0, true, None, ).0.unwrap(); @@ -747,7 +787,7 @@ mod tests { Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", - &block1big().0, + &big_block().0, false, None, ).0.is_err() @@ -805,11 +845,15 @@ mod tests { #[test] fn full_native_block_import_works_with_changes_trie() { + let block1 = changes_trie_block(); + let block_data = block1.0; + let block = Block::decode(&mut &block_data[..]).unwrap(); + let mut t = new_test_ext(COMPACT_CODE, true); Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", - &block1(true).0, + &block.encode(), true, None, ).0.unwrap(); @@ -819,8 +863,10 @@ mod tests { #[test] fn full_wasm_block_import_works_with_changes_trie() { + let block1 = changes_trie_block(); + let mut t = new_test_ext(COMPACT_CODE, true); - WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(true).0).unwrap(); + WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0).unwrap(); assert!(t.storage_changes_root(Default::default(), 0).is_some()); } @@ -832,10 +878,12 @@ mod tests { #[bench] fn wasm_execute_block(b: &mut Bencher) { + let (block1, block2) = blocks(); + b.iter(|| { let mut t = new_test_ext(COMPACT_CODE, false); - WasmExecutor::new().call(&mut t, "Core_execute_block", &block1(false).0).unwrap(); - WasmExecutor::new().call(&mut t, "Core_execute_block", &block2().0).unwrap(); + WasmExecutor::new().call(&mut t, "Core_execute_block", &block1.0).unwrap(); + WasmExecutor::new().call(&mut t, "Core_execute_block", &block2.0).unwrap(); }); } } diff --git a/substrate/node/primitives/src/lib.rs b/substrate/node/primitives/src/lib.rs index 36ed33cb92..4c72239e6d 100644 --- a/substrate/node/primitives/src/lib.rs +++ b/substrate/node/primitives/src/lib.rs @@ -21,15 +21,19 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc))] -use runtime_primitives::generic; -use runtime_primitives::{OpaqueExtrinsic, traits::BlakeTwo256}; +use runtime_primitives::{ + generic, traits::{Verify, BlakeTwo256}, Ed25519Signature, OpaqueExtrinsic +}; /// An index to a block. pub type BlockNumber = u64; -/// Alias to Ed25519 pubkey that identifies an account on the chain. This will almost -/// certainly continue to be the same as the substrate's `AuthorityId`. -pub type AccountId = ::primitives::H256; +/// Alias to 512-bit hash when used in the context of a signature on the chain. +pub type Signature = Ed25519Signature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = ::Signer; /// The type for looking up accounts. We don't expect more than 4 billion of them, but you /// never know... @@ -48,9 +52,6 @@ pub type Index = u64; /// A hash of some data used by the chain. pub type Hash = primitives::H256; -/// Alias to 512-bit hash when used in the context of a signature on the chain. -pub type Signature = runtime_primitives::Ed25519Signature; - /// A timestamp: seconds since the unix epoch. pub type Timestamp = u64; diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index f6a7619b04..fa1bbfb314 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -64,8 +64,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node"), impl_name: create_runtime_str!("substrate-node"), authoring_version: 10, - spec_version: 27, - impl_version: 27, + spec_version: 28, + impl_version: 28, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/node/runtime/wasm/Cargo.lock b/substrate/node/runtime/wasm/Cargo.lock index c28ae5f63b..21c8952384 100644 --- a/substrate/node/runtime/wasm/Cargo.lock +++ b/substrate/node/runtime/wasm/Cargo.lock @@ -62,11 +62,35 @@ dependencies = [ "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "block-buffer" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-padding" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "byte-tools" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.2.7" @@ -101,6 +125,14 @@ dependencies = [ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "clear_on_drop" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -168,6 +200,18 @@ dependencies = [ "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "curve25519-dalek" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "digest" version = "0.6.2" @@ -176,6 +220,26 @@ dependencies = [ "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "digest" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "elastic-array" version = "0.10.0" @@ -197,6 +261,11 @@ dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fake-simd" version = "0.1.2" @@ -261,6 +330,14 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "generic-array" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hash-db" version = "0.11.0" @@ -370,6 +447,11 @@ name = "itoa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -462,6 +544,18 @@ name = "memory_units" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "merlin" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mio" version = "0.6.16" @@ -611,6 +705,11 @@ name = "once_cell" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "opaque-debug" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "openssl" version = "0.10.16" @@ -958,6 +1057,22 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "schnorrkel" +version = "0.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scopeguard" version = "0.3.3" @@ -1018,6 +1133,29 @@ dependencies = [ "generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sha2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha3" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slab" version = "0.4.1" @@ -1614,10 +1752,13 @@ dependencies = [ "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", "twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1674,6 +1815,11 @@ dependencies = [ "trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "subtle" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "0.15.22" @@ -2047,12 +2193,16 @@ dependencies = [ "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" +"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" +"checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" +"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" @@ -2062,10 +2212,14 @@ dependencies = [ "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" "checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" +"checksum curve25519-dalek 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dae47cc3529cdab597dbc8b606e565707209b506e55848f3c15679214a56c956" "checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" +"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86" "checksum elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88d4851b005ef16de812ea9acdb7bece2f0a40dd86c07b85631d7dafa54537bb" "checksum environmental 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db746025e3ea695bfa0ae744dbacd5fcfc8db51b9760cf8bd0ab69708bb93c49" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fixed-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a557e80084b05c32b455963ff565a9de6f2866da023d6671705c6aff6f65e01c" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" @@ -2074,6 +2228,7 @@ dependencies = [ "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fceb69994e330afed50c93524be68c42fa898c2d9fd4ee8da03bd7363acd26f2" "checksum hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b03501f6e1a2a97f1618879aba3156f14ca2847faa530c4e28859638bd11483" "checksum hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5c13dbac3cc50684760f54af18545c9e80fb75e93a3e586d71ebdc13138f6a4" @@ -2089,6 +2244,7 @@ dependencies = [ "checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" @@ -2102,6 +2258,7 @@ dependencies = [ "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum memory-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94da53143d45f6bad3753f532e56ad57a6a26c0ca6881794583310c7cb4c885f" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +"checksum merlin 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a9e97b439f6d38cbe2a4a4aa93f6770c5305f62761b78b1851406c09c87ee2a" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" @@ -2112,6 +2269,7 @@ dependencies = [ "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d7ce3535d54560c937c1652ba4a0da66bfc63e0f8e07bed127483afb6e5ee925" +"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" "checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" "checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" @@ -2152,6 +2310,7 @@ dependencies = [ "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" +"checksum schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe554f318830b48e5da8ab1ccb1ffd02b79228364dac7766b7cd1ec461ca5116" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -2160,6 +2319,8 @@ dependencies = [ "checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" +"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34a5e54083ce2b934bf059fdf38e7330a154177e029ab6c4e18638f2f624053a" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" "checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" "checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" @@ -2169,6 +2330,7 @@ dependencies = [ "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" +"checksum subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" "checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 25d2287bf4b2dd515afd7d84917892564a0ff04d..68f3e5c98b51fc8d940da30f11520294adc6053b 100644 GIT binary patch delta 61889 zcmdSC2Y6IP)Hl8}cW>FqL|E+8O8>4HiXRFo>c{C{&xvc!P;e((1^&wqVz+Bs)t&YU@O=FH5^k{>Hx`k~^I zzLMlu!qWOnZ>61fy4Y@R-7~`BP-(_7-ua^>eq(!vP_? zLS12Q+2wW@NZao&?K!o@p#ga;2;iIIX zQi`;QjprHcJGO++VCUI%HjPbX%h(h)nN4CV*$TFtEn$niA`h^*jm1U zZDi|PurGNAU(6Trb^I&7o^RkA`98Lvea|-WbNp9+mT%^JSti@Vw(wm%nSITF;otBJ z{7?P|KhJ;XzwwWxVbXBvV`+rs%~<}2I&*dD``qVq1zZ6Z;QnOEry}mZ$9kmt0^1Kiall&y2W!>JP*n1a^*ofo=53JMOkR>WjF3^GQKOxS~BncEv^99qq_MAQ$jo|6+T3A z`ScXz>iEy!+~xC^HM+zzF#LNOUYZ?Z-y0puFgIfd=s;OklFvRsDP>txwqGPmA@^=s zR-X+w>Xu_eR?+rTERcWrW=xwx)p%6Et^2#-f2get-8sd2v9d<@)9gjgCK$VZVG@Uy z@fS9BpJTelPEpt;7GS503YXYj4;xP9ZnJNbQf_T@>6QJ7E_Bi#?L*TOyA^l&mNOtPFn)xfjduRwB24Io=Gx z$a1_if|cd?iwN?S=R;%6#-GEu^cIaj&oL%kKhC>hm_eny05tMc;CTd4B4u=}!iS*HI9-*0FR`+; zp(gJ}<^EJPBcT>QFDrAGW9Ed@g)uxKt?JHNG_XGRLI6k9=TGsu%jw7Zd=QfCJ`bnf zIwwABC;1xiIOL6OkGxx>c(l>J0q@JC%=;VZyN0|jit^5Khf{hZUYP1P;syDR+w@{1 zo)}b6j^Eo%dmHiM%9WcC@@V?02`@oK8uLg1Rc(yAuiT^&jro&$_9O_79-qC%<&PJ$ zH*1bOEJ~40czJ2&%1zWWjpwIw_0j4cO?Z)@*2q*ll}DLvmCm6TN1N~}LB;6Bqls}sXs4hJMN+?t6=4Sz_*p$c9yrw*lbO%J&H02c@z>RLk z??2mFAGX3@Y*j zuK^Tu7<;zih3KOvc+;3U$$D*

EVM-Id^)maJDdlZcO}U!UNUpxcH#$;UE;`CIY= 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%0A+n?eT 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

t(p0gmj+(r=p}It)Knk+c~Q@2UPsO@EbK=pQ0u z>`aen5+@SJCJ`$+j$ih-mM@pTg|ob!#9Mw*zHxn?J*~FQF}~Quv$OgUMw!qlcYal3 zi$Nc-6a(LK*Cd}&*uO5@8{}S+01Y<@VTyvJ*i{D`7q=V$rAH!@t`s;B|5s^WCYR@) z*fur=Gm>d694Gz_z6I;EpFa1#1YV#Zj}y&wiS_3iQOm*iiZ#G+rs$UUj2s0LC)XbW z`0{X=j_m`xe4trk|E~Yg;pliGD59Nd#QkF7!y^AZ-y3P?Tu6!xs@oPDMk7hm!pQG%( z&7N;O-b#Fo7t_xi!c{X3USz$VTxd*C-U4G{18>M$0eJ{BLo3VFSqqHi12`<)rnm?~ zlsHt|7GMLsfGnwNllH(&ns%g)SZEyFh&*CUG29#uf>vK`S;%p5GciZx&k8}TuC2bk z(0FgdHc4V&k^+*T992)9b||Ty)N)gje=I{1r71zvLx&pvphpIbHvXa%iwf+1y#LEk_uq z4dU@b(7K)ZWY9S_@2jcLPc#n0q{^ygIi5H&$?U0>M;Z?_0&sO+5TB%gO)DzYg0~to zS}E{`6oTaxxfQTp|5}?@W~>A#w?JB6=CZ{mo(b*xK<%)ymr#8eL7@P^S~4p9y)B99 zud6K@Cfa=fS49dj2<5JzAmw|+A|u6XIwm<;R02zfjlaJ3hMw;AMaHs*#o;9fM2?!H zfGtqVk1~#J5IZKMF|fbrAjvCr?@I=tUOvqYrn5-bn@Heq-e~hi0x46uT3=Wt9n1~@H zMd4$t)WM4le*jcK9tRZ{KboZKvc<;SrbU{rz?G3hFUV;{pHv@R0;(t39EvUS@ZB*x z_$l?vCB~*E4uIrp;<0iGH#g=jDqo5}v9YNcPz+7Md%D@D)v-$qQ@ys>sH4+_6RATA zK8&N2sTk5>$w`HYLO35u@S=hZKkq6`ANV&XhO&ZNSFTWd>& z$!Qx+tS&kT4hO_?n*8v#+6L*Jpwu#BQ4(OIVVmUsBf`3lIk(=RP}60?XmrA-}yAN#=O6`opp0DA-*v zsb^vHxFiVDFQW+89&5~;yn0kIgshWKmbTzB%=?B~aDw5qfPn|BV8D>90e0vf^@9_PgIZuR2|Bn300n1Ra<5+0l^f%A*@l?c z;dyM_sVEI8WXJoaEUMdNrUaBB0WyODx__%&>$^{6tp(bU$mb>v`%Pr`Z4Mq&nKd4~ ziA3_&phvn!+k@M zd*7{@Wp?n8lVx`$D~dX?AOVV++*b=F@v@uRaI(>A1puQ!k_;GFAgh0W?JUXKj8jjZ zX#`_ek+5;e2NPdOHmV38s9hv4j(1PjuU)%ZTsdaaBxx%EASKOgey?_dP&n#Sr$`u0 z^ayg|+$EgU#QHu%lbfIxnZz*WBBaQ0+HqlRV|Cl3YMpBA-o#80fsmfTxm%Iv|3ED` z)realz5tUC9OVWnHuDFyG@QR*aBW6_VG)%TKdik?4IFLEo;q*N9I~T%8+4GK!R-^3 z6BJ0+e0y!K`oU?&9(xuW*RMs1vh&tRu9e{u`V&2{s_bs`Q0>H$PVI6A@#7~?Gg{4p z)DtO0^w;HB*v^mC_f9jmHi=vlejG^_3#@rqU2wW_02rG)8X`HyoMmu4QkyN%x1}C9 z-7v;x;JMu4_ACk6s?7Rv?YQpyX0*IQ+#T44L)igHcB-+zy5|gILW>A5=MFb^fLazeUys(#R5zOln722E#ZDM)VkbU+$|V|p z49!~DT6G_=*aX6O=Se=BGbHyw;8*2FVe#?QTw%o=H3DF}bTUvb5g*sQB%^)6{1dfv%j@~wmK#TLm70U3G0Hatl&4bL(~l^b7%vu5MW?(fq=(E zy_4v-wL_(M{|P#s;DBA(7MwoUk7n_V+L|(Ka&laO5anU1xXU$v$96oJ8B^6R895#R z0Kg&QNW^&V)cSpGec5|)#+@HQ9T%EhK!=2sWbmF<+cM*f7GGL$d_TaEVZ=zWJ*SyY z%ZUUfSt<7dU})}*&Eomm+EV1U+?a<(^A!UEZZ15yP4m4!=-#;n*W{pzh+q}10fHCS z3+i7AGLK12BF%}gfLxrBM*kzmgflWzJy#fSZc6rz7>t~cjoZ(>{}zp!tY)ml&|r;W zB8_f>K^g6z)UuVvUM=te`S$>0Yb~M{kWVl z0UzK6*9EKx*~{wgRYuq%h>E#n<2nUxPQv0Z7&m5jkP22CZ{Yyr_+#P@g5Ml4_*Z;e z`@QQ{8&k&#K*u76R^b8O)A*Izp>t0^LEZRzeTJI9t=>n;FU{H^w8!swM{5dC`1Xjib<^2HeL$J4BX)!@zJL@1`#oyqIbw@(8@A+KtsG~V zrtckfuv&eNvDbujRg5876~;N=^&#o!;?O|_R|?xcExJL4p0~B>$_^Fb#moz if+_J!;=_<`sUz1JC+;@<2Y;twm7)Vp`#{Uw_x}Op1CD_J delta 62173 zcmdSC2Y6IP)IYp4cW>F#DdZU6$>WxB1jVs9h9oH zP%lVt(yO5<9h4#<9i)E0xh2`eV0qv7`JU&$J~-{nnVBC7qS?aKz%`W#i{`=T~Gl>SJe9ufpX}*%9gp zbIJ~qdts#Sysr>taFfdG;Gy#=mFt*lecrQT%H@k}v1P#-iqGm+fX7_;#MkHt}EiR(^$F z=9l>I{35@=`%3+!{?Y(xpya;1__F%#@?wv;$K&uhe9XtakGV%h-20GwLLGtq{WdrP z30|ke;c+_xHxDdcv2KFO(nk%x7dPta(f1c0+d5Zf>5B*NF2WEj+_T=9QP^?ugYz?)Z%VFT5(^=Ksz7 zg?oyODsv+_6Cxv>S(0Pyub7OS;MTIYu<+{Vqu#rhA8if3_j*P@1ok=iOJt;jF=V!! zCHF5aWx|=UntDOb{>UY8{@d~VKMPk=FOr`P68vP2wF0?|u;OewRVu>TR=<`C-t+ia zAg)6qcO>$V+zv-Bq!W2e;H)SM&AIGw>IQvZ5!RHs4{mh$cp#>Ow-+TPvZCR=C5I<4 z1i1nH=WXQhc#G-n5*Y}dP6LXuLo8i?y*P6+c8Cs?U`6=!Lo}oWYrqbQWKrZkEWv8C zLHbiAS)XMP8{T+Ydxj-M4%&dVldlqw@i_zD4)`CMEJ3%=u&%6_{?1v}hO-6w=HHma z_1))LEsgz3Vb_?C{i>I~#vZ!ZAS!vE?MgX%Z=EAh-do0jL3(37=z5tBg&dwmj7cfH zw)vlrCvsO>^Kym5k3G<6b>36(2xCnSZl z6372&^#fLfm7uQQO5ysQ2drf@E1@@w;H@~q@1yuTEPn~nGjF}nP9ls*aEgw9R3?W12-rI@yr=|31>$%CcA9F%@wUjF8pm&m+%Z0$pPkm1`glu*WLN?(2%vHa zyeCp=2}YH@38D&>EyzWOS{CH5A;4048hGv(@-_&{2&b#VcoN-y zR?b6dueg&awKf+#Hn=u_flpaN$7}OmNG5YBoVo=#@r^quqz+F&p8pjdPWOlMSpAhc zygQQ?rLL#_PxGfxl)El(#K%6MSL^aJX0i;esmr}QbtCPq%L^$R1^33%iTb=S6{yFf z092_STHJV#o@&UWXlgxPDUiwH!O@d5H#)qDSerQ)2j^0BeO^kMzHB{p9mON5RBd#) zOMUQ%(Zd+3F`UQH+WI`Nv>kmvTAx=CCC~5|dEW>0)-$}S-S@rEU_8i+YrtPJV7oWq zPfN#9>4yfqv<;QFAx|(eYc=H0B?NaQW36WCG^I7<#RQp-Hsm9-^l3^Xo}hr9jzA2p zZouQ{!Ph)D-E0I_dPD^p^D2NgrsTcGyj|RYUV-WkA-uE>0Y{SKacZElkwp9sU2M$9 zK??PKmXBZvqnh$)CML1;b37hc#3asY`y6M=;mK$&io89*4#S%95PMWRoAGCrE21z` z6c(nZp9f23wx3TQ@;uM&WLIeNOT1nD$SHwJL7n+>N@i#JOriWOcsul>cMI<4%9M$A zi-l=-OYR2JBQ5y~Wy}=2v7)rLm5~pI3a4YO_$SI7Q5bIYBzFK(jMs)>KPhzxcmvCg z;gq2bt$9JdW(u8aEoM;15NER>c^Nzhc}#&7C})NLJZU*jrSEU6uNt$_k@)XeHhqlV zEGKI|+0 zVJzVF4`+cC{|M|DnPdrR$Gh>dUsJDkyl34%Evn6f3xP;f;wR*0dr`I ze&a*Fli4sISUhUMd?5Js&=flQF@HM?OMTFT$2fg6&eRsIIei0J2j5pL$uY^!5Q))e z^zT3CQ=~F|PSrM8&NtiwdvMaI$202Pv@=A#OZq3Ne7aP2^BJR>lu>Q9iCxO5w$#oL z)#jbioA%|J#Lnq258(S4U%EptHi$RpzO@%>8|%-v2kq|zsD8m}UnCY>&?kS%qj>J6 zJJvfY@w+l6=CIl!fHk;zXcj^GQVt-=UvWPuW60VuU-71Bm45q*H_idH&M@qyyARW( zVY~_3O}`H_!~|B3A?VuiX&305;kHZ*rz^wxSmpF3$l*McTo*EC_6QzkO@h9C1aM$8 zi5bOPu$$C*6t86VB1T^WQOYc2k#zBEUWcFhSuZu3M@nt~%kr5$%aY?6k$aD**O!<_?JU^315miM-oXJ8ud5t2zWD8-wn@!b;Ye?5!4WxjA3O`Xfj13Y~$ zZ!dPY>hpMIBm>VY;dE|4kEdz#pf6paee-#-P>63HSm(6Fw*m9>LY_#^E#P7F_Iw_Z z^K1u>(#ZKxH4H3uZ0vT;&e$b;ZQ;?hb~%{;$^t{98UF*XM5WSr=g7?72WFqKXP6eH z;V?Y-D6Lz74e*bpSm}_wv%Xu%8NYI$)^CIYv2GD~#~KORDnQYTc@MD^Ml9wfP_Sk( zUm%j5m+($PT{y9X*R$cTF2~4UT8gbxr!Gr*N#svn%8N+)&UN(7TwaFmEamx?iAO>G zd~{6bMMLX2{1V86Q-at64AKBe0qV7k#{kLrWd;&EKc4O`<6d@#Tskk$cNya-rDUrd zPbqa3nP%y{j0F-&S9D%MIU(B3OH-C{pPIczR9emx(c-#|CP{_fU^m;s%#SkB^nCy{ z5duwq(S65XyB|;2S3tM1#wh@4*k&$M%^#qrU#8?A455X&y8nb7J81I$*HK@QfF{l> z!5TpZQi@o`3zb;1!`LL4FLwu@H_0(~hauUSFOQL&ZYNPRaR)5b~!WYB|u;&MH8KH}NsP47SWs-8g)P ze%Zta+1#pwg4dYI^FmA;oPK2sZ(4ldE~EE(aL^PxZR#$g_j#;M`0h?CiK46Y_Ex^s zH*|aLgbHFavtjxn!yz`|JOaT(s6KJ1uSIgwOyqoJzXq=~0{JNa8|KPB&iHa_hb z&D&+Hy3BI-Zk}w4glH7v`=Xc|T@`z&ha3Mw7?7@s3)noSZqRiT1 z_u_CI*bDs<`*pK@#(pgt)cfxfJEXY~bcnS9T^4Jw z=369N@s=#=T8g(Ms0+or%W)hl2hpzMd^rZ#{{(+gj$iW7n18#*Tsw&x(;w39vwV~_ zKAQ9^Z;eg!?ytO7{M3i0+GMpeHmKI{ht&MHztl>Ob;eTXbG#g%_kgCIGc=H}t62E= z&+%5}f`}y>e3Iy}T9C8004qe2V>nu)Qy$qzGtcv%*-Ywnfrr~&%DDn9yufFN4P0xC z)j-l~Exmn_e;5DwxN%gmtKB_rsK5ru)#I~D{?2(kRA8Y1+aOSY#ab{xp#CdO zs{McP>Yx=y^>LZM3@FKA5!%LL5!%24LNC3_FO;2$HG}0Ni{)d|;UB8$d#>?PTpV*A z-{8&Bc=Mb5Bi?H&?YzmGSlN+O<`#ds#FdHG`OsX3znO!ukBi6cB*=SkqQ3YRPlq-@ zuROrP{+l~Eci8nMYZ+VhZML!M8;o{vB029ttQm~v*Zbegz?A@$Up(NAU>@7{fWONo z(OxbUqdyeMJF2a_K0Q_>asD&TdGjQx5Z!vn18kuQl^P-$yD`202r4elF)TugqGOME zVN`(*Q;DiRhG{6Xdi>}zQe^SWnFto}R~Oq`evoV(-9>tq9Wh%QDoNJiH=K;F6lYSB z-Qg4_MFcfeh;}f^#g@+Jml)feK}Q$WbV-$zK?LwH z6a4BUE_%DrC8c7LAfIBQFxJ%N^JW?wZ z+S4CTWx_FrBh)xt5}MK{;Zj5Qxif&z<#h&@)6Q_IJexKq!sv-H&SxW}+j7PPbj)i{ zKqY-yUg;U_l}sw;OmUxLN$MPE98@=_gTCIfppE|ruXt8u5v5=ExD=BS;-`b*arRg~V4fFrUhP(7e#Rl!yx$I?_#8*~8C+bbi- zf)2UOIq6Uhls-x`t4WD$iN2?r^r{lJXoJJ|hR-8R)`8STR4pKV0>j^ufK)5)p=q44 zm+o!zq;4$TE0n8_^a|SO)IcgiYpXeH(3)zB<|<!W&4f&Cz@S%AaZ=4R_iW&mL(~X`0zYisaLm(ds6WP~9&!kzNwXKvRQtdp4CC zD+`wycBu7DK-@w4ou*O)i7nJ?zaS0a>|1?TbLm%R8!~&2l`7Ds7SaHANbml#^q48V z7ol%?YDoKeYx-+%OU*JMQ1k3N(lo}045dLGq!Y^6 z#Wwv4j~Op1;%4HieN3GGo|Mef7VGN!QZ(15L+5PZff=kwC+RrO5Ue|vU+tmRmQk&< zlqL<^zK#m?lM+RCF1=6}sS9V{(dZAPCVa|CI{N|S$e$G7O*&&%7xJxIcWE>`L3_JP zJ=spZ>4#Eo!|0Lxk<`R(TQ0^7rR5(<8vwm`h7>~~JtQA3{#eRmTQ=v-k@9EsM8Em5 z)RxNf^v8PlBr@q zO(89uUhXY5 z=DQZt^xjg>>`Slab}ev&Y=8x=0kk>Y7!KdF=`Sl&&8%trOf%a7YfT4TB^hO2Ug^yT{rcim2-E5h3%vr`Fg#Tv(>)2IBy^C?uwkh zSca+hFe%~R+#kT^l$TBp!-4B4vEh=?v4q-IH|H(xzvWV|;l|dodbrdJQ(bEW7UvZ@ zGeXj{6La=R@Y3H4anIM%lV928hHR{E6hIZf5ZNgwh# zCurd~ECfR;lp^PNV^hAi6K1ax)@SE$+M->{M%pU{u`D8){Z*hcMhE2Hye-!%eg}tQ!3FkZLcL1_7TSoPKPnBr^q@ zqR>5hZNesXakC_B|2A3Ush%!PH2ZAqYcZ5(x%9d+TU3cQtBhW5a11(Fh_)}6?vxCg z=zogBYJ6pdq-uQjcDl1(>Y(fwi1P`=MTEAbgU`!hi`F-8k|c)JyM8CmHJ3IU2Qz~t zrGJ#l+om-!0%1rF(hxESvhhc$D5S#gKT5@($+24?kZA;5EBX*FJSqa&uLXDRhfb~e z!VI1ID7D!leF)pb{w-2Uftk$b^+mV#h5I5~`*=QhSBPotfd8k;9lUe&E?cFs(1*yi zUHS+?>UOEdf07H-^r#X|kGD&`L5|)#q^B%$h_e(Zafr>OZM!6&0z0y}p|vSUF}tPw zwswllB=U8Uob>K)=}3^w3oPG(T8{;jgnEzYt@lVFJSm7uQ)gJa+CV!JRCrV$wolp! zrvm-O0}`CKis`EkOG`DjQUBnS)Z58s(XC&lU*LnV?>DKk6QS#O>7)oR{(&t8V*dSW z(kOO%*>$O?g4D#jQX~4{E{@u#b;J*cAn!xjIRZ&ladzdv|B2?@;6zv>)TznB+*Uu2 zQz-ADTjVyhCy#R!Cc0g?vy8pI?W2LE85>6fXvS&b&bLr2I>I>|6=p{`D+?RWsR(BS zX>QTJx7^K~0MRNw`8a$YA)FU9mqanAOFP7{63!3sO87cJ_H7UZo}%$Z9@7lrLz zf1|YX7>A(L1Ld4QNqIBp#TyR>-gLmyInFQCOI310&pvxvPp#~nDikDtRp%ZI{909K zExQW_X?|QrPgQeTrzYbJ_$-c2A=RBpGT%ChD%W-vWTRQk^!SSa8@}tZOQD7RJNP5l0K-e z^HY~7q&^UiM0jNH9u?yQ0> zoF2EWXAM7NfYJ$%tmqw*ou@RHt&646^L3q7^dTLb<2Cno3-!+JIvVt;?q98pvA>#a zjri2LRr1(MU)mgN0OP-K7UrI%*0@eCHM5uXaxQVYZB=pa0~5uqe$I)Zp8Xc=ru`O* z{iB?7nEQ&=-l{7!V6^iNn@lNVoL$%y{puJHA9FWltTU35#yUU5&W?CjSMX}iWP-r? z8I<^~^CD^(HkE-@AVlElB2%4d&Iruv%hR0q=O+&sxDGSs@PO^4l!A^xnfDSLg>Y*l z{tIN>1O}ho;O!Ye71%-ixEVC=3X$XM5CG5PbjJ{Bf^7*Ncs@VJ)#2h7Wo1 zhFe%5b*BE*i*gMyDx;5IHJ3*zQwFRP#*IcV%Y~@%OS0IMTE8T33C`CWw~#A}TD@MD zZ<*yq^~o*el~R!)0^}Gq*2YmirH$N^Ma&cI>+l#|a+zH^PTtq#2ydEM@{J-%DeMb1 zh4#IRyNSB5$xo+53jNR}Z1YaP1P@r_#v{zfaC+jxgD%7^jQ%0Q2@$q?_^(BX3eLZ& z0ROox6~aXYI0@v~f-IU)=+D>WD%HI{c~*kq+~+l+;lx)jR59H8lzO2d!f{Rw3H6An z^7tG+W{y$8plRRhaztdV>_x&+?+HcRE-H&!PQT)FhAJN1S7;#!mRk!IYu&u=$P!XW zTe(CEt}?}cK@Ny6qo;285c=Fck-*r1A;O@YOVCaU;i8M~;M_*0%b{epWT12zK8+^P z{T`nSlM*6m9^w-TK{4hD0iF<0+UFJn`KGO$mxa)(wsI^TZ7V;8_Dy_HOiConA9`9G z{tA3}Q!=!H|Eu`ibh?%%hlkHiHy6K8v$SOt#CMb*^67giu9N&C-?~@t+DVS#Y!eOc zA{XY@_tL^Haui!fTf4~lA&d3%UF1z%2<7?RIzkgal2e4z8vn8UG?q;A$MWY8AjdzJ;iIrcpZSUWyu`NB-OuH9S+}cAJ>{R+ zM1AZR@*!5_Np#pb60~~gFle=PDUD8*55PJ0yiPT1 zC!dTexQR{adZGSkJ}Nj9g2%YAotv(Q4wSzXTEV!%^5>Emd-PZG>r4=%$1sB!G=7*| zy;^YXe-qDafpQI(BQcV~!{x#T-e*V18`%W%j+9@FodEaBM6M<9P=`kx8zJ$W2}%I1 ze?C&~%*Xvgmq!MVyY47?Y>4RP@hP$=aA zYM!BO^JQTfLDo^0H@IGK+~T<)5gcp=m_3W)7Rrm*VSUd+IluD%JJ-LvTyDa@-cQSy z%P;ZO`zhB7xu9ng$7J(srexuJ zz11dp1d}EVT}SL)Er#SD<#JI-i48+cdq{!UJemO#2X_n~c_sgqTSelDD#SZR!FM$_w(2{hyd3j?CfwOkK&@e;P%AvV@mfVCi zg!QGQ1E>6FLRD-)nvlAFCj}13ujUtLe-tA#K`!ZV2pHkDX6$NynN}T;S2HJldQgr- zKnLaVOr~;&z?3p|J|xE_;%3t?i7f{kif{mji)>tVhs);xMxP`uR2@L(ll8@ii0MdgHuYkY6M^c~efJwDUrZ z(bt}r?=sx%EWclo)MdhNRG=hIeFuj}$_uc!YYh96ST6EI_e80^Kcw%5gT18;1|)1E*d zT|flZJN)jD{GLFBX_oL}!xneViH^S?$5S`tBg!;Z$Kfww(3ekIZjdY&Xe-_zWKg!t zO}Ud*2+uM-;+CAq_`>`2)NSnJ)2Y>Mxr0p)F*kzb&RnLtk%2^KcOVHOY!yFPKNJft zFV>y#R0s{0k7ia(maHJl7Tv##^*V^wG9`-o{3)0Ihk4ucr~G5wnygc+2Tkn)ec?SB zj5yES-GC_{fk!c*`a#TIfogFjMjSRUFiKF(#%0 zHm2~9Jis(YQxdW;-d?8?LX-T8SZT1%gwr0EQjo@LN+>%;vo$5azxsiG*OX@xPMHYv z*a)LSB8@vPNtljiJ3Dx1P;-}343m-KGWsIW=|IFa$QrS*!Fvb1R*gO(26?M}{lH*&vfPzl1Bbq1eVnDB{))yk41x zL@0gunAMa!Qc1ME1W-ANhN_A<5ZaaV(Tqr?C`8z>|v7O%V^GIJsGI&F;?nR+Afc(hb7hh<0(U+%y79eRriH$+1M6@G%a83h+0%o%Kxo&q8SyGssBK~H!3P)AxG|4R9a@c6QSfv$|UqJn?0gbWuw;_ zxgpT2lO!+nhd{51G^4Uoz;?p2H$%$_%h;zkPoz_o72&65BM|Qh?07Wgt*W?d_QHb) zhy*XVS!@l?6556aw}5t5RlY*2!f}GnVzjQB zv%2t|@M1^VQw?l=g-$%L6robpm0SRW^{zFIt*+EH^Pj>j#nn(gX0hM^EPdm66Kp0) z+eve4Dkb74nI3F*7slF2Xe-0l(yf|`@XO3}-uU$?#T#^oVPLcr$kP;3ODS2x^3Iej zM-9t4)W&Z)hZ;kKcjk`M$^cbt>%x~Ivz3=>8^e67wo(RGdaA9|LMIN@R=&t}2KHz? zz%-vF2F}o%0i_#24hNL7w*A}o3$>kUEo-aoR4eo_IMr6Hqs)lI^@h0Iuw6%SxgoAL z4A)V3D%Mesn1l_d_H~uK^zdoLha2Ghb&Y+)a8*WrlOS?ronm;fCPf1qUS*(7%T>@o z4p%`}J!K=DPN#HNitG35DdU`c>tq_!NGZa`2wP~4zcGVqIha8!@VR63R*jY3PM2k! z#LI=V&nd|mfg#vhHB)+kbM`mOiE}1pGEM#$lt6eGE}4CWeau+eV@FWO_DYR{BCo2I zcX#;4458sGh|D4o9%&==o$Zy+op5|@*g;t-o`WgxDSq_8IEAe02xH+3?QJS!eg7)TFcWnRv;vy)(!- zNWa!unI(J<$8}Yz*>|lrA6j?(1|Qy_Ke{So&`kdilpBEmw3|}%AJ#>BH|5(TSaETX zFfDzd<{>KWtZDf))&=HC96c_b6SG_u-Y=()sJ&_O8ka|Z|7R8cbKlVOA1k|9St`&& zxmXYfD%oH~abz;>ZBUAf!MG$6riHH5akUqN?tfe@ieT?2$|jdE!Ufzo{m?g`DoOgj zPnFAR1KZ#WTe$huWUp;6hH=@<>P%?1ouXtL%ktQYJ9!<@^qEn~`_ z9iY?^D#5UUN(?(pvj-~Xun5EQ=`Rja_KL9;`qCbopTdVI+Y+-3P@K&SE2kKsc~FB1 zQmkw*?U|s&P}ET6O^orgq1cO)Xxh-f4t4rhN;mEQc&ML~(u1>abWBV~&;K3n1)4Kn z#@7qh&C++yzndwP;Mn1#oIC=Lyg`YP4J#0F3*W zD@}9j=Zwblps=hbp!qdgxCAQeBZ~h~DH#F_a9}I$55x|m_g$gfV|>(kN?obkFLv3w z6$z3hPl$?lU3qEkDkUj*FvL${nNY8jN_db+3&7ETwK5JjZnS8P()GX4RByT#Tg!i$ zJ$>#v|RK{q7mhV}Hy+mw_LLqUAaSH)HkHyu#A zqGqLo%9y{Obp66XWfik2XYc3MvamO6Ygrik={9}uVI}{6qg?FI${_K&W!f)Firth= zg1=jV)a0mg`S1HrFCSA@*e8e1>v5W{eq0gG-}VZ)`k&_bqZ3Lgv5(C-seB@qlkb!w zuBVMxc5P2V`$Jim(@Nmo<_0mS;aZ70Z6!8KHU&0~S2p@YCmKl+S=fyk69E zpH%pL7#v)r0!ho60-}M}?1W zD|tBko(A1jo@R4s*IlJaTpScO@i~sY0=Lk@gFe+kv41KLVQP=Qr{q!T6_;87pD?)Q zkqgjM1)Q<^VwYOl`aFcAUMTK^gt0wbToHx&!o`z`aPR459(5Im|J3SG^%DuV=9P1+ z1*8O_REL|VErjOnRFp45s6i@>jNVjfe*qH4^{*Fco*HWoTQJ+C-S@W1>~z?{BD`YhzS+ zwM45`QF&#wDlEiyzK`N!)JDSd;GGy%T*}x5b@;fYB*m)DJK#tO1w(AL>m1_5qWp^! zi=oiKf+`f6v8iIpEXBuC{^#};uaK=giyiv*ruDIEc+!9%aI0wBpdfJTmUPu1{b8&+ z#~CgZO=v&uXdu!kaAJY^)u*Ye!Dnk>Q(ZeJwS<>PSJ< z;mpT{n?zr+e#RPEsp6|EJb*XrC>GhNaBrT9BJW`)bo5OWU0bacVXQS#o>6`FX6jH| z&C3o@zuM|kp3QcR!<%V$ZFMeK`LlrfHrVq_K=mpf%V!mh$yBz18n5STpdR4tC;eI@ z^>w(D=+8G(U&PL&&v+gK40`{I{BY+~DKJ?t^`iQ!Gp7C_Cs;3<*c!`YCY@}pwu>AB(IGxd zgWI80=n7cD?|Em5qH;9&6}8M0%J;mYK7#>9w^2Q;xIz58)_e$tF{eW_X5+4yjTmG? zqnkQXZ}O^oRAQ&}V#z8V1ufg?5Vs`IQzkB>s&A?lQmhg5qzf zcM%kNTW!FW=^fuz*X3dNsMM$Gd^4y-e|)YM)vJA`a_FOa&7NvyR?;8`4EBP(Zh|Tn zIj$mVbfOYZ6_Kl;_SBK|%@^unTT~5AQTqc;M5-zY#U`eg+K8Rj+x1c>NF@zhhPajw zfm3ak!*-@tW7#^Oh86Fpwvm8h;6QbvxXvpwNENQHhCu8zNUbFtDi>tUi!)y`#|&1> zWl`y<#bC8S6=P6c%t7_d98{_~sH+aKyJ=-ip$>3Bh(*o z4@jwBt1s|Py(#@`^*g?^H>HeLBl*qV`k2w`GNVH0gYJCvE~#H)+_y;GDlR?Oj#bNt zibp7ZFZO}l!t(NXteT(S=|u&`sjmu3eKAh0na3DyGoLYq!ryA_NZK_{jc$Z|LzW<` zF9r(#4=`5%dqZ;sTZ3zLH);t%1)?FoS5Qb$D*#%Fc`r3yy{Jy=gVmSXUoS90^*DKI ze=0FW?V#BzD+T7M;W2wHSCGK)?J&9}`05IF4uNmswkhg#CttLkI!{*{iqZWr9rh%I zN2jZ|O3v=R!Qrn9KMh}vI;r?|=~E}EufIazaW9eY@l}}Re;TEMvi_$7TjM6 zwT^2Wljglfxy~QuP(a4{g^wFH?UL zUs!6fPCbQIY9K>UmggiazcOHlcNN%{NegT#V+*ix-KEKe1_tlyxt^Yu+L>KO>MU_)OV}0hPPwuNY zo;^^-)fx&Lawrue9-z+kpK0?0RoE@=KTv<<*O$=7hbV?(9rno1u1KFeQrif{`p_dR zw3&4Oky`t|d||>+t05nST5X+wOnaiGR!>?J#2;{$6L5E7!OKv!E$_Rj^D^@i0v2-} z+z?dR(%q-e7l8E8rM)g_<<{a5eCpOdL2%Qp;rR>Y^=O$~43~3=YLkog79Op+kO6aY z8`ZYv);>b2Rvs--Hgk1}BN#IVV=M#Vvn~)w(5N`vKTONLPoiUw)nV+&=#E;M3co;u zfkQ}wGqBCk7{@MWKr!}oHygEv`w2BDcbZLzcEO2SH${(^7_aRpM29H_1vo|f1PXb{k zKV9BL`=Zh8BK_BBZILs6{Z{Mgk7<5fWhZe&TC$av#A&$6)Sr*nzI2w@w#E34fg#9I zynaiTnk(!iiWY7mEkT=G+py$mu;i)2&uQD%^F0u)SoOGBEkkt+X$7skB->A8Z;%^J zdr_zr)|&8%Tj}M(n$QLpmeVTe>k4bF8Cy#EifU#5#nransi?M*1HN1_Z4Xb~rc1@O zamHoo;x0CE$r7T5=mL%@&DJ zD`EHLDCrfn(E`3{MQ!wd8n2$Kl6HjIRJ2Wh7E3a5YG1Ndm#Y9K1>Ub2QZXlqYDvn& zcn^>PX9>jz=ygV(1-Cpn&xV7SPX?SNp-&px55CxJEHlegHhfVKptbZ;&j#h0pD+#V z#Pv)DLTme9yC+C$Tb-G>E(p%b+q*VP-qXh3@O5ye)kyl4zc#!Hk4G~awmP`;vR|AZ(rzNckZr~Xo_x{1 zNbffNr@C4_j(0k-&uI1HzdB=l4aI)*(*I26Q9c3Ba4frMVgv0I9_P3lYR&n` zGt{=BRvVYt-!#-bEI!SyX3C^Fb`lIQ4KAyVv=PAaN@K|0(=@fQHi|DlLlvLZ64(yC z<+EC6W_QDOT(Y_$3l2gz&Nk87<85T4rr1-8(YsBxc(gpAsWyg{J9Ntsad=Eq+Hv5P z_~J=G!NpaWxU37q=WIp(s3XRgP{IN*rVl$p&o$Eqq;o48T0 zwBztCazC%N2+P_Yb$VWl3Y&4mAR6G39FuR*$mg||IpNP`;tvCU^U8TiP`!CKDDDNV zVRro8UeG?y376Z%6%Jg2~{h4!31HwHf(xJ6&J(4yie-!$ev z)VjMHXD7i5BW}|AplTM2QvR30GV@G0gA6loQk|DG(c5rS1l;nBZX`OE-h|C96VC32 zuO+&%^QN^7%muh9s2i(p(u*xKtJ&z&P%Z4IplChDxC=MwSHRh`Yrz>S)QedPtruF>XOpehEsKgE+n+b}w_0nT$*?M& zeqDRaV3;|btc_>*2uII$S}&Q8KC}>FYabWyE_3{YDq9m;@jF{N1&!2+noa z{Lz!RFEUATB&c=x3&L9;dnukEPox4LYF~>wOFz_JGtM@VALB@kjLIKF(G!ubJv3a} zOr&0)Xg%@S@5i4&2pT~>I{vBF79WPF^_ljpif~A84cB`{St**+S8K<1QLcVkT@6|x zKKJb}No)wbgFE-r#4&VDKkZ!viT$BH;`*<@_MCX6ajm}=S@6OcC{@)0XErQ6qxi)a z!D`^2VR6|16V5@E@XCUQ_i(kNspDLgY2yHGo`2wBRAGT4{(`>JKHem>nXe3v^i{g! ztC96Wn+4_{rV#_RB7E^rv|^yvoexZ>(u1@pb@w6QyLd={c91qt+)v;8QhTSV+1&)# z&~YeW`2vaWcksU#ko@ll4%|X39r5<3Q{b?Ob`CIqm%vGfzboGFe-QY@-z^a4?;cos z6J;L;RR2eTRaj+1w5XI#H<0yd!0rDmuv*zKsepu8 z@1@iDub_vfr_+V6wB88yj>EL^s>pDWRyyVM0igwm1ChUANHdR5^~U1pm!59qhCG)& zqiObxCfPHd70;?BKxOhzWFh#bdRByuvSnx?4TW1t+5uWiT3$ZqApJrH6VpS|ibd@f z*7p#v5vXR6%e$Lujs=76p>M`&$qn~%|0EU=TOPP259Zz6@~rI*Y>=^?3K*C=!|{Q# zEZZVBXR$5njmK%LS-3rPSncetQ@#n>4z^D}H$nS~^Zh^RA5Yfs+4udlZ>qM0?brK% zqaAS~*>)y2@}KC=OziGI=~1%~U>Q}MtyNaX!{#5jbdb8u#gO`9XWyDdPdAU(%be(Yh#RoVIP!K1bh@w`%$5@fIzX zKHaQ6Yi8hcqnov-?D$(hX2uWv2-#;0s0el1tc6hREt)HY`CPO7Qb5Kre+2d7uKZMb zo943X&)cG@cnPv}i&iFk)i5fuRjXzKcCz5dY_ppvLG8C`Pn&fL(XMUUhls}?*6>aJ z?b-`wzS#}^=5`IA$2hEecj5$XA_}J|AuhMxW0zJ?LdnFv+8y!788F^LwEQP+JMNSF zq-#YOJ5Jvpu$w8OM;rw6n{cIQ<{_9y(si_1B_prz5v`?#M`u4n$*sd{<9%n|_h8q6 z&ELUmBaO$Eus~o%m|whv>sMa5|qb7Z~H^2N@IYgRwf1uS#|L6GUV=A_iOeW&!s# z7IH#xS6Or1*8CQKDE53~Uc>P*IaiqAONA~!(q8>*?gx*>-03?WYv(LVnpp4wJlC&( z1wSUa9w4`u%N0*|oUU?q{24hjPC;>C$xU}&%skkQEXazTlcA_Xzb+xi{ zGkUClr@Gu?An05H`p)gDLLQf^I_UF^%T*Qm=tXSdIqstee{8b-7(k2pglkb6%Gv z#**~Ne69yvl6;ADD!;2FNcXsaD}iPda7D%>%uDcKz4@ehePLAuVqYP_t%d1I0apY4 zNPgFCmr&{UCAxl(Vt?wZYq`ECim=ApuG1PeodR84JK0|SQWsZo9EtUqZmv7x8w}na zF1*9NN=cu(K5RDZj&X#Lab+M*cmwVjx~gn=XW{QI+_sXYch(&{X)5A>*hy48XT(F2 zDDZ_AO=%IbOAq_ZwU@JNbfTy04R%eh^95vX%9-0)+WW;uA-uto96#Afv%MX5(rj;| zodo1cBOX#1HUV>)Itn?S24CrZ#2MlECdut{Mxk#6uA4ftBX6uw;Md=@D~6Ie3;R%LGW6atw3Hc6uP|T zD`28UnIWWPe7?!3fg;gfUZ0RraQhd3r3SCfLw&Np0Q!HiA z&UfNDzbh{~P}ULZ522G&T(y`+K71f8uRO0W9+%JK{rmdn^S=HN;2O!rvqp_tPjzk8 z3czB64Z}^vzH#Nn%B}Z}Yna4)-=~AqU5$9}2YSK`m($5^=|#VDZDIxCo#^|>*WIwo z4T5To$FIg)>P?2*B5a1J5jMy5C1bZ~{9M=f?6zKS9@Z@|(dhZE-ar(yz%^OsgKp`| zm$>lxy*+xtWv&q%?`k1S_tC}Wu2~@T$Q7=tlH@Ny+gG@fp~{r_!F3OMf6%0#_wFC z+^@OQ0i&OL&0WT20VmPbkKLN_;lw8IxJv>2^LN~B@wcw%SO<4O7}Ntl$qS z2qy|$OqKl{f4yeLd+yQj0jvJL`&-6$U^#Vkmw;(0q?3DIhH1%g?f^gcKVz&{Zkd)2 zc6JYkY3c1Q?*6tF%Z9Y9SO(;@GrGI0`zINv!s8#g>qYE0?+&tDG2;N~E@^z6<*iTL zg+#Bv{LJok9PRkb-8xIxb#%Ri`1IFnJ>APJ#QF3xecXj1X!RC--Q~qrHn_iAH-p0T z_5gQRwq8Fnz&!yMo~AD2-LaU1 z!Qb+j)oz)fH{hqsyG zzJx{_&NPBbv)q%*;{iR^Ha=%%p2*KTI(YkFui*j2;K7AMd#%~j+-8E2Tyf&J=5dIr4FK|~4n|mFV zbK}^R*ul$uV-~n$-AF*58c%1|FL1ZwtFKdBnp=GK-LC7S-f8X{{KxyWF3l}&JM4md zRB$1d&d>DfLbvc9wDVi?eFl=GFhl5NHedkkT;$G6Z5Fu`m0v|~qQp>2*|kx4v}w?d z#Q#B5zrEOfo3lImraGZhQahIVtm%DQ#{?T%XZX-(s_smp{6-MS4E8KgK+4KkZ z40eZZ{^0gSi}jqy%Y+87tjh>#jNOiT?^5xV?m$Lig=~d=PzXGmSGsE>P*%BLK+tNH z`$b@#x5}L#zC1fuxfPah!^9q7^+OA1;t(xXNRaV82Q+kZwfh;=uCd1K;Tm^QAep(w z{WOA$YuuGlmax{{909r=L&Mg(*CPJhI(JI^*$2jkty(s~V-E}ogS*Zo$AJg*`#N{c zus?$G&Oe}D>)jeC)t2+SRSvYj+H>oIoH-0{D%lR~yVq^=u) zc^)wTZ?V*@zTL)bc4MQRG`q3VPMY0VY$wr;IS;AWkM2U0YrR{gh>h;fVSfabUU*0& zHo80IkXMW+?ET}Q{@pQppL75A z{^+h7f64|n>;7yfG4lNnsq7Ya?Hq^j-4^%Mu<3TY0G|9v5TY3M+UkCgV~wTT+#mdN zYsIM3c6U^c2v$9*z`f(&jH4Kh-tmO4ZQJ>TCZl&fp`iVf3KpZ_-;C0``w5s|ds4yN z-GAi`gW`#M{@w5w?|}?S*Z1#n7Z>lT9_@AGZk;CVbGOGWE8Fj$&7jYI|C75_*x)}Q zaF1CZ!?{bj)7>qgFu#+IKaC@fA8?<+AKST28xFZUv)g*P!|osOMLW8D)ctP!smBJR z+Lx!l*hz56PmihFG56CYQd8>)XJ`AR#h*5a$$;1FBx+oEOs9{zpNASy;kY{yqU+V; z?(f5Pm=K00v*|HKo^Us;zRJ!sSGR5_&GoUsPMS^3vXf|H%42=p33oY-mj3QO#LuhL ztD{<#R&|7rY02~Mfs#JtlKY&q1iTwyjyC--Y*&ZCC6S9yR2fQdW`g#Ol*3)+g(tTo zFtIe0;mlz>GzWSFfZVACj5}_7isIHUmLP} z!>0N3(;fQ4JlZ2CO}piODIc0PoP3Q+m3Sg-5(0tor$57QyX)ZnLW|q(ZepVUcTUHC z%>@r-*hXgRr|-IJ$|1i=+!07kUFYyzovs&uV4f}f2^9tM{JB0( z?$)vN2OoCo{%*(ir9S9J_nn@^#45?{E0-^mT%kg_cI~Ppzf~!@LY2zNWy@DiZeR6{ z;JV9ZE|}`|NDOB^LXxrK4IK? zfmly>PZ<2p z(xfLetQRitd4_SkIKArhMAMcMo*MtY>0c^%t~j57m=0F;JS_bmDW!X=dxkx6FtciU z3O%W{!!Gvn*}BOJh#~ zrhomcrw6NI@`A(hA1P?A6KdYn^W484n!cl{XSw=>e(J+pctV~yCEvC5{A4jt`G4IW z?P%r6`=sWsxAJs)Vsi#N4{qa`D*q4HVD~pX;ZKryhEStL?L2W$>f0~vJfAVWWqVJ3 z`3WEf4t-k(Pm3pwK`+tKqiav7u0yUq%fpSiFP()q2)t2_di3zD3(KKE@9~MpE9F!| zTR-=FUBhN35&q8@YI;vk%O`c(^@XP?6Y`_v6Ch}Oil=N?gXC`S_&Rm&?rY!m!{qmA zM~Y`(2ABWWUgXUWcI1a{OcX*9GZVgu@XE_&@M3KmMgjUL)L%uqx6G0W9!~U#QdT z2tg?7PKsgi||FvqPTfil{n# zY|d3}=+dZ~36W7Xveqo4`dpWt?Edm^HSGdp71SLE zoiaBE6XT~eY_umPH|961WT4^4Jo!^>3AX@}t^q1k2BE|f|Lha5qaecUlFx>pgI4OI zybb;dI$uRvNJOt{;#mni@bGu+b(!gNKx(hhlI{$8r#RM~@;aa#Wc=2R%Q{(A0Bnn^ zv1_xIZOsPT0I)Xaod@3FN#C0dwmD$K9M;4hMqzL#&IbW&9yVBW?c0Dh$!x&OAek*A-UU)I(c-sr zLe|bc$d>*Hur>pPO!PXOW;Nsg?;~w9kH|BwN`|r0tzf zAf5?WyYpwWm6e#30c+BK34n8pTKLsPVQ?qfWC9!In}a&sJsa$hY_R(QE0|LJre}j) zg*3P4UjY0b)QRlCI}Km~W&Y-dXOeLt;$p>!Up{PtHhF90HrH%jl($6LM1(f=@*!?e zM~uHdD%o7yuWklu9PP0QiX|w1NkNSS!u_;Mbvu{;+eOhj6Uc=7uM z>DopN^B>$}8}Sk#XlwzbA#O8}UEUOVLff$szK^t!1>#o!1E`FAn=(6~Hi#94 zUrLT7YwGnnTA_3n!gmpRtp-JnHDQ^E><)dE%Y;9NP%Oa!>e;I$CyH(a4k5S-q~J{ zJb7bnmfj60TMlMIRlwAoon~`~!*LUFyM`SeM$HIO#rm1}g~sM4-N9g!(*1g7{1Lmd(Qst|;{F5riREsA_k_?bhtDT(+tfHH7|jGpOq4IaGZLRfDIvG13JM z{i%{z3vn|tiP;y`?R8_f+zH_J+7O+#NF_Ay;FhQ7(DKKqDpV93Rq)v%SO8`3#$4da zPWIlwC4`TSD%ysn;5^->O1SD~uCRf%B*Esx-75hJjF_Gq`G zYA_ofjG!{}%nmz)m>~jjyNZqC5vpb)#7-Y+jI|0{2_9>SpsF^C0+AW|lYy-m(*8^} zzCuvTb!X6!bvW!61K_5-_`@0q3tL?f=!)ZCZ{*j>mR|ztTF8GoTYgETug7{FO%P5) z_*}N~Qb-p?{yPYVArt}&?NPtQp4gN!NHAm;LAWKx>wu?=V|=vN@e0CQ2!%*~9{D1i zhcGX~R>&8fz7l1^HAGsF?GvP5M|c=v6vE&^B_UlE`Lz-H5ekVdM|r96x1Pc&t3fQG z=mu919qNO8(V^h{a!5Bueieka;w$GfO#xz`5fro)Zf0kF-68p`ZtD?nqirB?vf=DSoV#lf(NL3qFSnVoOf$y|w3JEfTVg%<@c0daeT z^$>0bLVL?UjXYVjieE6(i*&^7O#MWp&jHpx?UX>7posmen+^5~U^RREZL$GpZ|F9F z?e*L}8|)CIgGcP}XYPy>vz6^cI#@4Fi3kGTv@UCp&t_{V@o!)+WrM8&SX=A9nXN43 zyNq_s@jnM(dm}lUtrHOd4jx?_zzQ8i{IVl1l!@3V?*>>~kuH&~tgex^=)b6t*CCdp zP4>@_7KSYG`?6rBWU@7^#(x7}4`sI04p#Z9BHw0G8_%i~AUAYH6bcKO_~q1~$e#dM zn-QlX9*4X?5=>3Z?sz@q*GK*~yq*n!`8zNkf zbRmS|rz37NU%l5&lJ-Sjd6W$=V#<%;)7fF<*-Q8TtL!}B?W(H$|K1BFa1XqD--RTk zkOm~QaC%7(C4`#L1B4`}CXqB#00n$hK`CN^?I@$nh%?wI$|wp*1ZBiQ#ez~4gQ5b1 z8p}}Bf&X{ib9e5^<$?b>pU=xad+)V&U3;zHTKnWZ;jdVb1$T9nym{w#G1z`kegkV8 z3kzqJHH2J03x;6*TUW0Y_;f>sbUy7$eCXTj#-eO+24AH|ZShdIrdj$ntP}zvvVAV%V zYpi2n)q5_i?Op|(nHAQ1hUoPaSjEukrm7f7%dIpiGP?zS{X8~ATPwPT(bt}WjH5b* zCx+mCXPbAZaa6}7<5*sq)7DB`dTbZcmS`y5)(#+1p9vwB#;OB*zS5XxzWQwz=_L1D&ZcLA~^n=8MdKGg03?;gE!l_lX&~-ehD(6s=`w*Pk%@)pzNLCkeIE$+1 zEM)RL-qmTFRmNMDt9pf1H}O2IRgwIYdgF7oQ6dSWD!Vsz2+kR&mS$PERNeh*&|WsL zI*PeNw6)9Baum9)h1JHYL3?Ses_qsK(O8|vwBeK088@}A-uXmrZ?9V>*H@T@P@eHH zR~5rFb=VhbqZZR`RRFK9aLSn9e`vkuAkr$Z6Gc9q@dYAko>XShE-8LUm zy82Vp17t_Pc5uB%K<@set4OaWJ(qOPgVnY#)JB~7(n0l}N#q|Ql~zAaD#4fYNTmml zbRKE7Hv!=d%EkOVd0>gys`X-+|5+`&y*6^6cJnfLV}vB)nXM- zr~D#P4Px(R&H{E%;YZeJ(P8aC8L5C{9g5sCt!<^-iN#P>m~I~3+_ z+P^}pRnCw90j*(|hP4Im{vk0V9xgrdR4?uP%B)wnmse;e)3`peRr+z1YuMM0la(-a zR)s+ts3^V)+|yiG)C$vuJZ|^l^zgAaRFXCPIrqc_V`ED}O_H!0Z z?c4IF2W5~~RM>|a^bN3!n%2!#7wH0;sj#Nuyx9%`Yxo8@#uK!YPzny;r;YM}G zhil{2Prg*!YfwASL!H8JxE=Jr-&Z=jCPO-;EB`RG+ER9361f#xJ!`{jMFj?X9)ocv z4Qh3;9~Gi*Wj1<0N1f9-FlLuJ2)puU!>$SDn|e6o+Ie0?Wz|nz*+u*g z8s53xPU`4UNpFBpoVv$I#f)fk!D~i zlt9({tGcCQgY7F_F8;4Jt1Ta|jg%YG)%2yGd#;ch@X_k_FV}_-j)zGr!Np(OQOjRV zzPfdXK&!X)7V5MdNyGPae)h_whlr&;oj}Mw;pxtr-JBCWjWUoYWT!!lB|6O|{>@kylGf&C(Ndgi*JD=9m)HN>8t zBY4-VxQKT>z~#K_HZ-5GY^J>B&dL1sU5r#*N`+o3-Ov=uBtjt1Sl+eToq&9ZU-@%Z zWDe=sq-T(RkyMbEJnv!>Rlo5{@_HgtuhxF3wwplq;a}HdW-ssWETi7zYhfJP#n=Y5 ze!k7S=FsUU;nYJGx{B3&tirl=2-eTSs#il;uZ&vWeD`>tAA zoI2gcvg*B*P9IR?zg9XY)ioM51gAE)x+Se;q?NlE&wld4BL{s#WxdTxTO|eF74-W2 zNLk-Ak-Fi=+DHrDu)@2b!Ylp8GfGtdAEcu1`)AyAZ*9bGznfm7_s^*D_X76MBP*b> z3a15apDbx!$Vi!Q&0{75=)w6#nseRt<~LKv@t+NYZi@Hq>U=T z`R>NjLVtvIJ*nim^2p_#hIe3uNH?e%h2dJt^$c|Ra?14T{D60TwuJuT&FYp1OZi#; z?T&P;M3(eib@~jf+V6iG*7ZZMZi7`X)!VRMFa+!0hGrG1tq%B-Ay{`gs>Diq0#&Kq zgSs&?6rOIW{b;4FlA@<)D)ce~-PR6K=ZiOY6p}Pn9oQ{2rl+o%9U2q3tn<}@yh7IF0>(Y|CPHSNEsWQ-@~lUfcCutRFtEj36!}m3ZWIQjxDe9$Q{mX<3tQ z4&>)v%6-zS7Swy>WXclBb36G~obQx{wA0g=@x)ya46H zY2YZ*t<2*b(pmF&>>wjAM&$w0C8T4HuJ;^Es@uuQ3*UpJhjz*bdj3Fxj7)d%8TEm0 z5yUL$=Lm|;<4Y5KCo`N}$=}t^??$}<{x4oxUhzMNYLG*>g@rnX^eR;IxJv$?c^3$v z>u=>xIzvD-CBcxo`egUZn;2EUi6uhII ze;29T7hOlHt!*dBfGYgRcXqTZdL`j$J?l^Ggx+q2wyG1mY0raJyE6CvgLW^LcC{*g z6k?f;e!3gJ9Ab?%{t@l9{|DN^@SKiv{qft3_^x)N8uE4L^@q7PLMPjBE2+qb&g)cz zpFI|~4$xrFr`Q**0=MwEGjYOR?;e_T-452 zuabL{VeFS0e55v|F_mbBj#-TqIVT;d5~tnz)3@>2iO z|5xc;i{690%LhL4R9EIY7{qipNKYVLN_vt8yA%Y;!ut6G< z5baYG$|;s-r~%zdy{J=puHaqc2#v+1{F9Z2^%n|DC=)~_&kOV=qN^VfaW&}^wY@`> z`wc%V6}(iA;vH#gJvx0AW^EItV%RAJJUU_RZ58$jL$FVSToze3r;nF36;L-(UU)<= zOs%vPR@y2ldU_T^UqSK1baX>P6zeOzb1S^M-wfXB#}%Dh+XWTQ#Y1qu2hJT9p!}~r zvUX2YSeFmM`o6ACl{D4)(sTHaI!nKD2==$Q$LOB!P+zv*PEXY>zfmpxZf%rsR`>hr zAv(PuPJJq5;Y&_|8CA|(hTwb{PMMHia;+Jqm7h>|sJ!sVR^JA{e(tHXrOSq$S}F$J z)?oF%xlZN5ZAxiuOQo^LDvfF8|I0mgbxWV`v^BVWR)^DhRiLZ0tU9+cux*ur_5A3~ zXX`lH64k5+dJ_5Z?TKm4BiVbd7{r*-fPO~tu9dJbzi)AATUL=yAYVmwHu(jVPbBRp zmC$;%URLtKGfMS#9jUl8BT3Jz(y2SXU)y!J7fvs)tv{|F_&$NHRb-|0YHJ6QpLx34 z_Wjz3eGKZ&u6n_gPpI*a)kgN+aatMwTFNwAR#*lk&t;V91Gm$UceG@Ck=J@#N16=aiRiKqE@5jY@gnjf&zERu9_e35#UklW z^&oGiOn2IWdpJFhcRGQjX90OlC;16hych$y8oILDlx|Uja`~JiB8e3hXI{ocA^}*KX z$OpnGsO!s&Qi86Rl8S_PH!zoSS$4hLkHROx*CY6mWz<5~z4yBO&D(=j-)~uGX=tP8 zFup|pF1`s{ef3kF(|p5EIxDQVY&NU{xOM(8@>;&S)y$$wTOaLeYc+hLQcfq;Uc%rt zWVHHtw89``e2)BZd1*iM;tuVRybn-*eY-I&v$v8zjq=w>#fLkUK*%|ycaa`Os_C|p zkI^m^_4F*OG%Wc_U~Tvloy8f&yIusHo(roMxh~cT6;^Wy*7IPknzwdLP6AqCg>}Ib z%6z=GFTXc=;p1%B=iw6R>DF|ElxwqA{odm?nyQ{By#O*;d8!ce3260ZNL@EAaB^__ zkTtv$!Ycke8O*6eB-QfjR|M7nq@}O3q@B0=WJBMul>apo!Yh*26{m=ARpgc3@~^2bnK6$TNG|79q0IK;k&C~kVHHlM%8dGu5K5|;bb2PAn|{Zx|gs_{>gJgrtp@}jy!l0T|f zBzaBE`C0AgzTOq;>Yvr-5AM981EaV6qO1n zwux)XkG9(+2yBhul zv|9If|A*vlU9`WiwEHS`9W8`C9{$TtfwrVN)$tF5uQx<@>vEkwzP7yM)Q0m@J+b@>gvAH>f}%Ej~5HO0#|kU z_jwl>cRA(N4j!jW=;iq#lh9jr%dd8jkHMaMDA0sL{4B)U)ILUCXRoMyZU^R`7ogP` zayWJRUD{dMMf*EwwE(Z*PTRs`grO*?8o-k`cLs45?{aQ_xoL+OYfnGrM@UaRTQ_$2 zU*KKO_8EBep!A8ojRXVv>&U3IqdOW&nFNdF`DSH+)%FJ8 zYUHn07KQtk+gpZytj6 z)39oRm9bSWq;9RS-aQ2C7rIz0|GDM93hSdou>Qwe5BSFw*5`&`eXy(7_FTg&>OC)2 zSpPl*>vv$)vMqCMosCZ1Yo`}F8?+bidSi6@B$_XWda&ne zhy>?sy|Db>s*~Xo_vSA0GJw4yE2GQTVn3ujc#pKpnjXW8$c8ys?^#FsZGIa3)GsN)rvA46BJ#5BdZzj}wOmD+ zG}v8!L%W=$=iW;@A0uc*C*`f*dvW)R9pRU<|AJVbn;nR$yRSm~2k2ylo+90wbi!q2 z&}A;^0`lTdPU7b#@}e*wB9)1LpHz(KUr0yDOn1J#{FvuO%;(PJ*I%xVe7-hCycBs> zeW*073n7z!ehssb$=D{4K0!J_Dr1pHwp|wGJKP6~5q*qQ#-Z;ASFu{c|0l|2=ZC+y zRHwRrUAunJp+Z)CIs*{Gy~#`C<47g{;;!Y&kD`80@&}NL0X>LRhTcv8d+4R(Cq7t) zxrRX}6FQSdCDr}SrhVL&Q+qOAL|d;Wm6>!m__ub0dY5j3jy3GLgj5DNhtbFa>%6m5 zkFvf{+gokDrgo}2;Kka%G_EPl?u6?ZFsu`9_{tM6)_%LwnUqg}a|%BaNV~J0pUV4$ zN?wj;wfVxMPBh|E5 z_=JRC2!Qsc&=~7N#;03GND4S>Myk!O*?WNKMHL#_TAJ> zvwIds57zSx%2fpt_ZW70nN_GZ)uv++XZEU?LyfliVIJOHbbi7=B_w+dQN61uH|Jxyx;!u>ecJg>C=lfoA_tlhBYziN+-1A)C^Lqurt@Q;+tNsomkUSau(GsRUGzg*i#eedO3t)5zWWMxH~g&B)$ z@prFZu8nDiapt9Ac ztIJ-gO&-V#&rjVX%6unu!_Ye99JOVtF-|RW5Wu()XGdGAPs{g2y8X6W=v5} z|Fvcf__4!sWUf<~Q5r{qbENvlt_Yp?x7xT74!>{K%WMZ}bc!qq-1##%JGP2nui4Ga zPhu-Z=292A@)Pf#UiHbjNY=xDt9_u62mH2L$K}`67O7eA`)bwwmXQrOUhJenVkd}` z?|E_1UZ$-_8)hR+!`x$WqNH$qH}FICja`g6{Y99&wv{-xnJ0c0tE>OFwyxniapL-E z9)?9``k6IdHFh=T)a@{{7^siHWSL+1>WtTGGY4!Z&&|~JqR1XwdM`ZQ=Zw-`44 zNj}XE!XxLXyAC$S-uP3aIS{98y%hy!?s;|;_(#oX)u~avM*l#}s6*4u{mf()a%XK4WUr^u54yMef3!O$?5^u2(hoGsdfr_Zds;h)m%X zrWX}Sz@ZJ*Zo>?H0qHa6=m(jXAdcZloo(2s zA5CF8W|TRJmAX-?p557)ThB}@HM4?4;5&9&M9SKQ(mb`DfN=$J?E0uxb?Gj~VfDxn z@y<<@x#u!2wMA&%!gAxJumXo&c1>5+ccs*JGFmi4_RaP(D_6^RH74!#<{kGJt9b_- z=OAIe8OJ%Y7;|Jy@61rGbB(e4uHUe3{ko0u>Wyq^>N-wt*#W;wnxhiiXDukVlr10I zaEmz2i^RfS1YVSQXP1&2$DxI8cQ6!%?We(#&Wem`xabtm_oFmN{Jh9Lr{u}~Ja_#f zjdL5dm$*w$P`?k25sE*$G^H8)G1|cn-2$=p&1~7XI;vx(igq{L0r-=GBOBYHWfn!U zJSb1)KkaVpF;K*oAH`|m1-Zv;3bc!LoH1rhzIOAPWgBxju&BC#iD25Y5bfux-|ucr zs&}uQnou*&q&WmL%MCSdx5{AR4$X^G+oCp{$93r-P$x~xS8c5 zDqdv85ew!eE4$3cz(B^nBzBy~QRqgT*;N;+cn@PQ^}bhYH8pGxPa_xz{3OKISymjlc9N!R zj*>M$P;DD;81=-n63#X=NzkjgrS90%m@;66QC64;Ta+MKnX_)TTK7h6oLV&AXbgBs z>YzMO{{`nIGS?p=mHVm_Pcil$$aBtrW}+oA6?s&=b3s}8jAM-M&tlguOgkvhd1!uh zcfT>S9=d6gnk$9r#~q2JPp#+HWS-6H(jQ-4jAuHw~R4%8kuikY2z5Q zVA`Bf+M~hECB;7JhCJRRYo8Q$5ut!$R@VlDsf!!N`~i#Mq2640QG%v>e!Jm01IBKR z2&j>x`is=I6EMdG>K6mXxufGO+mLT;9Wz$e^l}^Ez+$GcdS<{luVK0&yAzsT$m#bT z_uXptC}TWJk!Eh5*cLbmJrG@ZMQaW>?Pb&kOq6|*_(_%`L0OnzbfvD_Y4rLHt6IY2 zxNhObIkr6lhGfCT?=9D$e{Uqv&WqTM62~#wUdKw_)2ZA=ePVB8*MTgu{V+B`8XR;t ziU+T1vG2Pg-?VJwrgand9RvqtT9PFdWiZZMfq&g1^F>P+XaG06S~d1DHjUo6 z>fJK$9Ng;%*iSb^n3=`93RR5rf3C zJa*6lAVqyqm@vdo?{EUyiN!Qpa^{JG;JjP&!_<&)Rk8OUFS1>JHF+3Gmj+KhS%mI%yRe!jp_&EjKi9i zC_B~!nM@Ne2yW^}0r&d+X@tVJu$y7=Pioo}WAXrUL(hfjhpeO@e5`k)@QhIX6ODf5PB3OSJv)sv zJM)SJD~8Gbc<(zaB%hsN%xpRcomcSJ7#x(GYXvv=ZrV<=aKQFVgdK&DpkR|ZiTLG|7&l$y|$(voov_* z0dMF;D+_@bY~iQWmi>(VCTz&ptUE7XcHX*8E#>JV*D=l-ZYIVj32#-W>}M=#u$&RX z!+2dEN6!4TFgpz#SAa4KGl@eR>+)~vj)Rf8N&6e48*FESSQIFP6fyDtT{RG-I*1rV z!ECS~AoJVQC-w&=v11AAkwrk)$cjEArQ_6J_ct0%E5n$1UX}sy(InYtd*`WJ_BY0; z6HYNkFe|XP8KYdx1Q#OyoLYW>;Wx!(M~*M>C}x?x&-czKnZ9`dhu8@?OF6h3M<+_7 z=nK8`%i5ni#+W^$h++_^X)&c-EuCVlYNG7|E5i*1*`|QSJ9^Jmg9kCySEm@WntqI> z7DbPz33_(#?A=_}7E_I*>zLupHv#e%kii1$-9ObhyBQV$8Ox*};7%N6U+i69@*H!Z zad;E2+d;T+dLv5?3au6so=D2XmJlwSq zK}pp`2N|pSaaTCc0ATh?f^t_0nqnz_p7~!s(6;sRC^p^?A|&re&nN2eB9cs_*(BwwQPnlR?R_+C``rGa6og)5Am)h7=DZnz10GxtsO6TykN;E#G3pBA4N^qdvo@}R(g zs`ZC*IDM2i-Y8qa;pdcp9cA|e!Sf3(f*^Ywht#BID6$&(0ghnkq!08SQy~%2soQ~r zDvBLsr6}+f)WT`VC*tRO99<_wB8k1ITc#N+8z7Ke+yuHrqBG|~HQO}&x?`Fqeh5yV z1s3)~wd^osWfE;Q!y?;r9zn0_#TeVPvj~juga9cgu?z1zy89#l%P8ucMkme+zldYJ@yu41ZLF$eKoEx13UFc)5QzG$ zZCq2wff6qtG>fz3_?|k-F%IcZLO)2-#CA>4mhG!c9DYHE7ZN@)fl~-DZbYUYbXZJ0 z0NaXDWL`mUmaB%l#;J9Nk0XjN>t}xEIjLIhVx-U#=w*%uez%|*^?8@yV~`{q3p0s4 z+*n&q+8MAWrosegxQdQT z^FQrX^9o~foj=Fp*)hilr`<%?s;Ry)p<$Y+WDhuy6;Tp8;gf3CC}YBapWt2qHyEEl zx!|c@_1ICy#0F;HiU==phCmmA`?UJJX9Rosh#5Y)U_?Mr7W}MtQ#GhJEf9wh1)G>) z3y(hWe${&doaQVR9}UIsVI#xh88sM)vPSm-m`udq!-m(b2WYz z)(+f)y2FuS!X6zaQnf{L$#ks)gmuDOM)Fl|mpOFG~#2KMLPmP~rEbA9PM1rcK?NFTRx;dO> zVkP2Frvl<^n*+MbT(JwlF4h4{2-WaC>RdqmNVq+%? zkVi~pQ;nHttQg6wlXBu>&p|1<+3USW%shK@sFuH8n|#yXYQ_NQDafRyl&Pjs@kXzj zdpPGEE5P0o0~I$bbz(L9aO3ob95LUDK%l52%S|s;a}GC7tJ|iB3MTkT3@6CYTDu=% z+*xO#vH%4|7>WQ{?y2t_VI16uQ_eH`Ed)T}Po`I?@y8mc_UCx2h&W!e>jo%?RYw|U zH6xGURUA415>8v}yuYvFdei|f#1&&=sG=rJTTMO6c%%+$2Mgj`gPIAgd8&85F}Vpc zz#dDOy6~{*!H4>0m(i-0l|pU%fbA#^Q)v9~!+l4TwRO+vAKjMqP$IkhAuz`dTaNHY z`W9>_LMm~AkcQC2GXNmDYL}z&l6^c*L>QkG9PFpbO?_&PiH3ZW!P;`Pv8YZI#3I;W zg_dvG*gZ920g{K&_T9{<0Oe`rp}KT|*fDM-K-CTy35#xpA8RdRlbAJw%t9{-iZnH& zkN0gXoi&`i!yEX;c7dlQP!PoK-7HL#I}TtI^GkG{9U!=9nIP&adoz`oHR#t*%uvFI zpXeh}d@Qk$kMU2xonhPXN)xOD;b(O}zGdC!bod_bH;Oaz@<{yw-;js`8){|vQrJv1 zo0@i<;WjyeR>;XGK%L?>SpV8LU&2cVNgQO40Vj(RfF$M$&n2@z#Rk4{9N<(ou%56! zC?L?Q4X!4x^7rEmzn}j2Q*M4>c?Ia8Q1gyw;cV9x=PYw^a%`M}e^a#+4RfqxUbpyGPYXVmq_ z1IbPB4spl;kbqUlgU_lT9&c=H5N~jpVBw%Md_2X^snbs|CNx2L98(J&K$w;w;OF~} zQjeWz?AOwm>~%!Ylh`hSN+JN+7u5Go6!?{xwu4w>kz8C&>-N5d!sN8#MgUv(nCNj9 z;4CuZJNnj3?I?BCLSsP#ENs~>@nQ>C(6XF6)z*c^0Zmjh*p#pfy1YQH?&`}+rf*Ef zQ;L}*5@!+F2rb<6FRH;s1{V_I6|grp*H{Qv@}<5=-8qa9-jj=Pm~F5UUV#&42}jFy z?(UnXE?s0y8MA6_Mi`~#t+Se*#G;8#gtY!2YVN6ozs^0$s5Na^;}oonc?C)rUoP3F zjwRl+YTa6F5W+6{3uE9Ad(D!sv?)e!iqBoOc7-_Q;Ghfun{t;^5aho{^`C5b%>+e3 zSj7zTFa=bkUu};}z2{_*G=6T95({;)LxiNluW{UE+)}&iIC0d<#!=w`;E59p*a$uM z-o9fxbYqvTfo|PenI!=bTf&?zjQSsd|jDzvK)&fk#gR4-g39<_XUblaDS-ztv}| zOBx8sp{LU=(SF~>EL-RZ8_m=?K zR@%(N0h;mac*j3zj7QGB6pAUow}WN>VOz%?hGQ- zyaZdV@AS38%-A5&qo^xRw9B2wf3ei9;SF0%XLY24i4 zibcX>IIVIk5k@~$E6y?wL8`>cSS@W$)FJy(-(lh&Hq}?pGK{^@rdfm_ae2kl(zTCJ@QD-fN zX5pXsb3iyvTqtp?7bbWEf%jAO#M#Eey@*}pIi4pvPRxt-MBhbiSbp*neItLdV`2+Ly$z+`crZ|yr@ zr1Tv1QjAs-SWg%mO~VBpcR0_sYsYi~#^@5)WFP$~;9ki0f2kHO=MZA*i2RBU!VxC` z_^ZAR((aj~x1W!Mh)+xyEFpv_A(7|Qp0QC3_*`LR#6S=kFG3yvx=+m;VHD+fVpMC2 zqXE>#OV5Jeu)fzPocO-{Dew@TfMV%1mzLxC7#fg|x7qSJx&C z6_|pbBY4ab-R{27_fGZolpD%d5@Iqw=MY279e9GRx6Bv&)|IvArpDX`0z^1e0<;Jb zPX2$Z`%+^`lLPE>Qt>HKv8bB%htY*q>vp8~p?weB{ zuMZW*-gT3EcH)=BUu{%r`WL}0fPc3 z*af_>gz;