mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
sdk, blockchain, validator: removed slot stuff
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user