hdiff restart-support: add exponents encoding helpers

This commit is contained in:
Preston Van Loon
2026-02-04 11:59:27 -06:00
parent eaf3aa3e8e
commit 7df09b12a5
3 changed files with 80 additions and 2 deletions

View File

@@ -21,9 +21,46 @@ import (
var (
offsetKey = []byte("offset")
exponentsKey = []byte("exponents")
ErrSlotBeforeOffset = errors.New("slot is before state-diff root offset")
)
func encodeStateDiffExponents(exponents []int) ([]byte, error) {
if len(exponents) == 0 {
return nil, errors.New("state diff exponents cannot be empty")
}
if len(exponents) > 255 {
return nil, fmt.Errorf("state diff exponents length %d exceeds max 255", len(exponents))
}
encoded := make([]byte, len(exponents)+1)
encoded[0] = byte(len(exponents))
for i, exp := range exponents {
if exp < 2 || exp > flags.MaxStateDiffExponent {
return nil, fmt.Errorf("state diff exponent %d out of range for encoding", exp)
}
encoded[i+1] = byte(exp)
}
return encoded, nil
}
func decodeStateDiffExponents(encoded []byte) ([]int, error) {
if len(encoded) == 0 {
return nil, errors.New("state diff exponents missing length prefix")
}
count := int(encoded[0])
if count == 0 {
return nil, errors.New("state diff exponents length cannot be zero")
}
if len(encoded) != count+1 {
return nil, fmt.Errorf("state diff exponents length mismatch: expected %d got %d", count, len(encoded)-1)
}
exponents := make([]int, count)
for i := range count {
exponents[i] = int(encoded[i+1])
}
return exponents, nil
}
func makeKeyForStateDiffTree(level int, slot uint64) []byte {
buf := make([]byte, 16)
buf[0] = byte(level)

View File

@@ -34,6 +34,47 @@ func TestStateDiff_LoadOrInitOffset(t *testing.T) {
require.Equal(t, uint64(10), offset)
}
func TestStateDiff_EncodeDecodeExponents(t *testing.T) {
t.Run("roundtrip", func(t *testing.T) {
exponents := []int{21, 18, 16, 13}
encoded, err := encodeStateDiffExponents(exponents)
require.NoError(t, err)
decoded, err := decodeStateDiffExponents(encoded)
require.NoError(t, err)
require.DeepEqual(t, exponents, decoded)
})
t.Run("encode-empty", func(t *testing.T) {
_, err := encodeStateDiffExponents(nil)
require.ErrorContains(t, "cannot be empty", err)
})
t.Run("encode-negative", func(t *testing.T) {
_, err := encodeStateDiffExponents([]int{21, -1})
require.ErrorContains(t, "out of range", err)
})
t.Run("encode-too-large", func(t *testing.T) {
_, err := encodeStateDiffExponents([]int{flags.MaxStateDiffExponent + 1})
require.ErrorContains(t, "out of range", err)
})
t.Run("decode-empty", func(t *testing.T) {
_, err := decodeStateDiffExponents(nil)
require.ErrorContains(t, "missing length prefix", err)
})
t.Run("decode-zero-length", func(t *testing.T) {
_, err := decodeStateDiffExponents([]byte{0})
require.ErrorContains(t, "length cannot be zero", err)
})
t.Run("decode-length-mismatch", func(t *testing.T) {
_, err := decodeStateDiffExponents([]byte{2, 10})
require.ErrorContains(t, "length mismatch", err)
})
}
func TestStateDiff_ComputeLevel(t *testing.T) {
db := setupDB(t)
setDefaultStateDiffExponents()

View File

@@ -9,7 +9,7 @@ import (
"github.com/urfave/cli/v2"
)
const maxStateDiffExponents = 30
const MaxStateDiffExponent = 30
// GlobalFlags specifies all the global flags for the
// beacon node.
@@ -132,7 +132,7 @@ func validateStateDiffExponents(exponents []int) error {
if exponents[length-1] < 5 {
return errors.New("the last state diff exponent must be at least 5")
}
prev := maxStateDiffExponents + 1
prev := MaxStateDiffExponent + 1
for _, exp := range exponents {
if exp >= prev {
return errors.New("state diff exponents must be in strictly decreasing order, and each exponent must be <= 30")