@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.
@@ -0,0 +1,9 @@
1
+ use alloy_sol_types::sol;
2
+
3
+ sol! {
4
+ event Voted(address voter, address validator);
5
+ event Unvoted(address voter, address validator);
6
+
7
+ event UsernameRegistered(address addr, string username, string previousUsername);
8
+ event UsernameResigned(address addr, string username);
9
+ }
@@ -0,0 +1,544 @@
1
+ use std::collections::BTreeMap;
2
+
3
+ use heed::{RoTxn, RwTxn};
4
+ use revm::{
5
+ primitives::{Address, B256, U256},
6
+ state::AccountInfo,
7
+ };
8
+
9
+ use crate::{compression::CompactBincode, db::Error};
10
+
11
+ #[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
12
+ pub struct HistoricalAccountData {
13
+ pub balance: U256,
14
+ pub nonce: u64,
15
+ pub code_hash: B256,
16
+ }
17
+
18
+ impl From<AccountInfo> for HistoricalAccountData {
19
+ fn from(value: AccountInfo) -> Self {
20
+ HistoricalAccountData {
21
+ balance: value.balance,
22
+ nonce: value.nonce,
23
+ code_hash: value.code_hash,
24
+ }
25
+ }
26
+ }
27
+
28
+ pub struct AccountHistory {
29
+ capacity: u64,
30
+ }
31
+
32
+ impl AccountHistory {
33
+ pub fn new(capacity: u64) -> Self {
34
+ Self { capacity }
35
+ }
36
+
37
+ pub fn insert(
38
+ &self,
39
+ txn: &mut RwTxn,
40
+ database: &heed::Database<
41
+ heed::types::U64<heed::byteorder::BigEndian>,
42
+ CompactBincode<BTreeMap<Address, HistoricalAccountData>>,
43
+ >,
44
+ block_number: u64,
45
+ accounts: Vec<(Address, AccountInfo)>,
46
+ ) -> Result<(), Error> {
47
+ assert!(database.get(txn, &block_number)?.is_none());
48
+
49
+ let count = database.len(txn)?;
50
+ if count >= self.capacity {
51
+ // delete oldest entries
52
+ let range = ..=block_number.saturating_sub(self.capacity);
53
+ database.delete_range(txn, &range)?;
54
+ }
55
+
56
+ let data = accounts
57
+ .into_iter()
58
+ .map(|a| (a.0, HistoricalAccountData::from(a.1)))
59
+ .collect::<BTreeMap<Address, HistoricalAccountData>>();
60
+
61
+ database.put(txn, &block_number, &CompactBincode(&data))?;
62
+
63
+ Ok(())
64
+ }
65
+
66
+ pub fn get_by_block_and_address(
67
+ &self,
68
+ txn: &RoTxn,
69
+ database: &heed::Database<
70
+ heed::types::U64<heed::byteorder::BigEndian>,
71
+ CompactBincode<BTreeMap<Address, HistoricalAccountData>>,
72
+ >,
73
+ block_number: u64,
74
+ address: &Address,
75
+ ) -> Result<(Option<HistoricalAccountData>, bool), Error> {
76
+ let mut iter = database.rev_range(txn, &..=block_number)?;
77
+
78
+ let mut missing_fallback = false;
79
+
80
+ while let Some((_, history)) = iter.next().transpose()? {
81
+ if let Some(data) = history.get(address) {
82
+ return Ok((Some(data.clone()), false));
83
+ }
84
+
85
+ missing_fallback = true;
86
+ }
87
+
88
+ Ok((None, missing_fallback))
89
+ }
90
+ }
91
+
92
+ #[test]
93
+ fn test_account_history() {
94
+ let path = tempfile::Builder::new()
95
+ .prefix("evm.mdb")
96
+ .tempdir()
97
+ .unwrap();
98
+
99
+ let db = crate::db::PersistentDB::new(
100
+ crate::db::PersistentDBOptions::new(path.path().to_path_buf()).with_history_size(10),
101
+ )
102
+ .expect("database");
103
+
104
+ let history = AccountHistory::new(10);
105
+ let mut txn = db.env.write_txn().unwrap();
106
+
107
+ let history_db = &db.inner.borrow().accounts_history.unwrap();
108
+
109
+ // Block 1
110
+ history
111
+ .insert(
112
+ &mut txn,
113
+ history_db,
114
+ 1,
115
+ vec![
116
+ (
117
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
118
+ AccountInfo {
119
+ balance: U256::from(1),
120
+ nonce: 1,
121
+ ..Default::default()
122
+ },
123
+ ),
124
+ (
125
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
126
+ AccountInfo {
127
+ balance: U256::from(2),
128
+ nonce: 1,
129
+ ..Default::default()
130
+ },
131
+ ),
132
+ ],
133
+ )
134
+ .unwrap();
135
+
136
+ // Block 2
137
+ history
138
+ .insert(
139
+ &mut txn,
140
+ history_db,
141
+ 2,
142
+ vec![
143
+ (
144
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
145
+ AccountInfo {
146
+ balance: U256::from(2),
147
+ nonce: 1,
148
+ ..Default::default()
149
+ },
150
+ ),
151
+ (
152
+ revm::primitives::address!("0000000000000000000000000000000000000003"),
153
+ AccountInfo {
154
+ balance: U256::from(3),
155
+ nonce: 3,
156
+ ..Default::default()
157
+ },
158
+ ),
159
+ ],
160
+ )
161
+ .unwrap();
162
+
163
+ // Block 3 - 4 (empty)
164
+ history.insert(&mut txn, history_db, 3, vec![]).unwrap();
165
+ history.insert(&mut txn, history_db, 4, vec![]).unwrap();
166
+
167
+ // Block 5
168
+ history
169
+ .insert(
170
+ &mut txn,
171
+ history_db,
172
+ 5,
173
+ vec![
174
+ (
175
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
176
+ AccountInfo {
177
+ balance: U256::from(5),
178
+ nonce: 5,
179
+ ..Default::default()
180
+ },
181
+ ),
182
+ (
183
+ revm::primitives::address!("0000000000000000000000000000000000000004"),
184
+ AccountInfo {
185
+ balance: U256::from(4),
186
+ nonce: 4,
187
+ ..Default::default()
188
+ },
189
+ ),
190
+ ],
191
+ )
192
+ .unwrap();
193
+
194
+ // Assert Account 1 at respective blocks (1 - 5)
195
+ for (block_number, address, balance, nonce) in vec![
196
+ // Block 1
197
+ (
198
+ 1,
199
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
200
+ U256::from(1),
201
+ 1,
202
+ ),
203
+ // Block 2
204
+ (
205
+ 2,
206
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
207
+ U256::from(2),
208
+ 1,
209
+ ),
210
+ // Block 3 (unchanged since block_number 2)
211
+ (
212
+ 3,
213
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
214
+ U256::from(2),
215
+ 1,
216
+ ),
217
+ // Block 4 (unchanged since block_number 2)
218
+ (
219
+ 4,
220
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
221
+ U256::from(2),
222
+ 1,
223
+ ),
224
+ // Block 5
225
+ (
226
+ 5,
227
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
228
+ U256::from(5),
229
+ 5,
230
+ ),
231
+ ] {
232
+ let account = history
233
+ .get_by_block_and_address(&mut txn, history_db, block_number, &address)
234
+ .unwrap();
235
+
236
+ assert!(account.0.is_some_and(|a| a
237
+ == HistoricalAccountData {
238
+ balance: balance,
239
+ nonce: nonce,
240
+ code_hash: revm::primitives::KECCAK_EMPTY,
241
+ }));
242
+ assert_eq!(account.1, false);
243
+ }
244
+
245
+ // Assert Account 2 at respective block_numbers (1 - 5)
246
+ for (block_number, address, balance, nonce) in vec![
247
+ // Block 1
248
+ (
249
+ 1,
250
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
251
+ U256::from(2),
252
+ 1,
253
+ ),
254
+ // Block 2 (unchanged since block_number 1)
255
+ (
256
+ 2,
257
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
258
+ U256::from(2),
259
+ 1,
260
+ ),
261
+ // Block 3 (unchanged since block_number 1)
262
+ (
263
+ 3,
264
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
265
+ U256::from(2),
266
+ 1,
267
+ ),
268
+ // Block 4 (unchanged since block_number 1)
269
+ (
270
+ 4,
271
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
272
+ U256::from(2),
273
+ 1,
274
+ ),
275
+ // Block 5 (unchanged since block_number 1)
276
+ (
277
+ 5,
278
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
279
+ U256::from(2),
280
+ 1,
281
+ ),
282
+ ] {
283
+ let account = history
284
+ .get_by_block_and_address(&mut txn, history_db, block_number, &address)
285
+ .unwrap();
286
+
287
+ assert!(account.0.is_some_and(|a| a
288
+ == HistoricalAccountData {
289
+ balance: balance,
290
+ nonce: nonce,
291
+ code_hash: revm::primitives::KECCAK_EMPTY,
292
+ }));
293
+ assert_eq!(account.1, false);
294
+ }
295
+
296
+ // Assert Account 3 at respective block_numbers (1 - 5)
297
+ for (block_number, address) in vec![
298
+ // Block 1 - non existent
299
+ (
300
+ 1,
301
+ revm::primitives::address!("0000000000000000000000000000000000000003"),
302
+ ),
303
+ ] {
304
+ let account = history
305
+ .get_by_block_and_address(&mut txn, history_db, block_number, &address)
306
+ .unwrap();
307
+ assert_eq!(account, (None, true));
308
+ }
309
+
310
+ for (block_number, address, balance, nonce) in vec![
311
+ // Block 2
312
+ (
313
+ 2,
314
+ revm::primitives::address!("0000000000000000000000000000000000000003"),
315
+ U256::from(3),
316
+ 3,
317
+ ),
318
+ // Block 3 (unchanged since block_number 2)
319
+ (
320
+ 3,
321
+ revm::primitives::address!("0000000000000000000000000000000000000003"),
322
+ U256::from(3),
323
+ 3,
324
+ ),
325
+ // Block 4 (unchanged since block_number 2)
326
+ (
327
+ 4,
328
+ revm::primitives::address!("0000000000000000000000000000000000000003"),
329
+ U256::from(3),
330
+ 3,
331
+ ),
332
+ // Block 5 (unchanged since block_number 2)
333
+ (
334
+ 5,
335
+ revm::primitives::address!("0000000000000000000000000000000000000003"),
336
+ U256::from(3),
337
+ 3,
338
+ ),
339
+ ] {
340
+ let account = history
341
+ .get_by_block_and_address(&mut txn, history_db, block_number, &address)
342
+ .unwrap();
343
+
344
+ assert!(account.0.is_some_and(|a| a
345
+ == HistoricalAccountData {
346
+ balance: balance,
347
+ nonce: nonce,
348
+ code_hash: revm::primitives::KECCAK_EMPTY,
349
+ }));
350
+ assert_eq!(account.1, false);
351
+ }
352
+
353
+ // Assert Account 4 at respective block_numbers (1 - 5)
354
+ for (block_number, address) in vec![
355
+ // Block 1 - non existent
356
+ (
357
+ 1,
358
+ revm::primitives::address!("0000000000000000000000000000000000000004"),
359
+ ),
360
+ (
361
+ 2,
362
+ revm::primitives::address!("0000000000000000000000000000000000000004"),
363
+ ),
364
+ (
365
+ 3,
366
+ revm::primitives::address!("0000000000000000000000000000000000000004"),
367
+ ),
368
+ (
369
+ 4,
370
+ revm::primitives::address!("0000000000000000000000000000000000000004"),
371
+ ),
372
+ ] {
373
+ let account = history
374
+ .get_by_block_and_address(&mut txn, history_db, block_number, &address)
375
+ .unwrap();
376
+ assert!(account.0.is_none());
377
+ assert_eq!(account.1, true);
378
+ }
379
+
380
+ for (block_number, address, balance, nonce) in vec![
381
+ // Block 5
382
+ (
383
+ 5,
384
+ revm::primitives::address!("0000000000000000000000000000000000000004"),
385
+ U256::from(4),
386
+ 4,
387
+ ),
388
+ ] {
389
+ let account = history
390
+ .get_by_block_and_address(&mut txn, history_db, block_number, &address)
391
+ .unwrap();
392
+
393
+ assert!(account.0.is_some_and(|a| a
394
+ == HistoricalAccountData {
395
+ balance: balance,
396
+ nonce: nonce,
397
+ code_hash: revm::primitives::KECCAK_EMPTY,
398
+ }));
399
+ assert_eq!(account.1, false);
400
+ }
401
+ }
402
+
403
+ #[test]
404
+ fn test_accounts_history_capacity() {
405
+ let path = tempfile::Builder::new()
406
+ .prefix("evm.mdb")
407
+ .tempdir()
408
+ .unwrap();
409
+
410
+ let db = crate::db::PersistentDB::new(
411
+ crate::db::PersistentDBOptions::new(path.path().to_path_buf()).with_history_size(3),
412
+ )
413
+ .expect("database");
414
+
415
+ let history = AccountHistory::new(3);
416
+ let mut txn = db.env.write_txn().unwrap();
417
+
418
+ let history_db = &db.inner.borrow().accounts_history.unwrap();
419
+
420
+ for i in 0..5 {
421
+ println!("writing i... {}", i);
422
+ // Block 1
423
+ history
424
+ .insert(
425
+ &mut txn,
426
+ history_db,
427
+ i as u64,
428
+ vec![
429
+ (
430
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
431
+ AccountInfo {
432
+ balance: U256::from(i),
433
+ nonce: i,
434
+ ..Default::default()
435
+ },
436
+ ),
437
+ (
438
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
439
+ AccountInfo {
440
+ balance: U256::from(i + 2),
441
+ nonce: i + 2,
442
+ ..Default::default()
443
+ },
444
+ ),
445
+ ],
446
+ )
447
+ .unwrap();
448
+ }
449
+
450
+ // Assert accounts not available below capacity
451
+ for (block_number, address) in vec![
452
+ // Block 0
453
+ (
454
+ 0,
455
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
456
+ ),
457
+ // Block 1
458
+ (
459
+ 1,
460
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
461
+ ),
462
+ ] {
463
+ let account = history
464
+ .get_by_block_and_address(&mut txn, history_db, block_number, &address)
465
+ .unwrap();
466
+ assert_eq!(account, (None, false));
467
+ }
468
+
469
+ // Assert accounts found at respective block_numbers (2+)
470
+ for (block_number, address, balance, nonce) in vec![
471
+ // Block 2
472
+ (
473
+ 2,
474
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
475
+ U256::from(2),
476
+ 2,
477
+ ),
478
+ (
479
+ 2,
480
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
481
+ U256::from(4),
482
+ 4,
483
+ ),
484
+ // Block 3
485
+ (
486
+ 3,
487
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
488
+ U256::from(3),
489
+ 3,
490
+ ),
491
+ (
492
+ 3,
493
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
494
+ U256::from(5),
495
+ 5,
496
+ ),
497
+ // Block 4
498
+ (
499
+ 4,
500
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
501
+ U256::from(4),
502
+ 4,
503
+ ),
504
+ (
505
+ 4,
506
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
507
+ U256::from(6),
508
+ 6,
509
+ ),
510
+ ] {
511
+ let account = history
512
+ .get_by_block_and_address(&mut txn, history_db, block_number, &address)
513
+ .unwrap();
514
+
515
+ assert!(account.0.is_some_and(|a| a
516
+ == HistoricalAccountData {
517
+ balance: balance,
518
+ nonce: nonce,
519
+ code_hash: revm::primitives::KECCAK_EMPTY,
520
+ }));
521
+ assert!(account.1 == false);
522
+ }
523
+
524
+ // Write empty blocks until everything is evicted
525
+ for i in 5..10 {
526
+ // Block 1
527
+ history
528
+ .insert(&mut txn, history_db, i as u64, vec![])
529
+ .unwrap();
530
+ }
531
+
532
+ // Assert no accounts in history left
533
+ for i in 0..10 {
534
+ for address in vec![
535
+ revm::primitives::address!("0000000000000000000000000000000000000001"),
536
+ revm::primitives::address!("0000000000000000000000000000000000000002"),
537
+ ] {
538
+ let account = history
539
+ .get_by_block_and_address(&mut txn, history_db, i, &address)
540
+ .unwrap();
541
+ assert_eq!(account, (None, i >= 10 - history.capacity));
542
+ }
543
+ }
544
+ }
@@ -0,0 +1,153 @@
1
+ use alloy_primitives::wrap_fixed_bytes;
2
+ use bs58;
3
+ use revm::primitives::{Address, B256, U256};
4
+ use serde::{Deserialize, Serialize};
5
+ use sha2::{Digest, Sha256};
6
+
7
+ #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
8
+ pub struct LegacyColdWallet {
9
+ pub address: LegacyAddress,
10
+ pub balance: U256,
11
+ pub legacy_attributes: LegacyAccountAttributes,
12
+ pub merge_info: Option<(B256, Address)>,
13
+ }
14
+
15
+ #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
16
+ pub struct LegacyAccountAttributes {
17
+ pub legacy_nonce: Option<u64>,
18
+ pub second_public_key: Option<String>,
19
+ pub multi_signature: Option<LegacyMultiSignatureAttribute>,
20
+ }
21
+
22
+ impl LegacyAccountAttributes {
23
+ pub fn is_empty(&self) -> bool {
24
+ self.second_public_key.is_none() && self.multi_signature.is_none()
25
+ }
26
+ }
27
+
28
+ #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
29
+ pub struct LegacyMultiSignatureAttribute {
30
+ pub min: usize,
31
+ pub public_keys: Vec<String>,
32
+ }
33
+
34
+ #[derive(Clone, Copy, PartialEq, Eq, Debug)]
35
+ pub enum LegacyAddressError {
36
+ InvalidSize,
37
+ InvalidBase58,
38
+ InvalidChecksum,
39
+ InvalidBytes,
40
+ }
41
+
42
+ wrap_fixed_bytes!(
43
+ extra_derives: [],
44
+ // A legacy 21-byte ARK address
45
+ pub struct LegacyAddress<21>;
46
+ );
47
+
48
+ impl std::fmt::Display for LegacyAddress {
49
+ #[inline]
50
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51
+ let checksum = encode_base58check(&self[..]);
52
+ f.write_str(&checksum)
53
+ }
54
+ }
55
+
56
+ impl TryFrom<&str> for LegacyAddress {
57
+ type Error = LegacyAddressError;
58
+
59
+ #[inline]
60
+ fn try_from(value: &str) -> Result<Self, Self::Error> {
61
+ let decoded = decode_base58check(value)?;
62
+ Self::try_from(&decoded[..]).map_err(|_| LegacyAddressError::InvalidBytes)
63
+ }
64
+ }
65
+
66
+ #[inline]
67
+ fn decode_base58check(encoded: &str) -> Result<Vec<u8>, LegacyAddressError> {
68
+ let decoded = bs58::decode(encoded)
69
+ .into_vec()
70
+ .map_err(|e| e.to_string())
71
+ .map_err(|_| LegacyAddressError::InvalidBase58)?;
72
+
73
+ if decoded.len() < 4 {
74
+ return Err(LegacyAddressError::InvalidSize);
75
+ }
76
+
77
+ let (data, checksum) = decoded.split_at(decoded.len() - 4);
78
+ let computed_checksum = Sha256::digest(&Sha256::digest(data));
79
+ if &computed_checksum[..4] != checksum {
80
+ return Err(LegacyAddressError::InvalidChecksum);
81
+ }
82
+
83
+ Ok(data.to_vec())
84
+ }
85
+
86
+ #[inline]
87
+ fn encode_base58check(data: &[u8]) -> String {
88
+ let checksum = Sha256::digest(&Sha256::digest(data));
89
+ let mut extended_data = data.to_vec();
90
+ extended_data.extend_from_slice(&checksum[..4]);
91
+
92
+ bs58::encode(extended_data).into_string()
93
+ }
94
+
95
+ #[cfg(test)]
96
+ mod tests {
97
+ use crate::legacy::{
98
+ LegacyAddress, LegacyAddressError, decode_base58check, encode_base58check,
99
+ };
100
+
101
+ #[test]
102
+ fn test_encode() {
103
+ let address = "DJmvhhiQFSrEQCq9FUxvcLcpcBjx7K3yLt";
104
+
105
+ let decoded: [u8; 21] = [
106
+ 30, 149, 144, 208, 106, 80, 8, 63, 148, 59, 207, 233, 127, 161, 7, 27, 208, 185, 40,
107
+ 87, 19,
108
+ ];
109
+
110
+ let actual = encode_base58check(&decoded);
111
+ assert_eq!(actual, address);
112
+ }
113
+
114
+ #[test]
115
+ fn test_decode() {
116
+ let address = "DJmvhhiQFSrEQCq9FUxvcLcpcBjx7K3yLt";
117
+
118
+ let decoded: [u8; 21] = [
119
+ 30, 149, 144, 208, 106, 80, 8, 63, 148, 59, 207, 233, 127, 161, 7, 27, 208, 185, 40,
120
+ 87, 19,
121
+ ];
122
+
123
+ let actual = decode_base58check(address).expect("ok");
124
+ assert_eq!(actual, decoded);
125
+ }
126
+
127
+ #[test]
128
+ fn test_from_str() {
129
+ let address: LegacyAddress = "DJmvhhiQFSrEQCq9FUxvcLcpcBjx7K3yLt".try_into().expect("ok");
130
+
131
+ let decoded: [u8; 21] = [
132
+ 30, 149, 144, 208, 106, 80, 8, 63, 148, 59, 207, 233, 127, 161, 7, 27, 208, 185, 40,
133
+ 87, 19,
134
+ ];
135
+
136
+ assert_eq!(&address[..], decoded);
137
+ }
138
+
139
+ #[test]
140
+ fn test_decode_failure() {
141
+ let address = "_!@@@";
142
+ let err = decode_base58check(address).expect_err("must err");
143
+ assert_eq!(err, LegacyAddressError::InvalidBase58);
144
+
145
+ let address = "DJm";
146
+ let err = decode_base58check(address).expect_err("must err");
147
+ assert_eq!(err, LegacyAddressError::InvalidSize);
148
+
149
+ let address = "DjmvhhiqfSrEQCq9FUxvcLcpcBjx7K3yLt";
150
+ let err = decode_base58check(address).expect_err("must err");
151
+ assert_eq!(err, LegacyAddressError::InvalidChecksum);
152
+ }
153
+ }