cryptarchia: fix try_create_fork to find parent block (#84)
This commit is contained in:
parent
a0175e16f3
commit
601598f814
|
@ -244,14 +244,11 @@ class Chain:
|
||||||
def length(self) -> int:
|
def length(self) -> int:
|
||||||
return len(self.blocks)
|
return len(self.blocks)
|
||||||
|
|
||||||
def contains_block(self, block: BlockHeader) -> bool:
|
def block_position(self, block: Id) -> Optional[int]:
|
||||||
return block in self.blocks
|
|
||||||
|
|
||||||
def block_position(self, block: BlockHeader) -> int:
|
|
||||||
assert self.contains_block(block)
|
|
||||||
for i, b in enumerate(self.blocks):
|
for i, b in enumerate(self.blocks):
|
||||||
if b == block:
|
if b.id() == block:
|
||||||
return i
|
return i
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -420,10 +417,10 @@ class Follower:
|
||||||
|
|
||||||
chains = self.forks + [self.local_chain]
|
chains = self.forks + [self.local_chain]
|
||||||
for chain in chains:
|
for chain in chains:
|
||||||
if chain.contains_block(block):
|
block_position = chain.block_position(block.parent)
|
||||||
block_position = chain.block_position(block)
|
if block_position is not None:
|
||||||
return Chain(
|
return Chain(
|
||||||
blocks=chain.blocks[:block_position],
|
blocks=chain.blocks[: block_position + 1],
|
||||||
genesis=self.genesis_state.block,
|
genesis=self.genesis_state.block,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,52 @@ class TestLedgerStateUpdate(TestCase):
|
||||||
# and the original coin_1 should now be removed from the spent pool
|
# and the original coin_1 should now be removed from the spent pool
|
||||||
assert follower.tip_state().verify_unspent(coin_1.nullifier())
|
assert follower.tip_state().verify_unspent(coin_1.nullifier())
|
||||||
|
|
||||||
|
def test_fork_creation(self):
|
||||||
|
coins = [Coin(sk=i, value=100) for i in range(7)]
|
||||||
|
genesis = mk_genesis_state(coins)
|
||||||
|
|
||||||
|
follower = Follower(genesis, mk_config())
|
||||||
|
|
||||||
|
# coin_0 & coin_1 both concurrently win slot 0 based on the genesis block
|
||||||
|
# Both blocks are accepted, and a fork is created "from the genesis block"
|
||||||
|
block_1 = mk_block(parent=genesis.block, slot=0, coin=coins[0])
|
||||||
|
block_2 = mk_block(parent=genesis.block, slot=0, coin=coins[1])
|
||||||
|
follower.on_block(block_1)
|
||||||
|
follower.on_block(block_2)
|
||||||
|
assert follower.tip() == block_1
|
||||||
|
assert len(follower.forks) == 1, f"{len(follower.forks)}"
|
||||||
|
assert follower.forks[0].tip() == block_2
|
||||||
|
|
||||||
|
# coin_2 wins slot 1 and chooses to extend from block_1
|
||||||
|
# coin_3 also wins slot 1 and but chooses to extend from block_2
|
||||||
|
# Both blocks are accepted. Both the local chain and the fork grow. No fork is newly created.
|
||||||
|
block_3 = mk_block(parent=block_1.id(), slot=1, coin=coins[2])
|
||||||
|
block_4 = mk_block(parent=block_2.id(), slot=1, coin=coins[3])
|
||||||
|
follower.on_block(block_3)
|
||||||
|
follower.on_block(block_4)
|
||||||
|
assert follower.tip() == block_3
|
||||||
|
assert len(follower.forks) == 1, f"{len(follower.forks)}"
|
||||||
|
assert follower.forks[0].tip() == block_4
|
||||||
|
|
||||||
|
# coin_4 wins slot 1 and but chooses to extend from block_2 as well
|
||||||
|
# The block is accepted. A new fork is created "from the block_2".
|
||||||
|
block_5 = mk_block(parent=block_2.id(), slot=1, coin=coins[4])
|
||||||
|
follower.on_block(block_5)
|
||||||
|
assert follower.tip() == block_3
|
||||||
|
assert len(follower.forks) == 2, f"{len(follower.forks)}"
|
||||||
|
assert follower.forks[0].tip() == block_4
|
||||||
|
assert follower.forks[1].tip() == block_5
|
||||||
|
|
||||||
|
# A block based on an unknown parent is not accepted.
|
||||||
|
# Nothing changes from the local chain and forks.
|
||||||
|
unknown_block = mk_block(parent=block_5.id(), slot=2, coin=coins[5])
|
||||||
|
block_6 = mk_block(parent=unknown_block.id(), slot=2, coin=coins[6])
|
||||||
|
follower.on_block(block_6)
|
||||||
|
assert follower.tip() == block_3
|
||||||
|
assert len(follower.forks) == 2, f"{len(follower.forks)}"
|
||||||
|
assert follower.forks[0].tip() == block_4
|
||||||
|
assert follower.forks[1].tip() == block_5
|
||||||
|
|
||||||
def test_epoch_transition(self):
|
def test_epoch_transition(self):
|
||||||
leader_coins = [Coin(sk=i, value=100) for i in range(4)]
|
leader_coins = [Coin(sk=i, value=100) for i in range(4)]
|
||||||
genesis = mk_genesis_state(leader_coins)
|
genesis = mk_genesis_state(leader_coins)
|
||||||
|
|
Loading…
Reference in New Issue