Skip to content

Commit

Permalink
cryptarchia: update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
davidrusu committed Dec 1, 2024
1 parent de32864 commit 155ac24
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 232 deletions.
30 changes: 1 addition & 29 deletions cryptarchia/cryptarchia.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ def unimported_orphans(self) -> list[BlockHeader]:

# Evaluate the fork choice rule and return the chain we should be following
def fork_choice(self) -> Id:
return ghost_maxvalid_bg(
return maxvalid_bg(
self.local_chain,
self.forks,
k=self.config.k,
Expand Down Expand Up @@ -722,32 +722,6 @@ def block_children(states: Dict[Id, LedgerState]) -> Dict[Id, set[Id]]:
return children


def block_weight(states: Dict[Id, LedgerState]) -> Dict[Id, int]:
children = block_children(states)

block_weight = {}

pending = {b for b in states if len(children[b]) == 0}
ready = set()

while len(pending) > 0:
new_ready = set()
for b in pending:
if children[b] <= ready:
block_weight[b] = 1 + sum(block_weight[c] for c in children[b])
new_ready.add(b)

for b in new_ready:
pending.remove(b)

if states[b].block.parent in states:
pending.add(states[b].block.parent)

ready.add(b)

return block_weight


# Implementation of the Cryptarchia fork choice rule (following Ouroborous Genesis).
# The fork choice has two phases:
# 1. if the chain is not forking too deeply, we apply the longest chain fork choice rule
Expand All @@ -765,8 +739,6 @@ def maxvalid_bg(
assert type(local_chain) == Id
assert all(type(f) == Id for f in forks)

weights = block_weight(states)

cmax = local_chain
for fork in forks:
cmax_depth, fork_depth = common_prefix_depth(cmax, fork, states)
Expand Down
207 changes: 4 additions & 203 deletions cryptarchia/test_fork_choice.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

from copy import deepcopy
from cryptarchia.cryptarchia import (
block_weight,
ghost_maxvalid_bg,
maxvalid_bg,
Slot,
Coin,
Follower,
Expand All @@ -15,204 +14,6 @@


class TestForkChoice(TestCase):
def test_ghost_fork_choice(self):
# Example from the GHOST paper
#
# 2D - 3F - 4C - 5B
# /
# / 3E
# / /
# 1B - 2C - 3D - 4B
# / \ \
# 0 \ 3C
# \ \
# \ 2B - 3B
# \
# 1A - 2A - 3A - 4A - 5A - 6A

coin = Coin(sk=1, value=100)

b0 = mk_genesis_state([]).block

b1A = mk_block(b0, 1, coin, content=b"b1A")
b2A = mk_block(b1A, 2, coin, content=b"b2A")
b3A = mk_block(b2A, 3, coin, content=b"b3A")
b4A = mk_block(b3A, 4, coin, content=b"b4A")
b5A = mk_block(b4A, 5, coin, content=b"b5A")
b6A = mk_block(b5A, 6, coin, content=b"b6A")
b1B = mk_block(b0, 1, coin, content=b"b1B")
b2B = mk_block(b1B, 2, coin, content=b"b2B")
b3B = mk_block(b2B, 3, coin, content=b"b3B")
b2C = mk_block(b1B, 2, coin, content=b"b2C")
b3C = mk_block(b2C, 3, coin, content=b"b3C")
b2D = mk_block(b1B, 2, coin, content=b"b2D")
b3D = mk_block(b2C, 3, coin, content=b"b3D")
b4B = mk_block(b3D, 4, coin, content=b"b4B")
b3E = mk_block(b2C, 3, coin, content=b"b3E")
b3F = mk_block(b2D, 3, coin, content=b"b3F")
b4C = mk_block(b3F, 4, coin, content=b"b4C")
b5B = mk_block(b4C, 5, coin, content=b"b5B")

states = {
b.id(): LedgerState(block=b)
for b in [
b0,
b1A,
b2A,
b3A,
b4A,
b5A,
b6A,
b1B,
b2B,
b3B,
b4B,
b5B,
b2C,
b3C,
b4C,
b2D,
b3D,
b3E,
b3F,
]
}

assert (d := common_prefix_depth(b5B.id(), b3E.id(), states)) == (4, 2), d

k = 100
s = int(3 * k / 0.05)
tip = ghost_maxvalid_bg(
b5B.id(), [b3E.id(), b4B.id(), b3C.id(), b3B.id(), b6A.id()], k, s, states
)
assert tip == b4B.id()

def test_block_weight_paper(self):
# Example from the GHOST paper
#
# 2D - 3F - 4C - 5B
# /
# / 3E
# / /
# 1B - 2C - 3D - 4B
# / \ \
# 0 \ 3C
# \ \
# \ 2B - 3B
# \
# 1A - 2A - 3A - 4A - 5A - 6A

coin = Coin(sk=1, value=100)

b0 = mk_genesis_state([]).block

b1A = mk_block(b0, 1, coin, content=b"b1A")
b2A = mk_block(b1A, 2, coin, content=b"b2A")
b3A = mk_block(b2A, 3, coin, content=b"b3A")
b4A = mk_block(b3A, 4, coin, content=b"b4A")
b5A = mk_block(b4A, 5, coin, content=b"b5A")
b6A = mk_block(b5A, 6, coin, content=b"b6A")
b1B = mk_block(b0, 1, coin, content=b"b1B")
b2B = mk_block(b1B, 2, coin, content=b"b2B")
b3B = mk_block(b2B, 3, coin, content=b"b3B")
b2C = mk_block(b1B, 2, coin, content=b"b2C")
b3C = mk_block(b2C, 3, coin, content=b"b3C")
b2D = mk_block(b1B, 2, coin, content=b"b2D")
b3D = mk_block(b2C, 3, coin, content=b"b3D")
b4B = mk_block(b3D, 4, coin, content=b"b4B")
b3E = mk_block(b2C, 3, coin, content=b"b3E")
b3F = mk_block(b2D, 3, coin, content=b"b3F")
b4C = mk_block(b3F, 4, coin, content=b"b4C")
b5B = mk_block(b4C, 5, coin, content=b"b5B")

states = {
b.id(): LedgerState(block=b)
for b in [
b0,
b1A,
b2A,
b3A,
b4A,
b5A,
b6A,
b1B,
b2B,
b3B,
b4B,
b5B,
b2C,
b3C,
b4C,
b2D,
b3D,
b3E,
b3F,
]
}

weight = block_weight(states)

expected_weight = {
b0.id(): 19,
b1A.id(): 6,
b2A.id(): 5,
b3A.id(): 4,
b4A.id(): 3,
b5A.id(): 2,
b6A.id(): 1,
b1B.id(): 12,
b2B.id(): 2,
b3B.id(): 1,
b4B.id(): 1,
b5B.id(): 1,
b2C.id(): 5,
b3C.id(): 1,
b4C.id(): 2,
b2D.id(): 4,
b3D.id(): 2,
b3E.id(): 1,
b3F.id(): 3,
}

assert weight == expected_weight

def test_block_weight(self):
# 6 - 7
# /
# 0 - 1 - 2 - 3
# \
# 4 - 5

coin = Coin(sk=1, value=100)

b0 = mk_genesis_state([]).block
b1 = mk_block(b0, 1, coin)
b2 = mk_block(b1, 2, coin)
b3 = mk_block(b2, 3, coin)
b4 = mk_block(b0, 1, coin, content=b"b4")
b5 = mk_block(b4, 2, coin)
b6 = mk_block(b2, 3, coin, content=b"b6")
b7 = mk_block(b6, 4, coin)

states = {
b.id(): LedgerState(block=b) for b in [b0, b1, b2, b3, b4, b5, b6, b7]
}

weights = block_weight(states)

expected_weights = {
b0.id(): 8,
b1.id(): 5,
b2.id(): 4,
b3.id(): 1,
b4.id(): 2,
b5.id(): 1,
b6.id(): 2,
b7.id(): 1,
}

assert weights == expected_weights, weights

def test_common_prefix_depth(self):
# 6 - 7
# /
Expand Down Expand Up @@ -289,14 +90,14 @@ def test_fork_choice_long_sparse_chain(self):
states = {b.id(): LedgerState(block=b) for b in short_chain + long_chain}

assert (
ghost_maxvalid_bg(short_chain[-1].id(), [long_chain[-1].id()], k, s, states)
maxvalid_bg(short_chain[-1].id(), [long_chain[-1].id()], k, s, states)
== short_chain[-1].id()
)

# However, if we set k to the fork length, it will be accepted
k = len(long_chain)
assert (
ghost_maxvalid_bg(short_chain[-1].id(), [long_chain[-1].id()], k, s, states)
maxvalid_bg(short_chain[-1].id(), [long_chain[-1].id()], k, s, states)
== long_chain[-1].id()
)

Expand Down Expand Up @@ -324,7 +125,7 @@ def test_fork_choice_long_dense_chain(self):
states = {b.id(): LedgerState(block=b) for b in short_chain + long_chain}

assert (
ghost_maxvalid_bg(short_chain[-1].id(), [long_chain[-1].id()], k, s, states)
maxvalid_bg(short_chain[-1].id(), [long_chain[-1].id()], k, s, states)
== long_chain[-1].id()
)

Expand Down

0 comments on commit 155ac24

Please sign in to comment.