sui_core/
test_utils.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use fastcrypto::traits::KeyPair;
5use move_core_types::{account_address::AccountAddress, ident_str};
6use shared_crypto::intent::{Intent, IntentScope};
7use std::sync::Arc;
8use std::time::Duration;
9use sui_config::genesis::Genesis;
10use sui_macros::nondeterministic;
11use sui_types::base_types::{FullObjectRef, ObjectID, random_object_ref};
12use sui_types::crypto::AuthorityKeyPair;
13use sui_types::crypto::{AccountKeyPair, AuthorityPublicKeyBytes, Signer};
14use sui_types::effects::TestEffectsBuilder;
15use sui_types::signature_verification::VerifiedDigestCache;
16use sui_types::transaction::ObjectArg;
17use sui_types::transaction::{
18    CallArg, SignedTransaction, TEST_ONLY_GAS_UNIT_FOR_TRANSFER, Transaction, TransactionData,
19};
20use sui_types::utils::create_fake_transaction;
21use sui_types::utils::to_sender_signed_transaction;
22use sui_types::{
23    base_types::{AuthorityName, ExecutionDigests, ObjectRef, SuiAddress, TransactionDigest},
24    committee::Committee,
25    crypto::{AuthoritySignInfo, AuthoritySignature},
26    message_envelope::Message,
27    transaction::CertifiedTransaction,
28};
29use tokio::time::timeout;
30use tracing::{info, warn};
31
32use crate::authority::AuthorityState;
33
34// note: clippy is confused about this being dead - it appears to only be used in cfg(test), but
35// adding #[cfg(test)] causes other targets to fail
36#[allow(dead_code)]
37pub(crate) fn init_state_parameters_from_rng<R>(rng: &mut R) -> (Genesis, AuthorityKeyPair)
38where
39    R: rand::CryptoRng + rand::RngCore,
40{
41    let dir = nondeterministic!(tempfile::TempDir::new().unwrap());
42    let network_config = sui_swarm_config::network_config_builder::ConfigBuilder::new(&dir)
43        .rng(rng)
44        .build();
45    let genesis = network_config.genesis;
46    let authority_key = network_config.validator_configs[0]
47        .protocol_key_pair()
48        .copy();
49
50    (genesis, authority_key)
51}
52
53pub async fn wait_for_tx(digest: TransactionDigest, state: Arc<AuthorityState>, delay: Duration) {
54    match timeout(
55        delay,
56        state
57            .get_transaction_cache_reader()
58            .notify_read_executed_effects("", &[digest]),
59    )
60    .await
61    {
62        Ok(_) => info!(?digest, "digest found"),
63        Err(e) => {
64            warn!(?digest, "digest not found!");
65            panic!("timed out waiting for effects of digest! {e}");
66        }
67    }
68}
69
70pub fn create_fake_cert_and_effect_digest<'a>(
71    signers: impl Iterator<
72        Item = (
73            &'a AuthorityName,
74            &'a (dyn Signer<AuthoritySignature> + Send + Sync),
75        ),
76    >,
77    committee: &Committee,
78) -> (ExecutionDigests, CertifiedTransaction) {
79    let transaction = create_fake_transaction();
80    let cert = CertifiedTransaction::new(
81        transaction.data().clone(),
82        signers
83            .map(|(name, signer)| {
84                AuthoritySignInfo::new(
85                    committee.epoch,
86                    transaction.data(),
87                    Intent::sui_app(IntentScope::SenderSignedTransaction),
88                    *name,
89                    signer,
90                )
91            })
92            .collect(),
93        committee,
94    )
95    .unwrap();
96    let effects = TestEffectsBuilder::new(transaction.data()).build();
97    (
98        ExecutionDigests::new(*transaction.digest(), effects.digest()),
99        cert,
100    )
101}
102
103pub fn make_transfer_sui_transaction(
104    gas_object: ObjectRef,
105    recipient: SuiAddress,
106    amount: Option<u64>,
107    sender: SuiAddress,
108    keypair: &AccountKeyPair,
109    gas_price: u64,
110) -> Transaction {
111    let data = TransactionData::new_transfer_sui(
112        recipient,
113        sender,
114        amount,
115        gas_object,
116        gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER,
117        gas_price,
118    );
119    to_sender_signed_transaction(data, keypair)
120}
121
122pub fn make_pay_sui_transaction(
123    gas_object: ObjectRef,
124    coins: Vec<ObjectRef>,
125    recipients: Vec<SuiAddress>,
126    amounts: Vec<u64>,
127    sender: SuiAddress,
128    keypair: &AccountKeyPair,
129    gas_price: u64,
130    gas_budget: u64,
131) -> Transaction {
132    let data = TransactionData::new_pay_sui(
133        sender, coins, recipients, amounts, gas_object, gas_budget, gas_price,
134    )
135    .unwrap();
136    to_sender_signed_transaction(data, keypair)
137}
138
139pub fn make_transfer_object_transaction(
140    object_ref: ObjectRef,
141    gas_object: ObjectRef,
142    sender: SuiAddress,
143    keypair: &AccountKeyPair,
144    recipient: SuiAddress,
145    gas_price: u64,
146) -> Transaction {
147    let data = TransactionData::new_transfer(
148        recipient,
149        FullObjectRef::from_fastpath_ref(object_ref),
150        sender,
151        gas_object,
152        gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10,
153        gas_price,
154    );
155    to_sender_signed_transaction(data, keypair)
156}
157
158pub fn make_transfer_object_move_transaction(
159    src: SuiAddress,
160    keypair: &AccountKeyPair,
161    dest: SuiAddress,
162    object_ref: ObjectRef,
163    framework_obj_id: ObjectID,
164    gas_object_ref: ObjectRef,
165    gas_budget_in_units: u64,
166    gas_price: u64,
167) -> Transaction {
168    let args = vec![
169        CallArg::Object(ObjectArg::ImmOrOwnedObject(object_ref)),
170        CallArg::Pure(bcs::to_bytes(&AccountAddress::from(dest)).unwrap()),
171    ];
172
173    to_sender_signed_transaction(
174        TransactionData::new_move_call(
175            src,
176            framework_obj_id,
177            ident_str!("object_basics").to_owned(),
178            ident_str!("transfer").to_owned(),
179            Vec::new(),
180            gas_object_ref,
181            args,
182            gas_budget_in_units * gas_price,
183            gas_price,
184        )
185        .unwrap(),
186        keypair,
187    )
188}
189
190/// Make a dummy tx that uses random object refs.
191pub fn make_dummy_tx(
192    receiver: SuiAddress,
193    sender: SuiAddress,
194    sender_sec: &AccountKeyPair,
195) -> Transaction {
196    Transaction::from_data_and_signer(
197        TransactionData::new_transfer(
198            receiver,
199            FullObjectRef::from_fastpath_ref(random_object_ref()),
200            sender,
201            random_object_ref(),
202            TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10,
203            10,
204        ),
205        vec![sender_sec],
206    )
207}
208
209/// Make a cert using an arbitrarily large committee.
210pub fn make_cert_with_large_committee(
211    committee: &Committee,
212    key_pairs: &[AuthorityKeyPair],
213    transaction: &Transaction,
214) -> CertifiedTransaction {
215    // assumes equal weighting.
216    let len = committee.voting_rights.len();
217    assert_eq!(len, key_pairs.len());
218    let count = (len * 2).div_ceil(3);
219
220    let sigs: Vec<_> = key_pairs
221        .iter()
222        .take(count)
223        .map(|key_pair| {
224            SignedTransaction::new(
225                committee.epoch(),
226                transaction.clone().into_data(),
227                key_pair,
228                AuthorityPublicKeyBytes::from(key_pair.public()),
229            )
230            .auth_sig()
231            .clone()
232        })
233        .collect();
234
235    let cert = CertifiedTransaction::new(transaction.clone().into_data(), sigs, committee).unwrap();
236    cert.verify_signatures_authenticated(
237        committee,
238        &Default::default(),
239        Arc::new(VerifiedDigestCache::new_empty()),
240    )
241    .unwrap();
242    cert
243}