sui_adapter_latest/static_programmable_transactions/execution/
values.rs1use crate::static_programmable_transactions::{env::Env, typing::ast::Type};
5use move_binary_format::errors::PartialVMError;
6use move_core_types::{account_address::AccountAddress, runtime_value::MoveTypeLayout, u256::U256};
7use move_vm_types::{
8 values::{
9 self, Locals as VMLocals, Struct, VMValueCast, Value as VMValue, VectorSpecialization,
10 },
11 views::ValueView,
12};
13use sui_types::{
14 base_types::{ObjectID, SequenceNumber},
15 digests::TransactionDigest,
16 error::ExecutionError,
17 move_package::{UpgradeCap, UpgradeReceipt, UpgradeTicket},
18};
19pub enum InputValue<'a> {
20 Bytes(&'a ByteValue),
21 Loaded(Local<'a>),
22}
23
24pub enum ByteValue {
25 Pure(Vec<u8>),
26 Receiving {
27 id: ObjectID,
28 version: SequenceNumber,
29 },
30}
31
32pub struct Local<'a>(&'a mut Locals, u16);
34
35pub struct Locals(VMLocals);
37
38#[derive(Debug)]
39pub struct Value(VMValue);
40
41impl Locals {
42 pub fn new<Items>(values: Items) -> Result<Self, ExecutionError>
43 where
44 Items: IntoIterator<Item = Option<Value>>,
45 Items::IntoIter: ExactSizeIterator,
46 {
47 let values = values.into_iter();
48 let n = values.len();
49 assert_invariant!(n <= u16::MAX as usize, "Locals size exceeds u16::MAX");
50 let mut locals = VMLocals::new(n);
51 for (i, value_opt) in values.enumerate() {
52 let Some(value) = value_opt else {
53 continue;
55 };
56 locals
57 .store_loc(i, value.0, true)
58 .map_err(iv("store loc"))?;
59 }
60 Ok(Self(locals))
61 }
62
63 pub fn new_invalid(n: usize) -> Result<Self, ExecutionError> {
64 assert_invariant!(n <= u16::MAX as usize, "Locals size exceeds u16::MAX");
65 Ok(Self(VMLocals::new(n)))
66 }
67
68 pub fn local(&mut self, index: u16) -> Result<Local<'_>, ExecutionError> {
69 Ok(Local(self, index))
70 }
71}
72
73impl Local<'_> {
74 pub fn is_invalid(&self) -> Result<bool, ExecutionError> {
76 self.0
77 .0
78 .is_invalid(self.1 as usize)
79 .map_err(iv("out of bounds"))
80 }
81
82 pub fn store(&mut self, value: Value) -> Result<(), ExecutionError> {
83 self.0
84 .0
85 .store_loc(self.1 as usize, value.0, true)
86 .map_err(iv("store loc"))
87 }
88
89 pub fn move_(&mut self) -> Result<Value, ExecutionError> {
91 assert_invariant!(!self.is_invalid()?, "cannot move invalid local");
92 Ok(Value(
93 self.0
94 .0
95 .move_loc(self.1 as usize, true)
96 .map_err(iv("move loc"))?,
97 ))
98 }
99
100 pub fn copy(&self) -> Result<Value, ExecutionError> {
102 assert_invariant!(!self.is_invalid()?, "cannot copy invalid local");
103 Ok(Value(
104 self.0.0.copy_loc(self.1 as usize).map_err(iv("copy loc"))?,
105 ))
106 }
107
108 pub fn borrow(&self) -> Result<Value, ExecutionError> {
110 assert_invariant!(!self.is_invalid()?, "cannot borrow invalid local");
111 Ok(Value(
112 self.0
113 .0
114 .borrow_loc(self.1 as usize)
115 .map_err(iv("borrow loc"))?,
116 ))
117 }
118
119 pub fn move_if_valid(&mut self) -> Result<Option<Value>, ExecutionError> {
120 if self.is_invalid()? {
121 Ok(None)
122 } else {
123 Ok(Some(self.move_()?))
124 }
125 }
126}
127
128impl Value {
129 pub fn copy(&self) -> Result<Self, ExecutionError> {
130 Ok(Value(self.0.copy_value().map_err(iv("copy"))?))
131 }
132
133 pub fn read_ref(self) -> Result<Self, ExecutionError> {
135 let value: values::Reference = self.0.cast().map_err(iv("cast"))?;
136 Ok(Self(value.read_ref().map_err(iv("read ref"))?))
137 }
138
139 pub fn cast<V>(self) -> Result<V, ExecutionError>
141 where
142 VMValue: VMValueCast<V>,
143 {
144 self.0.cast().map_err(iv("cast"))
145 }
146
147 pub fn deserialize(env: &Env, bytes: &[u8], ty: Type) -> Result<Value, ExecutionError> {
148 let layout = env.runtime_layout(&ty)?;
149 let Some(value) = VMValue::simple_deserialize(bytes, &layout) else {
150 invariant_violation!("unable to deserialize value to type {ty:?}")
153 };
154 Ok(Value(value))
155 }
156
157 pub fn typed_serialize(&self, layout: &MoveTypeLayout) -> Option<Vec<u8>> {
158 self.0.typed_serialize(layout)
159 }
160
161 pub(super) fn inner_for_tracing(&self) -> &VMValue {
163 &self.0
164 }
165}
166
167impl From<VMValue> for Value {
168 fn from(value: VMValue) -> Self {
169 Value(value)
170 }
171}
172
173impl From<Value> for VMValue {
174 fn from(value: Value) -> Self {
175 value.0
176 }
177}
178
179impl VMValueCast<Value> for VMValue {
180 fn cast(self) -> Result<Value, PartialVMError> {
181 Ok(self.into())
182 }
183}
184
185impl ValueView for Value {
186 fn visit(
187 &self,
188 visitor: &mut impl move_vm_types::views::ValueVisitor,
189 ) -> move_binary_format::errors::PartialVMResult<()> {
190 self.0.visit(visitor)
191 }
192}
193
194impl Value {
199 pub fn id(address: AccountAddress) -> Self {
200 Self(VMValue::struct_(Struct::pack([VMValue::address(address)])))
202 }
203
204 pub fn uid(address: AccountAddress) -> Self {
205 Self(VMValue::struct_(Struct::pack([Self::id(address).0])))
207 }
208
209 pub fn receiving(id: ObjectID, version: SequenceNumber) -> Self {
210 Self(VMValue::struct_(Struct::pack([
211 Self::id(id.into()).0,
212 VMValue::u64(version.into()),
213 ])))
214 }
215
216 pub fn balance(amount: u64) -> Self {
217 Self(VMValue::struct_(Struct::pack([VMValue::u64(amount)])))
219 }
220
221 pub fn coin(id: ObjectID, amount: u64) -> Self {
223 Self(VMValue::struct_(Struct::pack([
224 Self::uid(id.into()).0,
225 Self::balance(amount).0,
226 ])))
227 }
228
229 pub fn funds_accumulator_withdrawal(owner: AccountAddress, limit: U256) -> Self {
231 Self(VMValue::struct_(Struct::pack([
236 VMValue::address(owner),
237 VMValue::u256(limit),
238 ])))
239 }
240
241 pub fn vec_pack(ty: Type, values: Vec<Self>) -> Result<Self, ExecutionError> {
242 let specialization: VectorSpecialization = ty
243 .try_into()
244 .map_err(|e| make_invariant_violation!("Unable to specialize vector: {e}"))?;
245 let vec = values::Vector::pack(specialization, values.into_iter().map(|v| v.0))
246 .map_err(iv("pack"))?;
247 Ok(Self(vec))
248 }
249
250 pub fn new_tx_context(digest: TransactionDigest) -> Result<Self, ExecutionError> {
253 Ok(Self(VMValue::struct_(Struct::pack([
261 VMValue::address(AccountAddress::ZERO),
262 VMValue::vector_u8(digest.inner().iter().copied()),
263 VMValue::u64(0),
264 VMValue::u64(0),
265 VMValue::u64(0),
266 ]))))
267 }
268
269 pub fn one_time_witness() -> Result<Self, ExecutionError> {
270 Ok(Self(VMValue::struct_(Struct::pack([VMValue::bool(true)]))))
274 }
275}
276
277impl Value {
282 pub fn unpack_coin(self) -> Result<(ObjectID, u64), ExecutionError> {
283 let [id, balance] = unpack(self.0)?;
284 let [id] = unpack(id)?;
286 let [id] = unpack(id)?;
288 let id: AccountAddress = id.cast().map_err(iv("cast"))?;
289 let [balance] = unpack(balance)?;
291 let balance: u64 = balance.cast().map_err(iv("cast"))?;
292 Ok((ObjectID::from(id), balance))
293 }
294
295 pub fn coin_ref_value(self) -> Result<u64, ExecutionError> {
296 let balance_value_ref = borrow_coin_ref_balance_value(self.0)?;
297 let balance_value_ref: values::Reference = balance_value_ref.cast().map_err(iv("cast"))?;
298 let balance_value = balance_value_ref.read_ref().map_err(iv("read ref"))?;
299 balance_value.cast().map_err(iv("cast"))
300 }
301
302 pub fn coin_ref_subtract_balance(self, amount: u64) -> Result<(), ExecutionError> {
305 coin_ref_modify_balance(self.0, |balance| {
306 let Some(new_balance) = balance.checked_sub(amount) else {
307 invariant_violation!("coin balance {balance} is less than {amount}")
308 };
309 Ok(new_balance)
310 })
311 }
312
313 pub fn coin_ref_add_balance(self, amount: u64) -> Result<(), ExecutionError> {
316 coin_ref_modify_balance(self.0, |balance| {
317 let Some(new_balance) = balance.checked_add(amount) else {
318 invariant_violation!("coin balance {balance} + {amount} is greater than u64::MAX")
319 };
320 Ok(new_balance)
321 })
322 }
323}
324
325fn coin_ref_modify_balance(
326 coin_ref: VMValue,
327 modify: impl FnOnce(u64) -> Result<u64, ExecutionError>,
328) -> Result<(), ExecutionError> {
329 let balance_value_ref = borrow_coin_ref_balance_value(coin_ref)?;
330 let reference: values::Reference = balance_value_ref
331 .copy_value()
332 .map_err(iv("copy"))?
333 .cast()
334 .map_err(iv("cast"))?;
335 let balance: u64 = reference
336 .read_ref()
337 .map_err(iv("read ref"))?
338 .cast()
339 .map_err(iv("cast"))?;
340 let new_balance = modify(balance)?;
341 let reference: values::Reference = balance_value_ref.cast().map_err(iv("cast"))?;
342 reference
343 .write_ref(VMValue::u64(new_balance))
344 .map_err(iv("write ref"))
345}
346
347fn borrow_coin_ref_balance_value(coin_ref: VMValue) -> Result<VMValue, ExecutionError> {
348 let coin_ref: values::StructRef = coin_ref.cast().map_err(iv("cast"))?;
349 let balance = coin_ref.borrow_field(1).map_err(iv("borrow field"))?;
350 let balance: values::StructRef = balance.cast().map_err(iv("cast"))?;
351 balance.borrow_field(0).map_err(iv("borrow field"))
352}
353
354impl Value {
359 pub fn upgrade_cap(cap: UpgradeCap) -> Self {
360 let UpgradeCap {
367 id,
368 package,
369 version,
370 policy,
371 } = cap;
372 Self(VMValue::struct_(Struct::pack([
373 Self::uid(id.id.bytes.into()).0,
374 Self::id(package.bytes.into()).0,
375 VMValue::u64(version),
376 VMValue::u8(policy),
377 ])))
378 }
379
380 pub fn upgrade_receipt(receipt: UpgradeReceipt) -> Self {
381 let UpgradeReceipt { cap, package } = receipt;
386 Self(VMValue::struct_(Struct::pack([
387 Self::id(cap.bytes.into()).0,
388 Self::id(package.bytes.into()).0,
389 ])))
390 }
391
392 pub fn into_upgrade_ticket(self) -> Result<UpgradeTicket, ExecutionError> {
393 let [cap, package, policy, digest] = unpack(self.0)?;
401 let [cap] = unpack(cap)?;
403 let cap: AccountAddress = cap.cast().map_err(iv("cast"))?;
404 let [package] = unpack(package)?;
406 let package: AccountAddress = package.cast().map_err(iv("cast"))?;
407 let policy: u8 = policy.cast().map_err(iv("cast"))?;
409 let digest: Vec<u8> = digest.cast().map_err(iv("cast"))?;
411 Ok(UpgradeTicket {
412 cap: sui_types::id::ID::new(cap.into()),
413 package: sui_types::id::ID::new(package.into()),
414 policy,
415 digest,
416 })
417 }
418}
419
420fn unpack<const N: usize>(value: VMValue) -> Result<[VMValue; N], ExecutionError> {
421 let value: values::Struct = value.cast().map_err(iv("cast"))?;
422 let unpacked = value.unpack().map_err(iv("unpack"))?.collect::<Vec<_>>();
423 assert_invariant!(unpacked.len() == N, "Expected {N} fields, got {unpacked:?}");
424 Ok(unpacked.try_into().unwrap())
425}
426
427const fn iv(case: &str) -> impl FnOnce(PartialVMError) -> ExecutionError + use<'_> {
428 move |e| make_invariant_violation!("unexpected {case} failure {e:?}")
429}