diff --git a/cmd/rlpgen/handlers.go b/cmd/rlpgen/handlers.go new file mode 100644 index 00000000000..2a8853c29b0 --- /dev/null +++ b/cmd/rlpgen/handlers.go @@ -0,0 +1,734 @@ +// Copyright 2025 The Erigon Authors +// This file is part of Erigon. +// +// Erigon is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Erigon is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Erigon. If not, see . + +package main + +import ( + "bytes" + "fmt" + "go/types" +) + +var decodeBufAdded bool +var intSizeAdded bool // for encoding size +var intEncodeAdded bool // for rlp encoding + +// create decoder buffer if not added yet +func addDecodeBuf(b *bytes.Buffer) { + if !decodeBufAdded { + fmt.Fprint(b, " var b []byte\n") + decodeBufAdded = true + } +} + +// add List start check +func startListDecode(b *bytes.Buffer, fieldName string) { + fmt.Fprintf(b, " _, err = s.List()\n") + fmt.Fprintf(b, " if err != nil {\n") + fmt.Fprintf(b, " return fmt.Errorf(\"error decoding field %s - expected list start, err: %%w\", err)\n", fieldName) + fmt.Fprintf(b, " }\n") +} + +// add List end check +func endListDecode(b *bytes.Buffer, fieldName string) { + fmt.Fprintf(b, " if err = s.ListEnd(); err != nil {\n") + fmt.Fprintf(b, " return fmt.Errorf(\"error decoding field %s - fail to close list, err: %%w\", err)\n", fieldName) + fmt.Fprintf(b, " }\n") +} + +// add reusable int for encoding size usage +func addIntSize(b *bytes.Buffer) { + if !intSizeAdded { + fmt.Fprint(b, " gidx := 0\n") + intSizeAdded = true + } else { + fmt.Fprint(b, " gidx = 0\n") + } +} + +// add reusable int for encoding usage +func addIntEncode(b *bytes.Buffer) { + if !intEncodeAdded { + fmt.Fprint(b, " gidx := 0\n") + intEncodeAdded = true + } else { + fmt.Fprint(b, " gidx = 0\n") + } +} + +func decodeErrorMsg(filedName string) string { + return fmt.Sprintf("return fmt.Errorf(\"error decoding field %s, err: %%w\", err)", filedName) +} + +func decodeLenMismatch(want int) string { + return fmt.Sprintf("return fmt.Errorf(\"error decoded length mismatch, expected: %d, got: %%d\", len(b))", want) +} + +// 1. add package to imports if the to-be encoded field is not in the same package +// e.g do not import "github.com/erigontech/erigon/core/types" if the field is types.BlockNonce +func addToImports(named *types.Named) (typ string) { + if named.Obj().Pkg().Name() != pkgSrc.Name() { + _imports[named.Obj().Pkg().Path()] = true + typ = named.Obj().Pkg().Name() + "." + named.Obj().Name() + } else { + typ = named.Obj().Name() + } + return +} + +func uint64CastTo(kind types.BasicKind) string { + var cast string + switch kind { + case types.Int16: + cast = "int16" + case types.Int32: + cast = "int32" + case types.Int: + cast = "int" + case types.Int64: + cast = "int64" + case types.Uint16: + cast = "uint16" + case types.Uint32: + cast = "uint32" + case types.Uint: + cast = "uint" + case types.Uint64: + return "i := n" + default: + panic(fmt.Sprintf("unhandled basic kind: %d", kind)) + } + return fmt.Sprintf("i := %s(n)", cast) +} + +func uintHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + var kind types.BasicKind + if basic, ok := fieldType.(*types.Basic); !ok { + _exit("uintHandle: expected fieldType to be Basic") + } else { + kind = basic.Kind() + } + + // size + fmt.Fprintf(b1, " size += rlp.IntLenExcludingHead(uint64(obj.%s)) + 1\n", fieldName) + + // encode + fmt.Fprintf(b2, " if err := rlp.EncodeInt(uint64(obj.%s), w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + if kind != types.Uint64 { + cast := uint64CastTo(kind) + fmt.Fprintf(b3, " if n, err := s.Uint(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " } else {\n") + fmt.Fprintf(b3, " %s\n", cast) + fmt.Fprintf(b3, " obj.%s = i\n", fieldName) + fmt.Fprintf(b3, " }\n") + } else { + fmt.Fprintf(b3, " if obj.%s, err = s.Uint(); err != nil {\n", fieldName) + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + } +} + +func uintPtrHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + var kind types.BasicKind + if ptr, ok := fieldType.(*types.Pointer); !ok { + _exit("uintPtrHandle: expected fieldType to be Pointer") + } else { + if basic, ok := ptr.Elem().(*types.Basic); !ok { + _exit("uintPtrHandle: expected fieldType to be Pointer Basic") + } else { + kind = basic.Kind() + } + } + + // size + fmt.Fprintf(b1, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b1, " size += rlp.IntLenExcludingHead(uint64(*obj.%s)) + 1\n", fieldName) + fmt.Fprintf(b1, " }\n") + + // encode + fmt.Fprintf(b2, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b2, " if err := rlp.EncodeInt(uint64(*obj.%s), w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " }\n") + + // decode + cast := uint64CastTo(kind) + fmt.Fprintf(b3, " if n, err := s.Uint(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " } else {\n") + fmt.Fprintf(b3, " %s\n", cast) + fmt.Fprintf(b3, " obj.%s = &i\n", fieldName) + fmt.Fprintf(b3, " }\n") +} + +func bigIntHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + if named, ok := fieldType.(*types.Named); !ok { + _exit("bigIntHandle: expected filedType to be Named") + } else { + _ = addToImports(named) + } + // size + fmt.Fprintf(b1, " size += rlp.BigIntLenExcludingHead(&obj.%s) + 1\n", fieldName) + + // encode + fmt.Fprintf(b2, " if err := rlp.EncodeBigInt(&obj.%s, w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Uint256Bytes(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " obj.%s = *(new(big.Int).SetBytes(b))\n", fieldName) +} + +func bigIntPtrHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + if ptr, ok := fieldType.(*types.Pointer); !ok { + _exit("bigIntPtrHandle: expected fieldType to be Pointer") + } else { + if named, ok := ptr.Elem().(*types.Named); !ok { + _exit("bigIntPtrHandle: expected filedType to be Pointer Named") + } else { + _ = addToImports(named) + } + } + + // size + fmt.Fprintf(b1, " size += 1\n") + fmt.Fprintf(b1, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b1, " size += rlp.BigIntLenExcludingHead(obj.%s)\n", fieldName) + fmt.Fprintf(b1, " }\n") + + // encode + fmt.Fprintf(b2, " if err := rlp.EncodeBigInt(obj.%s, w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Uint256Bytes(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " obj.%s = new(big.Int).SetBytes(b)\n", fieldName) +} + +func uint256Handle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + if named, ok := fieldType.(*types.Named); !ok { + _exit("uint256Handle: expected filedType to be Named") + } else { + _ = addToImports(named) + } + + // size + fmt.Fprintf(b1, " size += rlp.Uint256LenExcludingHead(&obj.%s) + 1\n", fieldName) + + // encode + fmt.Fprintf(b2, " if err := rlp.EncodeUint256(&obj.%s, w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Uint256Bytes(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " obj.%s = *(new(uint256.Int).SetBytes(b))\n", fieldName) +} + +func uint256PtrHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + if ptr, ok := fieldType.(*types.Pointer); !ok { + _exit("uint256PtrHandle: expected fieldType to be Pointer") + } else { + if named, ok := ptr.Elem().(*types.Named); !ok { + _exit("uint256PtrHandle: expected filedType to be Pointer Named") + } else { + _ = addToImports(named) + } + } + + // size + fmt.Fprintf(b1, " size += rlp.Uint256LenExcludingHead(obj.%s) + 1\n", fieldName) + + // encode + fmt.Fprintf(b2, " if err := rlp.EncodeUint256(obj.%s, w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Uint256Bytes(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " obj.%s = new(uint256.Int).SetBytes(b)\n", fieldName) +} + +func _shortArrayHandle(b1, b2, b3 *bytes.Buffer, fieldName string, size int) { // TODO change the name + // arr sizes < 56 + + // size + fmt.Fprintf(b1, " size += %d + 1\n", size) + + // encode + fmt.Fprintf(b2, " b[0] = 128 + %d\n", size) + fmt.Fprintf(b2, " if _, err := w.Write(b[:1]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " if _, err := w.Write(obj.%s[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Bytes(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " if len(b) > 0 && len(b) != %d {\n", size) + fmt.Fprintf(b3, " %s\n", decodeLenMismatch(size)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " copy(obj.%s[:], b)\n", fieldName) +} + +func _shortArrayPtrHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string, size int) error { + // arr sizes < 56 + var typ string + if ptr, ok := fieldType.(*types.Pointer); !ok { + _exit("_shortArrayPtrHandle: expected fieldType to be Pointer") + } else { + if named, ok := ptr.Elem().(*types.Named); !ok { + _exit("_shortArrayPtrHandle: expected filedType to be Pointer Named") + } else { + typ = addToImports(named) + } + } + + // size + fmt.Fprintf(b1, " size += 1\n") + fmt.Fprintf(b1, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b1, " size += %d\n", size) + fmt.Fprintf(b1, " }\n") + + // encode + fmt.Fprintf(b2, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b2, " b[0] = 128 + %d\n", size) + fmt.Fprintf(b2, " } else {\n") + fmt.Fprintf(b2, " b[0] = 128\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " if _, err := w.Write(b[:1]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b2, " if _, err := w.Write(obj.%s[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Bytes(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " if len(b) > 0 && len(b) != %d {\n", size) + fmt.Fprintf(b3, " %s\n", decodeLenMismatch(size)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " obj.%s = &%s{}\n", fieldName, typ) + fmt.Fprintf(b3, " copy((*obj.%s)[:], b)\n", fieldName) + + return nil +} + +func blockNonceHandle(b1, b2, b3 *bytes.Buffer, _ types.Type, fieldName string) { + _shortArrayHandle(b1, b2, b3, fieldName, 8) +} + +func blockNoncePtrHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + _shortArrayPtrHandle(b1, b2, b3, fieldType, fieldName, 8) +} + +func addressHandle(b1, b2, b3 *bytes.Buffer, _ types.Type, fieldName string) { + _shortArrayHandle(b1, b2, b3, fieldName, 20) +} + +func addressPtrHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + _shortArrayPtrHandle(b1, b2, b3, fieldType, fieldName, 20) +} + +func hashHandle(b1, b2, b3 *bytes.Buffer, _ types.Type, fieldName string) { + _shortArrayHandle(b1, b2, b3, fieldName, 32) +} + +func hashPtrHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + _shortArrayPtrHandle(b1, b2, b3, fieldType, fieldName, 32) +} + +func bloomHandle(b1, b2, b3 *bytes.Buffer, _ types.Type, fieldName string) { + // size + fmt.Fprintf(b1, " size += 259\n") + + // encode + fmt.Fprintf(b2, " b[0] = 183 + 2\n") + fmt.Fprintf(b2, " b[1] = 1\n") + fmt.Fprintf(b2, " b[2] = 0\n") + fmt.Fprintf(b2, " if _, err := w.Write(b[:3]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " if _, err := w.Write(obj.%s[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Bytes(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " if len(b) > 0 && len(b) != 256 {\n") + fmt.Fprintf(b3, " %s\n", decodeLenMismatch(256)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " copy(obj.%s[:], b)\n", fieldName) +} + +func bloomPtrHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + var typ string + if ptr, ok := fieldType.(*types.Pointer); !ok { + _exit("bloomPtrHandle: expected fieldType to be Pointer") + } else { + if named, ok := ptr.Elem().(*types.Named); !ok { + _exit("bloomPtrHandle: expected filedType to be Pointer Named") + } else { + typ = addToImports(named) + } + } + + // size + fmt.Fprintf(b1, " size += 1\n") + fmt.Fprintf(b1, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b1, " size += 258\n") + fmt.Fprintf(b1, " }\n") + + // encode + fmt.Fprintf(b2, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b2, " b[0] = 183 + 2\n") + fmt.Fprintf(b2, " b[1] = 1\n") + fmt.Fprintf(b2, " b[2] = 0\n") + fmt.Fprintf(b2, " } else {\n") + fmt.Fprintf(b2, " b[0] = 128\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b2, " if _, err := w.Write(b[:3]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " if _, err := w.Write(obj.%s[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " } else {\n") + fmt.Fprintf(b2, " if _, err := w.Write(b[:1]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Bytes(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " if len(b) > 0 && len(b) != 256 {\n") + fmt.Fprintf(b3, " %s\n", decodeLenMismatch(256)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " obj.%s = &%s{}\n", fieldName, typ) + fmt.Fprintf(b3, " copy((*obj.%s)[:], b)\n", fieldName) +} + +func byteSliceHandle(b1, b2, b3 *bytes.Buffer, _ types.Type, fieldName string) { + // size + fmt.Fprintf(b1, " size += rlp.StringLen(obj.%s)\n", fieldName) + + // encode + fmt.Fprintf(b2, " if err := rlp.EncodeString(obj.%s, w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if obj.%s, err = s.Bytes(); err != nil {\n", fieldName) + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") +} + +func byteSlicePtrHandle(b1, b2, b3 *bytes.Buffer, _ types.Type, fieldName string) { + // size + fmt.Fprintf(b1, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b1, " size += rlp.StringLen(*obj.%s)\n", fieldName) + fmt.Fprintf(b1, " } else {\n") + fmt.Fprintf(b1, " size += 1\n") + fmt.Fprintf(b1, " }\n") + + // encode + fmt.Fprintf(b2, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b2, " if err := rlp.EncodeString(*obj.%s, w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " } else {\n") + fmt.Fprintf(b2, " if err := rlp.EncodeString([]byte{}, w, b[:]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + + fmt.Fprintf(b3, " if b, err = s.Bytes(); err != nil {\n") + fmt.Fprintf(b3, " %s\n", decodeErrorMsg(fieldName)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " obj.%s = &[]byte{}\n", fieldName) + fmt.Fprintf(b3, " *obj.%s = append(*obj.%s, b...)\n", fieldName, fieldName) +} + +func byteSliceSliceHandle(b1, b2, b3 *bytes.Buffer, _ types.Type, fieldName string) { + // size + fmt.Fprintf(b1, " size += rlp.ByteSliceSliceSize(obj.%s)\n", fieldName) + + // encode + fmt.Fprintf(b2, " if err := rlp.EncodeByteSliceSlice(obj.%s, w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + startListDecode(b3, fieldName) + + fmt.Fprintf(b3, " obj.%s = [][]byte{}\n", fieldName) + fmt.Fprintf(b3, " for b, err = s.Bytes(); err == nil; b, err = s.Bytes() {\n") + fmt.Fprintf(b3, " obj.%s = append(obj.%s, b)\n", fieldName, fieldName) + fmt.Fprintf(b3, " }\n") + + endListDecode(b3, fieldName) +} + +func _shortArraySliceHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string, size int) { + var typ string + if slc, ok := fieldType.(*types.Slice); !ok { + _exit("_shortArraySliceHandle: expected filedType to be Slice") + } else { + if named, ok := slc.Elem().(*types.Named); !ok { + _exit("_shortArraySliceHandle: expected filedType to be Slice Named") + } else { + typ = addToImports(named) + } + } + + // size + addIntSize(b1) + fmt.Fprintf(b1, " gidx = (%d + 1) * len(obj.%s)\n", size, fieldName) + fmt.Fprintf(b1, " size += rlp.ListPrefixLen(gidx) + gidx\n") + + // encode + addIntEncode(b2) + fmt.Fprintf(b2, " gidx = (%d + 1) * len(obj.%s)\n", size, fieldName) + fmt.Fprintf(b2, " if err := rlp.EncodeStructSizePrefix(gidx, w, b[:]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " for i := 0; i < len(obj.%s); i++ {\n", fieldName) + fmt.Fprintf(b2, " if err := rlp.EncodeString(obj.%s[i][:], w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + startListDecode(b3, fieldName) + + fmt.Fprintf(b3, " obj.%s = []%s{}\n", fieldName, typ) + fmt.Fprintf(b3, " for b, err = s.Bytes(); err == nil; b, err = s.Bytes() {\n") + fmt.Fprintf(b3, " if len(b) > 0 && len(b) != %d {\n", size) + fmt.Fprintf(b3, " %s\n", decodeLenMismatch(size)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " var s %s\n", typ) + fmt.Fprintf(b3, " copy(s[:], b)\n") + fmt.Fprintf(b3, " obj.%s = append(obj.%s, s)\n", fieldName, fieldName) + fmt.Fprintf(b3, " }\n") + + endListDecode(b3, fieldName) +} + +func _shortArrayPtrSliceHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string, size int) { + // size < 56 + + var typ string + if slc, ok := fieldType.(*types.Slice); !ok { + _exit("_shortArrayPtrSliceHandle: expected filedType to be Slice") + } else { + if ptr, ok := slc.Elem().(*types.Pointer); !ok { + _exit("_shortArrayPtrSliceHandle: expected filedType to be Slice Pointer") + } else { + if named, ok := ptr.Elem().(*types.Named); !ok { + _exit("_shortArrayPtrSliceHandle: expected filedType to be Slice Pointer Named") + } else { + typ = addToImports(named) + } + } + } + + // size + addIntSize(b1) + fmt.Fprintf(b1, " for i := 0; i < len(obj.%s); i++ {\n", fieldName) + fmt.Fprintf(b1, " if obj.%s[i] != nil {\n", fieldName) + fmt.Fprintf(b1, " gidx += %d + 1\n", size) + fmt.Fprintf(b1, " } else {\n") + fmt.Fprintf(b1, " gidx += 1\n") + fmt.Fprintf(b1, " }\n") + fmt.Fprintf(b1, " }\n") + fmt.Fprintf(b1, " size += rlp.ListPrefixLen(gidx) + gidx\n") + + // encode + addIntEncode(b2) + fmt.Fprintf(b2, " for i := 0; i < len(obj.%s); i++ {\n", fieldName) + fmt.Fprintf(b2, " if obj.%s[i] != nil {\n", fieldName) + fmt.Fprintf(b2, " gidx += %d + 1\n", size) + fmt.Fprintf(b2, " } else {\n") + fmt.Fprintf(b2, " gidx += 1\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " if err := rlp.EncodeStructSizePrefix(gidx, w, b[:]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " for i := 0; i < len(obj.%s); i++ {\n", fieldName) + fmt.Fprintf(b2, " if obj.%s[i] != nil {\n", fieldName) + fmt.Fprintf(b2, " if err := rlp.EncodeString(obj.%s[i][:], w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " } else {\n") + fmt.Fprintf(b2, " if err := rlp.EncodeString([]byte{}, w, b[:]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + startListDecode(b3, fieldName) + + fmt.Fprintf(b3, " obj.%s = []*%s{}\n", fieldName, typ) + fmt.Fprintf(b3, " for b, err = s.Bytes(); err == nil; b, err = s.Bytes() {\n") + fmt.Fprintf(b3, " var s %s\n", typ) + fmt.Fprintf(b3, " if len(b) > 0 && len(b) != %d {\n", size) + fmt.Fprintf(b3, " %s\n", decodeLenMismatch(size)) + fmt.Fprintf(b3, " } else if len(b) == %d {\n", size) + fmt.Fprintf(b3, " copy(s[:], b)\n") + fmt.Fprintf(b3, " obj.%s = append(obj.%s, &s)\n", fieldName, fieldName) + fmt.Fprintf(b3, " } else if len(b) == 0{\n") + fmt.Fprintf(b3, " obj.%s = append(obj.%s, nil)\n", fieldName, fieldName) + fmt.Fprintf(b3, " } else {\n") + fmt.Fprintf(b3, " %s\n", decodeLenMismatch(size)) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " }\n") + + endListDecode(b3, fieldName) +} + +func blockNonceSliceHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + _shortArraySliceHandle(b1, b2, b3, fieldType, fieldName, 8) +} + +func blockNoncePtrSliceHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + _shortArrayPtrSliceHandle(b1, b2, b3, fieldType, fieldName, 8) +} + +func addressSliceHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + _shortArraySliceHandle(b1, b2, b3, fieldType, fieldName, 20) +} + +func addressPtrSliceHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + _shortArrayPtrSliceHandle(b1, b2, b3, fieldType, fieldName, 20) +} + +func hashSliceHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + _shortArraySliceHandle(b1, b2, b3, fieldType, fieldName, 32) +} + +func hashPtrSliceHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + _shortArrayPtrSliceHandle(b1, b2, b3, fieldType, fieldName, 32) +} + +func byteArrayHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + var size int + if arr, ok := fieldType.(*types.Array); !ok { + _exit("byteArrayHandle: expected filedType to be Array") + } else { + size = int(arr.Len()) + } + + // size + fmt.Fprintf(b1, " size += %d + rlp.ListPrefixLen(%d)\n", size, size) + + // encode + fmt.Fprintf(b2, " if err := rlp.EncodeString(obj.%s[:], w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Bytes(); err != nil {\n") + fmt.Fprintf(b3, " return err\n") + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " copy(obj.%s[:], b)\n", fieldName) +} + +func byteArrayPtrHandle(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) { + + var size int + if ptr, ok := fieldType.(*types.Pointer); !ok { + _exit("byteArrayPtrHandle: expected filedType to be Pointer") + } else { + if arr, ok := ptr.Elem().(*types.Array); !ok { + _exit("byteArrayPtrHandle: expected filedType to be Pointer Array") + } else { + size = int(arr.Len()) + } + } + + // size + fmt.Fprintf(b1, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b1, " size += %d\n", size) + fmt.Fprintf(b1, " }\n") + fmt.Fprintf(b1, " size += rlp.ListPrefixLen(%d)\n", size) + + // encode + fmt.Fprintf(b2, " if obj.%s != nil {\n", fieldName) + fmt.Fprintf(b2, " if err := rlp.EncodeString(obj.%s[:], w, b[:]); err != nil {\n", fieldName) + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " } else {\n") + fmt.Fprintf(b2, " if err := rlp.EncodeString([]byte{}, w, b[:]); err != nil {\n") + fmt.Fprintf(b2, " return err\n") + fmt.Fprintf(b2, " }\n") + fmt.Fprintf(b2, " }\n") + + // decode + addDecodeBuf(b3) + fmt.Fprintf(b3, " if b, err = s.Bytes(); err != nil {\n") + fmt.Fprintf(b3, " return err\n") + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " if len(b) > 0 {\n") + fmt.Fprintf(b3, " obj.%s = &[%d]byte{}\n", fieldName, size) + fmt.Fprintf(b3, " copy((*obj.%s)[:], b)\n", fieldName) + fmt.Fprintf(b3, " }\n") +} diff --git a/cmd/rlpgen/main.go b/cmd/rlpgen/main.go new file mode 100644 index 00000000000..0b88f6e8708 --- /dev/null +++ b/cmd/rlpgen/main.go @@ -0,0 +1,286 @@ +// Copyright 2025 The Erigon Authors +// This file is part of Erigon. +// +// Erigon is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Erigon is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Erigon. If not, see . + +// NOTE: This generator works only on structures, if the type is slice of types (e.g []MyType) it will fail. +// And not all the field types currently supported, see `matcher.go` +// This will be fixed in the future. + +package main + +import ( + "bytes" + "errors" + "flag" + "fmt" + "go/types" + "os" + "strings" + + "golang.org/x/tools/go/packages" +) + +const ( + rlpPackagePath = "github.com/erigontech/erigon-lib/rlp" +) + +const headerMsg = "// Code generated by rlpgen. DO NOT EDIT.\n\n" + +var ( + _imports = map[string]bool{} + pkgSrc *types.Package +) + +func main() { + var ( + pkgdir = flag.String("dir", ".", "input package") + typename = flag.String("type", "", "type to generate methods for") + writefile = flag.Bool("wfile", true, "set to false if no need to write to the file") + ) + flag.Parse() + + pcfg := &packages.Config{ + Mode: packages.NeedName | packages.NeedTypes, + Dir: *pkgdir, + } + ps, err := packages.Load(pcfg, rlpPackagePath, ".") + if err != nil { + _exit(fmt.Sprint("error loading package: ", err)) + } + if len(ps) != 2 { + _exit(fmt.Sprintf("expected to load 2 packages: 1) %v, 2) %v\n \tgot %v", rlpPackagePath, *pkgdir, len(ps))) + } + + if err := checkPackageErrors(ps[0]); err != nil { + _exit(err.Error()) + } + if err := checkPackageErrors(ps[1]); err != nil { + _exit(err.Error()) + } + if ps[0].PkgPath != rlpPackagePath { + _exit(fmt.Sprintf("expected first package to be %s\n", rlpPackagePath)) + } + + pkgSrc = ps[1].Types + fmt.Println("pkgSrc: ", pkgSrc.Name()) + fmt.Println("typename: ", *typename) + + // 1. search for a struct + typ, err := findType(pkgSrc.Scope(), *typename) + if err != nil { + _exit(err.Error()) + } + + // TODO(racytech): add error checks for the possible unhandled errors + + var encodingSize bytes.Buffer + var encodeRLP bytes.Buffer + var decodeRLP bytes.Buffer + // ps[0].Types - rlp package + // ps[1].Types - package where to search for to-be generated struct + if err := process(typ, &encodingSize, &encodeRLP, &decodeRLP); err != nil { + _exit(err.Error()) + } + + result := addImports() + + result = append(result, encodingSize.Bytes()...) + result = append(result, encodeRLP.Bytes()...) + result = append(result, decodeRLP.Bytes()...) + os.Stdout.Write(result) + if *writefile { + outfile := fmt.Sprintf("%s/gen_%s_rlp.go", *pkgdir, strings.ToLower(typ.Obj().Name())) + fmt.Println("outfile: ", outfile) + if err := os.WriteFile(outfile, result, 0600); err != nil { + _exit(err.Error()) + } + } else { + os.Stdout.Write(result) + } +} + +func _exit(msg string) { + fmt.Println(msg) + os.Exit(1) +} + +func checkPackageErrors(pkg *packages.Package) error { + var b bytes.Buffer + if len(pkg.Errors) > 0 { + fmt.Fprintf(&b, "package %s has errors: \n", pkg.PkgPath) + for _, e := range pkg.Errors { + fmt.Fprintf(&b, "%s\n", e.Msg) + } + } + if b.Len() > 0 { + return errors.New(b.String()) + } + return nil +} + +func addImports() []byte { + _imports["fmt"] = true + _imports["io"] = true + _imports[rlpPackagePath] = true + + result := make([]byte, 0, len(_imports)) + result = append(result, []byte(headerMsg)...) + result = append(result, []byte("package "+pkgSrc.Name()+"\n\n")...) + result = append(result, []byte("import (\n")...) + for k := range _imports { + result = append(result, []byte(" ")...) + result = append(result, '"') + result = append(result, []byte(k)...) + result = append(result, '"', '\n') + } + result = append(result, []byte(")\n\n")...) + return result +} + +func process(typ *types.Named, b1, b2, b3 *bytes.Buffer) error { + // TODO(racytech): handle all possible errors + + typename := typ.Obj().Name() + + // 1. start EncodingSize method on a struct + fmt.Fprintf(b1, "func (obj *%s) EncodingSize() (size int) {\n", typename) + + // 2. start EncodeRLP + fmt.Fprintf(b2, "func (obj *%s) EncodeRLP(w io.Writer) error {\n", typename) + fmt.Fprint(b2, " var b [32]byte\n") + fmt.Fprint(b2, " if err := rlp.EncodeStructSizePrefix(obj.EncodingSize(), w, b[:]); err != nil {\n") + fmt.Fprint(b2, " return err\n") + fmt.Fprint(b2, " }\n") + + // 3. start DecodeRLP + fmt.Fprintf(b3, "func (obj *%s) DecodeRLP(s *rlp.Stream) error {\n", typename) + fmt.Fprint(b3, " _, err := s.List()\n") + fmt.Fprint(b3, " if err != nil {\n") + fmt.Fprint(b3, " return err\n") + fmt.Fprint(b3, " }\n") + + // 4. add encoding/decoding logic + if err := addEncodeLogic(b1, b2, b3, typ); err != nil { + return err + } + + // 5. end EncodingSize method + fmt.Fprintf(b1, " return\n}\n\n") + + // 6. end EcnodeRLP + fmt.Fprintf(b2, " return nil\n}\n\n") + + // 7. end DecodeRLP + fmt.Fprintf(b3, " if err = s.ListEnd(); err != nil {\n") + fmt.Fprintf(b3, " return fmt.Errorf(\"error closing %s, err: %%w\", err)\n", typename) + fmt.Fprintf(b3, " }\n") + fmt.Fprintf(b3, " return nil\n}\n") + + return nil +} + +func findType(scope *types.Scope, typename string) (*types.Named, error) { + // fmt.Println("TYPENAME: ", typename) + // names := scope.Names() + // for _, s := range names { + // fmt.Println("obj: ", s) + // } + obj := scope.Lookup(typename) + if obj == nil { + return nil, fmt.Errorf("no such identifier: %s", typename) + } + typ, ok := obj.(*types.TypeName) + if !ok { + return nil, errors.New("not a type") + } + if named, ok := typ.Type().(*types.Named); ok { + return named, nil + } + return nil, errors.New("not a named type") +} + +func addEncodeLogic(b1, b2, b3 *bytes.Buffer, named *types.Named) error { + + if _struct, ok := named.Underlying().(*types.Struct); ok { + for i := 0; i < _struct.NumFields(); i++ { + + strTyp := matchTypeToString(_struct.Field(i).Type(), "") + // fmt.Println("-+-", strTyp) + + matchStrTypeToFunc(strTyp)(b1, b2, b3, _struct.Field(i).Type(), _struct.Field(i).Name()) + } + } + // else { + + // // TODO(racytech): see handleType + // } + + return nil +} + +func handleType(t types.Type, caller types.Type, depth int, ptr bool) { + switch e := t.(type) { + case *types.Pointer: + // check if double pointer, fail if depth > 0 and ptr == true + + // if t is Pointer type pass to the next level + handleType(e.Elem(), e, depth+1, true) + case *types.Named: + // if t is user named type, + // check if big.Int or uint256.Int -> check if pointer -> encode/decode accordingly -> return + // check if rlp generated for this type -> if yes remove the file + // else pass to the next level + handleType(e.Underlying(), e, depth+1, false) + // if underlying is a struct + // check if rlp generated for this type -> if yes call RLP encode/decode methods on it, return + case *types.Basic: + // check if caller Named (e.g type MyInt int) -> TODO + // check if caller Slice or Array + // if t is byte slice or byte array -> encode -> return + // check if caller Pointer -> encode -> return + // + // or if caller is nil -> call rlp encoding function on basic types, bool, uint, int etc. + // return + case *types.Slice: + // check if it's simple byteslice + // if yes call RLP encode/decode methods on it, return + // check if it's slice of named types. e.g []common.Hash -> [][32]byte, or type MyStruct struct {a, b, c} + // ^TODO think about this case^ + // + handleType(e.Elem(), e, depth+1, false) + case *types.Array: + // check if it's simple bytearray + // if yes call RLP encode/decode methods on it, return + // check if it's slice of named types. e.g [10]common.Hash -> [10][32]byte, or type MyStruct struct {a, b, c} + // ^TODO think about this case^ + // + handleType(e.Elem(), e, depth+1, false) + case *types.Struct: + // check if nested struct + // if yes check if rlp previously generated for this type -> if yes remove the file + // try generating rlp for this structure, e.g as follows: + // process(t) -> if successful + // add encoding/decoding logic of this struct to the buffers + // return + + // else -> top level call + for i := 0; i < e.NumFields(); i++ { + // this should panic and fail generating everything in case of error + handleType(e.Field(i).Type(), e, depth+1, false) + } + default: + panic("unhandled") + } +} diff --git a/cmd/rlpgen/matcher.go b/cmd/rlpgen/matcher.go new file mode 100644 index 00000000000..1e3159791f3 --- /dev/null +++ b/cmd/rlpgen/matcher.go @@ -0,0 +1,89 @@ +// Copyright 2025 The Erigon Authors +// This file is part of Erigon. +// +// Erigon is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Erigon is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Erigon. If not, see . + +package main + +import ( + "bytes" + "go/types" +) + +// handle should write encoding size of type as well as encoding and decoding logic for the type +type handle func(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) + +// func foofunc(b1, b2, b3 *bytes.Buffer, fieldType types.Type, fieldName string) {} + +// all possible types that this generator can handle for the time being. +// to add a new type add a string representation of type here and write the handle function for it in the `handlers.go` +var handlers = map[string]handle{ + "uint64": uintHandle, + "*uint64": uintPtrHandle, + "big.Int": bigIntHandle, + "*big.Int": bigIntPtrHandle, + "uint256.Int": uint256Handle, + "*uint256.Int": uint256PtrHandle, + "types.BlockNonce": blockNonceHandle, + "*types.BlockNonce": blockNoncePtrHandle, + "common.Address": addressHandle, + "*common.Address": addressPtrHandle, + "common.Hash": hashHandle, + "*common.Hash": hashPtrHandle, + "types.Bloom": bloomHandle, + "*types.Bloom": bloomPtrHandle, + "[]byte": byteSliceHandle, + "*[]byte": byteSlicePtrHandle, + "[][]byte": byteSliceSliceHandle, + "[]types.BlockNonce": blockNonceSliceHandle, + "[]*types.BlockNonce": blockNoncePtrSliceHandle, + "[]common.Address": addressSliceHandle, + "[]*common.Address": addressPtrSliceHandle, + "[]common.Hash": hashSliceHandle, + "[]*common.Hash": hashPtrSliceHandle, + "[n]byte": byteArrayHandle, + "*[n]byte": byteArrayPtrHandle, +} + +// recursive function, constructs string representation of a type. array represented as [n] +func matchTypeToString(fieldType types.Type, in string) string { + if named, ok := fieldType.(*types.Named); ok { + return in + named.Obj().Pkg().Name() + "." + named.Obj().Name() + } else if ptr, ok := fieldType.(*types.Pointer); ok { + return matchTypeToString(ptr.Elem(), in+"*") + } else if slc, ok := fieldType.(*types.Slice); ok { + return matchTypeToString(slc.Elem(), in+"[]") + } else if arr, ok := fieldType.(*types.Array); ok { + return matchTypeToString(arr.Elem(), in+"[n]") + } else if basic, ok := fieldType.(*types.Basic); ok { + return in + basic.Name() + } else { + panic("_matchTypeToString: unhandled match") + } +} + +// matches string representation of a type to a corresponding function +func matchStrTypeToFunc(strType string) handle { + switch strType { + case "int16", "int32", "int", "int64", "uint16", "uint32", "uint", "uint64": + return handlers["uint64"] + case "*int16", "*int32", "*int", "*int64", "*uint16", "*uint32", "*uint", "*uint64": + return handlers["*uint64"] + default: + if fn, ok := handlers[strType]; ok { + return fn + } + panic("no handle added for type: " + strType) + } +} diff --git a/cmd/rlpgen/testing/encdec_test.go b/cmd/rlpgen/testing/encdec_test.go new file mode 100644 index 00000000000..9f43e9ab69c --- /dev/null +++ b/cmd/rlpgen/testing/encdec_test.go @@ -0,0 +1,251 @@ +package testing + +import ( + "bytes" + "math/big" + "math/rand" + "reflect" + "testing" + "time" + + libcommon "github.com/erigontech/erigon-lib/common" + "github.com/erigontech/erigon-lib/rlp" + "github.com/erigontech/erigon/core/types" + "github.com/holiman/uint256" +) + +type TRand struct { + rnd *rand.Rand +} + +func NewTRand() *TRand { + seed := time.Now().UnixNano() + src := rand.NewSource(seed) + return &TRand{rnd: rand.New(src)} +} + +func (tr *TRand) RandIntInRange(_min, _max int) int { + return (tr.rnd.Intn(_max-_min) + _min) +} + +func (tr *TRand) RandUint64() *uint64 { + a := tr.rnd.Uint64() + return &a +} + +func (tr *TRand) RandUint256() *uint256.Int { + a := new(uint256.Int).SetBytes(tr.RandBytes(tr.RandIntInRange(1, 32))) + return a +} + +func (tr *TRand) RandBig() *big.Int { + return big.NewInt(int64(tr.rnd.Int())) +} + +func (tr *TRand) RandBytes(size int) []byte { + arr := make([]byte, size) + for i := 0; i < size; i++ { + arr[i] = byte(tr.rnd.Intn(256)) + } + return arr +} + +func (tr *TRand) RandAddress() libcommon.Address { + return libcommon.Address(tr.RandBytes(20)) +} + +func (tr *TRand) RandHash() libcommon.Hash { + return libcommon.Hash(tr.RandBytes(32)) +} + +func (tr *TRand) RandBloom() types.Bloom { + return types.Bloom(tr.RandBytes(types.BloomByteLength)) +} + +func check(t *testing.T, f string, want, got interface{}) { + if !reflect.DeepEqual(want, got) { + t.Errorf("%s mismatch: want %v, got %v", f, want, got) + } +} + +func compareTestingStructs(t *testing.T, a, b *TestingStruct) { + check(t, "obj.a", a.a, b.a) + check(t, "obj.aa", a.aa, b.aa) + check(t, "obj.b", a.b, b.b) + check(t, "obj.bb", a.bb, b.bb) + check(t, "obj.c", a.c, b.c) + check(t, "obj.cc", a.cc, b.cc) + check(t, "obj.d", a.d, b.d) + check(t, "obj.dd", a.dd, b.dd) + check(t, "obj.e", a.e, b.e) + check(t, "obj.ee", a.ee, b.ee) + check(t, "obj.f", a.f, b.f) + check(t, "obj.ff", a.ff, b.ff) + check(t, "obj.g", a.g, b.g) + check(t, "obj.gg", a.gg, b.gg) + check(t, "obj.h", a.h, b.h) + check(t, "obj.hh", a.hh, b.hh) + check(t, "obj.i", a.i, b.i) + + if len(a.j) != len(b.j) { + t.Errorf("len mismatch: want %v, got %v", len(a.j), len(b.j)) + } + for i := 0; i < len(a.j); i++ { + check(t, "obj.j each", a.j[i], b.j[i]) + } + check(t, "obj.j", a.j, b.j) + + if len(a.jj) != len(b.jj) { + t.Errorf("len mismatch: want %v, got %v", len(a.jj), len(b.jj)) + } + for i := 0; i < len(a.jj); i++ { + check(t, "obj.j each", a.jj[i], b.jj[i]) + } + + check(t, "obj.jj", a.jj, b.jj) + check(t, "obj.k", a.k, b.k) + check(t, "obj.kk", a.kk, b.kk) + check(t, "obj.l", a.l, b.l) + check(t, "obj.ll", a.ll, b.ll) + check(t, "obj.n", a.m, b.m) + check(t, "obj.n", a.mm, b.mm) +} + +func randTestingStruct(tr *TRand) *TestingStruct { + // _int := tr.RandIntInRange(0, 1<<32) + _byteSlice := tr.RandBytes(tr.RandIntInRange(0, 128)) + + l := tr.RandIntInRange(0, 8) + _byteSliceSlice := make([][]byte, l) + for i := 0; i < l; i++ { + _byteSliceSlice[i] = tr.RandBytes(tr.RandIntInRange(0, 128)) + } + + l = tr.RandIntInRange(0, 8) + _byteSliceSlicePtr := make([]*[]byte, l) + for i := 0; i < l; i++ { + arr := tr.RandBytes(tr.RandIntInRange(0, 128)) + _byteSliceSlicePtr[i] = &arr + } + + l = tr.RandIntInRange(0, 8) + _nonceSlice := make([]types.BlockNonce, l) + for i := 0; i < l; i++ { + _nonceSlice[i] = types.BlockNonce(tr.RandBytes(8)) + } + + l = tr.RandIntInRange(0, 8) + _nonceSlicePtr := make([]*types.BlockNonce, l) + for i := 0; i < l; i++ { + nonce := types.BlockNonce(tr.RandBytes(8)) + if i%2 == 0 { + _nonceSlicePtr[i] = &nonce + } else { + _nonceSlicePtr[i] = nil + } + + } + + l = tr.RandIntInRange(0, 8) + _addrSlice := make([]libcommon.Address, l) + for i := 0; i < l; i++ { + _addrSlice[i] = tr.RandAddress() + } + + l = tr.RandIntInRange(0, 8) + _addrSlicePtr := make([]*libcommon.Address, l) + for i := 0; i < l; i++ { + addr := tr.RandAddress() + _addrSlicePtr[i] = &addr + } + + l = tr.RandIntInRange(0, 8) + _hashSlice := make([]libcommon.Hash, l) + for i := 0; i < l; i++ { + _hashSlice[i] = tr.RandHash() + } + + l = tr.RandIntInRange(0, 8) + _hashSlicePtr := make([]*libcommon.Hash, l) + for i := 0; i < l; i++ { + hash := tr.RandHash() + _hashSlicePtr[i] = &hash + } + + l = tr.RandIntInRange(0, 8) + _bloomSlice := make([]types.Bloom, l) + for i := 0; i < l; i++ { + _bloomSlice[i] = tr.RandBloom() + } + + l = tr.RandIntInRange(0, 8) + _bloomSlicePtr := make([]*types.Bloom, l) + for i := 0; i < l; i++ { + bloom := tr.RandBloom() + _bloomSlicePtr[i] = &bloom + } + + enc := TestingStruct{ + a: *tr.RandUint64(), + aa: tr.RandUint64(), + b: *tr.RandBig(), + bb: tr.RandBig(), + c: *tr.RandUint256(), + cc: tr.RandUint256(), + d: types.BlockNonce(tr.RandBytes(8)), + dd: (*types.BlockNonce)(tr.RandBytes(8)), + e: tr.RandAddress(), + ee: (*libcommon.Address)(tr.RandBytes(20)), + f: tr.RandHash(), + ff: (*libcommon.Hash)(tr.RandBytes(32)), + g: tr.RandBloom(), + gg: (*types.Bloom)(tr.RandBytes(256)), + h: tr.RandBytes(tr.RandIntInRange(0, 128)), + hh: &_byteSlice, + i: _byteSliceSlice, + j: _nonceSlice, + jj: _nonceSlicePtr, + k: _addrSlice, + kk: _addrSlicePtr, + l: _hashSlice, + ll: _hashSlicePtr, + m: [10]byte(tr.RandBytes(10)), + mm: (*[245]byte)(tr.RandBytes(245)), + } + return &enc +} + +const RUNS = 1 + +func TestTestingStruct(t *testing.T) { + tr := NewTRand() + var buf bytes.Buffer + for i := 0; i < RUNS; i++ { + + enc := randTestingStruct(tr) + buf.Reset() + + if err := enc.EncodeRLP(&buf); err != nil { + t.Errorf("error: TestingStruct.EncodeRLP(): %v", err) + } + + s := rlp.NewStream(bytes.NewReader(buf.Bytes()), 0) + dec := &TestingStruct{} + if err := dec.DecodeRLP(s); err != nil { + t.Errorf("error: TestingStruct.DecodeRLP(): %v", err) + panic(err) + } + compareTestingStructs(t, enc, dec) + } +} + +func BenchmarkTestingStructRLP(b *testing.B) { + tr := NewTRand() + header := randTestingStruct(tr) + var buf bytes.Buffer + b.ResetTimer() + for i := 0; i < b.N; i++ { + buf.Reset() + header.EncodeRLP(&buf) + } +} diff --git a/cmd/rlpgen/testing/gen_testingstruct_rlp.go b/cmd/rlpgen/testing/gen_testingstruct_rlp.go new file mode 100644 index 00000000000..616f2ed0aef --- /dev/null +++ b/cmd/rlpgen/testing/gen_testingstruct_rlp.go @@ -0,0 +1,573 @@ +// Code generated by rlpgen. DO NOT EDIT. + +package testing + +import ( + "github.com/erigontech/erigon/core/types" + "github.com/erigontech/erigon-lib/common" + "fmt" + "io" + "github.com/erigontech/erigon-lib/rlp" + "math/big" + "github.com/holiman/uint256" +) + +func (obj *TestingStruct) EncodingSize() (size int) { + size += rlp.IntLenExcludingHead(uint64(obj.a)) + 1 + if obj.aa != nil { + size += rlp.IntLenExcludingHead(uint64(*obj.aa)) + 1 + } + size += rlp.BigIntLenExcludingHead(&obj.b) + 1 + size += 1 + if obj.bb != nil { + size += rlp.BigIntLenExcludingHead(obj.bb) + } + size += rlp.Uint256LenExcludingHead(&obj.c) + 1 + size += rlp.Uint256LenExcludingHead(obj.cc) + 1 + size += 8 + 1 + size += 1 + if obj.dd != nil { + size += 8 + } + size += 20 + 1 + size += 1 + if obj.ee != nil { + size += 20 + } + size += 32 + 1 + size += 1 + if obj.ff != nil { + size += 32 + } + size += 259 + size += 1 + if obj.gg != nil { + size += 258 + } + size += rlp.StringLen(obj.h) + if obj.hh != nil { + size += rlp.StringLen(*obj.hh) + } else { + size += 1 + } + size += rlp.ByteSliceSliceSize(obj.i) + gidx := 0 + gidx = (8 + 1) * len(obj.j) + size += rlp.ListPrefixLen(gidx) + gidx + gidx = 0 + for i := 0; i < len(obj.jj); i++ { + if obj.jj[i] != nil { + gidx += 8 + 1 + } else { + gidx += 1 + } + } + size += rlp.ListPrefixLen(gidx) + gidx + gidx = 0 + gidx = (20 + 1) * len(obj.k) + size += rlp.ListPrefixLen(gidx) + gidx + gidx = 0 + for i := 0; i < len(obj.kk); i++ { + if obj.kk[i] != nil { + gidx += 20 + 1 + } else { + gidx += 1 + } + } + size += rlp.ListPrefixLen(gidx) + gidx + gidx = 0 + gidx = (32 + 1) * len(obj.l) + size += rlp.ListPrefixLen(gidx) + gidx + gidx = 0 + for i := 0; i < len(obj.ll); i++ { + if obj.ll[i] != nil { + gidx += 32 + 1 + } else { + gidx += 1 + } + } + size += rlp.ListPrefixLen(gidx) + gidx + size += 10 + rlp.ListPrefixLen(10) + if obj.mm != nil { + size += 245 + } + size += rlp.ListPrefixLen(245) + return +} + +func (obj *TestingStruct) EncodeRLP(w io.Writer) error { + var b [32]byte + if err := rlp.EncodeStructSizePrefix(obj.EncodingSize(), w, b[:]); err != nil { + return err + } + if err := rlp.EncodeInt(uint64(obj.a), w, b[:]); err != nil { + return err + } + if obj.aa != nil { + if err := rlp.EncodeInt(uint64(*obj.aa), w, b[:]); err != nil { + return err + } + } + if err := rlp.EncodeBigInt(&obj.b, w, b[:]); err != nil { + return err + } + if err := rlp.EncodeBigInt(obj.bb, w, b[:]); err != nil { + return err + } + if err := rlp.EncodeUint256(&obj.c, w, b[:]); err != nil { + return err + } + if err := rlp.EncodeUint256(obj.cc, w, b[:]); err != nil { + return err + } + b[0] = 128 + 8 + if _, err := w.Write(b[:1]); err != nil { + return err + } + if _, err := w.Write(obj.d[:]); err != nil { + return err + } + if obj.dd != nil { + b[0] = 128 + 8 + } else { + b[0] = 128 + } + if _, err := w.Write(b[:1]); err != nil { + return err + } + if obj.dd != nil { + if _, err := w.Write(obj.dd[:]); err != nil { + return err + } + } + b[0] = 128 + 20 + if _, err := w.Write(b[:1]); err != nil { + return err + } + if _, err := w.Write(obj.e[:]); err != nil { + return err + } + if obj.ee != nil { + b[0] = 128 + 20 + } else { + b[0] = 128 + } + if _, err := w.Write(b[:1]); err != nil { + return err + } + if obj.ee != nil { + if _, err := w.Write(obj.ee[:]); err != nil { + return err + } + } + b[0] = 128 + 32 + if _, err := w.Write(b[:1]); err != nil { + return err + } + if _, err := w.Write(obj.f[:]); err != nil { + return err + } + if obj.ff != nil { + b[0] = 128 + 32 + } else { + b[0] = 128 + } + if _, err := w.Write(b[:1]); err != nil { + return err + } + if obj.ff != nil { + if _, err := w.Write(obj.ff[:]); err != nil { + return err + } + } + b[0] = 183 + 2 + b[1] = 1 + b[2] = 0 + if _, err := w.Write(b[:3]); err != nil { + return err + } + if _, err := w.Write(obj.g[:]); err != nil { + return err + } + if obj.gg != nil { + b[0] = 183 + 2 + b[1] = 1 + b[2] = 0 + } else { + b[0] = 128 + } + if obj.gg != nil { + if _, err := w.Write(b[:3]); err != nil { + return err + } + if _, err := w.Write(obj.gg[:]); err != nil { + return err + } + } else { + if _, err := w.Write(b[:1]); err != nil { + return err + } + } + if err := rlp.EncodeString(obj.h, w, b[:]); err != nil { + return err + } + if obj.hh != nil { + if err := rlp.EncodeString(*obj.hh, w, b[:]); err != nil { + return err + } + } else { + if err := rlp.EncodeString([]byte{}, w, b[:]); err != nil { + return err + } + } + if err := rlp.EncodeByteSliceSlice(obj.i, w, b[:]); err != nil { + return err + } + gidx := 0 + gidx = (8 + 1) * len(obj.j) + if err := rlp.EncodeStructSizePrefix(gidx, w, b[:]); err != nil { + return err + } + for i := 0; i < len(obj.j); i++ { + if err := rlp.EncodeString(obj.j[i][:], w, b[:]); err != nil { + return err + } + } + gidx = 0 + for i := 0; i < len(obj.jj); i++ { + if obj.jj[i] != nil { + gidx += 8 + 1 + } else { + gidx += 1 + } + } + if err := rlp.EncodeStructSizePrefix(gidx, w, b[:]); err != nil { + return err + } + for i := 0; i < len(obj.jj); i++ { + if obj.jj[i] != nil { + if err := rlp.EncodeString(obj.jj[i][:], w, b[:]); err != nil { + return err + } + } else { + if err := rlp.EncodeString([]byte{}, w, b[:]); err != nil { + return err + } + } + } + gidx = 0 + gidx = (20 + 1) * len(obj.k) + if err := rlp.EncodeStructSizePrefix(gidx, w, b[:]); err != nil { + return err + } + for i := 0; i < len(obj.k); i++ { + if err := rlp.EncodeString(obj.k[i][:], w, b[:]); err != nil { + return err + } + } + gidx = 0 + for i := 0; i < len(obj.kk); i++ { + if obj.kk[i] != nil { + gidx += 20 + 1 + } else { + gidx += 1 + } + } + if err := rlp.EncodeStructSizePrefix(gidx, w, b[:]); err != nil { + return err + } + for i := 0; i < len(obj.kk); i++ { + if obj.kk[i] != nil { + if err := rlp.EncodeString(obj.kk[i][:], w, b[:]); err != nil { + return err + } + } else { + if err := rlp.EncodeString([]byte{}, w, b[:]); err != nil { + return err + } + } + } + gidx = 0 + gidx = (32 + 1) * len(obj.l) + if err := rlp.EncodeStructSizePrefix(gidx, w, b[:]); err != nil { + return err + } + for i := 0; i < len(obj.l); i++ { + if err := rlp.EncodeString(obj.l[i][:], w, b[:]); err != nil { + return err + } + } + gidx = 0 + for i := 0; i < len(obj.ll); i++ { + if obj.ll[i] != nil { + gidx += 32 + 1 + } else { + gidx += 1 + } + } + if err := rlp.EncodeStructSizePrefix(gidx, w, b[:]); err != nil { + return err + } + for i := 0; i < len(obj.ll); i++ { + if obj.ll[i] != nil { + if err := rlp.EncodeString(obj.ll[i][:], w, b[:]); err != nil { + return err + } + } else { + if err := rlp.EncodeString([]byte{}, w, b[:]); err != nil { + return err + } + } + } + if err := rlp.EncodeString(obj.m[:], w, b[:]); err != nil { + return err + } + if obj.mm != nil { + if err := rlp.EncodeString(obj.mm[:], w, b[:]); err != nil { + return err + } + } else { + if err := rlp.EncodeString([]byte{}, w, b[:]); err != nil { + return err + } + } + return nil +} + +func (obj *TestingStruct) DecodeRLP(s *rlp.Stream) error { + _, err := s.List() + if err != nil { + return err + } + if obj.a, err = s.Uint(); err != nil { + return fmt.Errorf("error decoding field a, err: %w", err) + } + if n, err := s.Uint(); err != nil { + return fmt.Errorf("error decoding field aa, err: %w", err) + } else { + i := n + obj.aa = &i + } + var b []byte + if b, err = s.Uint256Bytes(); err != nil { + return fmt.Errorf("error decoding field b, err: %w", err) + } + obj.b = *(new(big.Int).SetBytes(b)) + if b, err = s.Uint256Bytes(); err != nil { + return fmt.Errorf("error decoding field bb, err: %w", err) + } + obj.bb = new(big.Int).SetBytes(b) + if b, err = s.Uint256Bytes(); err != nil { + return fmt.Errorf("error decoding field c, err: %w", err) + } + obj.c = *(new(uint256.Int).SetBytes(b)) + if b, err = s.Uint256Bytes(); err != nil { + return fmt.Errorf("error decoding field cc, err: %w", err) + } + obj.cc = new(uint256.Int).SetBytes(b) + if b, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field d, err: %w", err) + } + if len(b) > 0 && len(b) != 8 { + return fmt.Errorf("error decoded length mismatch, expected: 8, got: %d", len(b)) + } + copy(obj.d[:], b) + if b, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field dd, err: %w", err) + } + if len(b) > 0 && len(b) != 8 { + return fmt.Errorf("error decoded length mismatch, expected: 8, got: %d", len(b)) + } + obj.dd = &types.BlockNonce{} + copy((*obj.dd)[:], b) + if b, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field e, err: %w", err) + } + if len(b) > 0 && len(b) != 20 { + return fmt.Errorf("error decoded length mismatch, expected: 20, got: %d", len(b)) + } + copy(obj.e[:], b) + if b, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field ee, err: %w", err) + } + if len(b) > 0 && len(b) != 20 { + return fmt.Errorf("error decoded length mismatch, expected: 20, got: %d", len(b)) + } + obj.ee = &common.Address{} + copy((*obj.ee)[:], b) + if b, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field f, err: %w", err) + } + if len(b) > 0 && len(b) != 32 { + return fmt.Errorf("error decoded length mismatch, expected: 32, got: %d", len(b)) + } + copy(obj.f[:], b) + if b, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field ff, err: %w", err) + } + if len(b) > 0 && len(b) != 32 { + return fmt.Errorf("error decoded length mismatch, expected: 32, got: %d", len(b)) + } + obj.ff = &common.Hash{} + copy((*obj.ff)[:], b) + if b, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field g, err: %w", err) + } + if len(b) > 0 && len(b) != 256 { + return fmt.Errorf("error decoded length mismatch, expected: 256, got: %d", len(b)) + } + copy(obj.g[:], b) + if b, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field gg, err: %w", err) + } + if len(b) > 0 && len(b) != 256 { + return fmt.Errorf("error decoded length mismatch, expected: 256, got: %d", len(b)) + } + obj.gg = &types.Bloom{} + copy((*obj.gg)[:], b) + if obj.h, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field h, err: %w", err) + } + if b, err = s.Bytes(); err != nil { + return fmt.Errorf("error decoding field hh, err: %w", err) + } + obj.hh = &[]byte{} + *obj.hh = append(*obj.hh, b...) + _, err = s.List() + if err != nil { + return fmt.Errorf("error decoding field i - expected list start, err: %w", err) + } + obj.i = [][]byte{} + for b, err = s.Bytes(); err == nil; b, err = s.Bytes() { + obj.i = append(obj.i, b) + } + if err = s.ListEnd(); err != nil { + return fmt.Errorf("error decoding field i - fail to close list, err: %w", err) + } + _, err = s.List() + if err != nil { + return fmt.Errorf("error decoding field j - expected list start, err: %w", err) + } + obj.j = []types.BlockNonce{} + for b, err = s.Bytes(); err == nil; b, err = s.Bytes() { + if len(b) > 0 && len(b) != 8 { + return fmt.Errorf("error decoded length mismatch, expected: 8, got: %d", len(b)) + } + var s types.BlockNonce + copy(s[:], b) + obj.j = append(obj.j, s) + } + if err = s.ListEnd(); err != nil { + return fmt.Errorf("error decoding field j - fail to close list, err: %w", err) + } + _, err = s.List() + if err != nil { + return fmt.Errorf("error decoding field jj - expected list start, err: %w", err) + } + obj.jj = []*types.BlockNonce{} + for b, err = s.Bytes(); err == nil; b, err = s.Bytes() { + var s types.BlockNonce + if len(b) > 0 && len(b) != 8 { + return fmt.Errorf("error decoded length mismatch, expected: 8, got: %d", len(b)) + } else if len(b) == 8 { + copy(s[:], b) + obj.jj = append(obj.jj, &s) + } else if len(b) == 0{ + obj.jj = append(obj.jj, nil) + } else { + return fmt.Errorf("error decoded length mismatch, expected: 8, got: %d", len(b)) + } + } + if err = s.ListEnd(); err != nil { + return fmt.Errorf("error decoding field jj - fail to close list, err: %w", err) + } + _, err = s.List() + if err != nil { + return fmt.Errorf("error decoding field k - expected list start, err: %w", err) + } + obj.k = []common.Address{} + for b, err = s.Bytes(); err == nil; b, err = s.Bytes() { + if len(b) > 0 && len(b) != 20 { + return fmt.Errorf("error decoded length mismatch, expected: 20, got: %d", len(b)) + } + var s common.Address + copy(s[:], b) + obj.k = append(obj.k, s) + } + if err = s.ListEnd(); err != nil { + return fmt.Errorf("error decoding field k - fail to close list, err: %w", err) + } + _, err = s.List() + if err != nil { + return fmt.Errorf("error decoding field kk - expected list start, err: %w", err) + } + obj.kk = []*common.Address{} + for b, err = s.Bytes(); err == nil; b, err = s.Bytes() { + var s common.Address + if len(b) > 0 && len(b) != 20 { + return fmt.Errorf("error decoded length mismatch, expected: 20, got: %d", len(b)) + } else if len(b) == 20 { + copy(s[:], b) + obj.kk = append(obj.kk, &s) + } else if len(b) == 0{ + obj.kk = append(obj.kk, nil) + } else { + return fmt.Errorf("error decoded length mismatch, expected: 20, got: %d", len(b)) + } + } + if err = s.ListEnd(); err != nil { + return fmt.Errorf("error decoding field kk - fail to close list, err: %w", err) + } + _, err = s.List() + if err != nil { + return fmt.Errorf("error decoding field l - expected list start, err: %w", err) + } + obj.l = []common.Hash{} + for b, err = s.Bytes(); err == nil; b, err = s.Bytes() { + if len(b) > 0 && len(b) != 32 { + return fmt.Errorf("error decoded length mismatch, expected: 32, got: %d", len(b)) + } + var s common.Hash + copy(s[:], b) + obj.l = append(obj.l, s) + } + if err = s.ListEnd(); err != nil { + return fmt.Errorf("error decoding field l - fail to close list, err: %w", err) + } + _, err = s.List() + if err != nil { + return fmt.Errorf("error decoding field ll - expected list start, err: %w", err) + } + obj.ll = []*common.Hash{} + for b, err = s.Bytes(); err == nil; b, err = s.Bytes() { + var s common.Hash + if len(b) > 0 && len(b) != 32 { + return fmt.Errorf("error decoded length mismatch, expected: 32, got: %d", len(b)) + } else if len(b) == 32 { + copy(s[:], b) + obj.ll = append(obj.ll, &s) + } else if len(b) == 0{ + obj.ll = append(obj.ll, nil) + } else { + return fmt.Errorf("error decoded length mismatch, expected: 32, got: %d", len(b)) + } + } + if err = s.ListEnd(); err != nil { + return fmt.Errorf("error decoding field ll - fail to close list, err: %w", err) + } + if b, err = s.Bytes(); err != nil { + return err + } + copy(obj.m[:], b) + if b, err = s.Bytes(); err != nil { + return err + } + if len(b) > 0 { + obj.mm = &[245]byte{} + copy((*obj.mm)[:], b) + } + if err = s.ListEnd(); err != nil { + return fmt.Errorf("error closing TestingStruct, err: %w", err) + } + return nil +} diff --git a/cmd/rlpgen/testing/testing_struct.go b/cmd/rlpgen/testing/testing_struct.go new file mode 100644 index 00000000000..62f16ae7e40 --- /dev/null +++ b/cmd/rlpgen/testing/testing_struct.go @@ -0,0 +1,37 @@ +package testing + +import ( + "math/big" + + "github.com/erigontech/erigon-lib/common" + "github.com/erigontech/erigon/core/types" + "github.com/holiman/uint256" +) + +type TestingStruct struct { + a uint64 + aa *uint64 + b big.Int + bb *big.Int + c uint256.Int + cc *uint256.Int + d types.BlockNonce + dd *types.BlockNonce + e common.Address + ee *common.Address + f common.Hash + ff *common.Hash + g types.Bloom + gg *types.Bloom + h []byte + hh *[]byte + i [][]byte + j []types.BlockNonce + jj []*types.BlockNonce + k []common.Address + kk []*common.Address + l []common.Hash + ll []*common.Hash + m [10]byte + mm *[245]byte +} diff --git a/erigon-lib/rlp/encode.go b/erigon-lib/rlp/encode.go index 883124734e7..10acdf224ee 100644 --- a/erigon-lib/rlp/encode.go +++ b/erigon-lib/rlp/encode.go @@ -725,3 +725,29 @@ func EncodeStructSizePrefix(size int, w io.Writer, buffer []byte) error { } return nil } + +func ByteSliceSliceSize(bb [][]byte) int { + size := 0 + for i := 0; i < len(bb); i++ { + size += StringLen(bb[i]) + } + return size + ListPrefixLen(size) +} + +func EncodeByteSliceSlice(bb [][]byte, w io.Writer, b []byte) error { + totalSize := 0 + for i := 0; i < len(bb); i++ { + totalSize += StringLen(bb[i]) + } + + if err := EncodeStructSizePrefix(totalSize, w, b); err != nil { + return err + } + + for i := 0; i < len(bb); i++ { + if err := EncodeString(bb[i], w, b); err != nil { + return err + } + } + return nil +} diff --git a/go.mod b/go.mod index 1039631cb15..dbbdcbe43b8 100644 --- a/go.mod +++ b/go.mod @@ -280,9 +280,9 @@ require ( go.uber.org/dig v1.18.0 // indirect go.uber.org/fx v1.23.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/mod v0.21.0 // indirect + golang.org/x/mod v0.22.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.26.0 // indirect + golang.org/x/tools v0.29.0 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect lukechampine.com/blake3 v1.3.0 // indirect modernc.org/libc v1.55.3 // indirect diff --git a/go.sum b/go.sum index 64d09dadba1..5e84b3398d8 100644 --- a/go.sum +++ b/go.sum @@ -1011,8 +1011,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1247,8 +1247,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= +golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=