@mainsail/evm 0.0.1-evm.52 → 0.0.1-evm.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +5922 -0
- package/Cargo.toml +34 -0
- package/bindings/Cargo.toml +33 -0
- package/bindings/build.rs +6 -0
- package/bindings/src/ctx.rs +667 -0
- package/bindings/src/lib.rs +2231 -0
- package/bindings/src/logger.rs +110 -0
- package/bindings/src/result.rs +542 -0
- package/bindings/src/utils.rs +71 -0
- package/core/Cargo.toml +36 -0
- package/core/src/account.rs +112 -0
- package/core/src/bytecode.rs +39 -0
- package/core/src/compression.rs +158 -0
- package/core/src/db.rs +3311 -0
- package/core/src/events.rs +9 -0
- package/core/src/historical.rs +544 -0
- package/core/src/legacy.rs +153 -0
- package/core/src/lib.rs +14 -0
- package/core/src/logger.rs +98 -0
- package/core/src/logs_bloom.rs +96 -0
- package/core/src/precompiles.rs +450 -0
- package/core/src/receipt.rs +153 -0
- package/core/src/state_changes.rs +122 -0
- package/core/src/state_commit.rs +615 -0
- package/core/src/state_root.rs +266 -0
- package/index.d.ts +1 -0
- package/index.js +52 -52
- package/package.json +5 -4
- package/scripts/postinstall.mjs +73 -0
|
@@ -0,0 +1,2231 @@
|
|
|
1
|
+
use std::{sync::Arc, u64};
|
|
2
|
+
|
|
3
|
+
use ctx::{
|
|
4
|
+
BlockContext, CalculateRoundValidatorsContext, EvmOptions, ExecutionContext, GenesisContext,
|
|
5
|
+
JsBlockHeaderData, JsCalculateRoundValidatorsContext, JsCommitData, JsCommitKey, JsEvmOptions,
|
|
6
|
+
JsGenesisContext, JsPrepareNextCommitContext, JsPreverifyTransactionContext,
|
|
7
|
+
JsTransactionContext, JsTransactionData, JsTransactionSimulateContext,
|
|
8
|
+
JsTransactionViewContext, JsUpdateRewardsAndVotesContext, PrepareNextCommitContext,
|
|
9
|
+
PreverifyTxContext, TxContext, TxSimulateContext, TxViewContext, UpdateRewardsAndVotesContext,
|
|
10
|
+
};
|
|
11
|
+
use logger::JsLogger;
|
|
12
|
+
use mainsail_evm_core::{
|
|
13
|
+
account::AccountInfoExtended,
|
|
14
|
+
db::{
|
|
15
|
+
BlockHeaderData, CommitData, CommitKey, GenesisInfo, PendingCommit, PersistentDB,
|
|
16
|
+
PersistentDBOptions, ProofData, TransactionData, TxnDatabaseReader,
|
|
17
|
+
},
|
|
18
|
+
legacy::{LegacyAccountAttributes, LegacyAddress, LegacyColdWallet},
|
|
19
|
+
logger::LogLevel,
|
|
20
|
+
logs_bloom,
|
|
21
|
+
precompiles::MainsailPrecompiles,
|
|
22
|
+
receipt::{TxReceipt, map_execution_result},
|
|
23
|
+
state_changes::AccountUpdate,
|
|
24
|
+
state_commit, state_root,
|
|
25
|
+
};
|
|
26
|
+
use napi::bindgen_prelude::*;
|
|
27
|
+
use napi_derive::napi;
|
|
28
|
+
use result::{
|
|
29
|
+
CommitResult, JsAccountInfoExtended, JsCommitResult, JsGetState, JsLegacyAttributes,
|
|
30
|
+
JsLegacyColdWallet, JsTransactionReceipt, PreverifyTxResult, TxViewResult,
|
|
31
|
+
};
|
|
32
|
+
use revm::{
|
|
33
|
+
Database, DatabaseCommit, ExecuteEvm, MainBuilder, MainContext,
|
|
34
|
+
context::{
|
|
35
|
+
BlockEnv, ContextTr, TxEnv,
|
|
36
|
+
result::{EVMError, ExecutionResult, ResultAndState},
|
|
37
|
+
},
|
|
38
|
+
database::{State, TransitionAccount, WrapDatabaseRef, bal::EvmDatabaseError},
|
|
39
|
+
handler::EvmTr,
|
|
40
|
+
primitives::{Address, B256, Bytes, TxKind, U256, hex::ToHexExt, map::HashMap},
|
|
41
|
+
state::AccountInfo,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
mod ctx;
|
|
45
|
+
mod logger;
|
|
46
|
+
mod result;
|
|
47
|
+
mod utils;
|
|
48
|
+
|
|
49
|
+
// A complex struct which cannot be exposed to JavaScript directly.
|
|
50
|
+
pub struct EvmInner {
|
|
51
|
+
persistent_db: PersistentDB,
|
|
52
|
+
|
|
53
|
+
// A pending commit consists of one or more transactions.
|
|
54
|
+
//pending_commit: Option<PendingCommit>,
|
|
55
|
+
pending_commits: HashMap<CommitKey, PendingCommit>,
|
|
56
|
+
|
|
57
|
+
snapshot: Option<PendingCommit>,
|
|
58
|
+
|
|
59
|
+
logger: JsLogger,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
impl EvmInner {
|
|
63
|
+
pub fn new(opts: EvmOptions) -> Self {
|
|
64
|
+
let logger = JsLogger::new(opts.logger_callback).expect("logger ok");
|
|
65
|
+
|
|
66
|
+
let mut db_opts = PersistentDBOptions::new(opts.path).with_logger(logger.inner());
|
|
67
|
+
|
|
68
|
+
if let Some(history_size) = opts.history_size {
|
|
69
|
+
if history_size > 0 {
|
|
70
|
+
db_opts = db_opts.with_history_size(history_size)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let persistent_db = PersistentDB::new(db_opts).expect("path ok");
|
|
75
|
+
|
|
76
|
+
EvmInner {
|
|
77
|
+
persistent_db,
|
|
78
|
+
pending_commits: Default::default(),
|
|
79
|
+
snapshot: None,
|
|
80
|
+
logger,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pub fn prepare_next_commit(&mut self, ctx: PrepareNextCommitContext) -> Result<()> {
|
|
85
|
+
let genesis_block_number = self.genesis_block_number();
|
|
86
|
+
if let Some(pending) = self.pending_commits.get(&ctx.commit_key) {
|
|
87
|
+
// do not replace any pending commit, while still in bootstrapping phase.
|
|
88
|
+
if pending.key.0 == genesis_block_number && ctx.commit_key == pending.key {
|
|
89
|
+
return Ok(());
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
self.logger.log(
|
|
93
|
+
LogLevel::Debug,
|
|
94
|
+
format!(
|
|
95
|
+
"replacing existing pending commit {:?} for {:?}",
|
|
96
|
+
pending.key, ctx.commit_key
|
|
97
|
+
),
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let pending_commit = PendingCommit {
|
|
102
|
+
key: ctx.commit_key,
|
|
103
|
+
..Default::default()
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
self.pending_commits
|
|
107
|
+
.insert(pending_commit.key, pending_commit);
|
|
108
|
+
|
|
109
|
+
Ok(())
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pub fn view(&mut self, tx_ctx: TxViewContext) -> Result<TxViewResult> {
|
|
113
|
+
let result = self.transact_evm(tx_ctx.into());
|
|
114
|
+
|
|
115
|
+
Ok(match result {
|
|
116
|
+
Ok((r, _)) => {
|
|
117
|
+
// if !r.is_success() {
|
|
118
|
+
// self.logger
|
|
119
|
+
// .log(LogLevel::Warn, format!("view call failed: {:?}", r));
|
|
120
|
+
// }
|
|
121
|
+
|
|
122
|
+
TxViewResult {
|
|
123
|
+
success: r.is_success(),
|
|
124
|
+
output: r.into_output(),
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
Err(err) => {
|
|
128
|
+
self.logger.log(
|
|
129
|
+
LogLevel::Warn,
|
|
130
|
+
format!("view call returned error: {:?}", err),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
TxViewResult {
|
|
134
|
+
success: false,
|
|
135
|
+
output: None,
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
pub fn code_at(
|
|
142
|
+
&mut self,
|
|
143
|
+
address: Address,
|
|
144
|
+
block_number: Option<u64>,
|
|
145
|
+
) -> std::result::Result<Bytes, EVMError<String>> {
|
|
146
|
+
let account = match block_number {
|
|
147
|
+
None => self.persistent_db.basic(address),
|
|
148
|
+
Some(block_number) => {
|
|
149
|
+
let result = self
|
|
150
|
+
.persistent_db
|
|
151
|
+
.get_historical_account_info(block_number, address);
|
|
152
|
+
|
|
153
|
+
match result {
|
|
154
|
+
Ok((historical, _)) if historical.is_some() => Ok(historical),
|
|
155
|
+
Ok((_, missing_fallback)) if missing_fallback => {
|
|
156
|
+
self.persistent_db.basic(address)
|
|
157
|
+
} // fallback
|
|
158
|
+
Ok(_) => Ok(None),
|
|
159
|
+
Err(err) => Err(err),
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
.map_err(|err| EVMError::Database(format!("account lookup failed: {}", err).into()))?;
|
|
164
|
+
|
|
165
|
+
match account {
|
|
166
|
+
Some(account) => {
|
|
167
|
+
let code = self
|
|
168
|
+
.persistent_db
|
|
169
|
+
.code_by_hash(account.code_hash)
|
|
170
|
+
.map_err(|err| {
|
|
171
|
+
EVMError::Database(format!("code lookup failed: {}", err).into())
|
|
172
|
+
})?;
|
|
173
|
+
|
|
174
|
+
Ok(code.original_bytes())
|
|
175
|
+
}
|
|
176
|
+
None => Ok(Default::default()),
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
pub fn storage_at(
|
|
181
|
+
&mut self,
|
|
182
|
+
address: Address,
|
|
183
|
+
slot: U256,
|
|
184
|
+
) -> std::result::Result<U256, EVMError<String>> {
|
|
185
|
+
match self.persistent_db.storage(address, slot) {
|
|
186
|
+
Ok(slot) => Ok(slot),
|
|
187
|
+
Err(err) => Err(EVMError::Database(
|
|
188
|
+
format!("storage lookup failed: {}", err).into(),
|
|
189
|
+
)),
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
pub fn initialize_genesis(
|
|
194
|
+
&mut self,
|
|
195
|
+
genesis_ctx: GenesisContext,
|
|
196
|
+
) -> std::result::Result<(), EVMError<String>> {
|
|
197
|
+
match self.persistent_db.set_genesis_info(GenesisInfo {
|
|
198
|
+
account: genesis_ctx.account,
|
|
199
|
+
deployer_account: genesis_ctx.deployer_account,
|
|
200
|
+
validator_contract: genesis_ctx.validator_contract,
|
|
201
|
+
username_contract: genesis_ctx.username_contract,
|
|
202
|
+
initial_block_number: genesis_ctx.initial_block_number,
|
|
203
|
+
initial_supply: genesis_ctx.initial_supply,
|
|
204
|
+
}) {
|
|
205
|
+
Ok(_) => Ok(()),
|
|
206
|
+
Err(err) => Err(EVMError::Database(
|
|
207
|
+
format!("set_genesis_info failed: {}", err).into(),
|
|
208
|
+
)),
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
pub fn calculate_round_validators(
|
|
213
|
+
&mut self,
|
|
214
|
+
ctx: CalculateRoundValidatorsContext,
|
|
215
|
+
) -> std::result::Result<(), EVMError<String>> {
|
|
216
|
+
assert!(
|
|
217
|
+
self.pending_commits.contains_key(&ctx.commit_key),
|
|
218
|
+
"calculate_round_validators is missing commit key {:?}",
|
|
219
|
+
ctx.commit_key
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
let genesis_info = self
|
|
223
|
+
.persistent_db
|
|
224
|
+
.genesis_info
|
|
225
|
+
.as_ref()
|
|
226
|
+
.expect("genesis info")
|
|
227
|
+
.clone();
|
|
228
|
+
|
|
229
|
+
let abi = ethers_contract::BaseContract::from(
|
|
230
|
+
ethers_core::abi::parse_abi(&["function calculateRoundValidators(uint8 n) external"])
|
|
231
|
+
.expect("encode abi"),
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// encode abi into Bytes
|
|
235
|
+
let calldata = abi
|
|
236
|
+
.encode("calculateRoundValidators", ctx.round_validators)
|
|
237
|
+
.expect("encode calculateRoundValidators");
|
|
238
|
+
|
|
239
|
+
let nonce = self
|
|
240
|
+
.get_account_nonce(&ctx.commit_key, genesis_info.deployer_account)
|
|
241
|
+
.map_err(|err| EVMError::Database(format!("get_account_nonce: {err}").into()))?;
|
|
242
|
+
|
|
243
|
+
match self.transact_evm(ExecutionContext {
|
|
244
|
+
block_context: Some(BlockContext {
|
|
245
|
+
commit_key: ctx.commit_key,
|
|
246
|
+
gas_limit: u64::MAX,
|
|
247
|
+
timestamp: ctx.timestamp,
|
|
248
|
+
validator_address: ctx.validator_address,
|
|
249
|
+
}),
|
|
250
|
+
from: genesis_info.deployer_account,
|
|
251
|
+
to: Some(genesis_info.validator_contract),
|
|
252
|
+
data: Bytes::from(calldata.0),
|
|
253
|
+
value: U256::ZERO,
|
|
254
|
+
nonce: Some(nonce),
|
|
255
|
+
gas_limit: Some(u64::MAX),
|
|
256
|
+
gas_price: 0,
|
|
257
|
+
spec_id: ctx.spec_id,
|
|
258
|
+
tx_hash: None,
|
|
259
|
+
stateful: true,
|
|
260
|
+
}) {
|
|
261
|
+
Ok((receipt, _)) => {
|
|
262
|
+
self.logger.log(
|
|
263
|
+
LogLevel::Debug,
|
|
264
|
+
format!(
|
|
265
|
+
"calculate_round_validators {:?} {:?}",
|
|
266
|
+
ctx.commit_key, receipt
|
|
267
|
+
),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
assert!(
|
|
271
|
+
receipt.is_success(),
|
|
272
|
+
"calculate_round_validators unsuccessful"
|
|
273
|
+
);
|
|
274
|
+
Ok(())
|
|
275
|
+
}
|
|
276
|
+
Err(err) => Err(EVMError::Database(
|
|
277
|
+
format!("calculate_round_validators failed: {}", err).into(),
|
|
278
|
+
)),
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
pub fn update_rewards_and_votes(
|
|
283
|
+
&mut self,
|
|
284
|
+
ctx: UpdateRewardsAndVotesContext,
|
|
285
|
+
) -> std::result::Result<(), EVMError<String>> {
|
|
286
|
+
assert!(
|
|
287
|
+
self.pending_commits.contains_key(&ctx.commit_key),
|
|
288
|
+
"update_rewards_and_votes is missing commit key {:?}",
|
|
289
|
+
ctx.commit_key
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
let genesis_info = self
|
|
293
|
+
.persistent_db
|
|
294
|
+
.genesis_info
|
|
295
|
+
.as_ref()
|
|
296
|
+
.expect("genesis info")
|
|
297
|
+
.clone();
|
|
298
|
+
|
|
299
|
+
let nonce = self
|
|
300
|
+
.get_account_nonce(&ctx.commit_key, genesis_info.deployer_account)
|
|
301
|
+
.map_err(|err| EVMError::Database(format!("get_account_nonce: {err}").into()))?;
|
|
302
|
+
|
|
303
|
+
let mut pending_commit = self.pending_commits.get_mut(&ctx.commit_key).expect("ok");
|
|
304
|
+
let mut rewards = HashMap::<Address, u128>::default();
|
|
305
|
+
rewards.insert(ctx.validator_address, ctx.block_reward);
|
|
306
|
+
|
|
307
|
+
match state_commit::apply_rewards(&mut self.persistent_db, &mut pending_commit, rewards) {
|
|
308
|
+
Ok(_) => {
|
|
309
|
+
// call into consensus contract to update votes
|
|
310
|
+
let voters = pending_commit
|
|
311
|
+
.cache
|
|
312
|
+
.accounts
|
|
313
|
+
.keys()
|
|
314
|
+
.map(|k| ethers_core::types::Address::from_slice(k.0.as_slice()))
|
|
315
|
+
.collect::<Vec<ethers_core::types::Address>>();
|
|
316
|
+
|
|
317
|
+
let abi = ethers_contract::BaseContract::from(
|
|
318
|
+
ethers_core::abi::parse_abi(&[
|
|
319
|
+
"function updateVoters(address[] calldata voters) external",
|
|
320
|
+
])
|
|
321
|
+
.expect("encode abi"),
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
// encode abi into Bytes
|
|
325
|
+
let calldata = abi
|
|
326
|
+
.encode("updateVoters", voters.clone())
|
|
327
|
+
.expect("encode updateVoters");
|
|
328
|
+
|
|
329
|
+
match self.transact_evm(ExecutionContext {
|
|
330
|
+
block_context: Some(BlockContext {
|
|
331
|
+
commit_key: ctx.commit_key,
|
|
332
|
+
gas_limit: u64::MAX,
|
|
333
|
+
timestamp: ctx.timestamp,
|
|
334
|
+
validator_address: ctx.validator_address,
|
|
335
|
+
}),
|
|
336
|
+
from: genesis_info.deployer_account,
|
|
337
|
+
to: Some(genesis_info.validator_contract),
|
|
338
|
+
data: Bytes::from(calldata.0),
|
|
339
|
+
value: U256::ZERO,
|
|
340
|
+
nonce: Some(nonce),
|
|
341
|
+
gas_limit: Some(u64::MAX),
|
|
342
|
+
gas_price: 0,
|
|
343
|
+
spec_id: ctx.spec_id,
|
|
344
|
+
tx_hash: None,
|
|
345
|
+
stateful: true,
|
|
346
|
+
}) {
|
|
347
|
+
Ok((receipt, _)) => {
|
|
348
|
+
self.logger.log(
|
|
349
|
+
LogLevel::Debug,
|
|
350
|
+
format!(
|
|
351
|
+
"vote_update {:?} {:?} {:?}",
|
|
352
|
+
ctx.commit_key,
|
|
353
|
+
receipt,
|
|
354
|
+
voters.len()
|
|
355
|
+
),
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
assert!(receipt.is_success(), "vote_update unsuccessful");
|
|
359
|
+
Ok(())
|
|
360
|
+
}
|
|
361
|
+
Err(err) => Err(EVMError::Database(
|
|
362
|
+
format!("vote_update failed: {err}").into(),
|
|
363
|
+
)),
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
Err(err) => Err(EVMError::Database(
|
|
367
|
+
format!("apply_rewards failed: {err}").into(),
|
|
368
|
+
)),
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
pub fn get_account_info(
|
|
373
|
+
&mut self,
|
|
374
|
+
address: Address,
|
|
375
|
+
block_number: Option<u64>,
|
|
376
|
+
) -> std::result::Result<AccountInfo, EVMError<String>> {
|
|
377
|
+
let result = match block_number {
|
|
378
|
+
None => self.persistent_db.basic(address),
|
|
379
|
+
Some(block_number) => {
|
|
380
|
+
let result = self
|
|
381
|
+
.persistent_db
|
|
382
|
+
.get_historical_account_info(block_number, address);
|
|
383
|
+
|
|
384
|
+
match result {
|
|
385
|
+
Ok((historical, _)) if historical.is_some() => Ok(historical),
|
|
386
|
+
Ok((_, missing_fallback)) if missing_fallback => {
|
|
387
|
+
self.persistent_db.basic(address)
|
|
388
|
+
} // fallback
|
|
389
|
+
Ok(_) => Ok(None),
|
|
390
|
+
Err(err) => Err(err),
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
match result {
|
|
396
|
+
Ok(account) => Ok(account.unwrap_or_default()),
|
|
397
|
+
Err(err) => Err(EVMError::Database(
|
|
398
|
+
format!("account lookup failed: {}", err).into(),
|
|
399
|
+
)),
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
pub fn get_account_info_extended(
|
|
404
|
+
&mut self,
|
|
405
|
+
address: Address,
|
|
406
|
+
legacy_address: Option<LegacyAddress>,
|
|
407
|
+
) -> std::result::Result<AccountInfoExtended, EVMError<String>> {
|
|
408
|
+
let mut info = self
|
|
409
|
+
.persistent_db
|
|
410
|
+
.basic(address)
|
|
411
|
+
.map_err(|err| {
|
|
412
|
+
EVMError::Database(format!("account info lookup failed: {}", err).into())
|
|
413
|
+
})?
|
|
414
|
+
.unwrap_or_default();
|
|
415
|
+
|
|
416
|
+
let mut legacy_attributes = Default::default();
|
|
417
|
+
if let Some(legacy_address) = legacy_address {
|
|
418
|
+
match self
|
|
419
|
+
.persistent_db
|
|
420
|
+
.get_legacy_cold_wallet(legacy_address)
|
|
421
|
+
.map_err(|err| {
|
|
422
|
+
EVMError::Database(format!("legacy cold wallet lookup failed: {}", err).into())
|
|
423
|
+
})? {
|
|
424
|
+
Some(legacy_cold_wallet) if legacy_cold_wallet.merge_info.is_none() => {
|
|
425
|
+
// Merge cold wallet with account
|
|
426
|
+
info.balance = info.balance.saturating_add(legacy_cold_wallet.balance);
|
|
427
|
+
legacy_attributes = Some(legacy_cold_wallet.legacy_attributes);
|
|
428
|
+
}
|
|
429
|
+
_ => (),
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Use cold wallet legacy attributes if present as they can't be present in both at the same time.
|
|
434
|
+
let legacy_attributes = {
|
|
435
|
+
match legacy_attributes {
|
|
436
|
+
Some(legacy_attributes) => legacy_attributes,
|
|
437
|
+
None => self
|
|
438
|
+
.persistent_db
|
|
439
|
+
.get_legacy_attributes(address)
|
|
440
|
+
.map_err(|err| {
|
|
441
|
+
EVMError::Database(
|
|
442
|
+
format!("legacy attributes lookup failed: {}", err).into(),
|
|
443
|
+
)
|
|
444
|
+
})?
|
|
445
|
+
.unwrap_or_default(),
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
Ok(AccountInfoExtended {
|
|
450
|
+
address,
|
|
451
|
+
info,
|
|
452
|
+
legacy_attributes,
|
|
453
|
+
})
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
pub fn import_account_infos(
|
|
457
|
+
&mut self,
|
|
458
|
+
infos: Vec<AccountInfoExtended>,
|
|
459
|
+
) -> std::result::Result<(), EVMError<String>> {
|
|
460
|
+
let genesis_block_number = self.genesis_block_number();
|
|
461
|
+
|
|
462
|
+
let (_, pending) = self
|
|
463
|
+
.pending_commits
|
|
464
|
+
.iter_mut()
|
|
465
|
+
.find(|(key, _)| key.0 == genesis_block_number)
|
|
466
|
+
.expect("genesis commit");
|
|
467
|
+
|
|
468
|
+
for info in infos {
|
|
469
|
+
assert!(!pending.cache.accounts.contains_key(&info.address));
|
|
470
|
+
|
|
471
|
+
let (address, info, legacy_attributes) = info.into_parts();
|
|
472
|
+
pending.import_account(address, info, legacy_attributes);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
Ok(())
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
pub fn import_legacy_cold_wallets(
|
|
479
|
+
&mut self,
|
|
480
|
+
wallets: Vec<LegacyColdWallet>,
|
|
481
|
+
) -> std::result::Result<(), EVMError<String>> {
|
|
482
|
+
let genesis_block_number = self.genesis_block_number();
|
|
483
|
+
|
|
484
|
+
let (_, pending) = self
|
|
485
|
+
.pending_commits
|
|
486
|
+
.iter_mut()
|
|
487
|
+
.find(|(key, _)| key.0 == genesis_block_number)
|
|
488
|
+
.expect("genesis commit");
|
|
489
|
+
|
|
490
|
+
for wallet in wallets {
|
|
491
|
+
assert!(!pending.legacy_cold_wallets.contains_key(&wallet.address));
|
|
492
|
+
pending.legacy_cold_wallets.insert(wallet.address, wallet);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
Ok(())
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
pub fn get_accounts(
|
|
499
|
+
&mut self,
|
|
500
|
+
offset: u64,
|
|
501
|
+
limit: u64,
|
|
502
|
+
) -> std::result::Result<(Option<u64>, Vec<AccountInfoExtended>), EVMError<String>> {
|
|
503
|
+
match self.persistent_db.get_accounts(offset, limit) {
|
|
504
|
+
Ok((next_offset, accounts)) => Ok((next_offset, accounts)),
|
|
505
|
+
Err(err) => Err(EVMError::Database(
|
|
506
|
+
format!("failed reading accounts: {}", err).into(),
|
|
507
|
+
)),
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
pub fn get_legacy_attributes(
|
|
512
|
+
&mut self,
|
|
513
|
+
address: Address,
|
|
514
|
+
legacy_address: Option<LegacyAddress>,
|
|
515
|
+
) -> std::result::Result<Option<LegacyAccountAttributes>, EVMError<String>> {
|
|
516
|
+
if let Some(legacy_attributes) =
|
|
517
|
+
self.persistent_db
|
|
518
|
+
.get_legacy_attributes(address)
|
|
519
|
+
.map_err(|err| {
|
|
520
|
+
EVMError::Database(format!("failed reading legacy attributes: {}", err).into())
|
|
521
|
+
})?
|
|
522
|
+
{
|
|
523
|
+
return Ok(Some(legacy_attributes));
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Try fallback to legacy attributes from cold wallets
|
|
527
|
+
let legacy_attributes = match legacy_address {
|
|
528
|
+
Some(legacy_address) => {
|
|
529
|
+
match self
|
|
530
|
+
.persistent_db
|
|
531
|
+
.get_legacy_cold_wallet(legacy_address)
|
|
532
|
+
.map_err(|err| {
|
|
533
|
+
EVMError::Database(
|
|
534
|
+
format!("legacy cold wallet attributes lookup failed: {}", err).into(),
|
|
535
|
+
)
|
|
536
|
+
})? {
|
|
537
|
+
Some(legacy_cold_wallet) => Some(legacy_cold_wallet.legacy_attributes),
|
|
538
|
+
None => None,
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
None => None,
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
Ok(legacy_attributes)
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
pub fn get_legacy_cold_wallets(
|
|
548
|
+
&mut self,
|
|
549
|
+
offset: u64,
|
|
550
|
+
limit: u64,
|
|
551
|
+
) -> std::result::Result<(Option<u64>, Vec<LegacyColdWallet>), EVMError<String>> {
|
|
552
|
+
match self.persistent_db.get_legacy_cold_wallets(offset, limit) {
|
|
553
|
+
Ok((next_offset, accounts)) => Ok((next_offset, accounts)),
|
|
554
|
+
Err(err) => Err(EVMError::Database(
|
|
555
|
+
format!("failed reading legacy cold wallets: {}", err).into(),
|
|
556
|
+
)),
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
pub fn get_receipts(
|
|
561
|
+
&mut self,
|
|
562
|
+
offset: u64,
|
|
563
|
+
limit: u64,
|
|
564
|
+
) -> std::result::Result<(Option<u64>, Vec<(u64, Vec<(B256, TxReceipt)>)>), EVMError<String>>
|
|
565
|
+
{
|
|
566
|
+
match self.persistent_db.get_receipts(offset, limit) {
|
|
567
|
+
Ok((next_offset, receipts)) => Ok((next_offset, receipts)),
|
|
568
|
+
Err(err) => Err(EVMError::Database(
|
|
569
|
+
format!("failed reading receipts: {}", err).into(),
|
|
570
|
+
)),
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
pub fn get_receipts_by_block_number(
|
|
575
|
+
&mut self,
|
|
576
|
+
block_number: u64,
|
|
577
|
+
) -> std::result::Result<HashMap<B256, TxReceipt>, EVMError<String>> {
|
|
578
|
+
match self
|
|
579
|
+
.persistent_db
|
|
580
|
+
.get_receipts_by_block_number(block_number)
|
|
581
|
+
{
|
|
582
|
+
Ok(receipts) => Ok(receipts),
|
|
583
|
+
Err(err) => Err(EVMError::Database(
|
|
584
|
+
format!("failed reading receipts by block number: {}", err).into(),
|
|
585
|
+
)),
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
pub fn get_receipts_by_block_range(
|
|
590
|
+
&mut self,
|
|
591
|
+
from_block_number: u64,
|
|
592
|
+
to_block_number: u64,
|
|
593
|
+
) -> std::result::Result<Vec<(u64, Vec<(B256, TxReceipt)>)>, EVMError<String>> {
|
|
594
|
+
match self
|
|
595
|
+
.persistent_db
|
|
596
|
+
.get_receipts_by_block_range(from_block_number, to_block_number)
|
|
597
|
+
{
|
|
598
|
+
Ok(receipts) => Ok(receipts),
|
|
599
|
+
Err(err) => Err(EVMError::Database(
|
|
600
|
+
format!("failed reading receipts by block range: {}", err).into(),
|
|
601
|
+
)),
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
pub fn preverify_transaction(
|
|
606
|
+
&mut self,
|
|
607
|
+
ctx: PreverifyTxContext,
|
|
608
|
+
) -> std::result::Result<PreverifyTxResult, EVMError<String>> {
|
|
609
|
+
let mut pending_commit = PendingCommit::new(Default::default());
|
|
610
|
+
|
|
611
|
+
// Make legacy balance available to account in pending commit during preverification
|
|
612
|
+
if let Some(legacy_address) = ctx.legacy_address {
|
|
613
|
+
match self
|
|
614
|
+
.persistent_db
|
|
615
|
+
.get_legacy_cold_wallet(legacy_address)
|
|
616
|
+
.map_err(|err| {
|
|
617
|
+
EVMError::Database(format!("failed reading legacy cold wallet: {}", err).into())
|
|
618
|
+
})? {
|
|
619
|
+
Some(legacy_cold_wallet) if legacy_cold_wallet.merge_info.is_none() => {
|
|
620
|
+
let mut legacy_balances = HashMap::<Address, u128>::default();
|
|
621
|
+
legacy_balances.insert(
|
|
622
|
+
ctx.from,
|
|
623
|
+
legacy_cold_wallet.balance.try_into().expect("fit u128"),
|
|
624
|
+
);
|
|
625
|
+
state_commit::apply_rewards(
|
|
626
|
+
&mut self.persistent_db,
|
|
627
|
+
&mut pending_commit,
|
|
628
|
+
legacy_balances,
|
|
629
|
+
)
|
|
630
|
+
.map_err(|err| {
|
|
631
|
+
EVMError::Database(
|
|
632
|
+
format!("failed to apply legacy balance: {}", err).into(),
|
|
633
|
+
)
|
|
634
|
+
})?;
|
|
635
|
+
}
|
|
636
|
+
_ => (),
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
let db_reader = TxnDatabaseReader::new(&self.persistent_db).map_err(|err| {
|
|
641
|
+
EVMError::Database(format!("failed to create tx database reader {}", err))
|
|
642
|
+
})?;
|
|
643
|
+
|
|
644
|
+
let state_db = State::builder()
|
|
645
|
+
.with_bundle_update()
|
|
646
|
+
.with_cached_prestate(std::mem::take(&mut pending_commit.cache))
|
|
647
|
+
.with_database(WrapDatabaseRef(db_reader))
|
|
648
|
+
.build();
|
|
649
|
+
|
|
650
|
+
let evm = revm::Context::mainnet()
|
|
651
|
+
.with_db(state_db)
|
|
652
|
+
.modify_cfg_chained(|cfg| {
|
|
653
|
+
cfg.spec = ctx.spec_id;
|
|
654
|
+
})
|
|
655
|
+
.modify_block_chained(|block_env: &mut BlockEnv| {
|
|
656
|
+
block_env.gas_limit = ctx.block_gas_limit;
|
|
657
|
+
})
|
|
658
|
+
.modify_tx_chained(|tx_env: &mut TxEnv| {
|
|
659
|
+
tx_env.gas_limit = ctx.gas_limit;
|
|
660
|
+
tx_env.gas_price = ctx.gas_price;
|
|
661
|
+
tx_env.gas_priority_fee = None;
|
|
662
|
+
tx_env.caller = ctx.from;
|
|
663
|
+
tx_env.value = ctx.value;
|
|
664
|
+
tx_env.nonce = ctx.nonce;
|
|
665
|
+
tx_env.kind = match ctx.to {
|
|
666
|
+
Some(recipient) => TxKind::Call(recipient),
|
|
667
|
+
None => TxKind::Create,
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
tx_env.data = ctx.data;
|
|
671
|
+
})
|
|
672
|
+
.build_mainnet()
|
|
673
|
+
.with_precompiles(MainsailPrecompiles::new(ctx.spec_id));
|
|
674
|
+
|
|
675
|
+
let ctx = evm.ctx_ref();
|
|
676
|
+
let result = revm::handler::validation::validate_initial_tx_gas(
|
|
677
|
+
ctx.tx(),
|
|
678
|
+
(*ctx.cfg().spec()).into(),
|
|
679
|
+
false,
|
|
680
|
+
false,
|
|
681
|
+
0,
|
|
682
|
+
);
|
|
683
|
+
|
|
684
|
+
Ok(match result {
|
|
685
|
+
Ok(result) => PreverifyTxResult {
|
|
686
|
+
success: true,
|
|
687
|
+
initial_gas_used: result.initial_total_gas(),
|
|
688
|
+
..Default::default()
|
|
689
|
+
},
|
|
690
|
+
Err(err) => PreverifyTxResult {
|
|
691
|
+
error: Some(format!("preverify failed: {}", err.to_string())),
|
|
692
|
+
..Default::default()
|
|
693
|
+
},
|
|
694
|
+
})
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
pub fn get_receipt(
|
|
698
|
+
&mut self,
|
|
699
|
+
block_number: u64,
|
|
700
|
+
tx_hash: B256,
|
|
701
|
+
) -> std::result::Result<Option<TxReceipt>, EVMError<String>> {
|
|
702
|
+
match self.persistent_db.get_receipt(block_number, tx_hash) {
|
|
703
|
+
Ok((_, receipt)) => Ok(receipt),
|
|
704
|
+
Err(err) => Err(EVMError::Database(
|
|
705
|
+
format!("failed reading receipt: {}", err).into(),
|
|
706
|
+
)),
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
pub fn simulate(
|
|
711
|
+
&mut self,
|
|
712
|
+
ctx: TxSimulateContext,
|
|
713
|
+
) -> std::result::Result<TxReceipt, EVMError<String>> {
|
|
714
|
+
self.execute(ctx.into())
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
pub fn process(
|
|
718
|
+
&mut self,
|
|
719
|
+
tx_ctx: TxContext,
|
|
720
|
+
) -> std::result::Result<TxReceipt, EVMError<String>> {
|
|
721
|
+
let commit_key = &tx_ctx.block_context.commit_key;
|
|
722
|
+
|
|
723
|
+
let (committed, _) = self
|
|
724
|
+
.persistent_db
|
|
725
|
+
.get_receipt(commit_key.0, tx_ctx.tx_hash)
|
|
726
|
+
.map_err(|err| EVMError::Database(format!("commit receipt lookup: {}", err).into()))?;
|
|
727
|
+
assert!(!committed);
|
|
728
|
+
|
|
729
|
+
if let Some(mut pending) = self.pending_commits.get_mut(commit_key) {
|
|
730
|
+
// Make legacy cold wallet balance available to pending commit if not already present
|
|
731
|
+
if let Some(legacy_address) = tx_ctx.legacy_address {
|
|
732
|
+
if !pending
|
|
733
|
+
.merged_legacy_cold_wallets
|
|
734
|
+
.contains_key(&tx_ctx.from)
|
|
735
|
+
{
|
|
736
|
+
// Make legacy balance available to account in pending commit
|
|
737
|
+
match self
|
|
738
|
+
.persistent_db
|
|
739
|
+
.get_legacy_cold_wallet(legacy_address)
|
|
740
|
+
.map_err(|err| {
|
|
741
|
+
EVMError::Database(
|
|
742
|
+
format!("failed reading legacy cold wallet: {}", err).into(),
|
|
743
|
+
)
|
|
744
|
+
})? {
|
|
745
|
+
Some(legacy_cold_wallet) if legacy_cold_wallet.merge_info.is_none() => {
|
|
746
|
+
let mut legacy_balances = HashMap::<Address, u128>::default();
|
|
747
|
+
legacy_balances.insert(
|
|
748
|
+
tx_ctx.from,
|
|
749
|
+
legacy_cold_wallet.balance.try_into().expect("fit u128"),
|
|
750
|
+
);
|
|
751
|
+
|
|
752
|
+
state_commit::apply_rewards(
|
|
753
|
+
&mut self.persistent_db,
|
|
754
|
+
&mut pending,
|
|
755
|
+
legacy_balances,
|
|
756
|
+
)
|
|
757
|
+
.map_err(|err| {
|
|
758
|
+
EVMError::Database(
|
|
759
|
+
format!("failed to apply legacy balance: {}", err).into(),
|
|
760
|
+
)
|
|
761
|
+
})?;
|
|
762
|
+
|
|
763
|
+
pending
|
|
764
|
+
.merged_legacy_cold_wallets
|
|
765
|
+
.insert(tx_ctx.from, Some((tx_ctx.tx_hash, legacy_address)));
|
|
766
|
+
}
|
|
767
|
+
_ => {
|
|
768
|
+
// Prevent subsequent look ups for same sender in same commit
|
|
769
|
+
pending.merged_legacy_cold_wallets.insert(tx_ctx.from, None);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
self.execute(tx_ctx.into())
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
pub fn commit(
|
|
780
|
+
&mut self,
|
|
781
|
+
commit_key: CommitKey,
|
|
782
|
+
commit_data: Option<CommitData>,
|
|
783
|
+
) -> std::result::Result<Vec<AccountUpdate>, EVMError<String>> {
|
|
784
|
+
assert!(self.pending_commits.contains_key(&commit_key));
|
|
785
|
+
|
|
786
|
+
let pending_commit = self.take_pending_commit(commit_key);
|
|
787
|
+
|
|
788
|
+
// self.logger.log(
|
|
789
|
+
// LogLevel::Info,
|
|
790
|
+
// format!(
|
|
791
|
+
// "committing {:?} with {} transitions",
|
|
792
|
+
// commit_key,
|
|
793
|
+
// pending_commit.transitions.transitions.len(),
|
|
794
|
+
// ),
|
|
795
|
+
// );
|
|
796
|
+
|
|
797
|
+
match state_commit::commit_to_db(&mut self.persistent_db, pending_commit, commit_data) {
|
|
798
|
+
Ok(result) => Ok(result),
|
|
799
|
+
Err(err) => Err(EVMError::Database(format!("commit failed: {}", err).into())),
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
pub fn state_root(
|
|
804
|
+
&mut self,
|
|
805
|
+
commit_key: CommitKey,
|
|
806
|
+
current_hash: B256,
|
|
807
|
+
) -> std::result::Result<String, EVMError<String>> {
|
|
808
|
+
let pending_commit = self
|
|
809
|
+
.pending_commits
|
|
810
|
+
.get_mut(&commit_key)
|
|
811
|
+
.expect("pending commit exists");
|
|
812
|
+
|
|
813
|
+
let genesis_info = self
|
|
814
|
+
.persistent_db
|
|
815
|
+
.genesis_info
|
|
816
|
+
.as_ref()
|
|
817
|
+
.expect("genesis info exists");
|
|
818
|
+
|
|
819
|
+
let result = state_root::calculate(&genesis_info, pending_commit, current_hash);
|
|
820
|
+
|
|
821
|
+
match result {
|
|
822
|
+
Ok(result) => Ok(result.encode_hex()),
|
|
823
|
+
Err(err) => Err(EVMError::Database(
|
|
824
|
+
format!("state_root failed: {}", err).into(),
|
|
825
|
+
)),
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
pub fn logs_bloom(
|
|
830
|
+
&mut self,
|
|
831
|
+
commit_key: CommitKey,
|
|
832
|
+
) -> std::result::Result<String, EVMError<String>> {
|
|
833
|
+
let pending_commit = self
|
|
834
|
+
.pending_commits
|
|
835
|
+
.get(&commit_key)
|
|
836
|
+
.expect("pending commit exists");
|
|
837
|
+
|
|
838
|
+
let result = logs_bloom::calculate(pending_commit);
|
|
839
|
+
|
|
840
|
+
match result {
|
|
841
|
+
Ok(result) => Ok(result.encode_hex()),
|
|
842
|
+
Err(err) => Err(EVMError::Database(
|
|
843
|
+
format!("logs_bloom failed: {}", err).into(),
|
|
844
|
+
)),
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
pub fn is_empty(&mut self) -> std::result::Result<bool, EVMError<String>> {
|
|
849
|
+
let result = self.persistent_db.is_empty();
|
|
850
|
+
|
|
851
|
+
match result {
|
|
852
|
+
Ok(result) => Ok(result),
|
|
853
|
+
Err(err) => Err(EVMError::Database(
|
|
854
|
+
format!("is_empty failed: {}", err).into(),
|
|
855
|
+
)),
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
pub fn get_state(&mut self) -> std::result::Result<(u64, u64), EVMError<String>> {
|
|
860
|
+
let result = self.persistent_db.get_state();
|
|
861
|
+
|
|
862
|
+
match result {
|
|
863
|
+
Ok(result) => Ok(result),
|
|
864
|
+
Err(err) => Err(EVMError::Database(
|
|
865
|
+
format!("get_state failed: {}", err).into(),
|
|
866
|
+
)),
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
pub fn get_block_header_data(
|
|
871
|
+
&mut self,
|
|
872
|
+
block_number: u64,
|
|
873
|
+
) -> std::result::Result<Option<BlockHeaderData>, EVMError<String>> {
|
|
874
|
+
let result = self.persistent_db.get_block_header_data(block_number);
|
|
875
|
+
|
|
876
|
+
match result {
|
|
877
|
+
Ok(result) => Ok(result),
|
|
878
|
+
Err(err) => Err(EVMError::Database(
|
|
879
|
+
format!("get_block_header_bytes failed: {}", err).into(),
|
|
880
|
+
)),
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
pub fn get_block_number_by_hash(
|
|
885
|
+
&mut self,
|
|
886
|
+
block_hash: B256,
|
|
887
|
+
) -> std::result::Result<Option<u64>, EVMError<String>> {
|
|
888
|
+
let result = self.persistent_db.get_block_number_by_hash(block_hash);
|
|
889
|
+
|
|
890
|
+
match result {
|
|
891
|
+
Ok(result) => Ok(result),
|
|
892
|
+
Err(err) => Err(EVMError::Database(
|
|
893
|
+
format!("get_block_number_by_hash failed: {}", err).into(),
|
|
894
|
+
)),
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
pub fn get_commit_data(
|
|
899
|
+
&mut self,
|
|
900
|
+
block_number: u64,
|
|
901
|
+
) -> std::result::Result<
|
|
902
|
+
Option<(ProofData, BlockHeaderData, Vec<TransactionData>)>,
|
|
903
|
+
EVMError<String>,
|
|
904
|
+
> {
|
|
905
|
+
let Some(proof) = self
|
|
906
|
+
.persistent_db
|
|
907
|
+
.get_proof_data(block_number)
|
|
908
|
+
.map_err(|err| EVMError::Database(format!("get_proof_data failed: {}", err).into()))?
|
|
909
|
+
else {
|
|
910
|
+
return Ok(None);
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
let header = self
|
|
914
|
+
.persistent_db
|
|
915
|
+
.get_block_header_data(block_number)
|
|
916
|
+
.map_err(|err| {
|
|
917
|
+
EVMError::Database(format!("get_block_header_data failed: {}", err).into())
|
|
918
|
+
})?
|
|
919
|
+
.ok_or_else(|| EVMError::Custom("header not found".into()))?;
|
|
920
|
+
|
|
921
|
+
let mut txs = Vec::with_capacity(header.transactions_count as usize);
|
|
922
|
+
|
|
923
|
+
for i in 0..header.transactions_count {
|
|
924
|
+
let key = format!("{block_number}-{i}");
|
|
925
|
+
let tx_data = self.get_transaction_data(key)?.ok_or_else(|| {
|
|
926
|
+
EVMError::Custom(format!("tx {block_number}-{i} not found").into())
|
|
927
|
+
})?;
|
|
928
|
+
|
|
929
|
+
txs.push(tx_data);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
Ok(Some((proof, header, txs)))
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
pub fn get_commits_by_block_range(
|
|
936
|
+
&mut self,
|
|
937
|
+
from_block_number: u64,
|
|
938
|
+
to_block_number: u64,
|
|
939
|
+
max_bytes: u64,
|
|
940
|
+
) -> std::result::Result<
|
|
941
|
+
Vec<(ProofData, BlockHeaderData, Vec<TransactionData>)>,
|
|
942
|
+
EVMError<String>,
|
|
943
|
+
> {
|
|
944
|
+
match self.persistent_db.get_commits_by_block_range(
|
|
945
|
+
from_block_number,
|
|
946
|
+
to_block_number,
|
|
947
|
+
max_bytes,
|
|
948
|
+
) {
|
|
949
|
+
Ok(commits) => Ok(commits),
|
|
950
|
+
Err(err) => Err(EVMError::Database(
|
|
951
|
+
format!("failed reading commits by block range: {}", err).into(),
|
|
952
|
+
)),
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
pub fn get_transaction_data(
|
|
957
|
+
&mut self,
|
|
958
|
+
key: String,
|
|
959
|
+
) -> std::result::Result<Option<TransactionData>, EVMError<String>> {
|
|
960
|
+
let result = self.persistent_db.get_transaction_data(key);
|
|
961
|
+
|
|
962
|
+
match result {
|
|
963
|
+
Ok(result) => Ok(result),
|
|
964
|
+
Err(err) => Err(EVMError::Database(
|
|
965
|
+
format!("get_transaction_data failed: {}", err).into(),
|
|
966
|
+
)),
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
pub fn get_transaction_key_by_hash(
|
|
971
|
+
&mut self,
|
|
972
|
+
tx_hash: B256,
|
|
973
|
+
) -> std::result::Result<Option<String>, EVMError<String>> {
|
|
974
|
+
let result = self.persistent_db.get_transaction_key_by_hash(tx_hash);
|
|
975
|
+
|
|
976
|
+
match result {
|
|
977
|
+
Ok(result) => Ok(result),
|
|
978
|
+
Err(err) => Err(EVMError::Database(
|
|
979
|
+
format!("get_transaction_key_by_hash failed: {}", err).into(),
|
|
980
|
+
)),
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
pub fn snapshot(&mut self, commit_key: CommitKey) -> std::result::Result<(), EVMError<String>> {
|
|
985
|
+
self.logger.inner().log(
|
|
986
|
+
LogLevel::Debug,
|
|
987
|
+
format!("taking snapshot of commit {:?}", commit_key),
|
|
988
|
+
);
|
|
989
|
+
|
|
990
|
+
let _ = std::mem::replace(
|
|
991
|
+
&mut self.snapshot,
|
|
992
|
+
self.pending_commits.get(&commit_key).cloned(),
|
|
993
|
+
);
|
|
994
|
+
|
|
995
|
+
Ok(())
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
pub fn rollback(&mut self, commit_key: CommitKey) -> std::result::Result<(), EVMError<String>> {
|
|
999
|
+
self.logger.inner().log(
|
|
1000
|
+
LogLevel::Debug,
|
|
1001
|
+
format!("rolling back to commit {:?}", commit_key),
|
|
1002
|
+
);
|
|
1003
|
+
|
|
1004
|
+
match self.snapshot.take() {
|
|
1005
|
+
Some(commit) if commit.key == commit_key => {
|
|
1006
|
+
assert!(self.pending_commits.contains_key(&commit_key));
|
|
1007
|
+
self.pending_commits.insert(commit_key, commit);
|
|
1008
|
+
|
|
1009
|
+
Ok(())
|
|
1010
|
+
}
|
|
1011
|
+
Some(commit) => Err(EVMError::Custom(
|
|
1012
|
+
format!(
|
|
1013
|
+
"rollback commit key mismatch ({:?}, {:?})",
|
|
1014
|
+
commit.key, commit_key
|
|
1015
|
+
)
|
|
1016
|
+
.into(),
|
|
1017
|
+
)),
|
|
1018
|
+
None => Err(EVMError::Custom(
|
|
1019
|
+
format!("rollback to non-existent commit ({:?})", commit_key).into(),
|
|
1020
|
+
)),
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
pub fn dispose(&mut self) -> std::result::Result<(), EVMError<String>> {
|
|
1025
|
+
// replace to drop any reference to logging hook
|
|
1026
|
+
self.logger = JsLogger::new(None)
|
|
1027
|
+
.map_err(|err| EVMError::Custom(format!("close logger err={err}")))?;
|
|
1028
|
+
|
|
1029
|
+
Ok(())
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
fn execute(
|
|
1033
|
+
&mut self,
|
|
1034
|
+
ctx: ExecutionContext,
|
|
1035
|
+
) -> std::result::Result<TxReceipt, EVMError<String>> {
|
|
1036
|
+
match self.transact_evm(ctx.into()) {
|
|
1037
|
+
Ok((result, cumulative_gas_used)) => {
|
|
1038
|
+
let receipt = map_execution_result(result, cumulative_gas_used);
|
|
1039
|
+
Ok(receipt)
|
|
1040
|
+
}
|
|
1041
|
+
Err(err) => {
|
|
1042
|
+
match err {
|
|
1043
|
+
EVMError::Transaction(err) => {
|
|
1044
|
+
return Err(EVMError::Transaction(err));
|
|
1045
|
+
}
|
|
1046
|
+
// EVMError::Header(_) => todo!(),
|
|
1047
|
+
// EVMError::Database(_) => todo!(),
|
|
1048
|
+
// EVMError::Custom(_) => todo!(),
|
|
1049
|
+
_ => {
|
|
1050
|
+
panic!("fatal evm err {:?}", err);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
fn transact_evm(
|
|
1058
|
+
&mut self,
|
|
1059
|
+
ctx: ExecutionContext,
|
|
1060
|
+
) -> std::result::Result<
|
|
1061
|
+
(ExecutionResult, u64),
|
|
1062
|
+
EVMError<EvmDatabaseError<mainsail_evm_core::db::Error>>,
|
|
1063
|
+
> {
|
|
1064
|
+
let mut state_builder = State::builder().with_bundle_update();
|
|
1065
|
+
|
|
1066
|
+
if let Some(commit_key) = ctx.block_context.as_ref().map(|b| &b.commit_key)
|
|
1067
|
+
&& ctx.stateful
|
|
1068
|
+
{
|
|
1069
|
+
if let Some(pending_commit) = self.pending_commits.get_mut(commit_key) {
|
|
1070
|
+
state_builder =
|
|
1071
|
+
state_builder.with_cached_prestate(std::mem::take(&mut pending_commit.cache));
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
let db_reader = TxnDatabaseReader::new(&self.persistent_db)
|
|
1076
|
+
.map_err(|err| EVMError::Database(EvmDatabaseError::Database(err)))?;
|
|
1077
|
+
|
|
1078
|
+
let state_db = state_builder
|
|
1079
|
+
.with_database(WrapDatabaseRef(db_reader))
|
|
1080
|
+
.build();
|
|
1081
|
+
|
|
1082
|
+
let mut evm = revm::Context::mainnet()
|
|
1083
|
+
.with_db(state_db)
|
|
1084
|
+
.modify_cfg_chained(|cfg| {
|
|
1085
|
+
cfg.spec = ctx.spec_id;
|
|
1086
|
+
cfg.disable_nonce_check = ctx.nonce.is_none();
|
|
1087
|
+
})
|
|
1088
|
+
.modify_block_chained(|block_env: &mut BlockEnv| {
|
|
1089
|
+
let Some(block_ctx) = ctx.block_context.as_ref() else {
|
|
1090
|
+
return;
|
|
1091
|
+
};
|
|
1092
|
+
|
|
1093
|
+
block_env.number = U256::from(block_ctx.commit_key.0);
|
|
1094
|
+
block_env.beneficiary = block_ctx.validator_address;
|
|
1095
|
+
block_env.timestamp = U256::from(block_ctx.timestamp);
|
|
1096
|
+
block_env.gas_limit = block_ctx.gas_limit;
|
|
1097
|
+
block_env.difficulty = U256::ZERO;
|
|
1098
|
+
})
|
|
1099
|
+
.modify_tx_chained(|tx_env: &mut TxEnv| {
|
|
1100
|
+
tx_env.gas_limit = ctx.gas_limit.unwrap_or_else(|| u64::MAX);
|
|
1101
|
+
tx_env.gas_price = ctx.gas_price;
|
|
1102
|
+
tx_env.gas_priority_fee = None;
|
|
1103
|
+
tx_env.caller = ctx.from;
|
|
1104
|
+
tx_env.value = ctx.value;
|
|
1105
|
+
tx_env.nonce = ctx.nonce.unwrap_or_default();
|
|
1106
|
+
tx_env.kind = match ctx.to {
|
|
1107
|
+
Some(recipient) => TxKind::Call(recipient),
|
|
1108
|
+
None => TxKind::Create,
|
|
1109
|
+
};
|
|
1110
|
+
|
|
1111
|
+
tx_env.data = ctx.data;
|
|
1112
|
+
})
|
|
1113
|
+
.build_mainnet()
|
|
1114
|
+
.with_precompiles(MainsailPrecompiles::new(ctx.spec_id));
|
|
1115
|
+
|
|
1116
|
+
let result = evm.replay();
|
|
1117
|
+
|
|
1118
|
+
match result {
|
|
1119
|
+
Ok(result) => {
|
|
1120
|
+
let ResultAndState { state, result } = result;
|
|
1121
|
+
|
|
1122
|
+
let mut cumulative_gas_used = 0;
|
|
1123
|
+
|
|
1124
|
+
// Update state if transaction is part of a commit
|
|
1125
|
+
if let Some(commit_key) = ctx.block_context.as_ref().map(|b| &b.commit_key)
|
|
1126
|
+
&& ctx.stateful
|
|
1127
|
+
{
|
|
1128
|
+
let state_db = evm.db_mut();
|
|
1129
|
+
state_db.commit(state);
|
|
1130
|
+
|
|
1131
|
+
if let Some(pending_commit) = self.pending_commits.get_mut(commit_key) {
|
|
1132
|
+
pending_commit.cache = std::mem::take(&mut state_db.cache);
|
|
1133
|
+
|
|
1134
|
+
if let Some(tx_hash) = ctx.tx_hash {
|
|
1135
|
+
pending_commit.cumulative_gas_used += result.tx_gas_used();
|
|
1136
|
+
pending_commit.results.insert(
|
|
1137
|
+
tx_hash,
|
|
1138
|
+
(result.clone(), pending_commit.cumulative_gas_used),
|
|
1139
|
+
);
|
|
1140
|
+
cumulative_gas_used = pending_commit.cumulative_gas_used;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
pending_commit.transitions.add_transitions(
|
|
1144
|
+
state_db
|
|
1145
|
+
.transition_state
|
|
1146
|
+
.take()
|
|
1147
|
+
.unwrap_or_default()
|
|
1148
|
+
.transitions
|
|
1149
|
+
.into_iter()
|
|
1150
|
+
.collect::<Vec<(Address, TransitionAccount)>>(),
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
Ok((result, cumulative_gas_used))
|
|
1156
|
+
}
|
|
1157
|
+
Err(err) => Err(err),
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
fn get_account_nonce(
|
|
1162
|
+
&mut self,
|
|
1163
|
+
commit_key: &CommitKey,
|
|
1164
|
+
account: Address,
|
|
1165
|
+
) -> std::result::Result<u64, mainsail_evm_core::db::Error> {
|
|
1166
|
+
if let Some(pending) = self.pending_commits.get(commit_key) {
|
|
1167
|
+
if pending.cache.accounts.contains_key(&account) {
|
|
1168
|
+
if let Some(cache) = pending.cache.accounts.get(&account) {
|
|
1169
|
+
if let Some(account) = &cache.account {
|
|
1170
|
+
return Ok(account.info.nonce);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
if let Some(account_info) = self.persistent_db.basic(account)? {
|
|
1177
|
+
return Ok(account_info.nonce);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
return Ok(Default::default());
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
fn take_pending_commit(&mut self, commit_key: CommitKey) -> PendingCommit {
|
|
1184
|
+
let pending_commit = self
|
|
1185
|
+
.pending_commits
|
|
1186
|
+
.remove(&commit_key)
|
|
1187
|
+
.expect("pending commit exists");
|
|
1188
|
+
|
|
1189
|
+
if self.pending_commits.len() > 0 {
|
|
1190
|
+
self.logger.log(
|
|
1191
|
+
LogLevel::Debug,
|
|
1192
|
+
format!(
|
|
1193
|
+
"taking {commit_key:?} and dropping {:?}",
|
|
1194
|
+
self.pending_commits.keys().collect::<Vec<_>>()
|
|
1195
|
+
),
|
|
1196
|
+
);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
self.pending_commits.clear();
|
|
1200
|
+
self.snapshot.take();
|
|
1201
|
+
|
|
1202
|
+
pending_commit
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
#[inline]
|
|
1206
|
+
fn genesis_block_number(&mut self) -> u64 {
|
|
1207
|
+
self.persistent_db
|
|
1208
|
+
.genesis_info
|
|
1209
|
+
.as_ref()
|
|
1210
|
+
.cloned()
|
|
1211
|
+
.unwrap_or_default()
|
|
1212
|
+
.initial_block_number
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
// The EVM wrapper is exposed to JavaScript.
|
|
1217
|
+
|
|
1218
|
+
#[napi(js_name = "Evm")]
|
|
1219
|
+
pub struct JsEvmWrapper {
|
|
1220
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
#[napi]
|
|
1224
|
+
impl JsEvmWrapper {
|
|
1225
|
+
#[napi(constructor)]
|
|
1226
|
+
pub fn new(opts: JsEvmOptions) -> Result<Self> {
|
|
1227
|
+
let opts = EvmOptions::try_from(opts)?;
|
|
1228
|
+
Ok(JsEvmWrapper {
|
|
1229
|
+
evm: Arc::new(tokio::sync::Mutex::new(EvmInner::new(opts))),
|
|
1230
|
+
})
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
#[napi]
|
|
1234
|
+
pub fn preverify_transaction<'env>(
|
|
1235
|
+
&mut self,
|
|
1236
|
+
env: &'env Env,
|
|
1237
|
+
tx_ctx: JsPreverifyTransactionContext,
|
|
1238
|
+
) -> Result<PromiseRaw<'env, result::JsPreverifyTransactionResult>> {
|
|
1239
|
+
let tx_ctx = PreverifyTxContext::try_from(tx_ctx)?;
|
|
1240
|
+
env.spawn_future_with_callback(
|
|
1241
|
+
Self::preverify_transaction_async(self.evm.clone(), tx_ctx),
|
|
1242
|
+
|_, result| Ok(result::JsPreverifyTransactionResult::new(result)),
|
|
1243
|
+
)
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
#[napi]
|
|
1247
|
+
pub fn view<'env>(
|
|
1248
|
+
&mut self,
|
|
1249
|
+
env: &'env Env,
|
|
1250
|
+
view_ctx: JsTransactionViewContext,
|
|
1251
|
+
) -> Result<PromiseRaw<'env, result::JsViewResult>> {
|
|
1252
|
+
let view_ctx = TxViewContext::try_from(view_ctx)?;
|
|
1253
|
+
env.spawn_future_with_callback(Self::view_async(self.evm.clone(), view_ctx), |_, result| {
|
|
1254
|
+
Ok(result::JsViewResult::new(result)?)
|
|
1255
|
+
})
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
#[napi]
|
|
1259
|
+
pub fn process<'env>(
|
|
1260
|
+
&mut self,
|
|
1261
|
+
env: &'env Env,
|
|
1262
|
+
tx_ctx: JsTransactionContext,
|
|
1263
|
+
) -> Result<PromiseRaw<'env, result::JsProcessResult>> {
|
|
1264
|
+
let tx_ctx = TxContext::try_from(tx_ctx)?;
|
|
1265
|
+
env.spawn_future_with_callback(
|
|
1266
|
+
Self::process_async(self.evm.clone(), tx_ctx),
|
|
1267
|
+
|_, result| Ok(result::JsProcessResult::new(result)),
|
|
1268
|
+
)
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
#[napi]
|
|
1272
|
+
pub fn simulate<'env>(
|
|
1273
|
+
&mut self,
|
|
1274
|
+
env: &'env Env,
|
|
1275
|
+
tx_ctx: JsTransactionSimulateContext,
|
|
1276
|
+
) -> Result<PromiseRaw<'env, result::JsSimulateResult>> {
|
|
1277
|
+
let tx_ctx = TxSimulateContext::try_from(tx_ctx)?;
|
|
1278
|
+
env.spawn_future_with_callback(
|
|
1279
|
+
Self::simulate_async(self.evm.clone(), tx_ctx),
|
|
1280
|
+
|_, result| Ok(result::JsSimulateResult::new(result)),
|
|
1281
|
+
)
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
#[napi]
|
|
1285
|
+
pub fn initialize_genesis<'env>(
|
|
1286
|
+
&mut self,
|
|
1287
|
+
env: &'env Env,
|
|
1288
|
+
genesis_ctx: JsGenesisContext,
|
|
1289
|
+
) -> Result<PromiseRaw<'env, ()>> {
|
|
1290
|
+
let genesis_ctx = GenesisContext::try_from(genesis_ctx)?;
|
|
1291
|
+
env.spawn_future_with_callback(
|
|
1292
|
+
Self::initialize_genesis_async(self.evm.clone(), genesis_ctx),
|
|
1293
|
+
|_, _| Ok(()),
|
|
1294
|
+
)
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
#[napi]
|
|
1298
|
+
pub fn prepare_next_commit<'env>(
|
|
1299
|
+
&mut self,
|
|
1300
|
+
env: &'env Env,
|
|
1301
|
+
ctx: JsPrepareNextCommitContext,
|
|
1302
|
+
) -> Result<PromiseRaw<'env, ()>> {
|
|
1303
|
+
let ctx = PrepareNextCommitContext::try_from(ctx)?;
|
|
1304
|
+
env.spawn_future_with_callback(
|
|
1305
|
+
Self::prepare_next_commit_async(self.evm.clone(), ctx),
|
|
1306
|
+
|_, _| Ok(()),
|
|
1307
|
+
)
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
#[napi]
|
|
1311
|
+
pub fn calculate_round_validators<'env>(
|
|
1312
|
+
&mut self,
|
|
1313
|
+
env: &'env Env,
|
|
1314
|
+
ctx: JsCalculateRoundValidatorsContext,
|
|
1315
|
+
) -> Result<PromiseRaw<'env, ()>> {
|
|
1316
|
+
let ctx = CalculateRoundValidatorsContext::try_from(ctx)?;
|
|
1317
|
+
env.spawn_future_with_callback(
|
|
1318
|
+
Self::calculate_round_validators_async(self.evm.clone(), ctx),
|
|
1319
|
+
|_, _| Ok(()),
|
|
1320
|
+
)
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
#[napi]
|
|
1324
|
+
pub fn update_rewards_and_votes<'env>(
|
|
1325
|
+
&mut self,
|
|
1326
|
+
env: &'env Env,
|
|
1327
|
+
ctx: JsUpdateRewardsAndVotesContext,
|
|
1328
|
+
) -> Result<PromiseRaw<'env, ()>> {
|
|
1329
|
+
let ctx = UpdateRewardsAndVotesContext::try_from(ctx)?;
|
|
1330
|
+
env.spawn_future_with_callback(
|
|
1331
|
+
Self::update_rewards_and_votes_async(self.evm.clone(), ctx),
|
|
1332
|
+
|_, _| Ok(()),
|
|
1333
|
+
)
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
#[napi]
|
|
1337
|
+
pub fn get_account_info<'env>(
|
|
1338
|
+
&mut self,
|
|
1339
|
+
env: &'env Env,
|
|
1340
|
+
address: String,
|
|
1341
|
+
block_number: Option<BigInt>,
|
|
1342
|
+
) -> Result<PromiseRaw<'env, result::JsAccountInfo>> {
|
|
1343
|
+
let address = utils::create_address_from_string(&address)?;
|
|
1344
|
+
|
|
1345
|
+
let block_number = match block_number {
|
|
1346
|
+
Some(block_number) => Some(block_number.get_u64().1),
|
|
1347
|
+
None => None,
|
|
1348
|
+
};
|
|
1349
|
+
|
|
1350
|
+
env.spawn_future_with_callback(
|
|
1351
|
+
Self::get_account_info_async(self.evm.clone(), address, block_number),
|
|
1352
|
+
|_, result| Ok(result::JsAccountInfo::new(result)?),
|
|
1353
|
+
)
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
#[napi]
|
|
1357
|
+
pub fn get_account_info_extended<'env>(
|
|
1358
|
+
&mut self,
|
|
1359
|
+
env: &'env Env,
|
|
1360
|
+
address: String,
|
|
1361
|
+
legacy_address: Option<String>,
|
|
1362
|
+
) -> Result<PromiseRaw<'env, result::JsAccountInfoExtended>> {
|
|
1363
|
+
let address = utils::create_address_from_string(&address)?;
|
|
1364
|
+
let legacy_address = if let Some(legacy_address) = legacy_address {
|
|
1365
|
+
Some(utils::create_legacy_address_from_string(&legacy_address)?)
|
|
1366
|
+
} else {
|
|
1367
|
+
None
|
|
1368
|
+
};
|
|
1369
|
+
|
|
1370
|
+
env.spawn_future_with_callback(
|
|
1371
|
+
Self::get_account_info_extended_async(self.evm.clone(), address, legacy_address),
|
|
1372
|
+
|_, result| Ok(result::JsAccountInfoExtended::new(result)),
|
|
1373
|
+
)
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
#[napi]
|
|
1377
|
+
pub fn import_account_infos<'env>(
|
|
1378
|
+
&mut self,
|
|
1379
|
+
env: &'env Env,
|
|
1380
|
+
infos: Vec<JsAccountInfoExtended>,
|
|
1381
|
+
) -> Result<PromiseRaw<'env, ()>> {
|
|
1382
|
+
let mut accounts: Vec<AccountInfoExtended> = Vec::with_capacity(infos.len());
|
|
1383
|
+
for info in infos {
|
|
1384
|
+
accounts.push(info.try_into()?);
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
env.spawn_future_with_callback(
|
|
1388
|
+
Self::import_account_infos_async(self.evm.clone(), accounts),
|
|
1389
|
+
|_, _| Ok(()),
|
|
1390
|
+
)
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
#[napi]
|
|
1394
|
+
pub fn import_legacy_cold_wallets<'env>(
|
|
1395
|
+
&mut self,
|
|
1396
|
+
env: &'env Env,
|
|
1397
|
+
infos: Vec<JsLegacyColdWallet>,
|
|
1398
|
+
) -> Result<PromiseRaw<'env, ()>> {
|
|
1399
|
+
let mut cold_wallets: Vec<LegacyColdWallet> = Vec::with_capacity(infos.len());
|
|
1400
|
+
for info in infos {
|
|
1401
|
+
cold_wallets.push(info.try_into()?);
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
env.spawn_future_with_callback(
|
|
1405
|
+
Self::import_legacy_cold_wallets_async(self.evm.clone(), cold_wallets),
|
|
1406
|
+
|_, _| Ok(()),
|
|
1407
|
+
)
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
#[napi]
|
|
1411
|
+
pub fn get_accounts<'env>(
|
|
1412
|
+
&mut self,
|
|
1413
|
+
env: &'env Env,
|
|
1414
|
+
offset: BigInt,
|
|
1415
|
+
limit: BigInt,
|
|
1416
|
+
) -> Result<PromiseRaw<'env, result::JsGetAccounts>> {
|
|
1417
|
+
let offset = offset.get_u64().1;
|
|
1418
|
+
let limit = limit.get_u64().1;
|
|
1419
|
+
|
|
1420
|
+
env.spawn_future_with_callback(
|
|
1421
|
+
Self::get_accounts_async(self.evm.clone(), offset, limit),
|
|
1422
|
+
|_, result| Ok(result::JsGetAccounts::new(result.0, result.1)),
|
|
1423
|
+
)
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
#[napi]
|
|
1427
|
+
pub fn get_legacy_attributes<'env>(
|
|
1428
|
+
&mut self,
|
|
1429
|
+
env: &'env Env,
|
|
1430
|
+
address: String,
|
|
1431
|
+
legacy_address: Option<String>,
|
|
1432
|
+
) -> Result<PromiseRaw<'env, Option<JsLegacyAttributes>>> {
|
|
1433
|
+
let address = utils::create_address_from_string(&address)?;
|
|
1434
|
+
let legacy_address = if let Some(legacy_address) = legacy_address {
|
|
1435
|
+
Some(utils::create_legacy_address_from_string(&legacy_address)?)
|
|
1436
|
+
} else {
|
|
1437
|
+
None
|
|
1438
|
+
};
|
|
1439
|
+
|
|
1440
|
+
env.spawn_future_with_callback(
|
|
1441
|
+
Self::get_legacy_attributes_async(self.evm.clone(), address, legacy_address),
|
|
1442
|
+
|_, result| {
|
|
1443
|
+
Ok(match result {
|
|
1444
|
+
Some(result) => Some(JsLegacyAttributes::new(result)),
|
|
1445
|
+
None => None,
|
|
1446
|
+
})
|
|
1447
|
+
},
|
|
1448
|
+
)
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
#[napi]
|
|
1452
|
+
pub fn get_legacy_cold_wallets<'env>(
|
|
1453
|
+
&mut self,
|
|
1454
|
+
env: &'env Env,
|
|
1455
|
+
offset: BigInt,
|
|
1456
|
+
limit: BigInt,
|
|
1457
|
+
) -> Result<PromiseRaw<'env, result::JsGetLegacyColdWallets>> {
|
|
1458
|
+
let offset = offset.get_u64().1;
|
|
1459
|
+
let limit = limit.get_u64().1;
|
|
1460
|
+
|
|
1461
|
+
env.spawn_future_with_callback(
|
|
1462
|
+
Self::get_legacy_cold_wallets_async(self.evm.clone(), offset, limit),
|
|
1463
|
+
|_, result| Ok(result::JsGetLegacyColdWallets::new(result.0, result.1)),
|
|
1464
|
+
)
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
#[napi]
|
|
1468
|
+
pub fn get_receipts<'env>(
|
|
1469
|
+
&mut self,
|
|
1470
|
+
node_env: &'env Env,
|
|
1471
|
+
offset: BigInt,
|
|
1472
|
+
limit: BigInt,
|
|
1473
|
+
) -> Result<PromiseRaw<'env, result::JsGetReceipts>> {
|
|
1474
|
+
let offset = offset.get_u64().1;
|
|
1475
|
+
let limit = limit.get_u64().1;
|
|
1476
|
+
|
|
1477
|
+
node_env.spawn_future_with_callback(
|
|
1478
|
+
Self::get_receipts_async(self.evm.clone(), offset, limit),
|
|
1479
|
+
|_, result| Ok(result::JsGetReceipts::new(result.0, result.1)?),
|
|
1480
|
+
)
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
#[napi]
|
|
1484
|
+
pub fn get_receipts_by_block_number<'env>(
|
|
1485
|
+
&mut self,
|
|
1486
|
+
node_env: &'env Env,
|
|
1487
|
+
block_number: BigInt,
|
|
1488
|
+
) -> Result<PromiseRaw<'env, HashMap<String, result::JsTransactionReceipt>>> {
|
|
1489
|
+
let block_number = block_number.get_u64().1;
|
|
1490
|
+
|
|
1491
|
+
node_env.spawn_future_with_callback(
|
|
1492
|
+
Self::get_receipts_by_block_number_async(self.evm.clone(), block_number),
|
|
1493
|
+
|_, result| {
|
|
1494
|
+
Ok(result
|
|
1495
|
+
.into_iter()
|
|
1496
|
+
.map(|(k, v)| (format!("{:x}", k), JsTransactionReceipt::new(v)))
|
|
1497
|
+
.collect())
|
|
1498
|
+
},
|
|
1499
|
+
)
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
#[napi]
|
|
1503
|
+
pub fn get_receipts_by_block_range<'env>(
|
|
1504
|
+
&mut self,
|
|
1505
|
+
node_env: &'env Env,
|
|
1506
|
+
from_block_number: BigInt,
|
|
1507
|
+
to_block_number: BigInt,
|
|
1508
|
+
) -> Result<PromiseRaw<'env, result::JsGetReceipts>> {
|
|
1509
|
+
let from_block_number = from_block_number.get_u64().1;
|
|
1510
|
+
let to_block_number = to_block_number.get_u64().1;
|
|
1511
|
+
|
|
1512
|
+
node_env.spawn_future_with_callback(
|
|
1513
|
+
Self::get_receipts_by_block_range_async(
|
|
1514
|
+
self.evm.clone(),
|
|
1515
|
+
from_block_number,
|
|
1516
|
+
to_block_number,
|
|
1517
|
+
),
|
|
1518
|
+
|_, result| Ok(result::JsGetReceipts::new(None, result)?),
|
|
1519
|
+
)
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
#[napi]
|
|
1523
|
+
pub fn get_receipt<'env>(
|
|
1524
|
+
&mut self,
|
|
1525
|
+
env: &'env Env,
|
|
1526
|
+
block_number: BigInt,
|
|
1527
|
+
tx_hash: String,
|
|
1528
|
+
) -> Result<PromiseRaw<'env, result::JsGetReceipt>> {
|
|
1529
|
+
let block_number = block_number.get_u64().1;
|
|
1530
|
+
let tx_hash = utils::convert_string_to_b256(tx_hash)?;
|
|
1531
|
+
|
|
1532
|
+
env.spawn_future_with_callback(
|
|
1533
|
+
Self::get_receipt_async(self.evm.clone(), block_number, tx_hash),
|
|
1534
|
+
move |_, result| Ok(result::JsGetReceipt::new(result, block_number, tx_hash)),
|
|
1535
|
+
)
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
#[napi]
|
|
1539
|
+
pub fn code_at<'env>(
|
|
1540
|
+
&mut self,
|
|
1541
|
+
env: &'env Env,
|
|
1542
|
+
address: String,
|
|
1543
|
+
block_number: Option<BigInt>,
|
|
1544
|
+
) -> Result<PromiseRaw<'env, String>> {
|
|
1545
|
+
let address = utils::create_address_from_string(&address)?;
|
|
1546
|
+
let block_number = match block_number {
|
|
1547
|
+
Some(block_number) => Some(block_number.get_u64().1),
|
|
1548
|
+
None => None,
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
env.spawn_future_with_callback(
|
|
1552
|
+
Self::code_at_async(self.evm.clone(), address, block_number),
|
|
1553
|
+
|_, result| Ok(result),
|
|
1554
|
+
)
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
#[napi]
|
|
1558
|
+
pub fn storage_at<'env>(
|
|
1559
|
+
&mut self,
|
|
1560
|
+
env: &'env Env,
|
|
1561
|
+
address: String,
|
|
1562
|
+
slot: BigInt,
|
|
1563
|
+
) -> Result<PromiseRaw<'env, String>> {
|
|
1564
|
+
let address = utils::create_address_from_string(&address)?;
|
|
1565
|
+
let slot = utils::convert_bigint_to_u256(slot)?;
|
|
1566
|
+
env.spawn_future_with_callback(
|
|
1567
|
+
Self::storage_at_async(self.evm.clone(), address, slot),
|
|
1568
|
+
|_, result| Ok(result),
|
|
1569
|
+
)
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
#[napi]
|
|
1573
|
+
pub fn commit<'env>(
|
|
1574
|
+
&mut self,
|
|
1575
|
+
env: &'env Env,
|
|
1576
|
+
commit_key: JsCommitKey,
|
|
1577
|
+
commit_data: Option<JsCommitData>,
|
|
1578
|
+
) -> Result<PromiseRaw<'env, JsCommitResult>> {
|
|
1579
|
+
let commit_key = CommitKey::try_from(commit_key)?;
|
|
1580
|
+
let commit_data = if let Some(commit_data) = commit_data {
|
|
1581
|
+
Some(CommitData::try_from(commit_data)?)
|
|
1582
|
+
} else {
|
|
1583
|
+
None
|
|
1584
|
+
};
|
|
1585
|
+
|
|
1586
|
+
env.spawn_future_with_callback(
|
|
1587
|
+
Self::commit_async(self.evm.clone(), commit_key, commit_data),
|
|
1588
|
+
|_, result| Ok(result::JsCommitResult::new(result)?),
|
|
1589
|
+
)
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
#[napi]
|
|
1593
|
+
pub fn state_root<'env>(
|
|
1594
|
+
&mut self,
|
|
1595
|
+
env: &'env Env,
|
|
1596
|
+
commit_key: JsCommitKey,
|
|
1597
|
+
current_hash: String,
|
|
1598
|
+
) -> Result<PromiseRaw<'env, String>> {
|
|
1599
|
+
let commit_key = CommitKey::try_from(commit_key)?;
|
|
1600
|
+
let current_hash = utils::convert_string_to_b256(current_hash)?;
|
|
1601
|
+
env.spawn_future_with_callback(
|
|
1602
|
+
Self::state_root_async(self.evm.clone(), commit_key, current_hash),
|
|
1603
|
+
|_, result| Ok(result),
|
|
1604
|
+
)
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
#[napi]
|
|
1608
|
+
pub fn logs_bloom<'env>(
|
|
1609
|
+
&mut self,
|
|
1610
|
+
env: &'env Env,
|
|
1611
|
+
commit_key: JsCommitKey,
|
|
1612
|
+
) -> Result<PromiseRaw<'env, String>> {
|
|
1613
|
+
let commit_key = CommitKey::try_from(commit_key)?;
|
|
1614
|
+
env.spawn_future_with_callback(
|
|
1615
|
+
Self::logs_bloom_async(self.evm.clone(), commit_key),
|
|
1616
|
+
|_, result| Ok(result),
|
|
1617
|
+
)
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
#[napi]
|
|
1621
|
+
pub fn is_empty<'env>(&mut self, env: &'env Env) -> Result<PromiseRaw<'env, bool>> {
|
|
1622
|
+
env.spawn_future_with_callback(Self::is_empty_async(self.evm.clone()), |_, result| {
|
|
1623
|
+
Ok(result)
|
|
1624
|
+
})
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
#[napi]
|
|
1628
|
+
pub fn get_state<'env>(&mut self, env: &'env Env) -> Result<PromiseRaw<'env, JsGetState>> {
|
|
1629
|
+
env.spawn_future_with_callback(Self::get_state_async(self.evm.clone()), |_, result| {
|
|
1630
|
+
Ok(result::JsGetState::new(result))
|
|
1631
|
+
})
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
#[napi]
|
|
1635
|
+
pub fn get_block_header_data<'env>(
|
|
1636
|
+
&mut self,
|
|
1637
|
+
env: &'env Env,
|
|
1638
|
+
block_number: BigInt,
|
|
1639
|
+
) -> Result<PromiseRaw<'env, Option<JsBlockHeaderData>>> {
|
|
1640
|
+
let block_number = block_number.get_u64().1;
|
|
1641
|
+
env.spawn_future_with_callback(
|
|
1642
|
+
Self::get_block_header_data_async(self.evm.clone(), block_number),
|
|
1643
|
+
|_, result| {
|
|
1644
|
+
Ok(match result {
|
|
1645
|
+
Some(data) => Some(JsBlockHeaderData::new(data)),
|
|
1646
|
+
None => None,
|
|
1647
|
+
})
|
|
1648
|
+
},
|
|
1649
|
+
)
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
#[napi]
|
|
1653
|
+
pub fn get_block_number_by_hash<'env>(
|
|
1654
|
+
&mut self,
|
|
1655
|
+
env: &'env Env,
|
|
1656
|
+
block_hash: String,
|
|
1657
|
+
) -> Result<PromiseRaw<'env, Option<BigInt>>> {
|
|
1658
|
+
let block_hash = utils::convert_string_to_b256(block_hash)?;
|
|
1659
|
+
|
|
1660
|
+
env.spawn_future_with_callback(
|
|
1661
|
+
Self::get_block_number_by_hash_async(self.evm.clone(), block_hash),
|
|
1662
|
+
|_, result| {
|
|
1663
|
+
Ok(match result {
|
|
1664
|
+
Some(result) => Some(BigInt::from(result)),
|
|
1665
|
+
None => None,
|
|
1666
|
+
})
|
|
1667
|
+
},
|
|
1668
|
+
)
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
#[napi]
|
|
1672
|
+
pub fn get_commit_data<'env>(
|
|
1673
|
+
&mut self,
|
|
1674
|
+
env: &'env Env,
|
|
1675
|
+
block_number: BigInt,
|
|
1676
|
+
) -> Result<PromiseRaw<'env, Option<JsCommitData>>> {
|
|
1677
|
+
let block_number = block_number.get_u64().1;
|
|
1678
|
+
env.spawn_future_with_callback(
|
|
1679
|
+
Self::get_commit_data_async(self.evm.clone(), block_number),
|
|
1680
|
+
|_, result| {
|
|
1681
|
+
Ok(match result {
|
|
1682
|
+
Some((proof, header, txs)) => Some(JsCommitData::new(proof, header, txs)),
|
|
1683
|
+
None => None,
|
|
1684
|
+
})
|
|
1685
|
+
},
|
|
1686
|
+
)
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
#[napi]
|
|
1690
|
+
pub fn get_commits_by_block_range<'env>(
|
|
1691
|
+
&mut self,
|
|
1692
|
+
env: &'env Env,
|
|
1693
|
+
from_block_number: BigInt,
|
|
1694
|
+
to_block_number: BigInt,
|
|
1695
|
+
max_bytes: BigInt,
|
|
1696
|
+
) -> Result<PromiseRaw<'env, Vec<JsCommitData>>> {
|
|
1697
|
+
let from_block_number = from_block_number.get_u64().1;
|
|
1698
|
+
let to_block_number = to_block_number.get_u64().1;
|
|
1699
|
+
let max_bytes = max_bytes.get_u64().1;
|
|
1700
|
+
env.spawn_future_with_callback(
|
|
1701
|
+
Self::get_commits_by_block_range_async(
|
|
1702
|
+
self.evm.clone(),
|
|
1703
|
+
from_block_number,
|
|
1704
|
+
to_block_number,
|
|
1705
|
+
max_bytes,
|
|
1706
|
+
),
|
|
1707
|
+
|_, result| {
|
|
1708
|
+
Ok(result
|
|
1709
|
+
.into_iter()
|
|
1710
|
+
.map(|(proof, header, txs)| JsCommitData::new(proof, header, txs))
|
|
1711
|
+
.collect())
|
|
1712
|
+
},
|
|
1713
|
+
)
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
#[napi]
|
|
1717
|
+
pub fn get_transaction_data<'env>(
|
|
1718
|
+
&mut self,
|
|
1719
|
+
env: &'env Env,
|
|
1720
|
+
key: String,
|
|
1721
|
+
) -> Result<PromiseRaw<'env, Option<JsTransactionData>>> {
|
|
1722
|
+
env.spawn_future_with_callback(
|
|
1723
|
+
Self::get_transaction_data_async(self.evm.clone(), key),
|
|
1724
|
+
|_, result| Ok(result.map(|data| JsTransactionData::new(data))),
|
|
1725
|
+
)
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
#[napi]
|
|
1729
|
+
pub fn get_transaction_key_by_hash<'env>(
|
|
1730
|
+
&mut self,
|
|
1731
|
+
env: &'env Env,
|
|
1732
|
+
tx_hash: String,
|
|
1733
|
+
) -> Result<PromiseRaw<'env, Option<String>>> {
|
|
1734
|
+
let tx_hash = utils::convert_string_to_b256(tx_hash)?;
|
|
1735
|
+
|
|
1736
|
+
env.spawn_future_with_callback(
|
|
1737
|
+
Self::get_transaction_key_by_hash_async(self.evm.clone(), tx_hash),
|
|
1738
|
+
|_, result| Ok(result),
|
|
1739
|
+
)
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
#[napi]
|
|
1743
|
+
pub fn snapshot<'env>(
|
|
1744
|
+
&mut self,
|
|
1745
|
+
env: &'env Env,
|
|
1746
|
+
commit_key: JsCommitKey,
|
|
1747
|
+
) -> Result<PromiseRaw<'env, ()>> {
|
|
1748
|
+
let commit_key = CommitKey::try_from(commit_key)?;
|
|
1749
|
+
env.spawn_future_with_callback(
|
|
1750
|
+
Self::snapshot_async(self.evm.clone(), commit_key),
|
|
1751
|
+
|_, _| Ok(()),
|
|
1752
|
+
)
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
#[napi]
|
|
1756
|
+
pub fn rollback<'env>(
|
|
1757
|
+
&mut self,
|
|
1758
|
+
env: &'env Env,
|
|
1759
|
+
commit_key: JsCommitKey,
|
|
1760
|
+
) -> Result<PromiseRaw<'env, ()>> {
|
|
1761
|
+
let commit_key = CommitKey::try_from(commit_key)?;
|
|
1762
|
+
env.spawn_future_with_callback(
|
|
1763
|
+
Self::rollback_async(self.evm.clone(), commit_key),
|
|
1764
|
+
|_, _| Ok(()),
|
|
1765
|
+
)
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
#[napi]
|
|
1769
|
+
pub fn dispose<'env>(&mut self, env: &'env Env) -> Result<PromiseRaw<'env, ()>> {
|
|
1770
|
+
env.spawn_future_with_callback(Self::dispose_async(self.evm.clone()), |_, _| Ok(()))
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
async fn preverify_transaction_async(
|
|
1774
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1775
|
+
tx_ctx: PreverifyTxContext,
|
|
1776
|
+
) -> Result<PreverifyTxResult> {
|
|
1777
|
+
let mut lock = evm.lock().await;
|
|
1778
|
+
let result = lock.preverify_transaction(tx_ctx);
|
|
1779
|
+
|
|
1780
|
+
match result {
|
|
1781
|
+
Ok(result) => Result::Ok(result),
|
|
1782
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
async fn view_async(
|
|
1787
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1788
|
+
view_ctx: TxViewContext,
|
|
1789
|
+
) -> Result<TxViewResult> {
|
|
1790
|
+
let mut lock = evm.lock().await;
|
|
1791
|
+
lock.view(view_ctx)
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
async fn process_async(
|
|
1795
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1796
|
+
tx_ctx: TxContext,
|
|
1797
|
+
) -> Result<TxReceipt> {
|
|
1798
|
+
let mut lock = evm.lock().await;
|
|
1799
|
+
let result = lock.process(tx_ctx);
|
|
1800
|
+
|
|
1801
|
+
match result {
|
|
1802
|
+
Ok(result) => Result::Ok(result),
|
|
1803
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
async fn simulate_async(
|
|
1808
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1809
|
+
tx_ctx: TxSimulateContext,
|
|
1810
|
+
) -> Result<TxReceipt> {
|
|
1811
|
+
let mut lock = evm.lock().await;
|
|
1812
|
+
let result = lock.simulate(tx_ctx);
|
|
1813
|
+
|
|
1814
|
+
match result {
|
|
1815
|
+
Ok(result) => Result::Ok(result),
|
|
1816
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
async fn get_account_info_async(
|
|
1821
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1822
|
+
address: Address,
|
|
1823
|
+
block_number: Option<u64>,
|
|
1824
|
+
) -> Result<AccountInfo> {
|
|
1825
|
+
let mut lock = evm.lock().await;
|
|
1826
|
+
let result = lock.get_account_info(address, block_number);
|
|
1827
|
+
|
|
1828
|
+
match result {
|
|
1829
|
+
Ok(account) => Result::Ok(account),
|
|
1830
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
async fn get_account_info_extended_async(
|
|
1835
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1836
|
+
address: Address,
|
|
1837
|
+
legacy_address: Option<LegacyAddress>,
|
|
1838
|
+
) -> Result<AccountInfoExtended> {
|
|
1839
|
+
let mut lock = evm.lock().await;
|
|
1840
|
+
let result = lock.get_account_info_extended(address, legacy_address);
|
|
1841
|
+
|
|
1842
|
+
match result {
|
|
1843
|
+
Ok(account) => Result::Ok(account),
|
|
1844
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
async fn import_account_infos_async(
|
|
1849
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1850
|
+
infos: Vec<AccountInfoExtended>,
|
|
1851
|
+
) -> Result<()> {
|
|
1852
|
+
let mut lock = evm.lock().await;
|
|
1853
|
+
let result = lock.import_account_infos(infos);
|
|
1854
|
+
|
|
1855
|
+
match result {
|
|
1856
|
+
Ok(_) => Result::Ok(()),
|
|
1857
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
async fn import_legacy_cold_wallets_async(
|
|
1862
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1863
|
+
wallets: Vec<LegacyColdWallet>,
|
|
1864
|
+
) -> Result<()> {
|
|
1865
|
+
let mut lock = evm.lock().await;
|
|
1866
|
+
let result = lock.import_legacy_cold_wallets(wallets);
|
|
1867
|
+
|
|
1868
|
+
match result {
|
|
1869
|
+
Ok(_) => Result::Ok(()),
|
|
1870
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
async fn initialize_genesis_async(
|
|
1875
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1876
|
+
genesis_ctx: GenesisContext,
|
|
1877
|
+
) -> Result<()> {
|
|
1878
|
+
let mut lock = evm.lock().await;
|
|
1879
|
+
let result = lock.initialize_genesis(genesis_ctx);
|
|
1880
|
+
|
|
1881
|
+
match result {
|
|
1882
|
+
Ok(_) => Result::Ok(()),
|
|
1883
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
async fn prepare_next_commit_async(
|
|
1888
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1889
|
+
ctx: PrepareNextCommitContext,
|
|
1890
|
+
) -> Result<()> {
|
|
1891
|
+
let mut lock = evm.lock().await;
|
|
1892
|
+
let result = lock.prepare_next_commit(ctx);
|
|
1893
|
+
|
|
1894
|
+
match result {
|
|
1895
|
+
Ok(_) => Result::Ok(()),
|
|
1896
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
async fn calculate_round_validators_async(
|
|
1901
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1902
|
+
ctx: CalculateRoundValidatorsContext,
|
|
1903
|
+
) -> Result<()> {
|
|
1904
|
+
let mut lock = evm.lock().await;
|
|
1905
|
+
let result = lock.calculate_round_validators(ctx);
|
|
1906
|
+
|
|
1907
|
+
match result {
|
|
1908
|
+
Ok(_) => Result::Ok(()),
|
|
1909
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
async fn update_rewards_and_votes_async(
|
|
1914
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1915
|
+
ctx: UpdateRewardsAndVotesContext,
|
|
1916
|
+
) -> Result<()> {
|
|
1917
|
+
let mut lock = evm.lock().await;
|
|
1918
|
+
let result = lock.update_rewards_and_votes(ctx);
|
|
1919
|
+
|
|
1920
|
+
match result {
|
|
1921
|
+
Ok(_) => Result::Ok(()),
|
|
1922
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
async fn code_at_async(
|
|
1927
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1928
|
+
address: Address,
|
|
1929
|
+
block_number: Option<u64>,
|
|
1930
|
+
) -> Result<String> {
|
|
1931
|
+
let mut lock = evm.lock().await;
|
|
1932
|
+
let result = lock.code_at(address, block_number);
|
|
1933
|
+
|
|
1934
|
+
match result {
|
|
1935
|
+
Ok(code) => Result::Ok(revm::primitives::hex::encode_prefixed(code.as_ref())),
|
|
1936
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
async fn storage_at_async(
|
|
1941
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1942
|
+
address: Address,
|
|
1943
|
+
slot: U256,
|
|
1944
|
+
) -> Result<String> {
|
|
1945
|
+
let mut lock = evm.lock().await;
|
|
1946
|
+
let result = lock.storage_at(address, slot);
|
|
1947
|
+
|
|
1948
|
+
match result {
|
|
1949
|
+
Ok(slot) => Result::Ok(revm::primitives::hex::encode_prefixed(
|
|
1950
|
+
slot.to_be_bytes::<32>(),
|
|
1951
|
+
)),
|
|
1952
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
async fn commit_async(
|
|
1957
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1958
|
+
commit_key: CommitKey,
|
|
1959
|
+
commit_data: Option<CommitData>,
|
|
1960
|
+
) -> Result<CommitResult> {
|
|
1961
|
+
let mut lock = evm.lock().await;
|
|
1962
|
+
let result = lock.commit(commit_key, commit_data);
|
|
1963
|
+
|
|
1964
|
+
match result {
|
|
1965
|
+
Ok(result) => Result::Ok(CommitResult {
|
|
1966
|
+
dirty_accounts: result,
|
|
1967
|
+
}),
|
|
1968
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
async fn state_root_async(
|
|
1973
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1974
|
+
commit_key: CommitKey,
|
|
1975
|
+
current_hash: B256,
|
|
1976
|
+
) -> Result<String> {
|
|
1977
|
+
let mut lock = evm.lock().await;
|
|
1978
|
+
let result = lock.state_root(commit_key, current_hash);
|
|
1979
|
+
|
|
1980
|
+
match result {
|
|
1981
|
+
Ok(result) => Result::Ok(result),
|
|
1982
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
async fn logs_bloom_async(
|
|
1987
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
1988
|
+
commit_key: CommitKey,
|
|
1989
|
+
) -> Result<String> {
|
|
1990
|
+
let mut lock = evm.lock().await;
|
|
1991
|
+
let result = lock.logs_bloom(commit_key);
|
|
1992
|
+
|
|
1993
|
+
match result {
|
|
1994
|
+
Ok(result) => Result::Ok(result),
|
|
1995
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
async fn get_accounts_async(
|
|
2000
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2001
|
+
offset: u64,
|
|
2002
|
+
limit: u64,
|
|
2003
|
+
) -> Result<(Option<u64>, Vec<AccountInfoExtended>)> {
|
|
2004
|
+
let mut lock = evm.lock().await;
|
|
2005
|
+
let result = lock.get_accounts(offset, limit);
|
|
2006
|
+
|
|
2007
|
+
match result {
|
|
2008
|
+
Ok(result) => Result::Ok(result),
|
|
2009
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
async fn get_legacy_attributes_async(
|
|
2014
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2015
|
+
address: Address,
|
|
2016
|
+
legacy_address: Option<LegacyAddress>,
|
|
2017
|
+
) -> Result<Option<LegacyAccountAttributes>> {
|
|
2018
|
+
let mut lock = evm.lock().await;
|
|
2019
|
+
let result = lock.get_legacy_attributes(address, legacy_address);
|
|
2020
|
+
|
|
2021
|
+
match result {
|
|
2022
|
+
Ok(result) => Result::Ok(result),
|
|
2023
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
async fn get_legacy_cold_wallets_async(
|
|
2028
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2029
|
+
offset: u64,
|
|
2030
|
+
limit: u64,
|
|
2031
|
+
) -> Result<(Option<u64>, Vec<LegacyColdWallet>)> {
|
|
2032
|
+
let mut lock = evm.lock().await;
|
|
2033
|
+
let result = lock.get_legacy_cold_wallets(offset, limit);
|
|
2034
|
+
|
|
2035
|
+
match result {
|
|
2036
|
+
Ok(result) => Result::Ok(result),
|
|
2037
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
async fn get_receipts_async(
|
|
2042
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2043
|
+
offset: u64,
|
|
2044
|
+
limit: u64,
|
|
2045
|
+
) -> Result<(Option<u64>, Vec<(u64, Vec<(B256, TxReceipt)>)>)> {
|
|
2046
|
+
let mut lock = evm.lock().await;
|
|
2047
|
+
let result = lock.get_receipts(offset, limit);
|
|
2048
|
+
|
|
2049
|
+
match result {
|
|
2050
|
+
Ok(result) => Result::Ok(result),
|
|
2051
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
async fn get_receipts_by_block_number_async(
|
|
2056
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2057
|
+
block_number: u64,
|
|
2058
|
+
) -> Result<HashMap<B256, TxReceipt>> {
|
|
2059
|
+
let mut lock = evm.lock().await;
|
|
2060
|
+
let result = lock.get_receipts_by_block_number(block_number);
|
|
2061
|
+
|
|
2062
|
+
match result {
|
|
2063
|
+
Ok(result) => Result::Ok(result),
|
|
2064
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
async fn get_receipts_by_block_range_async(
|
|
2069
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2070
|
+
from_block_number: u64,
|
|
2071
|
+
to_block_number: u64,
|
|
2072
|
+
) -> Result<Vec<(u64, Vec<(B256, TxReceipt)>)>> {
|
|
2073
|
+
let mut lock = evm.lock().await;
|
|
2074
|
+
let result = lock.get_receipts_by_block_range(from_block_number, to_block_number);
|
|
2075
|
+
|
|
2076
|
+
match result {
|
|
2077
|
+
Ok(result) => Result::Ok(result),
|
|
2078
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
async fn get_receipt_async(
|
|
2083
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2084
|
+
block_number: u64,
|
|
2085
|
+
tx_hash: B256,
|
|
2086
|
+
) -> Result<Option<TxReceipt>> {
|
|
2087
|
+
let mut lock = evm.lock().await;
|
|
2088
|
+
let result = lock.get_receipt(block_number, tx_hash);
|
|
2089
|
+
|
|
2090
|
+
match result {
|
|
2091
|
+
Ok(result) => Result::Ok(result),
|
|
2092
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
async fn is_empty_async(evm: Arc<tokio::sync::Mutex<EvmInner>>) -> Result<bool> {
|
|
2097
|
+
let mut lock = evm.lock().await;
|
|
2098
|
+
let result = lock.is_empty();
|
|
2099
|
+
|
|
2100
|
+
match result {
|
|
2101
|
+
Ok(result) => Result::Ok(result),
|
|
2102
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
async fn get_state_async(evm: Arc<tokio::sync::Mutex<EvmInner>>) -> Result<(u64, u64)> {
|
|
2107
|
+
let mut lock = evm.lock().await;
|
|
2108
|
+
let result = lock.get_state();
|
|
2109
|
+
|
|
2110
|
+
match result {
|
|
2111
|
+
Ok(result) => Result::Ok(result),
|
|
2112
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
async fn get_block_header_data_async(
|
|
2117
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2118
|
+
block_number: u64,
|
|
2119
|
+
) -> Result<Option<BlockHeaderData>> {
|
|
2120
|
+
let mut lock = evm.lock().await;
|
|
2121
|
+
let result = lock.get_block_header_data(block_number);
|
|
2122
|
+
|
|
2123
|
+
match result {
|
|
2124
|
+
Ok(result) => Result::Ok(result),
|
|
2125
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
async fn get_block_number_by_hash_async(
|
|
2130
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2131
|
+
block_hash: B256,
|
|
2132
|
+
) -> Result<Option<u64>> {
|
|
2133
|
+
let mut lock = evm.lock().await;
|
|
2134
|
+
let result = lock.get_block_number_by_hash(block_hash);
|
|
2135
|
+
|
|
2136
|
+
match result {
|
|
2137
|
+
Ok(result) => Result::Ok(result),
|
|
2138
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
async fn get_commit_data_async(
|
|
2143
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2144
|
+
block_number: u64,
|
|
2145
|
+
) -> Result<Option<(ProofData, BlockHeaderData, Vec<TransactionData>)>> {
|
|
2146
|
+
let mut lock = evm.lock().await;
|
|
2147
|
+
let result = lock.get_commit_data(block_number);
|
|
2148
|
+
|
|
2149
|
+
match result {
|
|
2150
|
+
Ok(result) => Result::Ok(result),
|
|
2151
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
async fn get_commits_by_block_range_async(
|
|
2156
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2157
|
+
from_block_number: u64,
|
|
2158
|
+
to_block_number: u64,
|
|
2159
|
+
max_bytes: u64,
|
|
2160
|
+
) -> Result<Vec<(ProofData, BlockHeaderData, Vec<TransactionData>)>> {
|
|
2161
|
+
let mut lock = evm.lock().await;
|
|
2162
|
+
let result = lock.get_commits_by_block_range(from_block_number, to_block_number, max_bytes);
|
|
2163
|
+
|
|
2164
|
+
match result {
|
|
2165
|
+
Ok(result) => Result::Ok(result),
|
|
2166
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
async fn get_transaction_data_async(
|
|
2171
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2172
|
+
key: String,
|
|
2173
|
+
) -> Result<Option<TransactionData>> {
|
|
2174
|
+
let mut lock = evm.lock().await;
|
|
2175
|
+
let result = lock.get_transaction_data(key);
|
|
2176
|
+
|
|
2177
|
+
match result {
|
|
2178
|
+
Ok(result) => Result::Ok(result),
|
|
2179
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
async fn get_transaction_key_by_hash_async(
|
|
2184
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2185
|
+
tx_hash: B256,
|
|
2186
|
+
) -> Result<Option<String>> {
|
|
2187
|
+
let mut lock = evm.lock().await;
|
|
2188
|
+
let result = lock.get_transaction_key_by_hash(tx_hash);
|
|
2189
|
+
|
|
2190
|
+
match result {
|
|
2191
|
+
Ok(result) => Result::Ok(result),
|
|
2192
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
async fn snapshot_async(
|
|
2197
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2198
|
+
commit_key: CommitKey,
|
|
2199
|
+
) -> Result<()> {
|
|
2200
|
+
let mut lock = evm.lock().await;
|
|
2201
|
+
let result = lock.snapshot(commit_key);
|
|
2202
|
+
|
|
2203
|
+
match result {
|
|
2204
|
+
Ok(result) => Result::Ok(result),
|
|
2205
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
async fn rollback_async(
|
|
2210
|
+
evm: Arc<tokio::sync::Mutex<EvmInner>>,
|
|
2211
|
+
commit_key: CommitKey,
|
|
2212
|
+
) -> Result<()> {
|
|
2213
|
+
let mut lock = evm.lock().await;
|
|
2214
|
+
let result = lock.rollback(commit_key);
|
|
2215
|
+
|
|
2216
|
+
match result {
|
|
2217
|
+
Ok(result) => Result::Ok(result),
|
|
2218
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
async fn dispose_async(evm: Arc<tokio::sync::Mutex<EvmInner>>) -> Result<()> {
|
|
2223
|
+
let mut lock = evm.lock().await;
|
|
2224
|
+
let result = lock.dispose();
|
|
2225
|
+
|
|
2226
|
+
match result {
|
|
2227
|
+
Ok(result) => Result::Ok(result),
|
|
2228
|
+
Err(err) => Result::Err(serde::de::Error::custom(err)),
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
}
|