Skip to content

Commit

Permalink
feat(rust-sdk): Simulate WaitForLocalExecution (#18996)
Browse files Browse the repository at this point in the history
## Description

If transaction execution requires waiting for local execution, then
simulate it by polling, to account for the fact that fullnodes will soon
start to ignore this parameter.

## Test plan

Run the programmable transaction SDK example:

```
sui-sdk$ cargo run --example programmable_transactions_api
```

Run the tic-tac-toe E2E example:

```
examples/tic-tac-toe/cli$ env $(cat testnet.env) \
  cargo run -- new $(sui client active-address)
                                  |   |
                               ---+---+---
                                  |   |
                               ---+---+---
                                  |   |

 -> X: <ADDRESS>
    O: <ADDRESS>
 GAME: <GAME>

examples/tic-tac-toe/cli$ env $(cat testnet.env) \
  cargo run -- move -r 0 -c 0 $GAME

...
```

---

## Release notes

Check each box that your changes affect. If none of the boxes relate to
your changes, release notes aren't required.

For each box you select, include information after the relevant heading
that describes the impact of your changes that a user might notice and
any actions they must take to implement updates.

- [ ] Protocol: 
- [ ] Nodes (Validators and Full nodes): 
- [ ] Indexer: 
- [ ] JSON-RPC: 
- [ ] GraphQL: 
- [ ] CLI: 
- [X] Rust SDK: Adds support for simulating `WaitForLocalExecution` in
the client, using polling, as the flag will be ignored by fullnodes
shortly.
- [ ] REST API:
  • Loading branch information
amnn authored and suiwombat committed Sep 16, 2024
1 parent f4dc78d commit f6a72dc
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 30 deletions.
4 changes: 4 additions & 0 deletions crates/sui-json-rpc-types/src/sui_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ impl SuiTransactionBlockResponseOptions {
}
}

#[deprecated(
since = "1.33.0",
note = "Balance and object changes no longer require local execution"
)]
pub fn require_local_execution(&self) -> bool {
self.show_balance_changes || self.show_object_changes
}
Expand Down
73 changes: 43 additions & 30 deletions crates/sui-sdk/src/apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use jsonrpsee::core::client::Subscription;
use std::collections::BTreeMap;
use std::future;
use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
use sui_json_rpc_types::DevInspectArgs;
use sui_json_rpc_types::SuiData;
Expand Down Expand Up @@ -39,7 +40,9 @@ use sui_types::sui_serde::BigInt;
use sui_types::sui_system_state::sui_system_state_summary::SuiSystemStateSummary;
use sui_types::transaction::{Transaction, TransactionData, TransactionKind};

const WAIT_FOR_LOCAL_EXECUTION_RETRY_COUNT: u8 = 3;
const WAIT_FOR_LOCAL_EXECUTION_TIMEOUT: Duration = Duration::from_secs(60);
const WAIT_FOR_LOCAL_EXECUTION_DELAY: Duration = Duration::from_millis(200);
const WAIT_FOR_LOCAL_EXECUTION_INTERVAL: Duration = Duration::from_secs(2);

/// The main read API structure with functions for retrieving data about different objects and transactions
#[derive(Debug)]
Expand Down Expand Up @@ -1133,39 +1136,49 @@ impl QuorumDriverApi {
) -> SuiRpcResult<SuiTransactionBlockResponse> {
let (tx_bytes, signatures) = tx.to_tx_bytes_and_signatures();
let request_type = request_type.unwrap_or_else(|| options.default_execution_request_type());
let mut retry_count = 0;

let start = Instant::now();
while retry_count < WAIT_FOR_LOCAL_EXECUTION_RETRY_COUNT {
let response: SuiTransactionBlockResponse = self
.api
.http
.execute_transaction_block(
tx_bytes.clone(),
signatures.clone(),
Some(options.clone()),
Some(request_type.clone()),
)
.await?;
let response = self
.api
.http
.execute_transaction_block(
tx_bytes.clone(),
signatures.clone(),
Some(options.clone()),
Some(request_type.clone()),
)
.await?;

match request_type {
ExecuteTransactionRequestType::WaitForEffectsCert => {
return Ok(response);
}
ExecuteTransactionRequestType::WaitForLocalExecution => {
if let Some(true) = response.confirmed_local_execution {
return Ok(response);
} else {
// If fullnode executed the cert in the network but did not confirm local
// execution, it must have timed out and hence we could retry.
retry_count += 1;
}
if let ExecuteTransactionRequestType::WaitForEffectsCert = request_type {
return Ok(response);
}

// JSON-RPC ignores WaitForLocalExecution, so simulate it by polling for the transaction.
let mut poll_response = tokio::time::timeout(WAIT_FOR_LOCAL_EXECUTION_TIMEOUT, async {
// Apply a short delay to give the full node a chance to catch up.
tokio::time::sleep(WAIT_FOR_LOCAL_EXECUTION_DELAY).await;

let mut interval = tokio::time::interval(WAIT_FOR_LOCAL_EXECUTION_INTERVAL);
loop {
interval.tick().await;

if let Ok(poll_response) = self
.api
.http
.get_transaction_block(*tx.digest(), Some(options.clone()))
.await
{
break poll_response;
}
}
}
Err(Error::FailToConfirmTransactionStatus(
*tx.digest(),
start.elapsed().as_secs(),
))
})
.await
.map_err(|_| {
Error::FailToConfirmTransactionStatus(*tx.digest(), start.elapsed().as_secs())
})?;

poll_response.confirmed_local_execution = Some(true);
Ok(poll_response)
}
}

Expand Down

0 comments on commit f6a72dc

Please sign in to comment.