from io import BytesIO
import dbm.ndbm
import sys
from .environment import network, Network
if network() == Network.BCH:
from .bch.nodemessages import (
MsgTx,
CBlock,
MsgHeaders,
CBlockHeader,
MsgBlock,
CTransaction,
)
elif network() == Network.NEX:
from .nex.nodemessages import (
MsgTx,
CBlock,
MsgHeaders,
CBlockHeader,
MsgBlock,
CTransaction,
)
else:
raise NotImplementedError()
class BlockStore:
def __init__(self, datadir):
self.block_db = dbm.ndbm.open(datadir + "/blocks", "c")
self.current_block = 0
self.headers_map = {}
def close(self):
self.block_db.close()
def get(self, blockhash):
serialized_block = None
try:
serialized_block = self.block_db[repr(blockhash)]
except KeyError:
return None
f = BytesIO(serialized_block)
ret = CBlock()
ret.deserialize(f)
ret.calc_hash()
return ret
def get_header(self, blockhash):
try:
return self.headers_map[blockhash]
except KeyError:
return None
def headers_for(self, locator, hash_stop, current_tip=None):
if current_tip is None:
current_tip = self.current_block
current_block_header = self.get_header(current_tip)
if current_block_header is None:
return None
response = MsgHeaders()
headers_list = [current_block_header]
maxheaders = 2000
while headers_list[0].gethash() not in locator.vHave:
prev_block_hash = headers_list[0].hashPrevBlock
prev_block_header = self.get_header(prev_block_hash)
if prev_block_header is not None:
headers_list.insert(0, prev_block_header)
else:
break
headers_list = headers_list[:maxheaders] hash_list = [x.gethash() for x in headers_list]
index = len(headers_list)
if hash_stop in hash_list:
index = hash_list.index(hash_stop) + 1
response.headers = headers_list[:index]
return response
def add_block(self, block):
block.calc_hash()
try:
self.block_db[repr(block.gethash())] = bytes(block.serialize())
except TypeError as e:
print("Unexpected error: ", sys.exc_info()[0], e.args)
self.current_block = block.gethash()
self.headers_map[block.gethash()] = CBlockHeader(block)
def add_header(self, header):
self.headers_map[header.gethash()] = header
def get_blocks(self, inv):
responses = []
for i in inv:
if i.type == 2: block = self.get(i.hash)
if block is not None:
responses.append(MsgBlock(block))
return responses
class TxStore:
def __init__(self, datadir):
self.tx_db = dbm.ndbm.open(datadir + "/transactions", "c")
def close(self):
self.tx_db.close()
def get(self, txhash):
serialized_tx = None
try:
serialized_tx = self.tx_db[repr(txhash)]
except KeyError:
return None
f = BytesIO(serialized_tx)
ret = CTransaction()
ret.deserialize(f)
ret.calc_idem()
return ret
def add_transaction(self, tx):
idem = tx.calcIdem()
try:
self.tx_db[repr(idem)] = bytes(tx.serialize())
except TypeError as e:
print("Unexpected error: ", sys.exc_info()[0], e.args)
def get_transactions(self, inv):
responses = []
for i in inv:
if i.type == 1: tx = self.get(i.hash)
if tx is not None:
responses.append(MsgTx(tx))
return responses