From 8262636658a5b127a2cdb42c282ea8198e1ac03e Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Tue, 8 Feb 2022 17:04:14 +1100 Subject: [PATCH] add a mutex for tla functions --- workspaces/Cargo.toml | 1 + workspaces/src/network/sandbox_shared.rs | 23 ++++++++++++++--------- workspaces/src/rpc/client.rs | 10 +++++++++- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/workspaces/Cargo.toml b/workspaces/Cargo.toml index 490f7234..2ed6dcb8 100644 --- a/workspaces/Cargo.toml +++ b/workspaces/Cargo.toml @@ -9,6 +9,7 @@ Library for automating workflows and testing NEAR smart contracts. """ [dependencies] +async-mutex = "1.4.0" async-trait = "0.1" anyhow = "1.0" base64 = "0.13" diff --git a/workspaces/src/network/sandbox_shared.rs b/workspaces/src/network/sandbox_shared.rs index 9254ba60..d153ef7e 100644 --- a/workspaces/src/network/sandbox_shared.rs +++ b/workspaces/src/network/sandbox_shared.rs @@ -1,18 +1,17 @@ -use std::path::PathBuf; -use std::str::FromStr; - -use async_trait::async_trait; -use once_cell::sync::Lazy; - use super::{ Account, AllowDevAccountCreation, AllowStatePatching, CallExecution, Contract, NetworkClient, NetworkInfo, TopLevelAccountCreator, }; - +use crate::network::sandbox::NEAR_BASE; use crate::network::server::SandboxServer; use crate::network::Info; use crate::rpc::client::Client; use crate::types::{AccountId, Balance, InMemorySigner, SecretKey}; +use async_mutex::Mutex; +use async_trait::async_trait; +use once_cell::sync::Lazy; +use std::path::PathBuf; +use std::str::FromStr; static SHARED_SERVER: Lazy = Lazy::new(|| { let mut server = SandboxServer::default(); @@ -20,8 +19,10 @@ static SHARED_SERVER: Lazy = Lazy::new(|| { server }); -// Constant taken from nearcore crate to avoid dependency -pub(crate) const NEAR_BASE: Balance = 1_000_000_000_000_000_000_000_000; +// Using a shared sandbox instance is thread-safe as long as all threads use it with their own +// account. This means, however, is that the creation of these accounts should be sequential in +// order to avoid duplicated nonces. +static TLA_ACCOUNT_MUTEX: Lazy> = Lazy::new(|| Mutex::new(())); const DEFAULT_DEPOSIT: Balance = 100 * NEAR_BASE; @@ -69,10 +70,12 @@ impl TopLevelAccountCreator for SandboxShared { sk: SecretKey, ) -> anyhow::Result> { let root_signer = self.root_signer(); + let guard = TLA_ACCOUNT_MUTEX.lock().await; let outcome = self .client .create_account(&root_signer, &id, sk.public_key(), DEFAULT_DEPOSIT) .await?; + drop(guard); let signer = InMemorySigner::from_secret_key(id.clone(), sk); Ok(CallExecution { @@ -88,6 +91,7 @@ impl TopLevelAccountCreator for SandboxShared { wasm: &[u8], ) -> anyhow::Result> { let root_signer = self.root_signer(); + let guard = TLA_ACCOUNT_MUTEX.lock().await; let outcome = self .client .create_account_and_deploy( @@ -98,6 +102,7 @@ impl TopLevelAccountCreator for SandboxShared { wasm.into(), ) .await?; + drop(guard); let signer = InMemorySigner::from_secret_key(id.clone(), sk); Ok(CallExecution { diff --git a/workspaces/src/rpc/client.rs b/workspaces/src/rpc/client.rs index 49290642..51160e7d 100644 --- a/workspaces/src/rpc/client.rs +++ b/workspaces/src/rpc/client.rs @@ -41,7 +41,15 @@ impl Client { &self, method: &M, ) -> MethodCallResult { - retry(|| async { JsonRpcClient::connect(&self.rpc_addr).call(method).await }).await + retry(|| async { + // A new client is required since using a shared one between different threads can + // cause https://github.com/hyperium/hyper/issues/2112 + JsonRpcClient::new_client() + .connect(&self.rpc_addr) + .call(method) + .await + }) + .await } async fn send_tx_and_retry(