Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved away from tla on testnet #369

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
needs: cargo-fmt
strategy:
matrix:
platform: [ubuntu-latest, macos-latest]
platform: [macos-latest, ubuntu-latest]
toolchain: [stable]
runs-on: ${{ matrix.platform }}

Expand Down
2 changes: 1 addition & 1 deletion examples/src/croncat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ async fn main() -> anyhow::Result<()> {
.into_result()?;

// Create a root croncat account with agent subaccounts to schedule tasks.
let croncat = worker.dev_create_account().await?;
let croncat = worker.dev_create().await?;

// This will setup a task to call into the counter contract, with a cadence of 1 hour.
println!("Creating task for `counter.increment`");
Expand Down
2 changes: 1 addition & 1 deletion examples/src/various_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async fn main() -> anyhow::Result<()> {
.await?;
println!("Latest Chunk: {chunk:#?}");

let bob = worker.dev_create_account().await?;
let bob = worker.dev_create().await?;
println!("\nCreated bob's account with id {:?}", bob.id());

// Show all the access keys relating to bob:
Expand Down
2 changes: 1 addition & 1 deletion workspaces/src/network/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ pub use self::sandbox::Sandbox;
pub use self::server::{pick_unused_port, ValidatorKey};
pub use self::testnet::Testnet;
pub use self::variants::{
AllowDevAccountCreation, NetworkClient, NetworkInfo, TopLevelAccountCreator,
NetworkClient, NetworkInfo, SponsoredAccountCreator, TopLevelAccountCreator,
};
pub use config::set_sandbox_genesis;
57 changes: 52 additions & 5 deletions workspaces/src/network/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use near_sandbox_utils as sandbox;

use super::builder::{FromNetworkBuilder, NetworkBuilder};
use super::server::ValidatorKey;
use super::{AllowDevAccountCreation, NetworkClient, NetworkInfo, TopLevelAccountCreator};
use crate::error::SandboxErrorCode;
use super::{NetworkClient, NetworkInfo, SponsoredAccountCreator, TopLevelAccountCreator};
use crate::error::{ErrorKind, SandboxErrorCode};
use crate::network::server::SandboxServer;
use crate::network::Info;
use crate::result::{Execution, ExecutionFinalResult, Result};
Expand Down Expand Up @@ -128,8 +128,6 @@ impl FromNetworkBuilder for Sandbox {
}
}

impl AllowDevAccountCreation for Sandbox {}

#[async_trait]
impl TopLevelAccountCreator for Sandbox {
async fn create_tla(
Expand All @@ -143,7 +141,6 @@ impl TopLevelAccountCreator for Sandbox {
.client()
.create_account(&root_signer, &id, sk.public_key(), DEFAULT_DEPOSIT)
.await?;

let signer = InMemorySigner::from_secret_key(id, sk);
Ok(Execution {
result: Account::new(signer, worker),
Expand All @@ -169,7 +166,57 @@ impl TopLevelAccountCreator for Sandbox {
wasm.into(),
)
.await?;
let signer = InMemorySigner::from_secret_key(id, sk);
Ok(Execution {
result: Contract::new(signer, worker),
details: ExecutionFinalResult::from_view(outcome),
})
}
}

#[async_trait]
impl SponsoredAccountCreator for Sandbox {
async fn create_sponsored_account(
&self,
worker: Worker<dyn Network>,
subaccount_prefix: AccountId,
sk: SecretKey,
) -> Result<Execution<Account>> {
let id =
AccountId::from_str(format!("{}.{}", subaccount_prefix, self.info().root_id).as_str())
.map_err(|e| ErrorKind::DataConversion.custom(e))?;
let root_signer = self.root_signer()?;
let outcome = self
.client()
.create_account(&root_signer, &id, sk.public_key(), DEFAULT_DEPOSIT)
.await?;
let signer = InMemorySigner::from_secret_key(id, sk);
Ok(Execution {
result: Account::new(signer, worker),
details: ExecutionFinalResult::from_view(outcome),
})
}
async fn create_sponsored_account_and_deploy(
&self,
worker: Worker<dyn Network>,
subaccount_prefix: AccountId,
sk: SecretKey,
wasm: &[u8],
) -> Result<Execution<Contract>> {
let id =
AccountId::from_str(format!("{}.{}", subaccount_prefix, self.info().root_id).as_str())
.map_err(|e| ErrorKind::DataConversion.custom(e))?;
let root_signer = self.root_signer()?;
let outcome = self
.client()
.create_account_and_deploy(
&root_signer,
&id,
sk.public_key(),
DEFAULT_DEPOSIT,
wasm.into(),
)
.await?;
let signer = InMemorySigner::from_secret_key(id, sk);
Ok(Execution {
result: Contract::new(signer, worker),
Expand Down
34 changes: 21 additions & 13 deletions workspaces/src/network/testnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ use url::Url;

use near_primitives::views::ExecutionStatusView;

use crate::error::ErrorKind;
use crate::network::builder::{FromNetworkBuilder, NetworkBuilder};
use crate::network::Info;
use crate::network::{AllowDevAccountCreation, NetworkClient, NetworkInfo, TopLevelAccountCreator};
use crate::network::{NetworkClient, NetworkInfo, SponsoredAccountCreator};
use crate::result::{Execution, ExecutionDetails, ExecutionFinalResult, ExecutionOutcome, Result};
use crate::rpc::{client::Client, tool};
use crate::types::{AccountId, InMemorySigner, NearToken, SecretKey};
Expand All @@ -18,7 +19,7 @@ use crate::{Account, Contract, CryptoHash, Network, Worker};
/// URL to the testnet RPC node provided by near.org.
pub const RPC_URL: &str = "https://rpc.testnet.near.org";

/// URL to the helper contract used to create top-level-accounts (TLA) provided by near.org.
/// URL to the helper contract used to create named accounts provided by near.org.
pub const HELPER_URL: &str = "https://helper.testnet.near.org";

/// URL to the testnet archival RPC node provided by near.org.
Expand Down Expand Up @@ -64,18 +65,20 @@ impl std::fmt::Debug for Testnet {
}
}

impl AllowDevAccountCreation for Testnet {}

#[async_trait]
impl TopLevelAccountCreator for Testnet {
async fn create_tla(
impl SponsoredAccountCreator for Testnet {
async fn create_sponsored_account(
&self,
worker: Worker<dyn Network>,
id: AccountId,
subaccount_prefix: AccountId,
sk: SecretKey,
// TODO: return Account only, but then you don't get metadata info for it...
) -> Result<Execution<Account>> {
let url = Url::parse(HELPER_URL).unwrap();
//only registrar can create tla on testnet, so must concatenate random created id with .testnet
let id =
AccountId::from_str(format!("{}.{}", subaccount_prefix, self.info().root_id).as_str())
.map_err(|e| ErrorKind::DataConversion.custom(e))?;
tool::url_create_account(url, id.clone(), sk.public_key()).await?;
let signer = InMemorySigner::from_secret_key(id, sk);

Expand Down Expand Up @@ -104,17 +107,22 @@ impl TopLevelAccountCreator for Testnet {
})
}

async fn create_tla_and_deploy(
async fn create_sponsored_account_and_deploy(
&self,
worker: Worker<dyn Network>,
id: AccountId,
subaccount_prefix: AccountId,
sk: SecretKey,
wasm: &[u8],
) -> Result<Execution<Contract>> {
let signer = InMemorySigner::from_secret_key(id.clone(), sk.clone());
let account = self.create_tla(worker, id.clone(), sk).await?;

let outcome = self.client().deploy(&signer, &id, wasm.into()).await?;
let signer = InMemorySigner::from_secret_key(subaccount_prefix.clone(), sk.clone());
let account = self
.create_sponsored_account(worker, subaccount_prefix.clone(), sk)
.await?;

let outcome = self
.client()
.deploy(&signer, &subaccount_prefix, wasm.into())
.await?;

Ok(Execution {
result: Contract::account(account.into_result()?),
Expand Down
115 changes: 101 additions & 14 deletions workspaces/src/network/variants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,29 @@ pub trait NetworkInfo {
fn info(&self) -> &Info;
}

/// Trait provides the ability to create a sponsored account. A sponsored account is a subaccount
/// of the network's root account. The `subaccount_prefix` is a prefix for the subaccount ID.
/// For example, if this parameter is `"subaccount"`, the full ID for testnet will be `"subaccount.testnet"`.
///
/// It is expected that the `subaccount_prefix` does not contain a `.`.
#[async_trait]
pub trait SponsoredAccountCreator {
async fn create_sponsored_account(
&self,
worker: Worker<dyn Network>,
subaccount_prefix: AccountId,
sk: SecretKey,
) -> Result<Execution<Account>>;

async fn create_sponsored_account_and_deploy(
&self,
worker: Worker<dyn Network>,
subaccount_prefix: AccountId,
sk: SecretKey,
wasm: &[u8],
) -> Result<Execution<Contract>>;
}

#[async_trait]
pub trait TopLevelAccountCreator {
async fn create_tla(
Expand All @@ -33,13 +56,9 @@ pub trait TopLevelAccountCreator {
) -> Result<Execution<Contract>>;
}

// NOTE: Not all networks/runtimes will have the ability to be able to do dev_deploy.
// This trait acts as segmented boundary for only specific networks such as sandbox and testnet.
pub trait AllowDevAccountCreation {}

impl<T> Worker<T>
where
T: DevNetwork + TopLevelAccountCreator + 'static,
T: Network + TopLevelAccountCreator + 'static,
{
pub async fn create_tla(&self, id: AccountId, sk: SecretKey) -> Result<Execution<Account>> {
let res = self
Expand Down Expand Up @@ -72,7 +91,7 @@ where
Ok(res)
}

pub async fn dev_generate(&self) -> (AccountId, SecretKey) {
pub async fn generate_tla_credentials(&self) -> (AccountId, SecretKey) {
let id = crate::rpc::tool::random_account_id();
let sk = SecretKey::from_seed(KeyType::ED25519, DEV_ACCOUNT_SEED);
(id, sk)
Expand All @@ -90,15 +109,86 @@ where
/// }
/// ```
///
pub async fn dev_create_account(&self) -> Result<Account> {
let (id, sk) = self.dev_generate().await;
pub async fn dev_create_tla(&self) -> Result<Account> {
let (id, sk) = self.generate_tla_credentials().await;
let account = self.create_tla(id.clone(), sk).await?;
Ok(account.into_result()?)
}

pub async fn dev_deploy_tla(&self, wasm: &[u8]) -> Result<Contract> {
let (id, sk) = self.generate_tla_credentials().await;
let contract = self.create_tla_and_deploy(id.clone(), sk, wasm).await?;
Ok(contract.into_result()?)
}
}

impl<T> Worker<T>
where
T: DevNetwork + 'static,
{
pub async fn create_sponsored_account(
&self,
subaccount_prefix: AccountId,
sk: SecretKey,
) -> Result<Execution<Account>> {
if subaccount_prefix.as_str().contains('.') {
return Err(crate::error::ErrorKind::Io
.custom("Subaccount prefix for sponsored account cannot contain '.'"));
}
let res = self
.workspace
.create_sponsored_account(self.clone().coerce(), subaccount_prefix, sk)
.await?;

for callback in self.tx_callbacks.iter() {
callback(res.details.total_gas_burnt)?;
}

Ok(res)
}

pub async fn create_sponsored_account_and_deploy(
&self,
subaccount_prefix: AccountId,
sk: SecretKey,
wasm: &[u8],
) -> Result<Execution<Contract>> {
if subaccount_prefix.as_str().contains('.') {
return Err(crate::error::ErrorKind::Io
.custom("Subaccount prefix for sponsored account cannot contain '.'"));
}
let res = self
.workspace
.create_sponsored_account_and_deploy(self.clone().coerce(), subaccount_prefix, sk, wasm)
.await?;

for callback in self.tx_callbacks.iter() {
callback(res.details.total_gas_burnt)?;
}

Ok(res)
}

pub async fn dev_generate(&self) -> (AccountId, SecretKey) {
let id = crate::rpc::tool::random_account_id();
let sk = SecretKey::from_seed(KeyType::ED25519, DEV_ACCOUNT_SEED);
(id, sk)
}

/// Creates a sub-account of the network root account with
/// random account ID and secret key. By default, balance is around 10 Near.

pub async fn dev_create(&self) -> Result<Account> {
let (id, sk) = self.dev_generate().await;
let account = self.create_sponsored_account(id.clone(), sk).await?;
Ok(account.into_result()?)
}

pub async fn dev_deploy(&self, wasm: &[u8]) -> Result<Contract> {
let (id, sk) = self.dev_generate().await;
let contract = self.create_tla_and_deploy(id.clone(), sk, wasm).await?;
let contract = self
.create_sponsored_account_and_deploy(id.clone(), sk, wasm)
.await?;
Ok(contract.into_result()?)
}
}
Expand All @@ -110,9 +200,6 @@ pub trait Network: NetworkInfo + NetworkClient + Send + Sync {}
impl<T> Network for T where T: NetworkInfo + NetworkClient + Send + Sync {}

/// DevNetwork is a Network that can call into `dev_create` and `dev_deploy` to create developer accounts.
pub trait DevNetwork: TopLevelAccountCreator + AllowDevAccountCreation + Network + 'static {}
pub trait DevNetwork: Network + SponsoredAccountCreator + 'static {}

impl<T> DevNetwork for T where
T: TopLevelAccountCreator + AllowDevAccountCreation + Network + 'static
{
}
impl<T> DevNetwork for T where T: Network + SponsoredAccountCreator + 'static {}
4 changes: 1 addition & 3 deletions workspaces/src/worker/impls.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use near_primitives::views::StatusResponse;

use crate::network::{AllowDevAccountCreation, NetworkClient, NetworkInfo};
use crate::network::{Info, Sandbox};
use crate::network::{NetworkClient, NetworkInfo};
use crate::operations::{CallTransaction, Function};
use crate::result::{ExecutionFinalResult, Result};
use crate::rpc::client::Client;
Expand Down Expand Up @@ -41,8 +41,6 @@ impl<T: ?Sized> Clone for Worker<T> {
}
}

impl<T> AllowDevAccountCreation for Worker<T> where T: AllowDevAccountCreation {}

impl<T> NetworkInfo for Worker<T>
where
T: NetworkInfo,
Expand Down
Loading
Loading