Skip to content

Commit f781cee

Browse files
gzliudanfjl
andauthored
feat(rlp): add RawList for working with un-decoded lists ethereum#33755 (#2040)
This adds a new type wrapper that decodes as a list, but does not actually decode the contents of the list. The type parameter exists as a marker, and enables decoding the elements lazily. RawList can also be used for building a list incrementally. Co-authored-by: Felix Lange <fjl@twurst.com>
1 parent 466e368 commit f781cee

File tree

5 files changed

+386
-15
lines changed

5 files changed

+386
-15
lines changed

rlp/encode.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,29 @@ func EncodeToReader(val interface{}) (size int, r io.Reader, err error) {
102102
return buf.size(), &encReader{buf: buf}, nil
103103
}
104104

105+
// EncodeToRawList encodes val as an RLP list and returns it as a RawList.
106+
func EncodeToRawList[T any](val []T) (RawList[T], error) {
107+
if len(val) == 0 {
108+
return RawList[T]{}, nil
109+
}
110+
111+
// Encode the value to an internal buffer.
112+
buf := getEncBuffer()
113+
defer encBufferPool.Put(buf)
114+
if err := buf.encode(val); err != nil {
115+
return RawList[T]{}, err
116+
}
117+
118+
// Create the RawList. RawList assumes the initial list header is padded
119+
// 9 bytes, so we have to determine the offset where the value should be
120+
// placed.
121+
contentSize := buf.lheads[0].size
122+
bytes := make([]byte, contentSize+9)
123+
offset := 9 - headsize(uint64(contentSize))
124+
buf.copyTo(bytes[offset:])
125+
return RawList[T]{enc: bytes}, nil
126+
}
127+
105128
type listhead struct {
106129
offset int // index of this header in string data
107130
size int // total size of encoded data (including list headers)

rlp/iterator.go

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,35 @@
1616

1717
package rlp
1818

19-
type listIterator struct {
20-
data []byte
21-
next []byte
22-
err error
19+
// Iterator is an iterator over the elements of an encoded container.
20+
type Iterator struct {
21+
data []byte
22+
next []byte
23+
offset int
24+
err error
2325
}
2426

25-
// NewListIterator creates an iterator for the (list) represented by data
26-
func NewListIterator(data RawValue) (*listIterator, error) {
27+
// NewListIterator creates an iterator for the (list) represented by data.
28+
func NewListIterator(data RawValue) (*Iterator, error) {
2729
k, t, c, err := readKind(data)
2830
if err != nil {
2931
return nil, err
3032
}
3133
if k != List {
3234
return nil, ErrExpectedList
3335
}
34-
it := &listIterator{
35-
data: data[t : t+c],
36-
}
36+
it := &Iterator{data: data[t : t+c], offset: int(t)}
3737
return it, nil
3838
}
3939

40+
func newIterator(data []byte) *Iterator {
41+
return &Iterator{data: data}
42+
}
43+
4044
// Next forwards the iterator one step.
4145
// Returns true if there is a next item or an error occurred on this step (check Err()).
4246
// On parse error, the iterator is marked finished and subsequent calls return false.
43-
func (it *listIterator) Next() bool {
47+
func (it *Iterator) Next() bool {
4448
if len(it.data) == 0 {
4549
return false
4650
}
@@ -52,17 +56,34 @@ func (it *listIterator) Next() bool {
5256
it.data = nil
5357
return true
5458
}
55-
it.next = it.data[:t+c]
56-
it.data = it.data[t+c:]
59+
length := t + c
60+
it.next = it.data[:length]
61+
it.data = it.data[length:]
62+
it.offset += int(length)
5763
it.err = nil
5864
return true
5965
}
6066

61-
// Value returns the current value
62-
func (it *listIterator) Value() []byte {
67+
// Count returns the remaining number of items.
68+
// Note this is O(n) and the result may be incorrect if the list data is invalid.
69+
// The returned count is always an upper bound on the remaining items
70+
// that will be visited by the iterator.
71+
func (it *Iterator) Count() int {
72+
count, _ := CountValues(it.data)
73+
return count
74+
}
75+
76+
// Value returns the current value.
77+
func (it *Iterator) Value() []byte {
6378
return it.next
6479
}
6580

66-
func (it *listIterator) Err() error {
81+
// Offset returns the offset of the current value into the list data.
82+
func (it *Iterator) Offset() int {
83+
return it.offset - len(it.next)
84+
}
85+
86+
// Err returns the error that caused Next to return false, if any.
87+
func (it *Iterator) Err() error {
6788
return it.err
6889
}

rlp/iterator_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,18 @@ func TestIterator(t *testing.T) {
3838
t.Fatal("expected two elems, got zero")
3939
}
4040
txs := it.Value()
41+
if offset := it.Offset(); offset != 3 {
42+
t.Fatal("wrong offset", offset, "want 3")
43+
}
44+
4145
// Check that uncles exist
4246
if !it.Next() {
4347
t.Fatal("expected two elems, got one")
4448
}
49+
if offset := it.Offset(); offset != 219 {
50+
t.Fatal("wrong offset", offset, "want 219")
51+
}
52+
4553
txit, err := NewListIterator(txs)
4654
if err != nil {
4755
t.Fatal(err)

rlp/raw.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package rlp
1818

1919
import (
20+
"fmt"
2021
"io"
2122
"reflect"
23+
"slices"
2224
)
2325

2426
// RawValue represents an encoded RLP value and can be used to delay
@@ -28,6 +30,121 @@ type RawValue []byte
2830

2931
var rawValueType = reflect.TypeOf(RawValue{})
3032

33+
// RawList represents an encoded RLP list.
34+
type RawList[T any] struct {
35+
// The list is stored in encoded form.
36+
// Note this buffer has some special properties:
37+
//
38+
// - if the buffer is nil, it's the zero value, representing
39+
// an empty list.
40+
// - if the buffer is non-nil, it must have a length of at least
41+
// 9 bytes, which is reserved padding for the encoded list header.
42+
// The remaining bytes, enc[9:], store the content bytes of the list.
43+
//
44+
// The implementation code mostly works with the Content method because it
45+
// returns something valid either way.
46+
enc []byte
47+
}
48+
49+
// Content returns the RLP-encoded data of the list.
50+
// This does not include the list-header.
51+
// The return value is a direct reference to the internal buffer, not a copy.
52+
func (r *RawList[T]) Content() []byte {
53+
if r.enc == nil {
54+
return nil
55+
} else {
56+
return r.enc[9:]
57+
}
58+
}
59+
60+
// EncodeRLP writes the encoded list to the writer.
61+
func (r RawList[T]) EncodeRLP(w io.Writer) error {
62+
_, err := w.Write(r.Bytes())
63+
return err
64+
}
65+
66+
// Bytes returns the RLP encoding of the list.
67+
// Note the return value aliases the internal buffer.
68+
func (r *RawList[T]) Bytes() []byte {
69+
if r == nil || r.enc == nil {
70+
return []byte{0xC0} // zero value encodes as empty list
71+
}
72+
n := puthead(r.enc, 0xC0, 0xF7, uint64(len(r.Content())))
73+
copy(r.enc[9-n:], r.enc[:n])
74+
return r.enc[9-n:]
75+
}
76+
77+
// DecodeRLP decodes the list. This does not perform validation of the items!
78+
func (r *RawList[T]) DecodeRLP(s *Stream) error {
79+
k, size, err := s.Kind()
80+
if err != nil {
81+
return err
82+
}
83+
if k != List {
84+
return fmt.Errorf("%w for %T", ErrExpectedList, r)
85+
}
86+
enc := make([]byte, 9+size)
87+
if err := s.readFull(enc[9:]); err != nil {
88+
return err
89+
}
90+
*r = RawList[T]{enc: enc}
91+
return nil
92+
}
93+
94+
// Items decodes and returns all items in the list.
95+
func (r *RawList[T]) Items() ([]T, error) {
96+
items := make([]T, r.Len())
97+
it := r.ContentIterator()
98+
for i := 0; it.Next(); i++ {
99+
if err := DecodeBytes(it.Value(), &items[i]); err != nil {
100+
return items[:i], err
101+
}
102+
}
103+
return items, nil
104+
}
105+
106+
// Len returns the number of items in the list.
107+
func (r *RawList[T]) Len() int {
108+
len, _ := CountValues(r.Content())
109+
return len
110+
}
111+
112+
// Size returns the encoded size of the list.
113+
func (r *RawList[T]) Size() uint64 {
114+
return ListSize(uint64(len(r.Content())))
115+
}
116+
117+
// Empty returns true if the list contains no items.
118+
func (r *RawList[T]) Empty() bool {
119+
return len(r.Content()) == 0
120+
}
121+
122+
// ContentIterator returns an iterator over the content of the list.
123+
// Note the offsets returned by iterator.Offset are relative to the
124+
// Content bytes of the list.
125+
func (r *RawList[T]) ContentIterator() *Iterator {
126+
return newIterator(r.Content())
127+
}
128+
129+
// Append adds an item to the end of the list.
130+
func (r *RawList[T]) Append(item T) error {
131+
if r.enc == nil {
132+
r.enc = make([]byte, 9)
133+
}
134+
135+
eb := getEncBuffer()
136+
defer encBufferPool.Put(eb)
137+
138+
if err := eb.encode(item); err != nil {
139+
return err
140+
}
141+
prevEnd := len(r.enc)
142+
end := prevEnd + eb.size()
143+
r.enc = slices.Grow(r.enc, eb.size())[:end]
144+
eb.copyTo(r.enc[prevEnd:end])
145+
return nil
146+
}
147+
31148
// StringSize returns the encoded size of a string.
32149
func StringSize(s string) uint64 {
33150
switch n := len(s); n {

0 commit comments

Comments
 (0)