1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use crate::{
sandbox::utils::{
contains_module, explain_execution_effects, explain_execution_error, get_gas_status,
is_bytecode_file, maybe_commit_effects, on_disk_state_view::OnDiskStateView,
},
NativeFunctionRecord,
};
use anyhow::{anyhow, bail, Result};
use move_binary_format::file_format::CompiledModule;
use move_command_line_common::env::get_bytecode_version_from_env;
use move_core_types::{
account_address::AccountAddress,
errmap::ErrorMapping,
gas_schedule::CostTable,
identifier::IdentStr,
language_storage::TypeTag,
transaction_argument::{convert_txn_args, TransactionArgument},
value::MoveValue,
};
use move_package::compilation::compiled_package::CompiledPackage;
use move_vm_runtime::move_vm::MoveVM;
use std::{fs, path::Path};
pub fn run(
natives: impl IntoIterator<Item = NativeFunctionRecord>,
cost_table: &CostTable,
error_descriptions: &ErrorMapping,
state: &OnDiskStateView,
package: &CompiledPackage,
script_path: &Path,
script_name_opt: &Option<String>,
signers: &[String],
txn_args: &[TransactionArgument],
vm_type_args: Vec<TypeTag>,
gas_budget: Option<u64>,
dry_run: bool,
verbose: bool,
) -> Result<()> {
if !script_path.exists() {
bail!("Script file {:?} does not exist", script_path)
};
let bytecode_version = get_bytecode_version_from_env();
let bytecode = if is_bytecode_file(script_path) {
assert!(
state.is_module_path(script_path) || !contains_module(script_path),
"Attempting to run module {:?} outside of the `storage/` directory.
move run` must be applied to a module inside `storage/`",
script_path
);
fs::read(script_path)?
} else {
let file_contents = std::fs::read_to_string(script_path)?;
let script_opt = package
.scripts()
.find(|unit| unit.unit.source_map().check(&file_contents));
match script_opt {
Some(unit) => unit.unit.serialize(bytecode_version),
None => bail!("Unable to find script in file {:?}", script_path),
}
};
let signer_addresses = signers
.iter()
.map(|s| AccountAddress::from_hex_literal(s))
.collect::<Result<Vec<AccountAddress>, _>>()?;
let vm_args: Vec<Vec<u8>> = convert_txn_args(txn_args);
let vm = MoveVM::new(natives).unwrap();
let mut gas_status = get_gas_status(cost_table, gas_budget)?;
let mut session = vm.new_session(state);
let script_type_parameters = vec![];
let script_parameters = vec![];
let vm_args = signer_addresses
.iter()
.map(|a| {
MoveValue::Signer(*a)
.simple_serialize()
.expect("transaction arguments must serialize")
})
.chain(vm_args)
.collect();
let res = match script_name_opt {
Some(script_name) => {
let module = CompiledModule::deserialize(&bytecode)
.map_err(|e| anyhow!("Error deserializing module: {:?}", e))?;
session.execute_entry_function(
&module.self_id(),
IdentStr::new(script_name)?,
vm_type_args.clone(),
vm_args,
&mut gas_status,
)
}
None => session.execute_script(
bytecode.to_vec(),
vm_type_args.clone(),
vm_args,
&mut gas_status,
),
};
if let Err(err) = res {
explain_execution_error(
error_descriptions,
err,
state,
&script_type_parameters,
&script_parameters,
&vm_type_args,
&signer_addresses,
txn_args,
)
} else {
let (changeset, events) = session.finish().map_err(|e| e.into_vm_status())?;
if verbose {
explain_execution_effects(&changeset, &events, state)?
}
maybe_commit_effects(!dry_run, changeset, events, state)
}
}