Skip to content

Commit

Permalink
Only use the Db accounts for CDD/Sudo accounts. User accounts use a l…
Browse files Browse the repository at this point in the history
…ockable signer.
  • Loading branch information
Neopallium committed Jun 21, 2024
1 parent 2056d09 commit b0a6f8e
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 125 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ members = [
# Our crates
polymesh-api-codegen-macro = { version = "3.4.0", path = "crates/polymesh-api-codegen-macro", default-features = false }
polymesh-api-codegen = { version = "3.4.0", path = "crates/polymesh-api-codegen", default-features = false }
polymesh-api-client = { version = "3.6.0", path = "crates/polymesh-api-client", default-features = false }
polymesh-api-client = { version = "3.7.0", path = "crates/polymesh-api-client", default-features = false }
polymesh-api-client-extras = { version = "3.3.0", path = "crates/polymesh-api-client-extras", default-features = false }
polymesh-api-ink = { version = "1.3.0", path = "crates/polymesh-api-ink", default-features = false }
polymesh-api = { version = "3.7.0", path = "./", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion crates/polymesh-api-client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "polymesh-api-client"
version = "3.6.0"
version = "3.7.0"
edition = "2021"
authors = ["Robert G. Jakabosky <[email protected]>"]
license = "Apache-2.0"
Expand Down
43 changes: 33 additions & 10 deletions crates/polymesh-api-client/src/signer.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#[cfg(feature = "std")]
use sp_core::Pair;

use core::ops::{Deref, DerefMut};
use std::sync::Arc;

use sp_runtime::MultiSignature;
use sp_std::prelude::*;

use tokio::sync::{Mutex, MutexGuard};
use tokio::sync::{Mutex, OwnedMutexGuard};

use async_trait::async_trait;

Expand Down Expand Up @@ -78,22 +81,37 @@ pub mod dev {
}
}

pub struct LockableSigner(Mutex<Box<dyn Signer>>);
#[derive(Clone)]
pub struct LockableSigner<S>(Arc<Mutex<S>>);

impl LockableSigner {
pub fn new<S: Signer + 'static>(signer: S) -> Self {
Self(Mutex::new(Box::new(signer)))
impl<S: Signer + 'static> LockableSigner<S> {
pub fn new(signer: S) -> Self {
Self(Arc::new(Mutex::new(signer)))
}

pub async fn lock(&self) -> LockedSigner<'_> {
LockedSigner(self.0.lock().await)
pub async fn lock(&self) -> LockedSigner<S> {
LockedSigner(self.0.clone().lock_owned().await)
}
}

pub struct LockedSigner<'a>(MutexGuard<'a, Box<dyn Signer>>);
pub struct LockedSigner<S>(OwnedMutexGuard<S>);

impl<S> Deref for LockedSigner<S> {
type Target = S;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<S> DerefMut for LockedSigner<S> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

#[async_trait]
impl<'a> Signer for LockedSigner<'a> {
impl<S: Signer> Signer for LockedSigner<S> {
fn account(&self) -> AccountId {
self.0.account()
}
Expand Down Expand Up @@ -128,7 +146,8 @@ pub trait Signer: Send + Sync {

async fn sign(&self, msg: &[u8]) -> Result<MultiSignature>;

async fn lock(&self) -> Option<LockedSigner<'_>> {
/// Optional support for locking the signer.
async fn lock(&self) -> Option<Box<dyn Signer>> {
None
}
}
Expand Down Expand Up @@ -260,6 +279,10 @@ impl Signer for Box<dyn Signer> {
async fn sign(&self, msg: &[u8]) -> Result<MultiSignature> {
self.as_ref().sign(msg).await
}

async fn lock(&self) -> Option<Box<dyn Signer>> {
self.as_ref().lock().await
}
}

#[async_trait]
Expand Down

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/polymesh-api-tester/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "polymesh-api-tester"
version = "0.5.1"
version = "0.6.0"
edition = "2021"
authors = ["Robert G. Jakabosky <[email protected]>"]
license = "Apache-2.0"
Expand Down
105 changes: 50 additions & 55 deletions crates/polymesh-api-tester/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,56 @@ use std::sync::Arc;
use sp_keyring::{ed25519, sr25519};
use sp_runtime::MultiSignature;

use polymesh_api::client::{
AccountId, KeypairSigner, LockableSigner, LockedSigner, PairSigner, Signer,
};
use polymesh_api::client::{AccountId, KeypairSigner, LockableSigner, PairSigner, Signer};

use crate::error::Result;
use crate::Db;

struct AccountSignerInner {
signer: Box<dyn Signer + Send + Sync>,
db: Option<Db>,
/// DbAccountSigner is wrapper for signing keys (sr25519, ed25519, etc...) and using
/// a local Database for managing account nonces.
#[derive(Clone)]
pub struct DbAccountSigner {
signer: Arc<dyn Signer + Send + Sync>,
db: Db,
account: AccountId,
}

impl DbAccountSigner {
pub fn new<P: KeypairSigner + 'static>(db: Db, pair: P) -> Self {
let signer = PairSigner::new(pair);
let account = signer.account();
Self {
signer: Arc::new(signer),
db: db.clone(),
account,
}
}

pub fn alice(db: Db) -> Self {
Self::new(db, sr25519::Keyring::Alice.pair())
}

pub fn bob(db: Db) -> Self {
Self::new(db, sr25519::Keyring::Bob.pair())
}

/// Generate signing key pair from string `s`.
pub fn from_string(db: Db, s: &str) -> Result<Self> {
Ok(Self::new(
db,
<sr25519::sr25519::Pair as KeypairSigner>::from_string(s, None)?,
))
}
}

#[async_trait::async_trait]
impl Signer for AccountSignerInner {
impl Signer for DbAccountSigner {
fn account(&self) -> AccountId {
self.signer.account()
self.account
}

async fn nonce(&self) -> Option<u32> {
match &self.db {
Some(db) => db.get_nonce(self.account()).await.ok(),
None => None,
}
}

async fn set_nonce(&mut self, nonce: u32) {
match &self.db {
Some(db) => {
if let Err(err) = db.set_nonce(self.account(), nonce).await {
log::error!("Failed to update account nonce in DB: {err:?}");
}
}
None => (),
}
self.db.get_next_nonce(self.account).await.ok()
}

async fn sign(&self, msg: &[u8]) -> polymesh_api::client::Result<MultiSignature> {
Expand All @@ -47,49 +63,37 @@ impl Signer for AccountSignerInner {
/// AccountSigner is wrapper for signing keys (sr25519, ed25519, etc...).
#[derive(Clone)]
pub struct AccountSigner {
signer: Arc<LockableSigner>,
signer: Arc<LockableSigner<Box<dyn Signer>>>,
account: AccountId,
}

impl AccountSigner {
pub fn new<P: KeypairSigner + 'static>(db: Option<Db>, pair: P) -> Self {
pub fn new<P: KeypairSigner + 'static>(pair: P) -> Self {
let signer = PairSigner::new(pair);
let account = signer.account();
Self {
signer: Arc::new(LockableSigner::new(AccountSignerInner {
signer: Box::new(signer),
db: db.clone(),
})),
signer: Arc::new(LockableSigner::new(Box::new(signer))),
account,
}
}

pub fn alice(db: Option<Db>) -> Self {
Self::new(db, sr25519::Keyring::Alice.pair())
}

pub fn bob(db: Option<Db>) -> Self {
Self::new(db, sr25519::Keyring::Bob.pair())
}

/// Generate signing key pair from string `s`.
pub fn from_string(db: Option<Db>, s: &str) -> Result<Self> {
pub fn from_string(s: &str) -> Result<Self> {
Ok(Self::new(
db,
<sr25519::sr25519::Pair as KeypairSigner>::from_string(s, None)?,
))
}
}

impl From<sr25519::Keyring> for AccountSigner {
fn from(key: sr25519::Keyring) -> Self {
Self::new(None, key.pair())
Self::new(key.pair())
}
}

impl From<ed25519::Keyring> for AccountSigner {
fn from(key: ed25519::Keyring) -> Self {
Self::new(None, key.pair())
Self::new(key.pair())
}
}

Expand All @@ -99,22 +103,13 @@ impl Signer for AccountSigner {
self.account.clone()
}

async fn nonce(&self) -> Option<u32> {
let inner = self.signer.lock().await;
inner.nonce().await
}

async fn set_nonce(&mut self, nonce: u32) {
let mut inner = self.signer.lock().await;
inner.set_nonce(nonce).await
}

async fn sign(&self, msg: &[u8]) -> polymesh_api::client::Result<MultiSignature> {
let inner = self.signer.lock().await;
Ok(inner.sign(msg).await?)
let locked = self.signer.lock().await;
locked.sign(msg).await
}

async fn lock(&self) -> Option<LockedSigner<'_>> {
Some(self.signer.lock().await)
async fn lock(&self) -> Option<Box<dyn Signer>> {
let locked = self.signer.lock().await;
Some(Box::new(locked))
}
}
23 changes: 3 additions & 20 deletions crates/polymesh-api-tester/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use sqlx::SqlitePool;
use sqlx::sqlite::*;

use polymesh_api::client::AccountId;
use polymesh_api::{Api, ChainApi};
Expand All @@ -17,7 +17,7 @@ impl Db {
Ok(Self { api, pool })
}

pub async fn get_nonce(&self, account: AccountId) -> Result<u32> {
pub async fn get_next_nonce(&self, account: AccountId) -> Result<u32> {
// Get the nonce from the chain. (to check if the db nonce is old).
let nonce = self.api.get_nonce(account).await?;

Expand All @@ -26,7 +26,7 @@ impl Db {
let rec = sqlx::query!(
r#"
INSERT INTO accounts(account, nonce) VALUES(?, ?)
ON CONFLICT(account) DO UPDATE SET nonce=MAX(nonce, excluded.nonce)
ON CONFLICT(account) DO UPDATE SET nonce=MAX(nonce+1, excluded.nonce)
RETURNING nonce
"#,
id,
Expand All @@ -37,21 +37,4 @@ impl Db {

Ok(rec.nonce as u32)
}

pub async fn set_nonce(&self, account: AccountId, nonce: u32) -> Result<bool> {
let id = account.to_string();
// Save the nonce to the database.
let rows = sqlx::query!(
r#"
UPDATE accounts SET nonce = ? WHERE account = ?
"#,
nonce,
id
)
.execute(&self.pool)
.await?
.rows_affected();

Ok(rows > 0)
}
}
4 changes: 4 additions & 0 deletions crates/polymesh-api-tester/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ impl Signer for User {
async fn sign(&self, msg: &[u8]) -> polymesh_api::client::Result<sp_runtime::MultiSignature> {
Ok(self.primary_key.sign(msg).await?)
}

async fn lock(&self) -> Option<Box<dyn Signer>> {
self.primary_key.lock().await
}
}

impl User {
Expand Down
Loading

0 comments on commit b0a6f8e

Please sign in to comment.