Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/sync -- Use proto for sending Change Proofs #1541

Merged
merged 91 commits into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
d6426bf
Update sync.proto
dboehm-avalabs May 3, 2023
51e75d8
Update sync.proto
dboehm-avalabs May 3, 2023
dd74d3b
Update sync.proto
dboehm-avalabs May 3, 2023
b3b68ff
sync.proto recommended changes
rkuris May 3, 2023
f1eb6de
Review comments
rkuris May 4, 2023
6cce0d3
rename KeyProof to ProofNode; rename ProofNode.value_hash to ProofNod…
May 18, 2023
ec51aeb
actually add SerializedPath message
May 18, 2023
63386d4
int --> uint32 in proto
May 19, 2023
e108976
regenerate .pb.go files
May 19, 2023
7845dfd
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos
May 19, 2023
d04c7a1
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 19, 2023
dfe894d
add ToProto for ProofNode and RangeProof; send range proof repsonse a…
May 19, 2023
5af51ac
add FromProto for ProofNode; add tests
May 19, 2023
42422d1
add tests; add proto MaybeBytes type
May 19, 2023
35267b5
add proto MaybeBytes type
May 22, 2023
0d08f96
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 22, 2023
ef94cf1
add to test
May 22, 2023
860ee03
disallow maybe with nothing and value
May 22, 2023
b3d3387
add comment
May 22, 2023
70e4ab4
add more proofNode validity checks
May 22, 2023
c0b2bdc
remove EncodeRangeProof and DecodeRangeProof
May 22, 2023
6dae5b5
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos
May 22, 2023
e0f48b7
remove unused functions
May 22, 2023
7c1eb7c
import nits
May 22, 2023
e493c27
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 22, 2023
d33831f
make value in MaybeBytes non-optional; make value in KeyChange a Mayb…
May 22, 2023
3d6b53a
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 22, 2023
a47ad58
regenerate .pb.go files
May 22, 2023
8176dc3
add ToProto and UnmarshalProto for ChangeProof
May 22, 2023
ac38726
use proto to encode/decode change proofs
May 22, 2023
687e38f
WIP removing EncodeChangeProof and DecodeChangeProof usage
May 22, 2023
2859a54
add had_roots_in_history to ChangeProof
May 22, 2023
44f869c
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto-chang…
May 22, 2023
5f29b57
Merge branch 'MerkleSyncProtos-use-proto' of github.com:ava-labs/aval…
May 22, 2023
1115354
Merge branch 'MerkleSyncProtos-use-proto' of github.com:ava-labs/aval…
May 22, 2023
f2f50e2
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 22, 2023
d0cde74
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 22, 2023
d6daa7b
fix proto ordering
May 22, 2023
4d47288
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 22, 2023
94b03a0
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 22, 2023
35fbcec
update .pb.go files
May 22, 2023
3a0317c
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 22, 2023
93179cd
fix test
May 22, 2023
de32cda
comment nit
May 22, 2023
86a1b63
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 22, 2023
a1da8f7
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 22, 2023
844d032
appease linter
May 22, 2023
73bcfd0
/* --> // for proto comments
May 23, 2023
7b434ea
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos
May 23, 2023
4dffa64
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 23, 2023
f9adebc
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 23, 2023
72b748c
/* --> // for proto comments
May 23, 2023
bb98fc5
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 23, 2023
3149d41
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 23, 2023
f7d39a7
nit
May 23, 2023
07ade20
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 23, 2023
0524de5
Merge branch 'dev' into MerkleSyncProtos
May 24, 2023
0050f21
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos
May 24, 2023
c99236d
Merge branch 'MerkleSyncProtos' of github.com:ava-labs/avalanchego in…
May 24, 2023
61f4c27
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 24, 2023
081ab36
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 24, 2023
cad3a80
rename RangeProofResponse --> RangeProof
May 24, 2023
52af5a6
Merge branch 'MerkleSyncProtos' into MerkleSyncProtos-use-proto
May 24, 2023
4417a28
update .pb.go files
May 24, 2023
88d1495
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 24, 2023
f0c7833
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos-use…
May 25, 2023
46baa78
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 25, 2023
c2d6692
add nil checks in ProofNode.UnmarshalProto
May 25, 2023
c19fbf8
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 25, 2023
78da8e0
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos-use…
May 25, 2023
a62321c
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 25, 2023
be0f6bd
add nil checks in RangeProof.UnmarshalProto
May 25, 2023
dbd0714
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 25, 2023
4283af2
add nil checks in ChangeProof.UnmarshalProto
May 25, 2023
e5ad19b
`x/sync` -- Remove `EncodeProof`, `DecodeProof`, helpers (#1546)
May 30, 2023
d05f98c
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos-use…
May 30, 2023
dfea9e5
change nibble length field from uint32 to uint64
May 30, 2023
137f75f
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 30, 2023
22a91c8
Merge branch 'MerkleSyncProtos-use-proto-change-proof' of github.com:…
May 30, 2023
cea0f50
import nit
May 30, 2023
57bfa1e
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 30, 2023
9022216
appease linter
May 30, 2023
e405154
Merge branch 'MerkleSyncProtos-use-proto' into MerkleSyncProtos-use-p…
May 30, 2023
a3109e3
appease linter
May 30, 2023
527785e
appease linter
May 30, 2023
6e6abd4
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos-use…
May 31, 2023
9c19993
unexport codec methods
May 31, 2023
24f04e5
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos-use…
May 31, 2023
31f6420
Merge branch 'dev' into MerkleSyncProtos-use-proto-change-proof
Jun 1, 2023
9431d52
Merge remote-tracking branch 'upstream/dev' into MerkleSyncProtos-use…
Jun 1, 2023
e684663
Merge branch 'MerkleSyncProtos-use-proto-change-proof' of github.com:…
Jun 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
344 changes: 22 additions & 322 deletions x/merkledb/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,52 +41,44 @@ const (
)

var (
_ EncoderDecoder = (*codecImpl)(nil)
_ encoderDecoder = (*codecImpl)(nil)

trueBytes = []byte{trueByte}
falseBytes = []byte{falseByte}

errUnknownVersion = errors.New("unknown codec version")
errEncodeNil = errors.New("can't encode nil pointer or interface")
errDecodeNil = errors.New("can't decode nil")
errNegativeProofPathNodes = errors.New("negative proof path length")
errNegativeNumChildren = errors.New("number of children is negative")
errTooManyChildren = fmt.Errorf("length of children list is larger than branching factor of %d", NodeBranchFactor)
errChildIndexTooLarge = fmt.Errorf("invalid child index. Must be less than branching factor of %d", NodeBranchFactor)
errNegativeNibbleLength = errors.New("nibble length is negative")
errNegativeNumKeyValues = errors.New("negative number of key values")
errIntTooLarge = errors.New("integer too large to be decoded")
errLeadingZeroes = errors.New("varint has leading zeroes")
errInvalidBool = errors.New("decoded bool is neither true nor false")
errNonZeroNibblePadding = errors.New("nibbles should be padded with 0s")
errExtraSpace = errors.New("trailing buffer space")
errNegativeSliceLength = errors.New("negative slice length")
errInvalidCodecVersion = errors.New("invalid codec version")
errUnknownVersion = errors.New("unknown codec version")
errEncodeNil = errors.New("can't encode nil pointer or interface")
errDecodeNil = errors.New("can't decode nil")
errNegativeNumChildren = errors.New("number of children is negative")
errTooManyChildren = fmt.Errorf("length of children list is larger than branching factor of %d", NodeBranchFactor)
errChildIndexTooLarge = fmt.Errorf("invalid child index. Must be less than branching factor of %d", NodeBranchFactor)
errNegativeNibbleLength = errors.New("nibble length is negative")
errIntTooLarge = errors.New("integer too large to be decoded")
errLeadingZeroes = errors.New("varint has leading zeroes")
errInvalidBool = errors.New("decoded bool is neither true nor false")
errNonZeroNibblePadding = errors.New("nibbles should be padded with 0s")
errExtraSpace = errors.New("trailing buffer space")
errNegativeSliceLength = errors.New("negative slice length")
errInvalidCodecVersion = errors.New("invalid codec version")
)

// EncoderDecoder defines the interface needed by merkleDB to marshal
// encoderDecoder defines the interface needed by merkleDB to marshal
// and unmarshal relevant types.
type EncoderDecoder interface {
Encoder
Decoder
type encoderDecoder interface {
encoder
decoder
}

type Encoder interface {
EncodeProof(version uint16, p *Proof) ([]byte, error)
EncodeChangeProof(version uint16, p *ChangeProof) ([]byte, error)

type encoder interface {
encodeDBNode(version uint16, n *dbNode) ([]byte, error)
encodeHashValues(version uint16, hv *hashValues) ([]byte, error)
}

type Decoder interface {
DecodeProof(bytes []byte, p *Proof) (uint16, error)
DecodeChangeProof(bytes []byte, p *ChangeProof) (uint16, error)

type decoder interface {
decodeDBNode(bytes []byte, n *dbNode) (uint16, error)
}

func newCodec() (EncoderDecoder, uint16) {
func newCodec() (encoderDecoder, uint16) {
return &codecImpl{
varIntPool: sync.Pool{
New: func() interface{} {
Expand All @@ -100,65 +92,6 @@ type codecImpl struct {
varIntPool sync.Pool
}

func (c *codecImpl) EncodeProof(version uint16, proof *Proof) ([]byte, error) {
if proof == nil {
return nil, errEncodeNil
}

if version != codecVersion {
return nil, fmt.Errorf("%w: %d", errUnknownVersion, version)
}

buf := &bytes.Buffer{}
if err := c.encodeInt(buf, int(version)); err != nil {
return nil, err
}
if err := c.encodeProofPath(buf, proof.Path); err != nil {
return nil, err
}
if err := c.encodeByteSlice(buf, proof.Key); err != nil {
return nil, err
}
if err := c.encodeMaybeByteSlice(buf, proof.Value); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

func (c *codecImpl) EncodeChangeProof(version uint16, proof *ChangeProof) ([]byte, error) {
if proof == nil {
return nil, errEncodeNil
}

if version != codecVersion {
return nil, fmt.Errorf("%w: %d", errUnknownVersion, version)
}

buf := &bytes.Buffer{}

if err := c.encodeInt(buf, int(version)); err != nil {
return nil, err
}
if err := c.encodeBool(buf, proof.HadRootsInHistory); err != nil {
return nil, err
}
if err := c.encodeProofPath(buf, proof.StartProof); err != nil {
return nil, err
}
if err := c.encodeProofPath(buf, proof.EndProof); err != nil {
return nil, err
}
if err := c.encodeInt(buf, len(proof.KeyChanges)); err != nil {
return nil, err
}
for _, kv := range proof.KeyChanges {
if err := c.encodeKeyChange(kv, buf); err != nil {
return nil, err
}
}
return buf.Bytes(), nil
}

func (c *codecImpl) encodeDBNode(version uint16, n *dbNode) ([]byte, error) {
if n == nil {
return nil, errEncodeNil
Expand Down Expand Up @@ -237,92 +170,6 @@ func (c *codecImpl) encodeHashValues(version uint16, hv *hashValues) ([]byte, er
return buf.Bytes(), nil
}

func (c *codecImpl) DecodeProof(b []byte, proof *Proof) (uint16, error) {
if proof == nil {
return 0, errDecodeNil
}
if minProofLen > len(b) {
return 0, io.ErrUnexpectedEOF
}

var (
err error
src = bytes.NewReader(b)
)
gotCodecVersion, err := c.decodeInt(src)
if err != nil {
return 0, err
}
if codecVersion != gotCodecVersion {
return 0, fmt.Errorf("%w: %d", errInvalidCodecVersion, gotCodecVersion)
}
if proof.Path, err = c.decodeProofPath(src); err != nil {
return 0, err
}
if proof.Key, err = c.decodeByteSlice(src); err != nil {
return 0, err
}
if proof.Value, err = c.decodeMaybeByteSlice(src); err != nil {
return 0, err
}
if src.Len() != 0 {
return 0, errExtraSpace
}
return codecVersion, nil
}

func (c *codecImpl) DecodeChangeProof(b []byte, proof *ChangeProof) (uint16, error) {
if proof == nil {
return 0, errDecodeNil
}
if minChangeProofLen > len(b) {
return 0, io.ErrUnexpectedEOF
}

var (
src = bytes.NewReader(b)
err error
)

gotCodecVersion, err := c.decodeInt(src)
if err != nil {
return 0, err
}
if gotCodecVersion != codecVersion {
return 0, fmt.Errorf("%w: %d", errInvalidCodecVersion, gotCodecVersion)
}
if proof.HadRootsInHistory, err = c.decodeBool(src); err != nil {
return 0, err
}
if proof.StartProof, err = c.decodeProofPath(src); err != nil {
return 0, err
}
if proof.EndProof, err = c.decodeProofPath(src); err != nil {
return 0, err
}

numKeyChanges, err := c.decodeInt(src)
if err != nil {
return 0, err
}
if numKeyChanges < 0 {
return 0, errNegativeNumKeyValues
}
if numKeyChanges > src.Len()/minKeyChangeLen {
return 0, io.ErrUnexpectedEOF
}
proof.KeyChanges = make([]KeyChange, numKeyChanges)
for i := range proof.KeyChanges {
if proof.KeyChanges[i], err = c.decodeKeyChange(src); err != nil {
return 0, err
}
}
if src.Len() != 0 {
return 0, errExtraSpace
}
return codecVersion, nil
}

func (c *codecImpl) decodeDBNode(b []byte, n *dbNode) (uint16, error) {
if n == nil {
return 0, errDecodeNil
Expand Down Expand Up @@ -392,34 +239,6 @@ func (c *codecImpl) decodeDBNode(b []byte, n *dbNode) (uint16, error) {
return codecVersion, err
}

func (c *codecImpl) decodeKeyChange(src *bytes.Reader) (KeyChange, error) {
if minKeyChangeLen > src.Len() {
return KeyChange{}, io.ErrUnexpectedEOF
}

var (
result KeyChange
err error
)
if result.Key, err = c.decodeByteSlice(src); err != nil {
return result, err
}
if result.Value, err = c.decodeMaybeByteSlice(src); err != nil {
return result, err
}
return result, nil
}

func (c *codecImpl) encodeKeyChange(kv KeyChange, dst io.Writer) error {
if err := c.encodeByteSlice(dst, kv.Key); err != nil {
return err
}
if err := c.encodeMaybeByteSlice(dst, kv.Value); err != nil {
return err
}
return nil
}

func (*codecImpl) encodeBool(dst io.Writer, value bool) error {
bytesValue := falseBytes
if value {
Expand Down Expand Up @@ -584,125 +403,6 @@ func (*codecImpl) decodeID(src *bytes.Reader) (ids.ID, error) {
return id, nil
}

// Assumes a proof path has > 0 nodes.
func (c *codecImpl) decodeProofPath(src *bytes.Reader) ([]ProofNode, error) {
if minProofPathLen > src.Len() {
return nil, io.ErrUnexpectedEOF
}

numProofNodes, err := c.decodeInt(src)
if err != nil {
return nil, err
}
if numProofNodes < 0 {
return nil, errNegativeProofPathNodes
}
if numProofNodes > src.Len()/minProofNodeLen {
return nil, io.ErrUnexpectedEOF
}
result := make([]ProofNode, numProofNodes)
for i := 0; i < numProofNodes; i++ {
if result[i], err = c.decodeProofNode(src); err != nil {
return nil, err
}
}
return result, nil
}

// Invariant: len(path) > 0.
func (c *codecImpl) encodeProofPath(dst io.Writer, path []ProofNode) error {
if err := c.encodeInt(dst, len(path)); err != nil {
return err
}
for _, proofNode := range path {
if err := c.encodeProofNode(proofNode, dst); err != nil {
return err
}
}
return nil
}

func (c *codecImpl) decodeProofNode(src *bytes.Reader) (ProofNode, error) {
if minProofNodeLen > src.Len() {
return ProofNode{}, io.ErrUnexpectedEOF
}

var (
result ProofNode
err error
)
if result.KeyPath, err = c.decodeSerializedPath(src); err != nil {
return result, err
}
if result.ValueOrHash, err = c.decodeMaybeByteSlice(src); err != nil {
return result, err
}
numChildren, err := c.decodeInt(src)
if err != nil {
return result, err
}
switch {
case numChildren < 0:
return result, errNegativeNumChildren
case numChildren > NodeBranchFactor:
return result, errTooManyChildren
case numChildren > src.Len()/minProofNodeChildLen:
return result, io.ErrUnexpectedEOF
}

result.Children = make(map[byte]ids.ID, numChildren)
previousChild := -1
for addedEntries := 0; addedEntries < numChildren; addedEntries++ {
index, err := c.decodeInt(src)
if err != nil {
return result, err
}
if index <= previousChild || index >= NodeBranchFactor {
return result, errChildIndexTooLarge
}
previousChild = index

childID, err := c.decodeID(src)
if err != nil {
return result, err
}
result.Children[byte(index)] = childID
}
return result, nil
}

func (c *codecImpl) encodeProofNode(pn ProofNode, dst io.Writer) error {
if err := c.encodeSerializedPath(pn.KeyPath, dst); err != nil {
return err
}
if err := c.encodeMaybeByteSlice(dst, pn.ValueOrHash); err != nil {
return err
}
if err := c.encodeInt(dst, len(pn.Children)); err != nil {
return err
}
// ensure this is in order
childrenCount := 0
for index := byte(0); index < NodeBranchFactor; index++ {
childID, ok := pn.Children[index]
if !ok {
continue
}
childrenCount++
if err := c.encodeInt(dst, int(index)); err != nil {
return err
}
if _, err := dst.Write(childID[:]); err != nil {
return err
}
}
// there are children present with index >= NodeBranchFactor
if childrenCount != len(pn.Children) {
return errChildIndexTooLarge
}
return nil
}

func (c *codecImpl) encodeSerializedPath(s SerializedPath, dst io.Writer) error {
if err := c.encodeInt(dst, s.NibbleLength); err != nil {
return err
Expand Down
Loading