Files
node/x/merkledb/simple_fuzz_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

237 lines
5.1 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package merkledb
import (
"bytes"
"context"
"testing"
"github.com/luxfi/database/memdb"
)
// FuzzDatabaseOperations tests database operations with random data
func FuzzDatabaseOperations(f *testing.F) {
// Seed corpus with various key-value patterns
f.Add([]byte("key1"), []byte("value1"))
f.Add([]byte{}, []byte{})
f.Add([]byte{0xff, 0xfe, 0xfd}, []byte{1, 2, 3, 4, 5})
f.Add(bytes.Repeat([]byte{0xaa}, 100), bytes.Repeat([]byte{0xbb}, 100))
ctx := context.Background()
f.Fuzz(func(t *testing.T, key []byte, value []byte) {
// Limit key and value sizes to avoid OOM
if len(key) > 1024 {
key = key[:1024]
}
if len(value) > 10000 {
value = value[:10000]
}
// Create a new database
db, err := New(ctx, memdb.New(), Config{
BranchFactor: BranchFactor16,
HistoryLength: 100,
ValueNodeCacheSize: 1024,
IntermediateNodeCacheSize: 1024,
IntermediateWriteBufferSize: 16,
IntermediateWriteBatchSize: 256,
})
if err != nil {
t.Fatal(err)
}
defer db.Close()
// Test Put operation
batch := db.NewBatch()
err = batch.Put(key, value)
if err != nil {
// Some keys might be invalid
return
}
// Write the batch
err = batch.Write()
if err != nil {
// Some operations might fail
return
}
// Test Get operation
retrievedValue, err := db.Get(key)
if err != nil {
t.Errorf("Failed to get key after successful put: %v", err)
return
}
// Verify value matches
if !bytes.Equal(retrievedValue, value) {
t.Errorf("Value mismatch: got %x, want %x", retrievedValue, value)
}
// Test Delete operation
batch2 := db.NewBatch()
err = batch2.Delete(key)
if err != nil {
t.Errorf("Failed to delete key: %v", err)
return
}
err = batch2.Write()
if err != nil {
t.Errorf("Failed to write delete batch: %v", err)
return
}
// Verify key is deleted
_, err = db.Get(key)
if err == nil {
t.Error("Key should be deleted but still exists")
}
})
}
// FuzzBatchOperations tests batch operations with multiple keys
func FuzzBatchOperations(f *testing.F) {
// Seed corpus
f.Add([]byte("prefix"), uint8(10))
f.Add([]byte{}, uint8(0))
f.Add([]byte{0xff}, uint8(255))
ctx := context.Background()
f.Fuzz(func(t *testing.T, prefix []byte, count uint8) {
// Limit prefix size
if len(prefix) > 100 {
prefix = prefix[:100]
}
// Limit count to avoid too many operations
if count > 50 {
count = 50
}
// Create database
db, err := New(ctx, memdb.New(), Config{
BranchFactor: BranchFactor16,
HistoryLength: 100,
ValueNodeCacheSize: 1024,
IntermediateNodeCacheSize: 1024,
IntermediateWriteBufferSize: 16,
IntermediateWriteBatchSize: 256,
})
if err != nil {
t.Fatal(err)
}
defer db.Close()
// Create batch with multiple operations
batch := db.NewBatch()
keys := make([][]byte, 0, count)
for i := uint8(0); i < count; i++ {
key := append(prefix, byte(i))
value := []byte{i, i, i}
err = batch.Put(key, value)
if err != nil {
// Some keys might be invalid
continue
}
keys = append(keys, key)
}
// Write batch
err = batch.Write()
if err != nil {
// Batch might fail
return
}
// Verify all keys exist
for i, key := range keys {
val, err := db.Get(key)
if err != nil {
t.Errorf("Failed to get key %x: %v", key, err)
continue
}
expectedVal := []byte{uint8(i), uint8(i), uint8(i)}
if !bytes.Equal(val, expectedVal) {
t.Errorf("Value mismatch for key %x: got %x, want %x", key, val, expectedVal)
}
}
})
}
// FuzzIterator tests iterator operations with random ranges
func FuzzIterator(f *testing.F) {
// Seed corpus
f.Add([]byte("start"), []byte("end"))
f.Add([]byte{0}, []byte{255})
f.Add([]byte("a"), []byte("z"))
ctx := context.Background()
f.Fuzz(func(t *testing.T, start []byte, end []byte) {
// Limit key sizes
if len(start) > 100 {
start = start[:100]
}
if len(end) > 100 {
end = end[:100]
}
// Create database with some data
db, err := New(ctx, memdb.New(), Config{
BranchFactor: BranchFactor16,
HistoryLength: 100,
ValueNodeCacheSize: 1024,
IntermediateNodeCacheSize: 1024,
IntermediateWriteBufferSize: 16,
IntermediateWriteBatchSize: 256,
})
if err != nil {
t.Fatal(err)
}
defer db.Close()
// Add some test data
batch := db.NewBatch()
testKeys := [][]byte{
[]byte("key1"), []byte("key2"), []byte("key3"),
start, end,
}
for _, key := range testKeys {
if len(key) > 0 {
_ = batch.Put(key, []byte("value"))
}
}
if err := batch.Write(); err != nil {
return
}
// Create iterator
it := db.NewIteratorWithStartAndPrefix(start, nil)
defer it.Release()
// Iterate and ensure no panic
count := 0
for it.Next() && count < 100 { // Limit iterations
_ = it.Key()
_ = it.Value()
count++
}
// Check iterator error
if err := it.Error(); err != nil {
// Some errors are expected for invalid ranges
return
}
})
}