From 7f9cb9cd9d92e91f1c3d734501f29374ecf47843 Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Tue, 3 Jan 2017 08:52:41 +0900 Subject: [PATCH] Generic header length If header lengths change in the future, only one function needs to change in coins.py. --- lib/coins.py | 22 ++++++++++++++++++---- server/block_processor.py | 10 +++++----- server/db.py | 24 ++++++++++++++---------- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/lib/coins.py b/lib/coins.py index 81ba382..989bec1 100644 --- a/lib/coins.py +++ b/lib/coins.py @@ -34,7 +34,6 @@ class Coin(object): REORG_LIMIT=200 # Not sure if these are coin-specific - HEADER_LEN = 80 RPC_URL_REGEX = re.compile('.+@[^:]+(:[0-9]+)?') VALUE_PER_COIN = 100000000 CHUNK_SIZE=2016 @@ -191,9 +190,24 @@ class Coin(object): return header[4:36] @classmethod - def read_block(cls, block): - '''Return a tuple (header, tx_hashes, txs) given a raw block.''' - header, rest = block[:cls.HEADER_LEN], block[cls.HEADER_LEN:] + def header_offset(cls, height): + '''Given a header height return its offset in the headers file. + + 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() @classmethod diff --git a/server/block_processor.py b/server/block_processor.py index 40b2324..b301c4f 100644 --- a/server/block_processor.py +++ b/server/block_processor.py @@ -128,7 +128,7 @@ class Prefetcher(LoggedClass): # Strip the unspendable genesis coinbase 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 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)) 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): raise ChainReorg @@ -562,13 +562,13 @@ class BlockProcessor(server.db.DB): def backup_blocks(self, blocks, touched): '''Backup the blocks and flush. - The blocks should be in order of decreasing height. - A flush is performed once the blocks are backed up. + The blocks should be in order of decreasing height, starting at. + self.height. A flush is performed once the blocks are backed up. ''' self.assert_flushed() 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) if header_hash != self.tip: raise ChainError('backup block {} is not tip {} at height {:,d}' diff --git a/server/db.py b/server/db.py index 440aa98..219a233 100644 --- a/server/db.py +++ b/server/db.py @@ -258,7 +258,7 @@ class DB(util.LoggedClass): assert len(hashes) // 32 == txs_done # 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)) offset = (fs_height + 1) * self.tx_counts.itemsize 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' .format(count, start)) if disk_count: - header_len = self.coin.HEADER_LEN - offset = start * header_len - return self.headers_file.read(offset, disk_count * header_len) + offset = self.coin.header_offset(start) + size = self.coin.header_offset(start + disk_count) - offset + return self.headers_file.read(offset, size) return b'' def fs_tx_hash(self, tx_num): @@ -288,14 +288,18 @@ class DB(util.LoggedClass): tx_hash = None else: 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): - headers = self.read_headers(height, count) - # FIXME: move to coins.py - hlen = self.coin.HEADER_LEN - return [self.coin.header_hash(header) - for header in util.chunks(headers, hlen)] + headers_concat = self.read_headers(height, count) + offset = 0 + headers = [] + for n in range(count): + 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 def _resolve_limit(limit):