chainsyncer/chainsyncer/unittest/base.py

280 lines
6.8 KiB
Python
Raw Normal View History

2021-04-15 11:15:48 +02:00
# standard imports
import os
2021-04-15 14:11:06 +02:00
import logging
2022-03-17 23:07:19 +01:00
import hashlib
2021-04-15 11:15:48 +02:00
# external imports
from hexathon import add_0x
2022-03-17 23:07:19 +01:00
from shep.state import State
2021-04-15 11:15:48 +02:00
# local imports
2022-03-17 23:07:19 +01:00
#from chainsyncer.driver.history import HistorySyncer
2021-04-15 11:15:48 +02:00
from chainsyncer.error import NoBlockForYou
2022-03-18 02:11:30 +01:00
from chainsyncer.driver import SyncDriver
2021-04-15 11:15:48 +02:00
logging.STATETRACE = 5
logging.addLevelName('STATETRACE', logging.STATETRACE)
logg = logging.getLogger(__name__)
2021-04-15 14:11:06 +02:00
2021-04-15 11:15:48 +02:00
def state_event_handler(k, v_old, v_new):
2022-03-29 10:12:43 +02:00
if v_old == None:
logg.log(logging.STATETRACE, 'sync state create key {}: -> {}'.format(k, v_new))
else:
logg.log(logging.STATETRACE, 'sync state change key {}: {} -> {}'.format(k, v_old, v_new))
def filter_state_event_handler(k, v_old, v_new):
2022-03-29 10:12:43 +02:00
if v_old == None:
logg.log(logging.STATETRACE, 'filter state create key {}: -> {}'.format(k, v_new))
else:
logg.log(logging.STATETRACE, 'filter state change key {}: {} -> {}'.format(k, v_old, v_new))
2022-03-21 22:03:24 +01:00
class MockFilterError(Exception):
pass
2022-03-29 09:28:28 +02:00
class MockBlockGenerator:
def __init__(self, offset=0):
self.blocks = {}
self.offset = offset
self.cursor = offset
def generate(self, spec=[], driver=None):
for v in spec:
txs = []
for i in range(v):
tx_hash = os.urandom(32).hex()
tx = MockTx(0, tx_hash)
txs.append(tx)
block = MockBlock(self.cursor, txs)
2022-03-29 10:12:43 +02:00
self.blocks[self.cursor] = block
2022-03-29 09:28:28 +02:00
self.cursor += 1
2022-03-29 10:12:43 +02:00
if driver != None:
self.apply(driver)
def apply(self, driver, offset=0):
block_numbers = list(self.blocks.keys())
for block_number in block_numbers:
if block_number < offset:
continue
block = self.blocks[block_number]
driver.add_block(block)
2022-03-29 09:28:28 +02:00
class MockConn:
2021-08-27 14:16:46 +02:00
"""Noop connection mocker.
2021-08-27 14:16:46 +02:00
:param o: Object to execute rpc call for
:type o: dict
"""
def do(self, o):
pass
2021-04-15 11:15:48 +02:00
class MockTx:
2021-08-27 14:16:46 +02:00
"""Minimal mocked tx object.
2021-04-15 11:15:48 +02:00
2021-08-27 14:16:46 +02:00
:param index: Transaction index in block
:type index: int
:param tx_hash: Transaction hash
:type tx_hash: str
"""
2021-04-15 14:11:06 +02:00
def __init__(self, index, tx_hash):
2021-04-15 11:15:48 +02:00
self.hash = tx_hash
self.index = index
def apply_receipt(self, rcpt):
2021-08-27 14:16:46 +02:00
"""Save receipt source in mock tx object.
:param rcpt: Transaction receipt
:type rcpt: dict
"""
self.rcpt = rcpt
2021-04-15 11:15:48 +02:00
class MockBlock:
def __init__(self, number, txs):
2021-08-27 14:16:46 +02:00
"""Minimal mocked block object.
:param number: Block number
:type number: int
:param txs: Transaction list to include in block
:type txs: list
"""
2021-04-15 11:15:48 +02:00
self.number = number
self.txs = txs
2022-03-29 09:28:28 +02:00
self.hash = os.urandom(32).hex()
2021-04-15 11:15:48 +02:00
def tx(self, i):
2021-08-27 14:16:46 +02:00
"""Get block transaction at given index.
:param i: Transaction index
:type i: int
"""
2022-03-30 08:55:21 +02:00
return MockTx(i, self.txs[i].hash)
2021-04-15 11:15:48 +02:00
2022-03-17 23:07:19 +01:00
class MockStore(State):
2021-04-15 11:15:48 +02:00
2022-03-17 23:07:19 +01:00
def __init__(self, bits=0):
super(MockStore, self).__init__(bits, check_alias=False)
2021-04-15 11:15:48 +02:00
2022-03-17 23:07:19 +01:00
2022-03-18 00:48:23 +01:00
def start(self, offset=0, target=-1):
2022-03-17 23:07:19 +01:00
pass
2021-04-15 11:15:48 +02:00
2021-08-27 14:16:46 +02:00
2022-03-17 23:07:19 +01:00
class MockFilter:
2022-03-21 22:03:24 +01:00
def __init__(self, name, brk=None, brk_hard=None, z=None):
2022-03-17 23:07:19 +01:00
self.name = name
if z == None:
h = hashlib.sha256()
h.update(self.name.encode('utf-8'))
z = h.digest()
self.z = z
self.brk = brk
2022-03-21 22:03:24 +01:00
self.brk_hard = brk_hard
2022-03-18 00:48:23 +01:00
self.contents = []
2022-03-17 23:07:19 +01:00
def sum(self):
return self.z
def common_name(self):
return self.name
def filter(self, conn, block, tx):
2022-03-21 22:03:24 +01:00
r = False
if self.brk_hard != None:
r = True
if self.brk_hard > 0:
r = True
self.brk_hard -= 1
if r:
raise MockFilterError()
if self.brk != None:
if self.brk > 0:
r = True
self.brk -= 1
self.contents.append((block.number, tx.index, tx.hash,))
2022-03-30 08:55:21 +02:00
logg.debug('filter {} result {} block {} tx {} {}'.format(self.common_name(), r, block.number, tx.index, tx.hash))
2022-03-21 22:03:24 +01:00
return r
2022-03-17 23:07:19 +01:00
2022-03-18 02:11:30 +01:00
class MockDriver(SyncDriver):
2022-03-29 10:12:43 +02:00
def __init__(self, store, offset=0, target=-1, interrupt_block=None, interrupt_tx=None, interrupt_global=False):
2022-03-18 02:11:30 +01:00
super(MockDriver, self).__init__(store, offset=offset, target=target)
self.blocks = {}
2022-03-29 10:12:43 +02:00
self.interrupt = None
if interrupt_block != None:
interrupt_block = int(interrupt_block)
if interrupt_tx == None:
interrupt_tx = 0
else:
interrupt_tx = int(interrupt_tx)
self.interrupt = (interrupt_block, interrupt_tx,)
self.interrupt_global = interrupt_global
2022-03-18 02:11:30 +01:00
def add_block(self, block):
2022-03-29 09:28:28 +02:00
logg.debug('add block {} {} with {} txs'.format(block.number, block.hash, len(block.txs)))
2022-03-18 02:11:30 +01:00
self.blocks[block.number] = block
def get(self, conn, item):
try:
return self.blocks[item.cursor]
except KeyError:
raise NoBlockForYou()
2022-03-18 02:11:30 +01:00
2022-03-30 08:55:21 +02:00
def process(self, conn, item, block):
i = item.tx_cursor
2022-03-29 10:12:43 +02:00
while self.running:
if self.interrupt != None:
if self.interrupt[0] == block.number and self.interrupt[1] == i:
logg.info('interrupt triggered at {}'.format(self.interrupt))
if self.interrupt_global:
SyncDriver.running_global = False
self.running = False
break
2022-03-18 02:11:30 +01:00
tx = block.tx(i)
self.process_single(conn, block, tx)
item.next()
i += 1
2022-03-30 08:55:21 +02:00
class MockChainInterface:
def block_by_number(self, number):
return ('block_by_number', number,)
def tx_by_hash(self, hsh):
return ('tx_by_hash', hsh,)
def block_from_src(self, src):
return src
def src_normalize(self, src):
return src
def tx_receipt(self, hsh):
return ('receipt', hsh,)
class MockChainInterfaceConn(MockConn):
def __init__(self, interface):
self.ifc = interface
self.blocks = {}
self.txs = {}
def add_block(self, block):
logg.debug('add block {} {} with {} txs'.format(block.number, block.hash, len(block.txs)))
self.blocks[block.number] = block
for tx in block.txs:
self.txs[tx.hash] = tx
def do(self, o):
m = getattr(self, 'handle_' + o[0])
return m(o[1])
def handle_block_by_number(self, number):
return self.blocks[number]
def handle_receipt(self, hsh):
return {}
2022-04-20 18:36:06 +02:00
class MockItem:
def __init__(self, target, offset, cursor, state_key):
self.target = target
self.offset = offset
self.cursor = cursor
self.state_key = state_key