Add RLP package under restricted
This commit is contained in:
parent
0d3400ee78
commit
244866381c
1038
restricted/rlp/decode.go
Normal file
1038
restricted/rlp/decode.go
Normal file
File diff suppressed because it is too large
Load Diff
49
restricted/rlp/decode_tail_test.go
Normal file
49
restricted/rlp/decode_tail_test.go
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rlp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type structWithTail struct {
|
||||
A, B uint
|
||||
C []uint `rlp:"tail"`
|
||||
}
|
||||
|
||||
func ExampleDecode_structTagTail() {
|
||||
// In this example, the "tail" struct tag is used to decode lists of
|
||||
// differing length into a struct.
|
||||
var val structWithTail
|
||||
|
||||
err := Decode(bytes.NewReader([]byte{0xC4, 0x01, 0x02, 0x03, 0x04}), &val)
|
||||
fmt.Printf("with 4 elements: err=%v val=%v\n", err, val)
|
||||
|
||||
err = Decode(bytes.NewReader([]byte{0xC6, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}), &val)
|
||||
fmt.Printf("with 6 elements: err=%v val=%v\n", err, val)
|
||||
|
||||
// Note that at least two list elements must be present to
|
||||
// fill fields A and B:
|
||||
err = Decode(bytes.NewReader([]byte{0xC1, 0x01}), &val)
|
||||
fmt.Printf("with 1 element: err=%q\n", err)
|
||||
|
||||
// Output:
|
||||
// with 4 elements: err=<nil> val={1 2 [3 4]}
|
||||
// with 6 elements: err=<nil> val={1 2 [3 4 5 6]}
|
||||
// with 1 element: err="rlp: too few elements for rlp.structWithTail"
|
||||
}
|
1168
restricted/rlp/decode_test.go
Normal file
1168
restricted/rlp/decode_test.go
Normal file
File diff suppressed because it is too large
Load Diff
161
restricted/rlp/doc.go
Normal file
161
restricted/rlp/doc.go
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
Package rlp implements the RLP serialization format.
|
||||
|
||||
The purpose of RLP (Recursive Linear Prefix) is to encode arbitrarily nested arrays of
|
||||
binary data, and RLP is the main encoding method used to serialize objects in Ethereum.
|
||||
The only purpose of RLP is to encode structure; encoding specific atomic data types (eg.
|
||||
strings, ints, floats) is left up to higher-order protocols. In Ethereum integers must be
|
||||
represented in big endian binary form with no leading zeroes (thus making the integer
|
||||
value zero equivalent to the empty string).
|
||||
|
||||
RLP values are distinguished by a type tag. The type tag precedes the value in the input
|
||||
stream and defines the size and kind of the bytes that follow.
|
||||
|
||||
|
||||
Encoding Rules
|
||||
|
||||
Package rlp uses reflection and encodes RLP based on the Go type of the value.
|
||||
|
||||
If the type implements the Encoder interface, Encode calls EncodeRLP. It does not
|
||||
call EncodeRLP on nil pointer values.
|
||||
|
||||
To encode a pointer, the value being pointed to is encoded. A nil pointer to a struct
|
||||
type, slice or array always encodes as an empty RLP list unless the slice or array has
|
||||
elememt type byte. A nil pointer to any other value encodes as the empty string.
|
||||
|
||||
Struct values are encoded as an RLP list of all their encoded public fields. Recursive
|
||||
struct types are supported.
|
||||
|
||||
To encode slices and arrays, the elements are encoded as an RLP list of the value's
|
||||
elements. Note that arrays and slices with element type uint8 or byte are always encoded
|
||||
as an RLP string.
|
||||
|
||||
A Go string is encoded as an RLP string.
|
||||
|
||||
An unsigned integer value is encoded as an RLP string. Zero always encodes as an empty RLP
|
||||
string. big.Int values are treated as integers. Signed integers (int, int8, int16, ...)
|
||||
are not supported and will return an error when encoding.
|
||||
|
||||
Boolean values are encoded as the unsigned integers zero (false) and one (true).
|
||||
|
||||
An interface value encodes as the value contained in the interface.
|
||||
|
||||
Floating point numbers, maps, channels and functions are not supported.
|
||||
|
||||
|
||||
Decoding Rules
|
||||
|
||||
Decoding uses the following type-dependent rules:
|
||||
|
||||
If the type implements the Decoder interface, DecodeRLP is called.
|
||||
|
||||
To decode into a pointer, the value will be decoded as the element type of the pointer. If
|
||||
the pointer is nil, a new value of the pointer's element type is allocated. If the pointer
|
||||
is non-nil, the existing value will be reused. Note that package rlp never leaves a
|
||||
pointer-type struct field as nil unless one of the "nil" struct tags is present.
|
||||
|
||||
To decode into a struct, decoding expects the input to be an RLP list. The decoded
|
||||
elements of the list are assigned to each public field in the order given by the struct's
|
||||
definition. The input list must contain an element for each decoded field. Decoding
|
||||
returns an error if there are too few or too many elements for the struct.
|
||||
|
||||
To decode into a slice, the input must be a list and the resulting slice will contain the
|
||||
input elements in order. For byte slices, the input must be an RLP string. Array types
|
||||
decode similarly, with the additional restriction that the number of input elements (or
|
||||
bytes) must match the array's defined length.
|
||||
|
||||
To decode into a Go string, the input must be an RLP string. The input bytes are taken
|
||||
as-is and will not necessarily be valid UTF-8.
|
||||
|
||||
To decode into an unsigned integer type, the input must also be an RLP string. The bytes
|
||||
are interpreted as a big endian representation of the integer. If the RLP string is larger
|
||||
than the bit size of the type, decoding will return an error. Decode also supports
|
||||
*big.Int. There is no size limit for big integers.
|
||||
|
||||
To decode into a boolean, the input must contain an unsigned integer of value zero (false)
|
||||
or one (true).
|
||||
|
||||
To decode into an interface value, one of these types is stored in the value:
|
||||
|
||||
[]interface{}, for RLP lists
|
||||
[]byte, for RLP strings
|
||||
|
||||
Non-empty interface types are not supported when decoding.
|
||||
Signed integers, floating point numbers, maps, channels and functions cannot be decoded into.
|
||||
|
||||
|
||||
Struct Tags
|
||||
|
||||
As with other encoding packages, the "-" tag ignores fields.
|
||||
|
||||
type StructWithIgnoredField struct{
|
||||
Ignored uint `rlp:"-"`
|
||||
Field uint
|
||||
}
|
||||
|
||||
Go struct values encode/decode as RLP lists. There are two ways of influencing the mapping
|
||||
of fields to list elements. The "tail" tag, which may only be used on the last exported
|
||||
struct field, allows slurping up any excess list elements into a slice.
|
||||
|
||||
type StructWithTail struct{
|
||||
Field uint
|
||||
Tail []string `rlp:"tail"`
|
||||
}
|
||||
|
||||
The "optional" tag says that the field may be omitted if it is zero-valued. If this tag is
|
||||
used on a struct field, all subsequent public fields must also be declared optional.
|
||||
|
||||
When encoding a struct with optional fields, the output RLP list contains all values up to
|
||||
the last non-zero optional field.
|
||||
|
||||
When decoding into a struct, optional fields may be omitted from the end of the input
|
||||
list. For the example below, this means input lists of one, two, or three elements are
|
||||
accepted.
|
||||
|
||||
type StructWithOptionalFields struct{
|
||||
Required uint
|
||||
Optional1 uint `rlp:"optional"`
|
||||
Optional2 uint `rlp:"optional"`
|
||||
}
|
||||
|
||||
The "nil", "nilList" and "nilString" tags apply to pointer-typed fields only, and change
|
||||
the decoding rules for the field type. For regular pointer fields without the "nil" tag,
|
||||
input values must always match the required input length exactly and the decoder does not
|
||||
produce nil values. When the "nil" tag is set, input values of size zero decode as a nil
|
||||
pointer. This is especially useful for recursive types.
|
||||
|
||||
type StructWithNilField struct {
|
||||
Field *[3]byte `rlp:"nil"`
|
||||
}
|
||||
|
||||
In the example above, Field allows two possible input sizes. For input 0xC180 (a list
|
||||
containing an empty string) Field is set to nil after decoding. For input 0xC483000000 (a
|
||||
list containing a 3-byte string), Field is set to a non-nil array pointer.
|
||||
|
||||
RLP supports two kinds of empty values: empty lists and empty strings. When using the
|
||||
"nil" tag, the kind of empty value allowed for a type is chosen automatically. A field
|
||||
whose Go type is a pointer to an unsigned integer, string, boolean or byte array/slice
|
||||
expects an empty RLP string. Any other pointer field type encodes/decodes as an empty RLP
|
||||
list.
|
||||
|
||||
The choice of null value can be made explicit with the "nilList" and "nilString" struct
|
||||
tags. Using these tags encodes/decodes a Go nil pointer value as the empty RLP value kind
|
||||
defined by the tag.
|
||||
*/
|
||||
package rlp
|
676
restricted/rlp/encode.go
Normal file
676
restricted/rlp/encode.go
Normal file
@ -0,0 +1,676 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rlp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
// Common encoded values.
|
||||
// These are useful when implementing EncodeRLP.
|
||||
EmptyString = []byte{0x80}
|
||||
EmptyList = []byte{0xC0}
|
||||
)
|
||||
|
||||
// Encoder is implemented by types that require custom
|
||||
// encoding rules or want to encode private fields.
|
||||
type Encoder interface {
|
||||
// EncodeRLP should write the RLP encoding of its receiver to w.
|
||||
// If the implementation is a pointer method, it may also be
|
||||
// called for nil pointers.
|
||||
//
|
||||
// Implementations should generate valid RLP. The data written is
|
||||
// not verified at the moment, but a future version might. It is
|
||||
// recommended to write only a single value but writing multiple
|
||||
// values or no value at all is also permitted.
|
||||
EncodeRLP(io.Writer) error
|
||||
}
|
||||
|
||||
// Encode writes the RLP encoding of val to w. Note that Encode may
|
||||
// perform many small writes in some cases. Consider making w
|
||||
// buffered.
|
||||
//
|
||||
// Please see package-level documentation of encoding rules.
|
||||
func Encode(w io.Writer, val interface{}) error {
|
||||
if outer, ok := w.(*encbuf); ok {
|
||||
// Encode was called by some type's EncodeRLP.
|
||||
// Avoid copying by writing to the outer encbuf directly.
|
||||
return outer.encode(val)
|
||||
}
|
||||
eb := encbufPool.Get().(*encbuf)
|
||||
defer encbufPool.Put(eb)
|
||||
eb.reset()
|
||||
if err := eb.encode(val); err != nil {
|
||||
return err
|
||||
}
|
||||
return eb.toWriter(w)
|
||||
}
|
||||
|
||||
// EncodeToBytes returns the RLP encoding of val.
|
||||
// Please see package-level documentation for the encoding rules.
|
||||
func EncodeToBytes(val interface{}) ([]byte, error) {
|
||||
eb := encbufPool.Get().(*encbuf)
|
||||
defer encbufPool.Put(eb)
|
||||
eb.reset()
|
||||
if err := eb.encode(val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eb.toBytes(), nil
|
||||
}
|
||||
|
||||
// EncodeToReader returns a reader from which the RLP encoding of val
|
||||
// can be read. The returned size is the total size of the encoded
|
||||
// data.
|
||||
//
|
||||
// Please see the documentation of Encode for the encoding rules.
|
||||
func EncodeToReader(val interface{}) (size int, r io.Reader, err error) {
|
||||
eb := encbufPool.Get().(*encbuf)
|
||||
eb.reset()
|
||||
if err := eb.encode(val); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return eb.size(), &encReader{buf: eb}, nil
|
||||
}
|
||||
|
||||
type listhead struct {
|
||||
offset int // index of this header in string data
|
||||
size int // total size of encoded data (including list headers)
|
||||
}
|
||||
|
||||
// encode writes head to the given buffer, which must be at least
|
||||
// 9 bytes long. It returns the encoded bytes.
|
||||
func (head *listhead) encode(buf []byte) []byte {
|
||||
return buf[:puthead(buf, 0xC0, 0xF7, uint64(head.size))]
|
||||
}
|
||||
|
||||
// headsize returns the size of a list or string header
|
||||
// for a value of the given size.
|
||||
func headsize(size uint64) int {
|
||||
if size < 56 {
|
||||
return 1
|
||||
}
|
||||
return 1 + intsize(size)
|
||||
}
|
||||
|
||||
// puthead writes a list or string header to buf.
|
||||
// buf must be at least 9 bytes long.
|
||||
func puthead(buf []byte, smalltag, largetag byte, size uint64) int {
|
||||
if size < 56 {
|
||||
buf[0] = smalltag + byte(size)
|
||||
return 1
|
||||
}
|
||||
sizesize := putint(buf[1:], size)
|
||||
buf[0] = largetag + byte(sizesize)
|
||||
return sizesize + 1
|
||||
}
|
||||
|
||||
type encbuf struct {
|
||||
str []byte // string data, contains everything except list headers
|
||||
lheads []listhead // all list headers
|
||||
lhsize int // sum of sizes of all encoded list headers
|
||||
sizebuf [9]byte // auxiliary buffer for uint encoding
|
||||
}
|
||||
|
||||
// encbufs are pooled.
|
||||
var encbufPool = sync.Pool{
|
||||
New: func() interface{} { return new(encbuf) },
|
||||
}
|
||||
|
||||
func (w *encbuf) reset() {
|
||||
w.lhsize = 0
|
||||
w.str = w.str[:0]
|
||||
w.lheads = w.lheads[:0]
|
||||
}
|
||||
|
||||
// encbuf implements io.Writer so it can be passed it into EncodeRLP.
|
||||
func (w *encbuf) Write(b []byte) (int, error) {
|
||||
w.str = append(w.str, b...)
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (w *encbuf) encode(val interface{}) error {
|
||||
rval := reflect.ValueOf(val)
|
||||
writer, err := cachedWriter(rval.Type())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writer(rval, w)
|
||||
}
|
||||
|
||||
func (w *encbuf) encodeStringHeader(size int) {
|
||||
if size < 56 {
|
||||
w.str = append(w.str, 0x80+byte(size))
|
||||
} else {
|
||||
sizesize := putint(w.sizebuf[1:], uint64(size))
|
||||
w.sizebuf[0] = 0xB7 + byte(sizesize)
|
||||
w.str = append(w.str, w.sizebuf[:sizesize+1]...)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *encbuf) encodeString(b []byte) {
|
||||
if len(b) == 1 && b[0] <= 0x7F {
|
||||
// fits single byte, no string header
|
||||
w.str = append(w.str, b[0])
|
||||
} else {
|
||||
w.encodeStringHeader(len(b))
|
||||
w.str = append(w.str, b...)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *encbuf) encodeUint(i uint64) {
|
||||
if i == 0 {
|
||||
w.str = append(w.str, 0x80)
|
||||
} else if i < 128 {
|
||||
// fits single byte
|
||||
w.str = append(w.str, byte(i))
|
||||
} else {
|
||||
s := putint(w.sizebuf[1:], i)
|
||||
w.sizebuf[0] = 0x80 + byte(s)
|
||||
w.str = append(w.str, w.sizebuf[:s+1]...)
|
||||
}
|
||||
}
|
||||
|
||||
// list adds a new list header to the header stack. It returns the index
|
||||
// of the header. The caller must call listEnd with this index after encoding
|
||||
// the content of the list.
|
||||
func (w *encbuf) list() int {
|
||||
w.lheads = append(w.lheads, listhead{offset: len(w.str), size: w.lhsize})
|
||||
return len(w.lheads) - 1
|
||||
}
|
||||
|
||||
func (w *encbuf) listEnd(index int) {
|
||||
lh := &w.lheads[index]
|
||||
lh.size = w.size() - lh.offset - lh.size
|
||||
if lh.size < 56 {
|
||||
w.lhsize++ // length encoded into kind tag
|
||||
} else {
|
||||
w.lhsize += 1 + intsize(uint64(lh.size))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *encbuf) size() int {
|
||||
return len(w.str) + w.lhsize
|
||||
}
|
||||
|
||||
func (w *encbuf) toBytes() []byte {
|
||||
out := make([]byte, w.size())
|
||||
strpos := 0
|
||||
pos := 0
|
||||
for _, head := range w.lheads {
|
||||
// write string data before header
|
||||
n := copy(out[pos:], w.str[strpos:head.offset])
|
||||
pos += n
|
||||
strpos += n
|
||||
// write the header
|
||||
enc := head.encode(out[pos:])
|
||||
pos += len(enc)
|
||||
}
|
||||
// copy string data after the last list header
|
||||
copy(out[pos:], w.str[strpos:])
|
||||
return out
|
||||
}
|
||||
|
||||
func (w *encbuf) toWriter(out io.Writer) (err error) {
|
||||
strpos := 0
|
||||
for _, head := range w.lheads {
|
||||
// write string data before header
|
||||
if head.offset-strpos > 0 {
|
||||
n, err := out.Write(w.str[strpos:head.offset])
|
||||
strpos += n
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// write the header
|
||||
enc := head.encode(w.sizebuf[:])
|
||||
if _, err = out.Write(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if strpos < len(w.str) {
|
||||
// write string data after the last list header
|
||||
_, err = out.Write(w.str[strpos:])
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// encReader is the io.Reader returned by EncodeToReader.
|
||||
// It releases its encbuf at EOF.
|
||||
type encReader struct {
|
||||
buf *encbuf // the buffer we're reading from. this is nil when we're at EOF.
|
||||
lhpos int // index of list header that we're reading
|
||||
strpos int // current position in string buffer
|
||||
piece []byte // next piece to be read
|
||||
}
|
||||
|
||||
func (r *encReader) Read(b []byte) (n int, err error) {
|
||||
for {
|
||||
if r.piece = r.next(); r.piece == nil {
|
||||
// Put the encode buffer back into the pool at EOF when it
|
||||
// is first encountered. Subsequent calls still return EOF
|
||||
// as the error but the buffer is no longer valid.
|
||||
if r.buf != nil {
|
||||
encbufPool.Put(r.buf)
|
||||
r.buf = nil
|
||||
}
|
||||
return n, io.EOF
|
||||
}
|
||||
nn := copy(b[n:], r.piece)
|
||||
n += nn
|
||||
if nn < len(r.piece) {
|
||||
// piece didn't fit, see you next time.
|
||||
r.piece = r.piece[nn:]
|
||||
return n, nil
|
||||
}
|
||||
r.piece = nil
|
||||
}
|
||||
}
|
||||
|
||||
// next returns the next piece of data to be read.
|
||||
// it returns nil at EOF.
|
||||
func (r *encReader) next() []byte {
|
||||
switch {
|
||||
case r.buf == nil:
|
||||
return nil
|
||||
|
||||
case r.piece != nil:
|
||||
// There is still data available for reading.
|
||||
return r.piece
|
||||
|
||||
case r.lhpos < len(r.buf.lheads):
|
||||
// We're before the last list header.
|
||||
head := r.buf.lheads[r.lhpos]
|
||||
sizebefore := head.offset - r.strpos
|
||||
if sizebefore > 0 {
|
||||
// String data before header.
|
||||
p := r.buf.str[r.strpos:head.offset]
|
||||
r.strpos += sizebefore
|
||||
return p
|
||||
}
|
||||
r.lhpos++
|
||||
return head.encode(r.buf.sizebuf[:])
|
||||
|
||||
case r.strpos < len(r.buf.str):
|
||||
// String data at the end, after all list headers.
|
||||
p := r.buf.str[r.strpos:]
|
||||
r.strpos = len(r.buf.str)
|
||||
return p
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var encoderInterface = reflect.TypeOf(new(Encoder)).Elem()
|
||||
|
||||
// makeWriter creates a writer function for the given type.
|
||||
func makeWriter(typ reflect.Type, ts tags) (writer, error) {
|
||||
kind := typ.Kind()
|
||||
switch {
|
||||
case typ == rawValueType:
|
||||
return writeRawValue, nil
|
||||
case typ.AssignableTo(reflect.PtrTo(bigInt)):
|
||||
return writeBigIntPtr, nil
|
||||
case typ.AssignableTo(bigInt):
|
||||
return writeBigIntNoPtr, nil
|
||||
case kind == reflect.Ptr:
|
||||
return makePtrWriter(typ, ts)
|
||||
case reflect.PtrTo(typ).Implements(encoderInterface):
|
||||
return makeEncoderWriter(typ), nil
|
||||
case isUint(kind):
|
||||
return writeUint, nil
|
||||
case kind == reflect.Bool:
|
||||
return writeBool, nil
|
||||
case kind == reflect.String:
|
||||
return writeString, nil
|
||||
case kind == reflect.Slice && isByte(typ.Elem()):
|
||||
return writeBytes, nil
|
||||
case kind == reflect.Array && isByte(typ.Elem()):
|
||||
return makeByteArrayWriter(typ), nil
|
||||
case kind == reflect.Slice || kind == reflect.Array:
|
||||
return makeSliceWriter(typ, ts)
|
||||
case kind == reflect.Struct:
|
||||
return makeStructWriter(typ)
|
||||
case kind == reflect.Interface:
|
||||
return writeInterface, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("rlp: type %v is not RLP-serializable", typ)
|
||||
}
|
||||
}
|
||||
|
||||
func writeRawValue(val reflect.Value, w *encbuf) error {
|
||||
w.str = append(w.str, val.Bytes()...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeUint(val reflect.Value, w *encbuf) error {
|
||||
w.encodeUint(val.Uint())
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeBool(val reflect.Value, w *encbuf) error {
|
||||
if val.Bool() {
|
||||
w.str = append(w.str, 0x01)
|
||||
} else {
|
||||
w.str = append(w.str, 0x80)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeBigIntPtr(val reflect.Value, w *encbuf) error {
|
||||
ptr := val.Interface().(*big.Int)
|
||||
if ptr == nil {
|
||||
w.str = append(w.str, 0x80)
|
||||
return nil
|
||||
}
|
||||
return writeBigInt(ptr, w)
|
||||
}
|
||||
|
||||
func writeBigIntNoPtr(val reflect.Value, w *encbuf) error {
|
||||
i := val.Interface().(big.Int)
|
||||
return writeBigInt(&i, w)
|
||||
}
|
||||
|
||||
// wordBytes is the number of bytes in a big.Word
|
||||
const wordBytes = (32 << (uint64(^big.Word(0)) >> 63)) / 8
|
||||
|
||||
func writeBigInt(i *big.Int, w *encbuf) error {
|
||||
if i.Sign() == -1 {
|
||||
return fmt.Errorf("rlp: cannot encode negative *big.Int")
|
||||
}
|
||||
bitlen := i.BitLen()
|
||||
if bitlen <= 64 {
|
||||
w.encodeUint(i.Uint64())
|
||||
return nil
|
||||
}
|
||||
// Integer is larger than 64 bits, encode from i.Bits().
|
||||
// The minimal byte length is bitlen rounded up to the next
|
||||
// multiple of 8, divided by 8.
|
||||
length := ((bitlen + 7) & -8) >> 3
|
||||
w.encodeStringHeader(length)
|
||||
w.str = append(w.str, make([]byte, length)...)
|
||||
index := length
|
||||
buf := w.str[len(w.str)-length:]
|
||||
for _, d := range i.Bits() {
|
||||
for j := 0; j < wordBytes && index > 0; j++ {
|
||||
index--
|
||||
buf[index] = byte(d)
|
||||
d >>= 8
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeBytes(val reflect.Value, w *encbuf) error {
|
||||
w.encodeString(val.Bytes())
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeByteArrayWriter(typ reflect.Type) writer {
|
||||
switch typ.Len() {
|
||||
case 0:
|
||||
return writeLengthZeroByteArray
|
||||
case 1:
|
||||
return writeLengthOneByteArray
|
||||
default:
|
||||
return writeByteArray
|
||||
}
|
||||
}
|
||||
|
||||
func writeLengthZeroByteArray(val reflect.Value, w *encbuf) error {
|
||||
w.str = append(w.str, 0x80)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeLengthOneByteArray(val reflect.Value, w *encbuf) error {
|
||||
b := byte(val.Index(0).Uint())
|
||||
if b <= 0x7f {
|
||||
w.str = append(w.str, b)
|
||||
} else {
|
||||
w.str = append(w.str, 0x81, b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeByteArray(val reflect.Value, w *encbuf) error {
|
||||
if !val.CanAddr() {
|
||||
// Getting the byte slice of val requires it to be addressable. Make it
|
||||
// addressable by copying.
|
||||
copy := reflect.New(val.Type()).Elem()
|
||||
copy.Set(val)
|
||||
val = copy
|
||||
}
|
||||
|
||||
slice := byteArrayBytes(val)
|
||||
w.encodeStringHeader(len(slice))
|
||||
w.str = append(w.str, slice...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeString(val reflect.Value, w *encbuf) error {
|
||||
s := val.String()
|
||||
if len(s) == 1 && s[0] <= 0x7f {
|
||||
// fits single byte, no string header
|
||||
w.str = append(w.str, s[0])
|
||||
} else {
|
||||
w.encodeStringHeader(len(s))
|
||||
w.str = append(w.str, s...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeInterface(val reflect.Value, w *encbuf) error {
|
||||
if val.IsNil() {
|
||||
// Write empty list. This is consistent with the previous RLP
|
||||
// encoder that we had and should therefore avoid any
|
||||
// problems.
|
||||
w.str = append(w.str, 0xC0)
|
||||
return nil
|
||||
}
|
||||
eval := val.Elem()
|
||||
writer, err := cachedWriter(eval.Type())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writer(eval, w)
|
||||
}
|
||||
|
||||
func makeSliceWriter(typ reflect.Type, ts tags) (writer, error) {
|
||||
etypeinfo := theTC.infoWhileGenerating(typ.Elem(), tags{})
|
||||
if etypeinfo.writerErr != nil {
|
||||
return nil, etypeinfo.writerErr
|
||||
}
|
||||
writer := func(val reflect.Value, w *encbuf) error {
|
||||
if !ts.tail {
|
||||
defer w.listEnd(w.list())
|
||||
}
|
||||
vlen := val.Len()
|
||||
for i := 0; i < vlen; i++ {
|
||||
if err := etypeinfo.writer(val.Index(i), w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return writer, nil
|
||||
}
|
||||
|
||||
func makeStructWriter(typ reflect.Type) (writer, error) {
|
||||
fields, err := structFields(typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, f := range fields {
|
||||
if f.info.writerErr != nil {
|
||||
return nil, structFieldError{typ, f.index, f.info.writerErr}
|
||||
}
|
||||
}
|
||||
|
||||
var writer writer
|
||||
firstOptionalField := firstOptionalField(fields)
|
||||
if firstOptionalField == len(fields) {
|
||||
// This is the writer function for structs without any optional fields.
|
||||
writer = func(val reflect.Value, w *encbuf) error {
|
||||
lh := w.list()
|
||||
for _, f := range fields {
|
||||
if err := f.info.writer(val.Field(f.index), w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.listEnd(lh)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
// If there are any "optional" fields, the writer needs to perform additional
|
||||
// checks to determine the output list length.
|
||||
writer = func(val reflect.Value, w *encbuf) error {
|
||||
lastField := len(fields) - 1
|
||||
for ; lastField >= firstOptionalField; lastField-- {
|
||||
if !val.Field(fields[lastField].index).IsZero() {
|
||||
break
|
||||
}
|
||||
}
|
||||
lh := w.list()
|
||||
for i := 0; i <= lastField; i++ {
|
||||
if err := fields[i].info.writer(val.Field(fields[i].index), w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.listEnd(lh)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return writer, nil
|
||||
}
|
||||
|
||||
func makePtrWriter(typ reflect.Type, ts tags) (writer, error) {
|
||||
etypeinfo := theTC.infoWhileGenerating(typ.Elem(), tags{})
|
||||
if etypeinfo.writerErr != nil {
|
||||
return nil, etypeinfo.writerErr
|
||||
}
|
||||
// Determine how to encode nil pointers.
|
||||
var nilKind Kind
|
||||
if ts.nilOK {
|
||||
nilKind = ts.nilKind // use struct tag if provided
|
||||
} else {
|
||||
nilKind = defaultNilKind(typ.Elem())
|
||||
}
|
||||
|
||||
writer := func(val reflect.Value, w *encbuf) error {
|
||||
if val.IsNil() {
|
||||
if nilKind == String {
|
||||
w.str = append(w.str, 0x80)
|
||||
} else {
|
||||
w.listEnd(w.list())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return etypeinfo.writer(val.Elem(), w)
|
||||
}
|
||||
return writer, nil
|
||||
}
|
||||
|
||||
func makeEncoderWriter(typ reflect.Type) writer {
|
||||
if typ.Implements(encoderInterface) {
|
||||
return func(val reflect.Value, w *encbuf) error {
|
||||
return val.Interface().(Encoder).EncodeRLP(w)
|
||||
}
|
||||
}
|
||||
w := func(val reflect.Value, w *encbuf) error {
|
||||
if !val.CanAddr() {
|
||||
// package json simply doesn't call MarshalJSON for this case, but encodes the
|
||||
// value as if it didn't implement the interface. We don't want to handle it that
|
||||
// way.
|
||||
return fmt.Errorf("rlp: unadressable value of type %v, EncodeRLP is pointer method", val.Type())
|
||||
}
|
||||
return val.Addr().Interface().(Encoder).EncodeRLP(w)
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
// putint writes i to the beginning of b in big endian byte
|
||||
// order, using the least number of bytes needed to represent i.
|
||||
func putint(b []byte, i uint64) (size int) {
|
||||
switch {
|
||||
case i < (1 << 8):
|
||||
b[0] = byte(i)
|
||||
return 1
|
||||
case i < (1 << 16):
|
||||
b[0] = byte(i >> 8)
|
||||
b[1] = byte(i)
|
||||
return 2
|
||||
case i < (1 << 24):
|
||||
b[0] = byte(i >> 16)
|
||||
b[1] = byte(i >> 8)
|
||||
b[2] = byte(i)
|
||||
return 3
|
||||
case i < (1 << 32):
|
||||
b[0] = byte(i >> 24)
|
||||
b[1] = byte(i >> 16)
|
||||
b[2] = byte(i >> 8)
|
||||
b[3] = byte(i)
|
||||
return 4
|
||||
case i < (1 << 40):
|
||||
b[0] = byte(i >> 32)
|
||||
b[1] = byte(i >> 24)
|
||||
b[2] = byte(i >> 16)
|
||||
b[3] = byte(i >> 8)
|
||||
b[4] = byte(i)
|
||||
return 5
|
||||
case i < (1 << 48):
|
||||
b[0] = byte(i >> 40)
|
||||
b[1] = byte(i >> 32)
|
||||
b[2] = byte(i >> 24)
|
||||
b[3] = byte(i >> 16)
|
||||
b[4] = byte(i >> 8)
|
||||
b[5] = byte(i)
|
||||
return 6
|
||||
case i < (1 << 56):
|
||||
b[0] = byte(i >> 48)
|
||||
b[1] = byte(i >> 40)
|
||||
b[2] = byte(i >> 32)
|
||||
b[3] = byte(i >> 24)
|
||||
b[4] = byte(i >> 16)
|
||||
b[5] = byte(i >> 8)
|
||||
b[6] = byte(i)
|
||||
return 7
|
||||
default:
|
||||
b[0] = byte(i >> 56)
|
||||
b[1] = byte(i >> 48)
|
||||
b[2] = byte(i >> 40)
|
||||
b[3] = byte(i >> 32)
|
||||
b[4] = byte(i >> 24)
|
||||
b[5] = byte(i >> 16)
|
||||
b[6] = byte(i >> 8)
|
||||
b[7] = byte(i)
|
||||
return 8
|
||||
}
|
||||
}
|
||||
|
||||
// intsize computes the minimum number of bytes required to store i.
|
||||
func intsize(i uint64) (size int) {
|
||||
for size = 1; ; size++ {
|
||||
if i >>= 8; i == 0 {
|
||||
return size
|
||||
}
|
||||
}
|
||||
}
|
540
restricted/rlp/encode_test.go
Normal file
540
restricted/rlp/encode_test.go
Normal file
@ -0,0 +1,540 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rlp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testEncoder struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *testEncoder) EncodeRLP(w io.Writer) error {
|
||||
if e == nil {
|
||||
panic("EncodeRLP called on nil value")
|
||||
}
|
||||
if e.err != nil {
|
||||
return e.err
|
||||
}
|
||||
w.Write([]byte{0, 1, 0, 1, 0, 1, 0, 1, 0, 1})
|
||||
return nil
|
||||
}
|
||||
|
||||
type testEncoderValueMethod struct{}
|
||||
|
||||
func (e testEncoderValueMethod) EncodeRLP(w io.Writer) error {
|
||||
w.Write([]byte{0xFA, 0xFE, 0xF0})
|
||||
return nil
|
||||
}
|
||||
|
||||
type byteEncoder byte
|
||||
|
||||
func (e byteEncoder) EncodeRLP(w io.Writer) error {
|
||||
w.Write(EmptyList)
|
||||
return nil
|
||||
}
|
||||
|
||||
type undecodableEncoder func()
|
||||
|
||||
func (f undecodableEncoder) EncodeRLP(w io.Writer) error {
|
||||
w.Write([]byte{0xF5, 0xF5, 0xF5})
|
||||
return nil
|
||||
}
|
||||
|
||||
type encodableReader struct {
|
||||
A, B uint
|
||||
}
|
||||
|
||||
func (e *encodableReader) Read(b []byte) (int, error) {
|
||||
panic("called")
|
||||
}
|
||||
|
||||
type namedByteType byte
|
||||
|
||||
var (
|
||||
_ = Encoder(&testEncoder{})
|
||||
_ = Encoder(byteEncoder(0))
|
||||
|
||||
reader io.Reader = &encodableReader{1, 2}
|
||||
)
|
||||
|
||||
type encTest struct {
|
||||
val interface{}
|
||||
output, error string
|
||||
}
|
||||
|
||||
var encTests = []encTest{
|
||||
// booleans
|
||||
{val: true, output: "01"},
|
||||
{val: false, output: "80"},
|
||||
|
||||
// integers
|
||||
{val: uint32(0), output: "80"},
|
||||
{val: uint32(127), output: "7F"},
|
||||
{val: uint32(128), output: "8180"},
|
||||
{val: uint32(256), output: "820100"},
|
||||
{val: uint32(1024), output: "820400"},
|
||||
{val: uint32(0xFFFFFF), output: "83FFFFFF"},
|
||||
{val: uint32(0xFFFFFFFF), output: "84FFFFFFFF"},
|
||||
{val: uint64(0xFFFFFFFF), output: "84FFFFFFFF"},
|
||||
{val: uint64(0xFFFFFFFFFF), output: "85FFFFFFFFFF"},
|
||||
{val: uint64(0xFFFFFFFFFFFF), output: "86FFFFFFFFFFFF"},
|
||||
{val: uint64(0xFFFFFFFFFFFFFF), output: "87FFFFFFFFFFFFFF"},
|
||||
{val: uint64(0xFFFFFFFFFFFFFFFF), output: "88FFFFFFFFFFFFFFFF"},
|
||||
|
||||
// big integers (should match uint for small values)
|
||||
{val: big.NewInt(0), output: "80"},
|
||||
{val: big.NewInt(1), output: "01"},
|
||||
{val: big.NewInt(127), output: "7F"},
|
||||
{val: big.NewInt(128), output: "8180"},
|
||||
{val: big.NewInt(256), output: "820100"},
|
||||
{val: big.NewInt(1024), output: "820400"},
|
||||
{val: big.NewInt(0xFFFFFF), output: "83FFFFFF"},
|
||||
{val: big.NewInt(0xFFFFFFFF), output: "84FFFFFFFF"},
|
||||
{val: big.NewInt(0xFFFFFFFFFF), output: "85FFFFFFFFFF"},
|
||||
{val: big.NewInt(0xFFFFFFFFFFFF), output: "86FFFFFFFFFFFF"},
|
||||
{val: big.NewInt(0xFFFFFFFFFFFFFF), output: "87FFFFFFFFFFFFFF"},
|
||||
{
|
||||
val: big.NewInt(0).SetBytes(unhex("102030405060708090A0B0C0D0E0F2")),
|
||||
output: "8F102030405060708090A0B0C0D0E0F2",
|
||||
},
|
||||
{
|
||||
val: big.NewInt(0).SetBytes(unhex("0100020003000400050006000700080009000A000B000C000D000E01")),
|
||||
output: "9C0100020003000400050006000700080009000A000B000C000D000E01",
|
||||
},
|
||||
{
|
||||
val: big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")),
|
||||
output: "A1010000000000000000000000000000000000000000000000000000000000000000",
|
||||
},
|
||||
{
|
||||
val: veryBigInt,
|
||||
output: "89FFFFFFFFFFFFFFFFFF",
|
||||
},
|
||||
{
|
||||
val: veryVeryBigInt,
|
||||
output: "B848FFFFFFFFFFFFFFFFF800000000000000001BFFFFFFFFFFFFFFFFC8000000000000000045FFFFFFFFFFFFFFFFC800000000000000001BFFFFFFFFFFFFFFFFF8000000000000000001",
|
||||
},
|
||||
|
||||
// non-pointer big.Int
|
||||
{val: *big.NewInt(0), output: "80"},
|
||||
{val: *big.NewInt(0xFFFFFF), output: "83FFFFFF"},
|
||||
|
||||
// negative ints are not supported
|
||||
{val: big.NewInt(-1), error: "rlp: cannot encode negative *big.Int"},
|
||||
|
||||
// byte arrays
|
||||
{val: [0]byte{}, output: "80"},
|
||||
{val: [1]byte{0}, output: "00"},
|
||||
{val: [1]byte{1}, output: "01"},
|
||||
{val: [1]byte{0x7F}, output: "7F"},
|
||||
{val: [1]byte{0x80}, output: "8180"},
|
||||
{val: [1]byte{0xFF}, output: "81FF"},
|
||||
{val: [3]byte{1, 2, 3}, output: "83010203"},
|
||||
{val: [57]byte{1, 2, 3}, output: "B839010203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
|
||||
|
||||
// named byte type arrays
|
||||
{val: [0]namedByteType{}, output: "80"},
|
||||
{val: [1]namedByteType{0}, output: "00"},
|
||||
{val: [1]namedByteType{1}, output: "01"},
|
||||
{val: [1]namedByteType{0x7F}, output: "7F"},
|
||||
{val: [1]namedByteType{0x80}, output: "8180"},
|
||||
{val: [1]namedByteType{0xFF}, output: "81FF"},
|
||||
{val: [3]namedByteType{1, 2, 3}, output: "83010203"},
|
||||
{val: [57]namedByteType{1, 2, 3}, output: "B839010203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
|
||||
|
||||
// byte slices
|
||||
{val: []byte{}, output: "80"},
|
||||
{val: []byte{0}, output: "00"},
|
||||
{val: []byte{0x7E}, output: "7E"},
|
||||
{val: []byte{0x7F}, output: "7F"},
|
||||
{val: []byte{0x80}, output: "8180"},
|
||||
{val: []byte{1, 2, 3}, output: "83010203"},
|
||||
|
||||
// named byte type slices
|
||||
{val: []namedByteType{}, output: "80"},
|
||||
{val: []namedByteType{0}, output: "00"},
|
||||
{val: []namedByteType{0x7E}, output: "7E"},
|
||||
{val: []namedByteType{0x7F}, output: "7F"},
|
||||
{val: []namedByteType{0x80}, output: "8180"},
|
||||
{val: []namedByteType{1, 2, 3}, output: "83010203"},
|
||||
|
||||
// strings
|
||||
{val: "", output: "80"},
|
||||
{val: "\x7E", output: "7E"},
|
||||
{val: "\x7F", output: "7F"},
|
||||
{val: "\x80", output: "8180"},
|
||||
{val: "dog", output: "83646F67"},
|
||||
{
|
||||
val: "Lorem ipsum dolor sit amet, consectetur adipisicing eli",
|
||||
output: "B74C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E7365637465747572206164697069736963696E6720656C69",
|
||||
},
|
||||
{
|
||||
val: "Lorem ipsum dolor sit amet, consectetur adipisicing elit",
|
||||
output: "B8384C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E7365637465747572206164697069736963696E6720656C6974",
|
||||
},
|
||||
{
|
||||
val: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur mauris magna, suscipit sed vehicula non, iaculis faucibus tortor. Proin suscipit ultricies malesuada. Duis tortor elit, dictum quis tristique eu, ultrices at risus. Morbi a est imperdiet mi ullamcorper aliquet suscipit nec lorem. Aenean quis leo mollis, vulputate elit varius, consequat enim. Nulla ultrices turpis justo, et posuere urna consectetur nec. Proin non convallis metus. Donec tempor ipsum in mauris congue sollicitudin. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse convallis sem vel massa faucibus, eget lacinia lacus tempor. Nulla quis ultricies purus. Proin auctor rhoncus nibh condimentum mollis. Aliquam consequat enim at metus luctus, a eleifend purus egestas. Curabitur at nibh metus. Nam bibendum, neque at auctor tristique, lorem libero aliquet arcu, non interdum tellus lectus sit amet eros. Cras rhoncus, metus ac ornare cursus, dolor justo ultrices metus, at ullamcorper volutpat",
|
||||
output: "B904004C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E73656374657475722061646970697363696E6720656C69742E20437572616269747572206D6175726973206D61676E612C20737573636970697420736564207665686963756C61206E6F6E2C20696163756C697320666175636962757320746F72746F722E2050726F696E20737573636970697420756C74726963696573206D616C6573756164612E204475697320746F72746F7220656C69742C2064696374756D2071756973207472697374697175652065752C20756C7472696365732061742072697375732E204D6F72626920612065737420696D70657264696574206D6920756C6C616D636F7270657220616C6971756574207375736369706974206E6563206C6F72656D2E2041656E65616E2071756973206C656F206D6F6C6C69732C2076756C70757461746520656C6974207661726975732C20636F6E73657175617420656E696D2E204E756C6C6120756C74726963657320747572706973206A7573746F2C20657420706F73756572652075726E6120636F6E7365637465747572206E65632E2050726F696E206E6F6E20636F6E76616C6C6973206D657475732E20446F6E65632074656D706F7220697073756D20696E206D617572697320636F6E67756520736F6C6C696369747564696E2E20566573746962756C756D20616E746520697073756D207072696D697320696E206661756369627573206F726369206C756374757320657420756C74726963657320706F737565726520637562696C69612043757261653B2053757370656E646973736520636F6E76616C6C69732073656D2076656C206D617373612066617563696275732C2065676574206C6163696E6961206C616375732074656D706F722E204E756C6C61207175697320756C747269636965732070757275732E2050726F696E20617563746F722072686F6E637573206E69626820636F6E64696D656E74756D206D6F6C6C69732E20416C697175616D20636F6E73657175617420656E696D206174206D65747573206C75637475732C206120656C656966656E6420707572757320656765737461732E20437572616269747572206174206E696268206D657475732E204E616D20626962656E64756D2C206E6571756520617420617563746F72207472697374697175652C206C6F72656D206C696265726F20616C697175657420617263752C206E6F6E20696E74657264756D2074656C6C7573206C65637475732073697420616D65742065726F732E20437261732072686F6E6375732C206D65747573206163206F726E617265206375727375732C20646F6C6F72206A7573746F20756C747269636573206D657475732C20617420756C6C616D636F7270657220766F6C7574706174",
|
||||
},
|
||||
|
||||
// slices
|
||||
{val: []uint{}, output: "C0"},
|
||||
{val: []uint{1, 2, 3}, output: "C3010203"},
|
||||
{
|
||||
// [ [], [[]], [ [], [[]] ] ]
|
||||
val: []interface{}{[]interface{}{}, [][]interface{}{{}}, []interface{}{[]interface{}{}, [][]interface{}{{}}}},
|
||||
output: "C7C0C1C0C3C0C1C0",
|
||||
},
|
||||
{
|
||||
val: []string{"aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo"},
|
||||
output: "F83C836161618362626283636363836464648365656583666666836767678368686883696969836A6A6A836B6B6B836C6C6C836D6D6D836E6E6E836F6F6F",
|
||||
},
|
||||
{
|
||||
val: []interface{}{uint(1), uint(0xFFFFFF), []interface{}{[]uint{4, 5, 5}}, "abc"},
|
||||
output: "CE0183FFFFFFC4C304050583616263",
|
||||
},
|
||||
{
|
||||
val: [][]string{
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
{"asdf", "qwer", "zxcv"},
|
||||
},
|
||||
output: "F90200CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376",
|
||||
},
|
||||
|
||||
// RawValue
|
||||
{val: RawValue(unhex("01")), output: "01"},
|
||||
{val: RawValue(unhex("82FFFF")), output: "82FFFF"},
|
||||
{val: []RawValue{unhex("01"), unhex("02")}, output: "C20102"},
|
||||
|
||||
// structs
|
||||
{val: simplestruct{}, output: "C28080"},
|
||||
{val: simplestruct{A: 3, B: "foo"}, output: "C50383666F6F"},
|
||||
{val: &recstruct{5, nil}, output: "C205C0"},
|
||||
{val: &recstruct{5, &recstruct{4, &recstruct{3, nil}}}, output: "C605C404C203C0"},
|
||||
{val: &intField{X: 3}, error: "rlp: type int is not RLP-serializable (struct field rlp.intField.X)"},
|
||||
|
||||
// struct tag "-"
|
||||
{val: &ignoredField{A: 1, B: 2, C: 3}, output: "C20103"},
|
||||
|
||||
// struct tag "tail"
|
||||
{val: &tailRaw{A: 1, Tail: []RawValue{unhex("02"), unhex("03")}}, output: "C3010203"},
|
||||
{val: &tailRaw{A: 1, Tail: []RawValue{unhex("02")}}, output: "C20102"},
|
||||
{val: &tailRaw{A: 1, Tail: []RawValue{}}, output: "C101"},
|
||||
{val: &tailRaw{A: 1, Tail: nil}, output: "C101"},
|
||||
|
||||
// struct tag "optional"
|
||||
{val: &optionalFields{}, output: "C180"},
|
||||
{val: &optionalFields{A: 1}, output: "C101"},
|
||||
{val: &optionalFields{A: 1, B: 2}, output: "C20102"},
|
||||
{val: &optionalFields{A: 1, B: 2, C: 3}, output: "C3010203"},
|
||||
{val: &optionalFields{A: 1, B: 0, C: 3}, output: "C3018003"},
|
||||
{val: &optionalAndTailField{A: 1}, output: "C101"},
|
||||
{val: &optionalAndTailField{A: 1, B: 2}, output: "C20102"},
|
||||
{val: &optionalAndTailField{A: 1, Tail: []uint{5, 6}}, output: "C401800506"},
|
||||
{val: &optionalAndTailField{A: 1, Tail: []uint{5, 6}}, output: "C401800506"},
|
||||
{val: &optionalBigIntField{A: 1}, output: "C101"},
|
||||
{val: &optionalPtrField{A: 1}, output: "C101"},
|
||||
{val: &optionalPtrFieldNil{A: 1}, output: "C101"},
|
||||
|
||||
// nil
|
||||
{val: (*uint)(nil), output: "80"},
|
||||
{val: (*string)(nil), output: "80"},
|
||||
{val: (*[]byte)(nil), output: "80"},
|
||||
{val: (*[10]byte)(nil), output: "80"},
|
||||
{val: (*big.Int)(nil), output: "80"},
|
||||
{val: (*[]string)(nil), output: "C0"},
|
||||
{val: (*[10]string)(nil), output: "C0"},
|
||||
{val: (*[]interface{})(nil), output: "C0"},
|
||||
{val: (*[]struct{ uint })(nil), output: "C0"},
|
||||
{val: (*interface{})(nil), output: "C0"},
|
||||
|
||||
// nil struct fields
|
||||
{
|
||||
val: struct {
|
||||
X *[]byte
|
||||
}{},
|
||||
output: "C180",
|
||||
},
|
||||
{
|
||||
val: struct {
|
||||
X *[2]byte
|
||||
}{},
|
||||
output: "C180",
|
||||
},
|
||||
{
|
||||
val: struct {
|
||||
X *uint64
|
||||
}{},
|
||||
output: "C180",
|
||||
},
|
||||
{
|
||||
val: struct {
|
||||
X *uint64 `rlp:"nilList"`
|
||||
}{},
|
||||
output: "C1C0",
|
||||
},
|
||||
{
|
||||
val: struct {
|
||||
X *[]uint64
|
||||
}{},
|
||||
output: "C1C0",
|
||||
},
|
||||
{
|
||||
val: struct {
|
||||
X *[]uint64 `rlp:"nilString"`
|
||||
}{},
|
||||
output: "C180",
|
||||
},
|
||||
|
||||
// interfaces
|
||||
{val: []io.Reader{reader}, output: "C3C20102"}, // the contained value is a struct
|
||||
|
||||
// Encoder
|
||||
{val: (*testEncoder)(nil), output: "C0"},
|
||||
{val: &testEncoder{}, output: "00010001000100010001"},
|
||||
{val: &testEncoder{errors.New("test error")}, error: "test error"},
|
||||
{val: struct{ E testEncoderValueMethod }{}, output: "C3FAFEF0"},
|
||||
{val: struct{ E *testEncoderValueMethod }{}, output: "C1C0"},
|
||||
|
||||
// Verify that the Encoder interface works for unsupported types like func().
|
||||
{val: undecodableEncoder(func() {}), output: "F5F5F5"},
|
||||
|
||||
// Verify that pointer method testEncoder.EncodeRLP is called for
|
||||
// addressable non-pointer values.
|
||||
{val: &struct{ TE testEncoder }{testEncoder{}}, output: "CA00010001000100010001"},
|
||||
{val: &struct{ TE testEncoder }{testEncoder{errors.New("test error")}}, error: "test error"},
|
||||
|
||||
// Verify the error for non-addressable non-pointer Encoder.
|
||||
{val: testEncoder{}, error: "rlp: unadressable value of type rlp.testEncoder, EncodeRLP is pointer method"},
|
||||
|
||||
// Verify Encoder takes precedence over []byte.
|
||||
{val: []byteEncoder{0, 1, 2, 3, 4}, output: "C5C0C0C0C0C0"},
|
||||
}
|
||||
|
||||
func runEncTests(t *testing.T, f func(val interface{}) ([]byte, error)) {
|
||||
for i, test := range encTests {
|
||||
output, err := f(test.val)
|
||||
if err != nil && test.error == "" {
|
||||
t.Errorf("test %d: unexpected error: %v\nvalue %#v\ntype %T",
|
||||
i, err, test.val, test.val)
|
||||
continue
|
||||
}
|
||||
if test.error != "" && fmt.Sprint(err) != test.error {
|
||||
t.Errorf("test %d: error mismatch\ngot %v\nwant %v\nvalue %#v\ntype %T",
|
||||
i, err, test.error, test.val, test.val)
|
||||
continue
|
||||
}
|
||||
if err == nil && !bytes.Equal(output, unhex(test.output)) {
|
||||
t.Errorf("test %d: output mismatch:\ngot %X\nwant %s\nvalue %#v\ntype %T",
|
||||
i, output, test.output, test.val, test.val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
runEncTests(t, func(val interface{}) ([]byte, error) {
|
||||
b := new(bytes.Buffer)
|
||||
err := Encode(b, val)
|
||||
return b.Bytes(), err
|
||||
})
|
||||
}
|
||||
|
||||
func TestEncodeToBytes(t *testing.T) {
|
||||
runEncTests(t, EncodeToBytes)
|
||||
}
|
||||
|
||||
func TestEncodeToReader(t *testing.T) {
|
||||
runEncTests(t, func(val interface{}) ([]byte, error) {
|
||||
_, r, err := EncodeToReader(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.ReadAll(r)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEncodeToReaderPiecewise(t *testing.T) {
|
||||
runEncTests(t, func(val interface{}) ([]byte, error) {
|
||||
size, r, err := EncodeToReader(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// read output piecewise
|
||||
output := make([]byte, size)
|
||||
for start, end := 0, 0; start < size; start = end {
|
||||
if remaining := size - start; remaining < 3 {
|
||||
end += remaining
|
||||
} else {
|
||||
end = start + 3
|
||||
}
|
||||
n, err := r.Read(output[start:end])
|
||||
end = start + n
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return output, nil
|
||||
})
|
||||
}
|
||||
|
||||
// This is a regression test verifying that encReader
|
||||
// returns its encbuf to the pool only once.
|
||||
func TestEncodeToReaderReturnToPool(t *testing.T) {
|
||||
buf := make([]byte, 50)
|
||||
wg := new(sync.WaitGroup)
|
||||
for i := 0; i < 5; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
for i := 0; i < 1000; i++ {
|
||||
_, r, _ := EncodeToReader("foo")
|
||||
ioutil.ReadAll(r)
|
||||
r.Read(buf)
|
||||
r.Read(buf)
|
||||
r.Read(buf)
|
||||
r.Read(buf)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
var sink interface{}
|
||||
|
||||
func BenchmarkIntsize(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
sink = intsize(0x12345678)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPutint(b *testing.B) {
|
||||
buf := make([]byte, 8)
|
||||
for i := 0; i < b.N; i++ {
|
||||
putint(buf, 0x12345678)
|
||||
sink = buf
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeBigInts(b *testing.B) {
|
||||
ints := make([]*big.Int, 200)
|
||||
for i := range ints {
|
||||
ints[i] = new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(i)), nil)
|
||||
}
|
||||
out := bytes.NewBuffer(make([]byte, 0, 4096))
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
out.Reset()
|
||||
if err := Encode(out, ints); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeConcurrentInterface(b *testing.B) {
|
||||
type struct1 struct {
|
||||
A string
|
||||
B *big.Int
|
||||
C [20]byte
|
||||
}
|
||||
value := []interface{}{
|
||||
uint(999),
|
||||
&struct1{A: "hello", B: big.NewInt(0xFFFFFFFF)},
|
||||
[10]byte{1, 2, 3, 4, 5, 6},
|
||||
[]string{"yeah", "yeah", "yeah"},
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for cpu := 0; cpu < runtime.NumCPU(); cpu++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
var buffer bytes.Buffer
|
||||
for i := 0; i < b.N; i++ {
|
||||
buffer.Reset()
|
||||
err := Encode(&buffer, value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
type byteArrayStruct struct {
|
||||
A [20]byte
|
||||
B [32]byte
|
||||
C [32]byte
|
||||
}
|
||||
|
||||
func BenchmarkEncodeByteArrayStruct(b *testing.B) {
|
||||
var out bytes.Buffer
|
||||
var value byteArrayStruct
|
||||
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
out.Reset()
|
||||
if err := Encode(&out, &value); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
46
restricted/rlp/encoder_example_test.go
Normal file
46
restricted/rlp/encoder_example_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rlp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type MyCoolType struct {
|
||||
Name string
|
||||
a, b uint
|
||||
}
|
||||
|
||||
// EncodeRLP writes x as RLP list [a, b] that omits the Name field.
|
||||
func (x *MyCoolType) EncodeRLP(w io.Writer) (err error) {
|
||||
return Encode(w, []uint{x.a, x.b})
|
||||
}
|
||||
|
||||
func ExampleEncoder() {
|
||||
var t *MyCoolType // t is nil pointer to MyCoolType
|
||||
bytes, _ := EncodeToBytes(t)
|
||||
fmt.Printf("%v → %X\n", t, bytes)
|
||||
|
||||
t = &MyCoolType{Name: "foobar", a: 5, b: 6}
|
||||
bytes, _ = EncodeToBytes(t)
|
||||
fmt.Printf("%v → %X\n", t, bytes)
|
||||
|
||||
// Output:
|
||||
// <nil> → C0
|
||||
// &{foobar 5 6} → C20506
|
||||
}
|
61
restricted/rlp/iterator.go
Normal file
61
restricted/rlp/iterator.go
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rlp
|
||||
|
||||
type listIterator struct {
|
||||
data []byte
|
||||
next []byte
|
||||
err error
|
||||
}
|
||||
|
||||
// NewListIterator creates an iterator for the (list) represented by data
|
||||
// TODO: Consider removing this implementation, as it is no longer used.
|
||||
func NewListIterator(data RawValue) (*listIterator, error) {
|
||||
k, t, c, err := readKind(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if k != List {
|
||||
return nil, ErrExpectedList
|
||||
}
|
||||
it := &listIterator{
|
||||
data: data[t : t+c],
|
||||
}
|
||||
return it, nil
|
||||
|
||||
}
|
||||
|
||||
// Next forwards the iterator one step, returns true if it was not at end yet
|
||||
func (it *listIterator) Next() bool {
|
||||
if len(it.data) == 0 {
|
||||
return false
|
||||
}
|
||||
_, t, c, err := readKind(it.data)
|
||||
it.next = it.data[:t+c]
|
||||
it.data = it.data[t+c:]
|
||||
it.err = err
|
||||
return true
|
||||
}
|
||||
|
||||
// Value returns the current value
|
||||
func (it *listIterator) Value() []byte {
|
||||
return it.next
|
||||
}
|
||||
|
||||
func (it *listIterator) Err() error {
|
||||
return it.err
|
||||
}
|
59
restricted/rlp/iterator_test.go
Normal file
59
restricted/rlp/iterator_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rlp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/openrelayxyz/plugeth-utils/restricted/hexutil"
|
||||
)
|
||||
|
||||
// TestIterator tests some basic things about the ListIterator. A more
|
||||
// comprehensive test can be found in core/rlp_test.go, where we can
|
||||
// use both types and rlp without dependency cycles
|
||||
func TestIterator(t *testing.T) {
|
||||
bodyRlpHex := "0xf902cbf8d6f869800182c35094000000000000000000000000000000000000aaaa808a000000000000000000001ba01025c66fad28b4ce3370222624d952c35529e602af7cbe04f667371f61b0e3b3a00ab8813514d1217059748fd903288ace1b4001a4bc5fbde2790debdc8167de2ff869010182c35094000000000000000000000000000000000000aaaa808a000000000000000000001ca05ac4cf1d19be06f3742c21df6c49a7e929ceb3dbaf6a09f3cfb56ff6828bd9a7a06875970133a35e63ac06d360aa166d228cc013e9b96e0a2cae7f55b22e1ee2e8f901f0f901eda0c75448377c0e426b8017b23c5f77379ecf69abc1d5c224284ad3ba1c46c59adaa00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808080808080a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
|
||||
bodyRlp := hexutil.MustDecode(bodyRlpHex)
|
||||
|
||||
it, err := NewListIterator(bodyRlp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Check that txs exist
|
||||
if !it.Next() {
|
||||
t.Fatal("expected two elems, got zero")
|
||||
}
|
||||
txs := it.Value()
|
||||
// Check that uncles exist
|
||||
if !it.Next() {
|
||||
t.Fatal("expected two elems, got one")
|
||||
}
|
||||
txit, err := NewListIterator(txs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var i = 0
|
||||
for txit.Next() {
|
||||
if txit.err != nil {
|
||||
t.Fatal(txit.err)
|
||||
}
|
||||
i++
|
||||
}
|
||||
if exp := 2; i != exp {
|
||||
t.Errorf("count wrong, expected %d got %d", i, exp)
|
||||
}
|
||||
}
|
261
restricted/rlp/raw.go
Normal file
261
restricted/rlp/raw.go
Normal file
@ -0,0 +1,261 @@
|
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rlp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// RawValue represents an encoded RLP value and can be used to delay
|
||||
// RLP decoding or to precompute an encoding. Note that the decoder does
|
||||
// not verify whether the content of RawValues is valid RLP.
|
||||
type RawValue []byte
|
||||
|
||||
var rawValueType = reflect.TypeOf(RawValue{})
|
||||
|
||||
// ListSize returns the encoded size of an RLP list with the given
|
||||
// content size.
|
||||
func ListSize(contentSize uint64) uint64 {
|
||||
return uint64(headsize(contentSize)) + contentSize
|
||||
}
|
||||
|
||||
// IntSize returns the encoded size of the integer x.
|
||||
func IntSize(x uint64) int {
|
||||
if x < 0x80 {
|
||||
return 1
|
||||
}
|
||||
return 1 + intsize(x)
|
||||
}
|
||||
|
||||
// Split returns the content of first RLP value and any
|
||||
// bytes after the value as subslices of b.
|
||||
func Split(b []byte) (k Kind, content, rest []byte, err error) {
|
||||
k, ts, cs, err := readKind(b)
|
||||
if err != nil {
|
||||
return 0, nil, b, err
|
||||
}
|
||||
return k, b[ts : ts+cs], b[ts+cs:], nil
|
||||
}
|
||||
|
||||
// SplitString splits b into the content of an RLP string
|
||||
// and any remaining bytes after the string.
|
||||
func SplitString(b []byte) (content, rest []byte, err error) {
|
||||
k, content, rest, err := Split(b)
|
||||
if err != nil {
|
||||
return nil, b, err
|
||||
}
|
||||
if k == List {
|
||||
return nil, b, ErrExpectedString
|
||||
}
|
||||
return content, rest, nil
|
||||
}
|
||||
|
||||
// SplitUint64 decodes an integer at the beginning of b.
|
||||
// It also returns the remaining data after the integer in 'rest'.
|
||||
func SplitUint64(b []byte) (x uint64, rest []byte, err error) {
|
||||
content, rest, err := SplitString(b)
|
||||
if err != nil {
|
||||
return 0, b, err
|
||||
}
|
||||
switch {
|
||||
case len(content) == 0:
|
||||
return 0, rest, nil
|
||||
case len(content) == 1:
|
||||
if content[0] == 0 {
|
||||
return 0, b, ErrCanonInt
|
||||
}
|
||||
return uint64(content[0]), rest, nil
|
||||
case len(content) > 8:
|
||||
return 0, b, errUintOverflow
|
||||
default:
|
||||
x, err = readSize(content, byte(len(content)))
|
||||
if err != nil {
|
||||
return 0, b, ErrCanonInt
|
||||
}
|
||||
return x, rest, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SplitList splits b into the content of a list and any remaining
|
||||
// bytes after the list.
|
||||
func SplitList(b []byte) (content, rest []byte, err error) {
|
||||
k, content, rest, err := Split(b)
|
||||
if err != nil {
|
||||
return nil, b, err
|
||||
}
|
||||
if k != List {
|
||||
return nil, b, ErrExpectedList
|
||||
}
|
||||
return content, rest, nil
|
||||
}
|
||||
|
||||
// CountValues counts the number of encoded values in b.
|
||||
func CountValues(b []byte) (int, error) {
|
||||
i := 0
|
||||
for ; len(b) > 0; i++ {
|
||||
_, tagsize, size, err := readKind(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
b = b[tagsize+size:]
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func readKind(buf []byte) (k Kind, tagsize, contentsize uint64, err error) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0, 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := buf[0]
|
||||
switch {
|
||||
case b < 0x80:
|
||||
k = Byte
|
||||
tagsize = 0
|
||||
contentsize = 1
|
||||
case b < 0xB8:
|
||||
k = String
|
||||
tagsize = 1
|
||||
contentsize = uint64(b - 0x80)
|
||||
// Reject strings that should've been single bytes.
|
||||
if contentsize == 1 && len(buf) > 1 && buf[1] < 128 {
|
||||
return 0, 0, 0, ErrCanonSize
|
||||
}
|
||||
case b < 0xC0:
|
||||
k = String
|
||||
tagsize = uint64(b-0xB7) + 1
|
||||
contentsize, err = readSize(buf[1:], b-0xB7)
|
||||
case b < 0xF8:
|
||||
k = List
|
||||
tagsize = 1
|
||||
contentsize = uint64(b - 0xC0)
|
||||
default:
|
||||
k = List
|
||||
tagsize = uint64(b-0xF7) + 1
|
||||
contentsize, err = readSize(buf[1:], b-0xF7)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
// Reject values larger than the input slice.
|
||||
if contentsize > uint64(len(buf))-tagsize {
|
||||
return 0, 0, 0, ErrValueTooLarge
|
||||
}
|
||||
return k, tagsize, contentsize, err
|
||||
}
|
||||
|
||||
func readSize(b []byte, slen byte) (uint64, error) {
|
||||
if int(slen) > len(b) {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
var s uint64
|
||||
switch slen {
|
||||
case 1:
|
||||
s = uint64(b[0])
|
||||
case 2:
|
||||
s = uint64(b[0])<<8 | uint64(b[1])
|
||||
case 3:
|
||||
s = uint64(b[0])<<16 | uint64(b[1])<<8 | uint64(b[2])
|
||||
case 4:
|
||||
s = uint64(b[0])<<24 | uint64(b[1])<<16 | uint64(b[2])<<8 | uint64(b[3])
|
||||
case 5:
|
||||
s = uint64(b[0])<<32 | uint64(b[1])<<24 | uint64(b[2])<<16 | uint64(b[3])<<8 | uint64(b[4])
|
||||
case 6:
|
||||
s = uint64(b[0])<<40 | uint64(b[1])<<32 | uint64(b[2])<<24 | uint64(b[3])<<16 | uint64(b[4])<<8 | uint64(b[5])
|
||||
case 7:
|
||||
s = uint64(b[0])<<48 | uint64(b[1])<<40 | uint64(b[2])<<32 | uint64(b[3])<<24 | uint64(b[4])<<16 | uint64(b[5])<<8 | uint64(b[6])
|
||||
case 8:
|
||||
s = uint64(b[0])<<56 | uint64(b[1])<<48 | uint64(b[2])<<40 | uint64(b[3])<<32 | uint64(b[4])<<24 | uint64(b[5])<<16 | uint64(b[6])<<8 | uint64(b[7])
|
||||
}
|
||||
// Reject sizes < 56 (shouldn't have separate size) and sizes with
|
||||
// leading zero bytes.
|
||||
if s < 56 || b[0] == 0 {
|
||||
return 0, ErrCanonSize
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// AppendUint64 appends the RLP encoding of i to b, and returns the resulting slice.
|
||||
func AppendUint64(b []byte, i uint64) []byte {
|
||||
if i == 0 {
|
||||
return append(b, 0x80)
|
||||
} else if i < 128 {
|
||||
return append(b, byte(i))
|
||||
}
|
||||
switch {
|
||||
case i < (1 << 8):
|
||||
return append(b, 0x81, byte(i))
|
||||
case i < (1 << 16):
|
||||
return append(b, 0x82,
|
||||
byte(i>>8),
|
||||
byte(i),
|
||||
)
|
||||
case i < (1 << 24):
|
||||
return append(b, 0x83,
|
||||
byte(i>>16),
|
||||
byte(i>>8),
|
||||
byte(i),
|
||||
)
|
||||
case i < (1 << 32):
|
||||
return append(b, 0x84,
|
||||
byte(i>>24),
|
||||
byte(i>>16),
|
||||
byte(i>>8),
|
||||
byte(i),
|
||||
)
|
||||
case i < (1 << 40):
|
||||
return append(b, 0x85,
|
||||
byte(i>>32),
|
||||
byte(i>>24),
|
||||
byte(i>>16),
|
||||
byte(i>>8),
|
||||
byte(i),
|
||||
)
|
||||
|
||||
case i < (1 << 48):
|
||||
return append(b, 0x86,
|
||||
byte(i>>40),
|
||||
byte(i>>32),
|
||||
byte(i>>24),
|
||||
byte(i>>16),
|
||||
byte(i>>8),
|
||||
byte(i),
|
||||
)
|
||||
case i < (1 << 56):
|
||||
return append(b, 0x87,
|
||||
byte(i>>48),
|
||||
byte(i>>40),
|
||||
byte(i>>32),
|
||||
byte(i>>24),
|
||||
byte(i>>16),
|
||||
byte(i>>8),
|
||||
byte(i),
|
||||
)
|
||||
|
||||
default:
|
||||
return append(b, 0x88,
|
||||
byte(i>>56),
|
||||
byte(i>>48),
|
||||
byte(i>>40),
|
||||
byte(i>>32),
|
||||
byte(i>>24),
|
||||
byte(i>>16),
|
||||
byte(i>>8),
|
||||
byte(i),
|
||||
)
|
||||
}
|
||||
}
|
285
restricted/rlp/raw_test.go
Normal file
285
restricted/rlp/raw_test.go
Normal file
@ -0,0 +1,285 @@
|
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rlp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"reflect"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
)
|
||||
|
||||
func TestCountValues(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string // note: spaces in input are stripped by unhex
|
||||
count int
|
||||
err error
|
||||
}{
|
||||
// simple cases
|
||||
{"", 0, nil},
|
||||
{"00", 1, nil},
|
||||
{"80", 1, nil},
|
||||
{"C0", 1, nil},
|
||||
{"01 02 03", 3, nil},
|
||||
{"01 C406070809 02", 3, nil},
|
||||
{"820101 820202 8403030303 04", 4, nil},
|
||||
|
||||
// size errors
|
||||
{"8142", 0, ErrCanonSize},
|
||||
{"01 01 8142", 0, ErrCanonSize},
|
||||
{"02 84020202", 0, ErrValueTooLarge},
|
||||
|
||||
{
|
||||
input: "A12000BF49F440A1CD0527E4D06E2765654C0F56452257516D793A9B8D604DCFDF2AB853F851808D10000000000000000000000000A056E81F171BCC55A6FF8345E692C0F86E5B48E01B996CADC001622FB5E363B421A0C5D2460186F7233C927E7DB2DCC703C0E500B653CA82273B7BFAD8045D85A470",
|
||||
count: 2,
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
count, err := CountValues(unhex(test.input))
|
||||
if count != test.count {
|
||||
t.Errorf("test %d: count mismatch, got %d want %d\ninput: %s", i, count, test.count, test.input)
|
||||
}
|
||||
if !reflect.DeepEqual(err, test.err) {
|
||||
t.Errorf("test %d: err mismatch, got %q want %q\ninput: %s", i, err, test.err, test.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitTypes(t *testing.T) {
|
||||
if _, _, err := SplitString(unhex("C100")); err != ErrExpectedString {
|
||||
t.Errorf("SplitString returned %q, want %q", err, ErrExpectedString)
|
||||
}
|
||||
if _, _, err := SplitList(unhex("01")); err != ErrExpectedList {
|
||||
t.Errorf("SplitString returned %q, want %q", err, ErrExpectedList)
|
||||
}
|
||||
if _, _, err := SplitList(unhex("81FF")); err != ErrExpectedList {
|
||||
t.Errorf("SplitString returned %q, want %q", err, ErrExpectedList)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitUint64(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
val uint64
|
||||
rest string
|
||||
err error
|
||||
}{
|
||||
{"01", 1, "", nil},
|
||||
{"7FFF", 0x7F, "FF", nil},
|
||||
{"80FF", 0, "FF", nil},
|
||||
{"81FAFF", 0xFA, "FF", nil},
|
||||
{"82FAFAFF", 0xFAFA, "FF", nil},
|
||||
{"83FAFAFAFF", 0xFAFAFA, "FF", nil},
|
||||
{"84FAFAFAFAFF", 0xFAFAFAFA, "FF", nil},
|
||||
{"85FAFAFAFAFAFF", 0xFAFAFAFAFA, "FF", nil},
|
||||
{"86FAFAFAFAFAFAFF", 0xFAFAFAFAFAFA, "FF", nil},
|
||||
{"87FAFAFAFAFAFAFAFF", 0xFAFAFAFAFAFAFA, "FF", nil},
|
||||
{"88FAFAFAFAFAFAFAFAFF", 0xFAFAFAFAFAFAFAFA, "FF", nil},
|
||||
|
||||
// errors
|
||||
{"", 0, "", io.ErrUnexpectedEOF},
|
||||
{"00", 0, "00", ErrCanonInt},
|
||||
{"81", 0, "81", ErrValueTooLarge},
|
||||
{"8100", 0, "8100", ErrCanonSize},
|
||||
{"8200FF", 0, "8200FF", ErrCanonInt},
|
||||
{"8103FF", 0, "8103FF", ErrCanonSize},
|
||||
{"89FAFAFAFAFAFAFAFAFAFF", 0, "89FAFAFAFAFAFAFAFAFAFF", errUintOverflow},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
val, rest, err := SplitUint64(unhex(test.input))
|
||||
if val != test.val {
|
||||
t.Errorf("test %d: val mismatch: got %x, want %x (input %q)", i, val, test.val, test.input)
|
||||
}
|
||||
if !bytes.Equal(rest, unhex(test.rest)) {
|
||||
t.Errorf("test %d: rest mismatch: got %x, want %s (input %q)", i, rest, test.rest, test.input)
|
||||
}
|
||||
if err != test.err {
|
||||
t.Errorf("test %d: error mismatch: got %q, want %q", i, err, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplit(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
kind Kind
|
||||
val, rest string
|
||||
err error
|
||||
}{
|
||||
{input: "00FFFF", kind: Byte, val: "00", rest: "FFFF"},
|
||||
{input: "01FFFF", kind: Byte, val: "01", rest: "FFFF"},
|
||||
{input: "7FFFFF", kind: Byte, val: "7F", rest: "FFFF"},
|
||||
{input: "80FFFF", kind: String, val: "", rest: "FFFF"},
|
||||
{input: "C3010203", kind: List, val: "010203"},
|
||||
|
||||
// errors
|
||||
{input: "", err: io.ErrUnexpectedEOF},
|
||||
|
||||
{input: "8141", err: ErrCanonSize, rest: "8141"},
|
||||
{input: "B800", err: ErrCanonSize, rest: "B800"},
|
||||
{input: "B802FFFF", err: ErrCanonSize, rest: "B802FFFF"},
|
||||
{input: "B90000", err: ErrCanonSize, rest: "B90000"},
|
||||
{input: "B90055", err: ErrCanonSize, rest: "B90055"},
|
||||
{input: "BA0002FFFF", err: ErrCanonSize, rest: "BA0002FFFF"},
|
||||
{input: "F800", err: ErrCanonSize, rest: "F800"},
|
||||
{input: "F90000", err: ErrCanonSize, rest: "F90000"},
|
||||
{input: "F90055", err: ErrCanonSize, rest: "F90055"},
|
||||
{input: "FA0002FFFF", err: ErrCanonSize, rest: "FA0002FFFF"},
|
||||
|
||||
{input: "81", err: ErrValueTooLarge, rest: "81"},
|
||||
{input: "8501010101", err: ErrValueTooLarge, rest: "8501010101"},
|
||||
{input: "C60607080902", err: ErrValueTooLarge, rest: "C60607080902"},
|
||||
|
||||
// size check overflow
|
||||
{input: "BFFFFFFFFFFFFFFFFF", err: ErrValueTooLarge, rest: "BFFFFFFFFFFFFFFFFF"},
|
||||
{input: "FFFFFFFFFFFFFFFFFF", err: ErrValueTooLarge, rest: "FFFFFFFFFFFFFFFFFF"},
|
||||
|
||||
{
|
||||
input: "B838FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
err: ErrValueTooLarge,
|
||||
rest: "B838FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
},
|
||||
{
|
||||
input: "F838FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
err: ErrValueTooLarge,
|
||||
rest: "F838FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
},
|
||||
|
||||
// a few bigger values, just for kicks
|
||||
{
|
||||
input: "F839FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
kind: List,
|
||||
val: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
rest: "",
|
||||
},
|
||||
{
|
||||
input: "F90211A060EF29F20CC1007AE6E9530AEE16F4B31F8F1769A2D1264EC995C6D1241868D6A07C62AB8AC9838F5F5877B20BB37B387BC2106E97A3D52172CBEDB5EE17C36008A00EAB6B7324AADC0F6047C6AFC8229F09F7CF451B51D67C8DFB08D49BA8C3C626A04453343B2F3A6E42FCF87948F88AF7C8FC16D0C2735CBA7F026836239AB2C15FA024635C7291C882CE4C0763760C1A362DFC3FFCD802A55722236DE058D74202ACA0A220C808DE10F55E40AB25255201CFF009EA181D3906638E944EE2BF34049984A08D325AB26796F1CCB470F69C0F842501DC35D368A0C2575B2D243CFD1E8AB0FDA0B5298FF60DA5069463D610513C9F04F24051348391A143AFFAB7197DFACDEA72A02D2A7058A4463F8FB69378369E11EF33AE3252E2DB86CB545B36D3C26DDECE5AA0888F97BCA8E0BD83DC5B3B91CFF5FAF2F66F9501010682D67EF4A3B4E66115FBA0E8175A60C93BE9ED02921958F0EA55DA0FB5E4802AF5846147BAD92BC2D8AF26A08B3376FF433F3A4250FA64B7F804004CAC5807877D91C4427BD1CD05CF912ED8A09B32EF0F03BD13C37FF950C0CCCEFCCDD6669F2E7F2AA5CB859928E84E29763EA09BBA5E46610C8C8B1F8E921E5691BF8C7E40D75825D5EA3217AA9C3A8A355F39A0EEB95BC78251CCCEC54A97F19755C4A59A293544EEE6119AFA50531211E53C4FA00B6E86FE150BF4A9E0FEEE9C90F5465E617A861BB5E357F942881EE762212E2580",
|
||||
kind: List,
|
||||
val: "A060EF29F20CC1007AE6E9530AEE16F4B31F8F1769A2D1264EC995C6D1241868D6A07C62AB8AC9838F5F5877B20BB37B387BC2106E97A3D52172CBEDB5EE17C36008A00EAB6B7324AADC0F6047C6AFC8229F09F7CF451B51D67C8DFB08D49BA8C3C626A04453343B2F3A6E42FCF87948F88AF7C8FC16D0C2735CBA7F026836239AB2C15FA024635C7291C882CE4C0763760C1A362DFC3FFCD802A55722236DE058D74202ACA0A220C808DE10F55E40AB25255201CFF009EA181D3906638E944EE2BF34049984A08D325AB26796F1CCB470F69C0F842501DC35D368A0C2575B2D243CFD1E8AB0FDA0B5298FF60DA5069463D610513C9F04F24051348391A143AFFAB7197DFACDEA72A02D2A7058A4463F8FB69378369E11EF33AE3252E2DB86CB545B36D3C26DDECE5AA0888F97BCA8E0BD83DC5B3B91CFF5FAF2F66F9501010682D67EF4A3B4E66115FBA0E8175A60C93BE9ED02921958F0EA55DA0FB5E4802AF5846147BAD92BC2D8AF26A08B3376FF433F3A4250FA64B7F804004CAC5807877D91C4427BD1CD05CF912ED8A09B32EF0F03BD13C37FF950C0CCCEFCCDD6669F2E7F2AA5CB859928E84E29763EA09BBA5E46610C8C8B1F8E921E5691BF8C7E40D75825D5EA3217AA9C3A8A355F39A0EEB95BC78251CCCEC54A97F19755C4A59A293544EEE6119AFA50531211E53C4FA00B6E86FE150BF4A9E0FEEE9C90F5465E617A861BB5E357F942881EE762212E2580",
|
||||
rest: "",
|
||||
},
|
||||
{
|
||||
input: "F877A12000BF49F440A1CD0527E4D06E2765654C0F56452257516D793A9B8D604DCFDF2AB853F851808D10000000000000000000000000A056E81F171BCC55A6FF8345E692C0F86E5B48E01B996CADC001622FB5E363B421A0C5D2460186F7233C927E7DB2DCC703C0E500B653CA82273B7BFAD8045D85A470",
|
||||
kind: List,
|
||||
val: "A12000BF49F440A1CD0527E4D06E2765654C0F56452257516D793A9B8D604DCFDF2AB853F851808D10000000000000000000000000A056E81F171BCC55A6FF8345E692C0F86E5B48E01B996CADC001622FB5E363B421A0C5D2460186F7233C927E7DB2DCC703C0E500B653CA82273B7BFAD8045D85A470",
|
||||
rest: "",
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
kind, val, rest, err := Split(unhex(test.input))
|
||||
if kind != test.kind {
|
||||
t.Errorf("test %d: kind mismatch: got %v, want %v", i, kind, test.kind)
|
||||
}
|
||||
if !bytes.Equal(val, unhex(test.val)) {
|
||||
t.Errorf("test %d: val mismatch: got %x, want %s", i, val, test.val)
|
||||
}
|
||||
if !bytes.Equal(rest, unhex(test.rest)) {
|
||||
t.Errorf("test %d: rest mismatch: got %x, want %s", i, rest, test.rest)
|
||||
}
|
||||
if err != test.err {
|
||||
t.Errorf("test %d: error mismatch: got %q, want %q", i, err, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadSize(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
slen byte
|
||||
size uint64
|
||||
err error
|
||||
}{
|
||||
{input: "", slen: 1, err: io.ErrUnexpectedEOF},
|
||||
{input: "FF", slen: 2, err: io.ErrUnexpectedEOF},
|
||||
{input: "00", slen: 1, err: ErrCanonSize},
|
||||
{input: "36", slen: 1, err: ErrCanonSize},
|
||||
{input: "37", slen: 1, err: ErrCanonSize},
|
||||
{input: "38", slen: 1, size: 0x38},
|
||||
{input: "FF", slen: 1, size: 0xFF},
|
||||
{input: "FFFF", slen: 2, size: 0xFFFF},
|
||||
{input: "FFFFFF", slen: 3, size: 0xFFFFFF},
|
||||
{input: "FFFFFFFF", slen: 4, size: 0xFFFFFFFF},
|
||||
{input: "FFFFFFFFFF", slen: 5, size: 0xFFFFFFFFFF},
|
||||
{input: "FFFFFFFFFFFF", slen: 6, size: 0xFFFFFFFFFFFF},
|
||||
{input: "FFFFFFFFFFFFFF", slen: 7, size: 0xFFFFFFFFFFFFFF},
|
||||
{input: "FFFFFFFFFFFFFFFF", slen: 8, size: 0xFFFFFFFFFFFFFFFF},
|
||||
{input: "0102", slen: 2, size: 0x0102},
|
||||
{input: "010203", slen: 3, size: 0x010203},
|
||||
{input: "01020304", slen: 4, size: 0x01020304},
|
||||
{input: "0102030405", slen: 5, size: 0x0102030405},
|
||||
{input: "010203040506", slen: 6, size: 0x010203040506},
|
||||
{input: "01020304050607", slen: 7, size: 0x01020304050607},
|
||||
{input: "0102030405060708", slen: 8, size: 0x0102030405060708},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
size, err := readSize(unhex(test.input), test.slen)
|
||||
if err != test.err {
|
||||
t.Errorf("readSize(%s, %d): error mismatch: got %q, want %q", test.input, test.slen, err, test.err)
|
||||
continue
|
||||
}
|
||||
if size != test.size {
|
||||
t.Errorf("readSize(%s, %d): size mismatch: got %#x, want %#x", test.input, test.slen, size, test.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendUint64(t *testing.T) {
|
||||
tests := []struct {
|
||||
input uint64
|
||||
slice []byte
|
||||
output string
|
||||
}{
|
||||
{0, nil, "80"},
|
||||
{1, nil, "01"},
|
||||
{2, nil, "02"},
|
||||
{127, nil, "7F"},
|
||||
{128, nil, "8180"},
|
||||
{129, nil, "8181"},
|
||||
{0xFFFFFF, nil, "83FFFFFF"},
|
||||
{127, []byte{1, 2, 3}, "0102037F"},
|
||||
{0xFFFFFF, []byte{1, 2, 3}, "01020383FFFFFF"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
x := AppendUint64(test.slice, test.input)
|
||||
if !bytes.Equal(x, unhex(test.output)) {
|
||||
t.Errorf("AppendUint64(%v, %d): got %x, want %s", test.slice, test.input, x, test.output)
|
||||
}
|
||||
|
||||
// Check that IntSize returns the appended size.
|
||||
length := len(x) - len(test.slice)
|
||||
if s := IntSize(test.input); s != length {
|
||||
t.Errorf("IntSize(%d): got %d, want %d", test.input, s, length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendUint64Random(t *testing.T) {
|
||||
fn := func(i uint64) bool {
|
||||
enc, _ := EncodeToBytes(i)
|
||||
encAppend := AppendUint64(nil, i)
|
||||
return bytes.Equal(enc, encAppend)
|
||||
}
|
||||
config := quick.Config{MaxCountScale: 50}
|
||||
if err := quick.Check(fn, &config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
26
restricted/rlp/safe.go
Normal file
26
restricted/rlp/safe.go
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2021 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build nacl js !cgo
|
||||
|
||||
package rlp
|
||||
|
||||
import "reflect"
|
||||
|
||||
// byteArrayBytes returns a slice of the byte array v.
|
||||
func byteArrayBytes(v reflect.Value) []byte {
|
||||
return v.Slice(0, v.Len()).Bytes()
|
||||
}
|
283
restricted/rlp/typecache.go
Normal file
283
restricted/rlp/typecache.go
Normal file
@ -0,0 +1,283 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rlp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// typeinfo is an entry in the type cache.
|
||||
type typeinfo struct {
|
||||
decoder decoder
|
||||
decoderErr error // error from makeDecoder
|
||||
writer writer
|
||||
writerErr error // error from makeWriter
|
||||
}
|
||||
|
||||
// tags represents struct tags.
|
||||
type tags struct {
|
||||
// rlp:"nil" controls whether empty input results in a nil pointer.
|
||||
// nilKind is the kind of empty value allowed for the field.
|
||||
nilKind Kind
|
||||
nilOK bool
|
||||
|
||||
// rlp:"optional" allows for a field to be missing in the input list.
|
||||
// If this is set, all subsequent fields must also be optional.
|
||||
optional bool
|
||||
|
||||
// rlp:"tail" controls whether this field swallows additional list elements. It can
|
||||
// only be set for the last field, which must be of slice type.
|
||||
tail bool
|
||||
|
||||
// rlp:"-" ignores fields.
|
||||
ignored bool
|
||||
}
|
||||
|
||||
// typekey is the key of a type in typeCache. It includes the struct tags because
|
||||
// they might generate a different decoder.
|
||||
type typekey struct {
|
||||
reflect.Type
|
||||
tags
|
||||
}
|
||||
|
||||
type decoder func(*Stream, reflect.Value) error
|
||||
|
||||
type writer func(reflect.Value, *encbuf) error
|
||||
|
||||
var theTC = newTypeCache()
|
||||
|
||||
type typeCache struct {
|
||||
cur atomic.Value
|
||||
|
||||
// This lock synchronizes writers.
|
||||
mu sync.Mutex
|
||||
next map[typekey]*typeinfo
|
||||
}
|
||||
|
||||
func newTypeCache() *typeCache {
|
||||
c := new(typeCache)
|
||||
c.cur.Store(make(map[typekey]*typeinfo))
|
||||
return c
|
||||
}
|
||||
|
||||
func cachedDecoder(typ reflect.Type) (decoder, error) {
|
||||
info := theTC.info(typ)
|
||||
return info.decoder, info.decoderErr
|
||||
}
|
||||
|
||||
func cachedWriter(typ reflect.Type) (writer, error) {
|
||||
info := theTC.info(typ)
|
||||
return info.writer, info.writerErr
|
||||
}
|
||||
|
||||
func (c *typeCache) info(typ reflect.Type) *typeinfo {
|
||||
key := typekey{Type: typ}
|
||||
if info := c.cur.Load().(map[typekey]*typeinfo)[key]; info != nil {
|
||||
return info
|
||||
}
|
||||
|
||||
// Not in the cache, need to generate info for this type.
|
||||
return c.generate(typ, tags{})
|
||||
}
|
||||
|
||||
func (c *typeCache) generate(typ reflect.Type, tags tags) *typeinfo {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
cur := c.cur.Load().(map[typekey]*typeinfo)
|
||||
if info := cur[typekey{typ, tags}]; info != nil {
|
||||
return info
|
||||
}
|
||||
|
||||
// Copy cur to next.
|
||||
c.next = make(map[typekey]*typeinfo, len(cur)+1)
|
||||
for k, v := range cur {
|
||||
c.next[k] = v
|
||||
}
|
||||
|
||||
// Generate.
|
||||
info := c.infoWhileGenerating(typ, tags)
|
||||
|
||||
// next -> cur
|
||||
c.cur.Store(c.next)
|
||||
c.next = nil
|
||||
return info
|
||||
}
|
||||
|
||||
func (c *typeCache) infoWhileGenerating(typ reflect.Type, tags tags) *typeinfo {
|
||||
key := typekey{typ, tags}
|
||||
if info := c.next[key]; info != nil {
|
||||
return info
|
||||
}
|
||||
// Put a dummy value into the cache before generating.
|
||||
// If the generator tries to lookup itself, it will get
|
||||
// the dummy value and won't call itself recursively.
|
||||
info := new(typeinfo)
|
||||
c.next[key] = info
|
||||
info.generate(typ, tags)
|
||||
return info
|
||||
}
|
||||
|
||||
type field struct {
|
||||
index int
|
||||
info *typeinfo
|
||||
optional bool
|
||||
}
|
||||
|
||||
// structFields resolves the typeinfo of all public fields in a struct type.
|
||||
func structFields(typ reflect.Type) (fields []field, err error) {
|
||||
var (
|
||||
lastPublic = lastPublicField(typ)
|
||||
anyOptional = false
|
||||
)
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
if f := typ.Field(i); f.PkgPath == "" { // exported
|
||||
tags, err := parseStructTag(typ, i, lastPublic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Skip rlp:"-" fields.
|
||||
if tags.ignored {
|
||||
continue
|
||||
}
|
||||
// If any field has the "optional" tag, subsequent fields must also have it.
|
||||
if tags.optional || tags.tail {
|
||||
anyOptional = true
|
||||
} else if anyOptional {
|
||||
return nil, fmt.Errorf(`rlp: struct field %v.%s needs "optional" tag`, typ, f.Name)
|
||||
}
|
||||
info := theTC.infoWhileGenerating(f.Type, tags)
|
||||
fields = append(fields, field{i, info, tags.optional})
|
||||
}
|
||||
}
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
// anyOptionalFields returns the index of the first field with "optional" tag.
|
||||
func firstOptionalField(fields []field) int {
|
||||
for i, f := range fields {
|
||||
if f.optional {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return len(fields)
|
||||
}
|
||||
|
||||
type structFieldError struct {
|
||||
typ reflect.Type
|
||||
field int
|
||||
err error
|
||||
}
|
||||
|
||||
func (e structFieldError) Error() string {
|
||||
return fmt.Sprintf("%v (struct field %v.%s)", e.err, e.typ, e.typ.Field(e.field).Name)
|
||||
}
|
||||
|
||||
type structTagError struct {
|
||||
typ reflect.Type
|
||||
field, tag, err string
|
||||
}
|
||||
|
||||
func (e structTagError) Error() string {
|
||||
return fmt.Sprintf("rlp: invalid struct tag %q for %v.%s (%s)", e.tag, e.typ, e.field, e.err)
|
||||
}
|
||||
|
||||
func parseStructTag(typ reflect.Type, fi, lastPublic int) (tags, error) {
|
||||
f := typ.Field(fi)
|
||||
var ts tags
|
||||
for _, t := range strings.Split(f.Tag.Get("rlp"), ",") {
|
||||
switch t = strings.TrimSpace(t); t {
|
||||
case "":
|
||||
case "-":
|
||||
ts.ignored = true
|
||||
case "nil", "nilString", "nilList":
|
||||
ts.nilOK = true
|
||||
if f.Type.Kind() != reflect.Ptr {
|
||||
return ts, structTagError{typ, f.Name, t, "field is not a pointer"}
|
||||
}
|
||||
switch t {
|
||||
case "nil":
|
||||
ts.nilKind = defaultNilKind(f.Type.Elem())
|
||||
case "nilString":
|
||||
ts.nilKind = String
|
||||
case "nilList":
|
||||
ts.nilKind = List
|
||||
}
|
||||
case "optional":
|
||||
ts.optional = true
|
||||
if ts.tail {
|
||||
return ts, structTagError{typ, f.Name, t, `also has "tail" tag`}
|
||||
}
|
||||
case "tail":
|
||||
ts.tail = true
|
||||
if fi != lastPublic {
|
||||
return ts, structTagError{typ, f.Name, t, "must be on last field"}
|
||||
}
|
||||
if ts.optional {
|
||||
return ts, structTagError{typ, f.Name, t, `also has "optional" tag`}
|
||||
}
|
||||
if f.Type.Kind() != reflect.Slice {
|
||||
return ts, structTagError{typ, f.Name, t, "field type is not slice"}
|
||||
}
|
||||
default:
|
||||
return ts, fmt.Errorf("rlp: unknown struct tag %q on %v.%s", t, typ, f.Name)
|
||||
}
|
||||
}
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
func lastPublicField(typ reflect.Type) int {
|
||||
last := 0
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
if typ.Field(i).PkgPath == "" {
|
||||
last = i
|
||||
}
|
||||
}
|
||||
return last
|
||||
}
|
||||
|
||||
func (i *typeinfo) generate(typ reflect.Type, tags tags) {
|
||||
i.decoder, i.decoderErr = makeDecoder(typ, tags)
|
||||
i.writer, i.writerErr = makeWriter(typ, tags)
|
||||
}
|
||||
|
||||
// defaultNilKind determines whether a nil pointer to typ encodes/decodes
|
||||
// as an empty string or empty list.
|
||||
func defaultNilKind(typ reflect.Type) Kind {
|
||||
k := typ.Kind()
|
||||
if isUint(k) || k == reflect.String || k == reflect.Bool || isByteArray(typ) {
|
||||
return String
|
||||
}
|
||||
return List
|
||||
}
|
||||
|
||||
func isUint(k reflect.Kind) bool {
|
||||
return k >= reflect.Uint && k <= reflect.Uintptr
|
||||
}
|
||||
|
||||
func isByte(typ reflect.Type) bool {
|
||||
return typ.Kind() == reflect.Uint8 && !typ.Implements(encoderInterface)
|
||||
}
|
||||
|
||||
func isByteArray(typ reflect.Type) bool {
|
||||
return (typ.Kind() == reflect.Slice || typ.Kind() == reflect.Array) && isByte(typ.Elem())
|
||||
}
|
35
restricted/rlp/unsafe.go
Normal file
35
restricted/rlp/unsafe.go
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2021 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library 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.
|
||||
//
|
||||
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build !nacl,!js,cgo
|
||||
|
||||
package rlp
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// byteArrayBytes returns a slice of the byte array v.
|
||||
func byteArrayBytes(v reflect.Value) []byte {
|
||||
len := v.Len()
|
||||
var s []byte
|
||||
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s))
|
||||
hdr.Data = v.UnsafeAddr()
|
||||
hdr.Cap = len
|
||||
hdr.Len = len
|
||||
return s
|
||||
}
|
Loading…
Reference in New Issue
Block a user