Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor db error #69

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 6 additions & 7 deletions crates/floresta-chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,26 @@ version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["rlib"]
crate-type = ["cdylib", "rlib"]

[dependencies]
rustreexo = { git = "https://www.github.com/mit-dci/rustreexo" }
rustreexo = "0.1.0"
sha2 = "^0.10.6"
log = "0.4"
kv = "0.24.0"
bitcoin = { version = "0.29", features = [
"serde",
"no-std",
"bitcoinconsensus",
] }
], default-features = false }
spin = "0.9.8"
core2 = { version = "0.4.0", optional = true }
hashbrown = { version = "0.14.0", optional = true }
secp256k1 = { version = "*", features = ["alloc"] }
secp256k1 = { version = "*", features = ["alloc"], optional = true }
async-std = { version = "1.12.0", default-features = false, features = [
"std",
"futures-core",
] }
floresta-common = { path = "../floresta-common" }
floresta-common = { path = "../floresta-common", default-features = false }
futures = "0.3.28"
wasm-bindgen = "0.2.87"

Expand All @@ -37,4 +36,4 @@ zstd = "0.12.3"
hex = "0.4.3"

[features]
no-std = ["hashbrown", "core2"]
bitcoinconsensus = ["bitcoin/bitcoinconsensus"]
14 changes: 10 additions & 4 deletions crates/floresta-chain/src/pruned_utreexo/chain_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ use crate::prelude::*;
use crate::{read_lock, write_lock, Network};
use alloc::{borrow::ToOwned, fmt::format, string::ToString, vec::Vec};
use async_std::channel::Sender;
#[cfg(feature = "bitcoinconsensus")]
use bitcoin::bitcoinconsensus;

use bitcoin::{
bitcoinconsensus,
blockdata::constants::genesis_block,
consensus::{deserialize_partial, Decodable, Encodable},
hashes::{hex::FromHex, sha256},
Expand Down Expand Up @@ -71,6 +73,7 @@ impl<PersistedState: ChainStore> ChainState<PersistedState> {
_ => {}
}
}
#[cfg(feature = "bitcoinconsensus")]
/// Returns the validation flags, given the current block height
fn get_validation_flags(&self, height: u32) -> c_uint {
let chains_params = &read_lock!(self).consensus.parameters;
Expand Down Expand Up @@ -410,10 +413,10 @@ impl<PersistedState: ChainStore> ChainState<PersistedState> {
}

pub fn new(
chainstore: KvChainStore,
chainstore: PersistedState,
network: Network,
assume_valid: Option<BlockHash>,
) -> ChainState<KvChainStore> {
) -> ChainState<PersistedState> {
let genesis = genesis_block(network.into());
chainstore
.save_header(&super::chainstore::DiskBlockHeader::FullyValid(
Expand Down Expand Up @@ -661,7 +664,10 @@ impl<PersistedState: ChainStore> ChainState<PersistedState> {
// Validate block transactions
let subsidy = read_lock!(self).consensus.get_subsidy(height);
let verify_script = self.verify_script(height);
#[cfg(feature = "bitcoinconsensus")]
let flags = self.get_validation_flags(height);
#[cfg(not(feature = "bitcoinconsensus"))]
let flags = 0;
Consensus::verify_block_transactions(inputs, &block.txdata, subsidy, verify_script, flags)
.map_err(|_| BlockchainError::BlockValidationError(BlockValidationErrors::InvalidTx))?;
Ok(())
Expand Down Expand Up @@ -962,7 +968,7 @@ macro_rules! write_lock {
};
}

#[derive(Clone)]
#[derive(Clone, Debug)]
/// Internal representation of the chain we are in
pub struct BestChain {
/// Hash of the last block in the chain we believe has more work on
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use bitcoin::hashes::Hash;
use bitcoin::BlockHash;
use rustreexo::accumulator::stump::Stump;

use crate::{BestChain, ChainParams, ChainState, ChainStore};
use super::chain_state::{BestChain, ChainState};
use super::chainparams::ChainParams;
use super::chainstore::ChainStore;

#[derive(Clone, Debug)]
pub enum BlockchainBuilderError {
Expand Down
54 changes: 34 additions & 20 deletions crates/floresta-chain/src/pruned_utreexo/chainparams.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ use crate::prelude::*;
use alloc::vec::Vec;

use crate::Network;

#[cfg(feature = "bitcoinconsensus")]
use bitcoin::{
bitcoinconsensus::{VERIFY_NONE, VERIFY_P2SH, VERIFY_WITNESS},
blockdata::constants::{genesis_block, max_target},
hashes::hex::FromHex,
};

use bitcoin::{
blockdata::constants::{genesis_block, max_target},
util::uint::Uint256,
Block, BlockHash,
};
Expand Down Expand Up @@ -71,29 +76,38 @@ impl ChainParams {
}
}
}
#[cfg(feature = "bitcoinconsensus")]
fn get_exceptions() -> HashMap<BlockHash, c_uint> {
// For some reason, some blocks in the mainnet and testnet have different rules than it should
// be, so we need to keep a list of exceptions and treat them differently
let mut exceptions = HashMap::new();
exceptions.insert(
BlockHash::from_hex("00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22")
.unwrap(),
VERIFY_NONE,
); // BIP16 exception on main net
exceptions.insert(
BlockHash::from_hex("0000000000000000000f14c35b2d841e986ab5441de8c585d5ffe55ea1e395ad")
.unwrap(),
VERIFY_P2SH | VERIFY_WITNESS,
); // Taproot exception on main net
exceptions.insert(
BlockHash::from_hex("00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105")
.unwrap(),
VERIFY_NONE,
); // BIP16 exception on test net
exceptions
}

#[cfg(not(feature = "bitcoinconsensus"))]
fn get_exceptions() -> HashMap<BlockHash, c_uint> {
HashMap::new()
}
impl From<Network> for ChainParams {
fn from(net: Network) -> Self {
let genesis = genesis_block(net.into());
let max_target = ChainParams::max_target(net);
// For some reason, some blocks in the mainnet and testnet have different rules than it should
// be, so we need to keep a list of exceptions and treat them differently
let mut exceptions = HashMap::new();
exceptions.insert(
BlockHash::from_hex("00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22")
.unwrap(),
VERIFY_NONE,
); // BIP16 exception on main net
exceptions.insert(
BlockHash::from_hex("0000000000000000000f14c35b2d841e986ab5441de8c585d5ffe55ea1e395ad")
.unwrap(),
VERIFY_P2SH | VERIFY_WITNESS,
); // Taproot exception on main net
exceptions.insert(
BlockHash::from_hex("00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105")
.unwrap(),
VERIFY_NONE,
); // BIP16 exception on test net

let exceptions = get_exceptions();
match net {
Network::Bitcoin => ChainParams {
genesis,
Expand Down
43 changes: 22 additions & 21 deletions crates/floresta-chain/src/pruned_utreexo/chainstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
//! This is a basic kv database that stores all metadata about our blockchain and utreexo
//! state.
//! Author: Davidson Souza
type Result<T> = core::result::Result<T, kv::Error>;
use crate::prelude::*;

use bitcoin::{
Expand Down Expand Up @@ -110,24 +109,25 @@ impl Encodable for DiskBlockHeader {
}
use kv::{Config, Integer, Store};

use super::chain_state::BestChain;
use super::{chain_state::BestChain, error::DatabaseError};
pub trait ChainStore {
type Error: DatabaseError;
/// Saves the current state of our accumulator.
fn save_roots(&self, roots: Vec<u8>) -> Result<()>;
fn save_roots(&self, roots: Vec<u8>) -> Result<(), Self::Error>;
/// Loads the state of our accumulator.
fn load_roots(&self) -> Result<Option<Vec<u8>>>;
fn load_roots(&self) -> Result<Option<Vec<u8>>, Self::Error>;
/// Loads the blockchain height
fn load_height(&self) -> Result<Option<BestChain>>;
fn save_height(&self, height: &BestChain) -> Result<()>;
fn get_header(&self, block_hash: &BlockHash) -> Result<Option<DiskBlockHeader>>;
fn save_header(&self, header: &DiskBlockHeader) -> Result<()>;
fn get_block_hash(&self, height: u32) -> Result<Option<BlockHash>>;
fn flush(&self) -> Result<()>;
fn update_block_index(&self, height: u32, hash: BlockHash) -> Result<()>;
fn load_height(&self) -> Result<Option<BestChain>, Self::Error>;
fn save_height(&self, height: &BestChain) -> Result<(), Self::Error>;
fn get_header(&self, block_hash: &BlockHash) -> Result<Option<DiskBlockHeader>, Self::Error>;
fn save_header(&self, header: &DiskBlockHeader) -> Result<(), Self::Error>;
fn get_block_hash(&self, height: u32) -> Result<Option<BlockHash>, Self::Error>;
fn flush(&self) -> Result<(), Self::Error>;
fn update_block_index(&self, height: u32, hash: BlockHash) -> Result<(), Self::Error>;
}
pub struct KvChainStore(Store);
impl KvChainStore {
pub fn new(datadir: String) -> Result<KvChainStore> {
pub fn new(datadir: String) -> Result<KvChainStore, kv::Error> {
// Configure the database
let cfg = Config::new(datadir + "/chain_data").cache_capacity(100_000_000);

Expand All @@ -138,18 +138,19 @@ impl KvChainStore {
}
}
impl ChainStore for KvChainStore {
fn load_roots(&self) -> Result<Option<Vec<u8>>> {
type Error = kv::Error;
fn load_roots(&self) -> Result<Option<Vec<u8>>, Self::Error> {
let bucket = self.0.bucket::<&str, Vec<u8>>(None)?;
bucket.get(&"roots")
}
fn save_roots(&self, roots: Vec<u8>) -> Result<()> {
fn save_roots(&self, roots: Vec<u8>) -> Result<(), Self::Error> {
let bucket = self.0.bucket::<&str, Vec<u8>>(None)?;

bucket.set(&"roots", &roots)?;
Ok(())
}

fn load_height(&self) -> Result<Option<BestChain>> {
fn load_height(&self) -> Result<Option<BestChain>, Self::Error> {
let bucket = self.0.bucket::<&str, Vec<u8>>(None)?;
let height = bucket.get(&"height")?;

Expand All @@ -159,13 +160,13 @@ impl ChainStore for KvChainStore {
Ok(None)
}

fn save_height(&self, height: &BestChain) -> Result<()> {
fn save_height(&self, height: &BestChain) -> Result<(), Self::Error> {
let bucket = self.0.bucket::<&str, Vec<u8>>(None)?;
let height = serialize(height);
bucket.set(&"height", &height)?;
Ok(())
}
fn get_header(&self, block_hash: &BlockHash) -> Result<Option<DiskBlockHeader>> {
fn get_header(&self, block_hash: &BlockHash) -> Result<Option<DiskBlockHeader>, Self::Error> {
let bucket = self.0.bucket::<&[u8], Vec<u8>>(Some("header"))?;
let block_hash = serialize(&block_hash);

Expand All @@ -175,7 +176,7 @@ impl ChainStore for KvChainStore {
}
Ok(None)
}
fn flush(&self) -> Result<()> {
fn flush(&self) -> Result<(), Self::Error> {
// Flush the header bucket
let bucket = self.0.bucket::<&[u8], Vec<u8>>(Some("header"))?;
bucket.flush()?;
Expand All @@ -188,15 +189,15 @@ impl ChainStore for KvChainStore {

Ok(())
}
fn save_header(&self, header: &DiskBlockHeader) -> Result<()> {
fn save_header(&self, header: &DiskBlockHeader) -> Result<(), Self::Error> {
let ser_header = serialize(header);
let block_hash = serialize(&header.block_hash());
let bucket = self.0.bucket::<&[u8], Vec<u8>>(Some("header"))?;
bucket.set(&&*block_hash, &ser_header)?;
Ok(())
}

fn get_block_hash(&self, height: u32) -> Result<Option<BlockHash>> {
fn get_block_hash(&self, height: u32) -> Result<Option<BlockHash>, Self::Error> {
let bucket = self.0.bucket::<Integer, Vec<u8>>(Some("index"))?;
let block = bucket.get(&Integer::from(height))?;
if let Some(block) = block {
Expand All @@ -205,7 +206,7 @@ impl ChainStore for KvChainStore {
Ok(None)
}

fn update_block_index(&self, height: u32, hash: BlockHash) -> Result<()> {
fn update_block_index(&self, height: u32, hash: BlockHash) -> Result<(), Self::Error> {
let bucket = self.0.bucket::<Integer, Vec<u8>>(Some("index"))?;
let block_hash = serialize(&hash);

Expand Down
9 changes: 7 additions & 2 deletions crates/floresta-chain/src/pruned_utreexo/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ use core::ffi::c_uint;
use rustreexo::accumulator::{node_hash::NodeHash, proof::Proof, stump::Stump};
use sha2::{Digest, Sha512_256};

use crate::{BlockValidationErrors, BlockchainError, ChainParams};
use super::{
chainparams::ChainParams,
error::{BlockValidationErrors, BlockchainError},
};

/// This struct contains all the information and methods needed to validate a block,
/// it is used by the [ChainState] to validate blocks and transactions.
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -118,6 +122,7 @@ impl Consensus {
// Fee is the difference between inputs and outputs
fee += in_value - output_value;
// Verify the tx script
#[cfg(feature = "bitcoinconsensus")]
if verify_script {
transaction.verify_with_flags(|outpoint| utxos.remove(outpoint), flags)?;
}
Expand Down Expand Up @@ -180,7 +185,7 @@ impl Consensus {
.map(|hash| NodeHash::from(hash.into_inner()))
.collect::<Vec<_>>();
// Verify the proof of inclusion of the deleted nodes
if !proof.verify(&del_hashes, acc)? {
if !acc.verify(&proof, &del_hashes)? {
return Err(BlockValidationErrors::InvalidProof.into());
}
// Get inputs from the block, we'll need this HashSet to check if an output is spent
Expand Down
Loading
Loading