sputnikvm_callback/
lib.rs

1extern 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}