Merge branch 'master' into fix_319
This commit is contained in:
commit
f54b7691c4
|
@ -0,0 +1,22 @@
|
|||
|
||||
// Below flags apply in the context of BIP 68
|
||||
// If this flag set, CTxIn::nSequence is NOT interpreted as a
|
||||
// relative lock-time.
|
||||
pub const SEQUENCE_LOCKTIME_DISABLE_FLAG: u32 = 1u32 << 31;
|
||||
|
||||
// Setting nSequence to this value for every input in a transaction
|
||||
// disables nLockTime.
|
||||
pub const SEQUENCE_FINAL: u32 = 0xffffffff;
|
||||
|
||||
// If CTxIn::nSequence encodes a relative lock-time and this flag
|
||||
// is set, the relative lock-time has units of 512 seconds,
|
||||
// otherwise it specifies blocks with a granularity of 1.
|
||||
pub const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = (1 << 22);
|
||||
|
||||
// If CTxIn::nSequence encodes a relative lock-time, this mask is
|
||||
// applied to extract that lock-time from the sequence field.
|
||||
pub const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000ffff;
|
||||
|
||||
/// Threshold for `nLockTime`: below this value it is interpreted as block number,
|
||||
/// otherwise as UNIX timestamp.
|
||||
pub const LOCKTIME_THRESHOLD: u32 = 500000000; // Tue Nov 5 00:53:20 1985 UTC
|
|
@ -1,9 +1,14 @@
|
|||
use primitives::hash::H256;
|
||||
use chain::{Block, OutPoint, TransactionOutput, merkle_root, Transaction};
|
||||
use serialization::{Serializable, serialized_list_size};
|
||||
use std::{io, cmp};
|
||||
use hash::H256;
|
||||
use ser::{
|
||||
Serializable, serialized_list_size,
|
||||
Deserializable, Reader, Error as ReaderError
|
||||
};
|
||||
use block::Block;
|
||||
use transaction::Transaction;
|
||||
use merkle_root::merkle_root;
|
||||
use indexed_header::IndexedBlockHeader;
|
||||
use indexed_transaction::IndexedTransaction;
|
||||
use {TransactionOutputObserver, PreviousTransactionOutputProvider};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IndexedBlock {
|
||||
|
@ -11,40 +16,6 @@ pub struct IndexedBlock {
|
|||
pub transactions: Vec<IndexedTransaction>,
|
||||
}
|
||||
|
||||
impl PreviousTransactionOutputProvider for IndexedBlock {
|
||||
fn previous_transaction_output(&self, prevout: &OutPoint) -> Option<TransactionOutput> {
|
||||
let txs: &[_] = &self.transactions;
|
||||
txs.previous_transaction_output(prevout)
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionOutputObserver for IndexedBlock {
|
||||
fn is_spent(&self, _prevout: &OutPoint) -> Option<bool> {
|
||||
// the code below is valid, but commented out due it's poor performance
|
||||
// we could optimize it by indexing all outputs once
|
||||
// let tx: IndexedTransaction = { .. }
|
||||
// let indexed_outputs: IndexedOutputs = tx.indexed_outputs();
|
||||
// indexed_outputs.is_spent()
|
||||
None
|
||||
|
||||
// if previous transaction output appears more than once than we can safely
|
||||
// tell that it's spent (double spent)
|
||||
|
||||
//let spends = self.transactions.iter()
|
||||
//.flat_map(|tx| &tx.raw.inputs)
|
||||
//.filter(|input| &input.previous_output == prevout)
|
||||
//.take(2)
|
||||
//.count();
|
||||
|
||||
//match spends {
|
||||
//0 => None,
|
||||
//1 => Some(false),
|
||||
//2 => Some(true),
|
||||
//_ => unreachable!("spends <= 2; self.take(2); qed"),
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Block> for IndexedBlock {
|
||||
fn from(block: Block) -> Self {
|
||||
let Block { block_header, transactions } = block;
|
||||
|
@ -56,6 +27,12 @@ impl From<Block> for IndexedBlock {
|
|||
}
|
||||
}
|
||||
|
||||
impl cmp::PartialEq for IndexedBlock {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.header.hash == other.header.hash
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexedBlock {
|
||||
pub fn new(header: IndexedBlockHeader, transactions: Vec<IndexedTransaction>) -> Self {
|
||||
IndexedBlock {
|
||||
|
@ -87,3 +64,14 @@ impl IndexedBlock {
|
|||
self.transactions.iter().all(|tx| tx.raw.is_final_in_block(height, self.header.raw.time))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserializable for IndexedBlock {
|
||||
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, ReaderError> where T: io::Read {
|
||||
let block = IndexedBlock {
|
||||
header: try!(reader.read()),
|
||||
transactions: try!(reader.read_list()),
|
||||
};
|
||||
|
||||
Ok(block)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
use std::{io, cmp};
|
||||
use hash::H256;
|
||||
use ser::{Deserializable, Reader, Error as ReaderError};
|
||||
use block_header::BlockHeader;
|
||||
use read_and_hash::ReadAndHash;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IndexedBlockHeader {
|
||||
pub hash: H256,
|
||||
pub raw: BlockHeader,
|
||||
}
|
||||
|
||||
impl From<BlockHeader> for IndexedBlockHeader {
|
||||
fn from(header: BlockHeader) -> Self {
|
||||
IndexedBlockHeader {
|
||||
hash: header.hash(),
|
||||
raw: header,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexedBlockHeader {
|
||||
pub fn new(hash: H256, header: BlockHeader) -> Self {
|
||||
IndexedBlockHeader {
|
||||
hash: hash,
|
||||
raw: header,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl cmp::PartialEq for IndexedBlockHeader {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.hash == other.hash
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserializable for IndexedBlockHeader {
|
||||
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, ReaderError> where T: io::Read {
|
||||
let data = try!(reader.read_and_hash::<BlockHeader>());
|
||||
// TODO: use len
|
||||
let header = IndexedBlockHeader {
|
||||
raw: data.data,
|
||||
hash: data.hash,
|
||||
};
|
||||
|
||||
Ok(header)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
use std::{cmp, io, borrow};
|
||||
use hash::H256;
|
||||
use ser::{Deserializable, Reader, Error as ReaderError};
|
||||
use transaction::Transaction;
|
||||
use read_and_hash::ReadAndHash;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IndexedTransaction {
|
||||
pub hash: H256,
|
||||
pub raw: Transaction,
|
||||
}
|
||||
|
||||
impl From<Transaction> for IndexedTransaction {
|
||||
fn from(tx: Transaction) -> Self {
|
||||
IndexedTransaction {
|
||||
hash: tx.hash(),
|
||||
raw: tx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexedTransaction {
|
||||
pub fn new(hash: H256, transaction: Transaction) -> Self {
|
||||
IndexedTransaction {
|
||||
hash: hash,
|
||||
raw: transaction,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl cmp::PartialEq for IndexedTransaction {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.hash == other.hash
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserializable for IndexedTransaction {
|
||||
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, ReaderError> where T: io::Read {
|
||||
let data = try!(reader.read_and_hash::<Transaction>());
|
||||
// TODO: use len
|
||||
let tx = IndexedTransaction {
|
||||
raw: data.data,
|
||||
hash: data.hash,
|
||||
};
|
||||
|
||||
Ok(tx)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IndexedTransactionsRef<'a, T> where T: 'a {
|
||||
pub transactions: &'a [T],
|
||||
}
|
||||
|
||||
impl<'a, T> IndexedTransactionsRef<'a, T> where T: borrow::Borrow<IndexedTransaction> {
|
||||
pub fn new(transactions: &'a [T]) -> Self {
|
||||
IndexedTransactionsRef {
|
||||
transactions: transactions,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,27 +4,34 @@ extern crate primitives;
|
|||
extern crate bitcrypto as crypto;
|
||||
extern crate serialization as ser;
|
||||
|
||||
pub mod constants;
|
||||
|
||||
mod block;
|
||||
mod block_header;
|
||||
mod merkle_root;
|
||||
mod transaction;
|
||||
|
||||
/// `IndexedBlock` extension
|
||||
mod read_and_hash;
|
||||
mod indexed_block;
|
||||
mod indexed_header;
|
||||
mod indexed_transaction;
|
||||
|
||||
pub trait RepresentH256 {
|
||||
fn h256(&self) -> primitives::hash::H256;
|
||||
fn h256(&self) -> hash::H256;
|
||||
}
|
||||
|
||||
pub use rustc_serialize::hex;
|
||||
pub use primitives::{hash, bytes, uint, compact};
|
||||
|
||||
pub use self::block::Block;
|
||||
pub use self::block_header::BlockHeader;
|
||||
pub use self::merkle_root::merkle_root;
|
||||
pub use self::merkle_root::merkle_node_hash;
|
||||
pub use self::transaction::{
|
||||
Transaction, TransactionInput, TransactionOutput, OutPoint,
|
||||
SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_FINAL,
|
||||
SEQUENCE_LOCKTIME_TYPE_FLAG, SEQUENCE_LOCKTIME_MASK,
|
||||
LOCKTIME_THRESHOLD
|
||||
};
|
||||
pub use block::Block;
|
||||
pub use block_header::BlockHeader;
|
||||
pub use merkle_root::{merkle_root, merkle_node_hash};
|
||||
pub use transaction::{Transaction, TransactionInput, TransactionOutput, OutPoint};
|
||||
|
||||
pub use read_and_hash::{ReadAndHash, HashedData};
|
||||
pub use indexed_block::IndexedBlock;
|
||||
pub use indexed_header::IndexedBlockHeader;
|
||||
pub use indexed_transaction::{IndexedTransaction, IndexedTransactionsRef};
|
||||
|
||||
pub type ShortTransactionID = hash::H48;
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
use std::io;
|
||||
use hash::H256;
|
||||
use crypto::{DHash256, Digest};
|
||||
use ser::{Reader, Error as ReaderError, Deserializable};
|
||||
|
||||
pub struct HashedData<T> {
|
||||
pub size: usize,
|
||||
pub hash: H256,
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
pub trait ReadAndHash {
|
||||
fn read_and_hash<T>(&mut self) -> Result<HashedData<T>, ReaderError> where T: Deserializable;
|
||||
}
|
||||
|
||||
impl<R> ReadAndHash for Reader<R> where R: io::Read {
|
||||
fn read_and_hash<T>(&mut self) -> Result<HashedData<T>, ReaderError> where T: Deserializable {
|
||||
let mut size = 0usize;
|
||||
let mut hasher = DHash256::new();
|
||||
let data = self.read_with_proxy(|bytes| {
|
||||
size += bytes.len();
|
||||
hasher.input(bytes);
|
||||
})?;
|
||||
|
||||
let result = HashedData {
|
||||
hash: hasher.finish(),
|
||||
data: data,
|
||||
size: size,
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
|
@ -11,28 +11,7 @@ use ser::{
|
|||
};
|
||||
use crypto::dhash256;
|
||||
use hash::H256;
|
||||
|
||||
// Below flags apply in the context of BIP 68
|
||||
// If this flag set, CTxIn::nSequence is NOT interpreted as a
|
||||
// relative lock-time.
|
||||
pub const SEQUENCE_LOCKTIME_DISABLE_FLAG: u32 = 1u32 << 31;
|
||||
|
||||
// Setting nSequence to this value for every input in a transaction
|
||||
// disables nLockTime.
|
||||
pub const SEQUENCE_FINAL: u32 = 0xffffffff;
|
||||
|
||||
// If CTxIn::nSequence encodes a relative lock-time and this flag
|
||||
// is set, the relative lock-time has units of 512 seconds,
|
||||
// otherwise it specifies blocks with a granularity of 1.
|
||||
pub const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = (1 << 22);
|
||||
|
||||
// If CTxIn::nSequence encodes a relative lock-time, this mask is
|
||||
// applied to extract that lock-time from the sequence field.
|
||||
pub const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000ffff;
|
||||
|
||||
/// Threshold for `nLockTime`: below this value it is interpreted as block number,
|
||||
/// otherwise as UNIX timestamp.
|
||||
pub const LOCKTIME_THRESHOLD: u32 = 500000000; // Tue Nov 5 00:53:20 1985 UTC
|
||||
use constants::{SEQUENCE_FINAL, LOCKTIME_THRESHOLD};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
||||
pub struct OutPoint {
|
||||
|
|
|
@ -2,11 +2,11 @@ extern crate crypto as rcrypto;
|
|||
extern crate primitives;
|
||||
extern crate siphasher;
|
||||
|
||||
pub use rcrypto::digest::Digest;
|
||||
use std::hash::Hasher;
|
||||
use rcrypto::sha1::Sha1;
|
||||
use rcrypto::sha2::Sha256;
|
||||
use rcrypto::ripemd160::Ripemd160;
|
||||
use rcrypto::digest::Digest;
|
||||
use siphasher::sip::SipHasher24;
|
||||
use primitives::hash::{H32, H160, H256};
|
||||
|
||||
|
@ -72,6 +72,12 @@ impl DHash256 {
|
|||
pub fn new() -> Self {
|
||||
DHash256::default()
|
||||
}
|
||||
|
||||
pub fn finish(mut self) -> H256 {
|
||||
let mut result = H256::default();
|
||||
self.result(&mut *result);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest for DHash256 {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use primitives::hash::H256;
|
||||
use super::{BlockLocation, IndexedBlock};
|
||||
use chain;
|
||||
use chain::{self, IndexedBlock};
|
||||
use error::Error;
|
||||
use super::BlockLocation;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Reorganization {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
use std::borrow::Borrow;
|
||||
use chain::{OutPoint, TransactionOutput, IndexedTransactionsRef, IndexedTransaction, IndexedBlock};
|
||||
use transaction_provider::PreviousTransactionOutputProvider;
|
||||
use transaction_meta_provider::TransactionOutputObserver;
|
||||
|
||||
impl<'a, T> PreviousTransactionOutputProvider for IndexedTransactionsRef<'a, T>
|
||||
where T: Borrow<IndexedTransaction> + Send + Sync {
|
||||
fn previous_transaction_output(&self, prevout: &OutPoint) -> Option<TransactionOutput> {
|
||||
self.transactions.iter()
|
||||
.map(Borrow::borrow)
|
||||
.find(|tx| tx.hash == prevout.hash)
|
||||
.and_then(|tx| tx.raw.outputs.get(prevout.index as usize))
|
||||
.cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreviousTransactionOutputProvider for IndexedBlock {
|
||||
fn previous_transaction_output(&self, prevout: &OutPoint) -> Option<TransactionOutput> {
|
||||
let txs = IndexedTransactionsRef::new(&self.transactions);
|
||||
txs.previous_transaction_output(prevout)
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionOutputObserver for IndexedBlock {
|
||||
fn is_spent(&self, _prevout: &OutPoint) -> Option<bool> {
|
||||
// the code below is valid, but commented out due it's poor performance
|
||||
// we could optimize it by indexing all outputs once
|
||||
// let tx: IndexedTransaction = { .. }
|
||||
// let indexed_outputs: IndexedOutputs = tx.indexed_outputs();
|
||||
// indexed_outputs.is_spent()
|
||||
None
|
||||
|
||||
// if previous transaction output appears more than once than we can safely
|
||||
// tell that it's spent (double spent)
|
||||
|
||||
//let spends = self.transactions.iter()
|
||||
//.flat_map(|tx| &tx.raw.inputs)
|
||||
//.filter(|input| &input.previous_output == prevout)
|
||||
//.take(2)
|
||||
//.count();
|
||||
|
||||
//match spends {
|
||||
//0 => None,
|
||||
//1 => Some(false),
|
||||
//2 => Some(true),
|
||||
//_ => unreachable!("spends <= 2; self.take(2); qed"),
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
use primitives::hash::H256;
|
||||
use chain::BlockHeader;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IndexedBlockHeader {
|
||||
pub hash: H256,
|
||||
pub raw: BlockHeader,
|
||||
}
|
||||
|
||||
impl From<BlockHeader> for IndexedBlockHeader {
|
||||
fn from(header: BlockHeader) -> Self {
|
||||
IndexedBlockHeader {
|
||||
hash: header.hash(),
|
||||
raw: header,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexedBlockHeader {
|
||||
pub fn new(hash: H256, header: BlockHeader) -> Self {
|
||||
IndexedBlockHeader {
|
||||
hash: hash,
|
||||
raw: header,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
use std::cmp;
|
||||
use primitives::hash::H256;
|
||||
use chain::{Transaction, OutPoint, TransactionOutput};
|
||||
use PreviousTransactionOutputProvider;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IndexedTransaction {
|
||||
pub hash: H256,
|
||||
pub raw: Transaction,
|
||||
}
|
||||
|
||||
impl From<Transaction> for IndexedTransaction {
|
||||
fn from(tx: Transaction) -> Self {
|
||||
IndexedTransaction {
|
||||
hash: tx.hash(),
|
||||
raw: tx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexedTransaction {
|
||||
pub fn new(hash: H256, transaction: Transaction) -> Self {
|
||||
IndexedTransaction {
|
||||
hash: hash,
|
||||
raw: transaction,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl cmp::PartialEq for IndexedTransaction {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.hash == other.hash
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PreviousTransactionOutputProvider for &'a [IndexedTransaction] {
|
||||
fn previous_transaction_output(&self, prevout: &OutPoint) -> Option<TransactionOutput> {
|
||||
self.iter()
|
||||
.find(|tx| tx.hash == prevout.hash)
|
||||
.and_then(|tx| tx.raw.outputs.get(prevout.index as usize))
|
||||
.cloned()
|
||||
}
|
||||
}
|
|
@ -28,9 +28,7 @@ mod transaction_provider;
|
|||
mod transaction_meta_provider;
|
||||
mod error;
|
||||
mod update_context;
|
||||
mod indexed_block;
|
||||
mod indexed_header;
|
||||
mod indexed_transaction;
|
||||
mod impls;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BlockRef {
|
||||
|
@ -75,9 +73,6 @@ pub use transaction_meta_provider::{TransactionMetaProvider, TransactionOutputOb
|
|||
pub use transaction_meta::TransactionMeta;
|
||||
pub use block_stapler::{BlockStapler, BlockInsertedChain};
|
||||
pub use block_provider::{BlockProvider, BlockHeaderProvider};
|
||||
pub use indexed_block::IndexedBlock;
|
||||
pub use indexed_header::IndexedBlockHeader;
|
||||
pub use indexed_transaction::IndexedTransaction;
|
||||
|
||||
#[cfg(feature="dev")]
|
||||
pub use test_storage::TestStorage;
|
||||
|
|
|
@ -4,14 +4,13 @@ use std::fs;
|
|||
use std::path::Path;
|
||||
use kvdb::{Database, DatabaseConfig};
|
||||
use byteorder::{LittleEndian, ByteOrder};
|
||||
use primitives::hash::H256;
|
||||
use primitives::bytes::Bytes;
|
||||
use super::{BlockRef, BestBlock, BlockLocation, IndexedBlock};
|
||||
use serialization::{serialize, deserialize};
|
||||
use chain;
|
||||
use parking_lot::RwLock;
|
||||
use lru_cache::LruCache;
|
||||
|
||||
use primitives::hash::H256;
|
||||
use primitives::bytes::Bytes;
|
||||
use chain::{self, IndexedBlock, IndexedBlockHeader, IndexedTransaction};
|
||||
use serialization::{serialize, deserialize};
|
||||
use transaction_meta::TransactionMeta;
|
||||
use error::{Error, ConsistencyError, MetaError};
|
||||
use update_context::UpdateContext;
|
||||
|
@ -19,9 +18,7 @@ use block_provider::{BlockProvider, BlockHeaderProvider};
|
|||
use transaction_provider::{TransactionProvider, PreviousTransactionOutputProvider};
|
||||
use transaction_meta_provider::TransactionMetaProvider;
|
||||
use block_stapler::{BlockStapler, BlockInsertedChain, Reorganization};
|
||||
|
||||
use indexed_header::IndexedBlockHeader;
|
||||
use indexed_transaction::IndexedTransaction;
|
||||
use super::{BlockRef, BestBlock, BlockLocation};
|
||||
|
||||
pub const COL_COUNT: u32 = 10;
|
||||
pub const COL_META: u32 = 0;
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
use super::{
|
||||
BlockRef, Store, Error, BestBlock, BlockLocation, BlockInsertedChain, BlockProvider,
|
||||
BlockStapler, TransactionMetaProvider, TransactionProvider, PreviousTransactionOutputProvider,
|
||||
IndexedBlock, BlockHeaderProvider,
|
||||
BlockHeaderProvider,
|
||||
};
|
||||
use chain::{self, Block};
|
||||
use chain::{self, Block, IndexedBlock};
|
||||
use primitives::hash::H256;
|
||||
use serialization;
|
||||
use chain::bytes::Bytes;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use std::io;
|
||||
use hash::H32;
|
||||
use ser::{Deserializable, Reader, Error as ReaderError};
|
||||
use chain;
|
||||
use chain::IndexedBlock;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Block {
|
||||
pub magic: H32,
|
||||
pub block_size: u32,
|
||||
pub block: chain::Block,
|
||||
pub block: IndexedBlock,
|
||||
}
|
||||
|
||||
impl Deserializable for Block {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashSet;
|
||||
use primitives::hash::H256;
|
||||
use chain::{OutPoint, TransactionOutput};
|
||||
use db::{SharedStore, IndexedTransaction, PreviousTransactionOutputProvider};
|
||||
use chain::{OutPoint, TransactionOutput, IndexedTransaction};
|
||||
use db::{SharedStore, PreviousTransactionOutputProvider};
|
||||
use network::Magic;
|
||||
use memory_pool::{MemoryPool, OrderingStrategy, Entry};
|
||||
use verification::{work_required, block_reward_satoshi, transaction_sigops};
|
||||
|
@ -278,7 +278,7 @@ impl BlockAssembler {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use db::IndexedTransaction;
|
||||
use chain::{IndexedTransaction, IndexedTransactionsRef};
|
||||
use verification::constants::{MAX_BLOCK_SIZE, MAX_BLOCK_SIGOPS};
|
||||
use memory_pool::Entry;
|
||||
use super::{SizePolicy, NextStep, FittingTransactionsIterator};
|
||||
|
@ -317,8 +317,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_fitting_transactions_iterator_no_transactions() {
|
||||
let store: Vec<IndexedTransaction> = Vec::new();
|
||||
let store_ref = IndexedTransactionsRef::new(&store);
|
||||
let entries: Vec<Entry> = Vec::new();
|
||||
let store_ref: &[_] = &store;
|
||||
|
||||
let iter = FittingTransactionsIterator::new(&store_ref, entries.iter(), MAX_BLOCK_SIZE as u32, MAX_BLOCK_SIGOPS as u32, 0, 0);
|
||||
assert!(iter.collect::<Vec<_>>().is_empty());
|
||||
|
|
|
@ -32,5 +32,5 @@ pub use config::Config;
|
|||
pub use net::Config as NetConfig;
|
||||
pub use p2p::{P2P, Context};
|
||||
pub use event_loop::{event_loop, forever};
|
||||
pub use util::{NodeTableError, PeerId, PeerInfo, InternetProtocol};
|
||||
pub use util::{NodeTableError, PeerId, PeerInfo, InternetProtocol, Direction};
|
||||
pub use protocol::{InboundSyncConnection, InboundSyncConnectionRef, OutboundSyncConnection, OutboundSyncConnectionRef, LocalSyncNode, LocalSyncNodeRef};
|
||||
|
|
|
@ -35,8 +35,13 @@ impl Connections {
|
|||
self.channels().values().map(|channel| channel.peer_info().address).collect()
|
||||
}
|
||||
|
||||
/// Returns info on every peer
|
||||
pub fn info(&self) -> Vec<PeerInfo> {
|
||||
self.channels().values().map(|channel| channel.peer_info()).collect()
|
||||
}
|
||||
|
||||
/// Returns number of connections.
|
||||
pub fn _count(&self) -> usize {
|
||||
pub fn count(&self) -> usize {
|
||||
self.channels.read().len()
|
||||
}
|
||||
|
||||
|
|
|
@ -386,6 +386,14 @@ impl Context {
|
|||
pub fn create_sync_session(&self, start_height: i32, outbound_connection: OutboundSyncConnectionRef) -> InboundSyncConnectionRef {
|
||||
self.local_sync_node.create_sync_session(start_height, outbound_connection)
|
||||
}
|
||||
|
||||
pub fn connections(&self) -> &Connections {
|
||||
&self.connections
|
||||
}
|
||||
|
||||
pub fn nodes(&self) -> Vec<Node> {
|
||||
self.node_table.read().nodes()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct P2P {
|
||||
|
|
|
@ -296,6 +296,11 @@ impl<T> NodeTable<T> where T: Time {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Returnes all nodes
|
||||
pub fn nodes(&self) -> Vec<Node> {
|
||||
self.by_addr.iter().map(|(_, n)| n).cloned().collect()
|
||||
}
|
||||
|
||||
/// Returns most recently active nodes.
|
||||
///
|
||||
/// The documenation says:
|
||||
|
|
|
@ -78,3 +78,6 @@ subcommands:
|
|||
- PATH:
|
||||
required: true
|
||||
help: Path of the bitcoin core database
|
||||
- skip-verification:
|
||||
long: skip-verification
|
||||
help: Skip blocks verification
|
||||
|
|
|
@ -8,9 +8,11 @@ pub fn import(cfg: Config, matches: &ArgMatches) -> Result<(), String> {
|
|||
// TODO: this might be unnecessary here!
|
||||
try!(init_db(&cfg, &db));
|
||||
|
||||
let mut writer = create_sync_blocks_writer(db, cfg.magic);
|
||||
|
||||
let blk_path = matches.value_of("PATH").expect("PATH is required in cli.yml; qed");
|
||||
let skip_verification = matches.is_present("skip-verification");
|
||||
|
||||
let mut writer = create_sync_blocks_writer(db, cfg.magic, !skip_verification);
|
||||
|
||||
let blk_dir = try!(::import::open_blk_dir(blk_path).map_err(|_| "Import directory does not exist".to_owned()));
|
||||
let mut counter = 0;
|
||||
for blk in blk_dir {
|
||||
|
@ -20,7 +22,7 @@ pub fn import(cfg: Config, matches: &ArgMatches) -> Result<(), String> {
|
|||
Ok(_) => {
|
||||
counter += 1;
|
||||
if counter % 1000 == 0 {
|
||||
info!("Imported {} blocks", counter);
|
||||
info!(target: "sync", "Imported {} blocks", counter);
|
||||
}
|
||||
}
|
||||
Err(Error::TooManyOrphanBlocks) => return Err("Too many orphan (unordered) blocks".into()),
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
mod codes {
|
||||
// NOTE [ToDr] Codes from [-32099, -32000]
|
||||
pub const UNKNOWN: i64 = -32000;
|
||||
pub const EXECUTION_ERROR: i64 = -32015;
|
||||
pub const TRANSACTION_NOT_FOUND: i64 = -32096;
|
||||
pub const TRANSACTION_OUTPUT_NOT_FOUND: i64 = -32097;
|
||||
|
@ -97,3 +98,11 @@ pub fn node_not_added() -> Error {
|
|||
data: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unknown() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::UNKNOWN),
|
||||
message: "Unknown error has occurred".into(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use v1::helpers::errors::{block_not_found, block_at_height_not_found, transactio
|
|||
transaction_output_not_found, transaction_of_side_branch};
|
||||
use jsonrpc_macros::Trailing;
|
||||
use jsonrpc_core::Error;
|
||||
use db;
|
||||
use {db, chain};
|
||||
use global_script::Script;
|
||||
use chain::OutPoint;
|
||||
use verification;
|
||||
|
@ -69,7 +69,7 @@ impl BlockChainClientCoreApi for BlockChainClientCore {
|
|||
fn verbose_block(&self, hash: GlobalH256) -> Option<VerboseBlock> {
|
||||
self.storage.block(hash.into())
|
||||
.map(|block| {
|
||||
let block: db::IndexedBlock = block.into();
|
||||
let block: chain::IndexedBlock = block.into();
|
||||
let height = self.storage.block_number(block.hash());
|
||||
let confirmations = match height {
|
||||
Some(block_number) => (self.storage.best_block().expect("genesis block is required").number - block_number + 1) as i64,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
use std::net::SocketAddr;
|
||||
use std::net::{SocketAddr, IpAddr};
|
||||
use v1::traits::Network as NetworkRpc;
|
||||
use v1::types::AddNodeOperation;
|
||||
use v1::types::{AddNodeOperation, NodeInfo};
|
||||
use jsonrpc_core::Error;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::helpers::errors;
|
||||
use p2p;
|
||||
|
||||
|
@ -10,6 +11,9 @@ pub trait NetworkApi : Send + Sync + 'static {
|
|||
fn add_node(&self, socket_addr: SocketAddr) -> Result<(), p2p::NodeTableError>;
|
||||
fn remove_node(&self, socket_addr: SocketAddr) -> Result<(), p2p::NodeTableError>;
|
||||
fn connect(&self, socket_addr: SocketAddr);
|
||||
fn node_info(&self, node_addr: IpAddr) -> Result<NodeInfo, p2p::NodeTableError>;
|
||||
fn nodes_info(&self) -> Vec<NodeInfo>;
|
||||
fn connection_count(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<T> NetworkRpc for NetworkClient<T> where T: NetworkApi {
|
||||
|
@ -29,6 +33,27 @@ impl<T> NetworkRpc for NetworkClient<T> where T: NetworkApi {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn node_info(&self, _dns: bool, node_addr: Trailing<String>) -> Result<Vec<NodeInfo>, Error> {
|
||||
Ok(
|
||||
if node_addr.0.is_empty() {
|
||||
self.api.nodes_info()
|
||||
}
|
||||
else {
|
||||
let addr = try!(node_addr.0.parse().map_err(
|
||||
|_| errors::invalid_params("node", "Invalid ip address format, should be ip address (127.0.0.1)")));
|
||||
let node_info = try!(
|
||||
self.api.node_info(addr)
|
||||
.map_err(|_| errors::node_not_added())
|
||||
);
|
||||
vec![node_info]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn connection_count(&self) -> Result<usize, Error> {
|
||||
Ok(self.api.connection_count())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NetworkClient<T: NetworkApi> {
|
||||
|
@ -65,4 +90,43 @@ impl NetworkApi for NetworkClientCore {
|
|||
fn connect(&self, socket_addr: SocketAddr) {
|
||||
p2p::Context::connect_normal(self.p2p.clone(), socket_addr);
|
||||
}
|
||||
|
||||
fn node_info(&self, node_addr: IpAddr) -> Result<NodeInfo, p2p::NodeTableError> {
|
||||
let exact_node = try!(
|
||||
self.p2p.nodes()
|
||||
.iter()
|
||||
.find(|n| n.address().ip() == node_addr)
|
||||
.cloned()
|
||||
.ok_or(p2p::NodeTableError::NoAddressInTable)
|
||||
);
|
||||
|
||||
let peers: Vec<p2p::PeerInfo> = self.p2p.connections().info()
|
||||
.into_iter()
|
||||
.filter(|p| p.address == exact_node.address()).collect();
|
||||
|
||||
Ok(
|
||||
NodeInfo {
|
||||
addednode: format!("{}", exact_node.address()),
|
||||
connected: !peers.is_empty(),
|
||||
addresses: peers.into_iter().map(|p| p.into()).collect(),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn nodes_info(&self) -> Vec<NodeInfo> {
|
||||
let peers: Vec<p2p::PeerInfo> = self.p2p.connections().info();
|
||||
|
||||
self.p2p.nodes().iter().map(|n| {
|
||||
let node_peers: Vec<p2p::PeerInfo> = peers.iter().filter(|p| p.address == n.address()).cloned().collect();
|
||||
NodeInfo {
|
||||
addednode: format!("{}", n.address()),
|
||||
connected: !node_peers.is_empty(),
|
||||
addresses: node_peers.into_iter().map(|p| p.into()).collect(),
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn connection_count(&self) -> usize {
|
||||
self.p2p.connections().count()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
use jsonrpc_core::Error;
|
||||
use v1::types::AddNodeOperation;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::types::{AddNodeOperation, NodeInfo};
|
||||
|
||||
build_rpc_trait! {
|
||||
/// Parity-bitcoin network interface
|
||||
pub trait Network {
|
||||
/// Add/remove/connecto to the node
|
||||
/// Add/remove/connect to the node
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "addnode", "params": ["127.0.0.1:8888", "add"], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "addnode", "params": ["127.0.0.1:8888", "remove"], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "method": "addnode", "params": ["127.0.0.1:8888", "onetry"], "id":1 }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "addnode")]
|
||||
fn add_node(&self, String, AddNodeOperation) -> Result<(), Error>;
|
||||
/// Query node(s) info
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "id":"1", "method": "getaddednodeinfo", "params": [true] }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "id":"1", "method": "getaddednodeinfo", "params": [true, "192.168.0.201"] }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "getaddednodeinfo")]
|
||||
fn node_info(&self, bool, Trailing<String>) -> Result<Vec<NodeInfo>, Error>;
|
||||
/// Query node(s) info
|
||||
/// @curl-example: curl --data-binary '{"jsonrpc": "2.0", "id":"1", "method": "getconnectioncount", "params": [] }' -H 'content-type: application/json;' http://127.0.0.1:8332/
|
||||
#[rpc(name = "getconnectioncount")]
|
||||
fn connection_count(&self) -> Result<usize, Error>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
use super::hash::H256;
|
||||
use chain;
|
||||
use super::transaction::RawTransaction;
|
||||
use db;
|
||||
use miner;
|
||||
|
||||
/// Block template as described in:
|
||||
|
@ -96,8 +96,8 @@ impl From<miner::BlockTemplate> for BlockTemplate {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<db::IndexedTransaction> for BlockTemplateTransaction {
|
||||
fn from(transaction: db::IndexedTransaction) -> Self {
|
||||
impl From<chain::IndexedTransaction> for BlockTemplateTransaction {
|
||||
fn from(transaction: chain::IndexedTransaction) -> Self {
|
||||
use ser::serialize;
|
||||
let serialize = serialize(&transaction.raw);
|
||||
BlockTemplateTransaction {
|
||||
|
|
|
@ -26,4 +26,4 @@ pub use self::transaction::{RawTransaction, Transaction, TransactionInput, Trans
|
|||
TransactionInputScript, TransactionOutputScript, SignedTransactionInput, GetRawTransactionResponse,
|
||||
SignedTransactionOutput, TransactionOutputs};
|
||||
pub use self::uint::U256;
|
||||
pub use self::nodes::AddNodeOperation;
|
||||
pub use self::nodes::{AddNodeOperation, NodeInfo};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use serde::{Deserialize, Deserializer};
|
||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||
use p2p::{Direction, PeerInfo};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AddNodeOperation {
|
||||
|
@ -29,3 +30,42 @@ impl Deserialize for AddNodeOperation {
|
|||
deserializer.deserialize(DummyVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct NodeInfoAddress {
|
||||
address: String,
|
||||
connected: NodeInfoAddressConnectionType,
|
||||
}
|
||||
|
||||
impl From<PeerInfo> for NodeInfoAddress {
|
||||
fn from(info: PeerInfo) -> Self {
|
||||
NodeInfoAddress {
|
||||
address: format!("{}", info.address),
|
||||
connected: match info.direction {
|
||||
Direction::Inbound => NodeInfoAddressConnectionType::Inbound,
|
||||
Direction::Outbound => NodeInfoAddressConnectionType::Outbound,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct NodeInfo {
|
||||
pub addednode: String,
|
||||
pub connected: bool,
|
||||
pub addresses: Vec<NodeInfoAddress>,
|
||||
}
|
||||
|
||||
pub enum NodeInfoAddressConnectionType {
|
||||
Inbound,
|
||||
Outbound,
|
||||
}
|
||||
|
||||
impl Serialize for NodeInfoAddressConnectionType {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
|
||||
match *self {
|
||||
NodeInfoAddressConnectionType::Inbound => "inbound".serialize(serializer),
|
||||
NodeInfoAddressConnectionType::Outbound => "outbound".serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{cmp, mem};
|
||||
use bytes::Bytes;
|
||||
use keys::{Signature, Public};
|
||||
use chain::SEQUENCE_LOCKTIME_DISABLE_FLAG;
|
||||
use chain::constants::SEQUENCE_LOCKTIME_DISABLE_FLAG;
|
||||
use crypto::{sha1, sha256, dhash160, dhash256, ripemd160};
|
||||
use {
|
||||
script, Script, Num, VerificationFlags, Opcode, Error,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use keys::{Public, Signature};
|
||||
use chain::{
|
||||
self, SEQUENCE_FINAL, SEQUENCE_LOCKTIME_DISABLE_FLAG,
|
||||
SEQUENCE_LOCKTIME_MASK, SEQUENCE_LOCKTIME_TYPE_FLAG
|
||||
use chain::constants::{
|
||||
SEQUENCE_FINAL, SEQUENCE_LOCKTIME_DISABLE_FLAG,
|
||||
SEQUENCE_LOCKTIME_MASK, SEQUENCE_LOCKTIME_TYPE_FLAG, LOCKTIME_THRESHOLD
|
||||
};
|
||||
use {SignatureVersion, Script, TransactionInputSigner, Num};
|
||||
|
||||
|
@ -64,8 +64,8 @@ impl SignatureChecker for TransactionSignatureChecker {
|
|||
// the nLockTime in the transaction.
|
||||
let lock_time_u32: u32 = lock_time.into();
|
||||
if !(
|
||||
(self.signer.lock_time < chain::LOCKTIME_THRESHOLD && lock_time_u32 < chain::LOCKTIME_THRESHOLD) ||
|
||||
(self.signer.lock_time >= chain::LOCKTIME_THRESHOLD && lock_time_u32 >= chain::LOCKTIME_THRESHOLD)
|
||||
(self.signer.lock_time < LOCKTIME_THRESHOLD && lock_time_u32 < LOCKTIME_THRESHOLD) ||
|
||||
(self.signer.lock_time >= LOCKTIME_THRESHOLD && lock_time_u32 >= LOCKTIME_THRESHOLD)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -84,6 +84,11 @@ impl<R> Reader<R> where R: io::Read {
|
|||
T::deserialize(self)
|
||||
}
|
||||
|
||||
pub fn read_with_proxy<T, F>(&mut self, proxy: F) -> Result<T, Error> where T: Deserializable, F: FnMut(&[u8]) {
|
||||
let mut reader = Reader::from_read(Proxy::new(self, proxy));
|
||||
T::deserialize(&mut reader)
|
||||
}
|
||||
|
||||
pub fn read_slice(&mut self, bytes: &mut [u8]) -> Result<(), Error> {
|
||||
io::Read::read_exact(self, bytes).map_err(|_| Error::UnexpectedEnd)
|
||||
}
|
||||
|
@ -148,3 +153,26 @@ impl<R, T> Iterator for ReadIterator<R, T> where R: io::Read, T: Deserializable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Proxy<F, T> {
|
||||
from: F,
|
||||
to: T,
|
||||
}
|
||||
|
||||
impl<F, T> Proxy<F, T> {
|
||||
fn new(from: F, to: T) -> Self {
|
||||
Proxy {
|
||||
from: from,
|
||||
to: to,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T> io::Read for Proxy<F, T> where F: io::Read, T: FnMut(&[u8]) {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
|
||||
let len = try!(io::Read::read(&mut self.from, buf));
|
||||
let to = &mut self.to;
|
||||
to(&buf[..len]);
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ pub struct BlocksWriter {
|
|||
orphaned_blocks_pool: OrphanBlocksPool,
|
||||
verifier: SyncVerifier<BlocksWriterSink>,
|
||||
sink: Arc<BlocksWriterSinkData>,
|
||||
verification: bool,
|
||||
}
|
||||
|
||||
struct BlocksWriterSink {
|
||||
|
@ -29,7 +30,7 @@ struct BlocksWriterSinkData {
|
|||
}
|
||||
|
||||
impl BlocksWriter {
|
||||
pub fn new(storage: db::SharedStore, network: Magic) -> BlocksWriter {
|
||||
pub fn new(storage: db::SharedStore, network: Magic, verification: bool) -> BlocksWriter {
|
||||
let sink_data = Arc::new(BlocksWriterSinkData::new(storage.clone()));
|
||||
let sink = Arc::new(BlocksWriterSink::new(sink_data.clone()));
|
||||
let verifier = SyncVerifier::new(network, storage.clone(), sink);
|
||||
|
@ -38,18 +39,18 @@ impl BlocksWriter {
|
|||
orphaned_blocks_pool: OrphanBlocksPool::new(),
|
||||
verifier: verifier,
|
||||
sink: sink_data,
|
||||
verification: verification,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_block(&mut self, block: chain::Block) -> Result<(), Error> {
|
||||
let indexed_block: db::IndexedBlock = block.into();
|
||||
pub fn append_block(&mut self, block: chain::IndexedBlock) -> Result<(), Error> {
|
||||
// do not append block if it is already there
|
||||
if self.storage.contains_block(db::BlockRef::Hash(indexed_block.hash().clone())) {
|
||||
if self.storage.contains_block(db::BlockRef::Hash(block.hash().clone())) {
|
||||
return Ok(());
|
||||
}
|
||||
// verify && insert only if parent block is already in the storage
|
||||
if !self.storage.contains_block(db::BlockRef::Hash(indexed_block.header.raw.previous_header_hash.clone())) {
|
||||
self.orphaned_blocks_pool.insert_orphaned_block(indexed_block.hash().clone(), indexed_block);
|
||||
if !self.storage.contains_block(db::BlockRef::Hash(block.header.raw.previous_header_hash.clone())) {
|
||||
self.orphaned_blocks_pool.insert_orphaned_block(block.hash().clone(), block);
|
||||
// we can't hold many orphaned blocks in memory during import
|
||||
if self.orphaned_blocks_pool.len() > MAX_ORPHANED_BLOCKS {
|
||||
return Err(Error::TooManyOrphanBlocks);
|
||||
|
@ -58,13 +59,17 @@ impl BlocksWriter {
|
|||
}
|
||||
|
||||
// verify && insert block && all its orphan children
|
||||
let mut verification_queue: VecDeque<db::IndexedBlock> = self.orphaned_blocks_pool.remove_blocks_for_parent(indexed_block.hash()).into_iter().map(|(_, b)| b).collect();
|
||||
verification_queue.push_front(indexed_block);
|
||||
let mut verification_queue: VecDeque<chain::IndexedBlock> = self.orphaned_blocks_pool.remove_blocks_for_parent(block.hash()).into_iter().map(|(_, b)| b).collect();
|
||||
verification_queue.push_front(block);
|
||||
while let Some(block) = verification_queue.pop_front() {
|
||||
self.verifier.verify_block(block);
|
||||
if self.verification {
|
||||
self.verifier.verify_block(block);
|
||||
|
||||
if let Some(err) = self.sink.error() {
|
||||
return Err(err);
|
||||
if let Some(err) = self.sink.error() {
|
||||
return Err(err);
|
||||
}
|
||||
} else {
|
||||
try!(self.storage.insert_indexed_block(&block).map_err(Error::Database));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,7 +102,7 @@ impl VerificationSink for BlocksWriterSink {
|
|||
}
|
||||
|
||||
impl BlockVerificationSink for BlocksWriterSink {
|
||||
fn on_block_verification_success(&self, block: db::IndexedBlock) -> Option<Vec<VerificationTask>> {
|
||||
fn on_block_verification_success(&self, block: chain::IndexedBlock) -> Option<Vec<VerificationTask>> {
|
||||
if let Err(err) = self.data.storage.insert_indexed_block(&block) {
|
||||
*self.data.err.lock() = Some(Error::Database(err));
|
||||
}
|
||||
|
@ -132,8 +137,8 @@ mod tests {
|
|||
#[test]
|
||||
fn blocks_writer_appends_blocks() {
|
||||
let db = Arc::new(db::TestStorage::with_genesis_block());
|
||||
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet);
|
||||
blocks_target.append_block(test_data::block_h1()).expect("Expecting no error");
|
||||
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet, true);
|
||||
blocks_target.append_block(test_data::block_h1().into()).expect("Expecting no error");
|
||||
assert_eq!(db.best_block().expect("Block is inserted").number, 1);
|
||||
}
|
||||
|
||||
|
@ -141,9 +146,9 @@ mod tests {
|
|||
fn blocks_writer_verification_error() {
|
||||
let db = Arc::new(db::TestStorage::with_genesis_block());
|
||||
let blocks = test_data::build_n_empty_blocks_from_genesis((MAX_ORPHANED_BLOCKS + 2) as u32, 1);
|
||||
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet);
|
||||
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet, true);
|
||||
for (index, block) in blocks.into_iter().skip(1).enumerate() {
|
||||
match blocks_target.append_block(block) {
|
||||
match blocks_target.append_block(block.into()) {
|
||||
Err(Error::TooManyOrphanBlocks) if index == MAX_ORPHANED_BLOCKS => (),
|
||||
Ok(_) if index != MAX_ORPHANED_BLOCKS => (),
|
||||
_ => panic!("unexpected"),
|
||||
|
@ -155,12 +160,12 @@ mod tests {
|
|||
#[test]
|
||||
fn blocks_writer_out_of_order_block() {
|
||||
let db = Arc::new(db::TestStorage::with_genesis_block());
|
||||
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet);
|
||||
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet, true);
|
||||
|
||||
let wrong_block = test_data::block_builder()
|
||||
.header().parent(test_data::genesis().hash()).build()
|
||||
.build();
|
||||
match blocks_target.append_block(wrong_block).unwrap_err() {
|
||||
match blocks_target.append_block(wrong_block.into()).unwrap_err() {
|
||||
Error::Verification(_) => (),
|
||||
_ => panic!("Unexpected error"),
|
||||
};
|
||||
|
@ -170,12 +175,12 @@ mod tests {
|
|||
#[test]
|
||||
fn blocks_writer_append_to_existing_db() {
|
||||
let db = Arc::new(db::TestStorage::with_genesis_block());
|
||||
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet);
|
||||
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet, true);
|
||||
|
||||
assert!(blocks_target.append_block(test_data::genesis()).is_ok());
|
||||
assert!(blocks_target.append_block(test_data::genesis().into()).is_ok());
|
||||
assert_eq!(db.best_block().expect("Block is inserted").number, 0);
|
||||
|
||||
assert!(blocks_target.append_block(test_data::block_h1()).is_ok());
|
||||
assert!(blocks_target.append_block(test_data::block_h1().into()).is_ok());
|
||||
assert_eq!(db.best_block().expect("Block is inserted").number, 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,7 @@ use std::collections::HashSet;
|
|||
use rand::{thread_rng, Rng};
|
||||
use bitcrypto::{sha256, siphash24};
|
||||
use byteorder::{LittleEndian, ByteOrder};
|
||||
use chain::{BlockHeader, ShortTransactionID};
|
||||
use db::IndexedBlock;
|
||||
use chain::{BlockHeader, ShortTransactionID, IndexedBlock};
|
||||
use message::common::{BlockHeaderAndIDs, PrefilledTransaction};
|
||||
use primitives::hash::H256;
|
||||
use ser::{Stream, Serializable};
|
||||
|
|
|
@ -63,8 +63,8 @@ pub enum Error {
|
|||
}
|
||||
|
||||
/// Create blocks writer.
|
||||
pub fn create_sync_blocks_writer(db: db::SharedStore, network: Magic) -> blocks_writer::BlocksWriter {
|
||||
blocks_writer::BlocksWriter::new(db, network)
|
||||
pub fn create_sync_blocks_writer(db: db::SharedStore, network: Magic, verification: bool) -> blocks_writer::BlocksWriter {
|
||||
blocks_writer::BlocksWriter::new(db, network, verification)
|
||||
}
|
||||
|
||||
/// Creates local sync node for given `db`
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::hash_map::Entry;
|
|||
use linked_hash_map::LinkedHashMap;
|
||||
use time;
|
||||
use primitives::hash::H256;
|
||||
use db::IndexedBlock;
|
||||
use chain::IndexedBlock;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Storage for blocks, for which we have no parent yet.
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::sync::Arc;
|
|||
use std::collections::{VecDeque, HashSet};
|
||||
use linked_hash_map::LinkedHashMap;
|
||||
use parking_lot::RwLock;
|
||||
use chain::{BlockHeader, Transaction};
|
||||
use db::{self, IndexedBlock};
|
||||
use chain::{BlockHeader, Transaction, IndexedBlock};
|
||||
use db;
|
||||
use best_headers_chain::{BestHeadersChain, Information as BestHeadersInformation};
|
||||
use primitives::bytes::Bytes;
|
||||
use primitives::hash::H256;
|
||||
|
|
|
@ -7,8 +7,8 @@ use futures::{BoxFuture, Future, finished};
|
|||
use futures::stream::Stream;
|
||||
use tokio_core::reactor::{Handle, Interval};
|
||||
use futures_cpupool::CpuPool;
|
||||
use db::{self, IndexedBlock, BlockHeaderProvider, BlockRef};
|
||||
use chain::{BlockHeader, Transaction};
|
||||
use db::{self, BlockHeaderProvider, BlockRef};
|
||||
use chain::{BlockHeader, Transaction, IndexedBlock};
|
||||
use message::types;
|
||||
use message::common::{InventoryVector, InventoryType};
|
||||
use primitives::hash::H256;
|
||||
|
@ -1312,7 +1312,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
}
|
||||
},
|
||||
BlockAnnouncementType::SendCompactBlock => {
|
||||
let indexed_blocks: Vec<db::IndexedBlock> = {
|
||||
let indexed_blocks: Vec<IndexedBlock> = {
|
||||
let chain = self.chain.read();
|
||||
new_blocks_hashes.iter()
|
||||
.filter_map(|h| chain.storage().block(db::BlockRef::Hash(h.clone())))
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::thread;
|
|||
use std::collections::{VecDeque, HashSet};
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use chain::{Transaction, OutPoint, TransactionOutput};
|
||||
use chain::{Transaction, OutPoint, TransactionOutput, IndexedBlock};
|
||||
use network::Magic;
|
||||
use miner::{HashedOutPoint, DoubleSpendCheckResult};
|
||||
use primitives::hash::H256;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::ops;
|
||||
use primitives::hash::H256;
|
||||
use db::{IndexedBlock, IndexedTransaction, IndexedBlockHeader};
|
||||
use chain::{IndexedBlock, IndexedTransaction, IndexedBlockHeader};
|
||||
|
||||
/// Blocks whose parents are known to be in the chain
|
||||
#[derive(Clone, Copy)]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! Bitcoin chain verifier
|
||||
|
||||
use hash::H256;
|
||||
use db::{self, IndexedBlockHeader, BlockLocation, PreviousTransactionOutputProvider, BlockHeaderProvider, TransactionOutputObserver};
|
||||
use chain::{IndexedBlock, IndexedBlockHeader, BlockHeader, Transaction};
|
||||
use db::{BlockLocation, SharedStore, PreviousTransactionOutputProvider, BlockHeaderProvider, TransactionOutputObserver};
|
||||
use network::Magic;
|
||||
use error::{Error, TransactionError};
|
||||
use {Verify, chain};
|
||||
use canon::{CanonBlock, CanonTransaction};
|
||||
use duplex_store::{DuplexTransactionOutputProvider, NoopStore};
|
||||
use verify_chain::ChainVerifier;
|
||||
|
@ -12,6 +12,7 @@ use verify_header::HeaderVerifier;
|
|||
use verify_transaction::MemoryPoolTransactionVerifier;
|
||||
use accept_chain::ChainAcceptor;
|
||||
use accept_transaction::MemoryPoolTransactionAcceptor;
|
||||
use Verify;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
/// Block verification chain
|
||||
|
@ -28,13 +29,13 @@ pub enum Chain {
|
|||
pub type VerificationResult = Result<Chain, Error>;
|
||||
|
||||
pub struct BackwardsCompatibleChainVerifier {
|
||||
store: db::SharedStore,
|
||||
store: SharedStore,
|
||||
skip_pow: bool,
|
||||
network: Magic,
|
||||
}
|
||||
|
||||
impl BackwardsCompatibleChainVerifier {
|
||||
pub fn new(store: db::SharedStore, network: Magic) -> Self {
|
||||
pub fn new(store: SharedStore, network: Magic) -> Self {
|
||||
BackwardsCompatibleChainVerifier {
|
||||
store: store,
|
||||
skip_pow: false,
|
||||
|
@ -48,7 +49,7 @@ impl BackwardsCompatibleChainVerifier {
|
|||
self
|
||||
}
|
||||
|
||||
fn verify_block(&self, block: &db::IndexedBlock) -> VerificationResult {
|
||||
fn verify_block(&self, block: &IndexedBlock) -> VerificationResult {
|
||||
let current_time = ::time::get_time().sec as u32;
|
||||
// first run pre-verification
|
||||
let chain_verifier = ChainVerifier::new(block, self.network, current_time);
|
||||
|
@ -77,7 +78,7 @@ impl BackwardsCompatibleChainVerifier {
|
|||
&self,
|
||||
_block_header_provider: &BlockHeaderProvider,
|
||||
hash: &H256,
|
||||
header: &chain::BlockHeader
|
||||
header: &BlockHeader
|
||||
) -> Result<(), Error> {
|
||||
// let's do only preverifcation
|
||||
// TODO: full verification
|
||||
|
@ -92,7 +93,7 @@ impl BackwardsCompatibleChainVerifier {
|
|||
prevout_provider: &T,
|
||||
height: u32,
|
||||
time: u32,
|
||||
transaction: &chain::Transaction,
|
||||
transaction: &Transaction,
|
||||
) -> Result<(), TransactionError> where T: PreviousTransactionOutputProvider + TransactionOutputObserver {
|
||||
let indexed_tx = transaction.clone().into();
|
||||
// let's do preverification first
|
||||
|
@ -117,7 +118,7 @@ impl BackwardsCompatibleChainVerifier {
|
|||
}
|
||||
|
||||
impl Verify for BackwardsCompatibleChainVerifier {
|
||||
fn verify(&self, block: &db::IndexedBlock) -> VerificationResult {
|
||||
fn verify(&self, block: &IndexedBlock) -> VerificationResult {
|
||||
let result = self.verify_block(block);
|
||||
trace!(
|
||||
target: "verification", "Block {} (transactions: {}) verification finished. Result {:?}",
|
||||
|
@ -132,7 +133,8 @@ impl Verify for BackwardsCompatibleChainVerifier {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use db::{TestStorage, Storage, Store, BlockStapler, IndexedBlock};
|
||||
use chain::IndexedBlock;
|
||||
use db::{TestStorage, Storage, Store, BlockStapler};
|
||||
use network::Magic;
|
||||
use devtools::RandomTempPath;
|
||||
use {script, test_data};
|
||||
|
|
|
@ -112,5 +112,5 @@ pub use work::{work_required, is_valid_proof_of_work, is_valid_proof_of_work_has
|
|||
|
||||
/// Interface for block verification
|
||||
pub trait Verify : Send + Sync {
|
||||
fn verify(&self, block: &db::IndexedBlock) -> VerificationResult;
|
||||
fn verify(&self, block: &chain::IndexedBlock) -> VerificationResult;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::collections::HashSet;
|
||||
use db::IndexedBlock;
|
||||
use chain::IndexedBlock;
|
||||
use sigops::transaction_sigops;
|
||||
use duplex_store::NoopStore;
|
||||
use error::{Error, TransactionError};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rayon::prelude::{IntoParallelRefIterator, IndexedParallelIterator, ParallelIterator};
|
||||
use db::IndexedBlock;
|
||||
use chain::IndexedBlock;
|
||||
use network::Magic;
|
||||
use error::Error;
|
||||
use verify_block::BlockVerifier;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use primitives::compact::Compact;
|
||||
use db::IndexedBlockHeader;
|
||||
use chain::IndexedBlockHeader;
|
||||
use network::Magic;
|
||||
use work::is_valid_proof_of_work;
|
||||
use error::Error;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::ops;
|
||||
use serialization::Serializable;
|
||||
use db::IndexedTransaction;
|
||||
use chain::IndexedTransaction;
|
||||
use duplex_store::NoopStore;
|
||||
use sigops::transaction_sigops;
|
||||
use error::TransactionError;
|
||||
|
|
Loading…
Reference in New Issue