Skip to content

Commit

Permalink
Add dev-inspect-txn to RPC and SDK (#7008)
Browse files Browse the repository at this point in the history
Same as #6998 but
- fixed typescript types
- Relax RPC restriction for calling non-entry functions

Co-authored-by: Ge Gao <106119108+gegaowp@users.noreply.github.com>
  • Loading branch information
666lcz and gegaowp committed Dec 23, 2022
1 parent 96effe9 commit 7d0f25b
Show file tree
Hide file tree
Showing 30 changed files with 700 additions and 73 deletions.
5 changes: 5 additions & 0 deletions .changeset/smooth-ads-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@mysten/sui.js": minor
---

Add devInspectTransaction, which is similar to dryRunTransaction, but lets you call any Move function(including non-entry function) with arbitrary values.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions crates/sui-json-rpc-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1969,6 +1969,7 @@ pub struct DevInspectResults {
}

#[derive(Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "SuiExecutionResult", rename_all = "camelCase")]
pub struct SuiExecutionResult {
/// The value of any arguments that were mutably borrowed.
/// Non-mut borrowed values are not included
Expand Down Expand Up @@ -2017,6 +2018,15 @@ impl DevInspectResults {
}
}

#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub enum SuiTransactionBuilderMode {
/// Regular Sui Transactions that are committed on chain
Commit,
/// Simulated transaction that allows calling any Move function with
/// arbitrary values.
DevInspect,
}

#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "ExecutionStatus", rename_all = "camelCase", tag = "status")]
pub enum SuiExecutionStatus {
Expand Down
1 change: 1 addition & 0 deletions crates/sui-json-rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ bcs = "0.1.4"

tap = "1.0"

sui-adapter = { path = "../sui-adapter" }
sui-core = { path = "../sui-core" }
sui-types = { path = "../sui-types" }
sui-json = { path = "../sui-json" }
Expand Down
17 changes: 14 additions & 3 deletions crates/sui-json-rpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use sui_types::sui_system_state::SuiSystemState;
use fastcrypto::encoding::Base64;
use sui_json::SuiJsonValue;
use sui_json_rpc_types::{
Balance, CoinPage, DynamicFieldPage, EventPage, GetObjectDataResponse,
Balance, CoinPage, DevInspectResults, DynamicFieldPage, EventPage, GetObjectDataResponse,
GetPastObjectDataResponse, GetRawObjectDataResponse, MoveFunctionArgType,
RPCTransactionRequestParams, SuiCoinMetadata, SuiEventEnvelope, SuiEventFilter,
SuiExecuteTransactionResponse, SuiMoveNormalizedFunction, SuiMoveNormalizedModule,
SuiMoveNormalizedStruct, SuiObjectInfo, SuiTransactionAuthSignersResponse,
SuiTransactionEffects, SuiTransactionFilter, SuiTransactionResponse, SuiTypeTag,
TransactionBytes, TransactionsPage,
SuiTransactionBuilderMode, SuiTransactionEffects, SuiTransactionFilter, SuiTransactionResponse,
SuiTypeTag, TransactionBytes, TransactionsPage,
};
use sui_open_rpc_macros::open_rpc;
use sui_types::balance::Supply;
Expand Down Expand Up @@ -182,6 +182,13 @@ pub trait RpcReadApi {
#[open_rpc(namespace = "sui", tag = "Full Node API")]
#[rpc(server, client, namespace = "sui")]
pub trait RpcFullNodeReadApi {
/// Return dev-inpsect results of the transaction, including both the transaction
/// effects and return values of the transaction.
#[method(name = "devInspectTransaction")]
async fn dev_inspect_transaction(&self, tx_bytes: Base64) -> RpcResult<DevInspectResults>;

/// Return transaction execution effects including the gas cost summary,
/// while the effects are not committed to the chain.
#[method(name = "dryRunTransaction")]
async fn dry_run_transaction(&self, tx_bytes: Base64) -> RpcResult<SuiTransactionEffects>;

Expand Down Expand Up @@ -389,6 +396,8 @@ pub trait RpcTransactionBuilder {
gas: Option<ObjectID>,
/// the gas budget, the transaction will fail if the gas cost exceed the budget
gas_budget: u64,
/// Whether this is a Normal transaction or a Dev Inspect Transaction. Default to be `SuiTransactionBuilderMode::Commit` when it's None.
execution_mode: Option<SuiTransactionBuilderMode>,
) -> RpcResult<TransactionBytes>;

/// Create an unsigned transaction to publish Move module.
Expand Down Expand Up @@ -465,6 +474,8 @@ pub trait RpcTransactionBuilder {
gas: Option<ObjectID>,
/// the gas budget, the transaction will fail if the gas cost exceed the budget
gas_budget: u64,
/// Whether this is a regular transaction or a Dev Inspect Transaction
txn_builder_mode: Option<SuiTransactionBuilderMode>,
) -> RpcResult<TransactionBytes>;
}

Expand Down
40 changes: 31 additions & 9 deletions crates/sui-json-rpc/src/read_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ use move_binary_format::normalized::{Module as NormalizedModule, Type};
use move_core_types::identifier::Identifier;
use std::collections::BTreeMap;
use std::sync::Arc;
use sui_types::intent::{Intent, IntentMessage};
use sui_types::intent::{AppId, Intent, IntentMessage, IntentScope, IntentVersion};
use sui_types::sui_system_state::SuiSystemState;
use tap::TapFallible;

use fastcrypto::encoding::Base64;
use jsonrpsee::RpcModule;
use sui_core::authority::AuthorityState;
use sui_json_rpc_types::{
DynamicFieldPage, GetObjectDataResponse, GetPastObjectDataResponse, MoveFunctionArgType,
ObjectValueKind, Page, SuiMoveNormalizedFunction, SuiMoveNormalizedModule,
DevInspectResults, DynamicFieldPage, GetObjectDataResponse, GetPastObjectDataResponse,
MoveFunctionArgType, ObjectValueKind, Page, SuiMoveNormalizedFunction, SuiMoveNormalizedModule,
SuiMoveNormalizedStruct, SuiObjectInfo, SuiTransactionAuthSignersResponse,
SuiTransactionEffects, SuiTransactionResponse, TransactionsPage,
};
Expand All @@ -26,7 +26,7 @@ use sui_types::base_types::SequenceNumber;
use sui_types::base_types::{ObjectID, SuiAddress, TransactionDigest, TxSequenceNumber};
use sui_types::committee::EpochId;
use sui_types::crypto::sha3_hash;
use sui_types::messages::{CommitteeInfoRequest, CommitteeInfoResponse};
use sui_types::messages::{CommitteeInfoRequest, CommitteeInfoResponse, TransactionData};
use sui_types::move_package::normalize_modules;
use sui_types::object::{Data, ObjectRead};
use sui_types::query::TransactionQuery;
Expand Down Expand Up @@ -219,14 +219,19 @@ impl SuiRpcModule for ReadApi {

#[async_trait]
impl RpcFullNodeReadApiServer for FullNodeApi {
async fn dev_inspect_transaction(&self, tx_bytes: Base64) -> RpcResult<DevInspectResults> {
let (txn_data, txn_digest) = get_transaction_data_and_digest(tx_bytes)?;
Ok(self
.state
.dev_inspect_transaction(txn_data, txn_digest)
.await?)
}

async fn dry_run_transaction(&self, tx_bytes: Base64) -> RpcResult<SuiTransactionEffects> {
let tx_data =
bcs::from_bytes(&tx_bytes.to_vec().map_err(|e| anyhow!(e))?).map_err(|e| anyhow!(e))?;
let intent_msg = IntentMessage::new(Intent::default(), tx_data);
let txn_digest = TransactionDigest::new(sha3_hash(&intent_msg.value));
let (txn_data, txn_digest) = get_transaction_data_and_digest(tx_bytes)?;
Ok(self
.state
.dry_exec_transaction(intent_msg.value, txn_digest)
.dry_exec_transaction(txn_data, txn_digest)
.await?)
}

Expand Down Expand Up @@ -428,3 +433,20 @@ pub async fn get_move_modules_by_package(
_ => Err(anyhow!("Package object does not exist with ID {}", package)),
}?)
}

pub fn get_transaction_data_and_digest(
tx_bytes: Base64,
) -> RpcResult<(TransactionData, TransactionDigest)> {
let tx_data =
bcs::from_bytes(&tx_bytes.to_vec().map_err(|e| anyhow!(e))?).map_err(|e| anyhow!(e))?;
let intent_msg = IntentMessage::new(
Intent {
version: IntentVersion::V0,
scope: IntentScope::TransactionData,
app_id: AppId::Sui,
},
tx_data,
);
let txn_digest = TransactionDigest::new(sha3_hash(&intent_msg.value));
Ok((intent_msg.value, txn_digest))
}
76 changes: 57 additions & 19 deletions crates/sui-json-rpc/src/transaction_builder_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ use crate::SuiRpcModule;
use async_trait::async_trait;
use jsonrpsee::core::RpcResult;
use std::sync::Arc;
use sui_adapter::execution_mode;
use sui_core::authority::AuthorityState;
use sui_json_rpc_types::{GetRawObjectDataResponse, SuiObjectInfo, SuiTypeTag, TransactionBytes};
use sui_json_rpc_types::{
GetRawObjectDataResponse, SuiObjectInfo, SuiTransactionBuilderMode, SuiTypeTag,
TransactionBytes,
};
use sui_open_rpc::Module;
use sui_transaction_builder::{DataReader, TransactionBuilder};
use sui_types::base_types::{ObjectID, SuiAddress};
use sui_types::{
base_types::{ObjectID, SuiAddress},
messages::TransactionData,
};

use fastcrypto::encoding::Base64;
use jsonrpsee::RpcModule;
Expand Down Expand Up @@ -213,20 +220,39 @@ impl RpcTransactionBuilderServer for FullNodeTransactionBuilderApi {
rpc_arguments: Vec<SuiJsonValue>,
gas: Option<ObjectID>,
gas_budget: u64,
txn_builder_mode: Option<SuiTransactionBuilderMode>,
) -> RpcResult<TransactionBytes> {
let data = self
.builder
.move_call(
signer,
package_object_id,
&module,
&function,
type_arguments,
rpc_arguments,
gas,
gas_budget,
)
.await?;
let mode = txn_builder_mode.unwrap_or(SuiTransactionBuilderMode::Commit);
let data: TransactionData = match mode {
SuiTransactionBuilderMode::DevInspect => {
self.builder
.move_call::<execution_mode::DevInspect>(
signer,
package_object_id,
&module,
&function,
type_arguments,
rpc_arguments,
gas,
gas_budget,
)
.await?
}
SuiTransactionBuilderMode::Commit => {
self.builder
.move_call::<execution_mode::Normal>(
signer,
package_object_id,
&module,
&function,
type_arguments,
rpc_arguments,
gas,
gas_budget,
)
.await?
}
};
Ok(TransactionBytes::from_data(data)?)
}

Expand All @@ -236,11 +262,23 @@ impl RpcTransactionBuilderServer for FullNodeTransactionBuilderApi {
params: Vec<RPCTransactionRequestParams>,
gas: Option<ObjectID>,
gas_budget: u64,
txn_builder_mode: Option<SuiTransactionBuilderMode>,
) -> RpcResult<TransactionBytes> {
let data = self
.builder
.batch_transaction(signer, params, gas, gas_budget)
.await?;
let mode = txn_builder_mode.unwrap_or(SuiTransactionBuilderMode::Commit);
let data = match mode {
SuiTransactionBuilderMode::DevInspect => {
self.builder
.batch_transaction::<execution_mode::DevInspect>(
signer, params, gas, gas_budget,
)
.await?
}
SuiTransactionBuilderMode::Commit => {
self.builder
.batch_transaction::<execution_mode::Normal>(signer, params, gas, gas_budget)
.await?
}
};
Ok(TransactionBytes::from_data(data)?)
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/sui-json-rpc/src/unit_tests/rpc_server_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ async fn test_move_call() -> Result<(), anyhow::Error> {
json_args,
Some(gas.object_id),
10_000,
None,
)
.await?;

Expand Down Expand Up @@ -395,6 +396,7 @@ async fn test_get_total_supply() -> Result<(), anyhow::Error> {
],
Some(gas.object_id),
10_000,
None,
)
.await?;

Expand Down
3 changes: 2 additions & 1 deletion crates/sui-json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ pub fn resolve_move_function_args(
function: Identifier,
type_args: &[TypeTag],
combined_args_json: Vec<SuiJsonValue>,
allow_arbitrary_function_call: bool,
) -> Result<Vec<SuiJsonCallArg>, anyhow::Error> {
// Extract the expected function signature
let module = package.deserialize_module(&module_ident)?;
Expand All @@ -642,7 +643,7 @@ pub fn resolve_move_function_args(
let function_signature = module.function_handle_at(fdef.function);
let parameters = &module.signature_at(function_signature.parameters).0;

if !fdef.is_entry {
if !allow_arbitrary_function_call && !fdef.is_entry {
bail!(
"{}::{} is not an entry function",
module.self_id(),
Expand Down
Loading

3 comments on commit 7d0f25b

@vercel
Copy link

@vercel vercel bot commented on 7d0f25b Dec 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

wallet-adapter – ./sdk/wallet-adapter/example

sui-wallet-adapter.vercel.app
wallet-adapter-git-main-mysten-labs.vercel.app
wallet-adapter-mysten-labs.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 7d0f25b Dec 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Owned Transactions Benchmark Results

Benchmark Report:
+-------------+-----+--------+-----+-----+-----+-----+-----+-----+-------+-----+
| duration(s) | tps | error% | min | p25 | p50 | p75 | p90 | p99 | p99.9 | max |
+==============================================================================+
| 60          | 100 | 0      | 18  | 61  | 65  | 71  | 105 | 114 | 116   | 117 |

Shared Transactions Benchmark Results

Benchmark Report:
+-------------+-----+--------+-----+-----+-----+-----+-----+-----+-------+------+
| duration(s) | tps | error% | min | p25 | p50 | p75 | p90 | p99 | p99.9 | max  |
+===============================================================================+
| 60          | 99  | 0      | 21  | 396 | 465 | 547 | 638 | 911 | 1103  | 1154 |

Narwhal Benchmark Results

 SUMMARY:
-----------------------------------------
 + CONFIG:
 Faults: 0 node(s)
 Committee size: 4 node(s)
 Worker(s) per node: 1 worker(s)
 Collocate primary and workers: True
 Input rate: 50,000 tx/s
 Transaction size: 512 B
 Execution time: 57 s

 Header number of batches threshold: 32 digests
 Header maximum number of batches: 1,000 digests
 Max header delay: 2,000 ms
 GC depth: 50 round(s)
 Sync retry delay: 10,000 ms
 Sync retry nodes: 3 node(s)
 batch size: 500,000 B
 Max batch delay: 200 ms
 Max concurrent requests: 500,000 

 + RESULTS:
 Batch creation avg latency: 77 ms
 Header creation avg latency: 1,817 ms
 	Batch to header avg latency: 1,021 ms
 Header to certificate avg latency: 6 ms
 	Request vote outbound avg latency: 2 ms
 Certificate commit avg latency: 3,300 ms

 Consensus TPS: 49,713 tx/s
 Consensus BPS: 25,453,157 B/s
 Consensus latency: 3,398 ms

 End-to-end TPS: 48,002 tx/s
 End-to-end BPS: 24,577,003 B/s
 End-to-end latency: 4,381 ms
-----------------------------------------

Please sign in to comment.