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(_) => {
63            info!(?digest, "digest found");
64        }
65        Err(e) => {
66            warn!(?digest, "digest not found!");
67            panic!("timed out waiting for effects of digest! {e}");
68        }
69    }
70}
71
72pub fn create_fake_cert_and_effect_digest<'a>(
73    signers: impl Iterator<
74        Item = (
75            &'a AuthorityName,
76            &'a (dyn Signer<AuthoritySignature> + Send + Sync),
77        ),
78    >,
79    committee: &Committee,
80) -> (ExecutionDigests, CertifiedTransaction) {
81    let transaction = create_fake_transaction();
82    let cert = CertifiedTransaction::new(
83        transaction.data().clone(),
84        signers
85            .map(|(name, signer)| {
86                AuthoritySignInfo::new(
87                    committee.epoch,
88                    transaction.data(),
89                    Intent::sui_app(IntentScope::SenderSignedTransaction),
90                    *name,
91                    signer,
92                )
93            })
94            .collect(),
95        committee,
96    )
97    .unwrap();
98    let effects = TestEffectsBuilder::new(transaction.data()).build();
99    (
100        ExecutionDigests::new(*transaction.digest(), effects.digest()),
101        cert,
102    )
103}
104
105pub fn make_transfer_sui_transaction(
106    gas_object: ObjectRef,
107    recipient: SuiAddress,
108    amount: Option<u64>,
109    sender: SuiAddress,
110    keypair: &AccountKeyPair,
111    gas_price: u64,
112) -> Transaction {
113    let data = TransactionData::new_transfer_sui(
114        recipient,
115        sender,
116        amount,
117        gas_object,
118        gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER,
119        gas_price,
120    );
121    to_sender_signed_transaction(data, keypair)
122}
123
124pub fn make_pay_sui_transaction(
125    gas_object: ObjectRef,
126    coins: Vec<ObjectRef>,
127    recipients: Vec<SuiAddress>,
128    amounts: Vec<u64>,
129    sender: SuiAddress,
130    keypair: &AccountKeyPair,
131    gas_price: u64,
132    gas_budget: u64,
133) -> Transaction {
134    let data = TransactionData::new_pay_sui(
135        sender, coins, recipients, amounts, gas_object, gas_budget, gas_price,
136    )
137    .unwrap();
138    to_sender_signed_transaction(data, keypair)
139}
140
141pub fn make_transfer_object_transaction(
142    object_ref: ObjectRef,
143    gas_object: ObjectRef,
144    sender: SuiAddress,
145    keypair: &AccountKeyPair,
146    recipient: SuiAddress,
147    gas_price: u64,
148) -> Transaction {
149    let data = TransactionData::new_transfer(
150        recipient,
151        FullObjectRef::from_fastpath_ref(object_ref),
152        sender,
153        gas_object,
154        gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10,
155        gas_price,
156    );
157    to_sender_signed_transaction(data, keypair)
158}
159
160pub fn make_transfer_object_move_transaction(
161    src: SuiAddress,
162    keypair: &AccountKeyPair,
163    dest: SuiAddress,
164    object_ref: ObjectRef,
165    framework_obj_id: ObjectID,
166    gas_object_ref: ObjectRef,
167    gas_budget_in_units: u64,
168    gas_price: u64,
169) -> Transaction {
170    let args = vec![
171        CallArg::Object(ObjectArg::ImmOrOwnedObject(object_ref)),
172        CallArg::Pure(bcs::to_bytes(&AccountAddress::from(dest)).unwrap()),
173    ];
174
175    to_sender_signed_transaction(
176        TransactionData::new_move_call(
177            src,
178            framework_obj_id,
179            ident_str!("object_basics").to_owned(),
180            ident_str!("transfer").to_owned(),
181            Vec::new(),
182            gas_object_ref,
183            args,
184            gas_budget_in_units * gas_price,
185            gas_price,
186        )
187        .unwrap(),
188        keypair,
189    )
190}
191
192/// Make a dummy tx that uses random object refs.
193pub fn make_dummy_tx(
194    receiver: SuiAddress,
195    sender: SuiAddress,
196    sender_sec: &AccountKeyPair,
197) -> Transaction {
198    Transaction::from_data_and_signer(
199        TransactionData::new_transfer(
200            receiver,
201            FullObjectRef::from_fastpath_ref(random_object_ref()),
202            sender,
203            random_object_ref(),
204            TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10,
205            10,
206        ),
207        vec![sender_sec],
208    )
209}
210
211/// Make a cert using an arbitrarily large committee.
212pub fn make_cert_with_large_committee(
213    committee: &Committee,
214    key_pairs: &[AuthorityKeyPair],
215    transaction: &Transaction,
216) -> CertifiedTransaction {
217    // assumes equal weighting.
218    let len = committee.voting_rights.len();
219    assert_eq!(len, key_pairs.len());
220    let count = (len * 2).div_ceil(3);
221
222    let sigs: Vec<_> = key_pairs
223        .iter()
224        .take(count)
225        .map(|key_pair| {
226            SignedTransaction::new(
227                committee.epoch(),
228                transaction.clone().into_data(),
229                key_pair,
230                AuthorityPublicKeyBytes::from(key_pair.public()),
231            )
232            .auth_sig()
233            .clone()
234        })
235        .collect();
236
237    let cert = CertifiedTransaction::new(transaction.clone().into_data(), sigs, committee).unwrap();
238    cert.verify_signatures_authenticated(
239        committee,
240        &Default::default(),
241        Arc::new(VerifiedDigestCache::new_empty()),
242    )
243    .unwrap();
244    cert
245}