From 94d66ac0c30020fa5197f37db3be2a07a5bf1959 Mon Sep 17 00:00:00 2001 From: adsick Date: Tue, 19 Apr 2022 13:19:49 +0300 Subject: [PATCH 01/16] patch state builder init --- examples/src/spooning.rs | 4 +- workspaces/src/network/sandbox.rs | 67 +++++++++++++++++++++++++++++-- workspaces/src/worker/impls.rs | 4 +- workspaces/tests/patch_state.rs | 12 +++--- 4 files changed, 73 insertions(+), 14 deletions(-) diff --git a/examples/src/spooning.rs b/examples/src/spooning.rs index 5caf7938..6debbc49 100644 --- a/examples/src/spooning.rs +++ b/examples/src/spooning.rs @@ -99,8 +99,8 @@ async fn main() -> anyhow::Result<()> { worker .patch_state( sandbox_contract.id(), - "STATE".as_bytes(), - &status_msg.try_to_vec()?, + "STATE", + status_msg.try_to_vec()?, ) .await?; diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index 9af15fd2..693a2339 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -1,3 +1,4 @@ +use std::borrow::Borrow; use std::path::PathBuf; use std::str::FromStr; @@ -5,6 +6,7 @@ use async_trait::async_trait; use near_jsonrpc_client::methods::sandbox_fast_forward::RpcSandboxFastForwardRequest; use near_jsonrpc_client::methods::sandbox_patch_state::RpcSandboxPatchStateRequest; use near_primitives::state_record::StateRecord; +use std::iter::IntoIterator; use super::{AllowDevAccountCreation, NetworkClient, NetworkInfo, TopLevelAccountCreator}; use crate::network::server::SandboxServer; @@ -138,13 +140,13 @@ impl Sandbox { pub(crate) async fn patch_state( &self, contract_id: &AccountId, - key: &[u8], - value: &[u8], + key: impl Into>, + value: impl Into>, ) -> anyhow::Result<()> { let state = StateRecord::Data { account_id: contract_id.to_owned(), - data_key: key.to_vec(), - value: value.to_vec(), + data_key: key.into(), + value: value.into(), }; let records = vec![state]; @@ -169,3 +171,60 @@ impl Sandbox { Ok(()) } } + +#[must_use = "don't forget to .send() this `PatchStateBuilder`"] +struct PatchStateBuilder<'s> { + sandbox: &'s mut Sandbox, + records: Vec, +} + +impl<'s> PatchStateBuilder<'s> { + pub fn new(sandbox: &'s mut Sandbox) -> Self { + PatchStateBuilder { + sandbox, + records: Vec::with_capacity(4), + } + } + + pub fn data( + mut self, + contract_id: &AccountId, //todo: borrowed or owned? (or Into<> or smth) + key: impl Into>, + value: impl Into>, + ) -> Self { + let state = StateRecord::Data { + account_id: contract_id.to_owned(), + data_key: key.into(), + value: value.into(), + }; + self.records.push(state); + self + } + + pub fn data_many( + mut self, + contract_id: &AccountId, //todo: borrowed or owned? (or Into<> or smth) + kvs: impl IntoIterator, Vec)>, + key: impl Into>, + value: impl Into>, + ) -> Self { + self.records.extend(kvs.into_iter().map(|(key, value)|StateRecord::Data { + account_id: contract_id.to_owned(), + data_key: key.into(), + value: value.into(), + })); + self + } + + pub async fn send(self)->anyhow::Result<()>{ + let records = self.records; + // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: + let _patch_resp = self.sandbox + .client() + .query(&RpcSandboxPatchStateRequest { records }) + .await + .map_err(|err| anyhow::anyhow!("Failed to patch state: {:?}", err))?; + + Ok(()) + } +} diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index 62478f2b..8c3b4baa 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -180,8 +180,8 @@ impl Worker { pub async fn patch_state( &self, contract_id: &AccountId, - key: &[u8], - value: &[u8], + key: impl Into>, + value: impl Into>, ) -> anyhow::Result<()> { self.workspace.patch_state(contract_id, key, value).await } diff --git a/workspaces/tests/patch_state.rs b/workspaces/tests/patch_state.rs index 1c46c745..15423f30 100644 --- a/workspaces/tests/patch_state.rs +++ b/workspaces/tests/patch_state.rs @@ -21,20 +21,20 @@ struct StatusMessage { } async fn view_status_state( - worker: Worker, + worker: &Worker, ) -> anyhow::Result<(AccountId, StatusMessage)> { let wasm = std::fs::read(STATUS_MSG_WASM_FILEPATH)?; let contract = worker.dev_deploy(&wasm).await.unwrap(); contract - .call(&worker, "set_status") + .call(worker, "set_status") .args_json(json!({ "message": "hello", }))? .transact() .await?; - let mut state_items = contract.view_state(&worker, None).await?; + let mut state_items = contract.view_state(worker, None).await?; let state = state_items .remove(b"STATE".as_slice()) .ok_or_else(|| anyhow::anyhow!("Could not retrieve STATE"))?; @@ -46,7 +46,7 @@ async fn view_status_state( #[test(tokio::test)] async fn test_view_state() -> anyhow::Result<()> { let worker = workspaces::sandbox().await?; - let (contract_id, status_msg) = view_status_state(worker).await?; + let (contract_id, status_msg) = view_status_state(&worker).await?; assert_eq!( status_msg, @@ -64,14 +64,14 @@ async fn test_view_state() -> anyhow::Result<()> { #[test(tokio::test)] async fn test_patch_state() -> anyhow::Result<()> { let worker = workspaces::sandbox().await?; - let (contract_id, mut status_msg) = view_status_state(worker.clone()).await?; + let (contract_id, mut status_msg) = view_status_state(&worker).await?; status_msg.records.push(Record { k: "alice.near".to_string(), v: "hello world".to_string(), }); worker - .patch_state(&contract_id, "STATE".as_bytes(), &status_msg.try_to_vec()?) + .patch_state(&contract_id, "STATE", status_msg.try_to_vec()?) .await?; let status: String = worker From bda570d6402b6e0a8389a12113c7ea1cc15efda6 Mon Sep 17 00:00:00 2001 From: adsick Date: Tue, 19 Apr 2022 16:55:50 +0300 Subject: [PATCH 02/16] fix build.rs now using ensure_sandbox_bin() instead of installing it every time --- workspaces/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/workspaces/build.rs b/workspaces/build.rs index 82017194..d2ace692 100644 --- a/workspaces/build.rs +++ b/workspaces/build.rs @@ -1,6 +1,9 @@ fn main() { let doc_build = cfg!(doc) || std::env::var("DOCS_RS").is_ok(); if !doc_build && cfg!(feature = "install") { - near_sandbox_utils::install().expect("Could not install sandbox"); + // using unwrap because all the useful error messages are hidden inside + near_sandbox_utils::ensure_sandbox_bin().unwrap(); + // previously the next line was causing near sandbox to be installed every time cargo build/check was called + // near_sandbox_utils::install().expect("Could not install sandbox"); } } From 74c4f4ff1ac07565f5fb22a74d277db5f4410a2f Mon Sep 17 00:00:00 2001 From: adsick Date: Tue, 19 Apr 2022 18:28:47 +0300 Subject: [PATCH 03/16] builder pattern progress1 --- examples/src/spooning.rs | 9 ++++ workspaces/src/network/mod.rs | 13 +++--- workspaces/src/network/sandbox.rs | 71 ++++++++++++------------------- workspaces/src/worker/impls.rs | 34 ++++++++++++++- 4 files changed, 75 insertions(+), 52 deletions(-) diff --git a/examples/src/spooning.rs b/examples/src/spooning.rs index 6debbc49..d0d726c4 100644 --- a/examples/src/spooning.rs +++ b/examples/src/spooning.rs @@ -104,6 +104,15 @@ async fn main() -> anyhow::Result<()> { ) .await?; + // build pattern equivalent + + // worker + // .patch_state_builder() + // .data(sandbox_contract.id(), "STATE", status_msg.try_to_vec()?) + // // .data_many(sandbox_contract.id(), [("hello", "world"), ("goodbye", "putin")]) + // .send() + // .await?; + // Now grab the state to see that it has indeed been patched: let status: String = sandbox_contract .view( diff --git a/workspaces/src/network/mod.rs b/workspaces/src/network/mod.rs index e2367907..99c33d84 100644 --- a/workspaces/src/network/mod.rs +++ b/workspaces/src/network/mod.rs @@ -11,12 +11,13 @@ mod testnet; pub(crate) mod variants; pub(crate) use variants::DEV_ACCOUNT_SEED; +pub(crate) use sandbox::SandboxPatchStateBuilder; //not needed directly outside of the crate -pub use self::betanet::Betanet; -pub use self::info::Info; -pub use self::mainnet::Mainnet; -pub use self::sandbox::Sandbox; -pub use self::testnet::Testnet; -pub use self::variants::{ +pub use betanet::Betanet; +pub use info::Info; +pub use mainnet::Mainnet; +pub use sandbox::Sandbox; +pub use testnet::Testnet; +pub use variants::{ AllowDevAccountCreation, DevAccountDeployer, NetworkClient, NetworkInfo, TopLevelAccountCreator, }; diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index 693a2339..6b4154b1 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -1,4 +1,3 @@ -use std::borrow::Borrow; use std::path::PathBuf; use std::str::FromStr; @@ -137,27 +136,8 @@ impl Sandbox { ImportContractTransaction::new(id.to_owned(), worker.client(), self.client()) } - pub(crate) async fn patch_state( - &self, - contract_id: &AccountId, - key: impl Into>, - value: impl Into>, - ) -> anyhow::Result<()> { - let state = StateRecord::Data { - account_id: contract_id.to_owned(), - data_key: key.into(), - value: value.into(), - }; - let records = vec![state]; - - // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: - let _patch_resp = self - .client() - .query(&RpcSandboxPatchStateRequest { records }) - .await - .map_err(|err| anyhow::anyhow!("Failed to patch state: {:?}", err))?; - - Ok(()) + pub(crate) fn patch_state(&self) -> SandboxPatchStateBuilder { + SandboxPatchStateBuilder::new(self) } pub(crate) async fn fast_forward(&self, delta_height: u64) -> anyhow::Result<()> { @@ -172,15 +152,17 @@ impl Sandbox { } } +//todo: review naming #[must_use = "don't forget to .send() this `PatchStateBuilder`"] -struct PatchStateBuilder<'s> { - sandbox: &'s mut Sandbox, +pub struct SandboxPatchStateBuilder<'s> { + sandbox: &'s Sandbox, records: Vec, } -impl<'s> PatchStateBuilder<'s> { - pub fn new(sandbox: &'s mut Sandbox) -> Self { - PatchStateBuilder { +//todo: add more methods +impl<'s> SandboxPatchStateBuilder<'s> { + pub fn new(sandbox: &'s Sandbox) -> Self { + SandboxPatchStateBuilder { sandbox, records: Vec::with_capacity(4), } @@ -197,6 +179,7 @@ impl<'s> PatchStateBuilder<'s> { data_key: key.into(), value: value.into(), }; + self.records.push(state); self } @@ -204,27 +187,27 @@ impl<'s> PatchStateBuilder<'s> { pub fn data_many( mut self, contract_id: &AccountId, //todo: borrowed or owned? (or Into<> or smth) - kvs: impl IntoIterator, Vec)>, - key: impl Into>, - value: impl Into>, + kvs: impl IntoIterator>, impl Into>)>, ) -> Self { - self.records.extend(kvs.into_iter().map(|(key, value)|StateRecord::Data { - account_id: contract_id.to_owned(), - data_key: key.into(), - value: value.into(), - })); + self.records + .extend(kvs.into_iter().map(|(key, value)| StateRecord::Data { + account_id: contract_id.to_owned(), + data_key: key.into(), + value: value.into(), + })); self } - pub async fn send(self)->anyhow::Result<()>{ + pub async fn send(self) -> anyhow::Result<()> { let records = self.records; - // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: - let _patch_resp = self.sandbox - .client() - .query(&RpcSandboxPatchStateRequest { records }) - .await - .map_err(|err| anyhow::anyhow!("Failed to patch state: {:?}", err))?; - - Ok(()) + // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: + let _patch_resp = self + .sandbox + .client() + .query(&RpcSandboxPatchStateRequest { records }) + .await + .map_err(|err| anyhow::anyhow!("Failed to patch state: {:?}", err))?; + + Ok(()) } } diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index 8c3b4baa..cc368ddc 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -1,5 +1,5 @@ use crate::network::{AllowDevAccountCreation, NetworkClient, NetworkInfo, TopLevelAccountCreator}; -use crate::network::{Info, Sandbox}; +use crate::network::{Info, Sandbox, SandboxPatchStateBuilder}; use crate::result::{CallExecution, CallExecutionDetails, ViewResultDetails}; use crate::rpc::client::{Client, DEFAULT_CALL_DEPOSIT, DEFAULT_CALL_FN_GAS}; use crate::rpc::patch::ImportContractTransaction; @@ -174,6 +174,13 @@ impl Worker { self.workspace.import_contract(id, worker) } + /// Patch state into the sandbox network, using builder pattern. This will allow us to set + /// state that we have acquired in some manner. This allows us to test random cases that + /// are hard to come up naturally as state evolves. + pub fn patch_state_builder(&self) -> SandboxPatchStateBuilder { + self.workspace.patch_state() + } + /// Patch state into the sandbox network, given a key and value. This will allow us to set /// state that we have acquired in some manner. This allows us to test random cases that /// are hard to come up naturally as state evolves. @@ -183,7 +190,30 @@ impl Worker { key: impl Into>, value: impl Into>, ) -> anyhow::Result<()> { - self.workspace.patch_state(contract_id, key, value).await + self.workspace + .patch_state() + .data(contract_id, key, value) + .send() + .await?; + Ok(()) + } + + //todo: add more patch state methods like the previous one + + /// Patch state into the sandbox network, given a key and value. This will allow us to set + /// state that we have acquired in some manner. This allows us to test random cases that + /// are hard to come up naturally as state evolves. + pub async fn patch_state_many( + &self, + contract_id: &AccountId, + kvs: impl IntoIterator>, impl Into>)>, + ) -> anyhow::Result<()> { + self.workspace + .patch_state() + .data_many(contract_id, kvs) + .send() + .await?; + Ok(()) } /// Fast forward to a point in the future. The delta block height is supplied to tell the From f351e76bf9fceece2c6ea054eaa21c76f5429f18 Mon Sep 17 00:00:00 2001 From: adsick Date: Tue, 19 Apr 2022 18:41:43 +0300 Subject: [PATCH 04/16] docfix patch_state_many --- workspaces/src/worker/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index cc368ddc..8a7af5ed 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -200,7 +200,7 @@ impl Worker { //todo: add more patch state methods like the previous one - /// Patch state into the sandbox network, given a key and value. This will allow us to set + /// Patch state into the sandbox network, given a sequence of key value pairs. This will allow us to set /// state that we have acquired in some manner. This allows us to test random cases that /// are hard to come up naturally as state evolves. pub async fn patch_state_many( From 0d2167d4175756b14dae5237893f8b84831370ac Mon Sep 17 00:00:00 2001 From: adsick Date: Wed, 20 Apr 2022 13:57:23 +0300 Subject: [PATCH 05/16] renamed .send() to .apply() --- examples/src/spooning.rs | 2 +- workspaces/src/network/sandbox.rs | 4 ++-- workspaces/src/worker/impls.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/src/spooning.rs b/examples/src/spooning.rs index d0d726c4..d3ecdc8c 100644 --- a/examples/src/spooning.rs +++ b/examples/src/spooning.rs @@ -110,7 +110,7 @@ async fn main() -> anyhow::Result<()> { // .patch_state_builder() // .data(sandbox_contract.id(), "STATE", status_msg.try_to_vec()?) // // .data_many(sandbox_contract.id(), [("hello", "world"), ("goodbye", "putin")]) - // .send() + // .apply() // .await?; // Now grab the state to see that it has indeed been patched: diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index 6b4154b1..db4ff5fa 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -153,7 +153,7 @@ impl Sandbox { } //todo: review naming -#[must_use = "don't forget to .send() this `PatchStateBuilder`"] +#[must_use = "don't forget to .apply() this `PatchStateBuilder`"] pub struct SandboxPatchStateBuilder<'s> { sandbox: &'s Sandbox, records: Vec, @@ -198,7 +198,7 @@ impl<'s> SandboxPatchStateBuilder<'s> { self } - pub async fn send(self) -> anyhow::Result<()> { + pub async fn apply(self) -> anyhow::Result<()> { let records = self.records; // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: let _patch_resp = self diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index 8a7af5ed..8a5b83f7 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -193,7 +193,7 @@ impl Worker { self.workspace .patch_state() .data(contract_id, key, value) - .send() + .apply() .await?; Ok(()) } @@ -211,7 +211,7 @@ impl Worker { self.workspace .patch_state() .data_many(contract_id, kvs) - .send() + .apply() .await?; Ok(()) } From 58fa329c0144a0a1161488d07d644ba78b313fce Mon Sep 17 00:00:00 2001 From: adsick Date: Wed, 20 Apr 2022 20:29:58 +0300 Subject: [PATCH 06/16] refactor to pass AccountId once + access_key patch --- workspaces/src/network/sandbox.rs | 41 ++++++++++++++++++++++--------- workspaces/src/worker/impls.rs | 18 ++++++-------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index db4ff5fa..5283a73a 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use async_trait::async_trait; use near_jsonrpc_client::methods::sandbox_fast_forward::RpcSandboxFastForwardRequest; use near_jsonrpc_client::methods::sandbox_patch_state::RpcSandboxPatchStateRequest; +use near_primitives::account::AccessKey; use near_primitives::state_record::StateRecord; use std::iter::IntoIterator; @@ -13,7 +14,7 @@ use crate::network::Info; use crate::result::CallExecution; use crate::rpc::client::Client; use crate::rpc::patch::ImportContractTransaction; -use crate::types::{AccountId, Balance, InMemorySigner, SecretKey}; +use crate::types::{AccountId, Balance, InMemorySigner, SecretKey, PublicKey}; use crate::{Account, Contract, Network, Worker}; // Constant taken from nearcore crate to avoid dependency @@ -136,8 +137,8 @@ impl Sandbox { ImportContractTransaction::new(id.to_owned(), worker.client(), self.client()) } - pub(crate) fn patch_state(&self) -> SandboxPatchStateBuilder { - SandboxPatchStateBuilder::new(self) + pub(crate) fn patch_state(&self, account_id: AccountId) -> SandboxPatchStateBuilder { + SandboxPatchStateBuilder::new(self, account_id) } pub(crate) async fn fast_forward(&self, delta_height: u64) -> anyhow::Result<()> { @@ -153,51 +154,67 @@ impl Sandbox { } //todo: review naming -#[must_use = "don't forget to .apply() this `PatchStateBuilder`"] +#[must_use = "don't forget to .apply() this `SandboxPatchStateBuilder`"] pub struct SandboxPatchStateBuilder<'s> { sandbox: &'s Sandbox, + account_id: AccountId, records: Vec, } //todo: add more methods impl<'s> SandboxPatchStateBuilder<'s> { - pub fn new(sandbox: &'s Sandbox) -> Self { + //AsRef allows for both &AccountId and AccountId + pub fn new(sandbox: &'s Sandbox, account_id: AccountId) -> Self { SandboxPatchStateBuilder { sandbox, + account_id: account_id, records: Vec::with_capacity(4), } } pub fn data( mut self, - contract_id: &AccountId, //todo: borrowed or owned? (or Into<> or smth) key: impl Into>, value: impl Into>, ) -> Self { - let state = StateRecord::Data { - account_id: contract_id.to_owned(), + let data = StateRecord::Data { + account_id: self.account_id.clone(), data_key: key.into(), value: value.into(), }; - self.records.push(state); + self.records.push(data); self } pub fn data_many( mut self, - contract_id: &AccountId, //todo: borrowed or owned? (or Into<> or smth) kvs: impl IntoIterator>, impl Into>)>, ) -> Self { - self.records + let Self{ref mut records, ref account_id, ..} = self; + records .extend(kvs.into_iter().map(|(key, value)| StateRecord::Data { - account_id: contract_id.to_owned(), + account_id: account_id.clone(), data_key: key.into(), value: value.into(), })); self } + pub fn access_key( + mut self, + public_key: &PublicKey, + access_key: &AccessKey, + ) -> Self { + let access_key = StateRecord::AccessKey { + account_id: self.account_id.clone(), + public_key: public_key.0.clone(), + access_key: access_key.clone(), + }; + self.records.push(access_key); + self + } + pub async fn apply(self) -> anyhow::Result<()> { let records = self.records; // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index 8a5b83f7..69a2779a 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -177,8 +177,8 @@ impl Worker { /// Patch state into the sandbox network, using builder pattern. This will allow us to set /// state that we have acquired in some manner. This allows us to test random cases that /// are hard to come up naturally as state evolves. - pub fn patch_state_builder(&self) -> SandboxPatchStateBuilder { - self.workspace.patch_state() + pub fn patch_state_builder(&self, account_id: &AccountId) -> SandboxPatchStateBuilder { + self.workspace.patch_state(account_id.clone()) } /// Patch state into the sandbox network, given a key and value. This will allow us to set @@ -191,8 +191,8 @@ impl Worker { value: impl Into>, ) -> anyhow::Result<()> { self.workspace - .patch_state() - .data(contract_id, key, value) + .patch_state(contract_id.clone()) + .data(key, value) .apply() .await?; Ok(()) @@ -200,17 +200,15 @@ impl Worker { //todo: add more patch state methods like the previous one - /// Patch state into the sandbox network, given a sequence of key value pairs. This will allow us to set - /// state that we have acquired in some manner. This allows us to test random cases that - /// are hard to come up naturally as state evolves. - pub async fn patch_state_many( + /// Patch state into the sandbox network. Same as `patch_state` but accepts a sequence of key value pairs + pub async fn patch_state_multiple( &self, contract_id: &AccountId, kvs: impl IntoIterator>, impl Into>)>, ) -> anyhow::Result<()> { self.workspace - .patch_state() - .data_many(contract_id, kvs) + .patch_state(contract_id.clone()) + .data_many(kvs) .apply() .await?; Ok(()) From 6a99349a5ea073e88b5bc324395cafb6571328e4 Mon Sep 17 00:00:00 2001 From: adsick Date: Thu, 21 Apr 2022 01:21:32 +0300 Subject: [PATCH 07/16] patch_account with builder pattern --- examples/src/spooning.rs | 12 +-- workspaces/src/network/mod.rs | 3 +- workspaces/src/network/sandbox.rs | 134 +++++++++++++++++++++++++----- workspaces/src/worker/impls.rs | 30 +++++-- workspaces/tests/patch_state.rs | 15 ++++ 5 files changed, 160 insertions(+), 34 deletions(-) diff --git a/examples/src/spooning.rs b/examples/src/spooning.rs index d3ecdc8c..fd912688 100644 --- a/examples/src/spooning.rs +++ b/examples/src/spooning.rs @@ -97,19 +97,15 @@ async fn main() -> anyhow::Result<()> { // Patch our testnet STATE into our local sandbox: worker - .patch_state( - sandbox_contract.id(), - "STATE", - status_msg.try_to_vec()?, - ) + .patch_state(sandbox_contract.id(), "STATE", status_msg.try_to_vec()?) .await?; // build pattern equivalent // worker - // .patch_state_builder() - // .data(sandbox_contract.id(), "STATE", status_msg.try_to_vec()?) - // // .data_many(sandbox_contract.id(), [("hello", "world"), ("goodbye", "putin")]) + // .patch_state_builder(sandbox_contract.id()) + // .data( "STATE", status_msg.try_to_vec()?) + // // .data_multiple([("hello", "world"), ("goodbye", "putin")]) // .apply() // .await?; diff --git a/workspaces/src/network/mod.rs b/workspaces/src/network/mod.rs index 99c33d84..6aef987f 100644 --- a/workspaces/src/network/mod.rs +++ b/workspaces/src/network/mod.rs @@ -10,8 +10,9 @@ mod server; mod testnet; pub(crate) mod variants; +pub(crate) use sandbox::SandboxPatchStateAccountBuilder; //not needed directly outside of the crate +pub(crate) use sandbox::SandboxPatchStateBuilder; //not needed directly outside of the crate pub(crate) use variants::DEV_ACCOUNT_SEED; -pub(crate) use sandbox::SandboxPatchStateBuilder; //not needed directly outside of the crate pub use betanet::Betanet; pub use info::Info; diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index 5283a73a..250d10fd 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -5,7 +5,10 @@ use async_trait::async_trait; use near_jsonrpc_client::methods::sandbox_fast_forward::RpcSandboxFastForwardRequest; use near_jsonrpc_client::methods::sandbox_patch_state::RpcSandboxPatchStateRequest; use near_primitives::account::AccessKey; +use near_primitives::hash::CryptoHash; use near_primitives::state_record::StateRecord; +use near_primitives::types::StorageUsage; +use near_primitives::views::AccountView; use std::iter::IntoIterator; use super::{AllowDevAccountCreation, NetworkClient, NetworkInfo, TopLevelAccountCreator}; @@ -14,7 +17,7 @@ use crate::network::Info; use crate::result::CallExecution; use crate::rpc::client::Client; use crate::rpc::patch::ImportContractTransaction; -use crate::types::{AccountId, Balance, InMemorySigner, SecretKey, PublicKey}; +use crate::types::{AccountId, Balance, InMemorySigner, PublicKey, SecretKey}; use crate::{Account, Contract, Network, Worker}; // Constant taken from nearcore crate to avoid dependency @@ -141,6 +144,12 @@ impl Sandbox { SandboxPatchStateBuilder::new(self, account_id) } + pub(crate) fn patch_account(&self, account_id: AccountId) -> SandboxPatchStateAccountBuilder { + SandboxPatchStateAccountBuilder::new(self, account_id) + } + + // shall we expose convenience patch methods here for consistent API? + pub(crate) async fn fast_forward(&self, delta_height: u64) -> anyhow::Result<()> { // NOTE: RpcSandboxFastForwardResponse is an empty struct with no fields, so don't do anything with it: self.client() @@ -167,16 +176,12 @@ impl<'s> SandboxPatchStateBuilder<'s> { pub fn new(sandbox: &'s Sandbox, account_id: AccountId) -> Self { SandboxPatchStateBuilder { sandbox, - account_id: account_id, + account_id, records: Vec::with_capacity(4), } } - pub fn data( - mut self, - key: impl Into>, - value: impl Into>, - ) -> Self { + pub fn data(mut self, key: impl Into>, value: impl Into>) -> Self { let data = StateRecord::Data { account_id: self.account_id.clone(), data_key: key.into(), @@ -187,25 +192,24 @@ impl<'s> SandboxPatchStateBuilder<'s> { self } - pub fn data_many( + pub fn data_multiple( mut self, kvs: impl IntoIterator>, impl Into>)>, ) -> Self { - let Self{ref mut records, ref account_id, ..} = self; - records - .extend(kvs.into_iter().map(|(key, value)| StateRecord::Data { - account_id: account_id.clone(), - data_key: key.into(), - value: value.into(), - })); + let Self { + ref mut records, + ref account_id, + .. + } = self; + records.extend(kvs.into_iter().map(|(key, value)| StateRecord::Data { + account_id: account_id.clone(), + data_key: key.into(), + value: value.into(), + })); self } - pub fn access_key( - mut self, - public_key: &PublicKey, - access_key: &AccessKey, - ) -> Self { + pub fn access_key(mut self, public_key: &PublicKey, access_key: &AccessKey) -> Self { let access_key = StateRecord::AccessKey { account_id: self.account_id.clone(), public_key: public_key.0.clone(), @@ -215,6 +219,10 @@ impl<'s> SandboxPatchStateBuilder<'s> { self } + // pub fn account(self) -> SandboxPatchStateAccountBuilder<'s> { + // SandboxPatchStateAccountBuilder::new(self) + // } + pub async fn apply(self) -> anyhow::Result<()> { let records = self.records; // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: @@ -228,3 +236,89 @@ impl<'s> SandboxPatchStateBuilder<'s> { Ok(()) } } + +#[must_use = "don't forget to .apply() this `SandboxPatchStateAccountBuilder`"] +pub struct SandboxPatchStateAccountBuilder<'s> { + sandbox: &'s Sandbox, + account_id: AccountId, + amount: Option, + locked: Option, + code_hash: Option, + storage_usage: Option, +} + +impl<'s> SandboxPatchStateAccountBuilder<'s> { + pub const fn new(sandbox: &'s Sandbox, account_id: AccountId) -> Self { + Self { + sandbox, + account_id, + amount: None, + locked: None, + code_hash: None, + storage_usage: None, + } + } + + pub const fn amount(mut self, amount: Balance) -> Self { + // a little experiment, wonder if it can produce compile-time errors + if let Some(_amount) = self.amount { + panic!("'amount' field has already been set"); + } + self.amount = Some(amount); + self + } + + pub const fn locked(mut self, locked: Balance) -> Self { + self.locked = Some(locked); + self + } + + pub const fn code_hash(mut self, code_hash: CryptoHash) -> Self { + self.code_hash = Some(code_hash); + self + } + + pub const fn storage_usage(mut self, storage_usage: StorageUsage) -> Self { + self.storage_usage = Some(storage_usage); + self + } + + pub async fn apply(self) -> anyhow::Result<()> { + let account_view = self + .sandbox + .client() + .view_account(self.account_id.clone(), None); + + let AccountView { + amount: previous_amount, + locked: previous_locked, + code_hash: previous_code_hash, + storage_usage: previous_storage_usage, + .. + } = account_view + .await + .map_err(|err| anyhow::anyhow!("Failed to read account: {:?}", err))?; + + let account = StateRecord::Account { + account_id: self.account_id.clone(), + account: near_primitives::account::Account::new( + self.amount.unwrap_or(previous_amount), + self.locked.unwrap_or(previous_locked), + self.code_hash.unwrap_or(previous_code_hash), + self.storage_usage.unwrap_or(previous_storage_usage), + ), + }; + + let records = vec![account]; + + // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: + let _patch_resp = self + .sandbox + .client() + .query(&RpcSandboxPatchStateRequest { records }) + .await + .map_err(|err| anyhow::anyhow!("Failed to patch state: {:?}", err))?; + + Ok(()) + } +} diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index 69a2779a..4742977c 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -1,13 +1,14 @@ use crate::network::{AllowDevAccountCreation, NetworkClient, NetworkInfo, TopLevelAccountCreator}; -use crate::network::{Info, Sandbox, SandboxPatchStateBuilder}; +use crate::network::{Info, Sandbox, SandboxPatchStateAccountBuilder, SandboxPatchStateBuilder}; use crate::result::{CallExecution, CallExecutionDetails, ViewResultDetails}; use crate::rpc::client::{Client, DEFAULT_CALL_DEPOSIT, DEFAULT_CALL_FN_GAS}; use crate::rpc::patch::ImportContractTransaction; -use crate::types::{AccountId, Gas, InMemorySigner, SecretKey}; +use crate::types::{AccountId, Gas, InMemorySigner, PublicKey, SecretKey}; use crate::worker::Worker; use crate::{Account, Block, Contract}; use crate::{AccountDetails, Network}; use async_trait::async_trait; +use near_primitives::account::AccessKey; use near_primitives::types::Balance; use std::collections::HashMap; @@ -181,6 +182,11 @@ impl Worker { self.workspace.patch_state(account_id.clone()) } + /// Patch account state using builder pattern + pub fn patch_account(&self, account_id: &AccountId) -> SandboxPatchStateAccountBuilder { + self.workspace.patch_account(account_id.clone()) + } + /// Patch state into the sandbox network, given a key and value. This will allow us to set /// state that we have acquired in some manner. This allows us to test random cases that /// are hard to come up naturally as state evolves. @@ -203,12 +209,26 @@ impl Worker { /// Patch state into the sandbox network. Same as `patch_state` but accepts a sequence of key value pairs pub async fn patch_state_multiple( &self, - contract_id: &AccountId, + account_id: &AccountId, kvs: impl IntoIterator>, impl Into>)>, ) -> anyhow::Result<()> { self.workspace - .patch_state(contract_id.clone()) - .data_many(kvs) + .patch_state(account_id.clone()) + .data_multiple(kvs) + .apply() + .await?; + Ok(()) + } + + pub async fn patch_access_key( + &self, + account_id: &AccountId, + public_key: &PublicKey, + access_key: &AccessKey, + ) -> anyhow::Result<()> { + self.workspace + .patch_state(account_id.clone()) + .access_key(public_key, access_key) .apply() .await?; Ok(()) diff --git a/workspaces/tests/patch_state.rs b/workspaces/tests/patch_state.rs index 15423f30..7c387b74 100644 --- a/workspaces/tests/patch_state.rs +++ b/workspaces/tests/patch_state.rs @@ -91,3 +91,18 @@ async fn test_patch_state() -> anyhow::Result<()> { Ok(()) } + +#[test(tokio::test)] +#[ignore] +async fn patch_state_builder() -> anyhow::Result<()> { + let worker = workspaces::sandbox().await?; + let id: AccountId = "nino.near".parse()?; + worker + .patch_account(&id) + .amount(1) + .locked(0) + .apply() + .await?; + + Ok(()) +} From 991ce431a8ef51479076eab12b150db0a82d30e7 Mon Sep 17 00:00:00 2001 From: adsick Date: Thu, 21 Apr 2022 10:43:36 +0300 Subject: [PATCH 08/16] remove some comments --- workspaces/src/network/sandbox.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index 250d10fd..58a22780 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -170,9 +170,7 @@ pub struct SandboxPatchStateBuilder<'s> { records: Vec, } -//todo: add more methods impl<'s> SandboxPatchStateBuilder<'s> { - //AsRef allows for both &AccountId and AccountId pub fn new(sandbox: &'s Sandbox, account_id: AccountId) -> Self { SandboxPatchStateBuilder { sandbox, @@ -219,10 +217,6 @@ impl<'s> SandboxPatchStateBuilder<'s> { self } - // pub fn account(self) -> SandboxPatchStateAccountBuilder<'s> { - // SandboxPatchStateAccountBuilder::new(self) - // } - pub async fn apply(self) -> anyhow::Result<()> { let records = self.records; // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: @@ -260,10 +254,6 @@ impl<'s> SandboxPatchStateAccountBuilder<'s> { } pub const fn amount(mut self, amount: Balance) -> Self { - // a little experiment, wonder if it can produce compile-time errors - if let Some(_amount) = self.amount { - panic!("'amount' field has already been set"); - } self.amount = Some(amount); self } From 7ff6b82ba63dfe95d5dfd8f3b73a95e97efd73f2 Mon Sep 17 00:00:00 2001 From: adsick Date: Thu, 21 Apr 2022 10:47:56 +0300 Subject: [PATCH 09/16] remove some comments --- examples/src/spooning.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/examples/src/spooning.rs b/examples/src/spooning.rs index fd912688..3d987978 100644 --- a/examples/src/spooning.rs +++ b/examples/src/spooning.rs @@ -100,15 +100,6 @@ async fn main() -> anyhow::Result<()> { .patch_state(sandbox_contract.id(), "STATE", status_msg.try_to_vec()?) .await?; - // build pattern equivalent - - // worker - // .patch_state_builder(sandbox_contract.id()) - // .data( "STATE", status_msg.try_to_vec()?) - // // .data_multiple([("hello", "world"), ("goodbye", "putin")]) - // .apply() - // .await?; - // Now grab the state to see that it has indeed been patched: let status: String = sandbox_contract .view( From 2ec00fc875818f24f00a10869241ef11b053cbcf Mon Sep 17 00:00:00 2001 From: Buckram123 Date: Thu, 21 Apr 2022 15:16:11 +0300 Subject: [PATCH 10/16] feat: access key builder --- workspaces/src/network/mod.rs | 1 + workspaces/src/network/sandbox.rs | 108 +++++++++++++++++++++++++++--- workspaces/src/worker/impls.rs | 17 ++--- 3 files changed, 105 insertions(+), 21 deletions(-) diff --git a/workspaces/src/network/mod.rs b/workspaces/src/network/mod.rs index 6aef987f..1be98c07 100644 --- a/workspaces/src/network/mod.rs +++ b/workspaces/src/network/mod.rs @@ -10,6 +10,7 @@ mod server; mod testnet; pub(crate) mod variants; +pub(crate) use sandbox::SandboxPatchAcessKeyBuilder; //not needed directly outside of the crate pub(crate) use sandbox::SandboxPatchStateAccountBuilder; //not needed directly outside of the crate pub(crate) use sandbox::SandboxPatchStateBuilder; //not needed directly outside of the crate pub(crate) use variants::DEV_ACCOUNT_SEED; diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index 58a22780..e1e88191 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -4,7 +4,6 @@ use std::str::FromStr; use async_trait::async_trait; use near_jsonrpc_client::methods::sandbox_fast_forward::RpcSandboxFastForwardRequest; use near_jsonrpc_client::methods::sandbox_patch_state::RpcSandboxPatchStateRequest; -use near_primitives::account::AccessKey; use near_primitives::hash::CryptoHash; use near_primitives::state_record::StateRecord; use near_primitives::types::StorageUsage; @@ -17,7 +16,7 @@ use crate::network::Info; use crate::result::CallExecution; use crate::rpc::client::Client; use crate::rpc::patch::ImportContractTransaction; -use crate::types::{AccountId, Balance, InMemorySigner, PublicKey, SecretKey}; +use crate::types::{AccountId, Balance, InMemorySigner, Nonce, SecretKey}; use crate::{Account, Contract, Network, Worker}; // Constant taken from nearcore crate to avoid dependency @@ -148,6 +147,14 @@ impl Sandbox { SandboxPatchStateAccountBuilder::new(self, account_id) } + pub(crate) fn patch_access_key( + &self, + account_id: AccountId, + public_key: crate::types::PublicKey, + ) -> SandboxPatchAcessKeyBuilder { + SandboxPatchAcessKeyBuilder::new(self, account_id, public_key) + } + // shall we expose convenience patch methods here for consistent API? pub(crate) async fn fast_forward(&self, delta_height: u64) -> anyhow::Result<()> { @@ -207,15 +214,15 @@ impl<'s> SandboxPatchStateBuilder<'s> { self } - pub fn access_key(mut self, public_key: &PublicKey, access_key: &AccessKey) -> Self { - let access_key = StateRecord::AccessKey { - account_id: self.account_id.clone(), - public_key: public_key.0.clone(), - access_key: access_key.clone(), - }; - self.records.push(access_key); - self - } + // pub fn access_key(mut self, public_key: &PublicKey, access_key: &AccessKey) -> Self { + // let access_key = StateRecord::AccessKey { + // account_id: self.account_id.clone(), + // public_key: public_key.0.clone(), + // access_key: access_key.clone(), + // }; + // self.records.push(access_key); + // self + // } pub async fn apply(self) -> anyhow::Result<()> { let records = self.records; @@ -312,3 +319,82 @@ impl<'s> SandboxPatchStateAccountBuilder<'s> { Ok(()) } } + +#[must_use = "don't forget to .apply() this `SandboxPatchStateAccountBuilder`"] +pub struct SandboxPatchAcessKeyBuilder<'s> { + sandbox: &'s Sandbox, + account_id: AccountId, + public_key: crate::types::PublicKey, + nonce: Nonce, +} + +impl<'s> SandboxPatchAcessKeyBuilder<'s> { + pub const fn new( + sandbox: &'s Sandbox, + account_id: AccountId, + public_key: crate::types::PublicKey, + ) -> Self { + Self { + sandbox, + account_id, + public_key, + nonce: 0, + } + } + + pub const fn nonce(mut self, nonce: Nonce) -> Self { + self.nonce = nonce; + self + } + + pub async fn full_access(self) -> anyhow::Result<()> { + let mut access_key = near_primitives::account::AccessKey::full_access(); + access_key.nonce = self.nonce; + let access_key = StateRecord::AccessKey { + account_id: self.account_id, + public_key: self.public_key.into(), + access_key, + }; + + let records = vec![access_key]; + + // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: + let _patch_resp = self + .sandbox + .client() + .query(&RpcSandboxPatchStateRequest { records }) + .await + .map_err(|err| anyhow::anyhow!("Failed to patch state: {:?}", err))?; + + Ok(()) + } + + pub async fn function_call( + self, + receiver_id: &AccountId, + method_names: &[&str], + allowance: Option, + ) -> anyhow::Result<()> { + let mut access_key: near_primitives::account::AccessKey = + crate::types::AccessKey::function_call_access(receiver_id, method_names, allowance) + .into(); + access_key.nonce = self.nonce; + let access_key = StateRecord::AccessKey { + account_id: self.account_id, + public_key: self.public_key.into(), + access_key, + }; + + let records = vec![access_key]; + + // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: + let _patch_resp = self + .sandbox + .client() + .query(&RpcSandboxPatchStateRequest { records }) + .await + .map_err(|err| anyhow::anyhow!("Failed to patch state: {:?}", err))?; + + Ok(()) + } +} diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index 4742977c..6c2cab24 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -1,4 +1,7 @@ -use crate::network::{AllowDevAccountCreation, NetworkClient, NetworkInfo, TopLevelAccountCreator}; +use crate::network::{ + AllowDevAccountCreation, NetworkClient, NetworkInfo, SandboxPatchAcessKeyBuilder, + TopLevelAccountCreator, +}; use crate::network::{Info, Sandbox, SandboxPatchStateAccountBuilder, SandboxPatchStateBuilder}; use crate::result::{CallExecution, CallExecutionDetails, ViewResultDetails}; use crate::rpc::client::{Client, DEFAULT_CALL_DEPOSIT, DEFAULT_CALL_FN_GAS}; @@ -8,7 +11,6 @@ use crate::worker::Worker; use crate::{Account, Block, Contract}; use crate::{AccountDetails, Network}; use async_trait::async_trait; -use near_primitives::account::AccessKey; use near_primitives::types::Balance; use std::collections::HashMap; @@ -220,18 +222,13 @@ impl Worker { Ok(()) } - pub async fn patch_access_key( + pub fn patch_access_key( &self, account_id: &AccountId, public_key: &PublicKey, - access_key: &AccessKey, - ) -> anyhow::Result<()> { + ) -> SandboxPatchAcessKeyBuilder { self.workspace - .patch_state(account_id.clone()) - .access_key(public_key, access_key) - .apply() - .await?; - Ok(()) + .patch_access_key(account_id.clone(), public_key.clone()) } /// Fast forward to a point in the future. The delta block height is supplied to tell the From edceb777985329a7ce863d7fdfd2f620121616ed Mon Sep 17 00:00:00 2001 From: Buckram123 Date: Thu, 21 Apr 2022 15:17:20 +0300 Subject: [PATCH 11/16] style: renamed it to match crate function --- workspaces/src/network/sandbox.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index e1e88191..7b137f51 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -369,7 +369,7 @@ impl<'s> SandboxPatchAcessKeyBuilder<'s> { Ok(()) } - pub async fn function_call( + pub async fn function_call_access( self, receiver_id: &AccountId, method_names: &[&str], From 50d2266c45edfb4593084db625f5c4ab41d2d56a Mon Sep 17 00:00:00 2001 From: adsick Date: Thu, 5 May 2022 23:17:52 +0300 Subject: [PATCH 12/16] suggestions 1, 2 --- workspaces/src/network/mod.rs | 18 +++++++++--------- workspaces/src/network/sandbox.rs | 28 ++++++++++++++-------------- workspaces/src/worker/impls.rs | 14 +++++++------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/workspaces/src/network/mod.rs b/workspaces/src/network/mod.rs index 1be98c07..af860334 100644 --- a/workspaces/src/network/mod.rs +++ b/workspaces/src/network/mod.rs @@ -10,16 +10,16 @@ mod server; mod testnet; pub(crate) mod variants; -pub(crate) use sandbox::SandboxPatchAcessKeyBuilder; //not needed directly outside of the crate -pub(crate) use sandbox::SandboxPatchStateAccountBuilder; //not needed directly outside of the crate -pub(crate) use sandbox::SandboxPatchStateBuilder; //not needed directly outside of the crate +pub(crate) use sandbox::PatchAccessKeyTransaction; +pub(crate) use sandbox::PatchStateAccountTransaction; +pub(crate) use sandbox::PatchStateTransaction; pub(crate) use variants::DEV_ACCOUNT_SEED; -pub use betanet::Betanet; -pub use info::Info; -pub use mainnet::Mainnet; -pub use sandbox::Sandbox; -pub use testnet::Testnet; -pub use variants::{ +pub use self::betanet::Betanet; +pub use self::info::Info; +pub use self::mainnet::Mainnet; +pub use self::sandbox::Sandbox; +pub use self::testnet::Testnet; +pub use self::variants::{ AllowDevAccountCreation, DevAccountDeployer, NetworkClient, NetworkInfo, TopLevelAccountCreator, }; diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index 7b137f51..a89cc4b1 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -139,20 +139,20 @@ impl Sandbox { ImportContractTransaction::new(id.to_owned(), worker.client(), self.client()) } - pub(crate) fn patch_state(&self, account_id: AccountId) -> SandboxPatchStateBuilder { - SandboxPatchStateBuilder::new(self, account_id) + pub(crate) fn patch_state(&self, account_id: AccountId) -> PatchStateTransaction { + PatchStateTransaction::new(self, account_id) } - pub(crate) fn patch_account(&self, account_id: AccountId) -> SandboxPatchStateAccountBuilder { - SandboxPatchStateAccountBuilder::new(self, account_id) + pub(crate) fn patch_account(&self, account_id: AccountId) -> PatchStateAccountTransaction { + PatchStateAccountTransaction::new(self, account_id) } pub(crate) fn patch_access_key( &self, account_id: AccountId, public_key: crate::types::PublicKey, - ) -> SandboxPatchAcessKeyBuilder { - SandboxPatchAcessKeyBuilder::new(self, account_id, public_key) + ) -> PatchAccessKeyTransaction { + PatchAccessKeyTransaction::new(self, account_id, public_key) } // shall we expose convenience patch methods here for consistent API? @@ -171,15 +171,15 @@ impl Sandbox { //todo: review naming #[must_use = "don't forget to .apply() this `SandboxPatchStateBuilder`"] -pub struct SandboxPatchStateBuilder<'s> { +pub struct PatchStateTransaction<'s> { sandbox: &'s Sandbox, account_id: AccountId, records: Vec, } -impl<'s> SandboxPatchStateBuilder<'s> { +impl<'s> PatchStateTransaction<'s> { pub fn new(sandbox: &'s Sandbox, account_id: AccountId) -> Self { - SandboxPatchStateBuilder { + PatchStateTransaction { sandbox, account_id, records: Vec::with_capacity(4), @@ -224,7 +224,7 @@ impl<'s> SandboxPatchStateBuilder<'s> { // self // } - pub async fn apply(self) -> anyhow::Result<()> { + pub async fn transact(self) -> anyhow::Result<()> { let records = self.records; // NOTE: RpcSandboxPatchStateResponse is an empty struct with no fields, so don't do anything with it: let _patch_resp = self @@ -239,7 +239,7 @@ impl<'s> SandboxPatchStateBuilder<'s> { } #[must_use = "don't forget to .apply() this `SandboxPatchStateAccountBuilder`"] -pub struct SandboxPatchStateAccountBuilder<'s> { +pub struct PatchStateAccountTransaction<'s> { sandbox: &'s Sandbox, account_id: AccountId, amount: Option, @@ -248,7 +248,7 @@ pub struct SandboxPatchStateAccountBuilder<'s> { storage_usage: Option, } -impl<'s> SandboxPatchStateAccountBuilder<'s> { +impl<'s> PatchStateAccountTransaction<'s> { pub const fn new(sandbox: &'s Sandbox, account_id: AccountId) -> Self { Self { sandbox, @@ -321,14 +321,14 @@ impl<'s> SandboxPatchStateAccountBuilder<'s> { } #[must_use = "don't forget to .apply() this `SandboxPatchStateAccountBuilder`"] -pub struct SandboxPatchAcessKeyBuilder<'s> { +pub struct PatchAccessKeyTransaction<'s> { sandbox: &'s Sandbox, account_id: AccountId, public_key: crate::types::PublicKey, nonce: Nonce, } -impl<'s> SandboxPatchAcessKeyBuilder<'s> { +impl<'s> PatchAccessKeyTransaction<'s> { pub const fn new( sandbox: &'s Sandbox, account_id: AccountId, diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index 6c2cab24..ddb60f35 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -1,8 +1,8 @@ use crate::network::{ - AllowDevAccountCreation, NetworkClient, NetworkInfo, SandboxPatchAcessKeyBuilder, + AllowDevAccountCreation, NetworkClient, NetworkInfo, PatchAccessKeyTransaction, TopLevelAccountCreator, }; -use crate::network::{Info, Sandbox, SandboxPatchStateAccountBuilder, SandboxPatchStateBuilder}; +use crate::network::{Info, Sandbox, PatchStateAccountTransaction, PatchStateTransaction}; use crate::result::{CallExecution, CallExecutionDetails, ViewResultDetails}; use crate::rpc::client::{Client, DEFAULT_CALL_DEPOSIT, DEFAULT_CALL_FN_GAS}; use crate::rpc::patch::ImportContractTransaction; @@ -180,12 +180,12 @@ impl Worker { /// Patch state into the sandbox network, using builder pattern. This will allow us to set /// state that we have acquired in some manner. This allows us to test random cases that /// are hard to come up naturally as state evolves. - pub fn patch_state_builder(&self, account_id: &AccountId) -> SandboxPatchStateBuilder { + pub fn patch_state_builder(&self, account_id: &AccountId) -> PatchStateTransaction { self.workspace.patch_state(account_id.clone()) } /// Patch account state using builder pattern - pub fn patch_account(&self, account_id: &AccountId) -> SandboxPatchStateAccountBuilder { + pub fn patch_account(&self, account_id: &AccountId) -> PatchStateAccountTransaction { self.workspace.patch_account(account_id.clone()) } @@ -201,7 +201,7 @@ impl Worker { self.workspace .patch_state(contract_id.clone()) .data(key, value) - .apply() + .transact() .await?; Ok(()) } @@ -217,7 +217,7 @@ impl Worker { self.workspace .patch_state(account_id.clone()) .data_multiple(kvs) - .apply() + .transact() .await?; Ok(()) } @@ -226,7 +226,7 @@ impl Worker { &self, account_id: &AccountId, public_key: &PublicKey, - ) -> SandboxPatchAcessKeyBuilder { + ) -> PatchAccessKeyTransaction { self.workspace .patch_access_key(account_id.clone(), public_key.clone()) } From edacfd698778a66836f944c505719b7abdf5e611 Mon Sep 17 00:00:00 2001 From: adsick Date: Thu, 5 May 2022 23:19:35 +0300 Subject: [PATCH 13/16] changed unwrap to expect in workspaces/build.rs removed comments, Co-authored-by: Phuong Nguyen --- workspaces/build.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/workspaces/build.rs b/workspaces/build.rs index d2ace692..d801dc2b 100644 --- a/workspaces/build.rs +++ b/workspaces/build.rs @@ -1,9 +1,6 @@ fn main() { let doc_build = cfg!(doc) || std::env::var("DOCS_RS").is_ok(); if !doc_build && cfg!(feature = "install") { - // using unwrap because all the useful error messages are hidden inside - near_sandbox_utils::ensure_sandbox_bin().unwrap(); - // previously the next line was causing near sandbox to be installed every time cargo build/check was called - // near_sandbox_utils::install().expect("Could not install sandbox"); + near_sandbox_utils::ensure_sandbox_bin().expect("Could not install sandbox"); } } From 1c4c459bb7bab1b0dea52b48651ea865ea65d344 Mon Sep 17 00:00:00 2001 From: adsick Date: Thu, 5 May 2022 23:23:14 +0300 Subject: [PATCH 14/16] explanatory errors in build.rs --- workspaces/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/workspaces/build.rs b/workspaces/build.rs index d801dc2b..abd7f602 100644 --- a/workspaces/build.rs +++ b/workspaces/build.rs @@ -1,6 +1,9 @@ fn main() { let doc_build = cfg!(doc) || std::env::var("DOCS_RS").is_ok(); if !doc_build && cfg!(feature = "install") { - near_sandbox_utils::ensure_sandbox_bin().expect("Could not install sandbox"); + match near_sandbox_utils::ensure_sandbox_bin(){ + Ok(p) => println!("Successfully installed sandbox in: {:?}", p), + Err(e) => panic!("Could not install sandbox\nReason: {:?}", e), + } } } From 7e1b304fbd2a9f2230d03a4f8be647e224216003 Mon Sep 17 00:00:00 2001 From: adsick Date: Fri, 6 May 2022 11:13:24 +0300 Subject: [PATCH 15/16] removed commented access_key method in workspaces/src/network/sandbox.rs Co-authored-by: Phuong Nguyen --- workspaces/src/network/sandbox.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index a89cc4b1..7a457cf1 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -214,15 +214,6 @@ impl<'s> PatchStateTransaction<'s> { self } - // pub fn access_key(mut self, public_key: &PublicKey, access_key: &AccessKey) -> Self { - // let access_key = StateRecord::AccessKey { - // account_id: self.account_id.clone(), - // public_key: public_key.0.clone(), - // access_key: access_key.clone(), - // }; - // self.records.push(access_key); - // self - // } pub async fn transact(self) -> anyhow::Result<()> { let records = self.records; From ff26068bdc493a1a914b74269cd44f2cf07af680 Mon Sep 17 00:00:00 2001 From: adsick Date: Fri, 6 May 2022 23:52:53 +0300 Subject: [PATCH 16/16] replace StorageUsage and use slices --- workspaces/src/network/sandbox.rs | 37 ++++++++++++++++++------------- workspaces/src/types/mod.rs | 3 +++ workspaces/src/worker/impls.rs | 12 +++++----- workspaces/tests/patch_state.rs | 2 +- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index 7a457cf1..dcf27204 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -6,7 +6,6 @@ use near_jsonrpc_client::methods::sandbox_fast_forward::RpcSandboxFastForwardReq use near_jsonrpc_client::methods::sandbox_patch_state::RpcSandboxPatchStateRequest; use near_primitives::hash::CryptoHash; use near_primitives::state_record::StateRecord; -use near_primitives::types::StorageUsage; use near_primitives::views::AccountView; use std::iter::IntoIterator; @@ -16,7 +15,7 @@ use crate::network::Info; use crate::result::CallExecution; use crate::rpc::client::Client; use crate::rpc::patch::ImportContractTransaction; -use crate::types::{AccountId, Balance, InMemorySigner, Nonce, SecretKey}; +use crate::types::{AccountId, Balance, InMemorySigner, Nonce, SecretKey, StorageUsage}; use crate::{Account, Contract, Network, Worker}; // Constant taken from nearcore crate to avoid dependency @@ -186,11 +185,11 @@ impl<'s> PatchStateTransaction<'s> { } } - pub fn data(mut self, key: impl Into>, value: impl Into>) -> Self { + pub fn data(mut self, key: &[u8], value: &[u8]) -> Self { let data = StateRecord::Data { account_id: self.account_id.clone(), - data_key: key.into(), - value: value.into(), + data_key: key.to_vec(), + value: value.to_vec(), }; self.records.push(data); @@ -199,18 +198,9 @@ impl<'s> PatchStateTransaction<'s> { pub fn data_multiple( mut self, - kvs: impl IntoIterator>, impl Into>)>, + kvs: impl IntoIterator, ) -> Self { - let Self { - ref mut records, - ref account_id, - .. - } = self; - records.extend(kvs.into_iter().map(|(key, value)| StateRecord::Data { - account_id: account_id.clone(), - data_key: key.into(), - value: value.into(), - })); + self.extend(kvs); self } @@ -229,6 +219,21 @@ impl<'s> PatchStateTransaction<'s> { } } +impl<'s> std::iter::Extend<(&'s [u8], &'s [u8])> for PatchStateTransaction<'s>{ + fn extend>(&mut self, iter: T) { + let Self { + ref mut records, + ref account_id, + .. + } = self; + records.extend(iter.into_iter().map(|(key, value)| StateRecord::Data { + account_id: account_id.clone(), + data_key: key.to_vec(), + value: value.to_vec(), + })); + } +} + #[must_use = "don't forget to .apply() this `SandboxPatchStateAccountBuilder`"] pub struct PatchStateAccountTransaction<'s> { sandbox: &'s Sandbox, diff --git a/workspaces/src/types/mod.rs b/workspaces/src/types/mod.rs index 14b7d8ac..49013b55 100644 --- a/workspaces/src/types/mod.rs +++ b/workspaces/src/types/mod.rs @@ -28,6 +28,9 @@ pub type Balance = u128; /// Height of a specific block pub type BlockHeight = u64; +/// StorageUsage is used to count the amount of storage used by a contract. +pub type StorageUsage = u64; + impl From for near_crypto::PublicKey { fn from(pk: PublicKey) -> Self { pk.0 diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index ddb60f35..200c1e47 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -195,8 +195,8 @@ impl Worker { pub async fn patch_state( &self, contract_id: &AccountId, - key: impl Into>, - value: impl Into>, + key: &[u8], + value: &[u8], ) -> anyhow::Result<()> { self.workspace .patch_state(contract_id.clone()) @@ -206,13 +206,11 @@ impl Worker { Ok(()) } - //todo: add more patch state methods like the previous one - /// Patch state into the sandbox network. Same as `patch_state` but accepts a sequence of key value pairs - pub async fn patch_state_multiple( - &self, + pub async fn patch_state_multiple<'s>( + &'s self, account_id: &AccountId, - kvs: impl IntoIterator>, impl Into>)>, + kvs: impl IntoIterator, ) -> anyhow::Result<()> { self.workspace .patch_state(account_id.clone()) diff --git a/workspaces/tests/patch_state.rs b/workspaces/tests/patch_state.rs index 7c387b74..d870201c 100644 --- a/workspaces/tests/patch_state.rs +++ b/workspaces/tests/patch_state.rs @@ -71,7 +71,7 @@ async fn test_patch_state() -> anyhow::Result<()> { }); worker - .patch_state(&contract_id, "STATE", status_msg.try_to_vec()?) + .patch_state(&contract_id, b"STATE", &status_msg.try_to_vec()?) .await?; let status: String = worker