Skip to content

Commit

Permalink
Removed the lifetime in transact_async (#249)
Browse files Browse the repository at this point in the history
* Passed a Worker down to the TransactionStatus

As reccomended here
#249 (comment)

* Renamed client -> worker

* Clippy fix

* Made things a little more generic

* Added coercion

* Added changelog
  • Loading branch information
DavidM-D authored Jan 9, 2023
1 parent 8df17e5 commit 17e402a
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 57 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## [Unreleased]

### Added

### Changed

- [`Transaction::transact_async` no longer has a lifetime parameter to make it easier to use](https://github.com/near/workspaces-rs/pull/249)

### Fixed

## [0.7.0]

### Added
Expand Down
68 changes: 40 additions & 28 deletions workspaces/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
use crate::error::{ErrorKind, RpcErrorCode};
use crate::result::{Execution, ExecutionFinalResult, Result, ViewResultDetails};
use crate::rpc::client::{
send_batch_tx_and_retry, send_batch_tx_async_and_retry, Client, DEFAULT_CALL_DEPOSIT,
send_batch_tx_and_retry, send_batch_tx_async_and_retry, DEFAULT_CALL_DEPOSIT,
DEFAULT_CALL_FN_GAS,
};
use crate::rpc::query::{Query, ViewFunction};
use crate::rpc::BoxFuture;
use crate::types::{
AccessKey, AccountId, Balance, Gas, InMemorySigner, KeyType, PublicKey, SecretKey,
};
Expand All @@ -25,6 +24,7 @@ use near_primitives::views::FinalExecutionOutcomeView;
use std::convert::TryInto;
use std::fmt;
use std::future::IntoFuture;
use std::pin::Pin;
use std::task::Poll;

const MAX_GAS: Gas = 300_000_000_000_000;
Expand Down Expand Up @@ -112,18 +112,22 @@ impl Function {
/// is used by default for `Contract::batch`.
///
/// [`Contract::batch`]: crate::Contract::batch
pub struct Transaction<'a> {
client: &'a Client,
pub struct Transaction {
worker: Worker<dyn Network>,
signer: InMemorySigner,
receiver_id: AccountId,
// Result used to defer errors in argument parsing to later when calling into transact
actions: Result<Vec<Action>>,
}

impl<'a> Transaction<'a> {
pub(crate) fn new(client: &'a Client, signer: InMemorySigner, receiver_id: AccountId) -> Self {
impl Transaction {
pub(crate) fn new(
worker: Worker<dyn Network>,
signer: InMemorySigner,
receiver_id: AccountId,
) -> Self {
Self {
client,
worker,
signer,
receiver_id,
actions: Ok(Vec::new()),
Expand Down Expand Up @@ -230,7 +234,13 @@ impl<'a> Transaction<'a> {
}

async fn transact_raw(self) -> Result<FinalExecutionOutcomeView> {
send_batch_tx_and_retry(self.client, &self.signer, &self.receiver_id, self.actions?).await
send_batch_tx_and_retry(
self.worker.client(),
&self.signer,
&self.receiver_id,
self.actions?,
)
.await
}

/// Process the transaction, and return the result of the execution.
Expand All @@ -248,30 +258,30 @@ impl<'a> Transaction<'a> {
/// of the transaction.
///
/// [`status`]: TransactionStatus::status
pub async fn transact_async(self) -> Result<TransactionStatus<'a>> {
send_batch_tx_async_and_retry(self.client, &self.signer, &self.receiver_id, self.actions?)
pub async fn transact_async(self) -> Result<TransactionStatus> {
send_batch_tx_async_and_retry(self.worker, &self.signer, &self.receiver_id, self.actions?)
.await
}
}

/// Similiar to a [`Transaction`], but more specific to making a call into a contract.
/// Note, only one call can be made per `CallTransaction`.
pub struct CallTransaction<'a> {
client: &'a Client,
pub struct CallTransaction {
worker: Worker<dyn Network>,
signer: InMemorySigner,
contract_id: AccountId,
function: Function,
}

impl<'a> CallTransaction<'a> {
impl CallTransaction {
pub(crate) fn new(
client: &'a Client,
worker: Worker<dyn Network>,
contract_id: AccountId,
signer: InMemorySigner,
function: &str,
) -> Self {
Self {
client,
worker,
signer,
contract_id,
function: Function::new(function),
Expand Down Expand Up @@ -323,7 +333,8 @@ impl<'a> CallTransaction<'a> {
/// object and return us the execution details, along with any errors if the transaction
/// failed in any process along the way.
pub async fn transact(self) -> Result<ExecutionFinalResult> {
self.client
self.worker
.client()
.call(
&self.signer,
&self.contract_id,
Expand All @@ -344,9 +355,9 @@ impl<'a> CallTransaction<'a> {
/// of the transaction.
///
/// [`status`]: TransactionStatus::status
pub async fn transact_async(self) -> Result<TransactionStatus<'a>> {
pub async fn transact_async(self) -> Result<TransactionStatus> {
send_batch_tx_async_and_retry(
self.client,
self.worker,
&self.signer,
&self.contract_id,
vec![FunctionCallAction {
Expand All @@ -363,7 +374,7 @@ impl<'a> CallTransaction<'a> {
/// Instead of transacting the transaction, call into the specified view function.
pub async fn view(self) -> Result<ViewResultDetails> {
Query::new(
self.client,
self.worker.client(),
ViewFunction {
account_id: self.contract_id.clone(),
function: self.function,
Expand Down Expand Up @@ -446,20 +457,20 @@ impl<'a, 'b> CreateAccountTransaction<'a, 'b> {
///
/// [`asynchronous transaction`]: https://docs.near.org/api/rpc/transactions#send-transaction-async
#[must_use]
pub struct TransactionStatus<'a> {
client: &'a Client,
pub struct TransactionStatus {
worker: Worker<dyn Network>,
sender_id: AccountId,
hash: CryptoHash,
}

impl<'a> TransactionStatus<'a> {
impl TransactionStatus {
pub(crate) fn new(
client: &'a Client,
worker: Worker<dyn Network>,
id: AccountId,
hash: near_primitives::hash::CryptoHash,
) -> Self {
Self {
client,
worker,
sender_id: id,
hash: CryptoHash(hash.0),
}
Expand All @@ -470,7 +481,8 @@ impl<'a> TransactionStatus<'a> {
/// `Ok` value with [`Poll::Pending`] is returned, then the transaction has not finished.
pub async fn status(&self) -> Result<Poll<ExecutionFinalResult>> {
let result = self
.client
.worker
.client()
.tx_async_status(
&self.sender_id,
near_primitives::hash::CryptoHash(self.hash.0),
Expand Down Expand Up @@ -512,7 +524,7 @@ impl<'a> TransactionStatus<'a> {
}
}

impl<'a> fmt::Debug for TransactionStatus<'a> {
impl fmt::Debug for TransactionStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TransactionStatus")
.field("sender_id", &self.sender_id)
Expand All @@ -521,9 +533,9 @@ impl<'a> fmt::Debug for TransactionStatus<'a> {
}
}

impl<'a> IntoFuture for TransactionStatus<'a> {
impl IntoFuture for TransactionStatus {
type Output = Result<ExecutionFinalResult>;
type IntoFuture = BoxFuture<'a, Self::Output>;
type IntoFuture = Pin<Box<dyn std::future::Future<Output = Self::Output>>>;

fn into_future(self) -> Self::IntoFuture {
Box::pin(async { self.wait().await })
Expand Down
14 changes: 8 additions & 6 deletions workspaces/src/rpc/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::error::{Error, ErrorKind, RpcErrorCode};
use crate::operations::TransactionStatus;
use crate::result::Result;
use crate::types::{AccountId, InMemorySigner, Nonce, PublicKey};
use crate::{Network, Worker};

pub(crate) const DEFAULT_CALL_FN_GAS: Gas = 10_000_000_000_000;
pub(crate) const DEFAULT_CALL_DEPOSIT: Balance = 0;
Expand Down Expand Up @@ -464,18 +465,19 @@ pub(crate) async fn send_batch_tx_and_retry(
.await
}

pub(crate) async fn send_batch_tx_async_and_retry<'a>(
client: &'a Client,
pub(crate) async fn send_batch_tx_async_and_retry(
worker: Worker<dyn Network>,
signer: &InMemorySigner,
receiver_id: &AccountId,
actions: Vec<Action>,
) -> Result<TransactionStatus<'a>> {
) -> Result<TransactionStatus> {
let signer = signer.inner();
let cache_key = (signer.account_id.clone(), signer.public_key());

retry(|| async {
let (block_hash, nonce) = fetch_tx_nonce(client, &cache_key).await?;
let hash = client
let (block_hash, nonce) = fetch_tx_nonce(worker.client(), &cache_key).await?;
let hash = worker
.client()
.query(&methods::broadcast_tx_async::RpcBroadcastTxAsyncRequest {
signed_transaction: SignedTransaction::from_actions(
nonce,
Expand All @@ -490,7 +492,7 @@ pub(crate) async fn send_batch_tx_async_and_retry<'a>(
.map_err(|e| RpcErrorCode::BroadcastTxFailure.custom(e))?;

Ok(TransactionStatus::new(
client,
worker.clone(),
signer.account_id.clone(),
hash,
))
Expand Down
8 changes: 4 additions & 4 deletions workspaces/src/types/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ impl Account {
/// a [`CallTransaction`] object that we will make use to populate the
/// rest of the call details. Note that the current [`Account`]'s secret
/// key is used as the signer of the transaction.
pub fn call(&self, contract_id: &AccountId, function: &str) -> CallTransaction<'_> {
pub fn call(&self, contract_id: &AccountId, function: &str) -> CallTransaction {
CallTransaction::new(
self.worker.client(),
self.worker.clone(),
contract_id.to_owned(),
self.signer.clone(),
function,
Expand Down Expand Up @@ -172,7 +172,7 @@ impl Account {
/// network.
pub fn batch(&self, contract_id: &AccountId) -> Transaction {
Transaction::new(
self.worker.client(),
self.worker.clone(),
self.signer().clone(),
contract_id.clone(),
)
Expand Down Expand Up @@ -270,7 +270,7 @@ impl Contract {
///
/// If we want to make use of the contract's secret key as a signer to call
/// into another contract, use `contract.as_account().call` instead.
pub fn call(&self, function: &str) -> CallTransaction<'_> {
pub fn call(&self, function: &str) -> CallTransaction {
self.account.call(self.id(), function)
}

Expand Down
43 changes: 24 additions & 19 deletions workspaces/src/worker/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,6 @@ where
self.workspace.client()
}

/// Call into a contract's change function. Returns a [`CallTransaction`] object
/// that we will make use to populate the rest of the call details. The [`signer`]
/// will be used to sign the transaction.
///
/// [`signer`]: crate::types::InMemorySigner
pub fn call(
&self,
signer: &InMemorySigner,
contract_id: &AccountId,
function: &str,
) -> CallTransaction<'_> {
CallTransaction::new(
self.client(),
contract_id.to_owned(),
signer.clone(),
function,
)
}

/// Call into a contract's view function. Returns a [`Query`] which allows us
/// to specify further details like the arguments of the view call, or at what
/// point in the chain we want to view.
Expand Down Expand Up @@ -192,6 +173,30 @@ where
}
}

impl<T> Worker<T>
where
T: Network + 'static,
{
/// Call into a contract's change function. Returns a [`CallTransaction`] object
/// that we will make use to populate the rest of the call details. The [`signer`]
/// will be used to sign the transaction.
///
/// [`signer`]: crate::types::InMemorySigner
pub fn call(
&self,
signer: &InMemorySigner,
contract_id: &AccountId,
function: &str,
) -> CallTransaction {
CallTransaction::new(
self.clone().coerce(),
contract_id.to_owned(),
signer.clone(),
function,
)
}
}

impl Worker<Sandbox> {
pub fn root_account(&self) -> Result<Account> {
let signer = self.workspace.root_signer()?;
Expand Down

0 comments on commit 17e402a

Please sign in to comment.