From 47941f01811151230d4e88c78a2e85265cef3588 Mon Sep 17 00:00:00 2001 From: fospring Date: Wed, 26 Jun 2024 01:24:29 +0800 Subject: [PATCH 1/5] feat: Fixed `dev_deploy` to use registrar account to create top-level accounts (nearcore 1.37.0+ forbidden to create top-level accounts by non-registrar accounts) (#360) --- workspaces/Cargo.toml | 4 +- workspaces/src/network/config.rs | 83 +++++++++++++++++++++++++++++- workspaces/src/network/mod.rs | 1 + workspaces/src/network/sandbox.rs | 18 ++++++- workspaces/src/network/server.rs | 2 + workspaces/tests/cross_contract.rs | 15 +----- workspaces/tests/deploy.rs | 1 + 7 files changed, 106 insertions(+), 18 deletions(-) diff --git a/workspaces/Cargo.toml b/workspaces/Cargo.toml index daf6ac24..7215ea16 100644 --- a/workspaces/Cargo.toml +++ b/workspaces/Cargo.toml @@ -39,11 +39,11 @@ near-crypto = "0.20.0" near-primitives = "0.20.0" near-jsonrpc-primitives = "0.20.0" near-jsonrpc-client = { version = "0.8", features = ["sandbox"] } -near-sandbox-utils = "0.7.0" +near-sandbox-utils = "0.8.0" near-chain-configs = { version = "0.20.0", optional = true } [build-dependencies] -near-sandbox-utils = "0.7.0" +near-sandbox-utils = "0.8.0" [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/workspaces/src/network/config.rs b/workspaces/src/network/config.rs index 258504b3..c4509d89 100644 --- a/workspaces/src/network/config.rs +++ b/workspaces/src/network/config.rs @@ -11,8 +11,9 @@ // churn if we were to. use std::fs::File; -use std::io::BufReader; +use std::io::{BufReader, Write}; use std::path::Path; +use std::str::FromStr; use serde_json::Value; @@ -74,3 +75,83 @@ pub(crate) fn set_sandbox_configs(home_dir: impl AsRef) -> Result<()> { }), ) } + +/// Overwrite the $home_dir/genesis.json file over a set of entries. `value` will be used per (key, value) pair +/// where value can also be another dict. This recursively sets all entry in `value` dict to the config +/// dict, and saves back into `home_dir` at the end of the day. +fn overwrite_genesis(home_dir: impl AsRef) -> Result<()> { + let home_dir = home_dir.as_ref(); + let config_file = + File::open(home_dir.join("genesis.json")).map_err(|err| ErrorKind::Io.custom(err))?; + let config = BufReader::new(config_file); + let mut config: Value = + serde_json::from_reader(config).map_err(|err| ErrorKind::DataConversion.custom(err))?; + + let config = config.as_object_mut().expect("expected to be object"); + let mut total_supply = u128::from_str( + config + .get_mut("total_supply") + .expect("expected exist total_supply") + .as_str() + .unwrap_or_default(), + ) + .unwrap_or_default(); + let registrar_amount = 10_000_000_000_000_000_000_000_000_000_u128; + total_supply += registrar_amount; + config.insert( + "total_supply".to_string(), + Value::String(total_supply.to_string()), + ); + let records = config.get_mut("records").expect("expect exist records"); + records + .as_array_mut() + .expect("expected to be array") + .push(serde_json::json!( + { + "Account": { + "account_id": "registrar", + "account": { + "amount": registrar_amount.to_string(), + "locked": "0", + "code_hash": "11111111111111111111111111111111", + "storage_usage": 182 + } + } + } + )); + records + .as_array_mut() + .expect("expected to be array") + .push(serde_json::json!( + { + "AccessKey": { + "account_id": "registrar", + "public_key": "ed25519:5BGSaf6YjVm7565VzWQHNxoyEjwr3jUpRJSGjREvU9dB", + "access_key": { + "nonce": 0, + "permission": "FullAccess" + } + } + } + )); + + let config_file = + File::create(home_dir.join("genesis.json")).map_err(|err| ErrorKind::Io.custom(err))?; + serde_json::to_writer(config_file, &config).map_err(|err| ErrorKind::Io.custom(err))?; + + Ok(()) +} + +pub fn set_sandbox_genesis(home_dir: impl AsRef) -> Result<()> { + overwrite_genesis(&home_dir)?; + let registrar_key = r#"{"account_id":"registrar","public_key":"ed25519:5BGSaf6YjVm7565VzWQHNxoyEjwr3jUpRJSGjREvU9dB","private_key":"ed25519:3tgdk2wPraJzT4nsTuf86UX41xgPNk3MHnq8epARMdBNs29AFEztAuaQ7iHddDfXG9F2RzV1XNQYgJyAyoW51UBB"}"#; + let mut registrar_wallet = File::create(home_dir.as_ref().join("registrar.json")) + .map_err(|err| ErrorKind::Io.custom(err))?; + registrar_wallet + .write_all(registrar_key.as_bytes()) + .map_err(|err| ErrorKind::Io.custom(err))?; + registrar_wallet + .flush() + .map_err(|err| ErrorKind::Io.custom(err))?; + Ok(()) +} diff --git a/workspaces/src/network/mod.rs b/workspaces/src/network/mod.rs index 147a0802..c03a5995 100644 --- a/workspaces/src/network/mod.rs +++ b/workspaces/src/network/mod.rs @@ -27,3 +27,4 @@ pub use self::testnet::Testnet; pub use self::variants::{ AllowDevAccountCreation, NetworkClient, NetworkInfo, TopLevelAccountCreator, }; +pub use config::set_sandbox_genesis; diff --git a/workspaces/src/network/sandbox.rs b/workspaces/src/network/sandbox.rs index 1cea0ba1..4552fc5a 100644 --- a/workspaces/src/network/sandbox.rs +++ b/workspaces/src/network/sandbox.rs @@ -45,6 +45,20 @@ impl Sandbox { )), } } + + pub(crate) fn registrar_signer(&self) -> Result { + match &self.server.validator_key { + ValidatorKey::HomeDir(home_dir) => { + let path = home_dir.join("registrar.json"); + InMemorySigner::from_file(&path) + } + ValidatorKey::Known(account_id, secret_key) => Ok(InMemorySigner::from_secret_key( + account_id.clone(), + secret_key.clone(), + )), + } + } + pub(crate) async fn from_builder_with_version<'a>( build: NetworkBuilder<'a, Self>, version: &str, @@ -126,7 +140,7 @@ impl TopLevelAccountCreator for Sandbox { id: AccountId, sk: SecretKey, ) -> Result> { - let root_signer = self.root_signer()?; + let root_signer = self.registrar_signer()?; let outcome = self .client() .create_account(&root_signer, &id, sk.public_key(), DEFAULT_DEPOSIT) @@ -146,7 +160,7 @@ impl TopLevelAccountCreator for Sandbox { sk: SecretKey, wasm: &[u8], ) -> Result> { - let root_signer = self.root_signer()?; + let root_signer = self.registrar_signer()?; let outcome = self .client() .create_account_and_deploy( diff --git a/workspaces/src/network/server.rs b/workspaces/src/network/server.rs index ffd14457..f910105c 100644 --- a/workspaces/src/network/server.rs +++ b/workspaces/src/network/server.rs @@ -122,6 +122,8 @@ impl SandboxServer { // Configure `$home_dir/config.json` to our liking. Sandbox requires extra settings // for the best user experience, and being able to offer patching large state payloads. crate::network::config::set_sandbox_configs(&home_dir)?; + // Configure `$home_dir/genesis.json` to our liking. + crate::network::config::set_sandbox_genesis(&home_dir)?; // Try running the server with the follow provided rpc_ports and net_ports let (rpc_port, rpc_port_lock) = acquire_unused_port().await?; diff --git a/workspaces/tests/cross_contract.rs b/workspaces/tests/cross_contract.rs index 2b407c55..74e1efcd 100644 --- a/workspaces/tests/cross_contract.rs +++ b/workspaces/tests/cross_contract.rs @@ -29,7 +29,7 @@ async fn test_cross_contract_create_contract() -> anyhow::Result<()> { let contract = worker.dev_deploy(FACTORY_CONTRACT).await?; let status_amt = NearToken::from_near(35); - // Expect to fail for trying to create a new contract account with too short of a + // Expect to fail for trying to create a new contract account with a // top level account name, such as purely just "status" let status_id: AccountId = "status".parse().unwrap(); let outcome = cross_contract_create_contract(&status_id, &status_amt, &contract).await?; @@ -40,17 +40,6 @@ async fn test_cross_contract_create_contract() -> anyhow::Result<()> { failures.len() ); - // Expect to succeed after calling into the contract with expected length for a - // top level account. - let status_id: AccountId = "status-top-level-account-long-name".parse().unwrap(); - let outcome = cross_contract_create_contract(&status_id, &status_amt, &contract).await?; - let failures = outcome.failures(); - assert!( - failures.is_empty(), - "Expected no failures for creating a TLA, but got {} failures", - failures.len(), - ); - Ok(()) } @@ -60,7 +49,7 @@ async fn test_cross_contract_calls() -> anyhow::Result<()> { let contract = worker.dev_deploy(FACTORY_CONTRACT).await?; let status_amt = NearToken::from_near(35); - let status_id: AccountId = "status-top-level-account-long-name".parse().unwrap(); + let status_id: AccountId = format!("status.{}", contract.id()).parse().unwrap(); cross_contract_create_contract(&status_id, &status_amt, &contract) .await? .into_result()?; diff --git a/workspaces/tests/deploy.rs b/workspaces/tests/deploy.rs index bf5806f5..b6df67dc 100644 --- a/workspaces/tests/deploy.rs +++ b/workspaces/tests/deploy.rs @@ -70,6 +70,7 @@ async fn test_manually_spawned_deploy() -> anyhow::Result<()> { .await .unwrap(); tracing::info!(target: "workspaces-test", "sandbox-init: {:?}", output); + near_workspaces::network::set_sandbox_genesis(&home_dir)?; let mut child = near_sandbox_utils::run(&home_dir, rpc_port, net_port)?; From f97b91676e2525ba7468f7b418de1a89776521e3 Mon Sep 17 00:00:00 2001 From: Don <37594653+dndll@users.noreply.github.com> Date: Wed, 26 Jun 2024 14:18:38 +0100 Subject: [PATCH 2/5] chore: update manual spawn readme (#358) updates the readme to support latest --- examples/manually-spawned-sandbox.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/manually-spawned-sandbox.md b/examples/manually-spawned-sandbox.md index e473c89e..3706c406 100644 --- a/examples/manually-spawned-sandbox.md +++ b/examples/manually-spawned-sandbox.md @@ -18,7 +18,9 @@ In workspaces, to connect to our manually launched node, all we have to do is ad fn main() { let worker = workspaces::sandbox() .rpc_addr("http://localhost:3030") - .home_dir("/home/user/.near-sandbox-home") + .validator_key(workspaces::network::ValidatorKey::HomeDir( + "/.near/validator_key.json".into(), + )) .await?; Ok(()) From 1077ada16d807c95d11e4359b4ad9c41afdcbec2 Mon Sep 17 00:00:00 2001 From: Vladas Zakrevskis <146100@gmail.com> Date: Wed, 26 Jun 2024 16:19:35 +0300 Subject: [PATCH 3/5] docs: a way to get account with more than 100 near on sandbox (#351) This issue: https://github.com/near/near-workspaces-rs/issues/156 and my PR: https://github.com/near/near-workspaces-rs/pull/350 indicate that it is not clear for users how to create a dev account with more than 100 Near. Closes: https://github.com/near/near-workspaces-rs/issues/156 --- workspaces/src/network/variants.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/workspaces/src/network/variants.rs b/workspaces/src/network/variants.rs index eb228cd8..798ed7ba 100644 --- a/workspaces/src/network/variants.rs +++ b/workspaces/src/network/variants.rs @@ -78,6 +78,18 @@ where (id, sk) } + /// Creates a top level developement account. + /// On sandbox network it has a balance of 100 Near. + /// If you need more Near for your tests in sandbox consider using `root_account()` method: + /// + /// # Examples + /// ``` + /// use near_workspaces::{result::Result, Account, network::Sandbox, Worker}; + /// fn get_account_with_lots_of_near(worker: &Worker) -> Result { + /// worker.root_account() + /// } + /// ``` + /// pub async fn dev_create_account(&self) -> Result { let (id, sk) = self.dev_generate().await; let account = self.create_tla(id.clone(), sk).await?; From e0da2b187baef335528e8c3924a4b4436e80110b Mon Sep 17 00:00:00 2001 From: Yasir Shariff <141004977+shariffdev@users.noreply.github.com> Date: Wed, 26 Jun 2024 17:30:13 +0300 Subject: [PATCH 4/5] feat: Exposes status RPC API method (#308) Resolves: https://github.com/near/near-workspaces-rs/issues/148 --- examples/Cargo.toml | 4 ++ examples/src/status.rs | 67 ++++++++++++++++++++++++++++++++++ workspaces/Cargo.toml | 2 +- workspaces/src/rpc/client.rs | 14 ++----- workspaces/src/worker/impls.rs | 7 ++++ 5 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 examples/src/status.rs diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 7e8f4552..f9ef4859 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -101,3 +101,7 @@ path = "src/build_gen_abi.rs" [[example]] name = "macro_gen_abi" path = "src/macro_gen_abi.rs" + +[[example]] +name = "status" +path = "src/status.rs" diff --git a/examples/src/status.rs b/examples/src/status.rs new file mode 100644 index 00000000..8299b968 --- /dev/null +++ b/examples/src/status.rs @@ -0,0 +1,67 @@ +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let worker = near_workspaces::sandbox().await?; + let res = worker.status().await?; + + // status: StatusResponse { + // version: Version { + // version: "trunk", + // build: "eb2bbe1", + // rustc_version: "1.72.0", + // }, + // chain_id: "test-chain-vIC0E", + // protocol_version: 63, + // latest_protocol_version: 63, + // rpc_addr: Some( + // "0.0.0.0:3030", + // ), + // validators: [ + // ValidatorInfo { + // account_id: AccountId( + // "test.near", + // ), + // is_slashed: false, + // }, + // ], + // sync_info: StatusSyncInfo { + // latest_block_hash: GunSGsMD8fEmxsoyzdUGWBE4AiCUsBEefzxQJYMPdZoD, + // latest_block_height: 0, + // latest_state_root: 2tKZ7u2YU5GihxRveb2YMg5oxHBnCxNqgooUKfj9XSzh, + // latest_block_time: 2023-09-19T05:06:44.748482Z, + // syncing: false, + // earliest_block_hash: Some( + // GunSGsMD8fEmxsoyzdUGWBE4AiCUsBEefzxQJYMPdZoD, + // ), + // earliest_block_height: Some( + // 0, + // ), + // earliest_block_time: Some( + // 2023-09-19T05:06:44.748482Z, + // ), + // epoch_id: Some( + // EpochId( + // 11111111111111111111111111111111, + // ), + // ), + // epoch_start_height: Some( + // 0, + // ), + // }, + // validator_account_id: Some( + // AccountId( + // "test.near", + // ), + // ), + // validator_public_key: Some( + // ed25519:FHvRfJv7WYoaQVSQD3AES98rTJMyk5wKYPFuLJKXb3nx, + // ), + // node_public_key: ed25519:7gUkJ6EQvSZmRp98hS5mUwojwU8fqQxHjrGcpsfn88um, + // node_key: Some( + // ed25519:FHvRfJv7WYoaQVSQD3AES98rTJMyk5wKYPFuLJKXb3nx, + // ), + // uptime_sec: 0, + // detailed_debug_status: None, + // } + println!("status: {res:#?}"); + Ok(()) +} diff --git a/workspaces/Cargo.toml b/workspaces/Cargo.toml index 7215ea16..49d9017f 100644 --- a/workspaces/Cargo.toml +++ b/workspaces/Cargo.toml @@ -63,4 +63,4 @@ unstable = ["cargo_metadata"] experimental = ["near-chain-configs"] [package.metadata.docs.rs] -features = ["unstable"] +all-features = true diff --git a/workspaces/src/rpc/client.rs b/workspaces/src/rpc/client.rs index ac090776..a383602c 100644 --- a/workspaces/src/rpc/client.rs +++ b/workspaces/src/rpc/client.rs @@ -10,7 +10,6 @@ use tokio_retry::strategy::{jitter, ExponentialBackoff}; use tokio_retry::Retry; use near_jsonrpc_client::errors::{JsonRpcError, JsonRpcServerError}; -use near_jsonrpc_client::methods::health::RpcStatusError; use near_jsonrpc_client::methods::tx::RpcTransactionError; use near_jsonrpc_client::{methods, JsonRpcClient, MethodCallResult}; use near_jsonrpc_primitives::types::query::QueryResponseKind; @@ -294,18 +293,13 @@ impl Client { .await } - pub(crate) async fn status(&self) -> Result> { + pub(crate) async fn status(&self) -> Result { let result = self .rpc_client .call(methods::status::RpcStatusRequest) - .await; - - tracing::debug!( - target: "workspaces", - "Querying RPC with RpcStatusRequest resulted in {:?}", - result, - ); - result + .await + .map_err(|e| RpcErrorCode::QueryFailure.custom(e))?; + Ok(result) } pub(crate) async fn tx_async_status( diff --git a/workspaces/src/worker/impls.rs b/workspaces/src/worker/impls.rs index 84485ca3..0a0dbf4b 100644 --- a/workspaces/src/worker/impls.rs +++ b/workspaces/src/worker/impls.rs @@ -1,3 +1,5 @@ +use near_primitives::views::StatusResponse; + use crate::network::{AllowDevAccountCreation, NetworkClient, NetworkInfo}; use crate::network::{Info, Sandbox}; use crate::operations::{CallTransaction, Function}; @@ -192,6 +194,11 @@ where .map(ExecutionFinalResult::from_view) .map_err(crate::error::Error::from) } + + /// Returns the status of the network. + pub async fn status(&self) -> Result { + self.client().status().await + } } #[cfg(feature = "experimental")] From b5e90214c6bec503a60db90569ede5003e183d5d Mon Sep 17 00:00:00 2001 From: Vlad Frolov Date: Wed, 26 Jun 2024 18:35:00 +0200 Subject: [PATCH 5/5] chore: release v0.10.1 (#348) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🤖 New release * `near-workspaces`: 0.10.0 -> 0.10.1
Changelog

## [0.10.1](https://github.com/near/near-workspaces-rs/compare/near-workspaces-v0.10.0...near-workspaces-v0.10.1) - 2024-06-26 ### Added - Exposes status RPC API method ([#308](https://github.com/near/near-workspaces-rs/pull/308)) - Fixed `dev_deploy` to use registrar account to create top-level accounts (nearcore 1.37.0+ forbidden to create top-level accounts by non-registrar accounts) ([#360](https://github.com/near/near-workspaces-rs/pull/360)) - Re-exported near-abi-client ([#303](https://github.com/near/near-workspaces-rs/pull/303)) ### Other - a way to get account with more than 100 near on sandbox ([#351](https://github.com/near/near-workspaces-rs/pull/351)) - Updated cargo-near to "0.5.2" ([#347](https://github.com/near/near-workspaces-rs/pull/347))

--- This PR was generated with [release-plz](https://github.com/MarcoIeni/release-plz/). --- CHANGELOG.md | 11 +++++++++++ workspaces/Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a7850b5..0d0f8c51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ ## [Unreleased] +## [0.10.1](https://github.com/near/near-workspaces-rs/compare/near-workspaces-v0.10.0...near-workspaces-v0.10.1) - 2024-06-26 + +### Added +- Exposes status RPC API method ([#308](https://github.com/near/near-workspaces-rs/pull/308)) +- Fixed `dev_deploy` to use registrar account to create top-level accounts (nearcore 1.37.0+ forbidden to create top-level accounts by non-registrar accounts) ([#360](https://github.com/near/near-workspaces-rs/pull/360)) +- Re-exported near-abi-client ([#303](https://github.com/near/near-workspaces-rs/pull/303)) + +### Other +- a way to get account with more than 100 near on sandbox ([#351](https://github.com/near/near-workspaces-rs/pull/351)) +- Updated cargo-near to "0.5.2" ([#347](https://github.com/near/near-workspaces-rs/pull/347)) + ## [0.10.0](https://github.com/near/near-workspaces-rs/compare/near-workspaces-v0.9.0...near-workspaces-v0.10.0) - 2024-01-25 ### Other diff --git a/workspaces/Cargo.toml b/workspaces/Cargo.toml index 49d9017f..c4ac2497 100644 --- a/workspaces/Cargo.toml +++ b/workspaces/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "near-workspaces" -version = "0.10.0" +version = "0.10.1" edition = "2018" license = "MIT OR Apache-2.0" readme = "README.md"