go-ethereum/nomt/core/node_test.go
weiihann 2db24e85a3 nomt/core: redesign for EIP-7864 compatibility (Phase A)
Replace Keccak256+MSB tagging with SHA256. Remove leaf nodes entirely,
replacing them with opaque stem hashes. Simplify NodeKind to just
Terminator and Internal. Add HashStem (8-level binary SHA256 tree
matching bintrie StemNode.Hash). Reduce max trie depth from 256 to 248
(31-byte stem path). Replace BuildTrie/LeafOp with
BuildInternalTree/StemKeyValue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 21:59:53 +08:00

142 lines
3.1 KiB
Go

package core
import (
"crypto/sha256"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTerminatorIsZero(t *testing.T) {
var zero [32]byte
assert.Equal(t, zero, Terminator)
}
func TestNodeKindOf(t *testing.T) {
tests := []struct {
name string
node Node
want NodeKind
}{
{
name: "terminator",
node: Terminator,
want: NodeTerminator,
},
{
name: "non-zero hash is internal",
node: Node{0x80, 0x01, 0x02},
want: NodeInternal,
},
{
name: "any non-zero is internal",
node: Node{0x01, 0x02, 0x03},
want: NodeInternal,
},
{
name: "high bits set is still internal",
node: Node{0xFF, 0xFF, 0xFF},
want: NodeInternal,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := NodeKindOf(&tt.node)
assert.Equal(t, tt.want, got)
})
}
}
func TestIsTerminator(t *testing.T) {
assert.True(t, IsTerminator(&Terminator))
nonZero := Node{0x01}
assert.False(t, IsTerminator(&nonZero))
}
func TestHashInternalDeterministic(t *testing.T) {
data := &InternalData{
Left: Node{0x11, 0x22},
Right: Node{0x33, 0x44},
}
h1 := HashInternal(data)
h2 := HashInternal(data)
assert.Equal(t, h1, h2, "same inputs must produce same hash")
}
func TestHashInternalMatchesSHA256(t *testing.T) {
left := Node{0x01, 0x02, 0x03}
right := Node{0x04, 0x05, 0x06}
data := &InternalData{Left: left, Right: right}
got := HashInternal(data)
// Manual SHA256(left || right)
h := sha256.New()
h.Write(left[:])
h.Write(right[:])
expected := h.Sum(nil)
assert.Equal(t, expected, got[:])
}
func TestHashInternalNoMSBTagging(t *testing.T) {
// With SHA256, the MSB is determined by the hash output, not forced.
// Just verify it produces a non-zero, non-terminator result.
data := &InternalData{
Left: Node{0xFF, 0x01},
Right: Node{0x80, 0x02},
}
result := HashInternal(data)
require.False(t, IsTerminator(&result))
}
func TestHashStemDeterministic(t *testing.T) {
var stem StemPath
stem[0] = 0xAB
stem[1] = 0xCD
var values [StemNodeWidth][]byte
values[0] = make([]byte, 32)
values[0][0] = 0x01
h1 := HashStem(stem, values)
h2 := HashStem(stem, values)
assert.Equal(t, h1, h2, "same inputs must produce same hash")
}
func TestHashStemAllNilIsNotZero(t *testing.T) {
// Even with all nil values, the stem hash includes the stem bytes,
// so it should NOT be the zero hash (unless stem is also zero and
// subtree root is zero... let's check).
var stem StemPath
var values [StemNodeWidth][]byte
// With all-zero stem and all-nil values, the subtree root is zero.
// Final = SHA256(zero_stem || 0x00 || zero_hash)
result := HashStem(stem, values)
assert.False(t, IsTerminator(&result),
"stem hash should not be terminator even with empty values")
}
func TestHashStemSingleValue(t *testing.T) {
var stem StemPath
stem[0] = 0x42
var values [StemNodeWidth][]byte
val := make([]byte, 32)
val[0] = 0xFF
values[0] = val
result := HashStem(stem, values)
assert.False(t, IsTerminator(&result))
}
func TestStemPathType(t *testing.T) {
// Verify StemPath is 31 bytes.
var sp StemPath
assert.Equal(t, StemSize, len(sp))
assert.Equal(t, 31, len(sp))
}