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