68 lines
1.8 KiB
Python
68 lines
1.8 KiB
Python
|
from unittest import TestCase
|
||
|
|
||
|
import numpy as np
|
||
|
|
||
|
from .cryptarchia import (
|
||
|
Follower,
|
||
|
TimeConfig,
|
||
|
BlockHeader,
|
||
|
Config,
|
||
|
Coin,
|
||
|
LedgerState,
|
||
|
MockLeaderProof,
|
||
|
Slot,
|
||
|
)
|
||
|
|
||
|
|
||
|
def config() -> Config:
|
||
|
return Config(
|
||
|
k=10, time=TimeConfig(slots_per_epoch=1000, slot_duration=1, chain_start_time=0)
|
||
|
)
|
||
|
|
||
|
|
||
|
class TestLedgerStateUpdate(TestCase):
|
||
|
def test_ledger_state_prevents_coin_reuse(self):
|
||
|
leader_coin = Coin(pk=0, value=100)
|
||
|
genesis_state = LedgerState(
|
||
|
block=bytes(32),
|
||
|
nonce=bytes(32),
|
||
|
total_stake=leader_coin.value,
|
||
|
commitments={leader_coin.commitment()},
|
||
|
nullifiers=set(),
|
||
|
)
|
||
|
|
||
|
follower = Follower(genesis_state, config())
|
||
|
|
||
|
block = BlockHeader(
|
||
|
slot=Slot(0),
|
||
|
parent=genesis_state.block,
|
||
|
content_size=1,
|
||
|
content_id=bytes(32),
|
||
|
leader_proof=MockLeaderProof.from_coin(leader_coin),
|
||
|
)
|
||
|
|
||
|
follower.on_block(block)
|
||
|
|
||
|
# Follower should have accepted the block
|
||
|
assert follower.local_chain.length() == 1
|
||
|
assert follower.local_chain.tip() == block
|
||
|
|
||
|
# Follower should have updated their ledger state to mark the leader coin as spent
|
||
|
assert follower.ledger_state.verify_unspent(leader_coin.nullifier()) == False
|
||
|
|
||
|
reuse_coin_block = BlockHeader(
|
||
|
slot=Slot(0),
|
||
|
parent=block.id(),
|
||
|
content_size=1,
|
||
|
content_id=bytes(32),
|
||
|
leader_proof=MockLeaderProof(
|
||
|
commitment=leader_coin.commitment(),
|
||
|
nullifier=leader_coin.nullifier(),
|
||
|
),
|
||
|
)
|
||
|
follower.on_block(block)
|
||
|
|
||
|
# Follower should *not* have accepted the block
|
||
|
assert follower.local_chain.length() == 1
|
||
|
assert follower.local_chain.tip() == block
|