From 4d62019b077e876a773106dbe01f1dc5f3f59ffa Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Sat, 7 Jan 2017 16:37:44 +0900 Subject: [PATCH] Check Genesis hash Testnet RPC_PORT is 18332 --- lib/coins.py | 41 ++++++++++++++++++++++++++------------- server/block_processor.py | 6 ++++-- server/db.py | 6 +++++- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/lib/coins.py b/lib/coins.py index f9922d1..9f7da80 100644 --- a/lib/coins.py +++ b/lib/coins.py @@ -22,7 +22,7 @@ import sys from lib.hash import Base58, hash160, ripemd160, double_sha256, hash_to_str from lib.script import ScriptPubKey from lib.tx import Deserializer, DeserializerSegWit -from lib.util import cachedproperty, subclasses +import lib.util as util class CoinError(Exception): @@ -46,7 +46,7 @@ class Coin(object): '''Return a coin class given name and network. Raise an exception if unrecognised.''' - for coin in subclasses(Coin): + for coin in util.subclasses(Coin): if (coin.NAME.lower() == name.lower() and coin.NET.lower() == net.lower()): return coin @@ -70,6 +70,20 @@ class Coin(object): def daemon_urls(cls, urls): return [cls.sanitize_url(url) for url in urls.split(',')] + @classmethod + def genesis_block(cls, block): + '''Check the Genesis block is the right one for this coin. + + Return the block less its unspendable coinbase. + ''' + header = block[:cls.header_len(0)] + header_hex_hash = hash_to_str(cls.header_hash(header)) + if header_hex_hash != cls.GENESIS_HASH: + raise CoinError('genesis block has hash {} expected {}' + .format(header_hex_hash, cls.GENESIS_HASH)) + + return header + bytes(1) + @classmethod def hashX_from_script(cls, script): '''Returns a hashX from a script.''' @@ -78,7 +92,7 @@ class Coin(object): return None return sha256(script).digest()[:cls.HASHX_LEN] - @cachedproperty + @util.cachedproperty def address_handlers(cls): return ScriptPubKey.PayToHandlers( address = cls.P2PKH_address_from_hash160, @@ -251,8 +265,8 @@ class Bitcoin(Coin): P2PKH_VERBYTE = 0x00 P2SH_VERBYTE = 0x05 WIF_BYTE = 0x80 - GENESIS_HASH=(b'000000000019d6689c085ae165831e93' - b'4ff763ae46a2a6c172b3f1b60a8ce26f') + GENESIS_HASH=('000000000019d6689c085ae165831e93' + '4ff763ae46a2a6c172b3f1b60a8ce26f') TX_COUNT = 156335304 TX_COUNT_HEIGHT = 429972 TX_PER_BLOCK = 1800 @@ -269,13 +283,14 @@ class BitcoinTestnet(Bitcoin): P2PKH_VERBYTE = 0x6f P2SH_VERBYTE = 0xc4 WIF_BYTE = 0xef - GENESIS_HASH=(b'000000000933ea01ad0ee984209779ba' - b'aec3ced90fa3f408719526f8d77f4943') + GENESIS_HASH=('000000000933ea01ad0ee984209779ba' + 'aec3ced90fa3f408719526f8d77f4943') REORG_LIMIT = 2000 TX_COUNT = 12242438 TX_COUNT_HEIGHT = 1035428 TX_PER_BLOCK = 21 IRC_PREFIX = "ET_" + RPC_PORT = 18332 class BitcoinTestnetSegWit(BitcoinTestnet): @@ -300,8 +315,8 @@ class Litecoin(Coin): P2PKH_VERBYTE = 0x30 P2SH_VERBYTE = 0x05 WIF_BYTE = 0xb0 - GENESIS_HASH=(b'000000000019d6689c085ae165831e93' - b'4ff763ae46a2a6c172b3f1b60a8ce26f') + GENESIS_HASH=('000000000019d6689c085ae165831e93' + '4ff763ae46a2a6c172b3f1b60a8ce26f') TX_COUNT = 8908766 TX_COUNT_HEIGHT = 1105256 TX_PER_BLOCK = 10 @@ -375,8 +390,8 @@ class Dash(Coin): NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("02fe52cc") XPRV_VERBYTES = bytes.fromhex("02fe52f8") - GENESIS_HASH = (b'00000ffd590b1485b3caadc19b22e637' - b'9c733355108f107a430458cdf3407ab6') + GENESIS_HASH = ('00000ffd590b1485b3caadc19b22e637' + '9c733355108f107a430458cdf3407ab6') P2PKH_VERBYTE = 0x4c P2SH_VERBYTE = 0x10 WIF_BYTE = 0xcc @@ -398,8 +413,8 @@ class DashTestnet(Dash): NET = "testnet" XPUB_VERBYTES = bytes.fromhex("3a805837") XPRV_VERBYTES = bytes.fromhex("3a8061a0") - GENESIS_HASH = (b'00000bafbc94add76cb75e2ec9289483' - b'7288a481e5c005f6563d91623bf8bc2c') + GENESIS_HASH = ('00000bafbc94add76cb75e2ec9289483' + '7288a481e5c005f6563d91623bf8bc2c') P2PKH_VERBYTE = 0x8c P2SH_VERBYTE = 0x13 WIF_BYTE = 0xef diff --git a/server/block_processor.py b/server/block_processor.py index 2acad10..8535b85 100644 --- a/server/block_processor.py +++ b/server/block_processor.py @@ -125,9 +125,11 @@ class Prefetcher(LoggedClass): assert count == len(blocks) - # Strip the unspendable genesis coinbase + # Special handling for genesis block if first == 0: - blocks[0] = blocks[0][:self.coin.header_len(0)] + bytes(1) + blocks[0] = self.coin.genesis_block(blocks[0]) + self.logger.info('verified genesis block with hash {}' + .format(hex_hashes[0])) # Update our recent average block size estimate size = sum(len(block) for block in blocks) diff --git a/server/db.py b/server/db.py index 9b1b2d2..c124594 100644 --- a/server/db.py +++ b/server/db.py @@ -142,7 +142,11 @@ class DB(util.LoggedClass): raise self.DBError('your DB version is {} but this software ' 'only handles versions {}' .format(self.db_version, self.DB_VERSIONS)) - if state['genesis'] != self.coin.GENESIS_HASH: + # backwards compat + genesis_hash = state['genesis'] + if isinstance(genesis_hash, bytes): + genesis_hash = genesis_hash.decode() + if genesis_hash != self.coin.GENESIS_HASH: raise self.DBError('DB genesis hash {} does not match coin {}' .format(state['genesis_hash'], self.coin.GENESIS_HASH))