Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dev-inspect-txn to RPC and SDK #7008

Merged
merged 1 commit into from
Dec 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -181,6 +181,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 @@ -388,6 +395,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 @@ -464,6 +473,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 @@ -27,7 +27,7 @@ use sui_types::base_types::{ObjectID, SuiAddress, TransactionDigest};
use sui_types::batch::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 @@ -220,14 +220,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 @@ -429,3 +434,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