feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Bizinikiwi block-author/full-node API.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use self::error::{Error, Result};
|
||||
use crate::{
|
||||
utils::{spawn_subscription_task, BoundedVecDeque, PendingSubscription},
|
||||
SubscriptionTaskExecutor,
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
use jsonrpsee::{core::async_trait, types::ErrorObject, Extensions, PendingSubscriptionSink};
|
||||
use pezsc_rpc_api::check_if_safe;
|
||||
use pezsc_transaction_pool_api::{
|
||||
error::IntoPoolError, BlockHash, InPoolTransaction, TransactionFor, TransactionPool,
|
||||
TransactionSource, TxHash, TxInvalidityReportMap,
|
||||
};
|
||||
use pezsp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use pezsp_blockchain::HeaderBackend;
|
||||
use pezsp_core::Bytes;
|
||||
use pezsp_keystore::{KeystoreExt, KeystorePtr};
|
||||
use pezsp_runtime::traits::Block as BlockT;
|
||||
use pezsp_session::SessionKeys;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Re-export the API for backward compatibility.
|
||||
pub use pezsc_rpc_api::author::*;
|
||||
|
||||
/// Authoring API
|
||||
pub struct Author<P, Client> {
|
||||
/// Bizinikiwi client
|
||||
client: Arc<Client>,
|
||||
/// Transactions pool
|
||||
pool: Arc<P>,
|
||||
/// The key store.
|
||||
keystore: KeystorePtr,
|
||||
/// Executor to spawn subscriptions.
|
||||
executor: SubscriptionTaskExecutor,
|
||||
}
|
||||
|
||||
impl<P, Client> Author<P, Client> {
|
||||
/// Create new instance of Authoring API.
|
||||
pub fn new(
|
||||
client: Arc<Client>,
|
||||
pool: Arc<P>,
|
||||
keystore: KeystorePtr,
|
||||
executor: SubscriptionTaskExecutor,
|
||||
) -> Self {
|
||||
Author { client, pool, keystore, executor }
|
||||
}
|
||||
}
|
||||
|
||||
/// Currently we treat all RPC transactions as externals.
|
||||
///
|
||||
/// Possibly in the future we could allow opt-in for special treatment
|
||||
/// of such transactions, so that the block authors can inject
|
||||
/// some unique transactions via RPC and have them included in the pool.
|
||||
const TX_SOURCE: TransactionSource = TransactionSource::External;
|
||||
|
||||
#[async_trait]
|
||||
impl<P, Client> AuthorApiServer<TxHash<P>, BlockHash<P>> for Author<P, Client>
|
||||
where
|
||||
P: TransactionPool + Sync + Send + 'static,
|
||||
Client: HeaderBackend<P::Block> + ProvideRuntimeApi<P::Block> + Send + Sync + 'static,
|
||||
Client::Api: SessionKeys<P::Block>,
|
||||
P::Hash: Unpin,
|
||||
<P::Block as BlockT>::Hash: Unpin,
|
||||
{
|
||||
async fn submit_extrinsic(&self, ext: Bytes) -> Result<TxHash<P>> {
|
||||
let xt = match Decode::decode(&mut &ext[..]) {
|
||||
Ok(xt) => xt,
|
||||
Err(err) => return Err(Error::Client(Box::new(err)).into()),
|
||||
};
|
||||
let best_block_hash = self.client.info().best_hash;
|
||||
self.pool.submit_one(best_block_hash, TX_SOURCE, xt).await.map_err(|e| {
|
||||
e.into_pool_error()
|
||||
.map(|e| Error::Pool(e))
|
||||
.unwrap_or_else(|e| Error::Verification(Box::new(e)))
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
fn insert_key(
|
||||
&self,
|
||||
ext: &Extensions,
|
||||
key_type: String,
|
||||
suri: String,
|
||||
public: Bytes,
|
||||
) -> Result<()> {
|
||||
check_if_safe(ext)?;
|
||||
|
||||
let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?;
|
||||
self.keystore
|
||||
.insert(key_type, &suri, &public[..])
|
||||
.map_err(|_| Error::KeystoreUnavailable)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn rotate_keys(&self, ext: &Extensions) -> Result<Bytes> {
|
||||
check_if_safe(ext)?;
|
||||
|
||||
let best_block_hash = self.client.info().best_hash;
|
||||
let mut runtime_api = self.client.runtime_api();
|
||||
|
||||
runtime_api.register_extension(KeystoreExt::from(self.keystore.clone()));
|
||||
|
||||
runtime_api
|
||||
.generate_session_keys(best_block_hash, None)
|
||||
.map(Into::into)
|
||||
.map_err(|api_err| Error::Client(Box::new(api_err)).into())
|
||||
}
|
||||
|
||||
fn has_session_keys(&self, ext: &Extensions, session_keys: Bytes) -> Result<bool> {
|
||||
check_if_safe(ext)?;
|
||||
|
||||
let best_block_hash = self.client.info().best_hash;
|
||||
let keys = self
|
||||
.client
|
||||
.runtime_api()
|
||||
.decode_session_keys(best_block_hash, session_keys.to_vec())
|
||||
.map_err(|e| Error::Client(Box::new(e)))?
|
||||
.ok_or(Error::InvalidSessionKeys)?;
|
||||
|
||||
Ok(self.keystore.has_keys(&keys))
|
||||
}
|
||||
|
||||
fn has_key(&self, ext: &Extensions, public_key: Bytes, key_type: String) -> Result<bool> {
|
||||
check_if_safe(ext)?;
|
||||
|
||||
let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?;
|
||||
Ok(self.keystore.has_keys(&[(public_key.to_vec(), key_type)]))
|
||||
}
|
||||
|
||||
fn pending_extrinsics(&self) -> Result<Vec<Bytes>> {
|
||||
Ok(self.pool.ready().map(|tx| tx.data().encode().into()).collect())
|
||||
}
|
||||
|
||||
async fn remove_extrinsic(
|
||||
&self,
|
||||
ext: &Extensions,
|
||||
bytes_or_hash: Vec<hash::ExtrinsicOrHash<TxHash<P>>>,
|
||||
) -> Result<Vec<TxHash<P>>> {
|
||||
check_if_safe(ext)?;
|
||||
let hashes = bytes_or_hash
|
||||
.into_iter()
|
||||
.map(|x| match x {
|
||||
hash::ExtrinsicOrHash::Hash(h) => Ok((h, None)),
|
||||
hash::ExtrinsicOrHash::Extrinsic(bytes) => {
|
||||
let xt = Decode::decode(&mut &bytes[..])?;
|
||||
Ok((self.pool.hash_of(&xt), None))
|
||||
},
|
||||
})
|
||||
.collect::<Result<TxInvalidityReportMap<TxHash<P>>>>()?;
|
||||
|
||||
Ok(self
|
||||
.pool
|
||||
.report_invalid(None, hashes)
|
||||
.await
|
||||
.into_iter()
|
||||
.map(|tx| tx.hash().clone())
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn watch_extrinsic(&self, pending: PendingSubscriptionSink, xt: Bytes) {
|
||||
let best_block_hash = self.client.info().best_hash;
|
||||
let dxt = match TransactionFor::<P>::decode(&mut &xt[..]).map_err(|e| Error::from(e)) {
|
||||
Ok(dxt) => dxt,
|
||||
Err(e) => {
|
||||
spawn_subscription_task(&self.executor, pending.reject(e));
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
let pool = self.pool.clone();
|
||||
let fut = async move {
|
||||
let submit =
|
||||
pool.submit_and_watch(best_block_hash, TX_SOURCE, dxt).await.map_err(|e| {
|
||||
e.into_pool_error()
|
||||
.map(error::Error::from)
|
||||
.unwrap_or_else(|e| error::Error::Verification(Box::new(e)))
|
||||
});
|
||||
|
||||
let stream = match submit {
|
||||
Ok(stream) => stream,
|
||||
Err(err) => {
|
||||
let _ = pending.reject(ErrorObject::from(err)).await;
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
PendingSubscription::from(pending)
|
||||
.pipe_from_stream(stream, BoundedVecDeque::default())
|
||||
.await;
|
||||
};
|
||||
|
||||
spawn_subscription_task(&self.executor, fut);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
|
||||
use crate::testing::{test_executor, timeout_secs};
|
||||
use assert_matches::assert_matches;
|
||||
use codec::Encode;
|
||||
use jsonrpsee::{core::EmptyServerParams as EmptyParams, MethodsError as RpcError, RpcModule};
|
||||
use pezsc_rpc_api::DenyUnsafe;
|
||||
use pezsc_transaction_pool::{BasicPool, FullChainApi};
|
||||
use pezsc_transaction_pool_api::TransactionStatus;
|
||||
use pezsp_core::{
|
||||
bytes::to_hex,
|
||||
crypto::{ByteArray, Pair},
|
||||
ed25519,
|
||||
testing::{ED25519, SR25519},
|
||||
H256,
|
||||
};
|
||||
use pezsp_crypto_hashing::blake2_256;
|
||||
use pezsp_keystore::{testing::MemoryKeystore, Keystore};
|
||||
use pezsp_runtime::Perbill;
|
||||
use std::sync::Arc;
|
||||
use bizinikiwi_test_runtime_client::{
|
||||
self,
|
||||
runtime::{Block, Extrinsic, ExtrinsicBuilder, SessionKeys, Transfer},
|
||||
Backend, Client, DefaultTestClientBuilderExt, Sr25519Keyring, TestClientBuilderExt,
|
||||
};
|
||||
|
||||
fn uxt(sender: Sr25519Keyring, nonce: u64) -> Extrinsic {
|
||||
let tx = Transfer {
|
||||
amount: Default::default(),
|
||||
nonce,
|
||||
from: sender.into(),
|
||||
to: Sr25519Keyring::Bob.into(),
|
||||
};
|
||||
ExtrinsicBuilder::new_transfer(tx).build()
|
||||
}
|
||||
|
||||
type FullTransactionPool = BasicPool<FullChainApi<Client<Backend>, Block>, Block>;
|
||||
|
||||
struct TestSetup {
|
||||
pub client: Arc<Client<Backend>>,
|
||||
pub keystore: Arc<MemoryKeystore>,
|
||||
pub pool: Arc<FullTransactionPool>,
|
||||
}
|
||||
|
||||
impl Default for TestSetup {
|
||||
fn default() -> Self {
|
||||
let keystore = Arc::new(MemoryKeystore::new());
|
||||
let client = Arc::new(bizinikiwi_test_runtime_client::TestClientBuilder::new().build());
|
||||
|
||||
let spawner = pezsp_core::testing::TaskExecutor::new();
|
||||
let pool = Arc::from(BasicPool::new_full(
|
||||
Default::default(),
|
||||
true.into(),
|
||||
None,
|
||||
spawner,
|
||||
client.clone(),
|
||||
));
|
||||
TestSetup { client, keystore, pool }
|
||||
}
|
||||
}
|
||||
|
||||
impl TestSetup {
|
||||
fn to_rpc(&self) -> RpcModule<Author<FullTransactionPool, Client<Backend>>> {
|
||||
let mut module = Author {
|
||||
client: self.client.clone(),
|
||||
pool: self.pool.clone(),
|
||||
keystore: self.keystore.clone(),
|
||||
executor: test_executor(),
|
||||
}
|
||||
.into_rpc();
|
||||
module.extensions_mut().insert(DenyUnsafe::No);
|
||||
module
|
||||
}
|
||||
|
||||
fn into_rpc() -> RpcModule<Author<FullTransactionPool, Client<Backend>>> {
|
||||
Self::default().to_rpc()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn author_submit_transaction_should_not_cause_error() {
|
||||
let api = TestSetup::into_rpc();
|
||||
|
||||
let xt: Bytes = uxt(Sr25519Keyring::Alice, 1).encode().into();
|
||||
let extrinsic_hash: H256 = blake2_256(&xt).into();
|
||||
let response: H256 = api.call("author_submitExtrinsic", [xt.clone()]).await.unwrap();
|
||||
|
||||
assert_eq!(response, extrinsic_hash);
|
||||
|
||||
assert_matches!(
|
||||
api.call::<_, H256>("author_submitExtrinsic", [xt]).await,
|
||||
Err(RpcError::JsonRpc(err)) if err.message().contains("Already Imported") && err.code() == 1013
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn author_should_watch_extrinsic() {
|
||||
let api = TestSetup::into_rpc();
|
||||
let xt = to_hex(
|
||||
&ExtrinsicBuilder::new_call_with_priority(0)
|
||||
.signer(Sr25519Keyring::Alice.into())
|
||||
.build()
|
||||
.encode(),
|
||||
true,
|
||||
);
|
||||
|
||||
let mut sub = api.subscribe_unbounded("author_submitAndWatchExtrinsic", [xt]).await.unwrap();
|
||||
let (tx, sub_id) = timeout_secs(10, sub.next::<TransactionStatus<H256, Block>>())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_matches!(tx, TransactionStatus::Ready);
|
||||
assert_eq!(&sub_id, sub.subscription_id());
|
||||
|
||||
// Replace the extrinsic and observe the subscription is notified.
|
||||
let (xt_replacement, xt_hash) = {
|
||||
let tx = ExtrinsicBuilder::new_call_with_priority(1)
|
||||
.signer(Sr25519Keyring::Alice.into())
|
||||
.build()
|
||||
.encode();
|
||||
let hash = blake2_256(&tx);
|
||||
(to_hex(&tx, true), hash)
|
||||
};
|
||||
|
||||
let _ = api.call::<_, H256>("author_submitExtrinsic", [xt_replacement]).await.unwrap();
|
||||
|
||||
let (tx, sub_id) = timeout_secs(10, sub.next::<TransactionStatus<H256, Block>>())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(tx, TransactionStatus::Usurped(xt_hash.into()));
|
||||
assert_eq!(&sub_id, sub.subscription_id());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn author_should_return_watch_validation_error() {
|
||||
const METHOD: &'static str = "author_submitAndWatchExtrinsic";
|
||||
|
||||
let invalid_xt = ExtrinsicBuilder::new_fill_block(Perbill::from_percent(100)).build();
|
||||
|
||||
let api = TestSetup::into_rpc();
|
||||
let failed_sub = api.subscribe_unbounded(METHOD, [to_hex(&invalid_xt.encode(), true)]).await;
|
||||
|
||||
assert_matches!(
|
||||
failed_sub,
|
||||
Err(RpcError::JsonRpc(err)) if err.message().contains("Invalid Transaction") && err.code() == 1010
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn author_should_return_pending_extrinsics() {
|
||||
let api = TestSetup::into_rpc();
|
||||
|
||||
let xt_bytes: Bytes = uxt(Sr25519Keyring::Alice, 0).encode().into();
|
||||
api.call::<_, H256>("author_submitExtrinsic", [to_hex(&xt_bytes, true)])
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let pending: Vec<Bytes> =
|
||||
api.call("author_pendingExtrinsics", EmptyParams::new()).await.unwrap();
|
||||
assert_eq!(pending, vec![xt_bytes]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn author_should_remove_extrinsics() {
|
||||
const METHOD: &'static str = "author_removeExtrinsic";
|
||||
let setup = TestSetup::default();
|
||||
let api = setup.to_rpc();
|
||||
|
||||
// Submit three extrinsics, then remove two of them (will cause the third to be removed as well,
|
||||
// having a higher nonce)
|
||||
let xt1_bytes = uxt(Sr25519Keyring::Alice, 0).encode();
|
||||
let xt1 = to_hex(&xt1_bytes, true);
|
||||
let xt1_hash: H256 = api.call("author_submitExtrinsic", [xt1]).await.unwrap();
|
||||
|
||||
let xt2 = to_hex(&uxt(Sr25519Keyring::Alice, 1).encode(), true);
|
||||
let xt2_hash: H256 = api.call("author_submitExtrinsic", [xt2]).await.unwrap();
|
||||
|
||||
let xt3 = to_hex(&uxt(Sr25519Keyring::Bob, 0).encode(), true);
|
||||
let xt3_hash: H256 = api.call("author_submitExtrinsic", [xt3]).await.unwrap();
|
||||
assert_eq!(setup.pool.status().ready, 3);
|
||||
|
||||
// Now remove all three.
|
||||
// Notice how we need an extra `Vec` wrapping the `Vec` we want to submit as params.
|
||||
let removed: Vec<H256> = api
|
||||
.call(
|
||||
METHOD,
|
||||
vec![vec![
|
||||
hash::ExtrinsicOrHash::Hash(xt3_hash),
|
||||
// Removing this one will also remove xt2
|
||||
hash::ExtrinsicOrHash::Extrinsic(xt1_bytes.into()),
|
||||
]],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(removed, vec![xt1_hash, xt2_hash, xt3_hash]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn author_should_insert_key() {
|
||||
let setup = TestSetup::default();
|
||||
let api = setup.to_rpc();
|
||||
let suri = "//Alice";
|
||||
let keypair = ed25519::Pair::from_string(suri, None).expect("generates keypair");
|
||||
let params: (String, String, Bytes) = (
|
||||
String::from_utf8(ED25519.0.to_vec()).expect("Keytype is a valid string"),
|
||||
suri.to_string(),
|
||||
keypair.public().0.to_vec().into(),
|
||||
);
|
||||
api.call::<_, ()>("author_insertKey", params).await.unwrap();
|
||||
let pubkeys = setup.keystore.keys(ED25519).unwrap();
|
||||
|
||||
assert!(pubkeys.contains(&keypair.public().to_raw_vec()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn author_should_rotate_keys() {
|
||||
let setup = TestSetup::default();
|
||||
let api = setup.to_rpc();
|
||||
|
||||
let new_pubkeys: Bytes = api.call("author_rotateKeys", EmptyParams::new()).await.unwrap();
|
||||
let session_keys =
|
||||
SessionKeys::decode(&mut &new_pubkeys[..]).expect("SessionKeys decode successfully");
|
||||
let ed25519_pubkeys = setup.keystore.keys(ED25519).unwrap();
|
||||
let sr25519_pubkeys = setup.keystore.keys(SR25519).unwrap();
|
||||
assert!(ed25519_pubkeys.contains(&session_keys.ed25519.to_raw_vec()));
|
||||
assert!(sr25519_pubkeys.contains(&session_keys.sr25519.to_raw_vec()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn author_has_session_keys() {
|
||||
let api = TestSetup::into_rpc();
|
||||
|
||||
// Add a valid session key
|
||||
let pubkeys: Bytes = api
|
||||
.call("author_rotateKeys", EmptyParams::new())
|
||||
.await
|
||||
.expect("Rotates the keys");
|
||||
|
||||
// Add a session key in a different keystore
|
||||
let non_existent_pubkeys: Bytes = {
|
||||
let api2 = TestSetup::into_rpc();
|
||||
api2.call("author_rotateKeys", EmptyParams::new())
|
||||
.await
|
||||
.expect("Rotates the keys")
|
||||
};
|
||||
|
||||
// Then…
|
||||
let existing = api.call::<_, bool>("author_hasSessionKeys", vec![pubkeys]).await.unwrap();
|
||||
assert!(existing, "Existing key is in the session keys");
|
||||
|
||||
let inexistent = api
|
||||
.call::<_, bool>("author_hasSessionKeys", vec![non_existent_pubkeys])
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(inexistent, false, "Inexistent key is not in the session keys");
|
||||
|
||||
assert_matches!(
|
||||
api.call::<_, bool>("author_hasSessionKeys", vec![Bytes::from(vec![1, 2, 3])]).await,
|
||||
Err(RpcError::JsonRpc(err)) if err.message().contains("Session keys are not encoded correctly")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn author_has_key() {
|
||||
let api = TestSetup::into_rpc();
|
||||
let suri = "//Alice";
|
||||
let alice_keypair = ed25519::Pair::from_string(suri, None).expect("Generates keypair");
|
||||
let params = (
|
||||
String::from_utf8(ED25519.0.to_vec()).expect("Keytype is a valid string"),
|
||||
suri.to_string(),
|
||||
Bytes::from(alice_keypair.public().0.to_vec()),
|
||||
);
|
||||
|
||||
api.call::<_, ()>("author_insertKey", params).await.expect("insertKey works");
|
||||
|
||||
let bob_keypair = ed25519::Pair::from_string("//Bob", None).expect("Generates keypair");
|
||||
|
||||
// Alice's ED25519 key is there
|
||||
let has_alice_ed: bool = {
|
||||
let params = (
|
||||
Bytes::from(alice_keypair.public().to_raw_vec()),
|
||||
String::from_utf8(ED25519.0.to_vec()).expect("Keytype is a valid string"),
|
||||
);
|
||||
api.call("author_hasKey", params).await.unwrap()
|
||||
};
|
||||
assert!(has_alice_ed);
|
||||
|
||||
// Alice's SR25519 key is not there
|
||||
let has_alice_sr: bool = {
|
||||
let params = (
|
||||
Bytes::from(alice_keypair.public().to_raw_vec()),
|
||||
String::from_utf8(SR25519.0.to_vec()).expect("Keytype is a valid string"),
|
||||
);
|
||||
api.call("author_hasKey", params).await.unwrap()
|
||||
};
|
||||
assert!(!has_alice_sr);
|
||||
|
||||
// Bob's ED25519 key is not there
|
||||
let has_bob_ed: bool = {
|
||||
let params = (
|
||||
Bytes::from(bob_keypair.public().to_raw_vec()),
|
||||
String::from_utf8(ED25519.0.to_vec()).expect("Keytype is a valid string"),
|
||||
);
|
||||
api.call("author_hasKey", params).await.unwrap()
|
||||
};
|
||||
assert!(!has_bob_ed);
|
||||
}
|
||||
Reference in New Issue
Block a user