Browse Source

blockchain: use HEADER_SIZE named constant instead of magic numbers

master
SomberNight 7 years ago
parent
commit
1635bc8cb3
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 43
      electrum/blockchain.py

43
electrum/blockchain.py

@ -30,6 +30,7 @@ from . import constants
from .util import bfh, bh2u from .util import bfh, bh2u
HEADER_SIZE = 80 # bytes
MAX_TARGET = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 MAX_TARGET = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
@ -51,7 +52,7 @@ def serialize_header(header_dict: dict) -> str:
def deserialize_header(s: bytes, height: int) -> dict: def deserialize_header(s: bytes, height: int) -> dict:
if not s: if not s:
raise InvalidHeader('Invalid header: {}'.format(s)) raise InvalidHeader('Invalid header: {}'.format(s))
if len(s) != 80: if len(s) != HEADER_SIZE:
raise InvalidHeader('Invalid header length: {}'.format(len(s))) raise InvalidHeader('Invalid header length: {}'.format(len(s)))
hex_to_int = lambda s: int('0x' + bh2u(s[::-1]), 16) hex_to_int = lambda s: int('0x' + bh2u(s[::-1]), 16)
h = {} h = {}
@ -97,7 +98,7 @@ class Blockchain(util.PrintError):
Manages blockchain headers and their verification Manages blockchain headers and their verification
""" """
def __init__(self, config, forkpoint, parent_id): def __init__(self, config, forkpoint: int, parent_id: int):
self.config = config self.config = config
self.forkpoint = forkpoint self.forkpoint = forkpoint
self.checkpoints = constants.net.CHECKPOINTS self.checkpoints = constants.net.CHECKPOINTS
@ -113,7 +114,7 @@ class Blockchain(util.PrintError):
return func(self, *args, **kwargs) return func(self, *args, **kwargs)
return func_wrapper return func_wrapper
def parent(self): def parent(self) -> 'Blockchain':
return blockchains[self.parent_id] return blockchains[self.parent_id]
def get_max_child(self) -> Optional[int]: def get_max_child(self) -> Optional[int]:
@ -138,7 +139,7 @@ class Blockchain(util.PrintError):
except MissingHeader: except MissingHeader:
return False return False
def fork(parent, header: dict): def fork(parent, header: dict) -> 'Blockchain':
forkpoint = header.get('block_height') forkpoint = header.get('block_height')
self = Blockchain(parent.config, forkpoint, parent.forkpoint) self = Blockchain(parent.config, forkpoint, parent.forkpoint)
open(self.path(), 'w+').close() open(self.path(), 'w+').close()
@ -154,7 +155,7 @@ class Blockchain(util.PrintError):
def update_size(self) -> None: def update_size(self) -> None:
p = self.path() p = self.path()
self._size = os.path.getsize(p)//80 if os.path.exists(p) else 0 self._size = os.path.getsize(p)//HEADER_SIZE if os.path.exists(p) else 0
def verify_header(self, header: dict, prev_hash: str, target: int, expected_header_hash: str=None) -> None: def verify_header(self, header: dict, prev_hash: str, target: int, expected_header_hash: str=None) -> None:
_hash = hash_header(header) _hash = hash_header(header)
@ -171,7 +172,7 @@ class Blockchain(util.PrintError):
raise Exception("insufficient proof of work: %s vs target %s" % (int('0x' + _hash, 16), target)) raise Exception("insufficient proof of work: %s vs target %s" % (int('0x' + _hash, 16), target))
def verify_chunk(self, index: int, data: bytes) -> None: def verify_chunk(self, index: int, data: bytes) -> None:
num = len(data) // 80 num = len(data) // HEADER_SIZE
start_height = index * 2016 start_height = index * 2016
prev_hash = self.get_hash(start_height - 1) prev_hash = self.get_hash(start_height - 1)
target = self.get_target(index-1) target = self.get_target(index-1)
@ -181,14 +182,18 @@ class Blockchain(util.PrintError):
expected_header_hash = self.get_hash(height) expected_header_hash = self.get_hash(height)
except MissingHeader: except MissingHeader:
expected_header_hash = None expected_header_hash = None
raw_header = data[i*80:(i+1) * 80] raw_header = data[i*HEADER_SIZE : (i+1)*HEADER_SIZE]
header = deserialize_header(raw_header, index*2016 + i) header = deserialize_header(raw_header, index*2016 + i)
self.verify_header(header, prev_hash, target, expected_header_hash) self.verify_header(header, prev_hash, target, expected_header_hash)
prev_hash = hash_header(header) prev_hash = hash_header(header)
def path(self): def path(self):
d = util.get_headers_dir(self.config) d = util.get_headers_dir(self.config)
filename = 'blockchain_headers' if self.parent_id is None else os.path.join('forks', 'fork_%d_%d'%(self.parent_id, self.forkpoint)) if self.parent_id is None:
filename = 'blockchain_headers'
else:
basename = 'fork_%d_%d' % (self.parent_id, self.forkpoint)
filename = os.path.join('forks', basename)
return os.path.join(d, filename) return os.path.join(d, filename)
@with_lock @with_lock
@ -201,7 +206,7 @@ class Blockchain(util.PrintError):
return return
delta_height = (index * 2016 - self.forkpoint) delta_height = (index * 2016 - self.forkpoint)
delta_bytes = delta_height * 80 delta_bytes = delta_height * HEADER_SIZE
# if this chunk contains our forkpoint, only save the part after forkpoint # if this chunk contains our forkpoint, only save the part after forkpoint
# (the part before is the responsibility of the parent) # (the part before is the responsibility of the parent)
if delta_bytes < 0: if delta_bytes < 0:
@ -227,10 +232,10 @@ class Blockchain(util.PrintError):
my_data = f.read() my_data = f.read()
self.assert_headers_file_available(parent.path()) self.assert_headers_file_available(parent.path())
with open(parent.path(), 'rb') as f: with open(parent.path(), 'rb') as f:
f.seek((forkpoint - parent.forkpoint)*80) f.seek((forkpoint - parent.forkpoint)*HEADER_SIZE)
parent_data = f.read(parent_branch_size*80) parent_data = f.read(parent_branch_size*HEADER_SIZE)
self.write(parent_data, 0) self.write(parent_data, 0)
parent.write(my_data, (forkpoint - parent.forkpoint)*80) parent.write(my_data, (forkpoint - parent.forkpoint)*HEADER_SIZE)
# store file path # store file path
for b in blockchains.values(): for b in blockchains.values():
b.old_path = b.path() b.old_path = b.path()
@ -261,7 +266,7 @@ class Blockchain(util.PrintError):
with self.lock: with self.lock:
self.assert_headers_file_available(filename) self.assert_headers_file_available(filename)
with open(filename, 'rb+') as f: with open(filename, 'rb+') as f:
if truncate and offset != self._size*80: if truncate and offset != self._size * HEADER_SIZE:
f.seek(offset) f.seek(offset)
f.truncate() f.truncate()
f.seek(offset) f.seek(offset)
@ -276,8 +281,8 @@ class Blockchain(util.PrintError):
data = bfh(serialize_header(header)) data = bfh(serialize_header(header))
# headers are only _appended_ to the end: # headers are only _appended_ to the end:
assert delta == self.size() assert delta == self.size()
assert len(data) == 80 assert len(data) == HEADER_SIZE
self.write(data, delta*80) self.write(data, delta*HEADER_SIZE)
self.swap_with_parent() self.swap_with_parent()
def read_header(self, height: int) -> Optional[dict]: def read_header(self, height: int) -> Optional[dict]:
@ -292,11 +297,11 @@ class Blockchain(util.PrintError):
name = self.path() name = self.path()
self.assert_headers_file_available(name) self.assert_headers_file_available(name)
with open(name, 'rb') as f: with open(name, 'rb') as f:
f.seek(delta * 80) f.seek(delta * HEADER_SIZE)
h = f.read(80) h = f.read(HEADER_SIZE)
if len(h) < 80: if len(h) < HEADER_SIZE:
raise Exception('Expected to read a full header. This was only {} bytes'.format(len(h))) raise Exception('Expected to read a full header. This was only {} bytes'.format(len(h)))
if h == bytes([0])*80: if h == bytes([0])*HEADER_SIZE:
return None return None
return deserialize_header(h, height) return deserialize_header(h, height)

Loading…
Cancel
Save