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