Changeset View
Changeset View
Standalone View
Standalone View
qa/rpc-tests/test_framework/blockstore.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2015-2016 The Bitcoin Core developers | # Copyright (c) 2015-2016 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
# BlockStore: a helper class that keeps a map of blocks and implements | # BlockStore: a helper class that keeps a map of blocks and implements | ||||
# helper functions for responding to getheaders and getdata, | # helper functions for responding to getheaders and getdata, | ||||
# and for constructing a getheaders message | # and for constructing a getheaders message | ||||
# | # | ||||
from .mininode import * | from .mininode import * | ||||
from io import BytesIO | from io import BytesIO | ||||
import dbm.dumb as dbmd | import dbm.dumb as dbmd | ||||
logger = logging.getLogger("TestFramework.blockstore") | |||||
class BlockStore(object): | class BlockStore(object): | ||||
def __init__(self, datadir): | def __init__(self, datadir): | ||||
self.blockDB = dbmd.open(datadir + "/blocks", 'c') | self.blockDB = dbmd.open(datadir + "/blocks", 'c') | ||||
self.currentBlock = 0 | self.currentBlock = 0 | ||||
self.headers_map = dict() | self.headers_map = dict() | ||||
def close(self): | def close(self): | ||||
self.blockDB.close() | self.blockDB.close() | ||||
Show All 32 Lines | class BlockStore(object): | ||||
def headers_for(self, locator, hash_stop, current_tip=None): | def headers_for(self, locator, hash_stop, current_tip=None): | ||||
if current_tip is None: | if current_tip is None: | ||||
current_tip = self.currentBlock | current_tip = self.currentBlock | ||||
current_block_header = self.get_header(current_tip) | current_block_header = self.get_header(current_tip) | ||||
if current_block_header is None: | if current_block_header is None: | ||||
return None | return None | ||||
response = msg_headers() | response = msg_headers() | ||||
headersList = [ current_block_header ] | headersList = [current_block_header] | ||||
maxheaders = 2000 | maxheaders = 2000 | ||||
while (headersList[0].sha256 not in locator.vHave): | while (headersList[0].sha256 not in locator.vHave): | ||||
prevBlockHash = headersList[0].hashPrevBlock | prevBlockHash = headersList[0].hashPrevBlock | ||||
prevBlockHeader = self.get_header(prevBlockHash) | prevBlockHeader = self.get_header(prevBlockHash) | ||||
if prevBlockHeader is not None: | if prevBlockHeader is not None: | ||||
headersList.insert(0, prevBlockHeader) | headersList.insert(0, prevBlockHeader) | ||||
else: | else: | ||||
break | break | ||||
headersList = headersList[:maxheaders] # truncate if we have too many | headersList = headersList[:maxheaders] # truncate if we have too many | ||||
hashList = [x.sha256 for x in headersList] | hashList = [x.sha256 for x in headersList] | ||||
index = len(headersList) | index = len(headersList) | ||||
if (hash_stop in hashList): | if (hash_stop in hashList): | ||||
index = hashList.index(hash_stop)+1 | index = hashList.index(hash_stop) + 1 | ||||
response.headers = headersList[:index] | response.headers = headersList[:index] | ||||
return response | return response | ||||
def add_block(self, block): | def add_block(self, block): | ||||
block.calc_sha256() | block.calc_sha256() | ||||
try: | try: | ||||
self.blockDB[repr(block.sha256)] = bytes(block.serialize()) | self.blockDB[repr(block.sha256)] = bytes(block.serialize()) | ||||
except TypeError as e: | except TypeError as e: | ||||
print("Unexpected error: ", sys.exc_info()[0], e.args) | logger.exception("Unexpected error") | ||||
self.currentBlock = block.sha256 | self.currentBlock = block.sha256 | ||||
self.headers_map[block.sha256] = CBlockHeader(block) | self.headers_map[block.sha256] = CBlockHeader(block) | ||||
def add_header(self, header): | def add_header(self, header): | ||||
self.headers_map[header.sha256] = header | self.headers_map[header.sha256] = header | ||||
# lookup the hashes in "inv", and return p2p messages for delivering | # lookup the hashes in "inv", and return p2p messages for delivering | ||||
# blocks found. | # blocks found. | ||||
def get_blocks(self, inv): | def get_blocks(self, inv): | ||||
responses = [] | responses = [] | ||||
for i in inv: | for i in inv: | ||||
if (i.type == 2): # MSG_BLOCK | if (i.type == 2): # MSG_BLOCK | ||||
data = self.get(i.hash) | data = self.get(i.hash) | ||||
if data is not None: | if data is not None: | ||||
# Use msg_generic to avoid re-serialization | # Use msg_generic to avoid re-serialization | ||||
responses.append(msg_generic(b"block", data)) | responses.append(msg_generic(b"block", data)) | ||||
return responses | return responses | ||||
def get_locator(self, current_tip=None): | def get_locator(self, current_tip=None): | ||||
if current_tip is None: | if current_tip is None: | ||||
Show All 10 Lines | def get_locator(self, current_tip=None): | ||||
break | break | ||||
counter += 1 | counter += 1 | ||||
if counter > 10: | if counter > 10: | ||||
step *= 2 | step *= 2 | ||||
locator = CBlockLocator() | locator = CBlockLocator() | ||||
locator.vHave = r | locator.vHave = r | ||||
return locator | return locator | ||||
class TxStore(object): | class TxStore(object): | ||||
def __init__(self, datadir): | def __init__(self, datadir): | ||||
self.txDB = dbmd.open(datadir + "/transactions", 'c') | self.txDB = dbmd.open(datadir + "/transactions", 'c') | ||||
def close(self): | def close(self): | ||||
self.txDB.close() | self.txDB.close() | ||||
# lookup an entry and return the item as raw bytes | # lookup an entry and return the item as raw bytes | ||||
def get(self, txhash): | def get(self, txhash): | ||||
Show All 14 Lines | def get_transaction(self, txhash): | ||||
ret.calc_sha256() | ret.calc_sha256() | ||||
return ret | return ret | ||||
def add_transaction(self, tx): | def add_transaction(self, tx): | ||||
tx.calc_sha256() | tx.calc_sha256() | ||||
try: | try: | ||||
self.txDB[repr(tx.sha256)] = bytes(tx.serialize()) | self.txDB[repr(tx.sha256)] = bytes(tx.serialize()) | ||||
except TypeError as e: | except TypeError as e: | ||||
print("Unexpected error: ", sys.exc_info()[0], e.args) | logger.exception("Unexpected error") | ||||
def get_transactions(self, inv): | def get_transactions(self, inv): | ||||
responses = [] | responses = [] | ||||
for i in inv: | for i in inv: | ||||
if (i.type == 1): # MSG_TX | if (i.type == 1): # MSG_TX | ||||
tx = self.get(i.hash) | tx = self.get(i.hash) | ||||
if tx is not None: | if tx is not None: | ||||
responses.append(msg_generic(b"tx", tx)) | responses.append(msg_generic(b"tx", tx)) | ||||
return responses | return responses |