sputnikvm_callback/
lib.rs1extern crate sputnikvm;
2extern crate bigint;
3
4use sputnikvm::{VM, AccountCommitment, RequireError, VMStatus, AccountChange, Log};
5use bigint::{Address, U256, M256, H256, Gas};
6use std::collections::HashSet;
7use std::collections::hash_map::Values;
8
9pub trait Callback {
10 fn balance(&self, Address) -> U256;
11 fn nonce(&self, Address) -> U256;
12 fn code(&self, Address) -> Vec<u8>;
13 fn storage(&self, Address, U256) -> M256;
14 fn exists(&self, Address) -> bool;
15 fn blockhash(&self, U256) -> H256;
16}
17
18pub struct CallbackVM<'a, V: VM, C: Callback + 'a>(V, &'a C);
19
20impl<'a, V: VM, C: Callback + 'a> CallbackVM<'a, V, C> {
21 pub fn new(vm: V, callback: &'a C) -> Self {
22 CallbackVM(vm, callback)
23 }
24
25 pub fn fire(&mut self) {
26 loop {
27 match self.0.fire() {
28 Ok(()) => break,
29 Err(RequireError::Account(address)) => {
30 if self.1.exists(address) {
31 let commit = AccountCommitment::Full {
32 address,
33 nonce: self.1.nonce(address),
34 balance: self.1.balance(address),
35 code: self.1.code(address),
36 };
37 self.0.commit_account(commit).unwrap();
38 } else {
39 self.0.commit_account(AccountCommitment::Nonexist(address)).unwrap();
40 }
41 },
42 Err(RequireError::AccountCode(address)) => {
43 if self.1.exists(address) {
44 let commit = AccountCommitment::Code {
45 address,
46 code: self.1.code(address),
47 };
48 self.0.commit_account(commit).unwrap();
49 } else {
50 self.0.commit_account(AccountCommitment::Nonexist(address)).unwrap();
51 }
52 },
53 Err(RequireError::AccountStorage(address, index)) => {
54 if self.1.exists(address) {
55 let commit = AccountCommitment::Storage {
56 address, index,
57 value: self.1.storage(address, index),
58 };
59 self.0.commit_account(commit).unwrap();
60 } else {
61 self.0.commit_account(AccountCommitment::Nonexist(address)).unwrap();
62 }
63 },
64 Err(RequireError::Blockhash(number)) => {
65 self.0.commit_blockhash(number, self.1.blockhash(number)).unwrap();
66 },
67 }
68 }
69 }
70
71 pub fn status(&self) -> VMStatus {
72 self.0.status()
73 }
74
75 pub fn accounts(&self) -> Values<Address, AccountChange> {
76 self.0.accounts()
77 }
78
79 pub fn used_addresses(&self) -> HashSet<Address> {
80 self.0.used_addresses()
81 }
82
83 pub fn out(&self) -> &[u8] {
84 self.0.out()
85 }
86
87 pub fn available_gas(&self) -> Gas {
88 self.0.available_gas()
89 }
90
91 pub fn refunded_gas(&self) -> Gas {
92 self.0.refunded_gas()
93 }
94
95 pub fn logs(&self) -> &[Log] {
96 self.0.logs()
97 }
98
99 pub fn removed(&self) -> &[Address] {
100 self.0.removed()
101 }
102}