diff --git a/cmd/rlpgen/handlers.go b/cmd/rlpgen/handlers.go index 1718237a262..b2ddf9b5351 100644 --- a/cmd/rlpgen/handlers.go +++ b/cmd/rlpgen/handlers.go @@ -10,6 +10,7 @@ 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") @@ -17,6 +18,7 @@ func addDecodeBuf(b *bytes.Buffer) { } } +// 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") @@ -24,12 +26,14 @@ func startListDecode(b *bytes.Buffer, fieldName string) { 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") @@ -39,6 +43,7 @@ func addIntSize(b *bytes.Buffer) { } } +// add reusable int for encoding usage func addIntEncode(b *bytes.Buffer) { if !intEncodeAdded { fmt.Fprint(b, " gidx := 0\n") diff --git a/cmd/rlpgen/main.go b/cmd/rlpgen/main.go index 3ed3961190a..f05ea04208e 100644 --- a/cmd/rlpgen/main.go +++ b/cmd/rlpgen/main.go @@ -1,3 +1,7 @@ +// 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 ( @@ -202,14 +206,65 @@ func addEncodeLogic(b1, b2, b3 *bytes.Buffer, named *types.Named) error { matchStrTypeToFunc(strTyp)(b1, b2, b3, _struct.Field(i).Type(), _struct.Field(i).Name()) } - } else { // user named types that are not structs, could be: - // 1. type aliases - // - type aliases for basic types, e.g type MyInt int - // - type aliases for user named types, e.g type MyHash common.Hash (could be struct as well!) - // 2. slice types - // - slice of basice types, e.g type MyInts []int - // - slice of user named types, e.g type ReceiptsForStorage []*ReceiptForStorage + } 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 index 4cfefef1a9f..926f9395750 100644 --- a/cmd/rlpgen/matcher.go +++ b/cmd/rlpgen/matcher.go @@ -6,10 +6,13 @@ import ( "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, @@ -39,6 +42,7 @@ var handlers = map[string]handle{ "*[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() @@ -55,6 +59,7 @@ func matchTypeToString(fieldType types.Type, in string) string { } } +// 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": diff --git a/cmd/rlpgen/testing/encdec_test.go b/cmd/rlpgen/testing/encdec_test.go new file mode 100644 index 00000000000..aaa75afc2d6 --- /dev/null +++ b/cmd/rlpgen/testing/encdec_test.go @@ -0,0 +1,259 @@ +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.ii) != len(b.ii) { + t.Errorf("len mismatch: want %v, got %v", len(a.ii), len(b.ii)) + } + for i := 0; i < len(a.ii); i++ { + check(t, "obj.ii", *a.ii[i], *b.ii[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, + ii: _byteSliceSlicePtr, + 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 = 10000 + +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..44eb8b4d98d --- /dev/null +++ b/cmd/rlpgen/testing/gen_testingstruct_rlp.go @@ -0,0 +1,590 @@ +// Code generated by rlpgen. DO NOT EDIT. + +package testing + +import ( + "github.com/erigontech/erigon-lib/rlp" + "math/big" + "github.com/holiman/uint256" + "github.com/erigontech/erigon/core/types" + "github.com/erigontech/erigon-lib/common" + "fmt" + "io" +) + +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) + size += rlp.ByteSliceSlicePtrSize(obj.ii) + 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 + } + if err := rlp.EncodeByteSliceSlicePtr(obj.ii, 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 ii - expected list start, err: %w", err) + } + obj.ii = []*[]byte{} + for b, err = s.Bytes(); err == nil; b, err = s.Bytes() { + cpy := make([]byte, len(b)) + copy(cpy, b) + obj.ii = append(obj.ii, &cpy) + } + if err = s.ListEnd(); err != nil { + return fmt.Errorf("error decoding field ii - 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/core/types/rlpgen_struct.go b/cmd/rlpgen/testing/testing_struct.go similarity index 70% rename from core/types/rlpgen_struct.go rename to cmd/rlpgen/testing/testing_struct.go index 063e6844f2f..584e36a1939 100644 --- a/core/types/rlpgen_struct.go +++ b/cmd/rlpgen/testing/testing_struct.go @@ -1,9 +1,10 @@ -package types +package testing import ( "math/big" "github.com/erigontech/erigon-lib/common" + "github.com/erigontech/erigon/core/types" "github.com/holiman/uint256" ) @@ -14,20 +15,20 @@ type TestingStruct struct { bb *big.Int c uint256.Int cc *uint256.Int - d BlockNonce - dd *BlockNonce + d types.BlockNonce + dd *types.BlockNonce e common.Address ee *common.Address f common.Hash ff *common.Hash - g Bloom - gg *Bloom + g types.Bloom + gg *types.Bloom h []byte hh *[]byte i [][]byte ii []*[]byte - j []BlockNonce - jj []*BlockNonce + j []types.BlockNonce + jj []*types.BlockNonce k []common.Address kk []*common.Address l []common.Hash diff --git a/core/types/encdec_test.go b/core/types/encdec_test.go index 6a293bfff6e..01bd2fda5b1 100644 --- a/core/types/encdec_test.go +++ b/core/types/encdec_test.go @@ -544,194 +544,6 @@ func TestWithdrawalEncodeDecodeRLP(t *testing.T) { } } -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.ii) != len(b.ii) { - t.Errorf("len mismatch: want %v, got %v", len(a.ii), len(b.ii)) - } - for i := 0; i < len(a.ii); i++ { - check(t, "obj.ii", *a.ii[i], *b.ii[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([]BlockNonce, l) - for i := 0; i < l; i++ { - _nonceSlice[i] = BlockNonce(tr.RandBytes(8)) - } - - l = tr.RandIntInRange(0, 8) - _nonceSlicePtr := make([]*BlockNonce, l) - for i := 0; i < l; i++ { - nonce := 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([]Bloom, l) - for i := 0; i < l; i++ { - _bloomSlice[i] = tr.RandBloom() - } - - l = tr.RandIntInRange(0, 8) - _bloomSlicePtr := make([]*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: BlockNonce(tr.RandBytes(8)), - dd: (*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: (*Bloom)(tr.RandBytes(256)), - h: tr.RandBytes(tr.RandIntInRange(0, 128)), - hh: &_byteSlice, - i: _byteSliceSlice, - ii: _byteSliceSlicePtr, - 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 -} - -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.EncodeRLP2(&buf) -// } -// } - /* Benchmarks */