Introduce `BitcoinResult`, use it instead of boolean returns in blockchain
This commit is contained in:
parent
426e1fc556
commit
8f826a959d
|
@ -0,0 +1,2 @@
|
||||||
|
target
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
use std::io::IoResult;
|
use std::io::IoResult;
|
||||||
use std::num::{Zero, from_u64};
|
use std::num::{Zero, from_u64};
|
||||||
|
|
||||||
|
use util::error::{BitcoinResult, SpvBadTarget, SpvBadProofOfWork};
|
||||||
use util::hash::Sha256dHash;
|
use util::hash::Sha256dHash;
|
||||||
use util::uint::Uint256;
|
use util::uint::Uint256;
|
||||||
use network::serialize::{Serializable, SerializeIter, VarInt};
|
use network::serialize::{Serializable, SerializeIter, VarInt};
|
||||||
|
@ -95,13 +96,13 @@ impl BlockHeader {
|
||||||
/// Performs an SPV validation of a block, which confirms that the proof-of-work
|
/// Performs an SPV validation of a block, which confirms that the proof-of-work
|
||||||
/// is correct, but does not verify that the transactions are valid or encoded
|
/// is correct, but does not verify that the transactions are valid or encoded
|
||||||
/// correctly.
|
/// correctly.
|
||||||
pub fn spv_validate(&self, required_target: &Uint256) -> bool {
|
pub fn spv_validate(&self, required_target: &Uint256) -> BitcoinResult<()> {
|
||||||
let ref target = self.target();
|
let ref target = self.target();
|
||||||
if target != required_target {
|
if target != required_target {
|
||||||
return false;
|
return Err(SpvBadTarget);
|
||||||
}
|
}
|
||||||
let ref hash = self.hash().as_uint256();
|
let ref hash = self.hash().as_uint256();
|
||||||
hash <= target
|
if hash <= target { Ok(()) } else { Err(SpvBadProofOfWork) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the total work of the block
|
/// Returns the total work of the block
|
||||||
|
|
|
@ -33,6 +33,7 @@ use blockdata::transaction::Transaction;
|
||||||
use blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN, max_target};
|
use blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN, max_target};
|
||||||
use network::serialize::{Serializable, SerializeIter};
|
use network::serialize::{Serializable, SerializeIter};
|
||||||
use util::BitArray;
|
use util::BitArray;
|
||||||
|
use util::error::{BitcoinResult, BlockNotFound, DuplicateHash, PrevHashNotFound};
|
||||||
use util::uint::Uint256;
|
use util::uint::Uint256;
|
||||||
use util::hash::Sha256dHash;
|
use util::hash::Sha256dHash;
|
||||||
use util::misc::prepend_err;
|
use util::misc::prepend_err;
|
||||||
|
@ -389,7 +390,7 @@ impl Blockchain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_txdata(&mut self, hash: &Uint256, txdata: Vec<Transaction>, has_txdata: bool) -> bool {
|
fn replace_txdata(&mut self, hash: &Uint256, txdata: Vec<Transaction>, has_txdata: bool) -> BitcoinResult<()> {
|
||||||
match self.tree.lookup_mut(hash, 256) {
|
match self.tree.lookup_mut(hash, 256) {
|
||||||
Some(existing_block) => {
|
Some(existing_block) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -417,33 +418,33 @@ impl Blockchain {
|
||||||
*mutable_bool = has_txdata;
|
*mutable_bool = has_txdata;
|
||||||
forget(mutable_bool);
|
forget(mutable_bool);
|
||||||
}
|
}
|
||||||
return true
|
Ok(())
|
||||||
},
|
},
|
||||||
None => return false
|
None => Err(BlockNotFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locates a block in the chain and overwrites its txdata
|
/// Locates a block in the chain and overwrites its txdata
|
||||||
pub fn add_txdata(&mut self, block: Block) -> bool {
|
pub fn add_txdata(&mut self, block: Block) -> BitcoinResult<()> {
|
||||||
self.replace_txdata(&block.header.hash().as_uint256(), block.txdata, true)
|
self.replace_txdata(&block.header.hash().as_uint256(), block.txdata, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locates a block in the chain and removes its txdata
|
/// Locates a block in the chain and removes its txdata
|
||||||
pub fn remove_txdata(&mut self, hash: Sha256dHash) -> bool {
|
pub fn remove_txdata(&mut self, hash: Sha256dHash) -> BitcoinResult<()> {
|
||||||
self.replace_txdata(&hash.as_uint256(), vec![], false)
|
self.replace_txdata(&hash.as_uint256(), vec![], false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a block header to the chain
|
/// Adds a block header to the chain
|
||||||
pub fn add_header(&mut self, header: BlockHeader) -> bool {
|
pub fn add_header(&mut self, header: BlockHeader) -> BitcoinResult<()> {
|
||||||
self.real_add_block(Block { header: header, txdata: vec![] }, false)
|
self.real_add_block(Block { header: header, txdata: vec![] }, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a block to the chain
|
/// Adds a block to the chain
|
||||||
pub fn add_block(&mut self, block: Block) -> bool {
|
pub fn add_block(&mut self, block: Block) -> BitcoinResult<()> {
|
||||||
self.real_add_block(block, true)
|
self.real_add_block(block, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn real_add_block(&mut self, block: Block, has_txdata: bool) -> bool {
|
fn real_add_block(&mut self, block: Block, has_txdata: bool) -> BitcoinResult<()> {
|
||||||
// get_prev optimizes the common case where we are extending the best tip
|
// get_prev optimizes the common case where we are extending the best tip
|
||||||
fn get_prev<'a>(chain: &'a Blockchain, hash: Sha256dHash) -> Option<&'a Rc<BlockchainNode>> {
|
fn get_prev<'a>(chain: &'a Blockchain, hash: Sha256dHash) -> Option<&'a Rc<BlockchainNode>> {
|
||||||
if hash == chain.best_hash { return Some(&chain.best_tip); }
|
if hash == chain.best_hash { return Some(&chain.best_tip); }
|
||||||
|
@ -454,7 +455,7 @@ impl Blockchain {
|
||||||
// and this may also happen in case of a reorg.
|
// and this may also happen in case of a reorg.
|
||||||
if self.tree.lookup(&block.header.hash().as_uint256(), 256).is_some() {
|
if self.tree.lookup(&block.header.hash().as_uint256(), 256).is_some() {
|
||||||
println!("Warning: tried to add block {} twice!", block.header.hash());
|
println!("Warning: tried to add block {} twice!", block.header.hash());
|
||||||
return true;
|
return Err(DuplicateHash);
|
||||||
}
|
}
|
||||||
// Construct node, if possible
|
// Construct node, if possible
|
||||||
let rc_block = match get_prev(self, block.header.prev_blockhash) {
|
let rc_block = match get_prev(self, block.header.prev_blockhash) {
|
||||||
|
@ -500,15 +501,12 @@ impl Blockchain {
|
||||||
ret
|
ret
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
println!("TODO: couldn't add block");
|
return Err(PrevHashNotFound);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// spv validate the block
|
// spv validate the block
|
||||||
if !rc_block.block.header.spv_validate(&rc_block.required_difficulty) {
|
try!(rc_block.block.header.spv_validate(&rc_block.required_difficulty));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert the new block
|
// Insert the new block
|
||||||
self.tree.insert(&rc_block.block.header.hash().as_uint256(), 256, rc_block.clone());
|
self.tree.insert(&rc_block.block.header.hash().as_uint256(), 256, rc_block.clone());
|
||||||
|
@ -516,7 +514,7 @@ impl Blockchain {
|
||||||
if rc_block.total_work > self.best_tip.total_work {
|
if rc_block.total_work > self.best_tip.total_work {
|
||||||
self.set_best_tip(rc_block);
|
self.set_best_tip(rc_block);
|
||||||
}
|
}
|
||||||
return true;
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the best tip (not public)
|
/// Sets the best tip (not public)
|
||||||
|
|
|
@ -23,7 +23,6 @@ use std::io::timer;
|
||||||
|
|
||||||
use network::message::{NetworkMessage, Verack};
|
use network::message::{NetworkMessage, Verack};
|
||||||
use network::socket::Socket;
|
use network::socket::Socket;
|
||||||
use network::constants;
|
|
||||||
|
|
||||||
/// A message which can be sent on the Bitcoin network
|
/// A message which can be sent on the Bitcoin network
|
||||||
pub trait Listener {
|
pub trait Listener {
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
// Rust Bitcoin Library
|
||||||
|
// Written in 2014 by
|
||||||
|
// Andrew Poelstra <apoelstra@wpsoftware.net>
|
||||||
|
//
|
||||||
|
// To the extent possible under law, the author(s) have dedicated all
|
||||||
|
// copyright and related and neighboring rights to this software to
|
||||||
|
// the public domain worldwide. This software is distributed without
|
||||||
|
// any warranty.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the CC0 Public Domain Dedication
|
||||||
|
// along with this software.
|
||||||
|
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
//! # Error codes
|
||||||
|
//!
|
||||||
|
//! Various utility functions
|
||||||
|
|
||||||
|
use std::io::IoError;
|
||||||
|
|
||||||
|
/// A success/failure return value
|
||||||
|
pub type BitcoinResult<T> = Result<T, BitcoinError>;
|
||||||
|
|
||||||
|
/// A general error code
|
||||||
|
#[deriving(PartialEq, Eq, Show, Clone)]
|
||||||
|
pub enum BitcoinError {
|
||||||
|
/// An I/O error
|
||||||
|
IoError(IoError),
|
||||||
|
/// An object was attempted to be added twice
|
||||||
|
DuplicateHash,
|
||||||
|
/// Some operation was attempted on a block (or blockheader) that doesn't exist
|
||||||
|
BlockNotFound,
|
||||||
|
/// An object was added but it does not link into existing history
|
||||||
|
PrevHashNotFound,
|
||||||
|
/// The `target` field of a block header did not match the expected difficulty
|
||||||
|
SpvBadTarget,
|
||||||
|
/// The header hash is not below the target
|
||||||
|
SpvBadProofOfWork
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
//!
|
//!
|
||||||
//! Functions needed by all parts of the Bitcoin library
|
//! Functions needed by all parts of the Bitcoin library
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
|
|
Loading…
Reference in New Issue