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

crypto: intent signing for TransactionData #6445

Merged
merged 4 commits into from
Dec 9, 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/rich-dragons-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@mysten/sui.js": minor
---

Use intent signing if sui version > 0.18
1 change: 1 addition & 0 deletions Cargo.lock

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

Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,14 @@ export const deserializeTxn = createAsyncThunk<
const signer = api.getSignerInstance(keypairVault.getKeypair());
const localSerializer = new LocalTxnDataSerializer(signer.provider);
const txnBytes = new Base64DataBuffer(serializedTxn);
const version = await api.instance.fullNode.getRpcApiVersion();

//TODO: Error handling - either show the error or use the serialized txn
const useIntentSigning =
version != null && version.major >= 0 && version.minor > 18;
const deserializeTx =
(await localSerializer.deserializeTransactionBytesToSignableTransaction(
useIntentSigning,
txnBytes
)) as UnserializedSignableTransaction;

Expand Down
3 changes: 2 additions & 1 deletion crates/sui-cluster-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use test_utils::messages::make_transactions_with_wallet_context;

use sui_sdk::SuiClient;
use sui_types::gas_coin::GasCoin;
use sui_types::intent::Intent;
use sui_types::{
base_types::SuiAddress,
messages::{Transaction, TransactionData, VerifiedTransaction},
Expand Down Expand Up @@ -133,7 +134,7 @@ impl TestContext {
.get_fullnode_client()
.quorum_driver()
.execute_transaction(
Transaction::from_data(txn_data, signature)
Transaction::from_data(txn_data, Intent::default(), signature)
.verify()
.unwrap(),
Some(ExecuteTransactionRequestType::WaitForLocalExecution),
Expand Down
3 changes: 2 additions & 1 deletion crates/sui-cluster-test/src/wallet_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use sui_keys::keystore::AccountKeystore;
use sui_sdk::SuiClient;
use sui_types::base_types::SuiAddress;
use sui_types::crypto::{KeypairTraits, Signature};
use sui_types::intent::Intent;
use sui_types::messages::TransactionData;
use tracing::{info, info_span, Instrument};

Expand Down Expand Up @@ -58,7 +59,7 @@ impl WalletClient {
self.get_wallet()
.config
.keystore
.sign(&self.address, &txn_data.to_bytes())
.sign_secure(&self.address, txn_data, Intent::default())
.unwrap_or_else(|e| panic!("Failed to sign transaction for {}. {}", desc, e))
}
}
27 changes: 18 additions & 9 deletions crates/sui-core/src/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ impl AuthorityState {

let (_gas_status, input_objects) = transaction_input_checker::check_transaction_input(
&self.database,
&transaction.data().data,
&transaction.data().intent_message.value,
)
.await?;

Expand All @@ -612,7 +612,7 @@ impl AuthorityState {
transaction: VerifiedTransaction,
) -> Result<VerifiedTransactionInfoResponse, SuiError> {
let transaction_digest = *transaction.digest();
debug!(tx_digest=?transaction_digest, "handle_transaction. Tx data: {:?}", transaction.data().data);
debug!(tx_digest=?transaction_digest, "handle_transaction. Tx data: {:?}", &transaction.data().intent_message.value);

// Ensure an idempotent answer. This is checked before the system_tx check so that
// a validator is able to return the signed system tx if it was already signed locally.
Expand Down Expand Up @@ -703,7 +703,7 @@ impl AuthorityState {
?observed_effects_digest,
expected_effects=?effects.data(),
?resp.signed_effects,
input_objects = ?certificate.data().data.input_objects(),
input_objects = ?certificate.data().intent_message.value.input_objects(),
"Locally executed effects do not match canonical effects!");
}
Ok(())
Expand Down Expand Up @@ -743,7 +743,7 @@ impl AuthorityState {
let span = tracing::debug_span!(
"validator_acquire_tx_guard",
?tx_digest,
tx_kind = certificate.data().data.kind_as_str()
tx_kind = certificate.data().intent_message.value.kind_as_str()
);
let epoch_store = self.epoch_store();
let tx_guard = epoch_store
Expand Down Expand Up @@ -1004,7 +1004,7 @@ impl AuthorityState {
.observe(shared_object_count as f64);
self.metrics
.batch_size
.observe(certificate.data().data.kind.batch_size() as f64);
.observe(certificate.data().intent_message.value.kind.batch_size() as f64);

Ok(VerifiedTransactionInfoResponse {
signed_transaction: self.database.get_transaction(&digest)?,
Expand Down Expand Up @@ -1037,7 +1037,14 @@ impl AuthorityState {
// At this point we need to check if any shared objects need locks,
// and whether they have them.
let shared_object_refs = input_objects.filter_shared_objects();
if !shared_object_refs.is_empty() && !certificate.data().data.kind.is_change_epoch_tx() {
if !shared_object_refs.is_empty()
&& !certificate
.data()
.intent_message
.value
.kind
.is_change_epoch_tx()
{
// If the transaction contains shared objects, we need to ensure they have been scheduled
// for processing by the consensus protocol.
// There is no need to go through consensus for system transactions that can
Expand All @@ -1060,7 +1067,7 @@ impl AuthorityState {
execution_engine::execute_transaction_to_effects::<execution_mode::Normal, _>(
shared_object_refs,
temporary_store,
certificate.data().data.clone(),
certificate.data().intent_message.value.clone(),
*certificate.digest(),
transaction_dependencies,
&self.move_vm,
Expand Down Expand Up @@ -1137,7 +1144,8 @@ impl AuthorityState {
indexes.index_tx(
cert.sender_address(),
cert.data()
.data
.intent_message
.value
.input_objects()?
.iter()
.map(|o| o.object_id()),
Expand All @@ -1146,7 +1154,8 @@ impl AuthorityState {
.all_mutated()
.map(|(obj_ref, owner, _kind)| (*obj_ref, *owner)),
cert.data()
.data
.intent_message
.value
.move_calls()
.iter()
.map(|mc| (mc.package.0, mc.module.clone(), mc.function.clone())),
Expand Down
3 changes: 2 additions & 1 deletion crates/sui-core/src/authority/authority_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,8 @@ impl EffectsStore for Arc<AuthorityStore> {
fn certificate_input_object_keys(certificate: &VerifiedCertificate) -> SuiResult<Vec<ObjectKey>> {
Ok(certificate
.data()
.data
.intent_message
.value
.input_objects()?
.into_iter()
.filter_map(|object| {
Expand Down
5 changes: 4 additions & 1 deletion crates/sui-core/src/authority_aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,10 @@ where
validity_threshold = validity,
"Broadcasting transaction request to authorities"
);
trace!("Transaction data: {:?}", transaction.data().data);
trace!(
"Transaction data: {:?}",
transaction.data().intent_message.value
);

#[derive(Default)]
struct ProcessTransactionState {
Expand Down
4 changes: 2 additions & 2 deletions crates/sui-core/src/authority_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ impl ValidatorService {
let span = tracing::debug_span!(
"validator_state_process_tx",
?tx_digest,
tx_kind = transaction.data().data.kind_as_str()
tx_kind = transaction.data().intent_message.value.kind_as_str()
);

let info = state
Expand Down Expand Up @@ -435,7 +435,7 @@ impl ValidatorService {
let span = tracing::debug_span!(
"validator_state_process_cert",
?tx_digest,
tx_kind = certificate.data().data.kind_as_str()
tx_kind = certificate.data().intent_message.value.kind_as_str()
);
match state
.handle_certificate(&certificate)
Expand Down
26 changes: 15 additions & 11 deletions crates/sui-core/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ use std::time::Duration;
use sui_types::{
base_types::{dbg_addr, ObjectID, TransactionDigest},
batch::UpdateItem,
crypto::{
get_key_pair, AccountKeyPair, AuthoritySignInfo, AuthoritySignature, Signable, Signature,
},
crypto::{get_key_pair, AccountKeyPair, AuthoritySignInfo, AuthoritySignature, Signature},
intent::{Intent, IntentMessage},
messages::{
BatchInfoRequest, BatchInfoResponseItem, Transaction, TransactionData, VerifiedTransaction,
},
Expand Down Expand Up @@ -147,19 +146,24 @@ pub fn to_sender_signed_transaction(
data: TransactionData,
signer: &dyn Signer<Signature>,
) -> VerifiedTransaction {
let signature = Signature::new(&data, signer);
// let signature = Signature::new_secure(&data, Intent::default(), signer).unwrap();
VerifiedTransaction::new_unchecked(Transaction::from_data(data, signature))
VerifiedTransaction::new_unchecked(Transaction::from_data_and_signer(
data,
Intent::default(),
signer,
))
}

// Workaround for benchmark setup.
pub fn to_sender_signed_transaction_arc(
data: TransactionData,
signer: &Arc<fastcrypto::ed25519::Ed25519KeyPair>,
) -> VerifiedTransaction {
let mut message = Vec::new();
data.write(&mut message);
let signature: Signature = signer.sign(&message);
VerifiedTransaction::new_unchecked(Transaction::from_data(data, signature))
let data1 = data.clone();
let intent_message = IntentMessage::new(Intent::default(), data);
// OK to unwrap because this is used for benchmark only.
let bytes = bcs::to_bytes(&intent_message).unwrap();
let signature: Signature = signer.sign(&bytes);
VerifiedTransaction::new_unchecked(Transaction::from_data(data1, Intent::default(), signature))
}

pub fn dummy_transaction_effects(tx: &Transaction) -> TransactionEffects {
Expand All @@ -180,7 +184,7 @@ pub fn dummy_transaction_effects(tx: &Transaction) -> TransactionEffects {
wrapped: Vec::new(),
gas_object: (
random_object_ref(),
Owner::AddressOwner(tx.data().data.signer()),
Owner::AddressOwner(tx.data().intent_message.value.signer()),
),
events: Vec::new(),
dependencies: Vec::new(),
Expand Down
14 changes: 9 additions & 5 deletions crates/sui-core/src/transaction_input_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,22 @@ pub async fn check_certificate_input(
store: &AuthorityStore,
cert: &VerifiedCertificate,
) -> SuiResult<(SuiGasStatus<'static>, InputObjects)> {
let gas_status = get_gas_status(store, &cert.data().data).await?;
let input_object_kinds = cert.data().data.input_objects()?;
let tx_data = &cert.data().data;
let gas_status = get_gas_status(store, &cert.data().intent_message.value).await?;
let input_object_kinds = cert.data().intent_message.value.input_objects()?;
let tx_data = &cert.data().intent_message.value;
let input_object_data = if tx_data.kind.is_change_epoch_tx() {
// When changing the epoch, we update a the system object, which is shared, without going
// through sequencing, so we must bypass the sequence checks here.
store.check_input_objects(&input_object_kinds)?
} else {
store.check_sequenced_input_objects(cert.digest(), &input_object_kinds)?
};
let input_objects =
check_objects(&cert.data().data, input_object_kinds, input_object_data).await?;
let input_objects = check_objects(
&cert.data().intent_message.value,
input_object_kinds,
input_object_data,
)
.await?;
Ok((gas_status, input_objects))
}

Expand Down
5 changes: 4 additions & 1 deletion crates/sui-core/src/transaction_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ impl TransactionManager {

let missing = self
.authority_store
.get_missing_input_objects(&digest, &cert.data().data.input_objects()?)
.get_missing_input_objects(
&digest,
&cert.data().intent_message.value.input_objects()?,
)
.await
.expect("Are shared object locks set prior to enqueueing certificates?");

Expand Down
5 changes: 4 additions & 1 deletion crates/sui-core/src/unit_tests/authority_aggregator_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,10 @@ where
{
votes.push(signed.auth_sig().clone());
if let Some(inner_transaction) = transaction {
assert!(inner_transaction.data().data == signed.data().data);
assert!(
inner_transaction.data().intent_message.value
== signed.data().intent_message.value
);
}
transaction = Some(signed);
}
Expand Down
12 changes: 9 additions & 3 deletions crates/sui-core/src/unit_tests/authority_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,10 @@ async fn test_dry_run_transaction() {
let transaction_digest = *transaction.digest();

let response = authority
.dry_exec_transaction(transaction.data().data.clone(), transaction_digest)
.dry_exec_transaction(
transaction.data().intent_message.value.clone(),
transaction_digest,
)
.await;
assert!(response.is_ok());

Expand Down Expand Up @@ -253,7 +256,7 @@ async fn test_handle_transfer_transaction_bad_signature() {
bad_signature_transfer_transaction
.data_mut_for_testing()
.tx_signature =
Signature::new_temp(&transfer_transaction.data().data.to_bytes(), &unknown_key);
Signature::new_secure(&transfer_transaction.data().intent_message, &unknown_key);

assert!(client
.handle_transaction(bad_signature_transfer_transaction)
Expand Down Expand Up @@ -483,7 +486,10 @@ async fn test_handle_transfer_transaction_ok() {
panic!("No verified envelope for transaction");
};

assert_eq!(envelope.data().data, transfer_transaction.data().data);
assert_eq!(
envelope.data().intent_message.value,
transfer_transaction.data().intent_message.value
);
}

#[tokio::test]
Expand Down
3 changes: 2 additions & 1 deletion crates/sui-core/src/unit_tests/gas_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ async fn test_publish_gas() -> anyhow::Result<()> {
.as_ref()
.unwrap()
.data()
.data
.intent_message
.value
.kind
.single_transactions()
.next()
Expand Down
14 changes: 5 additions & 9 deletions crates/sui-core/src/unit_tests/pay_sui_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ use super::*;

use crate::authority::authority_tests::{init_state, send_and_confirm_transaction};
use crate::authority::AuthorityState;
use crate::test_utils::to_sender_signed_transaction;
use futures::future::join_all;
use std::collections::HashMap;
use sui_types::crypto::AccountKeyPair;
use sui_types::{
base_types::dbg_addr,
crypto::{get_key_pair, Signature},
crypto::get_key_pair,
error::SuiError,
messages::{Transaction, TransactionInfoResponse, TransactionKind},
messages::{TransactionInfoResponse, TransactionKind},
};

#[tokio::test]
Expand Down Expand Up @@ -448,9 +449,7 @@ async fn execute_pay_sui(
amounts,
}));
let data = TransactionData::new_with_gas_price(kind, sender, gas_object_ref, gas_budget, 1);

let signature = Signature::new(&data, &sender_key);
let tx = Transaction::from_data(data, signature).verify().unwrap();
let tx = to_sender_signed_transaction(data, &sender_key);
let txn_result = send_and_confirm_transaction(&authority_state, tx)
.await
.map(|t| t.into());
Expand Down Expand Up @@ -484,13 +483,10 @@ async fn execute_pay_all_sui(
recipient,
}));
let data = TransactionData::new_with_gas_price(kind, sender, gas_object_ref, gas_budget, 1);
let signature = Signature::new(&data, &sender_key);
let tx = Transaction::from_data(data, signature).verify().unwrap();

let tx = to_sender_signed_transaction(data, &sender_key);
let txn_result = send_and_confirm_transaction(&authority_state, tx)
.await
.map(|t| t.into());

PaySuiTransactionExecutionResult {
authority_state,
txn_result,
Expand Down
Loading