Skip to content

Commit

Permalink
crypto: send serialized signature flag || signature || pubkey (Mysten…
Browse files Browse the repository at this point in the history
  • Loading branch information
joyqvq authored Nov 30, 2022
1 parent 7caff40 commit 81ab833
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 0 deletions.
12 changes: 12 additions & 0 deletions crates/sui-json-rpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ pub trait TransactionExecutionApi {
/// makes sure this node is aware of this transaction when client fires subsequent queries.
/// However if the node fails to execute the transaction locally in a timely manner,
/// a bool type in the response is set to false to indicated the case.
// TODO(joyqvq): remove this and rename executeTransactionSerializedSig to executeTransaction
#[method(name = "executeTransaction")]
async fn execute_transaction(
&self,
Expand All @@ -490,6 +491,17 @@ pub trait TransactionExecutionApi {
/// The request type
request_type: ExecuteTransactionRequestType,
) -> RpcResult<SuiExecuteTransactionResponse>;

#[method(name = "executeTransactionSerializedSig")]
async fn execute_transaction_serialized_sig(
&self,
/// transaction data bytes, as base-64 encoded string
tx_bytes: Base64,
/// `flag || signature || pubkey` bytes, as base-64 encoded string
signature: Base64,
/// The request type
request_type: ExecuteTransactionRequestType,
) -> RpcResult<SuiExecuteTransactionResponse>;
}

#[open_rpc(
Expand Down
32 changes: 32 additions & 0 deletions crates/sui-json-rpc/src/transaction_execution_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,38 @@ impl TransactionExecutionApiServer for FullNodeTransactionExecutionApi {
)
.map_err(jsonrpsee::core::Error::from)
}

async fn execute_transaction_serialized_sig(
&self,
tx_bytes: Base64,
signature: Base64,
request_type: ExecuteTransactionRequestType,
) -> RpcResult<SuiExecuteTransactionResponse> {
let data =
TransactionData::from_signable_bytes(&tx_bytes.to_vec().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::new(SenderSignedData::new(data, signature));
let txn_digest = *txn.digest();

let transaction_orchestrator = self.transaction_orchestrator.clone();
let response = spawn_monitored_task!(transaction_orchestrator.execute_transaction(
ExecuteTransactionRequest {
transaction: txn,
request_type,
}
))
.await
.map_err(|e| anyhow!(e))? // for JoinError
.map_err(|e| anyhow!(e))?; // For Sui transaction execution error (SuiResult<ExecuteTransactionResponse>)

SuiExecuteTransactionResponse::from_execute_transaction_response(
response,
txn_digest,
self.module_cache.as_ref(),
)
.map_err(jsonrpsee::core::Error::from)
}
}

impl SuiRpcModule for FullNodeTransactionExecutionApi {
Expand Down
164 changes: 164 additions & 0 deletions crates/sui-open-rpc/spec/openrpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,170 @@
}
]
},
{
"name": "sui_executeTransactionSerializedSig",
"tags": [
{
"name": "APIs to execute transactions."
}
],
"params": [
{
"name": "tx_bytes",
"description": "transaction data bytes, as base-64 encoded string",
"required": true,
"schema": {
"$ref": "#/components/schemas/Base64"
}
},
{
"name": "signature",
"description": "`flag || signature || pubkey` bytes, as base-64 encoded string",
"required": true,
"schema": {
"$ref": "#/components/schemas/Base64"
}
},
{
"name": "request_type",
"description": "The request type",
"required": true,
"schema": {
"$ref": "#/components/schemas/ExecuteTransactionRequestType"
}
}
],
"result": {
"name": "SuiExecuteTransactionResponse",
"required": true,
"schema": {
"$ref": "#/components/schemas/SuiExecuteTransactionResponse"
}
},
"examples": [
{
"name": "Execute an transaction with serialized signature",
"params": [
{
"name": "tx_bytes",
"value": "VHJhbnNhY3Rpb25EYXRhOjoAAG78RO21zT3+MvS/bD6KxC7vE4XgFAPkmkspatyyLqJ9PJLkziJWrGQCAAAAAAAAACDj8oL6SLPgEDupu+1qBhU7n8SG4QHw6eJwOshmbQauzLUWBLUYN139/dtd9SR4/whdIVoLXLq9w2zxufLshIGibKfYEWlVl5QCAAAAAAAAACACi48C5DAqVZXYiJpnxtMcbJcOVn8D72fYEaT4Q2ZbjQEAAAAAAAAA6AMAAAAAAAA="
},
{
"name": "signature",
"value": "ACKEmGsaz85GBvHaUVX0s1f6Eev26tiIPpRN3qvpUeYGG+h8/svy0+xxFSbsy8pw/rGUl2t74ZRiMwhsKmXApwQETxNsaJH6UBKN/GfiZ46X8iMV/dyLU/zHwVMrBp9VTQ=="
},
{
"name": "request_type",
"value": "WaitForLocalExecution"
}
],
"result": {
"name": "Result",
"value": {
"certificate": {
"transactionDigest": "ewa++QvMPU1gkIJuz9F9r5RMGyAjOGZWB5+jBqkmDfg=",
"data": {
"transactions": [
{
"TransferObject": {
"recipient": "0x6efc44edb5cd3dfe32f4bf6c3e8ac42eef1385e0",
"objectRef": {
"objectId": "0x1403e49a4b296adcb22ea27d3c92e4ce2256ac64",
"version": 2,
"digest": "4/KC+kiz4BA7qbvtagYVO5/EhuEB8OnicDrIZm0Grsw="
}
}
}
],
"sender": "0xb51604b518375dfdfddb5df52478ff085d215a0b",
"gasPayment": {
"objectId": "0x5cbabdc36cf1b9f2ec8481a26ca7d81169559794",
"version": 2,
"digest": "AouPAuQwKlWV2IiaZ8bTHGyXDlZ/A+9n2BGk+ENmW40="
},
"gasBudget": 1000
},
"txSignature": "ACKEmGsaz85GBvHaUVX0s1f6Eev26tiIPpRN3qvpUeYGG+h8/svy0+xxFSbsy8pw/rGUl2t74ZRiMwhsKmXApwQETxNsaJH6UBKN/GfiZ46X8iMV/dyLU/zHwVMrBp9VTQ==",
"authSignInfo": {
"epoch": 0,
"signature": "",
"signers_map": [
58,
48,
0,
0,
0,
0,
0,
0
]
}
},
"effects": {
"status": {
"status": "success"
},
"gasUsed": {
"computationCost": 100,
"storageCost": 100,
"storageRebate": 10
},
"transactionDigest": "Td9+eSajYZcMZaWxLEOAXQ1vVAKnrQ2lvexUnHzeoGs=",
"mutated": [
{
"owner": {
"AddressOwner": "0xb51604b518375dfdfddb5df52478ff085d215a0b"
},
"reference": {
"objectId": "0x5cbabdc36cf1b9f2ec8481a26ca7d81169559794",
"version": 2,
"digest": "AouPAuQwKlWV2IiaZ8bTHGyXDlZ/A+9n2BGk+ENmW40="
}
},
{
"owner": {
"AddressOwner": "0x6efc44edb5cd3dfe32f4bf6c3e8ac42eef1385e0"
},
"reference": {
"objectId": "0x1403e49a4b296adcb22ea27d3c92e4ce2256ac64",
"version": 2,
"digest": "4/KC+kiz4BA7qbvtagYVO5/EhuEB8OnicDrIZm0Grsw="
}
}
],
"gasObject": {
"owner": {
"ObjectOwner": "0xb51604b518375dfdfddb5df52478ff085d215a0b"
},
"reference": {
"objectId": "0x5cbabdc36cf1b9f2ec8481a26ca7d81169559794",
"version": 2,
"digest": "AouPAuQwKlWV2IiaZ8bTHGyXDlZ/A+9n2BGk+ENmW40="
}
},
"events": [
{
"transferObject": {
"packageId": "0x0000000000000000000000000000000000000002",
"transactionModule": "native",
"sender": "0xb51604b518375dfdfddb5df52478ff085d215a0b",
"recipient": {
"AddressOwner": "0x6efc44edb5cd3dfe32f4bf6c3e8ac42eef1385e0"
},
"objectType": "0x2::example::Object",
"objectId": "0x1403e49a4b296adcb22ea27d3c92e4ce2256ac64",
"version": 2
}
}
]
},
"timestamp_ms": null,
"parsed_data": null
}
}
}
]
},
{
"name": "sui_getCoinMetadata",
"tags": [
Expand Down
22 changes: 22 additions & 0 deletions crates/sui-open-rpc/src/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ impl RpcExampleProvider {
self.get_transaction(),
self.get_transactions(),
self.get_events(),
self.execute_transaction_serialized_sig_example(),
]
.into_iter()
.map(|example| (example.function_name, example.examples))
Expand Down Expand Up @@ -189,6 +190,27 @@ impl RpcExampleProvider {
)
}

fn execute_transaction_serialized_sig_example(&mut self) -> Examples {
let (data, signature, _, _, result, _) = self.get_transfer_data_response();
let tx_bytes = TransactionBytes::from_data(data).unwrap();

Examples::new(
"sui_executeTransactionSerializedSig",
vec![ExamplePairing::new(
"Execute an transaction with serialized signature",
vec![
("tx_bytes", json!(tx_bytes.tx_bytes)),
("signature", json!(Base64::from_bytes(signature.as_ref()))),
(
"request_type",
json!(ExecuteTransactionRequestType::WaitForLocalExecution),
),
],
json!(result),
)],
)
}

fn get_object_example(&mut self) -> Examples {
let object_id = ObjectID::new(self.rng.gen());

Expand Down
8 changes: 8 additions & 0 deletions crates/sui-types/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,7 @@ impl Transaction {
Self::from_data(data, signature)
}

// TODO(joyqvq): remove and prefer to_tx_bytes_and_signature()
pub fn to_network_data_for_execution(&self) -> (Base64, SignatureScheme, Base64, Base64) {
(
Base64::from_bytes(&self.data().data.to_bytes()),
Expand All @@ -908,6 +909,13 @@ impl Transaction {
Base64::from_bytes(self.data().tx_signature.public_key_bytes()),
)
}

pub fn to_tx_bytes_and_signature(&self) -> (Base64, Base64) {
(
Base64::from_bytes(&self.data().data.to_bytes()),
Base64::from_bytes(self.data().tx_signature.as_ref()),
)
}
}

impl VerifiedTransaction {
Expand Down
46 changes: 46 additions & 0 deletions crates/sui/tests/full_node_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use sui_keys::keystore::AccountKeystore;
use sui_macros::*;
use sui_node::SuiNode;
use sui_types::base_types::{ObjectRef, SequenceNumber};
use sui_types::crypto::{get_key_pair, SuiKeyPair};
use sui_types::event::BalanceChangeType;
use sui_types::event::Event;
use sui_types::messages::{
Expand Down Expand Up @@ -1042,6 +1043,51 @@ async fn test_validator_node_has_no_transaction_orchestrator() {
.is_err());
}

#[tokio::test]
async fn test_execute_tx_with_serialized_signature() -> Result<(), anyhow::Error> {
let mut test_cluster = init_cluster_builder_env_aware().build().await?;
let context = &mut test_cluster.wallet;
context
.config
.keystore
.add_key(SuiKeyPair::Secp256k1SuiKeyPair(get_key_pair().1))?;
context
.config
.keystore
.add_key(SuiKeyPair::Ed25519SuiKeyPair(get_key_pair().1))?;

let jsonrpc_client = &test_cluster.fullnode_handle.as_ref().unwrap().rpc_client;

let txn_count = 4;
let txns = make_transactions_with_wallet_context(context, txn_count).await;
for txn in txns {
let tx_digest = txn.digest();
let (tx_bytes, signature) = txn.to_tx_bytes_and_signature();
let params = rpc_params![
tx_bytes,
signature,
ExecuteTransactionRequestType::WaitForLocalExecution
];
let response: SuiExecuteTransactionResponse = jsonrpc_client
.request("sui_executeTransactionSerializedSig", params)
.await
.unwrap();

if let SuiExecuteTransactionResponse::EffectsCert {
certificate,
effects: _,
confirmed_local_execution,
} = response
{
assert_eq!(&certificate.transaction_digest, tx_digest);
assert!(confirmed_local_execution);
} else {
panic!("Expect EffectsCert but got {:?}", response);
}
}
Ok(())
}

#[tokio::test]
async fn test_full_node_transaction_orchestrator_rpc_ok() -> Result<(), anyhow::Error> {
let mut test_cluster = init_cluster_builder_env_aware().build().await?;
Expand Down

0 comments on commit 81ab833

Please sign in to comment.