unc_workspaces/worker/
impls.rs

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