Skip to main content

iota_move_natives_latest/
tx_context.rs

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