sdk, blockchain, validator: removed slot stuff

This commit is contained in:
skoupidi
2024-02-01 19:18:42 +02:00
parent c99186cc73
commit f79bd2de18
10 changed files with 32 additions and 622 deletions

View File

@@ -59,7 +59,7 @@ impl Darkfid {
Err(_) => return JsonError::new(ParseError, None, id).into(),
};
let blocks = match self.validator.blockchain.get_blocks_by_slot(&[slot]) {
let blocks = match self.validator.blockchain.get_blocks_by_heights(&[slot]) {
Ok(v) => v,
Err(e) => {
error!(target: "darkfid::rpc::blockchain_get_slot", "Failed fetching block by slot: {}", e);

View File

@@ -69,7 +69,6 @@ impl Harness {
// Append genesis transactions and calculate their total
genesis_block.txs.push(genesis_mint_tx);
let genesis_txs_total = genesis_txs_total(&genesis_block.txs).await?;
genesis_block.slots[0].total_tokens = genesis_txs_total;
// Generate validators configuration
// NOTE: we are not using consensus constants here so we
@@ -129,7 +128,7 @@ impl Harness {
Ok(Self { config, vks, validator_config, alice, bob })
}
pub async fn validate_chains(&self, total_blocks: usize, total_slots: usize) -> Result<()> {
pub async fn validate_chains(&self, total_blocks: usize) -> Result<()> {
let alice = &self.alice.validator;
let bob = &self.bob.validator;
@@ -151,10 +150,6 @@ impl Harness {
assert_eq!(alice_blockchain_len, bob.blockchain.len());
assert_eq!(alice_blockchain_len, total_blocks);
let alice_slots_len = alice.blockchain.slots.len();
assert_eq!(alice_slots_len, bob.blockchain.slots.len());
assert_eq!(alice_slots_len, total_slots);
Ok(())
}

View File

@@ -28,7 +28,7 @@ use harness::{generate_node, Harness, HarnessConfig};
mod forks;
async fn sync_pos_blocks_real(ex: Arc<Executor<'static>>) -> Result<()> {
async fn sync_blocks_real(ex: Arc<Executor<'static>>) -> Result<()> {
init_logger();
// Initialize harness in testing mode
@@ -49,14 +49,14 @@ async fn sync_pos_blocks_real(ex: Arc<Executor<'static>>) -> Result<()> {
// Generate next block
//let block1 = th.generate_next_block(&previous).await?;
// Generate next block, with 4 empty slots inbetween
// Generate next block
//let block2 = th.generate_next_block(&block1).await?;
// Add it to nodes
//th.add_blocks(&vec![block1, block2]).await?;
// Validate chains
th.validate_chains(1, 1).await?;
th.validate_chains(1).await?;
// We are going to create a third node and try to sync from the previous two
let mut sync_settings =
@@ -74,22 +74,20 @@ async fn sync_pos_blocks_real(ex: Arc<Executor<'static>>) -> Result<()> {
let charlie = &charlie.validator;
charlie.validate_blockchain(vec![], pow_target, pow_fixed_difficulty).await?;
assert_eq!(alice.blockchain.len(), charlie.blockchain.len());
assert_eq!(alice.blockchain.slots.len(), charlie.blockchain.slots.len());
// Thanks for reading
Ok(())
}
#[test]
#[ignore]
fn sync_pos_blocks() -> Result<()> {
fn sync_blocks() -> Result<()> {
let ex = Arc::new(Executor::new());
let (signal, shutdown) = smol::channel::unbounded::<()>();
easy_parallel::Parallel::new().each(0..4, |_| smol::block_on(ex.run(shutdown.recv()))).finish(
|| {
smol::block_on(async {
sync_pos_blocks_real(ex.clone()).await.unwrap();
sync_blocks_real(ex.clone()).await.unwrap();
drop(signal);
})
},

View File

@@ -17,7 +17,6 @@
*/
use darkfi_sdk::{
blockchain::Slot,
crypto::{
schnorr::{SchnorrSecret, Signature},
SecretKey,
@@ -80,8 +79,6 @@ pub struct BlockInfo {
pub txs: Vec<Transaction>,
/// Block producer signature
pub signature: Signature,
/// Slots payload
pub slots: Vec<Slot>,
}
impl Default for BlockInfo {
@@ -91,28 +88,21 @@ impl Default for BlockInfo {
header: Header::default(),
txs: vec![Transaction::default()],
signature: Signature::dummy(),
slots: vec![Slot::default()],
}
}
}
impl BlockInfo {
pub fn new(
header: Header,
txs: Vec<Transaction>,
signature: Signature,
slots: Vec<Slot>,
) -> Self {
Self { header, txs, signature, slots }
pub fn new(header: Header, txs: Vec<Transaction>, signature: Signature) -> Self {
Self { header, txs, signature }
}
/// Generate an empty block for provided Header
/// and slots vector. Transactions and the producer
/// signature must be added after.
pub fn new_empty(header: Header, slots: Vec<Slot>) -> Self {
/// Generate an empty block for provided Header.
/// Transactions and the producer signature must be added after.
pub fn new_empty(header: Header) -> Self {
let txs = vec![];
let signature = Signature::dummy();
Self { header, txs, signature, slots }
Self { header, txs, signature }
}
/// A block's hash is the same as the hash of its header

View File

@@ -39,7 +39,7 @@ pub struct Header {
pub previous: blake3::Hash,
/// Epoch number
pub epoch: u64,
/// Block/Slot height
/// Block height
pub height: u64,
/// Block creation timestamp
pub timestamp: Timestamp,

View File

@@ -21,7 +21,6 @@ use std::sync::{Arc, Mutex};
use log::debug;
use sled::Transactional;
use darkfi_sdk::blockchain::Slot;
use darkfi_serial::{deserialize, serialize, Decodable};
use crate::{tx::Transaction, Error, Result};
@@ -37,10 +36,6 @@ pub use block_store::{
pub mod header_store;
pub use header_store::{Header, HeaderStore, HeaderStoreOverlay};
/// Slots storage implementation
pub mod slot_store;
pub use slot_store::{BlocksSlotsStore, BlocksSlotsStoreOverlay, SlotStore, SlotStoreOverlay};
/// Transactions related storage implementations
pub mod tx_store;
pub use tx_store::{PendingTxOrderStore, PendingTxStore, TxStore, TxStoreOverlay};
@@ -62,10 +57,6 @@ pub struct Blockchain {
pub blocks: BlockStore,
/// Block order sled tree
pub order: BlockOrderStore,
/// Slot sled tree
pub slots: SlotStore,
/// Blocks Slots sled tree
pub blocks_slots: BlocksSlotsStore,
/// Block height difficulties sled tree,
pub difficulties: BlockDifficultyStore,
/// Transactions sled tree
@@ -86,8 +77,6 @@ impl Blockchain {
let headers = HeaderStore::new(db)?;
let blocks = BlockStore::new(db)?;
let order = BlockOrderStore::new(db)?;
let slots = SlotStore::new(db)?;
let blocks_slots = BlocksSlotsStore::new(db)?;
let difficulties = BlockDifficultyStore::new(db)?;
let transactions = TxStore::new(db)?;
let pending_txs = PendingTxStore::new(db)?;
@@ -100,8 +89,6 @@ impl Blockchain {
headers,
blocks,
order,
slots,
blocks_slots,
difficulties,
transactions,
pending_txs,
@@ -144,17 +131,6 @@ impl Blockchain {
trees.push(self.order.0.clone());
batches.push(blocks_order_batch);
// Store block slots uids vector
let slots = block.slots.iter().map(|x| x.id).collect();
let blocks_slots_bactch = self.blocks_slots.insert_batch(&block_hash_vec, &[&slots])?;
trees.push(self.blocks_slots.0.clone());
batches.push(blocks_slots_bactch);
// Store block slots
let slots_batch = self.slots.insert_batch(&block.slots)?;
trees.push(self.slots.0.clone());
batches.push(slots_batch);
// Perform an atomic transaction over the trees and apply the batches.
self.atomic_write(&trees, &batches)?;
@@ -175,21 +151,6 @@ impl Blockchain {
return Ok(false)
}
// Check if we have block slots uids vector
let slots = match self.blocks_slots.get(&[blockhash], true) {
Ok(v) => v[0].clone().unwrap(),
Err(_) => return Ok(false),
};
let provided_block_slots: Vec<u64> = block.slots.iter().map(|x| x.id).collect();
if slots != provided_block_slots {
return Ok(false)
}
// Check if we have all slots
if self.slots.get(&slots, true).is_err() {
return Ok(false)
}
// Check provided info produces the same hash
Ok(blockhash == block.hash()?)
}
@@ -215,22 +176,17 @@ impl Blockchain {
let txs = self.transactions.get(&block.txs, true)?;
let txs = txs.iter().map(|x| x.clone().unwrap()).collect();
let slots = self.blocks_slots.get(&[block.hash()], true)?;
let slots = slots[0].clone().unwrap();
let slots = self.slots.get(&slots, true)?;
let block_slots = slots.iter().map(|x| x.clone().unwrap()).collect();
let info = BlockInfo::new(header, txs, block.signature, block_slots);
let info = BlockInfo::new(header, txs, block.signature);
ret.push(info);
}
Ok(ret)
}
/// Retrieve [`BlockInfo`]s by given slots. Does not fail if any of them are not found.
pub fn get_blocks_by_slot(&self, slots: &[u64]) -> Result<Vec<BlockInfo>> {
debug!(target: "blockchain", "get_blocks_by_slot(): {:?}", slots);
let blockhashes = self.order.get(slots, false)?;
/// Retrieve [`BlockInfo`]s by given heights. Does not fail if any of them are not found.
pub fn get_blocks_by_heights(&self, heights: &[u64]) -> Result<Vec<BlockInfo>> {
debug!(target: "blockchain", "get_blocks_by_heights(): {:?}", heights);
let blockhashes = self.order.get(heights, false)?;
let mut hashes = vec![];
for i in blockhashes.into_iter().flatten() {
@@ -240,10 +196,10 @@ impl Blockchain {
self.get_blocks_by_hash(&hashes)
}
/// Retrieve n blocks after given start slot.
pub fn get_blocks_after(&self, slot: u64, n: u64) -> Result<Vec<BlockInfo>> {
debug!(target: "blockchain", "get_blocks_after(): {} -> {}", slot, n);
let hashes = self.order.get_after(slot, n)?;
/// Retrieve n blocks after given start block height.
pub fn get_blocks_after(&self, height: u64, n: u64) -> Result<Vec<BlockInfo>> {
debug!(target: "blockchain", "get_blocks_after(): {} -> {}", height, n);
let hashes = self.order.get_after(height, n)?;
self.get_blocks_by_hash(&hashes)
}
@@ -262,12 +218,12 @@ impl Blockchain {
self.order.is_empty()
}
/// Retrieve genesis (first) block slot and hash.
/// Retrieve genesis (first) block height and hash.
pub fn genesis(&self) -> Result<(u64, blake3::Hash)> {
self.order.get_first()
}
/// Retrieve the last block slot and hash.
/// Retrieve the last block height and hash.
pub fn last(&self) -> Result<(u64, blake3::Hash)> {
self.order.get_last()
}
@@ -278,31 +234,9 @@ impl Blockchain {
Ok(self.get_blocks_by_hash(&[hash])?[0].clone())
}
/// Retrieve the last slot.
pub fn last_slot(&self) -> Result<Slot> {
self.slots.get_last()
}
/// Retrieve n slots after given start slot.
pub fn get_slots_after(&self, slot: u64, n: u64) -> Result<Vec<Slot>> {
debug!(target: "blockchain", "get_slots_after(): {} -> {}", slot, n);
self.slots.get_after(slot, n)
}
/// Retrieve [`Slot`]s by given ids. Does not fail if any of them are not found.
pub fn get_slots_by_id(&self, ids: &[u64]) -> Result<Vec<Option<Slot>>> {
debug!(target: "blockchain", "get_slots_by_id(): {:?}", ids);
self.slots.get(ids, true)
}
/// Check if the given [`Slot`] is in the database and all trees.
pub fn has_slot(&self, slot: &Slot) -> Result<bool> {
Ok(self.slots.get(&[slot.id], true).is_ok())
}
/// Check if block order for the given slot is in the database.
pub fn has_slot_order(&self, slot: u64) -> Result<bool> {
let vec = match self.order.get(&[slot], true) {
/// Check if block order for the given height is in the database.
pub fn has_height(&self, height: u64) -> Result<bool> {
let vec = match self.order.get(&[height], true) {
Ok(v) => v,
Err(_) => return Ok(false),
};
@@ -410,10 +344,6 @@ pub struct BlockchainOverlay {
pub blocks: BlockStoreOverlay,
/// Block order overlay
pub order: BlockOrderStoreOverlay,
/// Slots overlay
pub slots: SlotStoreOverlay,
/// Blocks slots overlay
pub blocks_slots: BlocksSlotsStoreOverlay,
/// Block height difficulties overlay,
pub difficulties: BlockDifficultyStoreOverlay,
/// Transactions overlay
@@ -431,8 +361,6 @@ impl BlockchainOverlay {
let headers = HeaderStoreOverlay::new(&overlay)?;
let blocks = BlockStoreOverlay::new(&overlay)?;
let order = BlockOrderStoreOverlay::new(&overlay)?;
let slots = SlotStoreOverlay::new(&overlay)?;
let blocks_slots = BlocksSlotsStoreOverlay::new(&overlay)?;
let difficulties = BlockDifficultyStoreOverlay::new(&overlay)?;
let transactions = TxStoreOverlay::new(&overlay)?;
let contracts = ContractStateStoreOverlay::new(&overlay)?;
@@ -443,8 +371,6 @@ impl BlockchainOverlay {
headers,
blocks,
order,
slots,
blocks_slots,
difficulties,
transactions,
contracts,
@@ -457,7 +383,7 @@ impl BlockchainOverlay {
self.order.is_empty()
}
/// Retrieve the last block slot and hash.
/// Retrieve the last block height and hash.
pub fn last(&self) -> Result<(u64, blake3::Hash)> {
self.order.get_last()
}
@@ -490,13 +416,6 @@ impl BlockchainOverlay {
// Store block order
self.order.insert(&[block.header.height], &block_hash_vec)?;
// Store block slots uids vector
let slots = block.slots.iter().map(|x| x.id).collect();
self.blocks_slots.insert(&block_hash_vec, &[&slots])?;
// Store block slots
self.slots.insert(&block.slots)?;
Ok(block_hash)
}
@@ -514,21 +433,6 @@ impl BlockchainOverlay {
return Ok(false)
}
// Check if we have block slots uids vector
let slots = match self.blocks_slots.get(&[blockhash], true) {
Ok(v) => v[0].clone().unwrap(),
Err(_) => return Ok(false),
};
let provided_block_slots: Vec<u64> = block.slots.iter().map(|x| x.id).collect();
if slots != provided_block_slots {
return Ok(false)
}
// Check if we have all slots
if self.slots.get(&slots, true).is_err() {
return Ok(false)
}
// Check provided info produces the same hash
Ok(blockhash == block.hash()?)
}
@@ -554,12 +458,7 @@ impl BlockchainOverlay {
let txs = self.transactions.get(&block.txs, true)?;
let txs = txs.iter().map(|x| x.clone().unwrap()).collect();
let slots = self.blocks_slots.get(&[block.hash()], true)?;
let slots = slots[0].clone().unwrap();
let slots = self.slots.get(&slots, true)?;
let block_slots = slots.iter().map(|x| x.clone().unwrap()).collect();
let info = BlockInfo::new(header, txs, block.signature, block_slots);
let info = BlockInfo::new(header, txs, block.signature);
ret.push(info);
}
@@ -585,8 +484,6 @@ impl BlockchainOverlay {
let headers = HeaderStoreOverlay::new(&overlay)?;
let blocks = BlockStoreOverlay::new(&overlay)?;
let order = BlockOrderStoreOverlay::new(&overlay)?;
let slots = SlotStoreOverlay::new(&overlay)?;
let blocks_slots = BlocksSlotsStoreOverlay::new(&overlay)?;
let difficulties = BlockDifficultyStoreOverlay::new(&overlay)?;
let transactions = TxStoreOverlay::new(&overlay)?;
let contracts = ContractStateStoreOverlay::new(&overlay)?;
@@ -597,8 +494,6 @@ impl BlockchainOverlay {
headers,
blocks,
order,
slots,
blocks_slots,
difficulties,
transactions,
contracts,

View File

@@ -1,353 +0,0 @@
/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2024 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/>.
*/
// [`Slot`] is defined in the sdk so contracts can use it
use darkfi_sdk::blockchain::Slot;
use darkfi_serial::{deserialize, serialize};
use crate::{Error, Result};
use super::{parse_record, parse_u64_key_record, SledDbOverlayPtr};
const SLED_SLOT_TREE: &[u8] = b"_slots";
/// The `SlotStore` is a `sled` tree storing the blockhains' slots,
/// where the key is the slot uid, and the value is is the serialized slot.
#[derive(Clone)]
pub struct SlotStore(pub sled::Tree);
impl SlotStore {
/// Opens a new or existing `SlotStore` on the given sled database.
pub fn new(db: &sled::Db) -> Result<Self> {
let tree = db.open_tree(SLED_SLOT_TREE)?;
Ok(Self(tree))
}
/// Insert a slice of [`Slot`] into the slot store.
pub fn insert(&self, slots: &[Slot]) -> Result<()> {
let batch = self.insert_batch(slots)?;
self.0.apply_batch(batch)?;
Ok(())
}
/// Generate the sled batch corresponding to an insert, so caller
/// can handle the write operation.
/// The slot id is used as the key, while value is the serialized [`Slot`] itself.
pub fn insert_batch(&self, slots: &[Slot]) -> Result<sled::Batch> {
let mut batch = sled::Batch::default();
for slot in slots {
let serialized = serialize(slot);
batch.insert(&slot.id.to_be_bytes(), serialized);
}
Ok(batch)
}
/// Check if the slot store contains a given id.
pub fn contains(&self, id: u64) -> Result<bool> {
Ok(self.0.contains_key(id.to_be_bytes())?)
}
/// Fetch given slots from the slot store.
/// The resulting vector contains `Option`, which is `Some` if the slot
/// was found in the slot store, 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, ids: &[u64], strict: bool) -> Result<Vec<Option<Slot>>> {
let mut ret = Vec::with_capacity(ids.len());
for id in ids {
if let Some(found) = self.0.get(id.to_be_bytes())? {
let slot = deserialize(&found)?;
ret.push(Some(slot));
} else {
if strict {
return Err(Error::SlotNotFound(*id))
}
ret.push(None);
}
}
Ok(ret)
}
/// Retrieve all slot from the slot store.
/// Be careful as this will try to load everything in memory.
pub fn get_all(&self) -> Result<Vec<Slot>> {
let mut slots = vec![];
for slot in self.0.iter() {
let (_, slot): (u64, Slot) = parse_u64_key_record(slot.unwrap())?;
slots.push(slot);
}
Ok(slots)
}
/// Fetch n slots 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 `SlotStore`.
pub fn get_after(&self, id: u64, n: u64) -> Result<Vec<Slot>> {
let mut ret = vec![];
let mut key = id;
let mut counter = 0;
while counter <= n {
if let Some(found) = self.0.get_gt(key.to_be_bytes())? {
let (id, slot) = parse_u64_key_record(found)?;
key = id;
ret.push(slot);
counter += 1;
continue
}
break
}
Ok(ret)
}
/// Fetch the last slot in the tree, based on the `Ord`
/// implementation for `Vec<u8>`. This should not be able to
/// fail because we initialize the store with the genesis slot.
pub fn get_last(&self) -> Result<Slot> {
let found = self.0.last()?.unwrap();
let slot = deserialize(&found.1)?;
Ok(slot)
}
/// Retrieve records count
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
/// Overlay structure over a [`SlotStore`] instance.
pub struct SlotStoreOverlay(SledDbOverlayPtr);
impl SlotStoreOverlay {
pub fn new(overlay: &SledDbOverlayPtr) -> Result<Self> {
overlay.lock().unwrap().open_tree(SLED_SLOT_TREE)?;
Ok(Self(overlay.clone()))
}
/// Insert a slice of [`Slot`] into the overlay.
/// The slot id is used as the key, while value is the serialized [`Slot`] itself.
pub fn insert(&self, slots: &[Slot]) -> Result<()> {
let mut lock = self.0.lock().unwrap();
for slot in slots {
let serialized = serialize(slot);
lock.insert(SLED_SLOT_TREE, &slot.id.to_be_bytes(), &serialized)?;
}
Ok(())
}
/// Fetch slot from the overlay by id.
pub fn get_by_id(&self, id: u64) -> Result<Vec<u8>> {
match self.0.lock().unwrap().get(SLED_SLOT_TREE, &id.to_be_bytes())? {
Some(found) => Ok(found.to_vec()),
None => Err(Error::SlotNotFound(id)),
}
}
/// Fetch given slots from the overlay.
/// The resulting vector contains `Option`, which is `Some` if the slot
/// was found in the overlay, 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, ids: &[u64], strict: bool) -> Result<Vec<Option<Slot>>> {
let mut ret = Vec::with_capacity(ids.len());
let lock = self.0.lock().unwrap();
for id in ids {
if let Some(found) = lock.get(SLED_SLOT_TREE, &id.to_be_bytes())? {
let slot = deserialize(&found)?;
ret.push(Some(slot));
} else {
if strict {
return Err(Error::SlotNotFound(*id))
}
ret.push(None);
}
}
Ok(ret)
}
/// Fetch the last slot from the overlay, based on the `Ord`
/// implementation for `Vec<u8>`.
pub fn get_last(&self) -> Result<Slot> {
let found = self.0.lock().unwrap().last(SLED_SLOT_TREE)?.unwrap();
let slot = deserialize(&found.1)?;
Ok(slot)
}
}
const SLED_BLOCK_SLOTS_TREE: &[u8] = b"_blocks_slots";
/// The `BlocksSlotsStore` is a `sled` tree storing all the blocks' corresponding slot
/// uids, meaning the slot numbers leading up to each block, where the key is the
/// blocks' hash, and value is the serialized slot uids vector.
#[derive(Clone)]
pub struct BlocksSlotsStore(pub sled::Tree);
impl BlocksSlotsStore {
/// Opens a new or existing `BlocksSlotsStore` on the given sled database.
pub fn new(db: &sled::Db) -> Result<Self> {
let tree = db.open_tree(SLED_BLOCK_SLOTS_TREE)?;
Ok(Self(tree))
}
/// Insert a slice of block hashes and their `u64` vectors into the store.
pub fn insert(&self, hashes: &[blake3::Hash], slots: &[&Vec<u64>]) -> Result<()> {
let batch = self.insert_batch(hashes, slots)?;
self.0.apply_batch(batch)?;
Ok(())
}
/// Generate the sled batch corresponding to an insert, so caller
/// can handle the write operation. The block hash is used as the key,
/// and the block slots serialized vector is used as value.
pub fn insert_batch(
&self,
hashes: &[blake3::Hash],
slots: &[&Vec<u64>],
) -> Result<sled::Batch> {
if hashes.len() != slots.len() {
return Err(Error::InvalidInputLengths)
}
let mut batch = sled::Batch::default();
for (i, hash) in hashes.iter().enumerate() {
let serialized = serialize(slots[i]);
batch.insert(hash.as_bytes(), serialized);
}
Ok(batch)
}
/// Check if the blocks slots store contains a given block hash.
pub fn contains(&self, blockhash: &blake3::Hash) -> Result<bool> {
Ok(self.0.contains_key(blockhash.as_bytes())?)
}
/// Fetch given blocks slots from the blocks slots store.
/// The resulting vector contains `Option`, which is `Some` if the block slots
/// were found in the blocks slots store, and otherwise it is `None`, if they have not.
/// The second parameter is a boolean which tells the function to fail in
/// case at least one block was not found.
pub fn get(
&self,
block_hashes: &[blake3::Hash],
strict: bool,
) -> Result<Vec<Option<Vec<u64>>>> {
let mut ret = Vec::with_capacity(block_hashes.len());
for hash in block_hashes {
if let Some(found) = self.0.get(hash.as_bytes())? {
let slots = deserialize(&found)?;
ret.push(Some(slots));
} else {
if strict {
let s = hash.to_hex().as_str().to_string();
return Err(Error::BlockSlotsNotFound(s))
}
ret.push(None);
}
}
Ok(ret)
}
/// Retrieve all blocks slots from the block store in the form of a tuple
/// (`hash`, `Vec<u64>`).
/// Be careful as this will try to load everything in memory.
pub fn get_all(&self) -> Result<Vec<(blake3::Hash, Vec<u64>)>> {
let mut blocks_slots = vec![];
for block_slots in self.0.iter() {
blocks_slots.push(parse_record(block_slots.unwrap())?);
}
Ok(blocks_slots)
}
}
/// Overlay structure over a [`BlocksSlotsStore`] instance.
pub struct BlocksSlotsStoreOverlay(SledDbOverlayPtr);
impl BlocksSlotsStoreOverlay {
pub fn new(overlay: &SledDbOverlayPtr) -> Result<Self> {
overlay.lock().unwrap().open_tree(SLED_BLOCK_SLOTS_TREE)?;
Ok(Self(overlay.clone()))
}
/// Insert a slice of block hashes and their `u64` vectors into the overlay.
/// The block hash is used as the key, and the block slots serialized vector
/// is used as value.
pub fn insert(&self, hashes: &[blake3::Hash], slots: &[&Vec<u64>]) -> Result<()> {
if hashes.len() != slots.len() {
return Err(Error::InvalidInputLengths)
}
let mut lock = self.0.lock().unwrap();
for (i, hash) in hashes.iter().enumerate() {
let serialized = serialize(slots[i]);
lock.insert(SLED_BLOCK_SLOTS_TREE, hash.as_bytes(), &serialized)?;
}
Ok(())
}
/// Fetch given blocks slots from the overlay.
/// The resulting vector contains `Option`, which is `Some` if the block slots
/// were found in the overlay, and otherwise it is `None`, if they have not.
/// The second parameter is a boolean which tells the function to fail in
/// case at least one block was not found.
pub fn get(
&self,
block_hashes: &[blake3::Hash],
strict: bool,
) -> Result<Vec<Option<Vec<u64>>>> {
let mut ret = Vec::with_capacity(block_hashes.len());
let lock = self.0.lock().unwrap();
for hash in block_hashes {
if let Some(found) = lock.get(SLED_BLOCK_SLOTS_TREE, hash.as_bytes())? {
let slots = deserialize(&found)?;
ret.push(Some(slots));
} else {
if strict {
let s = hash.to_hex().as_str().to_string();
return Err(Error::BlockSlotsNotFound(s))
}
ret.push(None);
}
}
Ok(ret)
}
}

View File

@@ -16,112 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#[cfg(feature = "async")]
use darkfi_serial::async_trait;
use darkfi_serial::{SerialDecodable, SerialEncodable};
use pasta_curves::{group::ff::Field, pallas};
/// Auxiliary structure used to keep track of slots' previous slot
/// relevant validation parameters.
#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)]
pub struct PreviousSlot {
/// Block producers count
pub producers: u64,
/// Existing forks last proposal/block hashes,
/// as observed by the validator
pub last_hashes: Vec<blake3::Hash>,
/// Existing forks second to last proposal/block hashes,
/// as observed by the validator
pub second_to_last_hashes: Vec<blake3::Hash>,
/// Feedback error
pub error: f64,
}
impl PreviousSlot {
pub fn new(
producers: u64,
last_hashes: Vec<blake3::Hash>,
second_to_last_hashes: Vec<blake3::Hash>,
error: f64,
) -> Self {
Self { producers, last_hashes, second_to_last_hashes, error }
}
}
impl Default for PreviousSlot {
/// Represents the genesis slot previous slot on current timestamp
fn default() -> Self {
Self::new(0, vec![], vec![], 0.0)
}
}
/// Auxiliary structure used to keep track of slot PID output.
#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)]
pub struct PidOutput {
/// Inverse probability `f` of becoming a block producer
pub f: f64,
/// Feedback error
pub error: f64,
/// Slot sigma1
pub sigma1: pallas::Base,
/// Slot sigma2
pub sigma2: pallas::Base,
}
impl PidOutput {
pub fn new(f: f64, error: f64, sigma1: pallas::Base, sigma2: pallas::Base) -> Self {
Self { f, error, sigma1, sigma2 }
}
}
impl Default for PidOutput {
/// Represents the genesis slot PID output on current timestamp
fn default() -> Self {
Self::new(0.0, 0.0, pallas::Base::ZERO, pallas::Base::ZERO)
}
}
/// Auxiliary structure used to keep track of slot validation parameters.
#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)]
pub struct Slot {
/// Slot UID
pub id: u64,
/// Previous slot information
pub previous: PreviousSlot,
/// Slot PID output
pub pid: PidOutput,
/// Last block/proposal nonce(eta)
pub last_nonce: pallas::Base,
/// Total tokens up until this slot
pub total_tokens: u64,
/// Slot reward
pub reward: u64,
}
impl Slot {
pub fn new(
id: u64,
previous: PreviousSlot,
pid: PidOutput,
last_nonce: pallas::Base,
total_tokens: u64,
reward: u64,
) -> Self {
Self { id, previous, pid, last_nonce, total_tokens, reward }
}
}
impl Default for Slot {
/// Represents the genesis slot on current timestamp
fn default() -> Self {
Self::new(0, PreviousSlot::default(), PidOutput::default(), pallas::Base::ZERO, 0, 0)
}
}
// TODO: This values are experimental, should be replaced with the proper ones once defined
pub const POW_CUTOFF: u64 = 1000000;
pub const POS_START: u64 = 1000001;
/// Auxiliary function to calculate provided block height block version.
/// Currently, a single version(1) exists.
pub fn block_version(_height: u64) -> u8 {

View File

@@ -97,7 +97,7 @@ impl Consensus {
);
// Generate the block
let mut block = BlockInfo::new_empty(header, vec![]);
let mut block = BlockInfo::new_empty(header);
// Add transactions to the block
block.append_txs(unproposed_txs)?;

View File

@@ -18,7 +18,7 @@
use std::sync::Arc;
use darkfi_sdk::{blockchain::Slot, crypto::PublicKey};
use darkfi_sdk::crypto::PublicKey;
use darkfi_serial::serialize_async;
use log::{debug, error, info, warn};
use num_bigint::BigUint;
@@ -468,15 +468,6 @@ impl Validator {
Ok(())
}
/// Append to canonical state received slot.
/// This should be only used for test purposes.
pub async fn receive_test_slot(&self, slot: &Slot) -> Result<()> {
debug!(target: "validator::receive_test_slot", "Appending slot to ledger");
self.blockchain.slots.insert(&[slot.clone()])?;
Ok(())
}
/// Validate a producer `Transaction` and apply it if valid.
/// In case the transactions fail, ir will be returned to the caller.
/// The function takes a boolean called `write` which tells it to actually write