2016-02-05 13:40:41 +01:00
|
|
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
|
|
|
// This file is part of Parity.
|
|
|
|
|
|
|
|
// Parity is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
|
|
|
// Parity is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2016-03-11 10:57:58 +01:00
|
|
|
use std::default::Default;
|
2015-12-19 13:35:26 +01:00
|
|
|
use sha3::*;
|
|
|
|
use hash::H256;
|
|
|
|
use bytes::*;
|
|
|
|
use rlp::*;
|
|
|
|
use hashdb::*;
|
|
|
|
|
|
|
|
/// Type of operation for the backing database - either a new node or a node deletion.
|
|
|
|
#[derive(Debug)]
|
|
|
|
enum Operation {
|
2016-10-26 13:53:47 +02:00
|
|
|
New(H256, DBValue),
|
2015-12-19 13:35:26 +01:00
|
|
|
Delete(H256),
|
|
|
|
}
|
|
|
|
|
2015-12-20 13:28:13 +01:00
|
|
|
/// How many insertions and removals were done in an `apply` operation.
|
2015-12-19 13:35:26 +01:00
|
|
|
pub struct Score {
|
2015-12-20 13:28:13 +01:00
|
|
|
/// Number of insertions.
|
2015-12-19 13:35:26 +01:00
|
|
|
pub inserts: usize,
|
2015-12-20 13:28:13 +01:00
|
|
|
/// Number of removals.
|
2015-12-19 13:35:26 +01:00
|
|
|
pub removes: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A journal of operations on the backing database.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Journal (Vec<Operation>);
|
|
|
|
|
2016-03-11 10:57:58 +01:00
|
|
|
impl Default for Journal {
|
|
|
|
fn default() -> Self {
|
|
|
|
Journal::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-19 13:35:26 +01:00
|
|
|
impl Journal {
|
|
|
|
/// Create a new, empty, object.
|
|
|
|
pub fn new() -> Journal { Journal(vec![]) }
|
|
|
|
|
|
|
|
/// Given the RLP that encodes a node, append a reference to that node `out` and leave `journal`
|
|
|
|
/// such that the reference is valid, once applied.
|
2016-10-26 13:53:47 +02:00
|
|
|
pub fn new_node(&mut self, rlp: DBValue, out: &mut RlpStream) {
|
2015-12-19 13:35:26 +01:00
|
|
|
if rlp.len() >= 32 {
|
|
|
|
let rlp_sha3 = rlp.sha3();
|
|
|
|
|
2016-10-26 13:53:47 +02:00
|
|
|
trace!("new_node: reference node {:?} => {:?}", rlp_sha3, &*rlp);
|
2015-12-19 13:35:26 +01:00
|
|
|
out.append(&rlp_sha3);
|
|
|
|
self.0.push(Operation::New(rlp_sha3, rlp));
|
|
|
|
}
|
|
|
|
else {
|
2016-10-26 13:53:47 +02:00
|
|
|
trace!("new_node: inline node {:?}", &*rlp);
|
2015-12-19 13:35:26 +01:00
|
|
|
out.append_raw(&rlp, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Given the RLP that encodes a now-unused node, leave `journal` in such a state that it is noted.
|
|
|
|
pub fn delete_node_sha3(&mut self, old_sha3: H256) {
|
|
|
|
trace!("delete_node: {:?}", old_sha3);
|
|
|
|
self.0.push(Operation::Delete(old_sha3));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Register an RLP-encoded node for deletion (given a slice), if it needs to be deleted.
|
|
|
|
pub fn delete_node(&mut self, old: &[u8]) {
|
|
|
|
let r = Rlp::new(old);
|
|
|
|
if r.is_data() && r.size() == 32 {
|
|
|
|
self.delete_node_sha3(r.as_val());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-20 13:28:13 +01:00
|
|
|
/// Apply this journal to the HashDB `db` and return the number of insertions and removals done.
|
2015-12-19 13:35:26 +01:00
|
|
|
pub fn apply(self, db: &mut HashDB) -> Score {
|
|
|
|
trace!("applying {:?} changes", self.0.len());
|
|
|
|
let mut ret = Score{inserts: 0, removes: 0};
|
2016-10-27 08:28:12 +02:00
|
|
|
for d in self.0 {
|
2015-12-19 13:35:26 +01:00
|
|
|
match d {
|
|
|
|
Operation::Delete(h) => {
|
|
|
|
trace!("TrieDBMut::apply --- {:?}", &h);
|
|
|
|
db.remove(&h);
|
|
|
|
ret.removes += 1;
|
|
|
|
},
|
|
|
|
Operation::New(h, d) => {
|
|
|
|
trace!("TrieDBMut::apply +++ {:?} -> {:?}", &h, d.pretty());
|
|
|
|
db.emplace(h, d);
|
|
|
|
ret.inserts += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret
|
|
|
|
}
|
|
|
|
}
|