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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
use crate::logging::AdapterLogSchema;
use diem_logger::prelude::*;
use move_binary_format::errors::VMError;
use move_core_types::vm_status::{known_locations, StatusCode, VMStatus};
pub const EACCOUNT_FROZEN: u64 = 1000; pub const EBAD_ACCOUNT_AUTHENTICATION_KEY: u64 = 1001; pub const ESEQUENCE_NUMBER_TOO_OLD: u64 = 1002; pub const ESEQUENCE_NUMBER_TOO_NEW: u64 = 1003; pub const EACCOUNT_DOES_NOT_EXIST: u64 = 1004; pub const ECANT_PAY_GAS_DEPOSIT: u64 = 1005; pub const ETRANSACTION_EXPIRED: u64 = 1006; pub const EBAD_CHAIN_ID: u64 = 1007; pub const ESCRIPT_NOT_ALLOWED: u64 = 1008;
pub const EMODULE_NOT_ALLOWED: u64 = 1009;
pub const EINVALID_WRITESET_SENDER: u64 = 1010; pub const ESEQUENCE_NUMBER_TOO_BIG: u64 = 1011;
pub const EBAD_TRANSACTION_FEE_CURRENCY: u64 = 1012;
pub const ESECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH: u64 = 1013;
pub const ESEQ_NONCE_NONCE_INVALID: u64 = 1014;
const INVALID_STATE: u8 = 1;
const INVALID_ARGUMENT: u8 = 7;
const LIMIT_EXCEEDED: u8 = 8;
fn error_split(code: u64) -> (u8, u64) {
let category = code as u8;
let reason = code >> 8;
(category, reason)
}
pub fn convert_prologue_error(
error: VMError,
log_context: &AdapterLogSchema,
) -> Result<(), VMStatus> {
let status = error.into_vm_status();
Err(match status {
VMStatus::Executed => VMStatus::Executed,
VMStatus::MoveAbort(location, code)
if location != known_locations::account_module_abort() =>
{
let (category, reason) = error_split(code);
log_context.alert();
error!(
*log_context,
"[diem_vm] Unexpected prologue Move abort: {:?}::{:?} (Category: {:?} Reason: {:?})",
location, code, category, reason,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
VMStatus::MoveAbort(location, code) => {
let new_major_status = match error_split(code) {
(INVALID_STATE, EACCOUNT_FROZEN) => StatusCode::SENDING_ACCOUNT_FROZEN,
(INVALID_ARGUMENT, EBAD_ACCOUNT_AUTHENTICATION_KEY) => StatusCode::INVALID_AUTH_KEY,
(INVALID_ARGUMENT, ESEQUENCE_NUMBER_TOO_OLD) => StatusCode::SEQUENCE_NUMBER_TOO_OLD,
(INVALID_ARGUMENT, ESEQUENCE_NUMBER_TOO_NEW) => StatusCode::SEQUENCE_NUMBER_TOO_NEW,
(INVALID_ARGUMENT, EACCOUNT_DOES_NOT_EXIST) => {
StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST
}
(INVALID_ARGUMENT, ECANT_PAY_GAS_DEPOSIT) => {
StatusCode::INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE
}
(INVALID_ARGUMENT, ETRANSACTION_EXPIRED) => StatusCode::TRANSACTION_EXPIRED,
(INVALID_ARGUMENT, EBAD_CHAIN_ID) => StatusCode::BAD_CHAIN_ID,
(INVALID_STATE, ESCRIPT_NOT_ALLOWED) => StatusCode::UNKNOWN_SCRIPT,
(INVALID_STATE, EMODULE_NOT_ALLOWED) => StatusCode::INVALID_MODULE_PUBLISHER,
(INVALID_ARGUMENT, EINVALID_WRITESET_SENDER) => StatusCode::REJECTED_WRITE_SET,
(LIMIT_EXCEEDED, ESEQUENCE_NUMBER_TOO_BIG) => StatusCode::SEQUENCE_NUMBER_TOO_BIG,
(INVALID_ARGUMENT, EBAD_TRANSACTION_FEE_CURRENCY) => {
StatusCode::BAD_TRANSACTION_FEE_CURRENCY
}
(INVALID_ARGUMENT, ESECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH) => {
StatusCode::SECONDARY_KEYS_ADDRESSES_COUNT_MISMATCH
}
(INVALID_ARGUMENT, ESEQ_NONCE_NONCE_INVALID) => StatusCode::SEQUENCE_NONCE_INVALID,
(category, reason) => {
log_context.alert();
error!(
*log_context,
"[diem_vm] Unexpected prologue Move abort: {:?}::{:?} (Category: {:?} Reason: {:?})",
location, code, category, reason,
);
return Err(VMStatus::Error(
StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION,
));
}
};
VMStatus::Error(new_major_status)
}
status @ VMStatus::ExecutionFailure { .. } | status @ VMStatus::Error(_) => {
log_context.alert();
error!(
*log_context,
"[diem_vm] Unexpected prologue error: {:?}", status
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
})
}
pub fn convert_epilogue_error(
error: VMError,
log_context: &AdapterLogSchema,
) -> Result<(), VMStatus> {
let status = error.into_vm_status();
Err(match status {
VMStatus::Executed => VMStatus::Executed,
VMStatus::MoveAbort(location, code)
if location != known_locations::account_module_abort() =>
{
let (category, reason) = error_split(code);
log_context.alert();
error!(
*log_context,
"[diem_vm] Unexpected success epilogue Move abort: {:?}::{:?} (Category: {:?} Reason: {:?})",
location, code, category, reason,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
VMStatus::MoveAbort(location, code) => match error_split(code) {
(LIMIT_EXCEEDED, ECANT_PAY_GAS_DEPOSIT) => VMStatus::MoveAbort(location, code),
(category, reason) => {
log_context.alert();
error!(
*log_context,
"[diem_vm] Unexpected success epilogue Move abort: {:?}::{:?} (Category: {:?} Reason: {:?})",
location, code, category, reason,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
},
status => {
log_context.alert();
error!(
*log_context,
"[diem_vm] Unexpected success epilogue error: {:?}", status,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
})
}
pub fn expect_only_successful_execution(
error: VMError,
function_name: &str,
log_context: &AdapterLogSchema,
) -> Result<(), VMStatus> {
let status = error.into_vm_status();
Err(match status {
VMStatus::Executed => VMStatus::Executed,
status => {
log_context.alert();
error!(
*log_context,
"[diem_vm] Unexpected error from known Move function, '{}'. Error: {:?}",
function_name,
status,
);
VMStatus::Error(StatusCode::UNEXPECTED_ERROR_FROM_KNOWN_MOVE_FUNCTION)
}
})
}