Skip to content

Commit

Permalink
merkledb -- add codec test and move helper (#1944)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Laine authored Aug 29, 2023
1 parent acc9e09 commit 7bf1239
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 46 deletions.
103 changes: 57 additions & 46 deletions x/merkledb/codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,9 @@ import (
"github.com/stretchr/testify/require"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/hashing"
"github.com/ava-labs/avalanchego/utils/maybe"
)

// TODO add more codec tests

func newRandomProofNode(r *rand.Rand) ProofNode {
key := make([]byte, r.Intn(32)) // #nosec G404
_, _ = r.Read(key) // #nosec G404
serializedKey := newPath(key).Serialize()

val := make([]byte, r.Intn(64)) // #nosec G404
_, _ = r.Read(val) // #nosec G404

children := map[byte]ids.ID{}
for j := 0; j < NodeBranchFactor; j++ {
if r.Float64() < 0.5 {
var childID ids.ID
_, _ = r.Read(childID[:]) // #nosec G404
children[byte(j)] = childID
}
}

hasValue := rand.Intn(2) == 1 // #nosec G404
var valueOrHash maybe.Maybe[[]byte]
if hasValue {
// use the hash instead when length is greater than the hash length
if len(val) >= HashLength {
val = hashing.ComputeHash256(val)
} else if len(val) == 0 {
// We do this because when we encode a value of []byte{} we will later
// decode it as nil.
// Doing this prevents inconsistency when comparing the encoded and
// decoded values.
// Calling nilEmptySlices doesn't set this because it is a private
// variable on the struct
val = nil
}
valueOrHash = maybe.Some(val)
}

return ProofNode{
KeyPath: serializedKey,
ValueOrHash: valueOrHash,
Children: children,
}
}

func FuzzCodecBool(f *testing.F) {
f.Fuzz(
func(
Expand Down Expand Up @@ -224,7 +179,7 @@ func FuzzCodecDBNodeDeterministic(f *testing.F) {
)
}

func TestCodec_DecodeDBNode(t *testing.T) {
func TestCodecDecodeDBNode(t *testing.T) {
require := require.New(t)

var (
Expand Down Expand Up @@ -260,3 +215,59 @@ func TestCodec_DecodeDBNode(t *testing.T) {
err = codec.decodeDBNode(proofBytesBuf.Bytes(), &parsedDBNode)
require.ErrorIs(err, errTooManyChildren)
}

// Ensure that encodeHashValues is deterministic
func FuzzEncodeHashValues(f *testing.F) {
codec1 := newCodec()
codec2 := newCodec()

f.Fuzz(
func(
t *testing.T,
randSeed int,
) {
require := require.New(t)

// Create a random *hashValues
r := rand.New(rand.NewSource(int64(randSeed))) // #nosec G404

children := map[byte]child{}
numChildren := r.Intn(NodeBranchFactor) // #nosec G404
for i := 0; i < numChildren; i++ {
compressedPathLen := r.Intn(32) // #nosec G404
compressedPathBytes := make([]byte, compressedPathLen)
_, _ = r.Read(compressedPathBytes) // #nosec G404

children[byte(i)] = child{
compressedPath: newPath(compressedPathBytes),
id: ids.GenerateTestID(),
hasValue: r.Intn(2) == 1, // #nosec G404
}
}

hasValue := r.Intn(2) == 1 // #nosec G404
value := maybe.Nothing[[]byte]()
if hasValue {
valueBytes := make([]byte, r.Intn(64)) // #nosec G404
_, _ = r.Read(valueBytes) // #nosec G404
value = maybe.Some(valueBytes)
}

key := make([]byte, r.Intn(32)) // #nosec G404
_, _ = r.Read(key) // #nosec G404

hv := &hashValues{
Children: children,
Value: value,
Key: newPath(key).Serialize(),
}

// Serialize the *hashValues with both codecs
hvBytes1 := codec1.encodeHashValues(hv)
hvBytes2 := codec2.encodeHashValues(hv)

// Make sure they're the same
require.Equal(hvBytes1, hvBytes2)
},
)
}
40 changes: 40 additions & 0 deletions x/merkledb/proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,46 @@ func writeBasicBatch(t *testing.T, db *merkleDB) {
require.NoError(batch.Write())
}

func newRandomProofNode(r *rand.Rand) ProofNode {
key := make([]byte, r.Intn(32)) // #nosec G404
_, _ = r.Read(key) // #nosec G404
serializedKey := newPath(key).Serialize()

val := make([]byte, r.Intn(64)) // #nosec G404
_, _ = r.Read(val) // #nosec G404

children := map[byte]ids.ID{}
for j := 0; j < NodeBranchFactor; j++ {
if r.Float64() < 0.5 {
var childID ids.ID
_, _ = r.Read(childID[:]) // #nosec G404
children[byte(j)] = childID
}
}

hasValue := rand.Intn(2) == 1 // #nosec G404
var valueOrHash maybe.Maybe[[]byte]
if hasValue {
// use the hash instead when length is greater than the hash length
if len(val) >= HashLength {
val = hashing.ComputeHash256(val)
} else if len(val) == 0 {
// We do this because when we encode a value of []byte{} we will later
// decode it as nil.
// Doing this prevents inconsistency when comparing the encoded and
// decoded values.
val = nil
}
valueOrHash = maybe.Some(val)
}

return ProofNode{
KeyPath: serializedKey,
ValueOrHash: valueOrHash,
Children: children,
}
}

func Test_Proof_Empty(t *testing.T) {
proof := &Proof{}
err := proof.Verify(context.Background(), ids.Empty)
Expand Down

0 comments on commit 7bf1239

Please sign in to comment.