Browse files

Remove ChainState and ChainStateDelta

  • Loading branch information...
edolstra committed Jan 11, 2019
1 parent 401ffb6 commit 0e531983b56dc58e2b44252cbd75c146ef19275c
@@ -1,12 +1,9 @@
use address;
use block::*;
use cbor_event::{se, Len};
use chain_core::property::{Block, BlockDate};
use config::{GenesisData, ProtocolMagic};
use fee;
use hash;
use std::collections::BTreeMap;
use std::iter::FromIterator;
use tx::{self, TxOut, TxoPointer};

pub type Utxos = BTreeMap<TxoPointer, TxOut>;
@@ -73,145 +70,3 @@ impl ChainState {

impl chain_core::property::ChainState for ChainState {
type Block = super::Block;
type Error = Error;
type GenesisData = GenesisData;

fn new(genesis_data: &Self::GenesisData) -> Result<Self, Self::Error> {

fn apply_block(&mut self, block: &Self::Block) -> Result<(), Self::Error> {
self.verify_block(&, block)

fn get_last_block_id(&self) -> HeaderHash {

fn get_chain_length(&self) -> u64 {

type Delta = ClassicChainStateDelta;

fn diff(from: &Self, to: &Self) -> Result<Self::Delta, Self::Error> {
assert_ne!(from, to);

let (removed_utxos, added_utxos) =
super::super::util::diff_maps::diff_maps(&from.utxos, &to.utxos);

Ok(ClassicChainStateDelta {
base: from.last_block.clone(),
last_block: to.last_block.clone(),
last_date: to.last_date.unwrap().clone(),
last_boundary_block: to.last_boundary_block.clone().unwrap(),
slot_leaders: to.slot_leaders.clone(),
chain_length: to.chain_length,
nr_transactions: to.nr_transactions,
spent_txos: to.spent_txos,
removed_utxos: removed_utxos.into_iter().map(|x| x.clone()).collect(),
added_utxos: Utxos::from_iter(
added_utxos.into_iter().map(|(n, v)| (n.clone(), v.clone())),

fn apply_delta(&mut self, delta: Self::Delta) -> Result<(), Self::Error> {
assert_eq!(self.last_block, delta.base);
self.last_block = delta.last_block;
self.last_date = Some(delta.last_date);
self.last_boundary_block = Some(delta.last_boundary_block);
self.chain_length = delta.chain_length;
self.nr_transactions = delta.nr_transactions;
self.spent_txos = delta.spent_txos;
self.slot_leaders = delta.slot_leaders;

for txo_ptr in &delta.removed_utxos {
if self.utxos.remove(txo_ptr).is_none() {
panic!("chain state delta removes non-existent utxo {}", txo_ptr);

for (txo_ptr, txo) in delta.added_utxos {
if self.utxos.insert(txo_ptr, txo).is_some() {
panic!("chain state delta inserts duplicate utxo");


pub struct ClassicChainStateDelta {
base: HeaderHash,
last_block: HeaderHash,
last_date: super::BlockDate,
last_boundary_block: HeaderHash,
chain_length: u64,
nr_transactions: u64,
spent_txos: u64,
slot_leaders: Vec<address::StakeholderId>, // FIXME: get from last_boundary_block
removed_utxos: Vec<TxoPointer>,
added_utxos: Utxos,

const NR_FIELDS: u64 = 10;

impl chain_core::property::ChainStateDelta for ClassicChainStateDelta {}

impl chain_core::property::Serializable for ClassicChainStateDelta {
type Error = cbor_event::Error;

fn serialize<W: std::io::Write>(&self, mut writer: W) -> Result<(), Self::Error> {
let mut data = vec![];
let mut serializer = se::Serializer::new(&mut data);
se::serialize_fixed_array(self.slot_leaders.iter(), &mut serializer)?;
se::serialize_fixed_array(self.removed_utxos.iter(), &mut serializer)?;
se::serialize_fixed_map(self.added_utxos.iter(), &mut serializer)?;

fn deserialize<R: std::io::BufRead>(reader: R) -> Result<Self, Self::Error> {
let mut raw = cbor_event::de::Deserializer::from(reader);

raw.tuple(NR_FIELDS, "chain state delta")?;
let base = raw.deserialize()?;
let last_block = raw.deserialize()?;
let last_date = BlockDate::deserialize(raw.deserialize()?);
let last_boundary_block = raw.deserialize()?;
let chain_length = raw.deserialize()?;
let nr_transactions = raw.deserialize()?;
let spent_txos = raw.deserialize()?;
let slot_leaders = raw.deserialize()?;
let removed_utxos = raw.deserialize()?;
let added_utxos = raw.deserialize()?;

Ok(Self {
@@ -230,51 +230,6 @@ pub trait Serializable: Sized {

/// A trait representing the state of a chain at a particular point in
/// time. The chain state is initialized from GenesisData and is
/// updated by applying blocks.
/// The main purpose of this trait is to enable generic, efficient
/// storage of chain states for various types of chains. To support
/// efficient storage, ChainState requires implementations to support
/// a "diff" method that produces a ChainStateDelta between arbitrary
/// states. These ChainStateDeltas can be serialized and
/// deserialized. (See also ChainStateStore in the chain-storage
/// crate, which uses this trait.)
pub trait ChainState: std::marker::Sized + Clone + Eq {
type Block: Block;
type GenesisData;
type Delta: ChainStateDelta;
type Error: std::error::Error;

/// Create a new chain state object from genesis data. The chain
/// length will be 0.
fn new(genesis_data: &Self::GenesisData) -> Result<Self, Self::Error>;

/// Update the chain state by applying a new 'block'. If an error
/// occurs, the chain state must be unchanged. If it succeeds,
/// then the chain length will be increased by 1 and
/// self.get_last_block_id() ==
fn apply_block(&mut self, block: &Self::Block) -> Result<(), Self::Error>;

fn get_last_block_id(&self) -> <Self::Block as Block>::Id;

fn get_chain_length(&self) -> u64;

/// Compute a delta that transforms chain state 'from' into
/// 'to'. That is, it must be the case that 'to == from.apply_delta(diff(from, to))'.
fn diff(from: &Self, to: &Self) -> Result<Self::Delta, Self::Error>;

/// Apply a delta computed by 'diff'.
fn apply_delta(&mut self, delta: Self::Delta) -> Result<(), Self::Error>;

/// A trait representing a delta between ChainState objects. See
/// 'ChainState::diff()'.
pub trait ChainStateDelta: Serializable {
//fn merge(a: &Self, b: &Self) -> Self;

#[cfg(feature = "property-test-api")]
pub mod testing {
use super::*;

This file was deleted.

Oops, something went wrong.
Oops, something went wrong.

0 comments on commit 0e53198

Please sign in to comment.