Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Response to Issue#32. #75

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# bitcoin-blockchain-parser [![Build Status](https://travis-ci.org/alecalve/python-bitcoin-blockchain-parser.svg?branch=master)](https://travis-ci.org/alecalve/python-bitcoin-blockchain-parser) [![Coverage Status](https://coveralls.io/repos/alecalve/python-bitcoin-blockchain-parser/badge.svg?branch=master&service=github)](https://coveralls.io/github/alecalve/python-bitcoin-blockchain-parser?branch=master)
This Python 3 library provides a parser for the raw data stored by bitcoind.
# python-bitcoin-blockchain-parser [![Build Status](https://travis-ci.org/alecalve/python-bitcoin-blockchain-parser.svg?branch=master)](https://travis-ci.org/alecalve/python-bitcoin-blockchain-parser) [![Coverage Status](https://coveralls.io/repos/alecalve/python-bitcoin-blockchain-parser/badge.svg?branch=master&service=github)](https://coveralls.io/github/alecalve/python-bitcoin-blockchain-parser?branch=master)
This Python 3 library provides a parser for the raw data stored by bitcoind (blk*.dat files).

## Features
- Detects outputs types
Expand Down
21 changes: 4 additions & 17 deletions blockchain_parser/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,13 @@ class Block(object):

def __init__(self, raw_hex, height = None):
self.hex = raw_hex
self._hash = None
self._transactions = None
self._header = None
self._n_transactions = None
self._hash = format_hash(double_sha256(self.hex[:80]))
self._header = BlockHeader(self.hex[:80])
self._n_transactions = decode_varint(self.hex[80:])[0]
self._transactions = list(get_block_transactions(self.hex))
self.size = len(raw_hex)
self.height = height

def __repr__(self):
return "Block(%s)" % self.hash

@classmethod
def from_hex(cls, raw_hex):
"""Builds a block object from its bytes representation"""
Expand All @@ -58,8 +55,6 @@ def from_hex(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
Expand All @@ -68,23 +63,15 @@ def n_transactions(self):
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
51 changes: 15 additions & 36 deletions blockchain_parser/block_header.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,82 +9,61 @@
# modified, propagated, or distributed except according to the terms contained
# in the LICENSE file.

import struct
from datetime import datetime
from bitcoin.core import CBlockHeader

from .utils import decode_uint32, format_hash
from .utils import format_hash


class BlockHeader(object):
"""Represents a block header"""

def __init__(self, raw_hex):
self._version = None
self._previous_block_hash = None
self._merkle_root = None
self._timestamp = None
self._bits = None
self._nonce = None
self._difficulty = None

self.hex = raw_hex[:80]

def __repr__(self):
return "BlockHeader(previous_block_hash=%s)" % self.previous_block_hash

@classmethod
def from_hex(cls, raw_hex):
"""Builds a BlockHeader object from its bytes representation"""
return cls(raw_hex)

self._hex = raw_hex[:80]
self._version,\
self._previous_block_hash,\
self._merkle_root,\
self._timestamp,\
self._bits,\
self._nonce = struct.unpack("<I32s32sIII", self._hex)
self._previous_block_hash,\
self._merkle_root = format_hash(self._previous_block_hash),\
format_hash(self._merkle_root)
self._difficulty = CBlockHeader.calc_difficulty(self._bits)

# GETTER Functions
@property
def version(self):
"""Return the block's version"""
if self._version is None:
self._version = decode_uint32(self.hex[:4])
return self._version

@property
def previous_block_hash(self):
"""Return the hash of the previous block"""
if self._previous_block_hash is None:
self._previous_block_hash = format_hash(self.hex[4:36])
return self._previous_block_hash

@property
def merkle_root(self):
"""Returns the block's merkle root"""
if self._merkle_root is None:
self._merkle_root = format_hash(self.hex[36:68])
return self._merkle_root

@property
def timestamp(self):
"""Returns the timestamp of the block as a UTC datetime object"""
if self._timestamp is None:
self._timestamp = datetime.utcfromtimestamp(
decode_uint32(self.hex[68:72])
)
return self._timestamp

@property
def bits(self):
"""Returns the bits (difficulty target) of the block"""
if self._bits is None:
self._bits = decode_uint32(self.hex[72:76])
return self._bits

@property
def nonce(self):
"""Returns the block's nonce"""
if self._nonce is None:
self._nonce = decode_uint32(self.hex[76:80])
return self._nonce

@property
def difficulty(self):
"""Returns the block's difficulty target as a float"""
if self._difficulty is None:
self._difficulty = CBlockHeader.calc_difficulty(self.bits)

return self._difficulty
2 changes: 1 addition & 1 deletion blockchain_parser/tests/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_from_hex(self):
self.assertEqual(1, block.header.version)
self.assertEqual(1, block.header.difficulty)
self.assertEqual(285, block.size)
self.assertEqual(datetime.utcfromtimestamp(1231006505),
self.assertEqual(1231006505,
block.header.timestamp)
self.assertEqual("0" * 64, block.header.previous_block_hash)

Expand Down