mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-10 05:53:46 +00:00
feat:add state nibbles type
Signed-off-by: Chen Kai <281165273grape@gmail.com>
This commit is contained in:
parent
f1a812fcad
commit
5805416966
3 changed files with 314 additions and 1 deletions
|
|
@ -208,7 +208,6 @@ func (c *ConsensusLightClient) Advance() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//lint:ignore U1000 placeholder function
|
||||
func (c *ConsensusLightClient) bootstrap() error {
|
||||
bootstrap, err := c.API.GetCheckpointData(c.InitialCheckpoint)
|
||||
if err != nil {
|
||||
|
|
|
|||
116
portalnetwork/state/types.go
Normal file
116
portalnetwork/state/types.go
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/protolambda/zrnt/eth2/beacon/common"
|
||||
"github.com/protolambda/ztyp/codec"
|
||||
"github.com/protolambda/ztyp/tree"
|
||||
)
|
||||
|
||||
var _ common.SSZObj = (*Nibbles)(nil)
|
||||
|
||||
type Nibbles struct {
|
||||
Nibbles []byte
|
||||
}
|
||||
|
||||
func (n *Nibbles) Serialize(w *codec.EncodingWriter) error {
|
||||
if len(n.Nibbles)%2 == 0 {
|
||||
err := w.WriteByte(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(n.Nibbles); i += 2 {
|
||||
err = w.WriteByte(n.Nibbles[i]<<4 | n.Nibbles[i+1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := w.WriteByte(0x10 | n.Nibbles[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 1; i < len(n.Nibbles); i += 2 {
|
||||
err = w.WriteByte(n.Nibbles[i]<<4 | n.Nibbles[i+1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Nibbles) ByteLength() uint64 {
|
||||
return uint64(len(n.Nibbles)/2 + 1)
|
||||
}
|
||||
|
||||
func (n *Nibbles) FixedLength() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (n *Nibbles) Deserialize(dr *codec.DecodingReader) error {
|
||||
firstByte, err := dr.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
packedNibbles := make([]byte, dr.Scope())
|
||||
_, err = dr.Read(packedNibbles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
flag, first := unpackNibblePair(firstByte)
|
||||
nibbles := make([]byte, 1+2*len(packedNibbles))
|
||||
|
||||
if flag == 0 {
|
||||
if first != 0 {
|
||||
return fmt.Errorf("nibbles: The lowest 4 bits of the first byte must be 0, but was: %x", first)
|
||||
}
|
||||
} else if flag == 1 {
|
||||
nibbles = append(nibbles, first)
|
||||
} else {
|
||||
return fmt.Errorf("nibbles: The highest 4 bits of the first byte must be 0 or 1, but was: %x", flag)
|
||||
}
|
||||
|
||||
for i, b := range packedNibbles {
|
||||
left, right := unpackNibblePair(b)
|
||||
nibbles[1+2*i] = left
|
||||
nibbles[1+2*i+1] = right
|
||||
}
|
||||
|
||||
unpackedNibbles, err := FromUnpackedNibbles(nibbles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*n = *unpackedNibbles
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Nibbles) HashTreeRoot(h tree.HashFn) tree.Root {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func FromUnpackedNibbles(nibbles []byte) (*Nibbles, error) {
|
||||
if len(nibbles) > 64 {
|
||||
return nil, errors.New("too many nibbles")
|
||||
}
|
||||
|
||||
for _, nibble := range nibbles {
|
||||
if nibble > 0xf {
|
||||
return nil, errors.New("nibble out of range")
|
||||
}
|
||||
}
|
||||
|
||||
return &Nibbles{Nibbles: nibbles}, nil
|
||||
}
|
||||
|
||||
func unpackNibblePair(pair byte) (byte, byte) {
|
||||
return pair >> 4, pair & 0xf
|
||||
}
|
||||
198
portalnetwork/state/types_test.go
Normal file
198
portalnetwork/state/types_test.go
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/protolambda/ztyp/codec"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNibblesEncodeDecode(t *testing.T) {
|
||||
type fields struct {
|
||||
Nibbles []byte
|
||||
}
|
||||
type args struct {
|
||||
buf bytes.Buffer
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
encodeds string
|
||||
}{
|
||||
{
|
||||
name: "emptyNibbles",
|
||||
fields: fields{
|
||||
Nibbles: []byte{},
|
||||
},
|
||||
args: args{
|
||||
bytes.Buffer{},
|
||||
},
|
||||
encodeds: "0x00",
|
||||
},
|
||||
{
|
||||
name: "singleNibble",
|
||||
fields: fields{
|
||||
Nibbles: []byte{10},
|
||||
},
|
||||
args: args{
|
||||
bytes.Buffer{},
|
||||
},
|
||||
encodeds: "0x1a",
|
||||
},
|
||||
{
|
||||
name: "evenNumberNibbles",
|
||||
fields: fields{
|
||||
Nibbles: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
|
||||
},
|
||||
args: args{
|
||||
bytes.Buffer{},
|
||||
},
|
||||
encodeds: "0x00123456789abc",
|
||||
},
|
||||
{
|
||||
name: "oddNumberNibbles",
|
||||
fields: fields{
|
||||
Nibbles: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
|
||||
},
|
||||
args: args{
|
||||
bytes.Buffer{},
|
||||
},
|
||||
encodeds: "0x1123456789abcd",
|
||||
},
|
||||
{
|
||||
name: "maxNumberNibbles",
|
||||
fields: fields{
|
||||
Nibbles: initSlice(64, 10),
|
||||
},
|
||||
args: args{
|
||||
bytes.Buffer{},
|
||||
},
|
||||
encodeds: "0x00aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
n, err := FromUnpackedNibbles(tt.fields.Nibbles)
|
||||
assert.NoError(t, err)
|
||||
err = n.Serialize(codec.NewEncodingWriter(&tt.args.buf))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.encodeds, hexutil.Encode(tt.args.buf.Bytes()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromUnpackedShouldFailForInvalidNibbles(t *testing.T) {
|
||||
type fields struct {
|
||||
Nibbles []byte
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
encodeds string
|
||||
}{
|
||||
{
|
||||
name: "singleNibble",
|
||||
fields: fields{
|
||||
Nibbles: []byte{0x10},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "firstOutOfTwo",
|
||||
fields: fields{
|
||||
Nibbles: []byte{0x11, 0x01},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secondOutOfTwo",
|
||||
fields: fields{
|
||||
Nibbles: []byte{0x01, 0x12},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "firstOutOfThree",
|
||||
fields: fields{
|
||||
Nibbles: []byte{0x11, 0x02, 0x03},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secondOutOfThree",
|
||||
fields: fields{
|
||||
Nibbles: []byte{0x01, 0x12, 0x03},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "thirdOutOfThree",
|
||||
fields: fields{
|
||||
Nibbles: []byte{0x01, 0x02, 0x13},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := FromUnpackedNibbles(tt.fields.Nibbles)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeShouldFailForInvalidBytes(t *testing.T) {
|
||||
type fields struct {
|
||||
Nibbles string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
encodeds string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
fields: fields{
|
||||
Nibbles: "0x",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid flag",
|
||||
fields: fields{
|
||||
Nibbles: "0x20",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "low bits not empty for even length",
|
||||
fields: fields{
|
||||
Nibbles: "0x01",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "too long",
|
||||
fields: fields{
|
||||
Nibbles: "0x1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
nibbles := hexutil.MustDecode(tt.fields.Nibbles)
|
||||
var n Nibbles
|
||||
err := n.Deserialize(codec.NewDecodingReader(bytes.NewReader(nibbles), uint64(len(nibbles))))
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromUnpackedShouldFailForTooManyNibbles(t *testing.T) {
|
||||
_, err := FromUnpackedNibbles(initSlice(65, 10))
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func initSlice(n int, v byte) []byte {
|
||||
s := make([]byte, n)
|
||||
for i := range s {
|
||||
s[i] = v
|
||||
}
|
||||
return s
|
||||
}
|
||||
Loading…
Reference in a new issue