Skip to content

Commit

Permalink
api: Use serialized signature for execute_transaction endpoint (#7185)
Browse files Browse the repository at this point in the history
## What

Make `sui_executeTransaction` API the same as
`sui_executeTransactionSerializedSig`.

This `sui_executeTransaction` now requires the client to be responsible
to serialize `flag || signature || pubkey` in one field and submit in
the `signature` field. Instead of sending three separate fields
previously (scheme, pubkey, signature).

## Why
This simplifies future use cases for multisig and multi agent execute
transaction.

## How to use

In Rust: 
```
let serialized_sig = crypto::Signature::from_bytes(&[&*flag, &*sig_bytes, &*pub_key].concat()).unwrap();
```

In CLI: See usage of `sui keytool sign`. 

```shell
target/debug/sui keytool sign --address 0xb59ce11ef3ad15b6c247dda9890dce1b781f99df --data $DATA_TO_SIGN

Intent message to sign: AAAAAAP986VtisOQSZxhH9M4A24xOaDppQDue7TlY/36sS2HyepBJa2PjB3RkxSAjb+7Pv1voJYk/RjX9AlYZ5+hAgAAAAAAAAAgghpx3ucYetjUIHnaFCho6iaUXnt4hczdAeLlgIw0GqsBAAAAAAAAAOgDAAAAAAAA
Signer address: 0xb59ce11ef3ad15b6c247dda9890dce1b781f99df
Serialized signature (`flag || sig || pk` in Base64): $SERIALIZED_SIG
```
In Typescript: 
```
      // Serialize signature field as: `flag || sig || pk`
        const serialized_sig = new Uint8Array(
          1 + signature.getLength() + pubkey.toBytes().length
        );
        serialized_sig.set([SIGNATURE_SCHEME_TO_FLAG[signatureScheme]]);
        serialized_sig.set(signature.getData(), 1);
        serialized_sig.set(pubkey.toBytes(), 1 + signature.getLength());
```

Also fixed some ergonomics and bugs of keytool and offline signing docs.
  • Loading branch information
joyqvq committed Jan 10, 2023
1 parent f9ddd9d commit 5cd51dd
Show file tree
Hide file tree
Showing 13 changed files with 190 additions and 440 deletions.
5 changes: 5 additions & 0 deletions .changeset/rare-shoes-sell.md
@@ -0,0 +1,5 @@
---
"@mysten/sui.js": minor
---

Deprecate sui_executeTransaction in favor of sui_executeTransactionSerializedSig
9 changes: 2 additions & 7 deletions crates/sui-json-rpc/src/api.rs
Expand Up @@ -23,7 +23,6 @@ use sui_types::base_types::{
ObjectID, SequenceNumber, SuiAddress, TransactionDigest, TxSequenceNumber,
};
use sui_types::committee::EpochId;
use sui_types::crypto::SignatureScheme;
use sui_types::event::EventID;
use sui_types::governance::DelegatedStake;
use sui_types::messages::CommitteeInfoResponse;
Expand Down Expand Up @@ -667,13 +666,9 @@ pub trait TransactionExecutionApi {
&self,
/// BCS serialized transaction data bytes without its type tag, as base-64 encoded string.
tx_bytes: Base64,
/// Flag of the signature scheme that is used.
sig_scheme: SignatureScheme,
/// Signature committed to the intent message of the transaction data, as base-64 encoded string.
/// `flag || signature || pubkey` bytes, as base-64 encoded string, signature is committed to the intent message of the transaction data, as base-64 encoded string.
signature: Base64,
/// Signer's public key, as base-64 encoded string.
pub_key: Base64,
/// The request type.
/// The request type
request_type: ExecuteTransactionRequestType,
) -> RpcResult<SuiExecuteTransactionResponse>;

Expand Down
16 changes: 3 additions & 13 deletions crates/sui-json-rpc/src/transaction_execution_api.rs
Expand Up @@ -17,7 +17,6 @@ use sui_core::authority_client::NetworkAuthorityClient;
use sui_core::transaction_orchestrator::TransactiondOrchestrator;
use sui_json_rpc_types::SuiExecuteTransactionResponse;
use sui_open_rpc::Module;
use sui_types::crypto::SignatureScheme;
use sui_types::intent::Intent;
use sui_types::messages::{ExecuteTransactionRequest, ExecuteTransactionRequestType};
use sui_types::{crypto, messages::Transaction};
Expand All @@ -43,23 +42,14 @@ impl TransactionExecutionApiServer for FullNodeTransactionExecutionApi {
async fn execute_transaction(
&self,
tx_bytes: Base64,
sig_scheme: SignatureScheme,
signature: Base64,
pub_key: Base64,
request_type: ExecuteTransactionRequestType,
) -> RpcResult<SuiExecuteTransactionResponse> {
let tx_data =
bcs::from_bytes(&tx_bytes.to_vec().map_err(|e| anyhow!(e))?).map_err(|e| anyhow!(e))?;
let flag = vec![sig_scheme.flag()];
let signature = crypto::Signature::from_bytes(
&[
&*flag,
&*signature.to_vec().map_err(|e| anyhow!(e))?,
&pub_key.to_vec().map_err(|e| anyhow!(e))?,
]
.concat(),
)
.map_err(|e| anyhow!(e))?;
let signature = crypto::Signature::from_bytes(&signature.to_vec().map_err(|e| anyhow!(e))?)
.map_err(|e| anyhow!(e))?;

let txn = Transaction::from_data(tx_data, Intent::default(), signature);

let transaction_orchestrator = self.transaction_orchestrator.clone();
Expand Down
36 changes: 15 additions & 21 deletions crates/sui-json-rpc/src/unit_tests/rpc_server_tests.rs
Expand Up @@ -73,7 +73,7 @@ async fn test_public_transfer_object() -> Result<(), anyhow::Error> {
let dryrun_response = http_client.dry_run_transaction(tx_bytes).await?;

let tx_response: SuiExecuteTransactionResponse = http_client
.execute_transaction_serialized_sig(
.execute_transaction(
tx_bytes1,
signature_bytes,
ExecuteTransactionRequestType::WaitForLocalExecution,
Expand Down Expand Up @@ -111,7 +111,7 @@ async fn test_publish() -> Result<(), anyhow::Error> {
let (tx_bytes, signature_bytes) = tx.to_tx_bytes_and_signature();

let tx_response = http_client
.execute_transaction_serialized_sig(
.execute_transaction(
tx_bytes,
signature_bytes,
ExecuteTransactionRequestType::WaitForLocalExecution,
Expand Down Expand Up @@ -162,7 +162,7 @@ async fn test_move_call() -> Result<(), anyhow::Error> {
let (tx_bytes, signature_bytes) = tx.to_tx_bytes_and_signature();

let tx_response = http_client
.execute_transaction_serialized_sig(
.execute_transaction(
tx_bytes,
signature_bytes,
ExecuteTransactionRequestType::WaitForLocalExecution,
Expand Down Expand Up @@ -266,14 +266,12 @@ async fn test_get_metadata() -> Result<(), anyhow::Error> {
let keystore_path = cluster.swarm.dir().join(SUI_KEYSTORE_FILENAME);
let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?);
let tx = to_sender_signed_transaction(transaction_bytes.to_data()?, keystore.get_key(address)?);
let (tx_bytes, sig_scheme, signature_bytes, pub_key) = tx.to_network_data_for_execution();
let (tx_bytes, signature) = tx.to_tx_bytes_and_signature();

let tx_response = http_client
.execute_transaction(
tx_bytes,
sig_scheme,
signature_bytes,
pub_key,
signature,
ExecuteTransactionRequestType::WaitForLocalExecution,
)
.await?;
Expand Down Expand Up @@ -327,14 +325,12 @@ async fn test_get_total_supply() -> Result<(), anyhow::Error> {
let keystore_path = cluster.swarm.dir().join(SUI_KEYSTORE_FILENAME);
let keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?);
let tx = to_sender_signed_transaction(transaction_bytes.to_data()?, keystore.get_key(address)?);
let (tx_bytes, sig_scheme, signature_bytes, pub_key) = tx.to_network_data_for_execution();
let (tx_bytes, signature) = tx.to_tx_bytes_and_signature();

let tx_response = http_client
.execute_transaction(
tx_bytes,
sig_scheme,
signature_bytes,
pub_key,
signature,
ExecuteTransactionRequestType::WaitForLocalExecution,
)
.await?;
Expand Down Expand Up @@ -407,14 +403,12 @@ async fn test_get_total_supply() -> Result<(), anyhow::Error> {
let tx = transaction_bytes.to_data()?;

let tx = to_sender_signed_transaction(tx, keystore.get_key(address)?);
let (tx_bytes, sig_scheme, signature_bytes, pub_key) = tx.to_network_data_for_execution();
let (tx_bytes, signature) = tx.to_tx_bytes_and_signature();

let tx_response = http_client
.execute_transaction(
tx_bytes,
sig_scheme,
signature_bytes,
pub_key,
signature,
ExecuteTransactionRequestType::WaitForLocalExecution,
)
.await?;
Expand Down Expand Up @@ -452,7 +446,7 @@ async fn test_get_transaction() -> Result<(), anyhow::Error> {
let (tx_bytes, signature_bytes) = tx.to_tx_bytes_and_signature();

let response = http_client
.execute_transaction_serialized_sig(
.execute_transaction(
tx_bytes,
signature_bytes,
ExecuteTransactionRequestType::WaitForLocalExecution,
Expand Down Expand Up @@ -784,7 +778,7 @@ async fn test_locked_sui() -> Result<(), anyhow::Error> {
let (tx_bytes, signature_bytes) = tx.to_tx_bytes_and_signature();

http_client
.execute_transaction_serialized_sig(
.execute_transaction(
tx_bytes,
signature_bytes,
ExecuteTransactionRequestType::WaitForLocalExecution,
Expand Down Expand Up @@ -838,7 +832,7 @@ async fn test_delegation() -> Result<(), anyhow::Error> {
let (tx_bytes, signature_bytes) = tx.to_tx_bytes_and_signature();

http_client
.execute_transaction_serialized_sig(
.execute_transaction(
tx_bytes,
signature_bytes,
ExecuteTransactionRequestType::WaitForLocalExecution,
Expand Down Expand Up @@ -897,7 +891,7 @@ async fn test_delegation_multiple_coins() -> Result<(), anyhow::Error> {
let (tx_bytes, signature_bytes) = tx.to_tx_bytes_and_signature();

http_client
.execute_transaction_serialized_sig(
.execute_transaction(
tx_bytes,
signature_bytes,
ExecuteTransactionRequestType::WaitForLocalExecution,
Expand Down Expand Up @@ -964,7 +958,7 @@ async fn test_delegation_with_locked_sui() -> Result<(), anyhow::Error> {
let (tx_bytes, signature_bytes) = tx.to_tx_bytes_and_signature();

http_client
.execute_transaction_serialized_sig(
.execute_transaction(
tx_bytes,
signature_bytes,
ExecuteTransactionRequestType::WaitForLocalExecution,
Expand Down Expand Up @@ -995,7 +989,7 @@ async fn test_delegation_with_locked_sui() -> Result<(), anyhow::Error> {
let (tx_bytes, signature_bytes) = tx.to_tx_bytes_and_signature();

http_client
.execute_transaction_serialized_sig(
.execute_transaction(
tx_bytes,
signature_bytes,
ExecuteTransactionRequestType::WaitForLocalExecution,
Expand Down

2 comments on commit 5cd51dd

@vercel
Copy link

@vercel vercel bot commented on 5cd51dd Jan 10, 2023

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

@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      | 12  | 56  | 58  | 61  | 98  | 102 | 103   | 106 |

Shared Transactions Benchmark Results

Benchmark Report:
+-------------+-----+--------+-----+-----+-----+-----+-----+-----+-------+------+
| duration(s) | tps | error% | min | p25 | p50 | p75 | p90 | p99 | p99.9 | max  |
+===============================================================================+
| 60          | 99  | 0      | 24  | 426 | 503 | 591 | 668 | 914 | 1254  | 1293 |

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: 59 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,721 ms
 	Batch to header avg latency: 943 ms
 Header to certificate avg latency: 7 ms
 	Request vote outbound avg latency: 3 ms
 Certificate commit avg latency: 3,095 ms

 Consensus TPS: 48,620 tx/s
 Consensus BPS: 24,893,436 B/s
 Consensus latency: 3,219 ms

 End-to-end TPS: 47,003 tx/s
 End-to-end BPS: 24,065,602 B/s
 End-to-end latency: 4,202 ms
-----------------------------------------

Please sign in to comment.