mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-01 11:17:56 +00:00
Refactors the offchain worker api (#3150)
* Update offchain primitives. * Update offchain worker. * Update im-online. * Update service. * Update node and node-template. * Update runtime version. * Fix build. * Fix offchain worker tests. * Generalize authority_pubkey. * Add test. * Update lib.rs
This commit is contained in:
@@ -28,7 +28,7 @@ use parking_lot::Mutex;
|
||||
/// Offchain local storage
|
||||
#[derive(Clone)]
|
||||
pub struct LocalStorage {
|
||||
db: Arc<KeyValueDB>,
|
||||
db: Arc<dyn KeyValueDB>,
|
||||
locks: Arc<Mutex<HashMap<Vec<u8>, Arc<Mutex<()>>>>>,
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ impl LocalStorage {
|
||||
}
|
||||
|
||||
/// Create offchain local storage with given `KeyValueDB` backend.
|
||||
pub fn new(db: Arc<KeyValueDB>) -> Self {
|
||||
pub fn new(db: Arc<dyn KeyValueDB>) -> Self {
|
||||
Self {
|
||||
db,
|
||||
locks: Default::default(),
|
||||
|
||||
@@ -122,16 +122,6 @@ fn deadline_to_timestamp(deadline: u64) -> Option<offchain::Timestamp> {
|
||||
}
|
||||
}
|
||||
|
||||
fn u32_to_key(key: u32) -> std::result::Result<Option<offchain::CryptoKeyId>, ()> {
|
||||
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 {
|
||||
|
||||
+194
-107
@@ -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<LocalKey, ()> {
|
||||
match self.kind {
|
||||
CryptoKind::Ed25519 => {
|
||||
ed25519::Pair::from_phrase(&self.phrase, password)
|
||||
.map(|x| LocalKey::Ed25519(x.0))
|
||||
}
|
||||
CryptoKind::Sr25519 => {
|
||||
sr25519::Pair::from_phrase(&self.phrase, password)
|
||||
.map(|x| LocalKey::Sr25519(x.0))
|
||||
}
|
||||
}
|
||||
.map_err(|e| {
|
||||
warn!("Error recovering Offchain Worker key. Password invalid? {:?}", e);
|
||||
()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
enum LocalKey {
|
||||
Ed25519(ed25519::Pair),
|
||||
Sr25519(sr25519::Pair),
|
||||
}
|
||||
|
||||
impl LocalKey {
|
||||
fn public(&self) -> Result<Vec<u8>, ()> {
|
||||
match self {
|
||||
LocalKey::Ed25519(pair) => Ok(pair.public().to_raw_vec()),
|
||||
LocalKey::Sr25519(pair) => Ok(pair.public().to_raw_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
match self {
|
||||
LocalKey::Ed25519(pair) => {
|
||||
let sig = pair.sign(data);
|
||||
let bytes: &[u8] = sig.as_ref();
|
||||
Ok(bytes.to_vec())
|
||||
}
|
||||
LocalKey::Sr25519(pair) => {
|
||||
let sig = pair.sign(data);
|
||||
let bytes: &[u8] = sig.as_ref();
|
||||
Ok(bytes.to_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn verify(&self, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
match self {
|
||||
LocalKey::Ed25519(pair) => {
|
||||
Ok(ed25519::Pair::verify_weak(signature, msg, pair.public()))
|
||||
}
|
||||
LocalKey::Sr25519(pair) => {
|
||||
Ok(sr25519::Pair::verify_weak(signature, msg, pair.public()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A key.
|
||||
enum Key<ConsensusPair, FinalityPair> {
|
||||
LocalKey(LocalKey),
|
||||
AuthorityKey(ConsensusPair),
|
||||
FgAuthorityKey(FinalityPair),
|
||||
}
|
||||
|
||||
impl<ConsensusPair: Pair, FinalityPair: Pair> Key<ConsensusPair, FinalityPair> {
|
||||
fn public(&self) -> Result<Vec<u8>, ()> {
|
||||
match self {
|
||||
Key::LocalKey(local) => {
|
||||
local.public()
|
||||
}
|
||||
Key::AuthorityKey(pair) => {
|
||||
Ok(pair.public().to_raw_vec())
|
||||
}
|
||||
Key::FgAuthorityKey(pair) => {
|
||||
Ok(pair.public().to_raw_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
match self {
|
||||
Key::LocalKey(local) => {
|
||||
local.sign(data)
|
||||
}
|
||||
Key::AuthorityKey(pair) => {
|
||||
Ok(pair.sign(data).as_ref().to_vec())
|
||||
}
|
||||
Key::FgAuthorityKey(pair) => {
|
||||
Ok(pair.sign(data).as_ref().to_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn verify(&self, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
match self {
|
||||
Key::LocalKey(local) => {
|
||||
local.verify(msg, signature)
|
||||
}
|
||||
Key::AuthorityKey(pair) => {
|
||||
Ok(ConsensusPair::verify_weak(signature, msg, pair.public()))
|
||||
}
|
||||
Key::FgAuthorityKey(pair) => {
|
||||
Ok(FinalityPair::verify_weak(signature, msg, pair.public()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Asynchronous offchain API.
|
||||
///
|
||||
/// NOTE this is done to prevent recursive calls into the runtime (which are not supported currently).
|
||||
pub(crate) struct Api<Storage, KeyProvider> {
|
||||
pub(crate) struct Api<Storage, KeyProvider, Block: traits::Block> {
|
||||
sender: mpsc::UnboundedSender<ExtMessage>,
|
||||
db: Storage,
|
||||
keys_password: Protected<String>,
|
||||
key_provider: KeyProvider,
|
||||
network_state: Arc<dyn NetworkStateInfo + Send + Sync>,
|
||||
at: BlockId<Block>,
|
||||
}
|
||||
|
||||
fn unavailable_yet<R: Default>(name: &str) -> R {
|
||||
@@ -77,55 +196,56 @@ const KEYS_PREFIX: &[u8] = b"keys";
|
||||
|
||||
const NEXT_ID: &[u8] = b"crypto_key_id";
|
||||
|
||||
impl<Storage, KeyProvider> Api<Storage, KeyProvider> where
|
||||
impl<Storage, KeyProvider, Block> Api<Storage, KeyProvider, Block> where
|
||||
Storage: OffchainStorage,
|
||||
KeyProvider: AuthorityKeyProvider,
|
||||
KeyProvider: AuthorityKeyProvider<Block>,
|
||||
Block: traits::Block,
|
||||
{
|
||||
fn keypair<P: Pair>(&self, phrase: &str) -> Result<P, ()> {
|
||||
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 password(&self) -> Option<&str> {
|
||||
Some(self.keys_password.as_ref().as_str())
|
||||
}
|
||||
|
||||
fn read_key(&self, id: Option<CryptoKeyId>, kind: CryptoKind) -> Result<Key, ()> {
|
||||
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 read_key(
|
||||
&self,
|
||||
key: CryptoKey,
|
||||
) -> Result<Key<KeyProvider::ConsensusPair, KeyProvider::FinalityPair>, ()> {
|
||||
match key {
|
||||
CryptoKey::LocalKey { id, kind } => {
|
||||
let key = self.db.get(KEYS_PREFIX, &id.encode())
|
||||
.and_then(|key| StoredKey::decode(&mut &*key))
|
||||
.ok_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<Storage, KeyProvider> OffchainExt for Api<Storage, KeyProvider> where
|
||||
impl<Storage, KeyProvider, Block> OffchainExt for Api<Storage, KeyProvider, Block>
|
||||
where
|
||||
Storage: OffchainStorage,
|
||||
KeyProvider: AuthorityKeyProvider,
|
||||
KeyProvider: AuthorityKeyProvider<Block>,
|
||||
Block: traits::Block,
|
||||
{
|
||||
fn submit_transaction(&mut self, ext: Vec<u8>) -> Result<(), ()> {
|
||||
self.sender
|
||||
@@ -134,16 +254,8 @@ impl<Storage, KeyProvider> OffchainExt for Api<Storage, KeyProvider> where
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
fn new_crypto_key(&mut self, kind: CryptoKind) -> Result<CryptoKeyId, ()> {
|
||||
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<CryptoKey, ()> {
|
||||
let key = StoredKey::generate_with_phrase(kind, self.password());
|
||||
let (id, id_encoded) = loop {
|
||||
let encoded = self.db.get(KEYS_PREFIX, NEXT_ID);
|
||||
let encoded_slice = encoded.as_ref().map(|x| x.as_slice());
|
||||
@@ -157,19 +269,13 @@ impl<Storage, KeyProvider> OffchainExt for Api<Storage, KeyProvider> 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<Vec<u8>, ()> {
|
||||
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<Vec<u8>, ()> {
|
||||
self.read_key(key)?.public()
|
||||
}
|
||||
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
|
||||
@@ -182,33 +288,23 @@ impl<Storage, KeyProvider> OffchainExt for Api<Storage, KeyProvider> where
|
||||
Ok(OpaqueNetworkState::from(state))
|
||||
}
|
||||
|
||||
fn encrypt(&mut self, _key: Option<CryptoKeyId>, _kind: CryptoKind, _data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
fn encrypt(&mut self, _key: CryptoKey, _data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
unavailable_yet::<()>("encrypt");
|
||||
Err(())
|
||||
}
|
||||
|
||||
fn decrypt(&mut self, _key: Option<CryptoKeyId>, _kind: CryptoKind, _data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
fn decrypt(&mut self, _key: CryptoKey, _data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
unavailable_yet::<()>("decrypt");
|
||||
Err(())
|
||||
|
||||
}
|
||||
|
||||
fn sign(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
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<Vec<u8>, ()> {
|
||||
self.read_key(key)?.sign(data)
|
||||
}
|
||||
|
||||
fn verify(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
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<bool, ()> {
|
||||
self.read_key(key)?.verify(msg, signature)
|
||||
}
|
||||
|
||||
fn timestamp(&mut self) -> Timestamp {
|
||||
@@ -385,14 +481,14 @@ pub(crate) struct AsyncApi<A: ChainApi> {
|
||||
|
||||
impl<A: ChainApi> AsyncApi<A> {
|
||||
/// Creates new Offchain extensions API implementation an the asynchronous processing part.
|
||||
pub fn new<S: OffchainStorage, P: AuthorityKeyProvider>(
|
||||
pub fn new<S: OffchainStorage, P: AuthorityKeyProvider<A::Block>>(
|
||||
transaction_pool: Arc<Pool<A>>,
|
||||
db: S,
|
||||
keys_password: Protected<String>,
|
||||
key_provider: P,
|
||||
at: BlockId<A::Block>,
|
||||
network_state: Arc<dyn NetworkStateInfo + Send + Sync>,
|
||||
) -> (Api<S, P>, AsyncApi<A>) {
|
||||
) -> (Api<S, P, A::Block>, AsyncApi<A>) {
|
||||
let (sender, rx) = mpsc::unbounded();
|
||||
|
||||
let api = Api {
|
||||
@@ -401,6 +497,7 @@ impl<A: ChainApi> AsyncApi<A> {
|
||||
keys_password,
|
||||
key_provider,
|
||||
network_state,
|
||||
at,
|
||||
};
|
||||
|
||||
let async_api = AsyncApi {
|
||||
@@ -446,10 +543,12 @@ impl<A: ChainApi> AsyncApi<A> {
|
||||
#[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<LocalStorage, TestProvider>, AsyncApi<impl ChainApi>) {
|
||||
fn offchain_api() -> (Api<LocalStorage, TestProvider<Block>, Block>, AsyncApi<impl ChainApi>) {
|
||||
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]
|
||||
|
||||
@@ -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<Block: traits::Block>: Clone + 'static {
|
||||
/// The crypto used by the block authoring algorithm.
|
||||
type ConsensusPair: crypto::Pair;
|
||||
/// The crypto used by the finality gadget.
|
||||
type FinalityPair: crypto::Pair;
|
||||
|
||||
/// Returns currently configured authority key.
|
||||
fn authority_key<TPair: crypto::Pair>(&self) -> Option<TPair>;
|
||||
fn authority_key(&self, block_id: &BlockId<Block>) -> Option<Self::ConsensusPair>;
|
||||
|
||||
/// Returns currently configured finality gadget authority key.
|
||||
fn fg_authority_key(&self, block_id: &BlockId<Block>) -> Option<Self::FinalityPair>;
|
||||
}
|
||||
|
||||
/// An offchain workers manager.
|
||||
@@ -122,7 +130,7 @@ impl<Client, Storage, KeyProvider, Block> OffchainWorkers<
|
||||
Block: traits::Block,
|
||||
Client: ProvideRuntimeApi,
|
||||
Client::Api: OffchainWorkerApi<Block>,
|
||||
KeyProvider: AuthorityKeyProvider,
|
||||
KeyProvider: AuthorityKeyProvider<Block>,
|
||||
Storage: client::backend::OffchainStorage + 'static,
|
||||
{
|
||||
/// Start the offchain workers after given block.
|
||||
@@ -163,8 +171,7 @@ impl<Client, Storage, KeyProvider, Block> 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<Block> {
|
||||
_marker: PhantomData<Block>,
|
||||
pub(crate) sr_key: Option<sr25519::Pair>,
|
||||
pub(crate) ed_key: Option<ed25519::Pair>,
|
||||
}
|
||||
|
||||
impl AuthorityKeyProvider for TestProvider {
|
||||
fn authority_key<TPair: crypto::Pair>(&self) -> Option<TPair> {
|
||||
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<Block: traits::Block> Default for TestProvider<Block> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
_marker: PhantomData,
|
||||
sr_key: None,
|
||||
ed_key: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: traits::Block> AuthorityKeyProvider<Block> for TestProvider<Block> {
|
||||
type ConsensusPair = ed25519::Pair;
|
||||
type FinalityPair = sr25519::Pair;
|
||||
|
||||
fn authority_key(&self, _: &BlockId<Block>) -> Option<Self::ConsensusPair> {
|
||||
self.ed_key.clone()
|
||||
}
|
||||
|
||||
fn fg_authority_key(&self, _: &BlockId<Block>) -> Option<Self::FinalityPair> {
|
||||
self.sr_key.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Vec<u8>, ()> {
|
||||
fn pubkey(&self, _key: CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
fn new_crypto_key(&mut self, _crypto: CryptoKind) -> Result<CryptoKeyId, ()> {
|
||||
fn new_crypto_key(&mut self, _crypto: CryptoKind) -> Result<CryptoKey, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
}
|
||||
|
||||
fn encrypt(
|
||||
&mut self,
|
||||
_key: Option<CryptoKeyId>,
|
||||
_kind: CryptoKind,
|
||||
_key: CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
@@ -163,8 +162,7 @@ impl offchain::Externalities for TestOffchainExt {
|
||||
|
||||
fn decrypt(
|
||||
&mut self,
|
||||
_key: Option<CryptoKeyId>,
|
||||
_kind: CryptoKind,
|
||||
_key: CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
@@ -172,8 +170,7 @@ impl offchain::Externalities for TestOffchainExt {
|
||||
|
||||
fn sign(
|
||||
&mut self,
|
||||
_key: Option<CryptoKeyId>,
|
||||
_kind: CryptoKind,
|
||||
_key: CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unimplemented!("not needed in tests so far")
|
||||
@@ -181,8 +178,7 @@ impl offchain::Externalities for TestOffchainExt {
|
||||
|
||||
fn verify(
|
||||
&mut self,
|
||||
_key: Option<CryptoKeyId>,
|
||||
_kind: CryptoKind,
|
||||
_key: CryptoKey,
|
||||
_msg: &[u8],
|
||||
_signature: &[u8],
|
||||
) -> Result<bool, ()> {
|
||||
@@ -332,4 +328,3 @@ impl offchain::Externalities for TestOffchainExt {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -457,7 +457,7 @@ impl<T: AsMut<[u8]> + 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<u8>),
|
||||
}
|
||||
|
||||
#[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
|
||||
|
||||
@@ -87,14 +87,49 @@ impl From<CryptoKind> 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<CryptoKeyId> for u32 {
|
||||
fn from(c: CryptoKeyId) -> Self {
|
||||
c.0 as u32
|
||||
impl TryFrom<u64> for CryptoKey {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(key: u64) -> Result<Self, Self::Error> {
|
||||
match key & 0xFF {
|
||||
0 => {
|
||||
let id = (key >> 8 & 0xFFFF) as u16;
|
||||
let kind = CryptoKind::try_from((key >> 32) as u32)?;
|
||||
Ok(CryptoKey::LocalKey { id, kind })
|
||||
}
|
||||
1 => Ok(CryptoKey::AuthorityKey),
|
||||
2 => Ok(CryptoKey::FgAuthorityKey),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CryptoKey> for u64 {
|
||||
fn from(key: CryptoKey) -> u64 {
|
||||
match key {
|
||||
CryptoKey::LocalKey { id, kind } => {
|
||||
((kind as u64) << 32) | ((id as u64) << 8)
|
||||
}
|
||||
CryptoKey::AuthorityKey => 1,
|
||||
CryptoKey::FgAuthorityKey => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,13 +314,13 @@ pub trait Externalities {
|
||||
/// Returns information about the local node's network state.
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()>;
|
||||
|
||||
/// Returns the locally configured authority public key, if available.
|
||||
fn authority_pubkey(&self, crypto: CryptoKind) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Create new key(pair) for signing/encryption/decryption.
|
||||
///
|
||||
/// Returns an error if given crypto kind is not supported.
|
||||
fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result<CryptoKeyId, ()>;
|
||||
fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result<CryptoKey, ()>;
|
||||
|
||||
/// Returns the locally configured authority public key, if available.
|
||||
fn pubkey(&self, key: CryptoKey) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Encrypt a piece of data using given crypto key.
|
||||
///
|
||||
@@ -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<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// 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<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// 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<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Verifies that `signature` for `msg` matches given `key`.
|
||||
///
|
||||
/// Returns an `Ok` with `true` in case it does, `false` in case it doesn't.
|
||||
/// Returns an error in case the key is not available or does not exist or the parameters
|
||||
/// lengths are incorrect or `CryptoKind` does not match.
|
||||
fn verify(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result<bool, ()>;
|
||||
fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result<bool, ()>;
|
||||
|
||||
/// Returns current UNIX timestamp (in millis)
|
||||
fn timestamp(&mut self) -> Timestamp;
|
||||
@@ -431,32 +466,32 @@ impl<T: Externalities + ?Sized> Externalities for Box<T> {
|
||||
(&mut **self).submit_transaction(ex)
|
||||
}
|
||||
|
||||
fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result<CryptoKeyId, ()> {
|
||||
fn new_crypto_key(&mut self, crypto: CryptoKind) -> Result<CryptoKey, ()> {
|
||||
(&mut **self).new_crypto_key(crypto)
|
||||
}
|
||||
|
||||
fn encrypt(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).encrypt(key, kind, data)
|
||||
fn encrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).encrypt(key, data)
|
||||
}
|
||||
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
|
||||
(& **self).network_state()
|
||||
}
|
||||
|
||||
fn authority_pubkey(&self, key:CryptoKind) -> Result<Vec<u8>, ()> {
|
||||
(&**self).authority_pubkey(key)
|
||||
fn pubkey(&self, key: CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
(&**self).pubkey(key)
|
||||
}
|
||||
|
||||
fn decrypt(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).decrypt(key, kind, data)
|
||||
fn decrypt(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).decrypt(key, data)
|
||||
}
|
||||
|
||||
fn sign(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).sign(key, kind, data)
|
||||
fn sign(&mut self, key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
(&mut **self).sign(key, data)
|
||||
}
|
||||
|
||||
fn verify(&mut self, key: Option<CryptoKeyId>, kind: CryptoKind, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
(&mut **self).verify(key, kind, msg, signature)
|
||||
fn verify(&mut self, key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result<bool, ()> {
|
||||
(&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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<C> = <
|
||||
/// Block type for `Components`
|
||||
pub type ComponentBlock<C> = <<C as Components>::Factory as ServiceFactory>::Block;
|
||||
|
||||
/// ConsensusPair type for `Components`
|
||||
pub type ComponentConsensusPair<C> = <<C as Components>::Factory as ServiceFactory>::ConsensusPair;
|
||||
|
||||
/// FinalityPair type for `Components`
|
||||
pub type ComponentFinalityPair<C> = <<C as Components>::Factory as ServiceFactory>::FinalityPair;
|
||||
|
||||
/// AuthorityKeyProvider type for `Components`
|
||||
pub type ComponentAuthorityKeyProvider<C> =
|
||||
AuthorityKeyProvider<ComponentBlock<C>, ComponentConsensusPair<C>, ComponentFinalityPair<C>>;
|
||||
|
||||
/// Extrinsic hash type for `Components`
|
||||
pub type ComponentExHash<C> = <<C as Components>::TransactionPoolApi as txpool::ChainApi>::Hash;
|
||||
|
||||
@@ -231,7 +241,7 @@ pub trait OffchainWorker<C: Components> {
|
||||
offchain: &offchain::OffchainWorkers<
|
||||
ComponentClient<C>,
|
||||
ComponentOffchainStorage<C>,
|
||||
AuthorityKeyProvider,
|
||||
ComponentAuthorityKeyProvider<C>,
|
||||
ComponentBlock<C>
|
||||
>,
|
||||
pool: &Arc<TransactionPool<C::TransactionPoolApi>>,
|
||||
@@ -248,7 +258,7 @@ impl<C: Components> OffchainWorker<Self> for C where
|
||||
offchain: &offchain::OffchainWorkers<
|
||||
ComponentClient<C>,
|
||||
ComponentOffchainStorage<C>,
|
||||
AuthorityKeyProvider,
|
||||
ComponentAuthorityKeyProvider<C>,
|
||||
ComponentBlock<C>
|
||||
>,
|
||||
pool: &Arc<TransactionPool<C::TransactionPoolApi>>,
|
||||
@@ -283,6 +293,10 @@ pub type TaskExecutor = Arc<dyn Executor<Box<dyn Future<Item = (), Error = ()> +
|
||||
pub trait ServiceFactory: 'static + Sized {
|
||||
/// Block type.
|
||||
type Block: BlockT<Hash=H256>;
|
||||
/// Consensus crypto type.
|
||||
type ConsensusPair: Pair;
|
||||
/// Finality crypto type.
|
||||
type FinalityPair: Pair;
|
||||
/// The type that implements the runtime API.
|
||||
type RuntimeApi: Send + Sync;
|
||||
/// Network protocol extensions.
|
||||
|
||||
@@ -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<Components: components::Components> {
|
||||
NetworkStatus<ComponentBlock<Components>>, NetworkState
|
||||
)>>>>,
|
||||
transaction_pool: Arc<TransactionPool<Components::TransactionPoolApi>>,
|
||||
keystore: AuthorityKeyProvider,
|
||||
keystore: ComponentAuthorityKeyProvider<Components>,
|
||||
exit: ::exit_future::Exit,
|
||||
signal: Option<Signal>,
|
||||
/// Sender for futures that must be spawned as background tasks.
|
||||
@@ -102,7 +105,7 @@ pub struct Service<Components: components::Components> {
|
||||
_offchain_workers: Option<Arc<offchain::OffchainWorkers<
|
||||
ComponentClient<Components>,
|
||||
ComponentOffchainStorage<Components>,
|
||||
AuthorityKeyProvider,
|
||||
ComponentAuthorityKeyProvider<Components>,
|
||||
ComponentBlock<Components>>
|
||||
>>,
|
||||
}
|
||||
@@ -264,6 +267,7 @@ impl<Components: components::Components> Service<Components> {
|
||||
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<Components: components::Components> Service<Components> {
|
||||
}
|
||||
|
||||
/// give the authority key, if we are an authority and have a key
|
||||
pub fn authority_key<TPair: Pair>(&self) -> Option<TPair> {
|
||||
pub fn authority_key(&self) -> Option<ComponentConsensusPair<Components>> {
|
||||
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<ComponentFinalityPair<Components>> {
|
||||
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<Components: components::Components> Service<Components> {
|
||||
/// 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<Item = Option<String>, Error = ()> {
|
||||
-> impl Future<Item = Option<String>, Error = ()>
|
||||
{
|
||||
self.rpc_handlers.handle_request(request, mem.metadata.clone())
|
||||
}
|
||||
|
||||
@@ -733,7 +745,7 @@ impl<Components> Drop for Service<Components> where Components: components::Comp
|
||||
fn start_rpc_servers<F: ServiceFactory, H: FnMut() -> rpc::RpcHandler>(
|
||||
config: &FactoryFullConfiguration<F>,
|
||||
mut gen_handler: H
|
||||
) -> Result<Box<std::any::Any + Send + Sync>, error::Error> {
|
||||
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
|
||||
fn maybe_start_server<T, F>(address: Option<SocketAddr>, mut start: F) -> Result<Option<T>, io::Error>
|
||||
where F: FnMut(&SocketAddr) -> Result<T, io::Error>,
|
||||
{
|
||||
@@ -876,16 +888,27 @@ impl<C: Components> network::TransactionPool<ComponentExHash<C>, ComponentBlock<
|
||||
}
|
||||
}
|
||||
|
||||
/// A provider of current authority key.
|
||||
#[derive(Clone)]
|
||||
pub struct AuthorityKeyProvider {
|
||||
/// A provider of current authority key.
|
||||
pub struct AuthorityKeyProvider<Block, ConsensusPair, FinalityPair> {
|
||||
_marker: PhantomData<(Block, ConsensusPair, FinalityPair)>,
|
||||
roles: Roles,
|
||||
keystore: Option<Arc<Keystore>>,
|
||||
password: crypto::Protected<String>,
|
||||
}
|
||||
|
||||
impl offchain::AuthorityKeyProvider for AuthorityKeyProvider {
|
||||
fn authority_key<TPair: Pair>(&self) -> Option<TPair> {
|
||||
impl<Block, ConsensusPair, FinalityPair>
|
||||
offchain::AuthorityKeyProvider<Block>
|
||||
for AuthorityKeyProvider<Block, ConsensusPair, FinalityPair>
|
||||
where
|
||||
Block: runtime_primitives::traits::Block,
|
||||
ConsensusPair: Pair,
|
||||
FinalityPair: Pair,
|
||||
{
|
||||
type ConsensusPair = ConsensusPair;
|
||||
type FinalityPair = FinalityPair;
|
||||
|
||||
fn authority_key(&self, _at: &BlockId<Block>) -> Option<Self::ConsensusPair> {
|
||||
if self.roles != Roles::AUTHORITY {
|
||||
return None
|
||||
}
|
||||
@@ -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<Block>) -> Option<Self::FinalityPair> {
|
||||
if self.roles != Roles::AUTHORITY {
|
||||
return None
|
||||
}
|
||||
|
||||
let keystore = match self.keystore {
|
||||
Some(ref keystore) => keystore,
|
||||
None => return None
|
||||
};
|
||||
|
||||
let loaded_key = keystore
|
||||
.contents()
|
||||
.map(|keys| keys.get(0)
|
||||
.map(|k| keystore.load(k, self.password.as_ref()))
|
||||
);
|
||||
|
||||
if let Ok(Some(Ok(key))) = loaded_key {
|
||||
Some(key)
|
||||
@@ -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;
|
||||
|
||||
@@ -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<OpaqueNetworkState, ()>;
|
||||
|
||||
/// Returns the currently configured authority public key, if available.
|
||||
// TODO [#3139] change into crypto_pubkey(&self, key: Option<CryptoKeyId>, kind: CryptoKind)
|
||||
fn authority_pubkey(crypto: CryptoKind) -> Result<Vec<u8>, ()>;
|
||||
fn pubkey(key: CryptoKey) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Create new key(pair) for signing/encryption/decryption.
|
||||
///
|
||||
/// Returns an error if given crypto kind is not supported.
|
||||
fn new_crypto_key(crypto: CryptoKind) -> Result<CryptoKeyId, ()>;
|
||||
fn new_crypto_key(crypto: CryptoKind) -> Result<CryptoKey, ()>;
|
||||
|
||||
/// Encrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist.
|
||||
fn encrypt(key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
fn encrypt(key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Decrypt a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key.
|
||||
///
|
||||
/// Returns an error if data cannot be decrypted or the `key` is not available or does not exist.
|
||||
fn decrypt(key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
fn decrypt(key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Sign a piece of data using given crypto key.
|
||||
///
|
||||
/// If `key` is `None`, it will attempt to use current authority key.
|
||||
///
|
||||
/// Returns an error if `key` is not available or does not exist.
|
||||
fn sign(key: Option<CryptoKeyId>, kind: CryptoKind, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
fn sign(key: CryptoKey, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
/// Verifies that `signature` for `msg` matches given `key`.
|
||||
///
|
||||
/// Returns an `Ok` with `true` in case it does, `false` in case it doesn't.
|
||||
/// Returns an error in case the key is not available or does not exist or the parameters
|
||||
/// lengths are incorrect.
|
||||
fn verify(
|
||||
key: Option<CryptoKeyId>,
|
||||
kind: CryptoKind,
|
||||
msg: &[u8],
|
||||
signature: &[u8]
|
||||
) -> Result<bool, ()>;
|
||||
fn verify(key: CryptoKey, msg: &[u8], signature: &[u8]) -> Result<bool, ()>;
|
||||
|
||||
/// Returns current UNIX timestamp (in millis)
|
||||
fn timestamp() -> Timestamp;
|
||||
|
||||
@@ -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<Vec<u8>, ()> {
|
||||
fn pubkey(key: offchain::CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
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<offchain::CryptoKeyId, ()> {
|
||||
fn new_crypto_key(crypto: offchain::CryptoKind) -> Result<offchain::CryptoKey, ()> {
|
||||
with_offchain(|ext| {
|
||||
ext.new_crypto_key(crypto)
|
||||
}, "new_crypto_key can be called only in the offchain worker context")
|
||||
}
|
||||
|
||||
fn encrypt(
|
||||
key: Option<offchain::CryptoKeyId>,
|
||||
kind: offchain::CryptoKind,
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
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<offchain::CryptoKeyId>,
|
||||
kind: offchain::CryptoKind,
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
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<offchain::CryptoKeyId>,
|
||||
kind: offchain::CryptoKind,
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
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<offchain::CryptoKeyId>,
|
||||
kind: offchain::CryptoKind,
|
||||
key: offchain::CryptoKey,
|
||||
msg: &[u8],
|
||||
signature: &[u8],
|
||||
) -> Result<bool, ()> {
|
||||
with_offchain(|ext| {
|
||||
ext.verify(key, kind, msg, signature)
|
||||
ext.verify(key, msg, signature)
|
||||
}, "verify can be called only in the offchain worker context")
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Vec<u8>, ()> {
|
||||
let kind = kind as isize as u32;
|
||||
|
||||
fn pubkey(key: CryptoKey) -> Result<Vec<u8>, ()> {
|
||||
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<offchain::CryptoKeyId, ()> {
|
||||
fn new_crypto_key(crypto: offchain::CryptoKind) -> Result<offchain::CryptoKey, ()> {
|
||||
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<offchain::CryptoKeyId>,
|
||||
kind: offchain::CryptoKind,
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
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<offchain::CryptoKeyId>,
|
||||
kind: offchain::CryptoKind,
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
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<offchain::CryptoKeyId>,
|
||||
kind: offchain::CryptoKind,
|
||||
key: offchain::CryptoKey,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
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<offchain::CryptoKeyId>,
|
||||
kind: offchain::CryptoKind,
|
||||
key: offchain::CryptoKey,
|
||||
msg: &[u8],
|
||||
signature: &[u8],
|
||||
) -> Result<bool, ()> {
|
||||
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(),
|
||||
|
||||
@@ -246,9 +246,9 @@ impl offchain::Externalities for NeverOffchainExt {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn authority_pubkey(
|
||||
fn pubkey(
|
||||
&self,
|
||||
_crypto: offchain::CryptoKind,
|
||||
_key: offchain::CryptoKey,
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
@@ -256,14 +256,13 @@ impl offchain::Externalities for NeverOffchainExt {
|
||||
fn new_crypto_key(
|
||||
&mut self,
|
||||
_crypto: offchain::CryptoKind,
|
||||
) -> Result<offchain::CryptoKeyId, ()> {
|
||||
) -> Result<offchain::CryptoKey, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn encrypt(
|
||||
&mut self,
|
||||
_key: Option<offchain::CryptoKeyId>,
|
||||
_kind: offchain::CryptoKind,
|
||||
_key: offchain::CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unreachable!()
|
||||
@@ -271,8 +270,7 @@ impl offchain::Externalities for NeverOffchainExt {
|
||||
|
||||
fn decrypt(
|
||||
&mut self,
|
||||
_key: Option<offchain::CryptoKeyId>,
|
||||
_kind: offchain::CryptoKind,
|
||||
_key: offchain::CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unreachable!()
|
||||
@@ -280,8 +278,7 @@ impl offchain::Externalities for NeverOffchainExt {
|
||||
|
||||
fn sign(
|
||||
&mut self,
|
||||
_key: Option<offchain::CryptoKeyId>,
|
||||
_kind: offchain::CryptoKind,
|
||||
_key: offchain::CryptoKey,
|
||||
_data: &[u8],
|
||||
) -> Result<Vec<u8>, ()> {
|
||||
unreachable!()
|
||||
@@ -289,8 +286,7 @@ impl offchain::Externalities for NeverOffchainExt {
|
||||
|
||||
fn verify(
|
||||
&mut self,
|
||||
_key: Option<offchain::CryptoKeyId>,
|
||||
_kind: offchain::CryptoKind,
|
||||
_key: offchain::CryptoKey,
|
||||
_msg: &[u8],
|
||||
_signature: &[u8],
|
||||
) -> Result<bool, ()> {
|
||||
|
||||
@@ -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::<Pair>() {
|
||||
if let Some(key) = service.authority_key() {
|
||||
info!("Using authority key {}", key.public());
|
||||
let proposer = Arc::new(ProposerFactory {
|
||||
client: service.client(),
|
||||
|
||||
@@ -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<F> Default for NodeConfig<F> 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::<AuraPair>() {
|
||||
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::<grandpa_primitives::AuthorityPair>()
|
||||
service.fg_authority_key()
|
||||
};
|
||||
|
||||
let config = grandpa::Config {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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<T: Trait>(block_number: T::BlockNumber) -> Result<(), OffchainErr> {
|
||||
let kind = match <T::AuthorityId as TypedKey>::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 = <T as Trait>::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())
|
||||
|
||||
Reference in New Issue
Block a user