bitcoin/blockdata/
block.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 Block
16//!
17//! A block is a bundle of transactions with a proof-of-work attached,
18//! which attaches to an earlier block to form the blockchain. This
19//! module describes structures and functions needed to describe
20//! these blocks and the blockchain.
21//!
22
23use bitcoin_hashes::{sha256d, Hash};
24
25use util;
26use util::Error::{SpvBadTarget, SpvBadProofOfWork};
27use util::hash::BitcoinHash;
28use util::uint::Uint256;
29use consensus::encode::VarInt;
30use network::constants::Network;
31use blockdata::transaction::Transaction;
32use blockdata::constants::max_target;
33
34/// A block header, which contains all the block's information except
35/// the actual transactions
36#[derive(Copy, PartialEq, Eq, Clone, Debug)]
37pub struct BlockHeader {
38    /// The protocol version. Should always be 1.
39    pub version: u32,
40    /// Reference to the previous block in the chain
41    pub prev_blockhash: sha256d::Hash,
42    /// The root hash of the merkle tree of transactions in the block
43    pub merkle_root: sha256d::Hash,
44    /// The timestamp of the block, as claimed by the miner
45    pub time: u32,
46    /// The target value below which the blockhash must lie, encoded as a
47    /// a float (with well-defined rounding, of course)
48    pub bits: u32,
49    /// The nonce, selected to obtain a low enough blockhash
50    pub nonce: u32,
51}
52
53/// A Bitcoin block, which is a collection of transactions with an attached
54/// proof of work.
55#[derive(PartialEq, Eq, Clone, Debug)]
56pub struct Block {
57    /// The block header
58    pub header: BlockHeader,
59    ///	Coinbase transaction that is in the parent block, linking the AuxPOW block to its parent block
60    pub coinbase_txn: Transaction,
61    /// Hash of the parent_block header
62    pub block_hash: sha256d::Hash,
63    /// The merkle branch linking the coinbase_txn to the parent block's merkle_root
64    pub coinbase_branch_hashes: Vec<sha256d::Hash>,
65    /// Bitmask of which side of the merkle hash function the branch_hash element should go on. Zero means it goes on the right, One means on the left. It is equal to the index of the starting hash within the widest level of the merkle tree for this merkle branch.
66    pub coinbase_branch_side_mask: u32,
67    /// The merkle branch linking this auxiliary blockchain to the others, when used in a merged mining setup with multiple auxiliary chains
68    pub blockchain_branch_hashes: Vec<sha256d::Hash>,
69    /// Bitmask of which side of the merkle hash function the branch_hash element should go on. Zero means it goes on the right, One means on the left. It is equal to the index of the starting hash within the widest level of the merkle tree for this merkle branch.
70    pub blockchain_branch_side_mask: u32,   
71    /// Parent block header
72    pub parent_block: BlockHeader,
73    /// List of transactions contained in the block
74    pub txdata: Vec<Transaction>
75}
76
77/// A block header with txcount attached, which is given in the `headers`
78/// network message.
79#[derive(PartialEq, Eq, Clone, Debug)]
80pub struct LoneBlockHeader {
81    /// The actual block header
82    pub header: BlockHeader,
83    /// The number of transactions in the block. This will always be zero
84    /// when the LoneBlockHeader is returned as part of a `headers` message.
85    pub tx_count: VarInt
86}
87/// A genesis block
88#[derive(PartialEq, Eq, Clone, Debug)]
89pub struct GenesisBlock {
90    /// The block header
91    pub header: BlockHeader,
92    /// List of transactions contained in the block
93    pub txdata: Vec<Transaction>
94}
95impl BlockHeader {
96    /// Computes the target [0, T] that a blockhash must land in to be valid
97    pub fn target(&self) -> Uint256 {
98        // This is a floating-point "compact" encoding originally used by
99        // OpenSSL, which satoshi put into consensus code, so we're stuck
100        // with it. The exponent needs to have 3 subtracted from it, hence
101        // this goofy decoding code:
102        let (mant, expt) = {
103            let unshifted_expt = self.bits >> 24;
104            if unshifted_expt <= 3 {
105                ((self.bits & 0xFFFFFF) >> (8 * (3 - unshifted_expt as usize)), 0)
106            } else {
107                (self.bits & 0xFFFFFF, 8 * ((self.bits >> 24) - 3))
108            }
109        };
110
111        // The mantissa is signed but may not be negative
112        if mant > 0x7FFFFF {
113            Default::default()
114        } else {
115            Uint256::from_u64(mant as u64).unwrap() << (expt as usize)
116        }
117    }
118
119    /// Computes the target value in float format from Uint256 format.
120    pub fn compact_target_from_u256(value: &Uint256) -> u32 {
121        let mut size = (value.bits() + 7) / 8;
122        let mut compact = if size <= 3 {
123            (value.low_u64() << (8 * (3 - size))) as u32
124        } else {
125            let bn = *value >> (8 * (size - 3));
126            bn.low_u32()
127        };
128
129        if (compact & 0x00800000) != 0 {
130            compact >>= 8;
131            size += 1;
132        }
133
134        compact | (size << 24) as u32
135    }
136
137    /// Compute the popular "difficulty" measure for mining
138    pub fn difficulty(&self, network: Network) -> u64 {
139        (max_target(network) / self.target()).low_u64()
140    }
141
142    /// Performs an SPV validation of a block, which confirms that the proof-of-work
143    /// is correct, but does not verify that the transactions are valid or encoded
144    /// correctly.
145    pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), util::Error> {
146        use byteorder::{ByteOrder, LittleEndian};
147
148        let target = &self.target();
149        if target != required_target {
150            return Err(SpvBadTarget);
151        }
152        let data: [u8; 32] = self.bitcoin_hash().into_inner();
153        let mut ret = [0u64; 4];
154        LittleEndian::read_u64_into(&data, &mut ret);
155        let hash = &Uint256(ret);
156        if hash <= target { Ok(()) } else { Err(SpvBadProofOfWork) }
157    }
158
159    /// Returns the total work of the block
160    pub fn work(&self) -> Uint256 {
161        // 2**256 / (target + 1) == ~target / (target+1) + 1    (eqn shamelessly stolen from bitcoind)
162        let mut ret = !self.target();
163        let mut ret1 = self.target();
164        ret1.increment();
165        ret = ret / ret1;
166        ret.increment();
167        ret
168    }
169}
170
171impl BitcoinHash for BlockHeader {
172    fn bitcoin_hash(&self) -> sha256d::Hash {
173        use consensus::encode::serialize;
174        sha256d::Hash::hash(&serialize(self))
175    }
176}
177
178impl BitcoinHash for Block {
179    fn bitcoin_hash(&self) -> sha256d::Hash {
180        self.header.bitcoin_hash()
181    }
182}
183impl_consensus_encoding!(BlockHeader, version, prev_blockhash, merkle_root, time, bits, nonce);
184impl_consensus_encoding!(Block, header, coinbase_txn, block_hash, coinbase_branch_hashes, coinbase_branch_side_mask, blockchain_branch_hashes, blockchain_branch_side_mask, parent_block, txdata);
185impl_consensus_encoding!(GenesisBlock, header, txdata);
186impl_consensus_encoding!(LoneBlockHeader, header, tx_count);
187
188#[cfg(test)]
189mod tests {
190    use hex::decode as hex_decode;
191
192    use blockdata::block::{Block, BlockHeader};
193    use consensus::encode::{deserialize, serialize};
194
195    #[test]
196    fn block_test() {
197        let some_block = hex_decode("040100106f378876737d2a2bfffd51ca4c7e3d6281dad5fbd0b8ce61cde88674440f0000aaa7bee217ab6c525b55734dfb013e6e7b7bb70848adb50407b6cc74fbf2011ee121525cf0ff0f1e0000000002000000010000000000000000000000000000000000000000000000000000000000000000ffffffff292890e8b09682761713f0f091aef58669e8c37149aedd282337da6193edc7ffc8f50100000000000000ffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000c69c3a951476397def6efd0d481944058f9d56497c040ff1c36c9f2ef090cbfb00000000000000005a5b000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510109ffffffff020040874e115cbd002321025687e93e908ab873cb37174215bed989791fe93e0ab5f5cc95f4250deb11fa8aac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
198        let cutoff_block = hex_decode("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000").unwrap();
199        let prevhash = hex_decode("6f378876737d2a2bfffd51ca4c7e3d6281dad5fbd0b8ce61cde88674440f0000").unwrap();
200        let merkle = hex_decode("aaa7bee217ab6c525b55734dfb013e6e7b7bb70848adb50407b6cc74fbf2011e").unwrap();
201
202        let decode: Result<Block, _> = deserialize(&some_block);
203        let bad_decode: Result<Block, _> = deserialize(&cutoff_block);
204
205        assert!(decode.is_ok());
206        assert!(bad_decode.is_err());
207        let real_decode = decode.unwrap();
208        assert_eq!(real_decode.header.version, 268435716);
209        assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash);
210        // [test] TODO: actually compute the merkle root
211        assert_eq!(serialize(&real_decode.header.merkle_root), merkle);
212        assert_eq!(real_decode.header.time, 1548886497);
213        assert_eq!(real_decode.header.bits, 504365040);
214        assert_eq!(real_decode.header.nonce, 0);
215        // [test] TODO: check the transaction data
216    
217        assert_eq!(serialize(&real_decode), some_block);
218    }
219    
220    #[test]
221    fn compact_roundrtip_test() {
222        let some_header = hex_decode("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b").unwrap();
223
224        let header: BlockHeader = deserialize(&some_header).expect("Can't deserialize correct block header");
225
226        assert_eq!(header.bits, BlockHeader::compact_target_from_u256(&header.target()));
227    }
228}
229