consensus: SlotCheckpoint struct created, blockchain: SlotCheckpointStore created

This commit is contained in:
aggstam
2022-11-29 16:02:01 +02:00
parent 6e895537c7
commit 0a030d7067
5 changed files with 174 additions and 2 deletions

View File

@@ -40,8 +40,8 @@ impl HeaderStore {
let store = Self(tree);
// In case the store is empty, initialize it with the genesis header.
let genesis_header = Header::genesis_header(genesis_ts, genesis_data);
if store.0.is_empty() {
let genesis_header = Header::genesis_header(genesis_ts, genesis_data);
store.insert(&[genesis_header])?;
}

View File

@@ -20,7 +20,7 @@ use darkfi_serial::serialize;
use log::debug;
use crate::{
consensus::{Block, BlockInfo},
consensus::{Block, BlockInfo, SlotCheckpoint},
util::time::Timestamp,
Error, Result,
};
@@ -28,6 +28,9 @@ use crate::{
pub mod blockstore;
pub use blockstore::{BlockOrderStore, BlockStore, HeaderStore};
pub mod slotcheckpointstore;
pub use slotcheckpointstore::SlotCheckpointStore;
pub mod nfstore;
pub use nfstore::NullifierStore;
@@ -51,6 +54,8 @@ pub struct Blockchain {
pub blocks: BlockStore,
/// Block order sled tree
pub order: BlockOrderStore,
/// Slot checkpoints sled tree
pub slot_checkpoints: SlotCheckpointStore,
/// Transactions sled tree
pub transactions: TxStore,
/// Nullifiers sled tree
@@ -69,6 +74,7 @@ impl Blockchain {
let headers = HeaderStore::new(db, genesis_ts, genesis_data)?;
let blocks = BlockStore::new(db, genesis_ts, genesis_data)?;
let order = BlockOrderStore::new(db, genesis_ts, genesis_data)?;
let slot_checkpoints = SlotCheckpointStore::new(db)?;
let transactions = TxStore::new(db)?;
let nullifiers = NullifierStore::new(db)?;
let merkle_roots = RootStore::new(db)?;
@@ -80,6 +86,7 @@ impl Blockchain {
headers,
blocks,
order,
slot_checkpoints,
transactions,
nullifiers,
merkle_roots,
@@ -211,4 +218,10 @@ impl Blockchain {
let block = blocks[0].clone().unwrap();
Ok((slot, block.lead_info.offset))
}
/// Retrieve n checkpoints after given start slot.
pub fn get_slot_checkpoints_after(&self, slot: u64, n: u64) -> Result<Vec<SlotCheckpoint>> {
debug!("get_slot_checkpoints_after(): {} -> {}", slot, n);
self.slot_checkpoints.get_after(slot, n)
}
}

View File

@@ -0,0 +1,130 @@
/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2022 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use darkfi_serial::{deserialize, serialize};
use crate::{consensus::SlotCheckpoint, Error, Result};
const SLED_SLOT_CHECKPOINT_TREE: &[u8] = b"_slot_checkpoints";
/// The `SlotCheckpointStore` is a `sled` tree storing the checkpoints of the
/// blockchain's slots, where the key is the slot uid, and the value is
/// is the serialized checkpoint.
#[derive(Clone)]
pub struct SlotCheckpointStore(sled::Tree);
impl SlotCheckpointStore {
/// Opens a new or existing `SlotCheckpointStore` on the given sled database.
pub fn new(db: &sled::Db) -> Result<Self> {
let tree = db.open_tree(SLED_SLOT_CHECKPOINT_TREE)?;
let store = Self(tree);
// In case the store is empty, initialize it with the genesis checkpoint.
if store.0.is_empty() {
let genesis_checkpoint = SlotCheckpoint::genesis_slot_checkpoint();
store.insert(&[genesis_checkpoint])?;
}
Ok(store)
}
/// Insert a slice of [`SlotCheckpoint`] into the slotcheckpointstore.
/// With sled, the operation is done as a batch.
/// The block slot is used as the key, while value is the serialized [`SlotCheckpoint`] itself.
pub fn insert(&self, checkpoints: &[SlotCheckpoint]) -> Result<()> {
let mut batch = sled::Batch::default();
for checkpoint in checkpoints {
let serialized = serialize(checkpoint);
batch.insert(&checkpoint.slot.to_be_bytes(), serialized);
}
self.0.apply_batch(batch)?;
Ok(())
}
/// Check if the slotcheckpointstore contains a given slot.
pub fn contains(&self, slot: u64) -> Result<bool> {
Ok(self.0.contains_key(slot.to_be_bytes())?)
}
/// Fetch given slots from the slotcheckpointstore.
/// The resulting vector contains `Option`, which is `Some` if the slot
/// was found in the slotcheckpointstore, and otherwise it is `None`, if it has not.
/// The second parameter is a boolean which tells the function to fail in
/// case at least one slot was not found.
pub fn get(&self, slots: &[u64], strict: bool) -> Result<Vec<Option<SlotCheckpoint>>> {
let mut ret = Vec::with_capacity(slots.len());
for slot in slots {
if let Some(found) = self.0.get(slot.to_be_bytes())? {
let checkpoint = deserialize(&found)?;
ret.push(Some(checkpoint));
} else {
if strict {
return Err(Error::SlotNotFound(*slot))
}
ret.push(None);
}
}
Ok(ret)
}
/// Retrieve all slot checkpointss from the slotcheckpointstore.
/// Be careful as this will try to load everything in memory.
pub fn get_all(&self) -> Result<Vec<SlotCheckpoint>> {
let mut slots = vec![];
for slot in self.0.iter() {
let (_, value) = slot.unwrap();
let checkpoint = deserialize(&value)?;
slots.push(checkpoint);
}
Ok(slots)
}
/// Fetch n slot checkpoints after given slot. In the iteration, if a slot is not
/// found, the iteration stops and the function returns what it has found
/// so far in the `SlotCheckpointStore`.
pub fn get_after(&self, slot: u64, n: u64) -> Result<Vec<SlotCheckpoint>> {
let mut ret = vec![];
let mut key = slot;
let mut counter = 0;
while counter <= n {
if let Some(found) = self.0.get_gt(key.to_be_bytes())? {
let key_bytes: [u8; 8] = found.0.as_ref().try_into().unwrap();
key = u64::from_be_bytes(key_bytes);
let checkpoint = deserialize(&found.1)?;
ret.push(checkpoint);
counter += 1;
continue
}
break
}
Ok(ret)
}
/// Retrieve records count
pub fn len(&self) -> usize {
self.0.len()
}
}

View File

@@ -29,6 +29,7 @@ pub use lead_info::{LeadInfo, LeadProof};
/// Consensus state
pub mod state;
pub use state::SlotCheckpoint;
/// Consensus validator state
pub mod validator;

View File

@@ -120,3 +120,31 @@ impl net::Message for ConsensusResponse {
"consensusresponse"
}
}
/// Auxiliary structure used to keep track of slot validation parameters.
#[derive(Debug, SerialEncodable, SerialDecodable)]
pub struct SlotCheckpoint {
/// Slot UID
pub slot: u64,
/// Slot eta
pub eta: pallas::Base,
/// Slot sigma1
pub sigma1: pallas::Base,
/// Slot sigma2
pub sigma2: pallas::Base,
}
impl SlotCheckpoint {
pub fn new(slot: u64, eta: pallas::Base, sigma1: pallas::Base, sigma2: pallas::Base) -> Self {
Self { slot, eta, sigma1, sigma2 }
}
/// Generate the genesis slot checkpoint.
pub fn genesis_slot_checkpoint() -> Self {
let eta = pallas::Base::zero();
let sigma1 = pallas::Base::zero();
let sigma2 = pallas::Base::zero();
Self::new(0, eta, sigma1, sigma2)
}
}