Skip to content

Commit

Permalink
fix: make users wait for sandbox to completely startup (#99)
Browse files Browse the repository at this point in the history
* Added wait_for_rpc

* Make testnet/mainnet functions async + some more docs

* Fix examples

* Made testnet(_archival) and mainnet(_archival) return consistent w/ sandbox

* Remove unused imports

* Fmt

* fix example and readme

Co-authored-by: austinabell <austinabell8@gmail.com>
  • Loading branch information
ChaoticTempest and austinabell committed Apr 5, 2022
1 parent 5fe9cb8 commit 8f12f3d
Show file tree
Hide file tree
Showing 18 changed files with 109 additions and 64 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use workspaces::prelude::*;

#[tokio::test]
async fn test_deploy_and_view() -> anyhow::Result<()> {
let worker = workspaces::sandbox();
let worker = workspaces::sandbox().await?;

let contract = worker.dev_deploy(include_bytes!("path/to/file.wasm"))
.await
Expand Down Expand Up @@ -67,12 +67,12 @@ cargo run --example nft

```rust
#[tokio::main] # or whatever runtime we want
async fn main() {
async fn main() -> anyhow::Result<()> {
// Create a sandboxed environment.
// NOTE: Each call will create a new sandboxed environment
let worker = workspaces::sandbox();
let worker = workspaces::sandbox().await?;
// or for testnet:
let worker = workspaces::testnet();
let worker = workspaces::testnet().await?;
}
```

Expand Down
2 changes: 1 addition & 1 deletion examples/src/fast_forward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const SIMPLE_WASM_FILEPATH: &str = "./examples/res/simple_contract.wasm";
/// to be produced, which could take hours with the default genesis configuration.
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let worker = workspaces::sandbox();
let worker = workspaces::sandbox().await?;
let contract = worker
.dev_deploy(&std::fs::read(SIMPLE_WASM_FILEPATH)?)
.await?;
Expand Down
2 changes: 1 addition & 1 deletion examples/src/nft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const NFT_WASM_FILEPATH: &str = "./examples/res/non_fungible_token.wasm";

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let worker = workspaces::sandbox();
let worker = workspaces::sandbox().await?;
let wasm = std::fs::read(NFT_WASM_FILEPATH)?;
let contract = worker.dev_deploy(&wasm).await?;

Expand Down
6 changes: 3 additions & 3 deletions examples/src/ref_finance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const BLOCK_HEIGHT: BlockHeight = 50_000_000;
/// Pull down the ref-finance contract and deploy it to the sandbox network,
/// initializing it with all data required to run the tests.
async fn create_ref(owner: &Account, worker: &Worker<Sandbox>) -> anyhow::Result<Contract> {
let mainnet = workspaces::mainnet_archival();
let mainnet = workspaces::mainnet_archival().await?;
let ref_finance_id: AccountId = REF_FINANCE_ACCOUNT_ID.parse()?;

// This will pull down the relevant ref-finance contract from mainnet. We're going
Expand Down Expand Up @@ -56,7 +56,7 @@ async fn create_ref(owner: &Account, worker: &Worker<Sandbox>) -> anyhow::Result

/// Pull down the WNear contract from mainnet and initilize it with our own metadata.
async fn create_wnear(owner: &Account, worker: &Worker<Sandbox>) -> anyhow::Result<Contract> {
let mainnet = workspaces::mainnet_archival();
let mainnet = workspaces::mainnet_archival().await?;
let wnear_id: AccountId = "wrap.near".to_string().try_into()?;
let wnear = worker
.import_contract(&wnear_id, &mainnet)
Expand Down Expand Up @@ -202,7 +202,7 @@ async fn create_custom_ft(

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let worker = workspaces::sandbox();
let worker = workspaces::sandbox().await?;
let owner = worker.root_account();

///////////////////////////////////////////////////////////////////////////
Expand Down
6 changes: 3 additions & 3 deletions examples/src/spooning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const STATUS_MSG_WASM_FILEPATH: &str = "./examples/res/status_message.wasm";
/// If you'd like a different account to deploy it to, run the following:
/// ```norun
/// async fn deploy_testnet() -> anyhow::Result<()> {
/// let worker = worspaces::testnet();
/// let worker = worspaces::testnet().await?;
///
/// let contract = deploy_status_contract(worker, "hello from testnet").await?;
/// println!("{}", contract.id());
Expand Down Expand Up @@ -74,7 +74,7 @@ async fn main() -> anyhow::Result<()> {
// Grab STATE from the testnet status_message contract. This contract contains the following data:
// get_status(dev-20211013002148-59466083160385) => "hello from testnet"
let (testnet_contract_id, status_msg) = {
let worker = workspaces::testnet();
let worker = workspaces::testnet().await?;
let contract_id: AccountId = TESTNET_PREDEPLOYED_CONTRACT_ID
.parse()
.map_err(anyhow::Error::msg)?;
Expand All @@ -90,7 +90,7 @@ async fn main() -> anyhow::Result<()> {
info!(target: "spooning", "Testnet: {:?}", status_msg);

// Create our sandboxed environment and grab a worker to do stuff in it:
let worker = workspaces::sandbox();
let worker = workspaces::sandbox().await?;

// Deploy with the following status_message state: sandbox_contract_id => "hello from sandbox"
let sandbox_contract = deploy_status_contract(&worker, "hello from sandbox").await?;
Expand Down
2 changes: 1 addition & 1 deletion examples/src/status_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const STATUS_MSG_WASM_FILEPATH: &str = "./examples/res/status_message.wasm";

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let worker = workspaces::sandbox();
let worker = workspaces::sandbox().await?;
let wasm = std::fs::read(STATUS_MSG_WASM_FILEPATH)?;
let contract = worker.dev_deploy(&wasm).await?;

Expand Down
22 changes: 14 additions & 8 deletions workspaces/src/network/mainnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,34 @@ pub struct Mainnet {
}

impl Mainnet {
pub(crate) fn new() -> Self {
Self {
client: Client::new(RPC_URL.into()),
pub(crate) async fn new() -> anyhow::Result<Self> {
let client = Client::new(RPC_URL.into());
client.wait_for_rpc().await?;

Ok(Self {
client,
info: Info {
name: "mainnet".into(),
root_id: "near".parse().unwrap(),
keystore_path: PathBuf::from(".near-credentials/mainnet/"),
rpc_url: RPC_URL.into(),
},
}
})
}

pub(crate) fn archival() -> Self {
Self {
client: Client::new(ARCHIVAL_URL.into()),
pub(crate) async fn archival() -> anyhow::Result<Self> {
let client = Client::new(ARCHIVAL_URL.into());
client.wait_for_rpc().await?;

Ok(Self {
client,
info: Info {
name: "mainnet-archival".into(),
root_id: "near".parse().unwrap(),
keystore_path: PathBuf::from(".near-credentials/mainnet/"),
rpc_url: ARCHIVAL_URL.into(),
},
}
})
}
}

Expand Down
11 changes: 6 additions & 5 deletions workspaces/src/network/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,24 @@ impl Sandbox {
InMemorySigner::from_file(&path)
}

pub(crate) fn new() -> Self {
pub(crate) async fn new() -> anyhow::Result<Self> {
let mut server = SandboxServer::default();
server.start().unwrap();

server.start()?;
let client = Client::new(server.rpc_addr());
client.wait_for_rpc().await?;

let info = Info {
name: "sandbox".to_string(),
root_id: AccountId::from_str("test.near").unwrap(),
keystore_path: PathBuf::from(".near-credentials/sandbox/"),
rpc_url: server.rpc_addr(),
};

Self {
Ok(Self {
server,
client,
info,
}
})
}
}

Expand Down
4 changes: 3 additions & 1 deletion workspaces/src/network/server.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::process::Child;

use crate::network::Sandbox;

use portpicker::pick_unused_port;
use std::process::Child;
use tracing::info;

pub struct SandboxServer {
Expand Down
22 changes: 14 additions & 8 deletions workspaces/src/network/testnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,34 @@ pub struct Testnet {
}

impl Testnet {
pub(crate) fn new() -> Self {
Self {
client: Client::new(RPC_URL.into()),
pub(crate) async fn new() -> anyhow::Result<Self> {
let client = Client::new(RPC_URL.into());
client.wait_for_rpc().await?;

Ok(Self {
client,
info: Info {
name: "testnet".into(),
root_id: AccountId::from_str("testnet").unwrap(),
keystore_path: PathBuf::from(".near-credentials/testnet/"),
rpc_url: RPC_URL.into(),
},
}
})
}

pub(crate) fn archival() -> Self {
Self {
client: Client::new(ARCHIVAL_URL.into()),
pub(crate) async fn archival() -> anyhow::Result<Self> {
let client = Client::new(ARCHIVAL_URL.into());
client.wait_for_rpc().await?;

Ok(Self {
client,
info: Info {
name: "testnet-archival".into(),
root_id: AccountId::from_str("testnet").unwrap(),
keystore_path: PathBuf::from(".near-credentials/testnet/"),
rpc_url: ARCHIVAL_URL.into(),
},
}
})
}
}

Expand Down
32 changes: 31 additions & 1 deletion workspaces/src/rpc/client.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::collections::HashMap;
use std::fmt::Debug;
use std::time::Duration;

use tokio_retry::strategy::{jitter, ExponentialBackoff};
use tokio_retry::Retry;

use near_jsonrpc_client::errors::JsonRpcError;
use near_jsonrpc_client::methods::health::RpcStatusError;
use near_jsonrpc_client::methods::query::RpcQueryRequest;
use near_jsonrpc_client::{methods, JsonRpcClient, MethodCallResult};
use near_jsonrpc_primitives::types::query::QueryResponseKind;
Expand All @@ -16,7 +19,7 @@ use near_primitives::transaction::{
use near_primitives::types::{Balance, BlockId, Finality, Gas, StoreKey};
use near_primitives::views::{
AccessKeyView, AccountView, BlockView, ContractCodeView, FinalExecutionOutcomeView,
QueryRequest,
QueryRequest, StatusResponse,
};

use crate::result::ViewResultDetails;
Expand Down Expand Up @@ -361,6 +364,33 @@ impl Client {
)
.await
}

pub(crate) async fn status(&self) -> Result<StatusResponse, JsonRpcError<RpcStatusError>> {
let result = JsonRpcClient::connect(&self.rpc_addr)
.call(methods::status::RpcStatusRequest)
.await;

tracing::debug!(
target: "workspaces",
"Querying RPC with RpcStatusRequest resulted in {:?}",
result,
);
result
}

pub(crate) async fn wait_for_rpc(&self) -> anyhow::Result<()> {
let retry_six_times = std::iter::repeat_with(|| Duration::from_millis(500)).take(6);
Retry::spawn(retry_six_times, || async { self.status().await })
.await
.map_err(|e| {
anyhow::anyhow!(
"Failed to connect to RPC service {} within three seconds: {:?}",
self.rpc_addr,
e
)
})?;
Ok(())
}
}

pub(crate) async fn access_key(
Expand Down
40 changes: 20 additions & 20 deletions workspaces/src/worker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,75 +21,75 @@ where
}

/// Spin up a new sandbox instance, and grab a [`Worker`] that interacts with it.
pub fn sandbox() -> Worker<Sandbox> {
Worker::new(Sandbox::new())
pub async fn sandbox() -> anyhow::Result<Worker<Sandbox>> {
Ok(Worker::new(Sandbox::new().await?))
}

/// Connect to the [testnet](https://explorer.testnet.near.org/) network, and grab
/// a [`Worker`] that can interact with it.
pub fn testnet() -> Worker<Testnet> {
Worker::new(Testnet::new())
pub async fn testnet() -> anyhow::Result<Worker<Testnet>> {
Ok(Worker::new(Testnet::new().await?))
}

/// Connect to the [testnet archival](https://near-nodes.io/intro/node-types#archival-node)
/// network, and grab a [`Worker`] that can interact with it.
pub fn testnet_archival() -> Worker<Testnet> {
Worker::new(Testnet::archival())
pub async fn testnet_archival() -> anyhow::Result<Worker<Testnet>> {
Ok(Worker::new(Testnet::archival().await?))
}

/// Connect to the [mainnet](https://explorer.near.org/) network, and grab
/// a [`Worker`] that can interact with it.
pub fn mainnet() -> Worker<Mainnet> {
Worker::new(Mainnet::new())
pub async fn mainnet() -> anyhow::Result<Worker<Mainnet>> {
Ok(Worker::new(Mainnet::new().await?))
}

/// Connect to the [mainnet archival](https://near-nodes.io/intro/node-types#archival-node)
/// network, and grab a [`Worker`] that can interact with it.
pub fn mainnet_archival() -> Worker<Mainnet> {
Worker::new(Mainnet::archival())
pub async fn mainnet_archival() -> anyhow::Result<Worker<Mainnet>> {
Ok(Worker::new(Mainnet::archival().await?))
}

/// Run a locally scoped task with a [`sandbox`] instanced [`Worker`] is supplied.
pub async fn with_sandbox<F, T>(task: F) -> T::Output
pub async fn with_sandbox<F, T>(task: F) -> anyhow::Result<T::Output>
where
F: Fn(Worker<Sandbox>) -> T,
T: core::future::Future,
{
task(sandbox()).await
Ok(task(sandbox().await?).await)
}

/// Run a locally scoped task with a [`testnet`] instanced [`Worker`] is supplied.
pub async fn with_testnet<F, T>(task: F) -> T::Output
pub async fn with_testnet<F, T>(task: F) -> anyhow::Result<T::Output>
where
F: Fn(Worker<Testnet>) -> T,
T: core::future::Future,
{
task(testnet()).await
Ok(task(testnet().await?).await)
}

/// Run a locally scoped task with a [`testnet_archival`] instanced [`Worker`] is supplied.
pub async fn with_testnet_archival<F, T>(task: F) -> T::Output
pub async fn with_testnet_archival<F, T>(task: F) -> anyhow::Result<T::Output>
where
F: Fn(Worker<Testnet>) -> T,
T: core::future::Future,
{
task(testnet_archival()).await
Ok(task(testnet_archival().await?).await)
}

/// Run a locally scoped task with a [`mainnet`] instanced [`Worker`] is supplied.
pub async fn with_mainnet<F, T>(task: F) -> T::Output
pub async fn with_mainnet<F, T>(task: F) -> anyhow::Result<T::Output>
where
F: Fn(Worker<Mainnet>) -> T,
T: core::future::Future,
{
task(mainnet()).await
Ok(task(mainnet().await?).await)
}

/// Run a locally scoped task with a [`mainnet_archival`] instanced [`Worker`] is supplied.
pub async fn with_mainnet_archival<F, T>(task: F) -> T::Output
pub async fn with_mainnet_archival<F, T>(task: F) -> anyhow::Result<T::Output>
where
F: Fn(Worker<Mainnet>) -> T,
T: core::future::Future,
{
task(mainnet_archival()).await
Ok(task(mainnet_archival().await?).await)
}
2 changes: 1 addition & 1 deletion workspaces/tests/batch_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use workspaces::prelude::*;

#[test(tokio::test)]
async fn test_batch_tx() -> anyhow::Result<()> {
let worker = workspaces::sandbox();
let worker = workspaces::sandbox().await?;
let contract = worker
.dev_deploy(include_bytes!("../../examples/res/status_message.wasm"))
.await?;
Expand Down
Loading

0 comments on commit 8f12f3d

Please sign in to comment.