Skip to content

Commit 21416bb

Browse files
fjljagdeep sidhu
authored andcommitted
rlp/rlpgen: RLP encoder code generator (ethereum#24251)
This change adds a code generator tool for creating EncodeRLP method implementations. The generated methods will behave identically to the reflect-based encoder, but run faster because there is no reflection overhead. Package rlp now provides the EncoderBuffer type for incremental encoding. This is used by generated code, but the new methods can also be useful for hand-written encoders. There is also experimental support for generating DecodeRLP, and some new methods have been added to the existing Stream type to support this. Creating decoders with rlpgen is not recommended at this time because the generated methods create very poor error reporting. More detail about package rlp changes: * rlp: externalize struct field processing / validation This adds a new package, rlp/internal/rlpstruct, in preparation for the RLP encoder generator. I think the struct field rules are subtle enough to warrant extracting this into their own package, even though it means that a bunch of adapter code is needed for converting to/from rlpstruct.Type. * rlp: add more decoder methods (for rlpgen) This adds new methods on rlp.Stream: - Uint64, Uint32, Uint16, Uint8, BigInt - ReadBytes for decoding into []byte - MoreDataInList - useful for optional list elements * rlp: expose encoder buffer (for rlpgen) This exposes the internal encoder buffer type for use in EncodeRLP implementations. The new EncoderBuffer type is a sort-of 'opaque handle' for a pointer to encBuffer. It is implemented this way to ensure the global encBuffer pool is handled correctly.
1 parent b7e5c23 commit 21416bb

25 files changed

+2693
-466
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ require (
6969
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0
7070
golang.org/x/text v0.3.6
7171
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
72+
golang.org/x/tools v0.1.0
7273
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
7374
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
7475
gopkg.in/urfave/cli.v1 v1.20.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
479479
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
480480
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
481481
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
482+
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
482483
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
483484
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
484485
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -601,6 +602,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
601602
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
602603
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
603604
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
605+
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
604606
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
605607
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
606608
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

rlp/decode.go

Lines changed: 131 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import (
2727
"reflect"
2828
"strings"
2929
"sync"
30+
31+
"github.com/ethereum/go-ethereum/rlp/internal/rlpstruct"
3032
)
3133

3234
//lint:ignore ST1012 EOL is not an error.
@@ -148,7 +150,7 @@ var (
148150
bigInt = reflect.TypeOf(big.Int{})
149151
)
150152

151-
func makeDecoder(typ reflect.Type, tags tags) (dec decoder, err error) {
153+
func makeDecoder(typ reflect.Type, tags rlpstruct.Tags) (dec decoder, err error) {
152154
kind := typ.Kind()
153155
switch {
154156
case typ == rawValueType:
@@ -220,63 +222,28 @@ func decodeBigIntNoPtr(s *Stream, val reflect.Value) error {
220222
}
221223

222224
func decodeBigInt(s *Stream, val reflect.Value) error {
223-
var buffer []byte
224-
kind, size, err := s.Kind()
225-
switch {
226-
case err != nil:
227-
return wrapStreamError(err, val.Type())
228-
case kind == List:
229-
return wrapStreamError(ErrExpectedString, val.Type())
230-
case kind == Byte:
231-
buffer = s.uintbuf[:1]
232-
buffer[0] = s.byteval
233-
s.kind = -1 // re-arm Kind
234-
case size == 0:
235-
// Avoid zero-length read.
236-
s.kind = -1
237-
case size <= uint64(len(s.uintbuf)):
238-
// For integers smaller than s.uintbuf, allocating a buffer
239-
// can be avoided.
240-
buffer = s.uintbuf[:size]
241-
if err := s.readFull(buffer); err != nil {
242-
return wrapStreamError(err, val.Type())
243-
}
244-
// Reject inputs where single byte encoding should have been used.
245-
if size == 1 && buffer[0] < 128 {
246-
return wrapStreamError(ErrCanonSize, val.Type())
247-
}
248-
default:
249-
// For large integers, a temporary buffer is needed.
250-
buffer = make([]byte, size)
251-
if err := s.readFull(buffer); err != nil {
252-
return wrapStreamError(err, val.Type())
253-
}
254-
}
255-
256-
// Reject leading zero bytes.
257-
if len(buffer) > 0 && buffer[0] == 0 {
258-
return wrapStreamError(ErrCanonInt, val.Type())
259-
}
260-
261-
// Set the integer bytes.
262225
i := val.Interface().(*big.Int)
263226
if i == nil {
264227
i = new(big.Int)
265228
val.Set(reflect.ValueOf(i))
266229
}
267-
i.SetBytes(buffer)
230+
231+
err := s.decodeBigInt(i)
232+
if err != nil {
233+
return wrapStreamError(err, val.Type())
234+
}
268235
return nil
269236
}
270237

271-
func makeListDecoder(typ reflect.Type, tag tags) (decoder, error) {
238+
func makeListDecoder(typ reflect.Type, tag rlpstruct.Tags) (decoder, error) {
272239
etype := typ.Elem()
273240
if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) {
274241
if typ.Kind() == reflect.Array {
275242
return decodeByteArray, nil
276243
}
277244
return decodeByteSlice, nil
278245
}
279-
etypeinfo := theTC.infoWhileGenerating(etype, tags{})
246+
etypeinfo := theTC.infoWhileGenerating(etype, rlpstruct.Tags{})
280247
if etypeinfo.decoderErr != nil {
281248
return nil, etypeinfo.decoderErr
282249
}
@@ -286,7 +253,7 @@ func makeListDecoder(typ reflect.Type, tag tags) (decoder, error) {
286253
dec = func(s *Stream, val reflect.Value) error {
287254
return decodeListArray(s, val, etypeinfo.decoder)
288255
}
289-
case tag.tail:
256+
case tag.Tail:
290257
// A slice with "tail" tag can occur as the last field
291258
// of a struct and is supposed to swallow all remaining
292259
// list elements. The struct decoder already called s.List,
@@ -451,16 +418,16 @@ func zeroFields(structval reflect.Value, fields []field) {
451418
}
452419

453420
// makePtrDecoder creates a decoder that decodes into the pointer's element type.
454-
func makePtrDecoder(typ reflect.Type, tag tags) (decoder, error) {
421+
func makePtrDecoder(typ reflect.Type, tag rlpstruct.Tags) (decoder, error) {
455422
etype := typ.Elem()
456-
etypeinfo := theTC.infoWhileGenerating(etype, tags{})
423+
etypeinfo := theTC.infoWhileGenerating(etype, rlpstruct.Tags{})
457424
switch {
458425
case etypeinfo.decoderErr != nil:
459426
return nil, etypeinfo.decoderErr
460-
case !tag.nilOK:
427+
case !tag.NilOK:
461428
return makeSimplePtrDecoder(etype, etypeinfo), nil
462429
default:
463-
return makeNilPtrDecoder(etype, etypeinfo, tag.nilKind), nil
430+
return makeNilPtrDecoder(etype, etypeinfo, tag), nil
464431
}
465432
}
466433

@@ -481,9 +448,13 @@ func makeSimplePtrDecoder(etype reflect.Type, etypeinfo *typeinfo) decoder {
481448
// values are decoded into a value of the element type, just like makePtrDecoder does.
482449
//
483450
// This decoder is used for pointer-typed struct fields with struct tag "nil".
484-
func makeNilPtrDecoder(etype reflect.Type, etypeinfo *typeinfo, nilKind Kind) decoder {
451+
func makeNilPtrDecoder(etype reflect.Type, etypeinfo *typeinfo, ts rlpstruct.Tags) decoder {
485452
typ := reflect.PtrTo(etype)
486453
nilPtr := reflect.Zero(typ)
454+
455+
// Determine the value kind that results in nil pointer.
456+
nilKind := typeNilKind(etype, ts)
457+
487458
return func(s *Stream, val reflect.Value) (err error) {
488459
kind, size, err := s.Kind()
489460
if err != nil {
@@ -659,6 +630,37 @@ func (s *Stream) Bytes() ([]byte, error) {
659630
}
660631
}
661632

633+
// ReadBytes decodes the next RLP value and stores the result in b.
634+
// The value size must match len(b) exactly.
635+
func (s *Stream) ReadBytes(b []byte) error {
636+
kind, size, err := s.Kind()
637+
if err != nil {
638+
return err
639+
}
640+
switch kind {
641+
case Byte:
642+
if len(b) != 1 {
643+
return fmt.Errorf("input value has wrong size 1, want %d", len(b))
644+
}
645+
b[0] = s.byteval
646+
s.kind = -1 // rearm Kind
647+
return nil
648+
case String:
649+
if uint64(len(b)) != size {
650+
return fmt.Errorf("input value has wrong size %d, want %d", size, len(b))
651+
}
652+
if err = s.readFull(b); err != nil {
653+
return err
654+
}
655+
if size == 1 && b[0] < 128 {
656+
return ErrCanonSize
657+
}
658+
return nil
659+
default:
660+
return ErrExpectedString
661+
}
662+
}
663+
662664
// Raw reads a raw encoded value including RLP type information.
663665
func (s *Stream) Raw() ([]byte, error) {
664666
kind, size, err := s.Kind()
@@ -687,10 +689,31 @@ func (s *Stream) Raw() ([]byte, error) {
687689
// Uint reads an RLP string of up to 8 bytes and returns its contents
688690
// as an unsigned integer. If the input does not contain an RLP string, the
689691
// returned error will be ErrExpectedString.
692+
//
693+
// Deprecated: use s.Uint64 instead.
690694
func (s *Stream) Uint() (uint64, error) {
691695
return s.uint(64)
692696
}
693697

698+
func (s *Stream) Uint64() (uint64, error) {
699+
return s.uint(64)
700+
}
701+
702+
func (s *Stream) Uint32() (uint32, error) {
703+
i, err := s.uint(32)
704+
return uint32(i), err
705+
}
706+
707+
func (s *Stream) Uint16() (uint16, error) {
708+
i, err := s.uint(16)
709+
return uint16(i), err
710+
}
711+
712+
func (s *Stream) Uint8() (uint8, error) {
713+
i, err := s.uint(8)
714+
return uint8(i), err
715+
}
716+
694717
func (s *Stream) uint(maxbits int) (uint64, error) {
695718
kind, size, err := s.Kind()
696719
if err != nil {
@@ -781,6 +804,65 @@ func (s *Stream) ListEnd() error {
781804
return nil
782805
}
783806

807+
// MoreDataInList reports whether the current list context contains
808+
// more data to be read.
809+
func (s *Stream) MoreDataInList() bool {
810+
_, listLimit := s.listLimit()
811+
return listLimit > 0
812+
}
813+
814+
// BigInt decodes an arbitrary-size integer value.
815+
func (s *Stream) BigInt() (*big.Int, error) {
816+
i := new(big.Int)
817+
if err := s.decodeBigInt(i); err != nil {
818+
return nil, err
819+
}
820+
return i, nil
821+
}
822+
823+
func (s *Stream) decodeBigInt(dst *big.Int) error {
824+
var buffer []byte
825+
kind, size, err := s.Kind()
826+
switch {
827+
case err != nil:
828+
return err
829+
case kind == List:
830+
return ErrExpectedString
831+
case kind == Byte:
832+
buffer = s.uintbuf[:1]
833+
buffer[0] = s.byteval
834+
s.kind = -1 // re-arm Kind
835+
case size == 0:
836+
// Avoid zero-length read.
837+
s.kind = -1
838+
case size <= uint64(len(s.uintbuf)):
839+
// For integers smaller than s.uintbuf, allocating a buffer
840+
// can be avoided.
841+
buffer = s.uintbuf[:size]
842+
if err := s.readFull(buffer); err != nil {
843+
return err
844+
}
845+
// Reject inputs where single byte encoding should have been used.
846+
if size == 1 && buffer[0] < 128 {
847+
return ErrCanonSize
848+
}
849+
default:
850+
// For large integers, a temporary buffer is needed.
851+
buffer = make([]byte, size)
852+
if err := s.readFull(buffer); err != nil {
853+
return err
854+
}
855+
}
856+
857+
// Reject leading zero bytes.
858+
if len(buffer) > 0 && buffer[0] == 0 {
859+
return ErrCanonInt
860+
}
861+
// Set the integer bytes.
862+
dst.SetBytes(buffer)
863+
return nil
864+
}
865+
784866
// Decode decodes a value and stores the result in the value pointed
785867
// to by val. Please see the documentation for the Decode function
786868
// to learn about the decoding rules.

rlp/decode_test.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,47 @@ func TestStreamRaw(t *testing.T) {
286286
}
287287
}
288288

289+
func TestStreamReadBytes(t *testing.T) {
290+
tests := []struct {
291+
input string
292+
size int
293+
err string
294+
}{
295+
// kind List
296+
{input: "C0", size: 1, err: "rlp: expected String or Byte"},
297+
// kind Byte
298+
{input: "04", size: 0, err: "input value has wrong size 1, want 0"},
299+
{input: "04", size: 1},
300+
{input: "04", size: 2, err: "input value has wrong size 1, want 2"},
301+
// kind String
302+
{input: "820102", size: 0, err: "input value has wrong size 2, want 0"},
303+
{input: "820102", size: 1, err: "input value has wrong size 2, want 1"},
304+
{input: "820102", size: 2},
305+
{input: "820102", size: 3, err: "input value has wrong size 2, want 3"},
306+
}
307+
308+
for _, test := range tests {
309+
test := test
310+
name := fmt.Sprintf("input_%s/size_%d", test.input, test.size)
311+
t.Run(name, func(t *testing.T) {
312+
s := NewStream(bytes.NewReader(unhex(test.input)), 0)
313+
b := make([]byte, test.size)
314+
err := s.ReadBytes(b)
315+
if test.err == "" {
316+
if err != nil {
317+
t.Errorf("unexpected error %q", err)
318+
}
319+
} else {
320+
if err == nil {
321+
t.Errorf("expected error, got nil")
322+
} else if err.Error() != test.err {
323+
t.Errorf("wrong error %q", err)
324+
}
325+
}
326+
})
327+
}
328+
}
329+
289330
func TestDecodeErrors(t *testing.T) {
290331
r := bytes.NewReader(nil)
291332

@@ -990,7 +1031,7 @@ func TestInvalidOptionalField(t *testing.T) {
9901031
v interface{}
9911032
err string
9921033
}{
993-
{v: new(invalid1), err: `rlp: struct field rlp.invalid1.B needs "optional" tag`},
1034+
{v: new(invalid1), err: `rlp: invalid struct tag "" for rlp.invalid1.B (must be optional because preceding field "A" is optional)`},
9941035
{v: new(invalid2), err: `rlp: invalid struct tag "optional" for rlp.invalid2.T (also has "tail" tag)`},
9951036
{v: new(invalid3), err: `rlp: invalid struct tag "tail" for rlp.invalid3.T (also has "optional" tag)`},
9961037
}

0 commit comments

Comments
 (0)