bitcoin_chain/
blockchain.rs

1// Rust Bitcoin Library
2// Written in 2014 by
3//     Andrew Poelstra <apoelstra@wpsoftware.net>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the CC0 Public Domain Dedication
11// along with this software.
12// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13//
14
15//! # Bitcoin Blockchain
16//!
17//! This module provides the structures and functions to maintain the
18//! blockchain.
19//!
20
21use std::{marker, ptr};
22use std::convert::From;
23use std::error::Error;
24use std::fmt;
25
26use bitcoin::blockdata::block::{Block, BlockHeader};
27use bitcoin::blockdata::transaction::Transaction;
28use bitcoin::blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN,
29                                                     TARGET_BLOCK_SPACING, max_target, genesis_block};
30use bitcoin::network::constants::Network;
31use bitcoin::consensus::{Decodable, Encodable};
32use bitcoin::util::BitArray;
33use bitcoin::util::uint::Uint256;
34use bitcoin::util::hash::{BitcoinHash, Sha256dHash};
35use bitcoin::consensus::{Decoder, Encoder};
36use bitcoin;
37use patricia_tree::PatriciaTree;
38use bitcoin::consensus::encode;
39
40
41type BlockTree = PatriciaTree<Uint256, Box<BlockchainNode>>;
42type NodePtr = *const BlockchainNode;
43
44pub enum BlockchainError {
45    BlockNotFound,
46    DuplicateHash,
47    PrevHashNotFound,
48    BitcoinError(bitcoin::Error)
49}
50
51impl From<bitcoin::Error> for BlockchainError {
52    fn from(e: bitcoin::Error) -> Self {
53        BlockchainError::BitcoinError(e)
54    }
55}
56
57impl Error for BlockchainError {
58}
59
60impl fmt::Display for BlockchainError {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        match *self {
63            BlockchainError::BlockNotFound => write!(f, "Block not found"),
64            BlockchainError::DuplicateHash => write!(f, "Duplicate hash"),
65            BlockchainError::PrevHashNotFound => write!(f, "previous hash not found"),
66            BlockchainError::BitcoinError(ref err) => write!(f, "Serialize error: {}", err),
67        }
68    }
69}
70
71impl fmt::Debug for BlockchainError {
72    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73        (self as &fmt::Display).fmt(f)
74    }
75}
76
77/// A link in the blockchain
78pub struct BlockchainNode {
79    /// The actual block
80    pub block: Block,
81    /// Total work from genesis to this point
82    pub total_work: Uint256,
83    /// Expected value of `block.header.bits` for this block; only changes every
84    /// `blockdata::constants::DIFFCHANGE_INTERVAL;` blocks
85    pub required_difficulty: Uint256,
86    /// Height above genesis
87    pub height: u32,
88    /// Whether the transaction data is stored
89    pub has_txdata: bool,
90    /// Pointer to block's parent
91    prev: NodePtr,
92    /// Pointer to block's child
93    next: NodePtr
94}
95
96unsafe impl Send for BlockchainNode {}
97
98impl BlockchainNode {
99    /// Is the node on the main chain?
100    pub fn is_on_main_chain(&self, chain: &Blockchain) -> bool {
101        if self.block.header == unsafe { (*chain.best_tip).block.header } {
102            true
103        } else {
104            unsafe {
105                let mut scan = self.next;
106                while !scan.is_null() {
107                    if (*scan).block.header == (*chain.best_tip).block.header {
108                        return true;
109                    }
110                    scan = (*scan).next;
111                }
112            }
113            false
114        }
115    }
116}
117
118impl<S: Encoder> Encodable<S> for BlockchainNode {
119    #[inline]
120    fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> where S: Encoder {
121        try!(self.block.consensus_encode(s));
122        try!(self.total_work.consensus_encode(s));
123        try!(self.required_difficulty.consensus_encode(s));
124        try!(self.height.consensus_encode(s));
125        try!(self.has_txdata.consensus_encode(s));
126        // Don't serialize the prev or next pointers
127        Ok(())
128    }
129}
130
131impl<D: Decoder> Decodable<D> for BlockchainNode {
132    #[inline]
133    fn consensus_decode(d: &mut D) -> Result<BlockchainNode, encode::Error> where D: Decoder {
134        Ok(BlockchainNode {
135            block: try!(Decodable::consensus_decode(d)),
136            total_work: try!(Decodable::consensus_decode(d)),
137            required_difficulty: try!(Decodable::consensus_decode(d)),
138            height: try!(Decodable::consensus_decode(d)),
139            has_txdata: try!(Decodable::consensus_decode(d)),
140            prev: ptr::null(),
141            next: ptr::null()
142        })
143    }
144}
145
146impl BitcoinHash for BlockchainNode {
147    fn bitcoin_hash(&self) -> Sha256dHash {
148        self.block.header.bitcoin_hash()
149    }
150}
151
152/// The blockchain
153pub struct Blockchain {
154    network: Network,
155    tree: BlockTree,
156    best_tip: NodePtr,
157    best_hash: Sha256dHash,
158    genesis_hash: Sha256dHash
159}
160
161unsafe impl Send for Blockchain {}
162
163impl<S: Encoder> Encodable<S> for Blockchain {
164    #[inline]
165    fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
166        try!(self.network.consensus_encode(s));
167        try!(self.tree.consensus_encode(s));
168        try!(self.best_hash.consensus_encode(s));
169        try!(self.genesis_hash.consensus_encode(s));
170        Ok(())
171    }
172}
173
174impl<D: Decoder> Decodable<D> for Blockchain {
175    fn consensus_decode(d: &mut D) -> Result<Blockchain, encode::Error> {
176        let network: Network = try!(Decodable::consensus_decode(d));
177        let mut tree: BlockTree = try!(Decodable::consensus_decode(d));
178        let best_hash: Sha256dHash = try!(Decodable::consensus_decode(d));
179        let genesis_hash: Sha256dHash = try!(Decodable::consensus_decode(d));
180
181        // Lookup best tip
182        let best = match tree.lookup(&best_hash.into_le(), 256) {
183            Some(node) => &**node as NodePtr,
184            None => {
185                // TODO: this is a dirty hack to compile. This entire project will be decomissioned soon
186                return Err(encode::Error::UnrecognizedNetworkCommand(format!("best tip {:x} not in tree", best_hash)));
187            }
188        };
189        // Lookup genesis
190        if tree.lookup(&genesis_hash.into_le(), 256).is_none() {
191            // TODO: this is a dirty hack to compile. This entire project will be decomissioned soon
192            return Err(encode::Error::UnrecognizedNetworkCommand(format!("genesis {:x} not in tree", genesis_hash)));
193        }
194        // Reconnect all prev pointers
195        let raw_tree = &tree as *const BlockTree;
196        for node in tree.mut_iter() {
197            let hash = node.block.header.prev_blockhash.into_le();
198            let prevptr =
199                match unsafe { (*raw_tree).lookup(&hash, 256) } {
200                    Some(node) => &**node as NodePtr,
201                    None => ptr::null() 
202                };
203            node.prev = prevptr;
204        }
205        // Reconnect next pointers on the main chain
206        unsafe {
207            let mut scan = best;
208            while !(*scan).prev.is_null() {
209                let prev = (*scan).prev as *mut BlockchainNode;
210                (*prev).next = scan;
211                scan = prev as NodePtr;
212            }
213
214            // Check that "genesis" is the genesis
215            if (*scan).bitcoin_hash() != genesis_hash {
216                // TODO: this is a dirty hack to compile. This entire project will be decomissioned soon
217                return Err(encode::Error::UnrecognizedNetworkCommand(format!("no path from tip {:x} to genesis {:x}",
218                                                                                best_hash, genesis_hash)));
219            }
220        }
221
222        // Return the chain
223        Ok(Blockchain {
224            network: network,
225            tree: tree,
226            best_tip: best,
227            best_hash: best_hash,
228            genesis_hash: genesis_hash
229        })
230    }
231}
232
233// TODO: this should maybe be public, in which case it needs to be tagged
234// with a PhantomData marker tying it to the tree's lifetime.
235struct LocatorHashIter {
236    index: NodePtr,
237    count: usize,
238    skip: usize
239}
240
241impl LocatorHashIter {
242    fn new(init: NodePtr) -> LocatorHashIter {
243        LocatorHashIter { index: init, count: 0, skip: 1 }
244    }
245}
246
247impl Iterator for LocatorHashIter {
248    type Item = Sha256dHash;
249
250    fn next(&mut self) -> Option<Sha256dHash> {
251        if self.index.is_null() {
252            return None;
253        }
254        let ret = Some(unsafe { (*self.index).bitcoin_hash() });
255
256        // Rewind once (if we are at the genesis, this will set self.index to None)
257        self.index = unsafe { (*self.index).prev };
258        // If we are not at the genesis, rewind `self.skip` times, or until we are.
259        if !self.index.is_null() {
260            for _ in 1..self.skip {
261                unsafe {
262                    if (*self.index).prev.is_null() {
263                        break;
264                    }
265                    self.index = (*self.index).prev;
266                }
267            }
268        }
269
270        self.count += 1;
271        if self.count > 10 {
272            self.skip *= 2;
273        }
274        ret
275    }
276}
277
278/// An iterator over blocks in blockheight order
279pub struct BlockIter<'tree> {
280    index: NodePtr,
281    // Note: we don't actually touch the blockchain. But we need
282    // to keep it borrowed to prevent it being mutated, since some
283    // mutable blockchain methods call .mut_borrow() on the block
284    // links, which would blow up if the iterator did a regular
285    // borrow at the same time.
286    marker: marker::PhantomData<&'tree Blockchain>
287}
288
289/// An iterator over blocks in reverse blockheight order. Note that this
290/// is essentially the same as if we'd implemented `DoubleEndedIterator`
291/// on `BlockIter` --- but we can't do that since if `BlockIter` is started
292/// off the main chain, it will not reach the best tip, so the iterator
293/// and its `.rev()` would be iterators over different chains! To avoid
294/// this suprising behaviour we simply use separate iterators.
295pub struct RevBlockIter<'tree> {
296    index: NodePtr,
297    // See comment in BlockIter for why we need this
298    marker: marker::PhantomData<&'tree Blockchain>
299}
300
301/// An iterator over blocks in reverse blockheight order, which yielding only
302/// stale blocks (ending at the point where it would've returned a block on
303/// the main chain). It does this by checking if the `next` pointer of the
304/// next-to-by-yielded block matches the currently-yielded block. If not, scan
305/// forward from next-to-be-yielded block. If we hit the best tip, set the
306/// next-to-by-yielded block to None instead.
307///
308/// So to handle reorgs, you create a `RevStaleBlockIter` starting from the last
309/// known block, and play it until it runs out, rewinding every block except for
310/// the last one. Since the `UtxoSet` `rewind` function sets its `last_hash()` to
311/// the prevblockhash of the rewinded block (which will be on the main chain at
312/// the end of the iteration), you can then sync it up same as if you were doing
313/// a plain old fast-forward.
314pub struct RevStaleBlockIter<'tree> {
315    index: NodePtr,
316    chain: &'tree Blockchain
317}
318
319impl<'tree> Iterator for BlockIter<'tree> {
320    type Item = &'tree BlockchainNode;
321
322    fn next(&mut self) -> Option<&'tree BlockchainNode> {
323        if self.index.is_null() {
324            return None;
325        }
326        unsafe {
327            let ret = Some(&*self.index);
328            self.index = (*self.index).next;
329            ret
330        }
331    }
332}
333
334impl<'tree> Iterator for RevBlockIter<'tree> {
335    type Item = &'tree BlockchainNode;
336
337    fn next(&mut self) -> Option<&'tree BlockchainNode> {
338        if self.index.is_null() {
339            return None;
340        }
341        unsafe {
342            let ret = Some(&*self.index);
343            self.index = (*self.index).prev;
344            ret
345        }
346    }
347}
348
349impl<'tree> Iterator for RevStaleBlockIter<'tree> {
350    type Item = &'tree Block;
351
352    fn next(&mut self) -> Option<&'tree Block> { 
353        if self.index.is_null() {
354            return None;
355        }
356
357        unsafe {
358            let ret = Some(&(*self.index).block);
359            let next_index = (*self.index).prev;
360            // Check if the next block is going to be on the main chain
361            if !next_index.is_null() &&
362                 (*next_index).next != self.index &&
363                 (&*next_index).is_on_main_chain(self.chain) {
364                self.index = ptr::null();
365            } else {
366                self.index = next_index;
367            }
368            ret
369        }
370    }
371}
372
373/// This function emulates the `GetCompact(SetCompact(n))` in the satoshi code,
374/// which drops the precision to something that can be encoded precisely in
375/// the nBits block header field. Savour the perversity. This is in Bitcoin
376/// consensus code. What. Gaah!
377fn satoshi_the_precision(n: Uint256) -> Uint256 {
378    // Shift by B bits right then left to turn the low bits to zero
379    let bits = 8 * ((n.bits() + 7) / 8 - 3);
380    let mut ret = n >> bits;
381    // Oh, did I say B was that fucked up formula? I meant sometimes also + 8.
382    if ret.bit(23) {
383        ret = (ret >> 8) << 8;
384    }
385    ret << bits
386}
387
388impl Blockchain {
389    /// Constructs a new blockchain
390    pub fn new(network: Network) -> Blockchain {
391        let genesis = genesis_block(network);
392        let genhash = genesis.header.bitcoin_hash();
393        let new_node = Box::new(BlockchainNode {
394            total_work: Default::default(),
395            required_difficulty: genesis.header.target(),
396            block: genesis,
397            height: 0,
398            has_txdata: true,
399            prev: ptr::null(),
400            next: ptr::null()
401        });
402        let raw_ptr = &*new_node as NodePtr;
403        Blockchain {
404            network: network,
405            tree: {
406                let mut pat = PatriciaTree::new();
407                pat.insert(&genhash.into_le(), 256, new_node);
408                pat
409            },
410            best_hash: genhash,
411            genesis_hash: genhash,
412            best_tip: raw_ptr
413        }
414    }
415
416    fn replace_txdata(&mut self, hash: &Uint256, txdata: Vec<Transaction>, has_txdata: bool) -> Result<(), BlockchainError> {
417        match self.tree.lookup_mut(hash, 256) {
418            Some(existing_block) => {
419                existing_block.block.txdata.clone_from(&txdata);
420                existing_block.has_txdata = has_txdata;
421                Ok(())
422            },
423            None => Err(BlockchainError::BlockNotFound)
424        }
425    }
426
427    /// Looks up a block in the chain and returns the BlockchainNode containing it
428    pub fn get_block(&self, hash: Sha256dHash) -> Option<&BlockchainNode> {
429        self.tree.lookup(&hash.into_le(), 256).map(|node| &**node)
430    }
431
432    /// Locates a block in the chain and overwrites its txdata
433    pub fn add_txdata(&mut self, block: Block) -> Result<(), BlockchainError> {
434        self.replace_txdata(&block.header.bitcoin_hash().into_le(), block.txdata, true)
435    }
436
437    /// Locates a block in the chain and removes its txdata
438    pub fn remove_txdata(&mut self, hash: Sha256dHash) -> Result<(), BlockchainError> {
439        self.replace_txdata(&hash.into_le(), vec![], false)
440    }
441
442    /// Adds a block header to the chain
443    pub fn add_header(&mut self, header: BlockHeader) -> Result<(), BlockchainError> {
444        self.real_add_block(Block { header: header, txdata: vec![] }, false)
445    }
446
447    /// Adds a block to the chain
448    pub fn add_block(&mut self, block: Block) -> Result<(), BlockchainError> {
449        self.real_add_block(block, true)
450    }
451
452    fn real_add_block(&mut self, block: Block, has_txdata: bool) -> Result<(), BlockchainError> {
453        // get_prev optimizes the common case where we are extending the best tip
454        #[inline]
455        fn get_prev(chain: &Blockchain, hash: Sha256dHash) -> Option<NodePtr> {
456            if hash == chain.best_hash { 
457                Some(chain.best_tip)
458            } else {
459                chain.tree.lookup(&hash.into_le(), 256).map(|boxptr| &**boxptr as NodePtr)
460            }
461        }
462        // Check for multiple inserts (bitcoind from c9a09183 to 3c85d2ec doesn't
463        // handle locator hashes properly and may return blocks multiple times,
464        // and this may also happen in case of a reorg.
465        if self.tree.lookup(&block.header.bitcoin_hash().into_le(), 256).is_some() {
466            return Err(BlockchainError::DuplicateHash);
467        }
468        // Construct node, if possible
469        let new_block = match get_prev(self, block.header.prev_blockhash) {
470            Some(prev) => {
471                let difficulty =
472                    // Compute required difficulty if this is a diffchange block
473                    if (unsafe { (*prev).height } + 1) % DIFFCHANGE_INTERVAL == 0 {
474                        let timespan = unsafe {
475                            // Scan back DIFFCHANGE_INTERVAL blocks
476                            let mut scan = prev;
477                            for _ in 0..(DIFFCHANGE_INTERVAL - 1) {
478                                scan = (*scan).prev;
479                            }
480                            // Get clamped timespan between first and last blocks
481                            match (*prev).block.header.time - (*scan).block.header.time {
482                                n if n < DIFFCHANGE_TIMESPAN / 4 => DIFFCHANGE_TIMESPAN / 4,
483                                n if n > DIFFCHANGE_TIMESPAN * 4 => DIFFCHANGE_TIMESPAN * 4,
484                                n => n
485                            }
486                        };
487                        // Compute new target
488                        let mut target = unsafe { (*prev).block.header.target() };
489                        target = target.mul_u32(timespan);
490                        target = target / Uint256::from_u64(DIFFCHANGE_TIMESPAN as u64).unwrap();
491                        // Clamp below MAX_TARGET (difficulty 1)
492                        let max = max_target(self.network);
493                        if target > max { target = max };
494                        // Compactify (make expressible in the 8+24 nBits float format
495                        satoshi_the_precision(target)
496                    // On non-diffchange blocks, Testnet has a rule that any 20-minute-long
497                    // block intervals result the difficulty
498                    } else if self.network == Network::Testnet &&
499                                        block.header.time > unsafe { (*prev).block.header.time } + 2*TARGET_BLOCK_SPACING {
500                        max_target(self.network)
501                    // On the other hand, if we are in Testnet and the block interval is less
502                    // than 20 minutes, we need to scan backward to find a block for which the
503                    // previous rule did not apply, to find the "real" difficulty.
504                    } else if self.network == Network::Testnet {
505                        // Scan back DIFFCHANGE_INTERVAL blocks
506                        unsafe {
507                            let mut scan = prev;
508                            while (*scan).height % DIFFCHANGE_INTERVAL != 0 &&
509                                        (*scan).required_difficulty == max_target(self.network) {
510                                scan = (*scan).prev;
511                            }
512                            (*scan).required_difficulty
513                        }
514                    // Otherwise just use the last block's difficulty
515                    } else {
516                        unsafe { (*prev).required_difficulty }
517                    };
518                // Create node
519                let ret = Box::new(BlockchainNode {
520                    total_work: block.header.work() + unsafe { (*prev).total_work },
521                    block: block,
522                    required_difficulty: difficulty,
523                    height: unsafe { (*prev).height + 1 },
524                    has_txdata: has_txdata,
525                    prev: prev,
526                    next: ptr::null()
527                });
528                unsafe {
529                    let prev = prev as *mut BlockchainNode;
530                    (*prev).next = &*ret as NodePtr;
531                }
532                ret
533            },
534            None => {
535                return Err(BlockchainError::PrevHashNotFound);
536            }
537        };
538
539        // spv validate the block
540        try!(new_block.block.header.spv_validate(&new_block.required_difficulty));
541
542        // Insert the new block
543        let raw_ptr = &*new_block as NodePtr;
544        self.tree.insert(&new_block.block.header.bitcoin_hash().into_le(), 256, new_block);
545        // Replace the best tip if necessary
546        if unsafe { (*raw_ptr).total_work > (*self.best_tip).total_work } {
547            self.set_best_tip(raw_ptr);
548        }
549        Ok(())
550    }
551
552    /// Sets the best tip (not public)
553    fn set_best_tip(&mut self, tip: NodePtr) {
554        // Fix next links
555        unsafe {
556            let mut scan = self.best_tip;
557            // Scan backward
558            while !(*scan).prev.is_null() {
559                // If we hit the old best, there is no need to reorg.
560                if scan == self.best_tip { break; }
561                // Otherwise set the next-ptr and carry on
562                let prev = (*scan).prev as *mut BlockchainNode;
563                (*prev).next = scan;
564                scan = (*scan).prev;
565            }
566        }
567        // Set best
568        self.best_hash = unsafe { (*tip).bitcoin_hash() };
569        self.best_tip = tip;
570    }
571
572    /// Returns the genesis block's blockhash
573    pub fn genesis_hash(&self) -> Sha256dHash {
574        self.genesis_hash
575    }
576
577    /// Returns the best tip
578    pub fn best_tip(&self) -> &Block {
579        unsafe { &(*self.best_tip).block }
580    }
581
582    /// Returns the best tip height
583    pub fn best_tip_height(&self) -> u32 {
584        unsafe { (*self.best_tip).height }
585    }
586
587    /// Returns the best tip's blockhash
588    pub fn best_tip_hash(&self) -> Sha256dHash {
589        self.best_hash
590    }
591
592    /// Returns an array of locator hashes used in `getheaders` messages
593    pub fn locator_hashes(&self) -> Vec<Sha256dHash> {
594        LocatorHashIter::new(self.best_tip).collect()
595    }
596
597    /// An iterator over all blocks in the chain starting from `start_hash`
598    pub fn iter(&self, start_hash: Sha256dHash) -> BlockIter {
599        let start = match self.tree.lookup(&start_hash.into_le(), 256) {
600                Some(boxptr) => &**boxptr as NodePtr,
601                None => ptr::null()
602            };
603        BlockIter {
604            index: start,
605            marker: marker::PhantomData
606        }
607    }
608
609    /// An iterator over all blocks in reverse order to the genesis, starting with `start_hash`
610    pub fn rev_iter(&self, start_hash: Sha256dHash) -> RevBlockIter {
611        let start = match self.tree.lookup(&start_hash.into_le(), 256) {
612                Some(boxptr) => &**boxptr as NodePtr,
613                None => ptr::null()
614            };
615        RevBlockIter {
616            index: start,
617            marker: marker::PhantomData
618        }
619    }
620
621    /// An iterator over all blocks -not- in the best chain, in reverse order, starting from `start_hash`
622    pub fn rev_stale_iter(&self, start_hash: Sha256dHash) -> RevStaleBlockIter {
623        let start = match self.tree.lookup(&start_hash.into_le(), 256) {
624                Some(boxptr) => {
625                    // If we are already on the main chain, we have a dead iterator
626                    if boxptr.is_on_main_chain(self) {
627                        ptr::null()
628                    } else {
629                        &**boxptr as NodePtr
630                    }
631                }
632                None => ptr::null()
633            };
634        RevStaleBlockIter { 
635            index: start,
636            chain: self
637        }
638    }
639}
640
641#[cfg(test)]
642mod tests {
643    use super::Blockchain;
644    use bitcoin::blockdata::constants::genesis_block;
645    use bitcoin::network::constants::Network::Bitcoin;
646    use bitcoin::consensus::serialize;
647    use bitcoin::consensus::deserialize;
648    use bitcoin::BitcoinHash;
649
650
651    #[test]
652    fn blockchain_serialize_test() {
653        let empty_chain = Blockchain::new(Bitcoin);
654        assert_eq!(empty_chain.best_tip().header.bitcoin_hash(),
655                   genesis_block(Bitcoin).header.bitcoin_hash());
656
657        let serial = serialize(&empty_chain);
658        let deserial: Result<Blockchain, _> = deserialize(&serial);
659
660        assert!(deserial.is_ok());
661        let read_chain = deserial.unwrap();
662        assert_eq!(read_chain.best_tip().header.bitcoin_hash(),
663                   genesis_block(Bitcoin).header.bitcoin_hash());
664    }
665}
666
667
668