mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
The registrar digest bound only the selector and the arguments, so a signature set authorising "register chain 5" stayed valid forever: anyone who saw the original transaction could re-apply it after an unregister, or re-apply a superseded SetGateway. The digest now carries a governance nonce that advances after each successful write. Selector 0x06 reads it. The nonce lives outside the govSlot namespace so re-seeding cannot revive retired authorisations. Two more, both reachable without any signature being valid. Every submitted signature is ECRECOVERed before any of them is known to belong to an operator, and the flat write fee bought up to 255 of them; signatures are now billed at the EVM's own ECRECOVER price. And loadGovernance allocated from a count it read out of storage, which genesis alloc can pre-populate at any address, so a malformed genesis could ask for four billion addresses at boot.
102 lines
2.7 KiB
Go
102 lines
2.7 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright (C) 2025, Lux Industries, Inc. All rights reserved.
|
|
|
|
package bridge
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/luxfi/geth/common"
|
|
)
|
|
|
|
// There is one StateDB fake in this package: regStateDB, in registrar_test.go.
|
|
// The previous second fake answered GetState/SetState and panicked on the other
|
|
// sixteen methods, so any test that reached past the storage surface died
|
|
// instead of failing — and no test could grow past it.
|
|
|
|
func TestStaticRegistry_GetAndAll(t *testing.T) {
|
|
r := NewStatic(DefaultSeed())
|
|
|
|
c, ok := r.Get(96369)
|
|
if !ok || c.Name != "lux" {
|
|
t.Fatalf("expected lux at 96369, got %+v ok=%v", c, ok)
|
|
}
|
|
|
|
if _, ok := r.Get(99999); ok {
|
|
t.Fatal("expected unknown id to miss")
|
|
}
|
|
|
|
all := r.All()
|
|
if len(all) != len(DefaultSeed()) {
|
|
t.Fatalf("All() length mismatch: %d vs %d", len(all), len(DefaultSeed()))
|
|
}
|
|
}
|
|
|
|
func TestStaticRegistry_AllReturnsCopy(t *testing.T) {
|
|
r := NewStatic(DefaultSeed())
|
|
a := r.All()
|
|
a[0].Name = "mutated"
|
|
b := r.All()
|
|
if b[0].Name == "mutated" {
|
|
t.Fatal("All() must return a defensive copy")
|
|
}
|
|
}
|
|
|
|
func TestStateRegistry_RoundTrip(t *testing.T) {
|
|
state := newRegState()
|
|
addr := common.HexToAddress("0x0000000000000000000000000000000000000440")
|
|
|
|
seed := DefaultSeed()
|
|
n, err := SeedRegistry(state, addr, seed)
|
|
if err != nil {
|
|
t.Fatalf("SeedRegistry: %v", err)
|
|
}
|
|
if n != len(seed) {
|
|
t.Fatalf("expected to write %d rows, got %d", len(seed), n)
|
|
}
|
|
|
|
r := NewStateRegistry(state, addr)
|
|
|
|
c, ok := r.Get(200200)
|
|
if !ok || c.Name != "zoo" {
|
|
t.Fatalf("expected zoo at 200200, got %+v ok=%v", c, ok)
|
|
}
|
|
|
|
c, ok = r.Get(900001)
|
|
if !ok || c.EVM {
|
|
t.Fatalf("expected solana virtual chain (EVM=false), got %+v ok=%v", c, ok)
|
|
}
|
|
|
|
all := r.All()
|
|
if len(all) != len(seed) {
|
|
t.Fatalf("All() length mismatch: %d vs %d", len(all), len(seed))
|
|
}
|
|
}
|
|
|
|
func TestStateRegistry_SeedIsIdempotent(t *testing.T) {
|
|
state := newRegState()
|
|
addr := common.HexToAddress("0x0000000000000000000000000000000000000440")
|
|
|
|
if _, err := SeedRegistry(state, addr, DefaultSeed()); err != nil {
|
|
t.Fatalf("first seed: %v", err)
|
|
}
|
|
n, err := SeedRegistry(state, addr, []Chain{{ID: 1, Name: "ignored", EVM: true}})
|
|
if err != nil {
|
|
t.Fatalf("second seed: %v", err)
|
|
}
|
|
if n != 0 {
|
|
t.Fatalf("second seed must be no-op, wrote %d rows", n)
|
|
}
|
|
}
|
|
|
|
func TestStateRegistry_RejectsLongName(t *testing.T) {
|
|
state := newRegState()
|
|
addr := common.HexToAddress("0x0000000000000000000000000000000000000440")
|
|
|
|
long := Chain{ID: 7, Name: "this-name-is-definitely-more-than-thirty-two-bytes", EVM: true}
|
|
_, err := SeedRegistry(state, addr, []Chain{long})
|
|
if err != ErrChainNameTooLong {
|
|
t.Fatalf("expected ErrChainNameTooLong, got %v", err)
|
|
}
|
|
}
|