1use 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}
23pub 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 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}
62pub 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}
97pub 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}
130pub 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}
163pub 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}
196pub 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}
229pub 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}
258pub 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}
291pub 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}
324pub 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#[derive(Clone)]
357pub struct TxContextReplaceCostParams {
358 pub tx_context_replace_cost_base: InternalGas,
359}
360pub 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 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
426const E_NO_IDS_CREATED: u64 = 1;
429
430pub 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}