-
Notifications
You must be signed in to change notification settings - Fork 188
/
block.py
99 lines (82 loc) · 3.13 KB
/
block.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# Copyright (C) 2015-2016 The bitcoin-blockchain-parser developers
#
# This file is part of bitcoin-blockchain-parser.
#
# It is subject to the license terms in the LICENSE file found in the top-level
# directory of this distribution.
#
# No part of bitcoin-blockchain-parser, including this file, may be copied,
# modified, propagated, or distributed except according to the terms contained
# in the LICENSE file.
from .transaction import Transaction
from .block_header import BlockHeader
from .utils import format_hash, decode_varint, double_sha256
def get_block_transactions(raw_hex):
"""Given the raw hexadecimal representation of a block,
yields the block's transactions
"""
# Skipping the header
transaction_data = raw_hex[80:]
# Decoding the number of transactions, offset is the size of
# the varint (1 to 9 bytes)
n_transactions, offset = decode_varint(transaction_data)
for i in range(n_transactions):
# Try from 1024 (1KiB) -> 1073741824 (1GiB) slice widths
for j in range(0, 20):
try:
offset_e = offset + (1024 * 2 ** j)
transaction = Transaction.from_hex(
transaction_data[offset:offset_e])
yield transaction
break
except:
continue
# Skipping to the next transaction
offset += transaction.size
class Block(object):
"""
Represents a Bitcoin block, contains its header and its transactions.
"""
def __init__(self, raw_hex, height=None, blk_file=None):
self.hex = raw_hex
self._hash = None
self._transactions = None
self._header = None
self._n_transactions = None
self.size = len(raw_hex)
self.height = height
self.blk_file = blk_file
def __repr__(self):
return "Block(%s)" % self.hash
@classmethod
def from_hex(cls, raw_hex):
"""Builds a block object from its bytes representation"""
return cls(raw_hex)
@property
def hash(self):
"""Returns the block's hash (double sha256 of its 80 bytes header"""
if self._hash is None:
self._hash = format_hash(double_sha256(self.hex[:80]))
return self._hash
@property
def n_transactions(self):
"""Return the number of transactions contained in this block,
it is faster to use this than to use len(block.transactions)
as there's no need to parse all transactions to get this information
"""
if self._n_transactions is None:
self._n_transactions = decode_varint(self.hex[80:])[0]
return self._n_transactions
@property
def transactions(self):
"""Returns a list of the block's transactions represented
as Transaction objects"""
if self._transactions is None:
self._transactions = list(get_block_transactions(self.hex))
return self._transactions
@property
def header(self):
"""Returns a BlockHeader object corresponding to this block"""
if self._header is None:
self._header = BlockHeader.from_hex(self.hex[:80])
return self._header