sputnikvm_stateful/
lib.rs

1#![deny(unused_import_braces, unused_imports,
2        unused_comparisons, unused_must_use,
3        unused_variables, non_shorthand_field_patterns,
4        unreachable_code)]
5
6extern crate trie;
7extern crate sputnikvm;
8extern crate sha3;
9extern crate block;
10extern crate rlp;
11extern crate bigint;
12
13use bigint::{H256, U256, M256, Address};
14use sputnikvm::{ValidTransaction, HeaderParams, Memory, TransactionVM, VM,
15                AccountCommitment, Patch, AccountState, AccountChange};
16use sputnikvm::errors::{PreExecutionError, RequireError};
17use sha3::{Keccak256, Digest};
18use trie::{FixedSecureTrie, DatabaseGuard, MemoryDatabase, Database, DatabaseOwned};
19use block::{Account, Transaction};
20use std::collections::HashMap;
21use std::cmp::min;
22use std::rc::Rc;
23use std::ops::Deref;
24
25pub struct LiteralAccount {
26    pub nonce: U256,
27    pub balance: U256,
28    pub storage: HashMap<U256, M256>,
29    pub code: Vec<u8>,
30}
31
32#[derive(Debug)]
33pub struct Stateful<'a, D: 'a> {
34    database: &'a D,
35    root: H256,
36}
37
38impl<'a, D: 'a> Clone for Stateful<'a, D> {
39    fn clone(&self) -> Self {
40        Self {
41            database: self.database.clone(),
42            root: self.root.clone(),
43        }
44    }
45}
46
47impl<'a, D> Stateful<'a, D> {
48    pub fn new(database: &'a D, root: H256) -> Self {
49        Self {
50            database,
51            root
52        }
53    }
54
55    pub fn empty(database: &'a D) -> Self {
56        Self::new(database, MemoryDatabase::new().create_empty().root())
57    }
58}
59
60impl<'b, D: DatabaseOwned> Stateful<'b, D> {
61    fn is_empty_hash(hash: H256) -> bool {
62        hash == H256::from(Keccak256::digest(&[]).as_slice())
63    }
64
65    pub fn database(&self) -> &'b D {
66        self.database
67    }
68
69    pub fn code(&self, hash: H256) -> Option<Vec<u8>> {
70        let code_hashes = self.database.create_guard();
71
72        if Self::is_empty_hash(hash) {
73            Some(Vec::new())
74        } else {
75            code_hashes.get(hash)
76        }
77    }
78
79    pub fn step<V: VM>(
80        &self, vm: &mut V, block_number: U256, most_recent_block_hashes: &[H256]
81    ) {
82        assert!(U256::from(most_recent_block_hashes.len()) >=
83                min(block_number, U256::from(256)));
84
85        let state = self.database.create_fixed_secure_trie(self.root);
86        let code_hashes = self.database.create_guard();
87
88        loop {
89            match vm.step() {
90                Ok(()) => break,
91                Err(RequireError::Account(address)) => {
92                    let account: Option<Account> = state.get(&address);
93
94                    match account {
95                        Some(account) => {
96                            let code = if Self::is_empty_hash(account.code_hash) {
97                                Vec::new()
98                            } else {
99                                code_hashes.get(account.code_hash).unwrap()
100                            };
101
102                            vm.commit_account(AccountCommitment::Full {
103                                nonce: account.nonce,
104                                address: address,
105                                balance: account.balance,
106                                code: Rc::new(code),
107                            }).unwrap();
108                        },
109                        None => {
110                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
111                        },
112                    }
113                },
114                Err(RequireError::AccountCode(address)) => {
115                    let account: Option<Account> = state.get(&address);
116
117                    match account {
118                        Some(account) => {
119                            let code = if Self::is_empty_hash(account.code_hash) {
120                                Vec::new()
121                            } else {
122                                code_hashes.get(account.code_hash).unwrap()
123                            };
124
125                            vm.commit_account(AccountCommitment::Code {
126                                address: address,
127                                code: Rc::new(code),
128                            }).unwrap();
129                        },
130                        None => {
131                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
132                        },
133                    }
134                },
135                Err(RequireError::AccountStorage(address, index)) => {
136                    let account: Option<Account> = state.get(&address);
137
138                    match account {
139                        Some(account) => {
140                            let storage = self.database.create_fixed_secure_trie(account.storage_root);
141                            let value = storage.get(&H256::from(index)).unwrap_or(M256::zero());
142
143                            vm.commit_account(AccountCommitment::Storage {
144                                address: address,
145                                index, value
146                            }).unwrap();
147                        },
148                        None => {
149                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
150                        },
151                    }
152                },
153                Err(RequireError::Blockhash(number)) => {
154                    let index = (block_number - number).as_usize();
155                    vm.commit_blockhash(number, most_recent_block_hashes[index]).unwrap();
156                },
157            }
158        }
159    }
160
161    pub fn call<M: Memory + Default, P: Patch>(
162        &self, transaction: ValidTransaction, block: HeaderParams,
163        most_recent_block_hashes: &[H256]
164    ) -> TransactionVM<M, P> {
165        assert!(U256::from(most_recent_block_hashes.len()) >=
166                min(block.number, U256::from(256)));
167
168        let mut vm = TransactionVM::new(transaction, block.clone());
169        let state = self.database.create_fixed_secure_trie(self.root);
170        let code_hashes = self.database.create_guard();
171
172        loop {
173            match vm.fire() {
174                Ok(()) => break,
175                Err(RequireError::Account(address)) => {
176                    let account: Option<Account> = state.get(&address);
177
178                    match account {
179                        Some(account) => {
180                            let code = if Self::is_empty_hash(account.code_hash) {
181                                Vec::new()
182                            } else {
183                                code_hashes.get(account.code_hash).unwrap()
184                            };
185
186                            vm.commit_account(AccountCommitment::Full {
187                                nonce: account.nonce,
188                                address: address,
189                                balance: account.balance,
190                                code: Rc::new(code),
191                            }).unwrap();
192                        },
193                        None => {
194                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
195                        },
196                    }
197                },
198                Err(RequireError::AccountCode(address)) => {
199                    let account: Option<Account> = state.get(&address);
200
201                    match account {
202                        Some(account) => {
203                            let code = if Self::is_empty_hash(account.code_hash) {
204                                Vec::new()
205                            } else {
206                                code_hashes.get(account.code_hash).unwrap()
207                            };
208
209                            vm.commit_account(AccountCommitment::Code {
210                                address: address,
211                                code: Rc::new(code),
212                            }).unwrap();
213                        },
214                        None => {
215                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
216                        },
217                    }
218                },
219                Err(RequireError::AccountStorage(address, index)) => {
220                    let account: Option<Account> = state.get(&address);
221
222                    match account {
223                        Some(account) => {
224                            let storage = self.database.create_fixed_secure_trie(account.storage_root);
225                            let value = storage.get(&H256::from(index)).unwrap_or(M256::zero());
226
227                            vm.commit_account(AccountCommitment::Storage {
228                                address: address,
229                                index, value
230                            }).unwrap();
231                        },
232                        None => {
233                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
234                        },
235                    }
236                },
237                Err(RequireError::Blockhash(number)) => {
238                    let index = (block.number - number).as_usize();
239                    vm.commit_blockhash(number, most_recent_block_hashes[index]).unwrap();
240                },
241            }
242        }
243
244        vm
245    }
246
247    pub fn sets(
248        &mut self, accounts: &[(Address, LiteralAccount)]
249    ) {
250        let mut state = self.database.create_fixed_secure_trie(self.root);
251        let mut code_hashes = self.database.create_guard();
252
253        for &(address, ref account) in accounts {
254            let mut storage_trie = self.database.create_fixed_secure_empty();
255            for (key, value) in &account.storage {
256                if *value == M256::zero() {
257                    storage_trie.remove(&H256::from(*key));
258                } else {
259                    storage_trie.insert(H256::from(*key), *value);
260                }
261            }
262
263            let code_hash = H256::from(Keccak256::digest(&account.code).as_slice());
264            code_hashes.set(code_hash, account.code.clone());
265
266            let account = Account {
267                nonce: account.nonce,
268                balance: account.balance,
269                storage_root: storage_trie.root(),
270                code_hash
271            };
272
273            state.insert(address, account);
274        }
275
276        self.root = state.root();
277    }
278
279    pub fn transit(
280        &mut self, accounts: &[AccountChange]
281    ) {
282        let mut state = self.database.create_fixed_secure_trie(self.root);
283        let mut code_hashes = self.database.create_guard();
284
285        for account in accounts {
286            match account.clone() {
287                AccountChange::Full {
288                    nonce, address, balance, changing_storage, code
289                } => {
290                    let changing_storage: HashMap<U256, M256> = changing_storage.into();
291
292                    let mut account: Account = state.get(&address).unwrap();
293
294                    let mut storage_trie = self.database.create_fixed_secure_trie(account.storage_root);
295                    for (key, value) in changing_storage {
296                        if value == M256::zero() {
297                            storage_trie.remove(&H256::from(key));
298                        } else {
299                            storage_trie.insert(H256::from(key), value);
300                        }
301                    }
302
303                    account.balance = balance;
304                    account.nonce = nonce;
305                    account.storage_root = storage_trie.root();
306                    assert!(account.code_hash == H256::from(Keccak256::digest(&code).as_slice()));
307
308                    state.insert(address, account);
309                },
310                AccountChange::IncreaseBalance(address, value) => {
311                    match state.get(&address) {
312                        Some(mut account) => {
313                            account.balance = account.balance + value;
314                            state.insert(address, account);
315                        },
316                        None => {
317                            let account = Account {
318                                nonce: U256::zero(),
319                                balance: value,
320                                storage_root: self.database.create_empty().root(),
321                                code_hash: H256::from(Keccak256::digest(&[]).as_slice())
322                            };
323                            state.insert(address, account);
324                        }
325                    }
326                },
327                AccountChange::Create {
328                    nonce, address, balance, storage, code
329                } => {
330                    let storage: HashMap<U256, M256> = storage.into();
331
332                    let mut storage_trie = self.database.create_fixed_secure_empty();
333                    for (key, value) in storage {
334                        if value == M256::zero() {
335                            storage_trie.remove(&H256::from(key));
336                        } else {
337                            storage_trie.insert(H256::from(key), value);
338                        }
339                    }
340
341                    let code_hash = H256::from(Keccak256::digest(&code).as_slice());
342                    code_hashes.set(code_hash, code.deref().clone());
343
344                    let account = Account {
345                        nonce: nonce,
346                        balance: balance,
347                        storage_root: storage_trie.root(),
348                        code_hash
349                    };
350
351                    state.insert(address, account);
352                },
353                AccountChange::Nonexist(address) => {
354                    state.remove(&address);
355                }
356            }
357        }
358
359        self.root = state.root();
360    }
361
362    pub fn execute<M: Memory + Default, P: Patch>(
363        &mut self, transaction: ValidTransaction, block: HeaderParams,
364        most_recent_block_hashes: &[H256]
365    ) -> TransactionVM<M, P> {
366        let vm = self.call::<_, P>(transaction, block, most_recent_block_hashes);
367        let mut accounts = Vec::new();
368        for account in vm.accounts() {
369            accounts.push(account.clone());
370        }
371        self.transit(&accounts);
372        vm
373    }
374
375    pub fn to_valid<P: Patch>(
376        &self, transaction: Transaction,
377    ) -> Result<ValidTransaction, PreExecutionError> {
378        let state = self.database.create_fixed_secure_trie(self.root);
379        let code_hashes = self.database.create_guard();
380        let mut account_state = AccountState::default();
381
382        loop {
383            match ValidTransaction::from_transaction::<P>(&transaction, &account_state) {
384                Ok(val) => return val,
385                Err(RequireError::Account(address)) => {
386                    let account: Option<Account> = state.get(&address);
387
388                    match account {
389                        Some(account) => {
390                            let code = if Self::is_empty_hash(account.code_hash) {
391                                Vec::new()
392                            } else {
393                                code_hashes.get(account.code_hash).unwrap()
394                            };
395
396                            account_state.commit(AccountCommitment::Full {
397                                nonce: account.nonce,
398                                address: address,
399                                balance: account.balance,
400                                code: Rc::new(code),
401                            }).unwrap();
402                        },
403                        None => {
404                            account_state.commit(AccountCommitment::Nonexist(address)).unwrap();
405                        },
406                    }
407                },
408                Err(RequireError::AccountCode(address)) => {
409                    let account: Option<Account> = state.get(&address);
410
411                    match account {
412                        Some(account) => {
413                            let code = if Self::is_empty_hash(account.code_hash) {
414                                Vec::new()
415                            } else {
416                                code_hashes.get(account.code_hash).unwrap()
417                            };
418
419                            account_state.commit(AccountCommitment::Code {
420                                address: address,
421                                code: Rc::new(code),
422                            }).unwrap();
423                        },
424                        None => {
425                            account_state.commit(AccountCommitment::Nonexist(address)).unwrap();
426                        },
427                    }
428                },
429                Err(RequireError::AccountStorage(address, index)) => {
430                    let account: Option<Account> = state.get(&address);
431
432                    match account {
433                        Some(account) => {
434                            let storage = self.database.create_fixed_secure_trie(account.storage_root);
435                            let value = storage.get(&H256::from(index)).unwrap_or(M256::zero());
436
437                            account_state.commit(AccountCommitment::Storage {
438                                address: address,
439                                index, value
440                            }).unwrap();
441                        },
442                        None => {
443                            account_state.commit(AccountCommitment::Nonexist(address)).unwrap();
444                        },
445                    }
446                },
447                Err(RequireError::Blockhash(_)) => {
448                    panic!()
449                },
450            }
451        }
452    }
453
454    pub fn root(&self) -> H256 {
455        self.root
456    }
457
458    pub fn state_of<'a>(&'a self, root: H256) -> FixedSecureTrie<<D as Database<'a>>::Guard, Address, Account> {
459        self.database.create_fixed_secure_trie::<Address, Account>(root)
460    }
461
462    pub fn state<'a>(&'a self) -> FixedSecureTrie<<D as Database<'a>>::Guard, Address, Account> {
463        self.state_of(self.root())
464    }
465
466    pub fn storage_state_of<'a>(&'a self, root: H256) -> FixedSecureTrie<<D as Database<'a>>::Guard, H256, M256> {
467        self.database.create_fixed_secure_trie::<H256, M256>(root)
468    }
469
470    pub fn storage_state<'a>(&'a self, address: Address) -> Option<FixedSecureTrie<<D as Database<'a>>::Guard, H256, M256>> {
471        let state = self.state();
472        let account = state.get(&address);
473
474        match account {
475            Some(account) => {
476                Some(self.storage_state_of(account.storage_root))
477            },
478            None => None,
479        }
480    }
481}
482
483pub type MemoryStateful<'a> = Stateful<'a, MemoryDatabase>;