mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
consensus: SlotCheckpoint struct created, blockchain: SlotCheckpointStore created
This commit is contained in:
@@ -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])?;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
130
src/blockchain/slotcheckpointstore.rs
Normal file
130
src/blockchain/slotcheckpointstore.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user