103 lines
3.3 KiB
Python
103 lines
3.3 KiB
Python
from unittest import TestCase
|
|
from itertools import repeat
|
|
import numpy as np
|
|
import hashlib
|
|
|
|
from copy import deepcopy
|
|
from cryptarchia.cryptarchia import (
|
|
maxvalid_bg,
|
|
Chain,
|
|
BlockHeader,
|
|
Slot,
|
|
Id,
|
|
MockLeaderProof,
|
|
Coin,
|
|
)
|
|
|
|
|
|
def make_block(parent_id: Id, slot: Slot, content: bytes) -> BlockHeader:
|
|
assert len(parent_id) == 32
|
|
content_id = hashlib.sha256(content).digest()
|
|
return BlockHeader(
|
|
parent=parent_id,
|
|
content_size=1,
|
|
slot=slot,
|
|
content_id=content_id,
|
|
leader_proof=MockLeaderProof.new(
|
|
Coin(sk=0, value=10), slot=slot, parent=parent_id
|
|
),
|
|
)
|
|
|
|
|
|
class TestLeader(TestCase):
|
|
def test_fork_choice_long_sparse_chain(self):
|
|
# The longest chain is not dense after the fork
|
|
common = [make_block(bytes(32), Slot(i), bytes(i)) for i in range(1, 50)]
|
|
long_chain = deepcopy(common)
|
|
short_chain = deepcopy(common)
|
|
|
|
for slot in range(50, 100):
|
|
# make arbitrary ids for the different chain so that the blocks appear to be different
|
|
long_content = f"{slot}-long".encode()
|
|
short_content = f"{slot}-short".encode()
|
|
if slot % 2 == 0:
|
|
long_chain.append(make_block(bytes(32), Slot(slot), long_content))
|
|
short_chain.append(make_block(bytes(32), Slot(slot), short_content))
|
|
# add more blocks to the long chain
|
|
for slot in range(100, 200):
|
|
long_content = f"{slot}-long".encode()
|
|
long_chain.append(make_block(bytes(32), Slot(slot), long_content))
|
|
assert len(long_chain) > len(short_chain)
|
|
# by setting a low k we trigger the density choice rule
|
|
k = 1
|
|
s = 50
|
|
short_chain = Chain(short_chain, genesis=bytes(32))
|
|
long_chain = Chain(long_chain, genesis=bytes(32))
|
|
assert (
|
|
maxvalid_bg(
|
|
short_chain,
|
|
[long_chain],
|
|
k,
|
|
s,
|
|
)
|
|
== short_chain
|
|
)
|
|
|
|
# However, if we set k to the fork length, it will be accepted
|
|
k = long_chain.length()
|
|
assert (
|
|
maxvalid_bg(
|
|
short_chain,
|
|
[long_chain],
|
|
k,
|
|
s,
|
|
)
|
|
== long_chain
|
|
)
|
|
|
|
def test_fork_choice_long_dense_chain(self):
|
|
# The longest chain is also the densest after the fork
|
|
common = [make_block(bytes(32), Slot(i), bytes(i)) for i in range(1, 50)]
|
|
long_chain = deepcopy(common)
|
|
short_chain = deepcopy(common)
|
|
for slot in range(50, 100):
|
|
# make arbitrary ids for the different chain so that the blocks appear to be different
|
|
long_content = f"{slot}-long".encode()
|
|
short_content = f"{slot}-short".encode()
|
|
long_chain.append(make_block(bytes(32), Slot(slot), long_content))
|
|
if slot % 2 == 0:
|
|
short_chain.append(make_block(bytes(32), Slot(slot), short_content))
|
|
k = 1
|
|
s = 50
|
|
short_chain = Chain(short_chain, genesis=bytes(32))
|
|
long_chain = Chain(long_chain, genesis=bytes(32))
|
|
assert (
|
|
maxvalid_bg(
|
|
short_chain,
|
|
[long_chain],
|
|
k,
|
|
s,
|
|
)
|
|
== long_chain
|
|
)
|