Browse Source

Generic header length

If header lengths change in the future, only one function needs
to change in coins.py.
master
Neil Booth 8 years ago
parent
commit
7f9cb9cd9d
  1. 22
      lib/coins.py
  2. 10
      server/block_processor.py
  3. 24
      server/db.py

22
lib/coins.py

@ -34,7 +34,6 @@ class Coin(object):
REORG_LIMIT=200 REORG_LIMIT=200
# Not sure if these are coin-specific # Not sure if these are coin-specific
HEADER_LEN = 80
RPC_URL_REGEX = re.compile('.+@[^:]+(:[0-9]+)?') RPC_URL_REGEX = re.compile('.+@[^:]+(:[0-9]+)?')
VALUE_PER_COIN = 100000000 VALUE_PER_COIN = 100000000
CHUNK_SIZE=2016 CHUNK_SIZE=2016
@ -191,9 +190,24 @@ class Coin(object):
return header[4:36] return header[4:36]
@classmethod @classmethod
def read_block(cls, block): def header_offset(cls, height):
'''Return a tuple (header, tx_hashes, txs) given a raw block.''' '''Given a header height return its offset in the headers file.
header, rest = block[:cls.HEADER_LEN], block[cls.HEADER_LEN:]
If header sizes change at some point, this is the only code
that needs updating.'''
return height * 80
@classmethod
def header_len(cls, height):
'''Given a header height return its length.'''
return cls.header_offset(height + 1) - cls.header_offset(height)
@classmethod
def read_block(cls, block, height):
'''Return a tuple (header, tx_hashes, txs) given a raw block at
the given height.'''
hlen = cls.header_len(height)
header, rest = block[:hlen], block[hlen:]
return (header, ) + Deserializer(rest).read_block() return (header, ) + Deserializer(rest).read_block()
@classmethod @classmethod

10
server/block_processor.py

@ -128,7 +128,7 @@ class Prefetcher(LoggedClass):
# Strip the unspendable genesis coinbase # Strip the unspendable genesis coinbase
if first == 0: if first == 0:
blocks[0] = blocks[0][:self.coin.HEADER_LEN] + bytes(1) blocks[0] = blocks[0][:self.coin.header_len(0)] + bytes(1)
# Update our recent average block size estimate # Update our recent average block size estimate
size = sum(len(block) for block in blocks) size = sum(len(block) for block in blocks)
@ -503,7 +503,7 @@ class BlockProcessor(server.db.DB):
self.tx_counts.append(prior_tx_count + len(txs)) self.tx_counts.append(prior_tx_count + len(txs))
def advance_block(self, block, touched): def advance_block(self, block, touched):
header, tx_hashes, txs = self.coin.read_block(block) header, tx_hashes, txs = self.coin.read_block(block, self.height + 1)
if self.tip != self.coin.header_prevhash(header): if self.tip != self.coin.header_prevhash(header):
raise ChainReorg raise ChainReorg
@ -562,13 +562,13 @@ class BlockProcessor(server.db.DB):
def backup_blocks(self, blocks, touched): def backup_blocks(self, blocks, touched):
'''Backup the blocks and flush. '''Backup the blocks and flush.
The blocks should be in order of decreasing height. The blocks should be in order of decreasing height, starting at.
A flush is performed once the blocks are backed up. self.height. A flush is performed once the blocks are backed up.
''' '''
self.assert_flushed() self.assert_flushed()
for block in blocks: for block in blocks:
header, tx_hashes, txs = self.coin.read_block(block) header, tx_hashes, txs = self.coin.read_block(block, self.height)
header_hash = self.coin.header_hash(header) header_hash = self.coin.header_hash(header)
if header_hash != self.tip: if header_hash != self.tip:
raise ChainError('backup block {} is not tip {} at height {:,d}' raise ChainError('backup block {} is not tip {} at height {:,d}'

24
server/db.py

@ -258,7 +258,7 @@ class DB(util.LoggedClass):
assert len(hashes) // 32 == txs_done assert len(hashes) // 32 == txs_done
# Write the headers, tx counts, and tx hashes # Write the headers, tx counts, and tx hashes
offset = (fs_height + 1) * self.coin.HEADER_LEN offset = self.coin.header_offset(fs_height + 1)
self.headers_file.write(offset, b''.join(headers)) self.headers_file.write(offset, b''.join(headers))
offset = (fs_height + 1) * self.tx_counts.itemsize offset = (fs_height + 1) * self.tx_counts.itemsize
self.tx_counts_file.write(offset, self.tx_counts_file.write(offset,
@ -274,9 +274,9 @@ class DB(util.LoggedClass):
raise self.DBError('{:,d} headers starting at {:,d} not on disk' raise self.DBError('{:,d} headers starting at {:,d} not on disk'
.format(count, start)) .format(count, start))
if disk_count: if disk_count:
header_len = self.coin.HEADER_LEN offset = self.coin.header_offset(start)
offset = start * header_len size = self.coin.header_offset(start + disk_count) - offset
return self.headers_file.read(offset, disk_count * header_len) return self.headers_file.read(offset, size)
return b'' return b''
def fs_tx_hash(self, tx_num): def fs_tx_hash(self, tx_num):
@ -288,14 +288,18 @@ class DB(util.LoggedClass):
tx_hash = None tx_hash = None
else: else:
tx_hash = self.hashes_file.read(tx_num * 32, 32) tx_hash = self.hashes_file.read(tx_num * 32, 32)
return tx_hash, height return tx_hash, tx_height
def fs_block_hashes(self, height, count): def fs_block_hashes(self, height, count):
headers = self.read_headers(height, count) headers_concat = self.read_headers(height, count)
# FIXME: move to coins.py offset = 0
hlen = self.coin.HEADER_LEN headers = []
return [self.coin.header_hash(header) for n in range(count):
for header in util.chunks(headers, hlen)] hlen = self.coin.header_len(height + n)
headers.append(headers_concat[offset:offset + hlen])
offset += hlen
return [self.coin.header_hash(header) for header in headers]
@staticmethod @staticmethod
def _resolve_limit(limit): def _resolve_limit(limit):

Loading…
Cancel
Save