sui_move_natives_latest/
tx_context.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use move_binary_format::errors::PartialVMResult;
5use move_core_types::{account_address::AccountAddress, gas_algebra::InternalGas};
6use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext};
7use move_vm_types::{
8    loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value,
9};
10use smallvec::smallvec;
11use std::collections::VecDeque;
12use sui_types::{base_types::ObjectID, digests::TransactionDigest};
13
14use crate::{
15    NativesCostTable, get_extension, get_extension_mut, object_runtime::ObjectRuntime,
16    transaction_context::TransactionContext,
17};
18
19#[derive(Clone)]
20pub struct TxContextDeriveIdCostParams {
21    pub tx_context_derive_id_cost_base: InternalGas,
22}
23/***************************************************************************************************
24 * native fun derive_id
25 * Implementation of the Move native function `fun derive_id(tx_hash: vector<u8>, ids_created: u64): address`
26 *   gas cost: tx_context_derive_id_cost_base                | we operate on fixed size data structures
27 **************************************************************************************************/
28pub fn derive_id(
29    context: &mut NativeContext,
30    ty_args: Vec<Type>,
31    mut args: VecDeque<Value>,
32) -> PartialVMResult<NativeResult> {
33    debug_assert!(ty_args.is_empty());
34    debug_assert!(args.len() == 2);
35
36    let tx_context_derive_id_cost_params = get_extension!(context, NativesCostTable)?
37        .tx_context_derive_id_cost_params
38        .clone();
39    native_charge_gas_early_exit!(
40        context,
41        tx_context_derive_id_cost_params.tx_context_derive_id_cost_base
42    );
43
44    let ids_created = pop_arg!(args, u64);
45    let tx_hash = pop_arg!(args, Vec<u8>);
46
47    // unwrap safe because all digests in Move are serialized from the Rust `TransactionDigest`
48    let digest = TransactionDigest::try_from(tx_hash.as_slice()).unwrap();
49    let address = AccountAddress::from(ObjectID::derive_id(digest, ids_created));
50    let obj_runtime: &mut ObjectRuntime = get_extension_mut!(context)?;
51    obj_runtime.new_id(address.into())?;
52
53    Ok(NativeResult::ok(
54        context.gas_used(),
55        smallvec![Value::address(address)],
56    ))
57}
58#[derive(Clone)]
59pub struct TxContextFreshIdCostParams {
60    pub tx_context_fresh_id_cost_base: InternalGas,
61}
62/***************************************************************************************************
63 * native fun fresh_id
64 * Implementation of the Move native function `fun fresh_id(): address`
65 **************************************************************************************************/
66pub fn fresh_id(
67    context: &mut NativeContext,
68    ty_args: Vec<Type>,
69    args: VecDeque<Value>,
70) -> PartialVMResult<NativeResult> {
71    debug_assert!(ty_args.is_empty());
72    debug_assert!(args.is_empty());
73
74    let tx_context_fresh_id_cost_params = get_extension!(context, NativesCostTable)?
75        .tx_context_fresh_id_cost_params
76        .clone();
77    native_charge_gas_early_exit!(
78        context,
79        tx_context_fresh_id_cost_params.tx_context_fresh_id_cost_base
80    );
81
82    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
83    let fresh_id = transaction_context.fresh_id();
84    let object_runtime: &mut ObjectRuntime = get_extension_mut!(context)?;
85    object_runtime.new_id(fresh_id)?;
86
87    Ok(NativeResult::ok(
88        context.gas_used(),
89        smallvec![Value::address(fresh_id.into())],
90    ))
91}
92
93#[derive(Clone)]
94pub struct TxContextSenderCostParams {
95    pub tx_context_sender_cost_base: InternalGas,
96}
97/***************************************************************************************************
98 * native fun native_sender
99 * Implementation of the Move native function `fun native_sender(): address`
100 **************************************************************************************************/
101pub fn sender(
102    context: &mut NativeContext,
103    ty_args: Vec<Type>,
104    args: VecDeque<Value>,
105) -> PartialVMResult<NativeResult> {
106    debug_assert!(ty_args.is_empty());
107    debug_assert!(args.is_empty());
108
109    let tx_context_sender_cost_params = get_extension!(context, NativesCostTable)?
110        .tx_context_sender_cost_params
111        .clone();
112    native_charge_gas_early_exit!(
113        context,
114        tx_context_sender_cost_params.tx_context_sender_cost_base
115    );
116
117    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
118    let sender = transaction_context.sender();
119
120    Ok(NativeResult::ok(
121        context.gas_used(),
122        smallvec![Value::address(sender.into())],
123    ))
124}
125
126#[derive(Clone)]
127pub struct TxContextEpochCostParams {
128    pub tx_context_epoch_cost_base: InternalGas,
129}
130/***************************************************************************************************
131 * native fun native_epoch
132 * Implementation of the Move native function `fun native_epoch(): u64`
133 **************************************************************************************************/
134pub fn epoch(
135    context: &mut NativeContext,
136    ty_args: Vec<Type>,
137    args: VecDeque<Value>,
138) -> PartialVMResult<NativeResult> {
139    debug_assert!(ty_args.is_empty());
140    debug_assert!(args.is_empty());
141
142    let tx_context_epoch_cost_params = get_extension!(context, NativesCostTable)?
143        .tx_context_epoch_cost_params
144        .clone();
145    native_charge_gas_early_exit!(
146        context,
147        tx_context_epoch_cost_params.tx_context_epoch_cost_base
148    );
149
150    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
151    let epoch = transaction_context.epoch();
152
153    Ok(NativeResult::ok(
154        context.gas_used(),
155        smallvec![Value::u64(epoch)],
156    ))
157}
158
159#[derive(Clone)]
160pub struct TxContextEpochTimestampMsCostParams {
161    pub tx_context_epoch_timestamp_ms_cost_base: InternalGas,
162}
163/***************************************************************************************************
164 * native fun native_epoch_timestamp_ms
165 * Implementation of the Move native function `fun native_epoch_timestamp_ms(): u64`
166 **************************************************************************************************/
167pub fn epoch_timestamp_ms(
168    context: &mut NativeContext,
169    ty_args: Vec<Type>,
170    args: VecDeque<Value>,
171) -> PartialVMResult<NativeResult> {
172    debug_assert!(ty_args.is_empty());
173    debug_assert!(args.is_empty());
174
175    let tx_context_epoch_timestamp_ms_cost_params = get_extension!(context, NativesCostTable)?
176        .tx_context_epoch_timestamp_ms_cost_params
177        .clone();
178    native_charge_gas_early_exit!(
179        context,
180        tx_context_epoch_timestamp_ms_cost_params.tx_context_epoch_timestamp_ms_cost_base
181    );
182
183    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
184    let timestamp = transaction_context.epoch_timestamp_ms();
185
186    Ok(NativeResult::ok(
187        context.gas_used(),
188        smallvec![Value::u64(timestamp)],
189    ))
190}
191
192#[derive(Clone)]
193pub struct TxContextSponsorCostParams {
194    pub tx_context_sponsor_cost_base: InternalGas,
195}
196/***************************************************************************************************
197 * native fun native_sponsor
198 * Implementation of the Move native function `fun native_sponsor(): Option<address>`
199 **************************************************************************************************/
200pub fn sponsor(
201    context: &mut NativeContext,
202    ty_args: Vec<Type>,
203    args: VecDeque<Value>,
204) -> PartialVMResult<NativeResult> {
205    debug_assert!(ty_args.is_empty());
206    debug_assert!(args.is_empty());
207
208    let tx_context_sponsor_cost_params = get_extension!(context, NativesCostTable)?
209        .tx_context_sponsor_cost_params
210        .clone();
211    native_charge_gas_early_exit!(
212        context,
213        tx_context_sponsor_cost_params.tx_context_sponsor_cost_base
214    );
215
216    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
217    let sponsor = transaction_context
218        .sponsor()
219        .map(|addr| addr.into())
220        .into_iter();
221    let sponsor = Value::vector_address(sponsor);
222    Ok(NativeResult::ok(context.gas_used(), smallvec![sponsor]))
223}
224
225#[derive(Clone)]
226pub struct TxContextRGPCostParams {
227    pub tx_context_rgp_cost_base: InternalGas,
228}
229/***************************************************************************************************
230 * native fun native_rgp
231 * Implementation of the Move native function `fun native_rgp(): u64`
232 **************************************************************************************************/
233pub fn rgp(
234    context: &mut NativeContext,
235    ty_args: Vec<Type>,
236    args: VecDeque<Value>,
237) -> PartialVMResult<NativeResult> {
238    debug_assert!(ty_args.is_empty());
239    debug_assert!(args.is_empty());
240
241    let tx_context_rgp_cost_params = get_extension!(context, NativesCostTable)?
242        .tx_context_rgp_cost_params
243        .clone();
244    native_charge_gas_early_exit!(context, tx_context_rgp_cost_params.tx_context_rgp_cost_base);
245
246    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
247    let rgp = transaction_context.rgp();
248
249    Ok(NativeResult::ok(
250        context.gas_used(),
251        smallvec![Value::u64(rgp)],
252    ))
253}
254#[derive(Clone)]
255pub struct TxContextGasPriceCostParams {
256    pub tx_context_gas_price_cost_base: InternalGas,
257}
258/***************************************************************************************************
259 * native fun native_gas_price
260 * Implementation of the Move native function `fun native_gas_price(): u64`
261 **************************************************************************************************/
262pub fn gas_price(
263    context: &mut NativeContext,
264    ty_args: Vec<Type>,
265    args: VecDeque<Value>,
266) -> PartialVMResult<NativeResult> {
267    debug_assert!(ty_args.is_empty());
268    debug_assert!(args.is_empty());
269
270    let tx_context_gas_price_cost_params = get_extension!(context, NativesCostTable)?
271        .tx_context_gas_price_cost_params
272        .clone();
273    native_charge_gas_early_exit!(
274        context,
275        tx_context_gas_price_cost_params.tx_context_gas_price_cost_base
276    );
277
278    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
279    let gas_price = transaction_context.gas_price();
280
281    Ok(NativeResult::ok(
282        context.gas_used(),
283        smallvec![Value::u64(gas_price)],
284    ))
285}
286
287#[derive(Clone)]
288pub struct TxContextGasBudgetCostParams {
289    pub tx_context_gas_budget_cost_base: InternalGas,
290}
291/***************************************************************************************************
292 * native fun native_gas_budget
293 * Implementation of the Move native function `fun native_gas_budget(): u64`
294 **************************************************************************************************/
295pub fn gas_budget(
296    context: &mut NativeContext,
297    ty_args: Vec<Type>,
298    args: VecDeque<Value>,
299) -> PartialVMResult<NativeResult> {
300    debug_assert!(ty_args.is_empty());
301    debug_assert!(args.is_empty());
302
303    let tx_context_gas_budget_cost_params = get_extension!(context, NativesCostTable)?
304        .tx_context_gas_budget_cost_params
305        .clone();
306    native_charge_gas_early_exit!(
307        context,
308        tx_context_gas_budget_cost_params.tx_context_gas_budget_cost_base
309    );
310
311    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
312    let gas_budget = transaction_context.gas_budget();
313
314    Ok(NativeResult::ok(
315        context.gas_used(),
316        smallvec![Value::u64(gas_budget)],
317    ))
318}
319
320#[derive(Clone)]
321pub struct TxContextIdsCreatedCostParams {
322    pub tx_context_ids_created_cost_base: InternalGas,
323}
324/***************************************************************************************************
325 * native fun native_ids_created
326 * Implementation of the Move native function `fun native_ids_created(): u64`
327 **************************************************************************************************/
328pub fn ids_created(
329    context: &mut NativeContext,
330    ty_args: Vec<Type>,
331    args: VecDeque<Value>,
332) -> PartialVMResult<NativeResult> {
333    debug_assert!(ty_args.is_empty());
334    debug_assert!(args.is_empty());
335
336    let tx_context_ids_created_cost_params = get_extension!(context, NativesCostTable)?
337        .tx_context_ids_created_cost_params
338        .clone();
339    native_charge_gas_early_exit!(
340        context,
341        tx_context_ids_created_cost_params.tx_context_ids_created_cost_base
342    );
343
344    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
345    let ids_created = transaction_context.ids_created();
346
347    Ok(NativeResult::ok(
348        context.gas_used(),
349        smallvec![Value::u64(ids_created)],
350    ))
351}
352
353// //
354// // Test only function
355// //
356#[derive(Clone)]
357pub struct TxContextReplaceCostParams {
358    pub tx_context_replace_cost_base: InternalGas,
359}
360/***************************************************************************************************
361 * native fun replace
362 * Implementation of the Move native function
363 * ```
364 * native fun replace(
365 *     sender: address,
366 *     tx_hash: vector<u8>,
367 *     epoch: u64,
368 *     epoch_timestamp_ms: u64,
369 *     ids_created: u64,
370 *     rgp: u64,
371 *     gas_price: u64,
372 *     gas_budget: u64,
373 *     sponsor: vector<address>,
374 * )
375 * ```
376 * Used by all testing functions that have to change a value in the `TransactionContext`.
377 **************************************************************************************************/
378pub fn replace(
379    context: &mut NativeContext,
380    ty_args: Vec<Type>,
381    mut args: VecDeque<Value>,
382) -> PartialVMResult<NativeResult> {
383    debug_assert!(ty_args.is_empty());
384    let args_len = args.len();
385    debug_assert!(args_len == 8 || args_len == 9);
386
387    // use the `TxContextReplaceCostParams` for the cost of this function
388    let tx_context_replace_cost_params: TxContextReplaceCostParams =
389        get_extension!(context, NativesCostTable)?
390            .tx_context_replace_cost_params
391            .clone();
392    native_charge_gas_early_exit!(
393        context,
394        tx_context_replace_cost_params.tx_context_replace_cost_base
395    );
396
397    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
398    let mut sponsor: Vec<AccountAddress> = pop_arg!(args, Vec<AccountAddress>);
399    let gas_budget: u64 = pop_arg!(args, u64);
400    let gas_price: u64 = pop_arg!(args, u64);
401    let rgp: u64 = if args_len == 9 {
402        pop_arg!(args, u64)
403    } else {
404        transaction_context.rgp()
405    };
406    let ids_created: u64 = pop_arg!(args, u64);
407    let epoch_timestamp_ms: u64 = pop_arg!(args, u64);
408    let epoch: u64 = pop_arg!(args, u64);
409    let tx_hash: Vec<u8> = pop_arg!(args, Vec<u8>);
410    let sender: AccountAddress = pop_arg!(args, AccountAddress);
411    transaction_context.replace(
412        sender,
413        tx_hash,
414        epoch,
415        epoch_timestamp_ms,
416        ids_created,
417        rgp,
418        gas_price,
419        gas_budget,
420        sponsor.pop(),
421    )?;
422
423    Ok(NativeResult::ok(context.gas_used(), smallvec![]))
424}
425
426// Attempt to get the most recent created object ID when none has been created.
427// Lifted out of Move into this native function.
428const E_NO_IDS_CREATED: u64 = 1;
429
430// use same protocol config and cost value as derive_id
431/***************************************************************************************************
432 * native fun last_created_id
433 * Implementation of the Move native function `fun last_created_id(): address`
434 **************************************************************************************************/
435pub fn last_created_id(
436    context: &mut NativeContext,
437    ty_args: Vec<Type>,
438    args: VecDeque<Value>,
439) -> PartialVMResult<NativeResult> {
440    debug_assert!(ty_args.is_empty());
441    debug_assert!(args.is_empty());
442
443    let tx_context_derive_id_cost_params = get_extension!(context, NativesCostTable)?
444        .tx_context_derive_id_cost_params
445        .clone();
446    native_charge_gas_early_exit!(
447        context,
448        tx_context_derive_id_cost_params.tx_context_derive_id_cost_base
449    );
450
451    let transaction_context: &mut TransactionContext = get_extension_mut!(context)?;
452    let mut ids_created = transaction_context.ids_created();
453    if ids_created == 0 {
454        return Ok(NativeResult::err(context.gas_used(), E_NO_IDS_CREATED));
455    }
456    ids_created -= 1;
457    let digest = transaction_context.digest();
458    let address = AccountAddress::from(ObjectID::derive_id(digest, ids_created));
459    let obj_runtime: &mut ObjectRuntime = get_extension_mut!(context)?;
460    obj_runtime.new_id(address.into())?;
461
462    Ok(NativeResult::ok(
463        context.gas_used(),
464        smallvec![Value::address(address)],
465    ))
466}