near_workspaces/worker/
impls.rs

1use near_primitives::views::StatusResponse;
2
3use crate::network::{Info, RootAccountSubaccountCreator, Sandbox, Testnet};
4use crate::network::{NetworkClient, NetworkInfo};
5use crate::operations::{CallTransaction, Function};
6use crate::result::{ExecutionFinalResult, Result};
7use crate::rpc::client::Client;
8use crate::rpc::patch::{ImportContractTransaction, PatchTransaction};
9use crate::rpc::query::{
10    GasPrice, Query, QueryChunk, ViewAccessKey, ViewAccessKeyList, ViewAccount, ViewBlock,
11    ViewCode, ViewFunction, ViewState,
12};
13use crate::types::{AccountId, InMemorySigner, NearToken, PublicKey};
14use crate::worker::Worker;
15use crate::{Account, Network};
16
17#[cfg(feature = "experimental")]
18use {
19    near_chain_configs::{GenesisConfig, ProtocolConfigView},
20    near_jsonrpc_client::methods::tx::RpcTransactionResponse,
21    near_jsonrpc_primitives::types::{
22        changes::{RpcStateChangesInBlockByTypeResponse, RpcStateChangesInBlockResponse},
23        receipts::ReceiptReference,
24        transactions::TransactionInfo,
25    },
26    near_primitives::{
27        types::{BlockReference, MaybeBlockId},
28        views::{
29            validator_stake_view::ValidatorStakeView, ReceiptView, StateChangesRequestView,
30            TxExecutionStatus,
31        },
32    },
33};
34
35impl<T: ?Sized> Clone for Worker<T> {
36    fn clone(&self) -> Self {
37        Self {
38            workspace: self.workspace.clone(),
39            tx_callbacks: self.tx_callbacks.clone(),
40        }
41    }
42}
43
44impl<T> NetworkInfo for Worker<T>
45where
46    T: NetworkInfo,
47{
48    fn info(&self) -> &Info {
49        self.workspace.info()
50    }
51}
52
53impl<T> Worker<T>
54where
55    T: NetworkClient + ?Sized,
56{
57    pub(crate) fn client(&self) -> &Client {
58        self.workspace.client()
59    }
60
61    /// Call into a contract's view function. Returns a [`Query`] which allows us
62    /// to specify further details like the arguments of the view call, or at what
63    /// point in the chain we want to view.
64    pub fn view(&self, contract_id: &AccountId, function: &str) -> Query<'_, ViewFunction> {
65        self.view_by_function(contract_id, Function::new(function))
66    }
67
68    pub(crate) fn view_by_function(
69        &self,
70        contract_id: &AccountId,
71        function: Function,
72    ) -> Query<'_, ViewFunction> {
73        Query::new(
74            self.client(),
75            ViewFunction {
76                account_id: contract_id.clone(),
77                function,
78            },
79        )
80    }
81
82    /// View the WASM code bytes of a contract on the network.
83    pub fn view_code(&self, contract_id: &AccountId) -> Query<'_, ViewCode> {
84        Query::new(
85            self.client(),
86            ViewCode {
87                account_id: contract_id.clone(),
88            },
89        )
90    }
91
92    /// View the state of a account/contract on the network. This will return the internal
93    /// state of the account in the form of a map of key-value pairs; where STATE contains
94    /// info on a contract's internal data.
95    pub fn view_state(&self, contract_id: &AccountId) -> Query<'_, ViewState> {
96        Query::view_state(self.client(), contract_id)
97    }
98
99    /// View the block from the network. Supply additional parameters such as [`block_height`]
100    /// or [`block_hash`] to get the block.
101    ///
102    /// [`block_height`]: Query::block_height
103    /// [`block_hash`]: Query::block_hash
104    pub fn view_block(&self) -> Query<'_, ViewBlock> {
105        Query::new(self.client(), ViewBlock)
106    }
107
108    /// View the chunk from the network once awaited. Supply additional parameters such as
109    /// [`block_hash_and_shard`], [`block_height_and_shard`] or [`chunk_hash`] to get the
110    /// chunk at a specific reference point. If none of those are supplied, the default
111    /// reference point will be used, which will be the latest block_hash with a shard_id
112    /// of 0.
113    ///
114    /// [`block_hash_and_shard`]: QueryChunk::block_hash_and_shard
115    /// [`block_height_and_shard`]: QueryChunk::block_height_and_shard
116    /// [`chunk_hash`]: QueryChunk::chunk_hash
117    pub fn view_chunk(&self) -> QueryChunk<'_> {
118        QueryChunk::new(self.client())
119    }
120
121    /// Views the [`AccessKey`] of the account specified by [`AccountId`] associated with
122    /// the [`PublicKey`]
123    ///
124    /// [`AccessKey`]: crate::types::AccessKey
125    pub fn view_access_key(&self, id: &AccountId, pk: &PublicKey) -> Query<'_, ViewAccessKey> {
126        Query::new(
127            self.client(),
128            ViewAccessKey {
129                account_id: id.clone(),
130                public_key: pk.clone(),
131            },
132        )
133    }
134
135    /// Views all the [`AccessKey`]s of the account specified by [`AccountId`]. This will
136    /// return a list of [`AccessKey`]s along with the associated [`PublicKey`].
137    ///
138    /// [`AccessKey`]: crate::types::AccessKey
139    pub fn view_access_keys(&self, id: &AccountId) -> Query<'_, ViewAccessKeyList> {
140        Query::new(
141            self.client(),
142            ViewAccessKeyList {
143                account_id: id.clone(),
144            },
145        )
146    }
147
148    /// View account details of a specific account on the network.
149    pub fn view_account(&self, account_id: &AccountId) -> Query<'_, ViewAccount> {
150        Query::new(
151            self.client(),
152            ViewAccount {
153                account_id: account_id.clone(),
154            },
155        )
156    }
157
158    pub fn gas_price(&self) -> Query<'_, GasPrice> {
159        Query::new(self.client(), GasPrice)
160    }
161}
162
163impl<T> Worker<T>
164where
165    T: NetworkClient + Send + Sync + ?Sized,
166{
167    /// Transfer tokens from one account to another. The signer is the account
168    /// that will be used to send from.
169    pub async fn transfer_near(
170        &self,
171        signer: &InMemorySigner,
172        receiver_id: &AccountId,
173        amount_yocto: NearToken,
174    ) -> Result<ExecutionFinalResult> {
175        self.client()
176            .transfer_near(signer, receiver_id, amount_yocto)
177            .await
178            .map(ExecutionFinalResult::from_view)
179    }
180
181    /// Deletes an account from the network. The beneficiary will receive the balance
182    /// of the account deleted.
183    pub async fn delete_account(
184        &self,
185        account_id: &AccountId,
186        signer: &InMemorySigner,
187        beneficiary_id: &AccountId,
188    ) -> Result<ExecutionFinalResult> {
189        self.client()
190            .delete_account(signer, account_id, beneficiary_id)
191            .await
192            .map(ExecutionFinalResult::from_view)
193    }
194
195    /// Returns the status of the network.
196    pub async fn status(&self) -> Result<StatusResponse> {
197        self.client().status().await
198    }
199}
200
201#[cfg(feature = "experimental")]
202impl<T> Worker<T>
203where
204    T: NetworkClient + Send + Sync + ?Sized,
205{
206    /// Provides a list of changes in block associated with the given block reference.
207    pub async fn changes_in_block(
208        &self,
209        block_reference: BlockReference,
210    ) -> Result<RpcStateChangesInBlockByTypeResponse> {
211        self.client().changes_in_block(block_reference).await
212    }
213
214    /// Provides a list of changes in block associated with the given block reference and state changes request.
215    pub async fn changes(
216        &self,
217        block_reference: BlockReference,
218        state_changes_request: StateChangesRequestView,
219    ) -> Result<RpcStateChangesInBlockResponse> {
220        self.client()
221            .changes(block_reference, state_changes_request)
222            .await
223    }
224
225    /// Provides a genesis config associated with the network being used.
226    pub async fn genesis_config(&self) -> Result<GenesisConfig> {
227        self.client().genesis_config().await
228    }
229
230    /// Provides a protocol config associated with the given block reference.
231    pub async fn protocol_config(
232        &self,
233        block_reference: BlockReference,
234    ) -> Result<ProtocolConfigView> {
235        self.client().protocol_config(block_reference).await
236    }
237
238    /// Provides a receipt associated with the given receipt reference.
239    pub async fn receipt(&self, receipt_reference: ReceiptReference) -> Result<ReceiptView> {
240        self.client().receipt(receipt_reference).await
241    }
242
243    /// Returns the transaction status for a given transaction hash or signed transaction.
244    pub async fn tx_status(
245        &self,
246        transaction_info: TransactionInfo,
247        wait_until: TxExecutionStatus,
248    ) -> Result<RpcTransactionResponse> {
249        self.client().tx_status(transaction_info, wait_until).await
250    }
251
252    /// Provides a list of validators ordered with respect to their stake.
253    pub async fn validators_ordered(
254        &self,
255        block_id: MaybeBlockId,
256    ) -> Result<Vec<ValidatorStakeView>> {
257        self.client().validators_ordered(block_id).await
258    }
259}
260
261impl<T> Worker<T>
262where
263    T: Network + 'static,
264{
265    /// Call into a contract's change function. Returns a [`CallTransaction`] object
266    /// that we will make use to populate the rest of the call details. The [`signer`]
267    /// will be used to sign the transaction.
268    ///
269    /// [`signer`]: crate::types::InMemorySigner
270    pub fn call(
271        &self,
272        signer: &InMemorySigner,
273        contract_id: &AccountId,
274        function: &str,
275    ) -> CallTransaction {
276        CallTransaction::new(
277            self.clone().coerce(),
278            contract_id.to_owned(),
279            signer.clone(),
280            function,
281        )
282    }
283}
284
285impl Worker<Testnet> {
286    /// it's just `"testnet"`
287    pub fn root_account_id(&self) -> AccountId {
288        self.workspace
289            .root_account_id()
290            .expect("no source of error expected for testnet")
291    }
292}
293
294impl Worker<Sandbox> {
295    /// Returns root account of this `Sandbox` instance
296    ///
297    /// # Examples
298    /// ```
299    /// use near_workspaces::{result::Result, Account, network::Sandbox, Worker};
300    /// fn get_account_with_lots_of_near(worker: &Worker<Sandbox>) -> Result<Account> {
301    ///     worker.root_account()
302    /// }
303    /// ```
304    ///
305    pub fn root_account(&self) -> Result<Account> {
306        let signer = self.workspace.root_signer()?;
307        Ok(Account::new(signer, self.clone().coerce()))
308    }
309
310    /// Import a contract from the given network, and return us a [`ImportContractTransaction`]
311    /// which allows to specify further details, such as being able to import contract data and
312    /// how far back in time we wanna grab the contract.
313    pub fn import_contract<'a>(
314        &self,
315        id: &'a AccountId,
316        worker: &Worker<impl Network + 'static>,
317    ) -> ImportContractTransaction<'a> {
318        ImportContractTransaction::new(id, worker.clone().coerce(), self.clone())
319    }
320
321    /// Start patching the state of the account specified by the [`AccountId`]. This will create
322    /// a [`PatchTransaction`] that will allow us to patch access keys, code, and contract state.
323    /// This is similar to functions like [`Account::batch`] where we can perform multiple actions
324    /// in one transaction.
325    pub fn patch(&self, account_id: &AccountId) -> PatchTransaction {
326        PatchTransaction::new(self, account_id.clone())
327    }
328
329    /// Patch state into the sandbox network, given a prefix key and value. This will allow us
330    /// to set contract state that we have acquired in some manner, where we are able to test
331    /// random cases that are hard to come up naturally as state evolves.
332    pub async fn patch_state(
333        &self,
334        contract_id: &AccountId,
335        key: &[u8],
336        value: &[u8],
337    ) -> Result<()> {
338        self.workspace.patch_state(contract_id, key, value).await
339    }
340
341    /// Fast forward to a point in the future. The delta block height is supplied to tell the
342    /// network to advanced a certain amount of blocks. This comes with the advantage only having
343    /// to wait a fraction of the time it takes to produce the same number of blocks.
344    ///
345    /// Estimate as to how long it takes: if our delta_height crosses `X` epochs, then it would
346    /// roughly take `X * 5` seconds for the fast forward request to be processed.
347    ///
348    /// Note: This is not to be confused with speeding up the current in-flight transactions;
349    /// the state being forwarded in this case refers to time-related state (the block height, timestamp and epoch).
350    pub async fn fast_forward(&self, delta_height: u64) -> Result<()> {
351        self.workspace.fast_forward(delta_height).await
352    }
353
354    /// The port being used by RPC
355    pub fn rpc_port(&self) -> Option<u16> {
356        self.workspace.server.rpc_port()
357    }
358
359    /// Get the address the client is using to connect to the RPC of the network.
360    pub fn rpc_addr(&self) -> String {
361        self.workspace.server.rpc_addr()
362    }
363}