diff --git a/core/client/db/src/offchain.rs b/core/client/db/src/offchain.rs index 3cefdbf47a288..0640fb6c29bd6 100644 --- a/core/client/db/src/offchain.rs +++ b/core/client/db/src/offchain.rs @@ -28,7 +28,7 @@ use parking_lot::Mutex; /// Offchain local storage #[derive(Clone)] pub struct LocalStorage { - db: Arc, + db: Arc, locks: Arc, Arc>>>>, } @@ -48,7 +48,7 @@ impl LocalStorage { } /// Create offchain local storage with given `KeyValueDB` backend. - pub fn new(db: Arc) -> Self { + pub fn new(db: Arc) -> Self { Self { db, locks: Default::default(), diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index 3bb8412be2020..30d5ccd542581 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -122,16 +122,6 @@ fn deadline_to_timestamp(deadline: u64) -> Option { } } -fn u32_to_key(key: u32) -> std::result::Result, ()> { - if key > u16::max_value() as u32 { - Err(()) - } else if key == 0 { - Ok(None) - } else { - Ok(Some(offchain::CryptoKeyId(key as u16))) - } -} - impl_function_executor!(this: FunctionExecutor<'e, E>, ext_print_utf8(utf8_data: *const u8, utf8_len: u32) => { if let Ok(utf8) = this.memory.get(utf8_data, utf8_len as usize) { @@ -721,7 +711,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(if res.is_ok() { 0 } else { 1 }) }, - ext_new_crypto_key(crypto: u32) -> u32 => { + ext_new_crypto_key(crypto: u32) -> u64 => { let kind = offchain::CryptoKind::try_from(crypto) .map_err(|_| "crypto kind OOB while ext_new_crypto_key: wasm")?; @@ -730,26 +720,23 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, .ok_or_else(|| "Calling unavailable API ext_new_crypto_key: wasm")?; match res { - Ok(key_id) => Ok(key_id.into()), - Err(()) => Ok(u32::max_value()), + Ok(key) => Ok(key.into()), + Err(()) => Ok(u64::max_value()), } }, ext_encrypt( - key: u32, - kind: u32, + key: u64, data: *const u8, data_len: u32, msg_len: *mut u32 ) -> *mut u8 => { - let key = u32_to_key(key) + let key = offchain::CryptoKey::try_from(key) .map_err(|_| "Key OOB while ext_encrypt: wasm")?; - let kind = offchain::CryptoKind::try_from(kind) - .map_err(|_| "crypto kind OOB while ext_encrypt: wasm")?; let message = this.memory.get(data, data_len as usize) .map_err(|_| "OOB while ext_encrypt: wasm")?; let res = this.ext.offchain() - .map(|api| api.encrypt(key, kind, &*message)) + .map(|api| api.encrypt(key, &*message)) .ok_or_else(|| "Calling unavailable API ext_encrypt: wasm")?; let (offset,len) = match res { @@ -784,15 +771,14 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, - ext_authority_pubkey( - kind: u32, + ext_pubkey( + key: u64, written_out: *mut u32 ) -> *mut u8 => { - let kind = offchain::CryptoKind::try_from(kind) - .map_err(|_| "crypto kind OOB while ext_authority_pubkey: wasm")?; - + let key = offchain::CryptoKey::try_from(key) + .map_err(|_| "Key OOB while ext_decrypt: wasm")?; let res = this.ext.offchain() - .map(|api| api.authority_pubkey(kind)) + .map(|api| api.pubkey(key)) .ok_or_else(|| "Calling unavailable API ext_authority_pubkey: wasm")?; let encoded = res.encode(); @@ -805,21 +791,18 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, ext_decrypt( - key: u32, - kind: u32, + key: u64, data: *const u8, data_len: u32, msg_len: *mut u32 ) -> *mut u8 => { - let key = u32_to_key(key) + let key = offchain::CryptoKey::try_from(key) .map_err(|_| "Key OOB while ext_decrypt: wasm")?; - let kind = offchain::CryptoKind::try_from(kind) - .map_err(|_| "crypto kind OOB while ext_decrypt: wasm")?; let message = this.memory.get(data, data_len as usize) .map_err(|_| "OOB while ext_decrypt: wasm")?; let res = this.ext.offchain() - .map(|api| api.decrypt(key, kind, &*message)) + .map(|api| api.decrypt(key, &*message)) .ok_or_else(|| "Calling unavailable API ext_decrypt: wasm")?; let (offset,len) = match res { @@ -839,21 +822,18 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, ext_sign( - key: u32, - kind: u32, + key: u64, data: *const u8, data_len: u32, sig_data_len: *mut u32 ) -> *mut u8 => { - let key = u32_to_key(key) + let key = offchain::CryptoKey::try_from(key) .map_err(|_| "Key OOB while ext_sign: wasm")?; - let kind = offchain::CryptoKind::try_from(kind) - .map_err(|_| "crypto kind OOB while ext_sign: wasm")?; let message = this.memory.get(data, data_len as usize) .map_err(|_| "OOB while ext_sign: wasm")?; let res = this.ext.offchain() - .map(|api| api.sign(key, kind, &*message)) + .map(|api| api.sign(key, &*message)) .ok_or_else(|| "Calling unavailable API ext_sign: wasm")?; let (offset,len) = match res { @@ -873,24 +853,21 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(offset) }, ext_verify( - key: u32, - kind: u32, + key: u64, msg: *const u8, msg_len: u32, signature: *const u8, signature_len: u32 ) -> u32 => { - let key = u32_to_key(key) + let key = offchain::CryptoKey::try_from(key) .map_err(|_| "Key OOB while ext_verify: wasm")?; - let kind = offchain::CryptoKind::try_from(kind) - .map_err(|_| "crypto kind OOB while ext_verify: wasm")?; let message = this.memory.get(msg, msg_len as usize) .map_err(|_| "OOB while ext_verify: wasm")?; let signature = this.memory.get(signature, signature_len as usize) .map_err(|_| "OOB while ext_verify: wasm")?; let res = this.ext.offchain() - .map(|api| api.verify(key, kind, &*message, &*signature)) + .map(|api| api.verify(key, &*message, &*signature)) .ok_or_else(|| "Calling unavailable API ext_verify: wasm")?; match res { diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 776b31ef12dee..64c6427750a7a 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -23,11 +23,11 @@ use parity_codec::{Encode, Decode}; use primitives::offchain::{ Timestamp, HttpRequestId, HttpRequestStatus, HttpError, Externalities as OffchainExt, - CryptoKind, CryptoKeyId, + CryptoKind, CryptoKey, StorageKind, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, }; -use primitives::crypto::{Pair, Protected}; +use primitives::crypto::{Pair, Public, Protected}; use primitives::{ed25519, sr25519}; use runtime_primitives::{ generic::BlockId, @@ -44,25 +44,144 @@ enum ExtMessage { /// A persisted key seed. #[derive(Encode, Decode)] -struct CryptoKey { +struct StoredKey { kind: CryptoKind, phrase: String, } -enum Key { - Sr25519(sr25519::Pair), +impl StoredKey { + fn generate_with_phrase(kind: CryptoKind, password: Option<&str>) -> Self { + match kind { + CryptoKind::Ed25519 => { + let phrase = ed25519::Pair::generate_with_phrase(password).1; + Self { kind, phrase } + } + CryptoKind::Sr25519 => { + let phrase = sr25519::Pair::generate_with_phrase(password).1; + Self { kind, phrase } + } + } + } + + fn to_local_key(&self, password: Option<&str>) -> Result { + match self.kind { + CryptoKind::Ed25519 => { + ed25519::Pair::from_phrase(&self.phrase, password) + .map(|x| LocalKey::Ed25519(x.0)) + } + CryptoKind::Sr25519 => { + sr25519::Pair::from_phrase(&self.phrase, password) + .map(|x| LocalKey::Sr25519(x.0)) + } + } + .map_err(|e| { + warn!("Error recovering Offchain Worker key. Password invalid? {:?}", e); + () + }) + } +} + +enum LocalKey { Ed25519(ed25519::Pair), + Sr25519(sr25519::Pair), +} + +impl LocalKey { + fn public(&self) -> Result, ()> { + match self { + LocalKey::Ed25519(pair) => Ok(pair.public().to_raw_vec()), + LocalKey::Sr25519(pair) => Ok(pair.public().to_raw_vec()), + } + } + + fn sign(&self, data: &[u8]) -> Result, ()> { + match self { + LocalKey::Ed25519(pair) => { + let sig = pair.sign(data); + let bytes: &[u8] = sig.as_ref(); + Ok(bytes.to_vec()) + } + LocalKey::Sr25519(pair) => { + let sig = pair.sign(data); + let bytes: &[u8] = sig.as_ref(); + Ok(bytes.to_vec()) + } + } + } + + fn verify(&self, msg: &[u8], signature: &[u8]) -> Result { + match self { + LocalKey::Ed25519(pair) => { + Ok(ed25519::Pair::verify_weak(signature, msg, pair.public())) + } + LocalKey::Sr25519(pair) => { + Ok(sr25519::Pair::verify_weak(signature, msg, pair.public())) + } + } + } +} + +/// A key. +enum Key { + LocalKey(LocalKey), + AuthorityKey(ConsensusPair), + FgAuthorityKey(FinalityPair), +} + +impl Key { + fn public(&self) -> Result, ()> { + match self { + Key::LocalKey(local) => { + local.public() + } + Key::AuthorityKey(pair) => { + Ok(pair.public().to_raw_vec()) + } + Key::FgAuthorityKey(pair) => { + Ok(pair.public().to_raw_vec()) + } + } + } + + fn sign(&self, data: &[u8]) -> Result, ()> { + match self { + Key::LocalKey(local) => { + local.sign(data) + } + Key::AuthorityKey(pair) => { + Ok(pair.sign(data).as_ref().to_vec()) + } + Key::FgAuthorityKey(pair) => { + Ok(pair.sign(data).as_ref().to_vec()) + } + } + } + + fn verify(&self, msg: &[u8], signature: &[u8]) -> Result { + match self { + Key::LocalKey(local) => { + local.verify(msg, signature) + } + Key::AuthorityKey(pair) => { + Ok(ConsensusPair::verify_weak(signature, msg, pair.public())) + } + Key::FgAuthorityKey(pair) => { + Ok(FinalityPair::verify_weak(signature, msg, pair.public())) + } + } + } } /// Asynchronous offchain API. /// /// NOTE this is done to prevent recursive calls into the runtime (which are not supported currently). -pub(crate) struct Api { +pub(crate) struct Api { sender: mpsc::UnboundedSender, db: Storage, keys_password: Protected, key_provider: KeyProvider, network_state: Arc, + at: BlockId, } fn unavailable_yet(name: &str) -> R { @@ -77,55 +196,56 @@ const KEYS_PREFIX: &[u8] = b"keys"; const NEXT_ID: &[u8] = b"crypto_key_id"; -impl Api where +impl Api where Storage: OffchainStorage, - KeyProvider: AuthorityKeyProvider, + KeyProvider: AuthorityKeyProvider, + Block: traits::Block, { - fn keypair(&self, phrase: &str) -> Result { - P::from_phrase(phrase, Some(self.keys_password.as_ref())) - .map_err(|e| { - warn!("Error recovering Offchain Worker key. Password invalid? {:?}", e); - () - }) - .map(|x| x.0) - } - - fn read_key(&self, id: Option, kind: CryptoKind) -> Result { - if let Some(id) = id { - let key = self.db.get(KEYS_PREFIX, &id.0.encode()) - .and_then(|key| CryptoKey::decode(&mut &*key)) - .ok_or(())?; - if key.kind != kind { - warn!( - "Invalid crypto kind (got: {:?}, expected: {:?}), when requesting key {:?}", - key.kind, - kind, - id - ); - return Err(()) + fn password(&self) -> Option<&str> { + Some(self.keys_password.as_ref().as_str()) + } + + fn read_key( + &self, + key: CryptoKey, + ) -> Result, ()> { + match key { + CryptoKey::LocalKey { id, kind } => { + let key = self.db.get(KEYS_PREFIX, &id.encode()) + .and_then(|key| StoredKey::decode(&mut &*key)) + .ok_or(())?; + if key.kind != kind { + warn!( + "Invalid crypto kind (got: {:?}, expected: {:?}), when requesting key {:?}", + key.kind, + kind, + id + ); + return Err(()) + } + Ok(Key::LocalKey(key.to_local_key(self.password())?)) + } + CryptoKey::AuthorityKey => { + let key = self.key_provider + .authority_key(&self.at) + .ok_or(())?; + Ok(Key::AuthorityKey(key)) + } + CryptoKey::FgAuthorityKey => { + let key = self.key_provider + .fg_authority_key(&self.at) + .ok_or(())?; + Ok(Key::FgAuthorityKey(key)) } - - Ok(match key.kind { - CryptoKind::Sr25519 => Key::Sr25519(self.keypair(&key.phrase)?), - CryptoKind::Ed25519 => Key::Ed25519(self.keypair(&key.phrase)?), - }) - } else { - let key = match kind { - CryptoKind::Sr25519 => self.key_provider.authority_key().map(Key::Sr25519), - CryptoKind::Ed25519 => self.key_provider.authority_key().map(Key::Ed25519), - }; - - key.ok_or_else(|| { - warn!("AuthorityKey is not configured, yet offchain worker tried to access it."); - () - }) } } } -impl OffchainExt for Api where +impl OffchainExt for Api +where Storage: OffchainStorage, - KeyProvider: AuthorityKeyProvider, + KeyProvider: AuthorityKeyProvider, + Block: traits::Block, { fn submit_transaction(&mut self, ext: Vec) -> Result<(), ()> { self.sender @@ -134,16 +254,8 @@ impl OffchainExt for Api where .map_err(|_| ()) } - fn new_crypto_key(&mut self, kind: CryptoKind) -> Result { - let phrase = match kind { - CryptoKind::Ed25519 => { - ed25519::Pair::generate_with_phrase(Some(self.keys_password.as_ref())).1 - }, - CryptoKind::Sr25519 => { - sr25519::Pair::generate_with_phrase(Some(self.keys_password.as_ref())).1 - }, - }; - + fn new_crypto_key(&mut self, kind: CryptoKind) -> Result { + let key = StoredKey::generate_with_phrase(kind, self.password()); let (id, id_encoded) = loop { let encoded = self.db.get(KEYS_PREFIX, NEXT_ID); let encoded_slice = encoded.as_ref().map(|x| x.as_slice()); @@ -157,19 +269,13 @@ impl OffchainExt for Api where } }; - self.db.set(KEYS_PREFIX, &id_encoded, &CryptoKey { phrase, kind } .encode()); + self.db.set(KEYS_PREFIX, &id_encoded, &key.encode()); - Ok(CryptoKeyId(id)) + Ok(CryptoKey::LocalKey { id, kind }) } - fn authority_pubkey(&self, kind: CryptoKind) -> Result, ()> { - let key = self.read_key(None, kind)?; - let public = match key { - Key::Sr25519(pair) => pair.public().encode(), - Key::Ed25519(pair) => pair.public().encode(), - }; - - Ok(public) + fn pubkey(&self, key: CryptoKey) -> Result, ()> { + self.read_key(key)?.public() } fn network_state(&self) -> Result { @@ -182,33 +288,23 @@ impl OffchainExt for Api where Ok(OpaqueNetworkState::from(state)) } - fn encrypt(&mut self, _key: Option, _kind: CryptoKind, _data: &[u8]) -> Result, ()> { + fn encrypt(&mut self, _key: CryptoKey, _data: &[u8]) -> Result, ()> { unavailable_yet::<()>("encrypt"); Err(()) } - fn decrypt(&mut self, _key: Option, _kind: CryptoKind, _data: &[u8]) -> Result, ()> { + fn decrypt(&mut self, _key: CryptoKey, _data: &[u8]) -> Result, ()> { unavailable_yet::<()>("decrypt"); Err(()) } - fn sign(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()> { - let key = self.read_key(key, kind)?; - - Ok(match key { - Key::Sr25519(pair) => pair.sign(data).0.to_vec(), - Key::Ed25519(pair) => pair.sign(data).0.to_vec(), - }) + fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()> { + self.read_key(key)?.sign(data) } - fn verify(&mut self, key: Option, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result { - let key = self.read_key(key, kind)?; - - Ok(match key { - Key::Sr25519(pair) => sr25519::Pair::verify_weak(signature, msg, pair.public()), - Key::Ed25519(pair) => ed25519::Pair::verify_weak(signature, msg, pair.public()), - }) + fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result { + self.read_key(key)?.verify(msg, signature) } fn timestamp(&mut self) -> Timestamp { @@ -385,14 +481,14 @@ pub(crate) struct AsyncApi { impl AsyncApi { /// Creates new Offchain extensions API implementation an the asynchronous processing part. - pub fn new( + pub fn new>( transaction_pool: Arc>, db: S, keys_password: Protected, key_provider: P, at: BlockId, network_state: Arc, - ) -> (Api, AsyncApi) { + ) -> (Api, AsyncApi) { let (sender, rx) = mpsc::unbounded(); let api = Api { @@ -401,6 +497,7 @@ impl AsyncApi { keys_password, key_provider, network_state, + at, }; let async_api = AsyncApi { @@ -446,10 +543,12 @@ impl AsyncApi { #[cfg(test)] mod tests { use super::*; - use std::{collections::HashSet, convert::TryFrom}; + use std::convert::TryFrom; + use runtime_primitives::traits::Zero; use client_db::offchain::LocalStorage; use crate::tests::TestProvider; use network::PeerId; + use test_client::runtime::Block; struct MockNetworkStateInfo(); @@ -463,7 +562,7 @@ mod tests { } } - fn offchain_api() -> (Api, AsyncApi) { + fn offchain_api() -> (Api, Block>, AsyncApi) { let _ = env_logger::try_init(); let db = LocalStorage::new_test(); let client = Arc::new(test_client::new()); @@ -472,7 +571,7 @@ mod tests { ); let mock = Arc::new(MockNetworkStateInfo()); - AsyncApi::new(pool, db, "pass".to_owned().into(), TestProvider::default(), BlockId::Number(0), mock) + AsyncApi::new(pool, db, "pass".to_owned().into(), TestProvider::default(), BlockId::Number(Zero::zero()), mock) } #[test] @@ -515,22 +614,16 @@ mod tests { let msg = b"Hello world!"; // when - let key_id = api.new_crypto_key(kind).unwrap(); - let signature = api.sign(Some(key_id), kind, msg).unwrap(); + let key = api.new_crypto_key(kind).unwrap(); + let signature = api.sign(key, msg).unwrap(); // then - let res = api.verify(Some(key_id), kind, msg, &signature).unwrap(); + let res = api.verify(key, msg, &signature).unwrap(); assert_eq!(res, true); - let res = api.verify(Some(key_id), kind, msg, &[]).unwrap(); + let res = api.verify(key, msg, &[]).unwrap(); assert_eq!(res, false); - let res = api.verify(Some(key_id), kind, b"Different msg", &signature).unwrap(); + let res = api.verify(key, b"Different msg", &signature).unwrap(); assert_eq!(res, false); - - assert_eq!( - api.verify(Some(key_id), CryptoKind::Sr25519, msg, &signature).is_err(), - kind != CryptoKind::Sr25519 - ); - }; test(CryptoKind::Ed25519); @@ -543,23 +636,17 @@ mod tests { let mut api = offchain_api().0; api.key_provider.ed_key = Some(ed25519::Pair::generate().0); let msg = b"Hello world!"; - let kind = CryptoKind::Ed25519; // when - let signature = api.sign(None, kind, msg).unwrap(); + let signature = api.sign(CryptoKey::AuthorityKey, msg).unwrap(); // then - let res = api.verify(None, kind, msg, &signature).unwrap(); + let res = api.verify(CryptoKey::AuthorityKey, msg, &signature).unwrap(); assert_eq!(res, true); - let res = api.verify(None, kind, msg, &[]).unwrap(); + let res = api.verify(CryptoKey::AuthorityKey, msg, &[]).unwrap(); assert_eq!(res, false); - let res = api.verify(None, kind, b"Different msg", &signature).unwrap(); + let res = api.verify(CryptoKey::AuthorityKey, b"Different msg", &signature).unwrap(); assert_eq!(res, false); - - assert!( - api.verify(None, CryptoKind::Sr25519, msg, &signature).is_err(), - "Invalid kind should trigger a missing key error." - ); } #[test] diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index f9eb3da07a27a..e187bbc0e3375 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -60,9 +60,17 @@ pub mod testing; pub use offchain_primitives::OffchainWorkerApi; /// Provides currently configured authority key. -pub trait AuthorityKeyProvider: Clone + 'static { +pub trait AuthorityKeyProvider: Clone + 'static { + /// The crypto used by the block authoring algorithm. + type ConsensusPair: crypto::Pair; + /// The crypto used by the finality gadget. + type FinalityPair: crypto::Pair; + /// Returns currently configured authority key. - fn authority_key(&self) -> Option; + fn authority_key(&self, block_id: &BlockId) -> Option; + + /// Returns currently configured finality gadget authority key. + fn fg_authority_key(&self, block_id: &BlockId) -> Option; } /// An offchain workers manager. @@ -122,7 +130,7 @@ impl OffchainWorkers< Block: traits::Block, Client: ProvideRuntimeApi, Client::Api: OffchainWorkerApi, - KeyProvider: AuthorityKeyProvider, + KeyProvider: AuthorityKeyProvider, Storage: client::backend::OffchainStorage + 'static, { /// Start the offchain workers after given block. @@ -163,8 +171,7 @@ impl OffchainWorkers< mod tests { use super::*; use futures::Future; - use primitives::{ed25519, sr25519, crypto::{TypedKey, Pair}}; - use std::collections::HashSet; + use primitives::{ed25519, sr25519}; use network::{Multiaddr, PeerId}; struct MockNetworkStateInfo(); @@ -179,19 +186,33 @@ mod tests { } } - #[derive(Clone, Default)] - pub(crate) struct TestProvider { + #[derive(Clone)] + pub(crate) struct TestProvider { + _marker: PhantomData, pub(crate) sr_key: Option, pub(crate) ed_key: Option, } - impl AuthorityKeyProvider for TestProvider { - fn authority_key(&self) -> Option { - TPair::from_seed_slice(&match TPair::KEY_TYPE { - sr25519::Pair::KEY_TYPE => self.sr_key.as_ref().map(|key| key.to_raw_vec()), - ed25519::Pair::KEY_TYPE => self.ed_key.as_ref().map(|key| key.to_raw_vec()), - _ => None, - }?).ok() + impl Default for TestProvider { + fn default() -> Self { + Self { + _marker: PhantomData, + sr_key: None, + ed_key: None, + } + } + } + + impl AuthorityKeyProvider for TestProvider { + type ConsensusPair = ed25519::Pair; + type FinalityPair = sr25519::Pair; + + fn authority_key(&self, _: &BlockId) -> Option { + self.ed_key.clone() + } + + fn fg_authority_key(&self, _: &BlockId) -> Option { + self.sr_key.clone() } } diff --git a/core/offchain/src/testing.rs b/core/offchain/src/testing.rs index f2fb7e14c494b..6f473a9cd49a0 100644 --- a/core/offchain/src/testing.rs +++ b/core/offchain/src/testing.rs @@ -29,7 +29,7 @@ use primitives::offchain::{ HttpRequestStatus as RequestStatus, Timestamp, CryptoKind, - CryptoKeyId, + CryptoKey, StorageKind, OpaqueNetworkState, }; @@ -144,18 +144,17 @@ impl offchain::Externalities for TestOffchainExt { unimplemented!("not needed in tests so far") } - fn authority_pubkey(&self, _kind: CryptoKind) -> Result, ()> { + fn pubkey(&self, _key: CryptoKey) -> Result, ()> { unimplemented!("not needed in tests so far") } - fn new_crypto_key(&mut self, _crypto: CryptoKind) -> Result { + fn new_crypto_key(&mut self, _crypto: CryptoKind) -> Result { unimplemented!("not needed in tests so far") } fn encrypt( &mut self, - _key: Option, - _kind: CryptoKind, + _key: CryptoKey, _data: &[u8], ) -> Result, ()> { unimplemented!("not needed in tests so far") @@ -163,8 +162,7 @@ impl offchain::Externalities for TestOffchainExt { fn decrypt( &mut self, - _key: Option, - _kind: CryptoKind, + _key: CryptoKey, _data: &[u8], ) -> Result, ()> { unimplemented!("not needed in tests so far") @@ -172,8 +170,7 @@ impl offchain::Externalities for TestOffchainExt { fn sign( &mut self, - _key: Option, - _kind: CryptoKind, + _key: CryptoKey, _data: &[u8], ) -> Result, ()> { unimplemented!("not needed in tests so far") @@ -181,8 +178,7 @@ impl offchain::Externalities for TestOffchainExt { fn verify( &mut self, - _key: Option, - _kind: CryptoKind, + _key: CryptoKey, _msg: &[u8], _signature: &[u8], ) -> Result { @@ -332,4 +328,3 @@ impl offchain::Externalities for TestOffchainExt { } } } - diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 3578ea9027f91..327a8a3eb1254 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -457,7 +457,7 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { } /// Trait suitable for typical cryptographic PKI key public type. -pub trait Public: TypedKey + PartialEq + Eq { +pub trait Public: AsRef<[u8]> + TypedKey + PartialEq + Eq + Clone + Send + Sync { /// A new instance from the given slice that should be 32 bytes long. /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if @@ -476,7 +476,7 @@ pub trait Public: TypedKey + PartialEq + Eq { /// /// For now it just specifies how to create a key from a phrase and derivation path. #[cfg(feature = "std")] -pub trait Pair: TypedKey + Sized + 'static { +pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static { /// The type which is used to encode a public key. type Public: Public + Hash; @@ -631,7 +631,7 @@ mod tests { use hex_literal::hex; use super::*; - #[derive(Eq, PartialEq, Debug)] + #[derive(Clone, Eq, PartialEq, Debug)] enum TestPair { Generated, GeneratedWithPhrase, @@ -640,8 +640,13 @@ mod tests { Seed(Vec), } - #[derive(PartialEq, Eq, Hash)] + #[derive(Clone, PartialEq, Eq, Hash)] struct TestPublic; + impl AsRef<[u8]> for TestPublic { + fn as_ref(&self) -> &[u8] { + &[] + } + } impl Public for TestPublic { fn from_slice(_bytes: &[u8]) -> Self { Self diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index a13c26da268ea..fc1d4f0bdabee 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -87,14 +87,49 @@ impl From for u32 { } } -/// Opaque type for created crypto keys. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +/// Key to use in the offchain worker crypto api. +#[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct CryptoKeyId(pub u16); +pub enum CryptoKey { + /// Use a key from the offchain workers local storage. + LocalKey { + /// The id of the key. + id: u16, + /// The kind of the key. + kind: CryptoKind, + }, + /// Use the key the block authoring algorithm uses. + AuthorityKey, + /// Use the key the finality gadget uses. + FgAuthorityKey, +} -impl From for u32 { - fn from(c: CryptoKeyId) -> Self { - c.0 as u32 +impl TryFrom for CryptoKey { + type Error = (); + + fn try_from(key: u64) -> Result { + match key & 0xFF { + 0 => { + let id = (key >> 8 & 0xFFFF) as u16; + let kind = CryptoKind::try_from((key >> 32) as u32)?; + Ok(CryptoKey::LocalKey { id, kind }) + } + 1 => Ok(CryptoKey::AuthorityKey), + 2 => Ok(CryptoKey::FgAuthorityKey), + _ => Err(()), + } + } +} + +impl From for u64 { + fn from(key: CryptoKey) -> u64 { + match key { + CryptoKey::LocalKey { id, kind } => { + ((kind as u64) << 32) | ((id as u64) << 8) + } + CryptoKey::AuthorityKey => 1, + CryptoKey::FgAuthorityKey => 2, + } } } @@ -279,13 +314,13 @@ pub trait Externalities { /// Returns information about the local node's network state. fn network_state(&self) -> Result; - /// Returns the locally configured authority public key, if available. - fn authority_pubkey(&self, crypto: CryptoKind) -> Result, ()>; - /// Create new key(pair) for signing/encryption/decryption. /// /// Returns an error if given crypto kind is not supported. - fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result; + fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result; + + /// Returns the locally configured authority public key, if available. + fn pubkey(&self, key: CryptoKey) -> Result, ()>; /// Encrypt a piece of data using given crypto key. /// @@ -293,7 +328,7 @@ pub trait Externalities { /// /// Returns an error if `key` is not available or does not exist, /// or the expected `CryptoKind` does not match. - fn encrypt(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; + fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()>; /// Decrypt a piece of data using given crypto key. /// @@ -301,7 +336,7 @@ pub trait Externalities { /// /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist, /// or the expected `CryptoKind` does not match. - fn decrypt(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; + fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()>; /// Sign a piece of data using given crypto key. /// @@ -309,14 +344,14 @@ pub trait Externalities { /// /// Returns an error if `key` is not available or does not exist, /// or the expected `CryptoKind` does not match. - fn sign(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; + fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()>; /// Verifies that `signature` for `msg` matches given `key`. /// /// Returns an `Ok` with `true` in case it does, `false` in case it doesn't. /// Returns an error in case the key is not available or does not exist or the parameters /// lengths are incorrect or `CryptoKind` does not match. - fn verify(&mut self, key: Option, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result; + fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result; /// Returns current UNIX timestamp (in millis) fn timestamp(&mut self) -> Timestamp; @@ -431,32 +466,32 @@ impl Externalities for Box { (&mut **self).submit_transaction(ex) } - fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result { + fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result { (&mut **self).new_crypto_key(crypto) } - fn encrypt(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()> { - (&mut **self).encrypt(key, kind, data) + fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()> { + (&mut **self).encrypt(key, data) } fn network_state(&self) -> Result { (& **self).network_state() } - fn authority_pubkey(&self, key:CryptoKind) -> Result, ()> { - (&**self).authority_pubkey(key) + fn pubkey(&self, key: CryptoKey) -> Result, ()> { + (&**self).pubkey(key) } - fn decrypt(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()> { - (&mut **self).decrypt(key, kind, data) + fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()> { + (&mut **self).decrypt(key, data) } - fn sign(&mut self, key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()> { - (&mut **self).sign(key, kind, data) + fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result, ()> { + (&mut **self).sign(key, data) } - fn verify(&mut self, key: Option, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result { - (&mut **self).verify(key, kind, msg, signature) + fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result { + (&mut **self).verify(key, msg, signature) } fn timestamp(&mut self) -> Timestamp { @@ -536,4 +571,27 @@ mod tests { assert_eq!(t.sub(Duration::from_millis(10)), Timestamp(0)); assert_eq!(t.diff(&Timestamp(3)), Duration(2)); } + + #[test] + fn crypto_key_to_from_u64() { + let key = CryptoKey::AuthorityKey; + let uint: u64 = key.clone().into(); + let key2 = CryptoKey::try_from(uint).unwrap(); + assert_eq!(key, key2); + + let key = CryptoKey::FgAuthorityKey; + let uint: u64 = key.clone().into(); + let key2 = CryptoKey::try_from(uint).unwrap(); + assert_eq!(key, key2); + + let key = CryptoKey::LocalKey { id: 0, kind: CryptoKind::Ed25519 }; + let uint: u64 = key.clone().into(); + let key2 = CryptoKey::try_from(uint).unwrap(); + assert_eq!(key, key2); + + let key = CryptoKey::LocalKey { id: 10, kind: CryptoKind::Sr25519 }; + let uint: u64 = key.clone().into(); + let key2 = CryptoKey::try_from(uint).unwrap(); + assert_eq!(key, key2); + } } diff --git a/core/service/src/components.rs b/core/service/src/components.rs index 1b0f9500a1cdb..e81380b3202fd 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -30,7 +30,7 @@ use runtime_primitives::{ BuildStorage, traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, generic::BlockId }; use crate::config::Configuration; -use primitives::{Blake2Hasher, H256}; +use primitives::{Blake2Hasher, H256, Pair}; use rpc::{self, apis::system::SystemInfo}; use futures::{prelude::*, future::Executor, sync::mpsc}; @@ -128,6 +128,16 @@ pub type ComponentOffchainStorage = < /// Block type for `Components` pub type ComponentBlock = <::Factory as ServiceFactory>::Block; +/// ConsensusPair type for `Components` +pub type ComponentConsensusPair = <::Factory as ServiceFactory>::ConsensusPair; + +/// FinalityPair type for `Components` +pub type ComponentFinalityPair = <::Factory as ServiceFactory>::FinalityPair; + +/// AuthorityKeyProvider type for `Components` +pub type ComponentAuthorityKeyProvider = + AuthorityKeyProvider, ComponentConsensusPair, ComponentFinalityPair>; + /// Extrinsic hash type for `Components` pub type ComponentExHash = <::TransactionPoolApi as txpool::ChainApi>::Hash; @@ -231,7 +241,7 @@ pub trait OffchainWorker { offchain: &offchain::OffchainWorkers< ComponentClient, ComponentOffchainStorage, - AuthorityKeyProvider, + ComponentAuthorityKeyProvider, ComponentBlock >, pool: &Arc>, @@ -248,7 +258,7 @@ impl OffchainWorker for C where offchain: &offchain::OffchainWorkers< ComponentClient, ComponentOffchainStorage, - AuthorityKeyProvider, + ComponentAuthorityKeyProvider, ComponentBlock >, pool: &Arc>, @@ -283,6 +293,10 @@ pub type TaskExecutor = Arc + pub trait ServiceFactory: 'static + Sized { /// Block type. type Block: BlockT; + /// Consensus crypto type. + type ConsensusPair: Pair; + /// Finality crypto type. + type FinalityPair: Pair; /// The type that implements the runtime API. type RuntimeApi: Send + Sync; /// Network protocol extensions. diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 1ae5a0a58aaa2..6d9ce92b313df 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -26,6 +26,7 @@ pub mod chain_ops; pub mod error; use std::io; +use std::marker::PhantomData; use std::net::SocketAddr; use std::collections::HashMap; use std::time::Duration; @@ -42,7 +43,7 @@ use log::{info, warn, debug, error}; use parity_codec::{Encode, Decode}; use primitives::{Pair, ed25519, crypto}; use runtime_primitives::generic::BlockId; -use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion}; +use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion, Zero}; use substrate_executor::NativeExecutor; use sysinfo::{get_current_pid, ProcessExt, System, SystemExt}; use tel::{telemetry, SUBSTRATE_INFO}; @@ -55,12 +56,14 @@ pub use transaction_pool::txpool::{ }; pub use client::FinalityNotifications; -pub use components::{ServiceFactory, FullBackend, FullExecutor, LightBackend, +pub use components::{ + ServiceFactory, FullBackend, FullExecutor, LightBackend, ComponentAuthorityKeyProvider, LightExecutor, Components, PoolApi, ComponentClient, ComponentOffchainStorage, ComponentBlock, FullClient, LightClient, FullComponents, LightComponents, CodeExecutor, NetworkService, FactoryChainSpec, FactoryBlock, FactoryFullConfiguration, RuntimeGenesis, FactoryGenesis, - ComponentExHash, ComponentExtrinsic, FactoryExtrinsic + ComponentExHash, ComponentExtrinsic, FactoryExtrinsic, + ComponentConsensusPair, ComponentFinalityPair, }; use components::{StartRPC, MaintainTransactionPool, OffchainWorker}; #[doc(hidden)] @@ -82,7 +85,7 @@ pub struct Service { NetworkStatus>, NetworkState )>>>>, transaction_pool: Arc>, - keystore: AuthorityKeyProvider, + keystore: ComponentAuthorityKeyProvider, exit: ::exit_future::Exit, signal: Option, /// Sender for futures that must be spawned as background tasks. @@ -102,7 +105,7 @@ pub struct Service { _offchain_workers: Option, ComponentOffchainStorage, - AuthorityKeyProvider, + ComponentAuthorityKeyProvider, ComponentBlock> >>, } @@ -264,6 +267,7 @@ impl Service { let network_status_sinks = Arc::new(Mutex::new(Vec::new())); let keystore_authority_key = AuthorityKeyProvider { + _marker: PhantomData, roles: config.roles, password: config.password.clone(), keystore: keystore.map(Arc::new), @@ -498,10 +502,17 @@ impl Service { } /// give the authority key, if we are an authority and have a key - pub fn authority_key(&self) -> Option { + pub fn authority_key(&self) -> Option> { use offchain::AuthorityKeyProvider; - self.keystore.authority_key() + self.keystore.authority_key(&BlockId::Number(Zero::zero())) + } + + /// give the authority key, if we are an authority and have a key + pub fn fg_authority_key(&self) -> Option> { + use offchain::AuthorityKeyProvider; + + self.keystore.fg_authority_key(&BlockId::Number(Zero::zero())) } /// return a shared instance of Telemetry (if enabled) @@ -531,7 +542,8 @@ impl Service { /// If the request subscribes you to events, the `Sender` in the `RpcSession` object is used to /// send back spontaneous events. pub fn rpc_query(&self, mem: &RpcSession, request: &str) - -> impl Future, Error = ()> { + -> impl Future, Error = ()> + { self.rpc_handlers.handle_request(request, mem.metadata.clone()) } @@ -733,7 +745,7 @@ impl Drop for Service where Components: components::Comp fn start_rpc_servers rpc::RpcHandler>( config: &FactoryFullConfiguration, mut gen_handler: H -) -> Result, error::Error> { +) -> Result, error::Error> { fn maybe_start_server(address: Option, mut start: F) -> Result, io::Error> where F: FnMut(&SocketAddr) -> Result, { @@ -876,16 +888,27 @@ impl network::TransactionPool, ComponentBlock< } } -/// A provider of current authority key. #[derive(Clone)] -pub struct AuthorityKeyProvider { +/// A provider of current authority key. +pub struct AuthorityKeyProvider { + _marker: PhantomData<(Block, ConsensusPair, FinalityPair)>, roles: Roles, keystore: Option>, password: crypto::Protected, } -impl offchain::AuthorityKeyProvider for AuthorityKeyProvider { - fn authority_key(&self) -> Option { +impl + offchain::AuthorityKeyProvider + for AuthorityKeyProvider +where + Block: runtime_primitives::traits::Block, + ConsensusPair: Pair, + FinalityPair: Pair, +{ + type ConsensusPair = ConsensusPair; + type FinalityPair = FinalityPair; + + fn authority_key(&self, _at: &BlockId) -> Option { if self.roles != Roles::AUTHORITY { return None } @@ -896,10 +919,33 @@ impl offchain::AuthorityKeyProvider for AuthorityKeyProvider { }; let loaded_key = keystore - .contents() - .map(|keys| keys.get(0) - .map(|k| keystore.load(k, self.password.as_ref())) - ); + .contents() + .map(|keys| keys.get(0) + .map(|k| keystore.load(k, self.password.as_ref())) + ); + + if let Ok(Some(Ok(key))) = loaded_key { + Some(key) + } else { + None + } + } + + fn fg_authority_key(&self, _at: &BlockId) -> Option { + if self.roles != Roles::AUTHORITY { + return None + } + + let keystore = match self.keystore { + Some(ref keystore) => keystore, + None => return None + }; + + let loaded_key = keystore + .contents() + .map(|keys| keys.get(0) + .map(|k| keystore.load(k, self.password.as_ref())) + ); if let Ok(Some(Ok(key))) = loaded_key { Some(key) @@ -957,6 +1003,8 @@ impl offchain::AuthorityKeyProvider for AuthorityKeyProvider { /// struct Factory { /// // Declare the block type /// Block = Block, +/// ConsensusPair = primitives::ed25519::Pair, +/// FinalityPair = primitives::ed25519::Pair, /// RuntimeApi = RuntimeApi, /// // Declare the network protocol and give an initializer. /// NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, @@ -1000,6 +1048,8 @@ macro_rules! construct_service_factory { $(#[$attr:meta])* struct $name:ident { Block = $block:ty, + ConsensusPair = $consensus_pair:ty, + FinalityPair = $finality_pair:ty, RuntimeApi = $runtime_api:ty, NetworkProtocol = $protocol:ty { $( $protocol_init:tt )* }, RuntimeDispatch = $dispatch:ty, @@ -1025,6 +1075,8 @@ macro_rules! construct_service_factory { #[allow(unused_variables)] impl $crate::ServiceFactory for $name { type Block = $block; + type ConsensusPair = $consensus_pair; + type FinalityPair = $finality_pair; type RuntimeApi = $runtime_api; type NetworkProtocol = $protocol; type RuntimeDispatch = $dispatch; diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index 4e5b9c9def2e4..6ffb15ffdf2d3 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -36,7 +36,7 @@ pub use primitives::Blake2Hasher; use primitives::offchain::{ Timestamp, HttpRequestId, HttpRequestStatus, HttpError, - CryptoKind, CryptoKeyId, + CryptoKind, CryptoKey, StorageKind, OpaqueNetworkState, }; @@ -244,46 +244,40 @@ export_api! { fn network_state() -> Result; /// Returns the currently configured authority public key, if available. - // TODO [#3139] change into crypto_pubkey(&self, key: Option, kind: CryptoKind) - fn authority_pubkey(crypto: CryptoKind) -> Result, ()>; + fn pubkey(key: CryptoKey) -> Result, ()>; /// Create new key(pair) for signing/encryption/decryption. /// /// Returns an error if given crypto kind is not supported. - fn new_crypto_key(crypto: CryptoKind) -> Result; + fn new_crypto_key(crypto: CryptoKind) -> Result; /// Encrypt a piece of data using given crypto key. /// /// If `key` is `None`, it will attempt to use current authority key. /// /// Returns an error if `key` is not available or does not exist. - fn encrypt(key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; + fn encrypt(key: CryptoKey, data: &[u8]) -> Result, ()>; /// Decrypt a piece of data using given crypto key. /// /// If `key` is `None`, it will attempt to use current authority key. /// /// Returns an error if data cannot be decrypted or the `key` is not available or does not exist. - fn decrypt(key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; + fn decrypt(key: CryptoKey, data: &[u8]) -> Result, ()>; /// Sign a piece of data using given crypto key. /// /// If `key` is `None`, it will attempt to use current authority key. /// /// Returns an error if `key` is not available or does not exist. - fn sign(key: Option, kind: CryptoKind, data: &[u8]) -> Result, ()>; + fn sign(key: CryptoKey, data: &[u8]) -> Result, ()>; /// Verifies that `signature` for `msg` matches given `key`. /// /// Returns an `Ok` with `true` in case it does, `false` in case it doesn't. /// Returns an error in case the key is not available or does not exist or the parameters /// lengths are incorrect. - fn verify( - key: Option, - kind: CryptoKind, - msg: &[u8], - signature: &[u8] - ) -> Result; + fn verify(key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result; /// Returns current UNIX timestamp (in millis) fn timestamp() -> Timestamp; diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index c6abef7cea962..18cb2fd2dfda6 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -275,56 +275,52 @@ impl OffchainApi for () { }, "network_state can be called only in the offchain worker context") } - fn authority_pubkey(crypto: offchain::CryptoKind) -> Result, ()> { + fn pubkey(key: offchain::CryptoKey) -> Result, ()> { with_offchain(|ext| { - ext.authority_pubkey(crypto) + ext.pubkey(key) }, "authority_pubkey can be called only in the offchain worker context") } - fn new_crypto_key(crypto: offchain::CryptoKind) -> Result { + fn new_crypto_key(crypto: offchain::CryptoKind) -> Result { with_offchain(|ext| { ext.new_crypto_key(crypto) }, "new_crypto_key can be called only in the offchain worker context") } fn encrypt( - key: Option, - kind: offchain::CryptoKind, + key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { with_offchain(|ext| { - ext.encrypt(key, kind, data) + ext.encrypt(key, data) }, "encrypt can be called only in the offchain worker context") } fn decrypt( - key: Option, - kind: offchain::CryptoKind, + key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { with_offchain(|ext| { - ext.decrypt(key, kind, data) + ext.decrypt(key, data) }, "decrypt can be called only in the offchain worker context") } fn sign( - key: Option, - kind: offchain::CryptoKind, + key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { with_offchain(|ext| { - ext.sign(key, kind, data) + ext.sign(key, data) }, "sign can be called only in the offchain worker context") } fn verify( - key: Option, - kind: offchain::CryptoKind, + key: offchain::CryptoKey, msg: &[u8], signature: &[u8], ) -> Result { with_offchain(|ext| { - ext.verify(key, kind, msg, signature) + ext.verify(key, msg, signature) }, "verify can be called only in the offchain worker context") } diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 9090d449f393e..001b697934c99 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -19,7 +19,7 @@ pub use rstd; pub use rstd::{mem, slice}; use core::{intrinsics, panic::PanicInfo}; -use rstd::{vec::Vec, cell::Cell, convert::TryInto}; +use rstd::{vec::Vec, cell::Cell, convert::TryInto, convert::TryFrom}; use primitives::{offchain, Blake2Hasher}; #[cfg(not(feature = "no_panic_handler"))] @@ -410,7 +410,7 @@ pub mod ext { /// code and the runtime is responsible for freeing it. This is always /// a properly allocated pointer (which cannot be NULL), hence the /// runtime code can always rely on it. - fn ext_authority_pubkey(crypto: u32, written_out: *mut u32) -> *mut u8; + fn ext_pubkey(key: u64, written_out: *mut u32) -> *mut u8; /// Create new key(pair) for signing/encryption/decryption. /// @@ -418,7 +418,7 @@ pub mod ext { /// /// - A crypto key id (if the value is less than u16::max_value) /// - `u32::max_value` in case the crypto is not supported - fn ext_new_crypto_key(crypto: u32) -> u32; + fn ext_new_crypto_key(crypto: u32) -> u64; /// Encrypt a piece of data using given crypto key. /// @@ -430,8 +430,7 @@ pub mod ext { /// - Otherwise, pointer to the encrypted message in memory, /// `msg_len` contains the length of the message. fn ext_encrypt( - key: u32, - kind: u32, + key: u64, data: *const u8, data_len: u32, msg_len: *mut u32 @@ -448,8 +447,7 @@ pub mod ext { /// - Otherwise, pointer to the decrypted message in memory, /// `msg_len` contains the length of the message. fn ext_decrypt( - key: u32, - kind: u32, + key: u64, data: *const u8, data_len: u32, msg_len: *mut u32 @@ -466,8 +464,7 @@ pub mod ext { /// - Otherwise, pointer to the signature in memory, /// `sig_data_len` contains the length of the signature. fn ext_sign( - key: u32, - kind: u32, + key: u64, data: *const u8, data_len: u32, sig_data_len: *mut u32 @@ -482,8 +479,7 @@ pub mod ext { /// - `1` in case it doesn't match the key /// - `u32::max_value` if the key is invalid. fn ext_verify( - key: u32, - kind: u32, + key: u64, msg: *const u8, msg_len: u32, signature: *const u8, @@ -929,13 +925,11 @@ impl OffchainApi for () { } } - fn authority_pubkey(kind: offchain::CryptoKind) -> Result, ()> { - let kind = kind as isize as u32; - + fn pubkey(key: CryptoKey) -> Result, ()> { let mut len = 0u32; let raw_result = unsafe { - let ptr = ext_authority_pubkey.get()( - kind, + let ptr = ext_pubkey.get()( + key.into(), &mut len, ); @@ -948,76 +942,73 @@ impl OffchainApi for () { } } - fn new_crypto_key(crypto: offchain::CryptoKind) -> Result { + fn new_crypto_key(crypto: offchain::CryptoKind) -> Result { let crypto = crypto.into(); let ret = unsafe { ext_new_crypto_key.get()(crypto) }; - - if ret > u16::max_value() as u32 { - Err(()) - } else { - Ok(offchain::CryptoKeyId(ret as u16)) - } + offchain::CryptoKey::try_from(ret) } fn encrypt( - key: Option, - kind: offchain::CryptoKind, + key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { - let key = key.map(Into::into).unwrap_or(0); - let kind = kind.into(); let mut len = 0_u32; unsafe { - let ptr = ext_encrypt.get()(key, kind, data.as_ptr(), data.len() as u32, &mut len); + let ptr = ext_encrypt.get()( + key.into(), + data.as_ptr(), + data.len() as u32, + &mut len + ); from_raw_parts(ptr, len).ok_or(()) } } fn decrypt( - key: Option, - kind: offchain::CryptoKind, + key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { - let key = key.map(Into::into).unwrap_or(0); - let kind = kind.into(); let mut len = 0_u32; unsafe { - let ptr = ext_decrypt.get()(key, kind, data.as_ptr(), data.len() as u32, &mut len); + let ptr = ext_decrypt.get()( + key.into(), + data.as_ptr(), + data.len() as u32, + &mut len + ); from_raw_parts(ptr, len).ok_or(()) } } fn sign( - key: Option, - kind: offchain::CryptoKind, + key: offchain::CryptoKey, data: &[u8], ) -> Result, ()> { - let key = key.map(Into::into).unwrap_or(0); - let kind = kind.into(); let mut len = 0_u32; unsafe { - let ptr = ext_sign.get()(key, kind, data.as_ptr(), data.len() as u32, &mut len); + let ptr = ext_sign.get()( + key.into(), + data.as_ptr(), + data.len() as u32, + &mut len + ); from_raw_parts(ptr, len).ok_or(()) } } fn verify( - key: Option, - kind: offchain::CryptoKind, + key: offchain::CryptoKey, msg: &[u8], signature: &[u8], ) -> Result { - let key = key.map(Into::into).unwrap_or(0); - let kind = kind.into(); let val = unsafe { ext_verify.get()( - key, - kind, + key.into(), msg.as_ptr(), msg.len() as u32, signature.as_ptr(), diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 769c774756ceb..f2275cc41fd0c 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -246,9 +246,9 @@ impl offchain::Externalities for NeverOffchainExt { unreachable!() } - fn authority_pubkey( + fn pubkey( &self, - _crypto: offchain::CryptoKind, + _key: offchain::CryptoKey, ) -> Result, ()> { unreachable!() } @@ -256,14 +256,13 @@ impl offchain::Externalities for NeverOffchainExt { fn new_crypto_key( &mut self, _crypto: offchain::CryptoKind, - ) -> Result { + ) -> Result { unreachable!() } fn encrypt( &mut self, - _key: Option, - _kind: offchain::CryptoKind, + _key: offchain::CryptoKey, _data: &[u8], ) -> Result, ()> { unreachable!() @@ -271,8 +270,7 @@ impl offchain::Externalities for NeverOffchainExt { fn decrypt( &mut self, - _key: Option, - _kind: offchain::CryptoKind, + _key: offchain::CryptoKey, _data: &[u8], ) -> Result, ()> { unreachable!() @@ -280,8 +278,7 @@ impl offchain::Externalities for NeverOffchainExt { fn sign( &mut self, - _key: Option, - _kind: offchain::CryptoKind, + _key: offchain::CryptoKey, _data: &[u8], ) -> Result, ()> { unreachable!() @@ -289,8 +286,7 @@ impl offchain::Externalities for NeverOffchainExt { fn verify( &mut self, - _key: Option, - _kind: offchain::CryptoKind, + _key: offchain::CryptoKey, _msg: &[u8], _signature: &[u8], ) -> Result { diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 050fb2646be7f..2a981c3bcc348 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -43,6 +43,8 @@ construct_simple_protocol! { construct_service_factory! { struct Factory { Block = Block, + ConsensusPair = Pair, + FinalityPair = Pair, RuntimeApi = RuntimeApi, NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, RuntimeDispatch = Executor, @@ -66,7 +68,7 @@ construct_service_factory! { }, AuthoritySetup = { |service: Self::FullService| { - if let Some(key) = service.authority_key::() { + if let Some(key) = service.authority_key() { info!("Using authority key {}", key.public()); let proposer = Arc::new(ProposerFactory { client: service.client(), diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 3786d5bdd1628..e3e98407fe3a8 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -26,6 +26,7 @@ use client::{self, LongestChain}; use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; use node_executor; use primitives::Pair; +use grandpa_primitives::AuthorityPair as GrandpaPair; use futures::prelude::*; use node_primitives::{AuraPair, Block}; use node_runtime::{GenesisConfig, RuntimeApi}; @@ -66,6 +67,8 @@ impl Default for NodeConfig where F: substrate_service::ServiceFactory { construct_service_factory! { struct Factory { Block = Block, + ConsensusPair = AuraPair, + FinalityPair = GrandpaPair, RuntimeApi = RuntimeApi, NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, RuntimeDispatch = node_executor::Executor, @@ -83,7 +86,7 @@ construct_service_factory! { let (block_import, link_half) = service.config.custom.grandpa_import_setup.take() .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); - if let Some(aura_key) = service.authority_key::() { + if let Some(aura_key) = service.authority_key() { info!("Using aura key {}", aura_key.public()); let proposer = Arc::new(substrate_basic_authorship::ProposerFactory { @@ -113,7 +116,7 @@ construct_service_factory! { let grandpa_key = if service.config.disable_grandpa { None } else { - service.authority_key::() + service.fg_authority_key() }; let config = grandpa::Config { diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 2f276580f495d..80e43393da097 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -74,8 +74,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 115, - impl_version: 115, + spec_version: 116, + impl_version: 116, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 26ca2f0581e04..10443fda14707 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -69,8 +69,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use substrate_primitives::{ - crypto::TypedKey, offchain::CryptoKind, - crypto::key_types, + crypto::TypedKey, offchain::CryptoKey, offchain::OpaqueNetworkState, offchain::StorageKind, sr25519, ed25519, @@ -113,7 +112,6 @@ enum OffchainErr { FailedSigning, NetworkState, SubmitTransaction, - UnknownCryptoKind, } impl Printable for OffchainErr { @@ -125,7 +123,6 @@ impl Printable for OffchainErr { OffchainErr::FailedSigning => print("Offchain error: signing failed!"), OffchainErr::NetworkState => print("Offchain error: fetching network state failed!"), OffchainErr::SubmitTransaction => print("Offchain error: submitting transaction failed!"), - OffchainErr::UnknownCryptoKind => print("Offchain error: the CryptoKind is unknown!"), } } } @@ -216,14 +213,8 @@ decl_module! { // Runs after every block. fn offchain_worker(now: T::BlockNumber) { fn gossip_at(block_number: T::BlockNumber) -> Result<(), OffchainErr> { - let kind = match ::KEY_TYPE { - key_types::SR25519 => CryptoKind::Sr25519, - key_types::ED25519 => CryptoKind::Ed25519, - _ => return Err(OffchainErr::UnknownCryptoKind), - }; - // we run only when a local authority key is configured - if let Ok(key) = sr_io::authority_pubkey(kind) { + if let Ok(key) = sr_io::pubkey(CryptoKey::AuthorityKey) { let authority_id = ::AuthorityId::decode(&mut &key[..]) .ok_or(OffchainErr::DecodeAuthorityId)?; let network_state = @@ -235,7 +226,7 @@ decl_module! { authority_id, }; - let signature = sr_io::sign(None, kind, &heartbeat_data.encode()) + let signature = sr_io::sign(CryptoKey::AuthorityKey, &heartbeat_data.encode()) .map_err(|_| OffchainErr::FailedSigning)?; let call = Call::heartbeat(heartbeat_data, signature); let ex = T::UncheckedExtrinsic::new_unsigned(call.into())