1use 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}
25pub 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 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}
64pub 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}
99pub 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}
132pub 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}
165pub 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}
198pub 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}
231pub 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}
260pub 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}
293pub 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}
326pub 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#[derive(Clone)]
359pub struct TxContextReplaceCostParams {
360 pub tx_context_replace_cost_base: InternalGas,
361}
362pub 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 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
428const E_NO_IDS_CREATED: u64 = 1;
431
432pub 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}