blockstate rework, not debugged
This commit is contained in:
@@ -1,62 +1,133 @@
|
||||
from dexorder.blockstate import BlockState, BlockDict
|
||||
from dexorder.database.model.block import Block
|
||||
import logging
|
||||
import sys
|
||||
|
||||
block_10 = Block(chain=1, height=10, hash=bytes.fromhex('10'), parent=bytes.fromhex('09'), data=None)
|
||||
block_11a = Block(chain=1, height=11, hash=bytes.fromhex('1a'), parent=block_10.hash, data=None)
|
||||
block_11b = Block(chain=1, height=11, hash=bytes.fromhex('1b'), parent=block_10.hash, data=None)
|
||||
block_12a = Block(chain=1, height=12, hash=bytes.fromhex('12'), parent=block_11a.hash, data=None)
|
||||
state = BlockState(block_10, {'series':{'foo':'bar'}})
|
||||
BlockState.set_cur(state)
|
||||
d = BlockDict('series')
|
||||
from dexorder import DELETE, NARG
|
||||
from dexorder.base.chain import current_chain, Mock
|
||||
from dexorder.blockstate import BlockState, BlockDict, current_blockstate
|
||||
from dexorder.blockstate.branch import Branch
|
||||
from dexorder.blockstate.fork import current_fork, Fork
|
||||
|
||||
def start_block(b):
|
||||
Block.set_cur(b)
|
||||
state.add_block(b)
|
||||
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
|
||||
logging.getLogger('dexorder').setLevel(logging.DEBUG)
|
||||
|
||||
start_block(block_11a)
|
||||
del d['foo']
|
||||
d['foue'] = 'barre'
|
||||
current_chain.set(Mock)
|
||||
|
||||
start_block(block_12a)
|
||||
d['foo'] = 'bar2'
|
||||
b0 = bytes([0]) # genesis block hash
|
||||
root_branch = Branch(0, 0, bytes(), [b0])
|
||||
|
||||
start_block(block_11b)
|
||||
d['fu'] = 'ku'
|
||||
def new_state():
|
||||
state = BlockState()
|
||||
state.add_branch(root_branch)
|
||||
current_blockstate.set(state)
|
||||
return state
|
||||
|
||||
def print_dict(x:dict=d):
|
||||
for k, v in x.items():
|
||||
print(f'{k:>10} : {v}')
|
||||
s = new_state()
|
||||
|
||||
for block in [block_10,block_11a,block_12a,block_11b]:
|
||||
Block.set_cur(block)
|
||||
print()
|
||||
print(Block.cur().hash)
|
||||
print_dict()
|
||||
series_name = 'test'
|
||||
series = BlockDict(series_name)
|
||||
|
||||
def test11b():
|
||||
Block.set_cur(block_11b)
|
||||
assert 'fu' in d
|
||||
assert d['fu'] == 'ku'
|
||||
assert 'foo' in d
|
||||
assert d['foo'] == 'bar'
|
||||
def get(fork: Fork, default=NARG):
|
||||
value = s.get(fork, series_name, 'foo', default)
|
||||
# print(f'{fork} => {value}')
|
||||
return value
|
||||
|
||||
def test12a():
|
||||
Block.set_cur(block_12a)
|
||||
assert 'fu' not in d
|
||||
assert 'foo' in d
|
||||
assert d['foo'] == 'bar2'
|
||||
assert 'foue' in d
|
||||
assert d['foue'] == 'barre'
|
||||
|
||||
test11b()
|
||||
test12a()
|
||||
state.promote_root(block_11a)
|
||||
print()
|
||||
print('promoted root')
|
||||
print_dict(state.root_state)
|
||||
test12a()
|
||||
state.promote_root(block_12a)
|
||||
print()
|
||||
print('promoted root')
|
||||
print_dict(state.root_state)
|
||||
test12a()
|
||||
block_data = {}
|
||||
|
||||
def make_block(num: int, data: dict=None):
|
||||
key = bytes([num])
|
||||
block_data[key] = data if data is not None else dict(foo=hex(num)[2:])
|
||||
return key
|
||||
|
||||
|
||||
# blocks are by height and then an a-b-c fork
|
||||
# by default, each block sets foo=<blockname>
|
||||
b1a = make_block(0x1a)
|
||||
b2a = make_block(0x2a)
|
||||
b3a = make_block(0x3a)
|
||||
b4a = make_block(0x4a)
|
||||
b5a = make_block(0x5a)
|
||||
|
||||
|
||||
def make_branch(state: BlockState, height: int, start: int, parent: bytes, path: list[bytes]):
|
||||
branch = Branch(height, start, parent, path)
|
||||
fork = state.add_branch(branch)
|
||||
current_fork.set(fork)
|
||||
for block_id in reversed(branch.path):
|
||||
for k,v in block_data[block_id].items():
|
||||
series[k] = v
|
||||
return fork
|
||||
|
||||
fork_a = make_branch(s, 5, 1, b0, [b5a, b4a, b3a, b2a, b1a])
|
||||
fork_a1 = make_branch(s, 1, 1, b0, [b1a])
|
||||
fork_a2 = make_branch(s, 2, 2, b1a, [b2a])
|
||||
fork_a3 = make_branch(s, 3, 3, b2a, [b3a])
|
||||
fork_aa = make_branch(s, 3, 1, b0, [b3a, b2a, b1a])
|
||||
|
||||
fork_ab = make_branch(s, 5, 4, b3a, [b5a, b4a])
|
||||
# this fork has multiple branch combinations. the algo should prefer using fewer branches.
|
||||
assert fork_ab.branches[1] == fork_aa.branch
|
||||
|
||||
assert get(fork_a) == '5a'
|
||||
assert get(fork_aa) == '3a'
|
||||
assert get(fork_ab) == '5a'
|
||||
|
||||
# now change the current value at the end of fork_a
|
||||
current_fork.set(fork_a)
|
||||
diff_count = len(s.diffs_by_branch[fork_a.branch_id])
|
||||
series['foo'] = 'not'
|
||||
assert get(fork_a) == 'not'
|
||||
series['foo'] = 'bar'
|
||||
assert get(fork_a) == 'bar'
|
||||
# make sure it didn't create any extra diffs but performed value replacement in the DiffEntry instead
|
||||
assert diff_count == len(s.diffs_by_branch[fork_a.branch_id])
|
||||
|
||||
# chain B does nothing until deleting foo at height 3, then it sets it back at height 5
|
||||
# block 1 is taken from a-chain
|
||||
b2b = make_block(0x2b, {})
|
||||
b3b = make_block(0x3b, dict(foo=DELETE))
|
||||
b4b = make_block(0x4b, {})
|
||||
b5b = make_block(0x5b)
|
||||
|
||||
fork_from_a = make_branch(s, 2, 2, b1a, [b2b])
|
||||
# this fork should have joined the branch from fork_a1, which connects to genesis for a total of three branches
|
||||
assert len(fork_from_a.branches) == 3
|
||||
assert fork_from_a.branches[1] == fork_a1.branch
|
||||
# the value should have carried over from the other branch
|
||||
assert get(fork_from_a) == '1a'
|
||||
|
||||
fork_delete = make_branch(s, 4, 3, b2b, [b4b, b3b])
|
||||
missing = 'missing'
|
||||
assert get(fork_delete, missing) is missing
|
||||
# make sure it throws KeyError since the key is deleted
|
||||
try:
|
||||
found = series['foo']
|
||||
assert False
|
||||
except KeyError:
|
||||
pass
|
||||
# restore the 'foo' key with a value of '5b'
|
||||
fork_restore = make_branch(s, 5, 5, b4b, [b5b])
|
||||
assert get(fork_restore) == '5b'
|
||||
|
||||
|
||||
s.promote_root(fork_aa)
|
||||
|
||||
# test garbage collection
|
||||
diffs = s.diffs_by_series[series_name].get('foo')
|
||||
assert diffs
|
||||
assert diffs[-1].height == 3 # only the very latest value should be maintained
|
||||
|
||||
try:
|
||||
s.promote_root(fork_from_a)
|
||||
assert False # fork B should not be able to be promoted
|
||||
except AssertionError:
|
||||
pass
|
||||
|
||||
# chain C
|
||||
b1c = make_block(0x1c)
|
||||
b2c = make_block(0x2c)
|
||||
b3c = make_block(0x3c)
|
||||
b4c = make_block(0x4c)
|
||||
b5c = make_block(0x5c)
|
||||
|
||||
logging.getLogger('dexorder').error('Insufficient number of test cases')
|
||||
|
||||
Reference in New Issue
Block a user