Files
node/db/rpcdb/zap_server_test.go
zeekay 7cf87b230b node-unified is the node
The module already called itself github.com/luxfi/node while containing no node
in Go: cmd/luxd was twenty-one lines that printed the size of a few types, and
the Go column of the matrix measured a VM plugin. A repo that fetches the thing
it claims to be has not replaced it, so the Go sources move in — 1515 files,
the daemon and everything under it — and the build reaches outside this module
for nothing.

Rust and C++ sit beside it unchanged and are still measured against it by the
differential. That is the point of one repo: the reference implementation and
the two ports are the same checkout, so parity is a thing you can run rather
than a thing you assert.

Verified: builds, and the closure carries no lux-private — checked at build time
rather than believed. The daemon starts twelve chains on a local network
(P X C Q Z A B G K M F, plus D through its plugin) and reports healthy.
2026-09-07 16:15:25 -07:00

276 lines
6.9 KiB
Go

// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package rpcdb
import (
"context"
"net"
"testing"
"time"
"github.com/stretchr/testify/require"
zapwire "github.com/luxfi/api/zap"
"github.com/luxfi/database"
"github.com/luxfi/database/memdb"
)
// startZAPServer spawns a ZAPServer over an in-memory listener bound to
// 127.0.0.1:0, returns the addr + the server (for shutdown).
func startZAPServer(t *testing.T, db database.Database) (string, *ZAPServer, context.CancelFunc) {
t.Helper()
listener, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)
s := NewZAPServer(db)
s.ListenOn(listener)
ctx, cancel := context.WithCancel(context.Background())
go func() {
_ = s.Serve(ctx)
}()
// Wait for Serve to fully install accept loop.
time.Sleep(50 * time.Millisecond)
return listener.Addr().String(), s, cancel
}
// TestZAPServer_HasGetPutDelete exercises the four primitive ops.
func TestZAPServer_HasGetPutDelete(t *testing.T) {
require := require.New(t)
mem := memdb.New()
addr, srv, cancel := startZAPServer(t, mem)
defer cancel()
defer srv.Close()
conn, err := zapwire.Dial(context.Background(), addr, nil)
require.NoError(err)
defer conn.Close()
ctx := context.Background()
// Has (key absent) → has=false, err=NotFound
{
buf := zapwire.GetBuffer()
buf.WriteBytes([]byte("foo"))
_, resp, err := conn.Call(ctx, MsgDBHas, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
hasB, _ := r.ReadUint8()
errB, _ := r.ReadUint8()
require.Equal(uint8(0), hasB)
require.Equal(dbErrUnspecified, errB) // memdb returns no err on Has-miss
}
// Put
{
buf := zapwire.GetBuffer()
buf.WriteBytes([]byte("foo"))
buf.WriteBytes([]byte("bar"))
_, resp, err := conn.Call(ctx, MsgDBPut, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
errB, _ := r.ReadUint8()
require.Equal(dbErrUnspecified, errB)
}
// Has (key present) → has=true
{
buf := zapwire.GetBuffer()
buf.WriteBytes([]byte("foo"))
_, resp, err := conn.Call(ctx, MsgDBHas, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
hasB, _ := r.ReadUint8()
errB, _ := r.ReadUint8()
require.Equal(uint8(1), hasB)
require.Equal(dbErrUnspecified, errB)
}
// Get
{
buf := zapwire.GetBuffer()
buf.WriteBytes([]byte("foo"))
_, resp, err := conn.Call(ctx, MsgDBGet, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
val, _ := r.ReadBytes()
errB, _ := r.ReadUint8()
require.Equal([]byte("bar"), val)
require.Equal(dbErrUnspecified, errB)
}
// Get (missing) → empty value, err=NotFound
{
buf := zapwire.GetBuffer()
buf.WriteBytes([]byte("absent"))
_, resp, err := conn.Call(ctx, MsgDBGet, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
val, _ := r.ReadBytes()
errB, _ := r.ReadUint8()
require.Empty(val)
require.Equal(dbErrNotFound, errB)
}
// Delete
{
buf := zapwire.GetBuffer()
buf.WriteBytes([]byte("foo"))
_, resp, err := conn.Call(ctx, MsgDBDelete, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
errB, _ := r.ReadUint8()
require.Equal(dbErrUnspecified, errB)
}
// Get post-delete → NotFound
{
buf := zapwire.GetBuffer()
buf.WriteBytes([]byte("foo"))
_, resp, err := conn.Call(ctx, MsgDBGet, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
_, _ = r.ReadBytes()
errB, _ := r.ReadUint8()
require.Equal(dbErrNotFound, errB)
}
}
// TestZAPServer_WriteBatch_AndIterate covers batched writes plus the
// iterator path used by cevm's load_persisted snapshot_with_prefix.
func TestZAPServer_WriteBatch_AndIterate(t *testing.T) {
require := require.New(t)
mem := memdb.New()
addr, srv, cancel := startZAPServer(t, mem)
defer cancel()
defer srv.Close()
conn, err := zapwire.Dial(context.Background(), addr, nil)
require.NoError(err)
defer conn.Close()
ctx := context.Background()
// WriteBatch: 3 puts (prefix p:), 1 delete (no-op since absent).
{
buf := zapwire.GetBuffer()
buf.WriteUint32(3)
buf.WriteBytes([]byte("p:1"))
buf.WriteBytes([]byte("v1"))
buf.WriteBytes([]byte("p:2"))
buf.WriteBytes([]byte("v2"))
buf.WriteBytes([]byte("q:3"))
buf.WriteBytes([]byte("v3"))
buf.WriteUint32(1)
buf.WriteBytes([]byte("absent"))
_, resp, err := conn.Call(ctx, MsgDBWriteBatch, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
errB, _ := r.ReadUint8()
require.Equal(dbErrUnspecified, errB)
}
// IteratorNew with prefix "p:"
var iterID uint64
{
buf := zapwire.GetBuffer()
buf.WriteBytes(nil) // start
buf.WriteBytes([]byte("p:")) // prefix
_, resp, err := conn.Call(ctx, MsgDBIteratorNew, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
iterID, _ = r.ReadUint64()
}
// IteratorNext — collect.
collected := map[string]string{}
for {
buf := zapwire.GetBuffer()
buf.WriteUint64(iterID)
_, resp, err := conn.Call(ctx, MsgDBIteratorNext, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
n, _ := r.ReadUint32()
if n == 0 {
break
}
for i := uint32(0); i < n; i++ {
k, _ := r.ReadBytes()
v, _ := r.ReadBytes()
collected[string(k)] = string(v)
}
}
// IteratorRelease
{
buf := zapwire.GetBuffer()
buf.WriteUint64(iterID)
_, resp, err := conn.Call(ctx, MsgDBIteratorRelease, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
r := zapwire.NewReader(resp)
errB, _ := r.ReadUint8()
require.Equal(dbErrUnspecified, errB)
}
require.Equal(map[string]string{"p:1": "v1", "p:2": "v2"}, collected)
}
// TestZAPServer_ParityWithMemDB writes/reads via wire and via direct
// memdb Get to confirm both paths see the same state — proves the ZAP
// round-trip preserves bytes exactly.
func TestZAPServer_ParityWithMemDB(t *testing.T) {
require := require.New(t)
mem := memdb.New()
addr, srv, cancel := startZAPServer(t, mem)
defer cancel()
defer srv.Close()
conn, err := zapwire.Dial(context.Background(), addr, nil)
require.NoError(err)
defer conn.Close()
ctx := context.Background()
key := []byte{0x42, 0x00, 0x01, 0xff}
value := make([]byte, 256)
for i := range value {
value[i] = byte(i)
}
// Put via wire.
buf := zapwire.GetBuffer()
buf.WriteBytes(key)
buf.WriteBytes(value)
_, _, err = conn.Call(ctx, MsgDBPut, buf.Bytes())
zapwire.PutBuffer(buf)
require.NoError(err)
// Read directly.
got, dErr := mem.Get(key)
require.NoError(dErr)
require.Equal(value, got)
// Read via wire.
buf2 := zapwire.GetBuffer()
buf2.WriteBytes(key)
_, resp, err := conn.Call(ctx, MsgDBGet, buf2.Bytes())
zapwire.PutBuffer(buf2)
require.NoError(err)
r := zapwire.NewReader(resp)
wireVal, _ := r.ReadBytes()
require.Equal(value, wireVal)
}