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=