Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

Commit

Permalink
WIP on applying nit allocations
Browse files Browse the repository at this point in the history
  • Loading branch information
oleganza committed Jul 19, 2019
1 parent e67c59b commit 29a308b
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 13 deletions.
5 changes: 3 additions & 2 deletions zkvm/src/blockchain/block.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use merlin::Transcript;

use super::super::utreexo;
use crate::{MerkleTree, Tx, TxID};
use crate::{utreexo, MerkleTree, Predicate, Tx, TxID};

/// Identifier of the block, computed as a hash of the `BlockHeader`.
#[derive(Clone, Copy, PartialEq)]
Expand Down Expand Up @@ -33,6 +32,8 @@ pub struct BlockHeader {
pub struct Block {
/// Block header.
pub header: BlockHeader,
/// List of nit allocations
pub nits: Vec<(u64, Predicate)>,
/// List of transactions.
pub txs: Vec<Tx>,
/// UTXO proofs
Expand Down
4 changes: 4 additions & 0 deletions zkvm/src/blockchain/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ pub enum BlockchainError {
#[fail(display = "Inconsistent data in the block header.")]
InconsistentHeader,

/// Occurs when the block allocates incorrect amount of nits.
#[fail(display = "Invalid allocation of nits in the block.")]
InvalidNitAllocation,

/// Occurs when extension field is non-empty in v1 blocks.
#[fail(display = "Extension field must be empty in v1 blocks.")]
IllegalExtension,
Expand Down
3 changes: 1 addition & 2 deletions zkvm/src/blockchain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

mod block;
mod errors;
mod nits;
pub mod nits;
mod state;

#[cfg(test)]
mod tests;

pub use self::block::*;
pub use self::errors::*;
pub use self::nits::*;
pub use self::state::*;
3 changes: 2 additions & 1 deletion zkvm/src/blockchain/nits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use crate::{Anchor, Commitment, Contract, PortableItem, Predicate, Value};
/// Interval of halving the amount of issued nits, in ms.
pub const HALVING_INTERVAL: u64 = 4 * 365 * 24 * 3600 * 1000;

/// Number of units issued per ms, before halving.
/// Number of units issued per millisecond, before halvings.
/// This translates to 1 nit per second.
pub const UNITS_PER_MS: u64 = 1000;

/// Returns amount eligible for circulation between
Expand Down
80 changes: 73 additions & 7 deletions zkvm/src/blockchain/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ use core::borrow::Borrow;

use super::block::{Block, BlockHeader, BlockID};
use super::errors::BlockchainError;
use super::nits;
use crate::utreexo::{self, Catchup, Forest, WorkForest};
use crate::{ContractID, MerkleTree, Tx, TxEntry, TxHeader, VerifiedTx, Verifier};
use crate::{
Anchor, ContractID, MerkleTree, Predicate, Tx, TxEntry, TxHeader, VerifiedTx, Verifier,
};

/// State of the blockchain node.
#[derive(Clone)]
pub struct BlockchainState {
/// Initial block of the given network.
pub initial_id: BlockID,
/// Initial block header of the given network.
pub initial: BlockHeader,
/// Latest block header in the chain.
pub tip: BlockHeader,
/// The utreexo state.
Expand Down Expand Up @@ -44,7 +47,7 @@ impl BlockchainState {

let tip = BlockHeader::make_initial(timestamp_ms, utreexo.root());
let state = BlockchainState {
initial_id: tip.id(),
initial: tip.clone(),
tip,
utreexo,
catchup,
Expand All @@ -55,14 +58,27 @@ impl BlockchainState {

/// Applies the block to the current state and returns a new one.
pub fn apply_block(
&mut self,
&self,
block: &Block,
bp_gens: &BulletproofGens,
) -> Result<BlockchainState, BlockchainError> {
check_block_header(&block.header, &self.tip)?;

check_nit_allocation(
self,
block.header.timestamp_ms,
block.nits.iter().map(|(q, _)| *q),
)?;

let mut work_forest = self.utreexo.work_forest();

// Apply nit contracts to the utreexo
let nit_proofs = apply_nits(
block.header.prev,
block.nits.iter().map(|(qty, pred)| (*qty, pred.clone())),
&mut work_forest,
);

let txroot = apply_txs(
block.header.version,
block.header.timestamp_ms,
Expand All @@ -83,7 +99,7 @@ impl BlockchainState {
}

Ok(BlockchainState {
initial_id: self.initial_id,
initial: self.initial.clone(),
tip: block.header.clone(),
utreexo: new_forest,
catchup: new_catchup,
Expand All @@ -97,6 +113,7 @@ impl BlockchainState {
block_version: u64,
timestamp_ms: u64,
ext: Vec<u8>,
nits: Vec<(u64, Predicate)>,
txs: Vec<Tx>,
utxo_proofs: Vec<utreexo::Proof>,
bp_gens: &BulletproofGens,
Expand All @@ -109,9 +126,12 @@ impl BlockchainState {
timestamp_ms > self.tip.timestamp_ms,
BlockchainError::InconsistentHeader,
)?;
check_nit_allocation(self, timestamp_ms, nits.iter().map(|(q, _)| *q))?;

let mut work_forest = self.utreexo.work_forest();

let nit_proofs = apply_nits(self.tip.id(), nits.iter().map(|(qty, pred)| (*qty, pred.clone())), &mut work_forest);

let txroot = apply_txs(
block_version,
timestamp_ms,
Expand All @@ -123,6 +143,12 @@ impl BlockchainState {

let (new_forest, new_catchup) = work_forest.normalize();

// TBD: update nit proofs with new_catchup
// Need to keep around contract ids
// let nit_proofs = nit_proofs.into_iter().map(|proof| {
// new_catchup.update_proof()
// })

let utxoroot = new_forest.root();

let new_block = Block {
Expand All @@ -135,12 +161,13 @@ impl BlockchainState {
utxoroot,
ext,
},
nits,
txs,
all_utxo_proofs: utxo_proofs,
};

let new_state = BlockchainState {
initial_id: self.initial_id,
initial: self.initial.clone(),
tip: new_block.header.clone(),
utreexo: new_forest,
catchup: new_catchup,
Expand Down Expand Up @@ -188,6 +215,23 @@ fn apply_tx<P: Borrow<utreexo::Proof>>(
Ok(verified_tx)
}

/// Applies a list of new nit allocations to the state and
/// returns an iterator of the corresponding utxo proofs.
fn apply_nits(
prev_id: BlockID,
nits: impl IntoIterator<Item = (u64, Predicate)>,
mut work_forest: &mut WorkForest<ContractID>,
) -> Vec<utreexo::Proof> {
let mut transcript = Anchor::create_nit_anchoring_transcript(prev_id.0);

nits.into_iter()
.map(|(qty, pred)| {
let contract = nits::make_nit_contract(qty, pred, &mut transcript);
work_forest.insert(&contract.id())
})
.collect::<Vec<_>>()
}

/// Applies a list of transactions to the state and returns the txroot.
fn apply_txs<T: Borrow<Tx>, P: Borrow<utreexo::Proof>>(
block_version: u64,
Expand Down Expand Up @@ -217,6 +261,28 @@ fn apply_txs<T: Borrow<Tx>, P: Borrow<utreexo::Proof>>(
Ok(MerkleTree::root(b"ZkVM.txroot", &txids))
}

/// Checks that nits allocation is not exceeding the limit for the current blockchain state.
fn check_nit_allocation(
state: &BlockchainState,
new_timestamp_ms: u64,
allocations: impl Iterator<Item = u64>,
) -> Result<(), BlockchainError> {
let allowance = nits::block_allowance(
state.initial.timestamp_ms,
state.tip.timestamp_ms,
new_timestamp_ms,
);
// Note: we are checking each individual value before adding them up to prevent overflow.
let total = allocations.fold(Ok(0u64), |total, qty| {
total.and_then(|total| {
check(qty <= allowance, BlockchainError::InvalidNitAllocation)?;
Ok(total + qty)
})
})?;
check(total <= allowance, BlockchainError::InvalidNitAllocation)?;
Ok(())
}

/// Verifies consistency of the block header with respect to the previous block header.
fn check_block_header(
block_header: &BlockHeader,
Expand Down
2 changes: 1 addition & 1 deletion zkvm/src/blockchain/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn test_state_machine() {
};

let (block, future_state) = state
.make_block(1, 1, Vec::new(), vec![tx], proofs, &bp_gens)
.make_block(1, 1, Vec::new(), Vec::new(), vec![tx], proofs, &bp_gens)
.unwrap();

// Apply the block to the state
Expand Down

0 comments on commit 29a308b

Please sign in to comment.