Add proper block chaining check
This commit is contained in:
parent
78d0acc95b
commit
30d1b7f77c
13
lib/coins.py
13
lib/coins.py
@ -6,7 +6,7 @@ from decimal import Decimal
|
|||||||
import inspect
|
import inspect
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from lib.hash import Base58, hash160
|
from lib.hash import Base58, hash160, double_sha256
|
||||||
from lib.script import ScriptPubKey
|
from lib.script import ScriptPubKey
|
||||||
from lib.tx import Deserializer
|
from lib.tx import Deserializer
|
||||||
|
|
||||||
@ -135,10 +135,17 @@ class Coin(object):
|
|||||||
payload.append(0x01)
|
payload.append(0x01)
|
||||||
return Base58.encode_check(payload)
|
return Base58.encode_check(payload)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def header_hashes(cls, header):
|
||||||
|
'''Given a header return the previous block hash and the current block
|
||||||
|
hash.'''
|
||||||
|
return header[4:36], double_sha256(header)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def read_block(cls, block):
|
def read_block(cls, block):
|
||||||
d = Deserializer(block[cls.HEADER_LEN:])
|
'''Read a block and return (header, tx_hashes, txs)'''
|
||||||
return d.read_block()
|
header, rest = block[:cls.HEADER_LEN], block[cls.HEADER_LEN:]
|
||||||
|
return (header, ) + Deserializer(rest).read_block()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def decimal_value(cls, value):
|
def decimal_value(cls, value):
|
||||||
|
|||||||
@ -260,7 +260,7 @@ class BlockCache(LoggedClass):
|
|||||||
data = json.dumps(payload)
|
data = json.dumps(payload)
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
async with aiohttp.post(self.daemon_url, data = data) as resp:
|
async with aiohttp.post(self.daemon_url, data=data) as resp:
|
||||||
result = await resp.json()
|
result = await resp.json()
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
raise
|
raise
|
||||||
|
|||||||
22
server/db.py
22
server/db.py
@ -310,17 +310,17 @@ class FSCache(LoggedClass):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def process_block(self, block):
|
def process_block(self, block):
|
||||||
'''Process a new block.'''
|
'''Process a new block and return (header, tx_hashes, txs)'''
|
||||||
assert len(self.tx_counts) == self.height + 1 + len(self.headers)
|
assert len(self.tx_counts) == self.height + 1 + len(self.headers)
|
||||||
|
|
||||||
tx_hashes, txs = self.coin.read_block(block)
|
triple = header, tx_hashes, txs = self.coin.read_block(block)
|
||||||
|
|
||||||
# Cache the new header, tx hashes and cumulative tx count
|
# Cache the new header, tx hashes and cumulative tx count
|
||||||
self.headers.append(block[:self.coin.HEADER_LEN])
|
self.headers.append(header)
|
||||||
self.tx_hashes.append(tx_hashes)
|
self.tx_hashes.append(tx_hashes)
|
||||||
self.tx_counts.append(self.tx_count + len(txs))
|
self.tx_counts.append(self.tx_count + len(txs))
|
||||||
|
|
||||||
return tx_hashes, txs
|
return triple
|
||||||
|
|
||||||
def flush(self, new_height, new_tx_count):
|
def flush(self, new_height, new_tx_count):
|
||||||
'''Flush the things stored on the filesystem.'''
|
'''Flush the things stored on the filesystem.'''
|
||||||
@ -431,6 +431,9 @@ class DB(LoggedClass):
|
|||||||
class Error(Exception):
|
class Error(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ChainError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
def __init__(self, env):
|
def __init__(self, env):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@ -447,7 +450,7 @@ class DB(LoggedClass):
|
|||||||
self.flush_count = 0
|
self.flush_count = 0
|
||||||
self.utxo_flush_count = 0
|
self.utxo_flush_count = 0
|
||||||
self.wall_time = 0
|
self.wall_time = 0
|
||||||
self.tip = self.coin.GENESIS_HASH
|
self.tip = b'\0' * 32
|
||||||
|
|
||||||
# Open DB and metadata files. Record some of its state.
|
# Open DB and metadata files. Record some of its state.
|
||||||
self.db = self.open_db(self.coin)
|
self.db = self.open_db(self.coin)
|
||||||
@ -654,8 +657,15 @@ class DB(LoggedClass):
|
|||||||
def process_block(self, block, daemon_height):
|
def process_block(self, block, daemon_height):
|
||||||
# We must update the fs_cache before calling process_tx() as
|
# We must update the fs_cache before calling process_tx() as
|
||||||
# it uses the fs_cache for tx hash lookup
|
# it uses the fs_cache for tx hash lookup
|
||||||
tx_hashes, txs = self.fs_cache.process_block(block)
|
header, tx_hashes, txs = self.fs_cache.process_block(block)
|
||||||
|
prev_hash, header_hash = self.coin.header_hashes(header)
|
||||||
|
if prev_hash != self.tip:
|
||||||
|
raise self.ChainError('trying to build header with prev_hash {} '
|
||||||
|
'on top of tip with hash {}'
|
||||||
|
.format(hash_to_str(prev_hash),
|
||||||
|
hash_to_str(self.tip)))
|
||||||
|
|
||||||
|
self.tip = header_hash
|
||||||
self.height += 1
|
self.height += 1
|
||||||
for tx_hash, tx in zip(tx_hashes, txs):
|
for tx_hash, tx in zip(tx_hashes, txs):
|
||||||
self.process_tx(tx_hash, tx)
|
self.process_tx(tx_hash, tx)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user