mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
Delete rlp directory
Signed-off-by: Isabel Schöps Thiel @IsabelSchoepd <155141998+IST-Github@users.noreply.github.com>
This commit is contained in:
parent
4de78cea08
commit
2f27d51edc
33 changed files with 0 additions and 7527 deletions
1204
rlp/decode.go
1204
rlp/decode.go
File diff suppressed because it is too large
Load diff
|
|
@ -1,49 +0,0 @@
|
||||||
// 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"
|
|
||||||
}
|
|
||||||
1286
rlp/decode_test.go
1286
rlp/decode_test.go
File diff suppressed because it is too large
Load diff
158
rlp/doc.go
158
rlp/doc.go
|
|
@ -1,158 +0,0 @@
|
||||||
// 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
|
|
||||||
element 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
|
|
||||||
423
rlp/encbuffer.go
423
rlp/encbuffer.go
|
|
@ -1,423 +0,0 @@
|
||||||
// Copyright 2022 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 (
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
"math/big"
|
|
||||||
"reflect"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/holiman/uint256"
|
|
||||||
)
|
|
||||||
|
|
||||||
type encBuffer 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// The global encBuffer pool.
|
|
||||||
var encBufferPool = sync.Pool{
|
|
||||||
New: func() interface{} { return new(encBuffer) },
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEncBuffer() *encBuffer {
|
|
||||||
buf := encBufferPool.Get().(*encBuffer)
|
|
||||||
buf.reset()
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf *encBuffer) reset() {
|
|
||||||
buf.lhsize = 0
|
|
||||||
buf.str = buf.str[:0]
|
|
||||||
buf.lheads = buf.lheads[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// size returns the length of the encoded data.
|
|
||||||
func (buf *encBuffer) size() int {
|
|
||||||
return len(buf.str) + buf.lhsize
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeBytes creates the encoder output.
|
|
||||||
func (buf *encBuffer) makeBytes() []byte {
|
|
||||||
out := make([]byte, buf.size())
|
|
||||||
buf.copyTo(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf *encBuffer) copyTo(dst []byte) {
|
|
||||||
strpos := 0
|
|
||||||
pos := 0
|
|
||||||
for _, head := range buf.lheads {
|
|
||||||
// write string data before header
|
|
||||||
n := copy(dst[pos:], buf.str[strpos:head.offset])
|
|
||||||
pos += n
|
|
||||||
strpos += n
|
|
||||||
// write the header
|
|
||||||
enc := head.encode(dst[pos:])
|
|
||||||
pos += len(enc)
|
|
||||||
}
|
|
||||||
// copy string data after the last list header
|
|
||||||
copy(dst[pos:], buf.str[strpos:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeTo writes the encoder output to w.
|
|
||||||
func (buf *encBuffer) writeTo(w io.Writer) (err error) {
|
|
||||||
strpos := 0
|
|
||||||
for _, head := range buf.lheads {
|
|
||||||
// write string data before header
|
|
||||||
if head.offset-strpos > 0 {
|
|
||||||
n, err := w.Write(buf.str[strpos:head.offset])
|
|
||||||
strpos += n
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// write the header
|
|
||||||
enc := head.encode(buf.sizebuf[:])
|
|
||||||
if _, err = w.Write(enc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strpos < len(buf.str) {
|
|
||||||
// write string data after the last list header
|
|
||||||
_, err = w.Write(buf.str[strpos:])
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write implements io.Writer and appends b directly to the output.
|
|
||||||
func (buf *encBuffer) Write(b []byte) (int, error) {
|
|
||||||
buf.str = append(buf.str, b...)
|
|
||||||
return len(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeBool writes b as the integer 0 (false) or 1 (true).
|
|
||||||
func (buf *encBuffer) writeBool(b bool) {
|
|
||||||
if b {
|
|
||||||
buf.str = append(buf.str, 0x01)
|
|
||||||
} else {
|
|
||||||
buf.str = append(buf.str, 0x80)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf *encBuffer) writeUint64(i uint64) {
|
|
||||||
if i == 0 {
|
|
||||||
buf.str = append(buf.str, 0x80)
|
|
||||||
} else if i < 128 {
|
|
||||||
// fits single byte
|
|
||||||
buf.str = append(buf.str, byte(i))
|
|
||||||
} else {
|
|
||||||
s := putint(buf.sizebuf[1:], i)
|
|
||||||
buf.sizebuf[0] = 0x80 + byte(s)
|
|
||||||
buf.str = append(buf.str, buf.sizebuf[:s+1]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf *encBuffer) writeBytes(b []byte) {
|
|
||||||
if len(b) == 1 && b[0] <= 0x7F {
|
|
||||||
// fits single byte, no string header
|
|
||||||
buf.str = append(buf.str, b[0])
|
|
||||||
} else {
|
|
||||||
buf.encodeStringHeader(len(b))
|
|
||||||
buf.str = append(buf.str, b...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf *encBuffer) writeString(s string) {
|
|
||||||
buf.writeBytes([]byte(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// wordBytes is the number of bytes in a big.Word
|
|
||||||
const wordBytes = (32 << (uint64(^big.Word(0)) >> 63)) / 8
|
|
||||||
|
|
||||||
// writeBigInt writes i as an integer.
|
|
||||||
func (buf *encBuffer) writeBigInt(i *big.Int) {
|
|
||||||
bitlen := i.BitLen()
|
|
||||||
if bitlen <= 64 {
|
|
||||||
buf.writeUint64(i.Uint64())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 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
|
|
||||||
buf.encodeStringHeader(length)
|
|
||||||
buf.str = append(buf.str, make([]byte, length)...)
|
|
||||||
index := length
|
|
||||||
bytesBuf := buf.str[len(buf.str)-length:]
|
|
||||||
for _, d := range i.Bits() {
|
|
||||||
for j := 0; j < wordBytes && index > 0; j++ {
|
|
||||||
index--
|
|
||||||
bytesBuf[index] = byte(d)
|
|
||||||
d >>= 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeUint256 writes z as an integer.
|
|
||||||
func (buf *encBuffer) writeUint256(z *uint256.Int) {
|
|
||||||
bitlen := z.BitLen()
|
|
||||||
if bitlen <= 64 {
|
|
||||||
buf.writeUint64(z.Uint64())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nBytes := byte((bitlen + 7) / 8)
|
|
||||||
var b [33]byte
|
|
||||||
binary.BigEndian.PutUint64(b[1:9], z[3])
|
|
||||||
binary.BigEndian.PutUint64(b[9:17], z[2])
|
|
||||||
binary.BigEndian.PutUint64(b[17:25], z[1])
|
|
||||||
binary.BigEndian.PutUint64(b[25:33], z[0])
|
|
||||||
b[32-nBytes] = 0x80 + nBytes
|
|
||||||
buf.str = append(buf.str, b[32-nBytes:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// list adds a new list header to the header stack. It returns the index of the header.
|
|
||||||
// Call listEnd with this index after encoding the content of the list.
|
|
||||||
func (buf *encBuffer) list() int {
|
|
||||||
buf.lheads = append(buf.lheads, listhead{offset: len(buf.str), size: buf.lhsize})
|
|
||||||
return len(buf.lheads) - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf *encBuffer) listEnd(index int) {
|
|
||||||
lh := &buf.lheads[index]
|
|
||||||
lh.size = buf.size() - lh.offset - lh.size
|
|
||||||
if lh.size < 56 {
|
|
||||||
buf.lhsize++ // length encoded into kind tag
|
|
||||||
} else {
|
|
||||||
buf.lhsize += 1 + intsize(uint64(lh.size))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf *encBuffer) encode(val interface{}) error {
|
|
||||||
rval := reflect.ValueOf(val)
|
|
||||||
writer, err := cachedWriter(rval.Type())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return writer(rval, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf *encBuffer) encodeStringHeader(size int) {
|
|
||||||
if size < 56 {
|
|
||||||
buf.str = append(buf.str, 0x80+byte(size))
|
|
||||||
} else {
|
|
||||||
sizesize := putint(buf.sizebuf[1:], uint64(size))
|
|
||||||
buf.sizebuf[0] = 0xB7 + byte(sizesize)
|
|
||||||
buf.str = append(buf.str, buf.sizebuf[:sizesize+1]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// encReader is the io.Reader returned by EncodeToReader.
|
|
||||||
// It releases its encbuf at EOF.
|
|
||||||
type encReader struct {
|
|
||||||
buf *encBuffer // 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 {
|
|
||||||
encBufferPool.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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func encBufferFromWriter(w io.Writer) *encBuffer {
|
|
||||||
switch w := w.(type) {
|
|
||||||
case EncoderBuffer:
|
|
||||||
return w.buf
|
|
||||||
case *EncoderBuffer:
|
|
||||||
return w.buf
|
|
||||||
case *encBuffer:
|
|
||||||
return w
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncoderBuffer is a buffer for incremental encoding.
|
|
||||||
//
|
|
||||||
// The zero value is NOT ready for use. To get a usable buffer,
|
|
||||||
// create it using NewEncoderBuffer or call Reset.
|
|
||||||
type EncoderBuffer struct {
|
|
||||||
buf *encBuffer
|
|
||||||
dst io.Writer
|
|
||||||
|
|
||||||
ownBuffer bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEncoderBuffer creates an encoder buffer.
|
|
||||||
func NewEncoderBuffer(dst io.Writer) EncoderBuffer {
|
|
||||||
var w EncoderBuffer
|
|
||||||
w.Reset(dst)
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset truncates the buffer and sets the output destination.
|
|
||||||
func (w *EncoderBuffer) Reset(dst io.Writer) {
|
|
||||||
if w.buf != nil && !w.ownBuffer {
|
|
||||||
panic("can't Reset derived EncoderBuffer")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the destination writer has an *encBuffer, use it.
|
|
||||||
// Note that w.ownBuffer is left false here.
|
|
||||||
if dst != nil {
|
|
||||||
if outer := encBufferFromWriter(dst); outer != nil {
|
|
||||||
*w = EncoderBuffer{outer, nil, false}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a fresh buffer.
|
|
||||||
if w.buf == nil {
|
|
||||||
w.buf = encBufferPool.Get().(*encBuffer)
|
|
||||||
w.ownBuffer = true
|
|
||||||
}
|
|
||||||
w.buf.reset()
|
|
||||||
w.dst = dst
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush writes encoded RLP data to the output writer. This can only be called once.
|
|
||||||
// If you want to re-use the buffer after Flush, you must call Reset.
|
|
||||||
func (w *EncoderBuffer) Flush() error {
|
|
||||||
var err error
|
|
||||||
if w.dst != nil {
|
|
||||||
err = w.buf.writeTo(w.dst)
|
|
||||||
}
|
|
||||||
// Release the internal buffer.
|
|
||||||
if w.ownBuffer {
|
|
||||||
encBufferPool.Put(w.buf)
|
|
||||||
}
|
|
||||||
*w = EncoderBuffer{}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToBytes returns the encoded bytes.
|
|
||||||
func (w *EncoderBuffer) ToBytes() []byte {
|
|
||||||
return w.buf.makeBytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendToBytes appends the encoded bytes to dst.
|
|
||||||
func (w *EncoderBuffer) AppendToBytes(dst []byte) []byte {
|
|
||||||
size := w.buf.size()
|
|
||||||
out := append(dst, make([]byte, size)...)
|
|
||||||
w.buf.copyTo(out[len(dst):])
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write appends b directly to the encoder output.
|
|
||||||
func (w EncoderBuffer) Write(b []byte) (int, error) {
|
|
||||||
return w.buf.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteBool writes b as the integer 0 (false) or 1 (true).
|
|
||||||
func (w EncoderBuffer) WriteBool(b bool) {
|
|
||||||
w.buf.writeBool(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteUint64 encodes an unsigned integer.
|
|
||||||
func (w EncoderBuffer) WriteUint64(i uint64) {
|
|
||||||
w.buf.writeUint64(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteBigInt encodes a big.Int as an RLP string.
|
|
||||||
// Note: Unlike with Encode, the sign of i is ignored.
|
|
||||||
func (w EncoderBuffer) WriteBigInt(i *big.Int) {
|
|
||||||
w.buf.writeBigInt(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteUint256 encodes uint256.Int as an RLP string.
|
|
||||||
func (w EncoderBuffer) WriteUint256(i *uint256.Int) {
|
|
||||||
w.buf.writeUint256(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteBytes encodes b as an RLP string.
|
|
||||||
func (w EncoderBuffer) WriteBytes(b []byte) {
|
|
||||||
w.buf.writeBytes(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteString encodes s as an RLP string.
|
|
||||||
func (w EncoderBuffer) WriteString(s string) {
|
|
||||||
w.buf.writeString(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// List starts a list. It returns an internal index. Call EndList with
|
|
||||||
// this index after encoding the content to finish the list.
|
|
||||||
func (w EncoderBuffer) List() int {
|
|
||||||
return w.buf.list()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListEnd finishes the given list.
|
|
||||||
func (w EncoderBuffer) ListEnd(index int) {
|
|
||||||
w.buf.listEnd(index)
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
// Copyright 2022 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_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleEncoderBuffer() {
|
|
||||||
var w bytes.Buffer
|
|
||||||
|
|
||||||
// Encode [4, [5, 6]] to w.
|
|
||||||
buf := rlp.NewEncoderBuffer(&w)
|
|
||||||
l1 := buf.List()
|
|
||||||
buf.WriteUint64(4)
|
|
||||||
l2 := buf.List()
|
|
||||||
buf.WriteUint64(5)
|
|
||||||
buf.WriteUint64(6)
|
|
||||||
buf.ListEnd(l2)
|
|
||||||
buf.ListEnd(l1)
|
|
||||||
|
|
||||||
if err := buf.Flush(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fmt.Printf("%X\n", w.Bytes())
|
|
||||||
// Output:
|
|
||||||
// C404C20506
|
|
||||||
}
|
|
||||||
495
rlp/encode.go
495
rlp/encode.go
|
|
@ -1,495 +0,0 @@
|
||||||
// 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 (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math/big"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/rlp/internal/rlpstruct"
|
|
||||||
"github.com/holiman/uint256"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Common encoded values.
|
|
||||||
// These are useful when implementing EncodeRLP.
|
|
||||||
|
|
||||||
// EmptyString is the encoding of an empty string.
|
|
||||||
EmptyString = []byte{0x80}
|
|
||||||
// EmptyList is the encoding of an empty list.
|
|
||||||
EmptyList = []byte{0xC0}
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrNegativeBigInt = errors.New("rlp: cannot encode negative big.Int")
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
// Optimization: reuse *encBuffer when called by EncodeRLP.
|
|
||||||
if buf := encBufferFromWriter(w); buf != nil {
|
|
||||||
return buf.encode(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := getEncBuffer()
|
|
||||||
defer encBufferPool.Put(buf)
|
|
||||||
if err := buf.encode(val); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return buf.writeTo(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeToBytes returns the RLP encoding of val.
|
|
||||||
// Please see package-level documentation for the encoding rules.
|
|
||||||
func EncodeToBytes(val interface{}) ([]byte, error) {
|
|
||||||
buf := getEncBuffer()
|
|
||||||
defer encBufferPool.Put(buf)
|
|
||||||
|
|
||||||
if err := buf.encode(val); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.makeBytes(), 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) {
|
|
||||||
buf := getEncBuffer()
|
|
||||||
if err := buf.encode(val); err != nil {
|
|
||||||
encBufferPool.Put(buf)
|
|
||||||
return 0, nil, err
|
|
||||||
}
|
|
||||||
// Note: can't put the reader back into the pool here
|
|
||||||
// because it is held by encReader. The reader puts it
|
|
||||||
// back when it has been fully consumed.
|
|
||||||
return buf.size(), &encReader{buf: buf}, 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
|
|
||||||
}
|
|
||||||
|
|
||||||
var encoderInterface = reflect.TypeOf(new(Encoder)).Elem()
|
|
||||||
|
|
||||||
// makeWriter creates a writer function for the given type.
|
|
||||||
func makeWriter(typ reflect.Type, ts rlpstruct.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 typ == reflect.PtrTo(u256Int):
|
|
||||||
return writeU256IntPtr, nil
|
|
||||||
case typ == u256Int:
|
|
||||||
return writeU256IntNoPtr, 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 *encBuffer) error {
|
|
||||||
w.str = append(w.str, val.Bytes()...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeUint(val reflect.Value, w *encBuffer) error {
|
|
||||||
w.writeUint64(val.Uint())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBool(val reflect.Value, w *encBuffer) error {
|
|
||||||
w.writeBool(val.Bool())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBigIntPtr(val reflect.Value, w *encBuffer) error {
|
|
||||||
ptr := val.Interface().(*big.Int)
|
|
||||||
if ptr == nil {
|
|
||||||
w.str = append(w.str, 0x80)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if ptr.Sign() == -1 {
|
|
||||||
return ErrNegativeBigInt
|
|
||||||
}
|
|
||||||
w.writeBigInt(ptr)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBigIntNoPtr(val reflect.Value, w *encBuffer) error {
|
|
||||||
i := val.Interface().(big.Int)
|
|
||||||
if i.Sign() == -1 {
|
|
||||||
return ErrNegativeBigInt
|
|
||||||
}
|
|
||||||
w.writeBigInt(&i)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeU256IntPtr(val reflect.Value, w *encBuffer) error {
|
|
||||||
ptr := val.Interface().(*uint256.Int)
|
|
||||||
if ptr == nil {
|
|
||||||
w.str = append(w.str, 0x80)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
w.writeUint256(ptr)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeU256IntNoPtr(val reflect.Value, w *encBuffer) error {
|
|
||||||
i := val.Interface().(uint256.Int)
|
|
||||||
w.writeUint256(&i)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBytes(val reflect.Value, w *encBuffer) error {
|
|
||||||
w.writeBytes(val.Bytes())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeByteArrayWriter(typ reflect.Type) writer {
|
|
||||||
switch typ.Len() {
|
|
||||||
case 0:
|
|
||||||
return writeLengthZeroByteArray
|
|
||||||
case 1:
|
|
||||||
return writeLengthOneByteArray
|
|
||||||
default:
|
|
||||||
length := typ.Len()
|
|
||||||
return func(val reflect.Value, w *encBuffer) 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, length)
|
|
||||||
w.encodeStringHeader(len(slice))
|
|
||||||
w.str = append(w.str, slice...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeLengthZeroByteArray(val reflect.Value, w *encBuffer) error {
|
|
||||||
w.str = append(w.str, 0x80)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeLengthOneByteArray(val reflect.Value, w *encBuffer) 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 writeString(val reflect.Value, w *encBuffer) 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 *encBuffer) 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 rlpstruct.Tags) (writer, error) {
|
|
||||||
etypeinfo := theTC.infoWhileGenerating(typ.Elem(), rlpstruct.Tags{})
|
|
||||||
if etypeinfo.writerErr != nil {
|
|
||||||
return nil, etypeinfo.writerErr
|
|
||||||
}
|
|
||||||
|
|
||||||
var wfn writer
|
|
||||||
if ts.Tail {
|
|
||||||
// This is for struct tail slices.
|
|
||||||
// w.list is not called for them.
|
|
||||||
wfn = func(val reflect.Value, w *encBuffer) error {
|
|
||||||
vlen := val.Len()
|
|
||||||
for i := 0; i < vlen; i++ {
|
|
||||||
if err := etypeinfo.writer(val.Index(i), w); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This is for regular slices and arrays.
|
|
||||||
wfn = func(val reflect.Value, w *encBuffer) error {
|
|
||||||
vlen := val.Len()
|
|
||||||
if vlen == 0 {
|
|
||||||
w.str = append(w.str, 0xC0)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
listOffset := w.list()
|
|
||||||
for i := 0; i < vlen; i++ {
|
|
||||||
if err := etypeinfo.writer(val.Index(i), w); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.listEnd(listOffset)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wfn, 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 *encBuffer) 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 *encBuffer) 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 rlpstruct.Tags) (writer, error) {
|
|
||||||
nilEncoding := byte(0xC0)
|
|
||||||
if typeNilKind(typ.Elem(), ts) == String {
|
|
||||||
nilEncoding = 0x80
|
|
||||||
}
|
|
||||||
|
|
||||||
etypeinfo := theTC.infoWhileGenerating(typ.Elem(), rlpstruct.Tags{})
|
|
||||||
if etypeinfo.writerErr != nil {
|
|
||||||
return nil, etypeinfo.writerErr
|
|
||||||
}
|
|
||||||
|
|
||||||
writer := func(val reflect.Value, w *encBuffer) error {
|
|
||||||
if ev := val.Elem(); ev.IsValid() {
|
|
||||||
return etypeinfo.writer(ev, w)
|
|
||||||
}
|
|
||||||
w.str = append(w.str, nilEncoding)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return writer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeEncoderWriter(typ reflect.Type) writer {
|
|
||||||
if typ.Implements(encoderInterface) {
|
|
||||||
return func(val reflect.Value, w *encBuffer) error {
|
|
||||||
return val.Interface().(Encoder).EncodeRLP(w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w := func(val reflect.Value, w *encBuffer) 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: unaddressable 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,638 +0,0 @@
|
||||||
// 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"
|
|
||||||
"math/big"
|
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
|
||||||
"github.com/holiman/uint256"
|
|
||||||
)
|
|
||||||
|
|
||||||
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: new(big.Int).SetBytes(unhex("102030405060708090A0B0C0D0E0F2")),
|
|
||||||
output: "8F102030405060708090A0B0C0D0E0F2",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
val: new(big.Int).SetBytes(unhex("0100020003000400050006000700080009000A000B000C000D000E01")),
|
|
||||||
output: "9C0100020003000400050006000700080009000A000B000C000D000E01",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
val: new(big.Int).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"},
|
|
||||||
{val: *big.NewInt(-1), error: "rlp: cannot encode negative big.Int"},
|
|
||||||
|
|
||||||
// uint256
|
|
||||||
{val: uint256.NewInt(0), output: "80"},
|
|
||||||
{val: uint256.NewInt(1), output: "01"},
|
|
||||||
{val: uint256.NewInt(127), output: "7F"},
|
|
||||||
{val: uint256.NewInt(128), output: "8180"},
|
|
||||||
{val: uint256.NewInt(256), output: "820100"},
|
|
||||||
{val: uint256.NewInt(1024), output: "820400"},
|
|
||||||
{val: uint256.NewInt(0xFFFFFF), output: "83FFFFFF"},
|
|
||||||
{val: uint256.NewInt(0xFFFFFFFF), output: "84FFFFFFFF"},
|
|
||||||
{val: uint256.NewInt(0xFFFFFFFFFF), output: "85FFFFFFFFFF"},
|
|
||||||
{val: uint256.NewInt(0xFFFFFFFFFFFF), output: "86FFFFFFFFFFFF"},
|
|
||||||
{val: uint256.NewInt(0xFFFFFFFFFFFFFF), output: "87FFFFFFFFFFFFFF"},
|
|
||||||
{
|
|
||||||
val: new(uint256.Int).SetBytes(unhex("102030405060708090A0B0C0D0E0F2")),
|
|
||||||
output: "8F102030405060708090A0B0C0D0E0F2",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
val: new(uint256.Int).SetBytes(unhex("0100020003000400050006000700080009000A000B000C000D000E01")),
|
|
||||||
output: "9C0100020003000400050006000700080009000A000B000C000D000E01",
|
|
||||||
},
|
|
||||||
// non-pointer uint256.Int
|
|
||||||
{val: *uint256.NewInt(0), output: "80"},
|
|
||||||
{val: *uint256.NewInt(0xFFFFFF), output: "83FFFFFF"},
|
|
||||||
|
|
||||||
// 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",
|
|
||||||
},
|
|
||||||
|
|
||||||
// Non-byte arrays are encoded as lists.
|
|
||||||
// Note that it is important to test [4]uint64 specifically,
|
|
||||||
// because that's the underlying type of uint256.Int.
|
|
||||||
{val: [4]uint32{1, 2, 3, 4}, output: "C401020304"},
|
|
||||||
{val: [4]uint64{1, 2, 3, 4}, output: "C401020304"},
|
|
||||||
|
|
||||||
// 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"},
|
|
||||||
{val: &multipleOptionalFields{A: nil, B: nil}, output: "C0"},
|
|
||||||
{val: &multipleOptionalFields{A: &[3]byte{1, 2, 3}, B: &[3]byte{1, 2, 3}}, output: "C88301020383010203"},
|
|
||||||
{val: &multipleOptionalFields{A: nil, B: &[3]byte{1, 2, 3}}, output: "C58083010203"}, // encodes without error but decode will fail
|
|
||||||
{val: &nonOptionalPtrField{A: 1}, output: "C20180"}, // encodes without error but decode will fail
|
|
||||||
|
|
||||||
// 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: (*uint256.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: unaddressable 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 TestEncodeAppendToBytes(t *testing.T) {
|
|
||||||
buffer := make([]byte, 20)
|
|
||||||
runEncTests(t, func(val interface{}) ([]byte, error) {
|
|
||||||
w := NewEncoderBuffer(nil)
|
|
||||||
defer w.Flush()
|
|
||||||
|
|
||||||
err := Encode(w, val)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
output := w.AppendToBytes(buffer[:0])
|
|
||||||
return output, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodeToReader(t *testing.T) {
|
|
||||||
runEncTests(t, func(val interface{}) ([]byte, error) {
|
|
||||||
_, r, err := EncodeToReader(val)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return io.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")
|
|
||||||
io.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] = math.BigPow(2, int64(i))
|
|
||||||
}
|
|
||||||
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 BenchmarkEncodeU256Ints(b *testing.B) {
|
|
||||||
ints := make([]*uint256.Int, 200)
|
|
||||||
for i := range ints {
|
|
||||||
ints[i], _ = uint256.FromBig(math.BigPow(2, int64(i)))
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type structSliceElem struct {
|
|
||||||
X uint64
|
|
||||||
Y uint64
|
|
||||||
Z uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type structPtrSlice []*structSliceElem
|
|
||||||
|
|
||||||
func BenchmarkEncodeStructPtrSlice(b *testing.B) {
|
|
||||||
var out bytes.Buffer
|
|
||||||
var value = structPtrSlice{
|
|
||||||
&structSliceElem{1, 1, 1},
|
|
||||||
&structSliceElem{2, 2, 2},
|
|
||||||
&structSliceElem{3, 3, 3},
|
|
||||||
&structSliceElem{5, 5, 5},
|
|
||||||
&structSliceElem{6, 6, 6},
|
|
||||||
&structSliceElem{7, 7, 7},
|
|
||||||
}
|
|
||||||
|
|
||||||
b.ReportAllocs()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
out.Reset()
|
|
||||||
if err := Encode(&out, &value); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
// 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_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
)
|
|
||||||
|
|
||||||
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 rlp.Encode(w, []uint{x.a, x.b})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleEncoder() {
|
|
||||||
var t *MyCoolType // t is nil pointer to MyCoolType
|
|
||||||
bytes, _ := rlp.EncodeToBytes(t)
|
|
||||||
fmt.Printf("%v → %X\n", t, bytes)
|
|
||||||
|
|
||||||
t = &MyCoolType{Name: "foobar", a: 5, b: 6}
|
|
||||||
bytes, _ = rlp.EncodeToBytes(t)
|
|
||||||
fmt.Printf("%v → %X\n", t, bytes)
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// <nil> → C0
|
|
||||||
// &{foobar 5 6} → C20506
|
|
||||||
}
|
|
||||||
|
|
@ -1,213 +0,0 @@
|
||||||
// Copyright 2022 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 rlpstruct implements struct processing for RLP encoding/decoding.
|
|
||||||
//
|
|
||||||
// In particular, this package handles all rules around field filtering,
|
|
||||||
// struct tags and nil value determination.
|
|
||||||
package rlpstruct
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Field represents a struct field.
|
|
||||||
type Field struct {
|
|
||||||
Name string
|
|
||||||
Index int
|
|
||||||
Exported bool
|
|
||||||
Type Type
|
|
||||||
Tag string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type represents the attributes of a Go type.
|
|
||||||
type Type struct {
|
|
||||||
Name string
|
|
||||||
Kind reflect.Kind
|
|
||||||
IsEncoder bool // whether type implements rlp.Encoder
|
|
||||||
IsDecoder bool // whether type implements rlp.Decoder
|
|
||||||
Elem *Type // non-nil for Kind values of Ptr, Slice, Array
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultNilValue determines whether a nil pointer to t encodes/decodes
|
|
||||||
// as an empty string or empty list.
|
|
||||||
func (t Type) DefaultNilValue() NilKind {
|
|
||||||
k := t.Kind
|
|
||||||
if isUint(k) || k == reflect.String || k == reflect.Bool || isByteArray(t) {
|
|
||||||
return NilKindString
|
|
||||||
}
|
|
||||||
return NilKindList
|
|
||||||
}
|
|
||||||
|
|
||||||
// NilKind is the RLP value encoded in place of nil pointers.
|
|
||||||
type NilKind uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
NilKindString NilKind = 0x80
|
|
||||||
NilKindList NilKind = 0xC0
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 NilKind
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// TagError is raised for invalid struct tags.
|
|
||||||
type TagError struct {
|
|
||||||
StructType string
|
|
||||||
|
|
||||||
// These are set by this package.
|
|
||||||
Field string
|
|
||||||
Tag string
|
|
||||||
Err string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e TagError) Error() string {
|
|
||||||
field := "field " + e.Field
|
|
||||||
if e.StructType != "" {
|
|
||||||
field = e.StructType + "." + e.Field
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("rlp: invalid struct tag %q for %s (%s)", e.Tag, field, e.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessFields filters the given struct fields, returning only fields
|
|
||||||
// that should be considered for encoding/decoding.
|
|
||||||
func ProcessFields(allFields []Field) ([]Field, []Tags, error) {
|
|
||||||
lastPublic := lastPublicField(allFields)
|
|
||||||
|
|
||||||
// Gather all exported fields and their tags.
|
|
||||||
var fields []Field
|
|
||||||
var tags []Tags
|
|
||||||
for _, field := range allFields {
|
|
||||||
if !field.Exported {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ts, err := parseTag(field, lastPublic)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if ts.Ignored {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fields = append(fields, field)
|
|
||||||
tags = append(tags, ts)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify optional field consistency. If any optional field exists,
|
|
||||||
// all fields after it must also be optional. Note: optional + tail
|
|
||||||
// is supported.
|
|
||||||
var anyOptional bool
|
|
||||||
var firstOptionalName string
|
|
||||||
for i, ts := range tags {
|
|
||||||
name := fields[i].Name
|
|
||||||
if ts.Optional || ts.Tail {
|
|
||||||
if !anyOptional {
|
|
||||||
firstOptionalName = name
|
|
||||||
}
|
|
||||||
anyOptional = true
|
|
||||||
} else {
|
|
||||||
if anyOptional {
|
|
||||||
msg := fmt.Sprintf("must be optional because preceding field %q is optional", firstOptionalName)
|
|
||||||
return nil, nil, TagError{Field: name, Err: msg}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fields, tags, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseTag(field Field, lastPublic int) (Tags, error) {
|
|
||||||
name := field.Name
|
|
||||||
tag := reflect.StructTag(field.Tag)
|
|
||||||
var ts Tags
|
|
||||||
for _, t := range strings.Split(tag.Get("rlp"), ",") {
|
|
||||||
switch t = strings.TrimSpace(t); t {
|
|
||||||
case "":
|
|
||||||
// empty tag is allowed for some reason
|
|
||||||
case "-":
|
|
||||||
ts.Ignored = true
|
|
||||||
case "nil", "nilString", "nilList":
|
|
||||||
ts.NilOK = true
|
|
||||||
if field.Type.Kind != reflect.Ptr {
|
|
||||||
return ts, TagError{Field: name, Tag: t, Err: "field is not a pointer"}
|
|
||||||
}
|
|
||||||
switch t {
|
|
||||||
case "nil":
|
|
||||||
ts.NilKind = field.Type.Elem.DefaultNilValue()
|
|
||||||
case "nilString":
|
|
||||||
ts.NilKind = NilKindString
|
|
||||||
case "nilList":
|
|
||||||
ts.NilKind = NilKindList
|
|
||||||
}
|
|
||||||
case "optional":
|
|
||||||
ts.Optional = true
|
|
||||||
if ts.Tail {
|
|
||||||
return ts, TagError{Field: name, Tag: t, Err: `also has "tail" tag`}
|
|
||||||
}
|
|
||||||
case "tail":
|
|
||||||
ts.Tail = true
|
|
||||||
if field.Index != lastPublic {
|
|
||||||
return ts, TagError{Field: name, Tag: t, Err: "must be on last field"}
|
|
||||||
}
|
|
||||||
if ts.Optional {
|
|
||||||
return ts, TagError{Field: name, Tag: t, Err: `also has "optional" tag`}
|
|
||||||
}
|
|
||||||
if field.Type.Kind != reflect.Slice {
|
|
||||||
return ts, TagError{Field: name, Tag: t, Err: "field type is not slice"}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return ts, TagError{Field: name, Tag: t, Err: "unknown tag"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lastPublicField(fields []Field) int {
|
|
||||||
last := 0
|
|
||||||
for _, f := range fields {
|
|
||||||
if f.Exported {
|
|
||||||
last = f.Index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return last
|
|
||||||
}
|
|
||||||
|
|
||||||
func isUint(k reflect.Kind) bool {
|
|
||||||
return k >= reflect.Uint && k <= reflect.Uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
func isByte(typ Type) bool {
|
|
||||||
return typ.Kind == reflect.Uint8 && !typ.IsEncoder
|
|
||||||
}
|
|
||||||
|
|
||||||
func isByteArray(typ Type) bool {
|
|
||||||
return (typ.Kind == reflect.Slice || typ.Kind == reflect.Array) && isByte(*typ.Elem)
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
// Copyright 2020 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
|
|
||||||
}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
// Copyright 2020 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/ethereum/go-ethereum/common/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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
294
rlp/raw.go
294
rlp/raw.go
|
|
@ -1,294 +0,0 @@
|
||||||
// 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{})
|
|
||||||
|
|
||||||
// StringSize returns the encoded size of a string.
|
|
||||||
func StringSize(s string) uint64 {
|
|
||||||
switch {
|
|
||||||
case len(s) == 0:
|
|
||||||
return 1
|
|
||||||
case len(s) == 1:
|
|
||||||
if s[0] <= 0x7f {
|
|
||||||
return 1
|
|
||||||
} else {
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return uint64(headsize(uint64(len(s))) + len(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesSize returns the encoded size of a byte slice.
|
|
||||||
func BytesSize(b []byte) uint64 {
|
|
||||||
switch {
|
|
||||||
case len(b) == 0:
|
|
||||||
return 1
|
|
||||||
case len(b) == 1:
|
|
||||||
if b[0] <= 0x7f {
|
|
||||||
return 1
|
|
||||||
} else {
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return uint64(headsize(uint64(len(b))) + len(b))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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. Note: The return type of this
|
|
||||||
// function is 'int' for backwards-compatibility reasons. The result is always positive.
|
|
||||||
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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
338
rlp/raw_test.go
338
rlp/raw_test.go
|
|
@ -1,338 +0,0 @@
|
||||||
// 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"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"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 !errors.Is(err, test.err) {
|
|
||||||
t.Errorf("test %d: err mismatch, got %q want %q\ninput: %s", i, err, test.err, test.input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSplitString(t *testing.T) {
|
|
||||||
for i, test := range []string{
|
|
||||||
"C0",
|
|
||||||
"C100",
|
|
||||||
"C3010203",
|
|
||||||
"C88363617483646F67",
|
|
||||||
"F8384C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E7365637465747572206164697069736963696E6720656C6974",
|
|
||||||
} {
|
|
||||||
if _, _, err := SplitString(unhex(test)); !errors.Is(err, ErrExpectedString) {
|
|
||||||
t.Errorf("test %d: error mismatch: have %q, want %q", i, err, ErrExpectedString)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSplitList(t *testing.T) {
|
|
||||||
for i, test := range []string{
|
|
||||||
"80",
|
|
||||||
"00",
|
|
||||||
"01",
|
|
||||||
"8180",
|
|
||||||
"81FF",
|
|
||||||
"820400",
|
|
||||||
"83636174",
|
|
||||||
"83646F67",
|
|
||||||
"B8384C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E7365637465747572206164697069736963696E6720656C6974",
|
|
||||||
} {
|
|
||||||
if _, _, err := SplitList(unhex(test)); !errors.Is(err, ErrExpectedList) {
|
|
||||||
t.Errorf("test %d: error mismatch: have %q, want %q", i, 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBytesSize(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
v []byte
|
|
||||||
size uint64
|
|
||||||
}{
|
|
||||||
{v: []byte{}, size: 1},
|
|
||||||
{v: []byte{0x1}, size: 1},
|
|
||||||
{v: []byte{0x7E}, size: 1},
|
|
||||||
{v: []byte{0x7F}, size: 1},
|
|
||||||
{v: []byte{0x80}, size: 2},
|
|
||||||
{v: []byte{0xFF}, size: 2},
|
|
||||||
{v: []byte{0xFF, 0xF0}, size: 3},
|
|
||||||
{v: make([]byte, 55), size: 56},
|
|
||||||
{v: make([]byte, 56), size: 58},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
s := BytesSize(test.v)
|
|
||||||
if s != test.size {
|
|
||||||
t.Errorf("BytesSize(%#x) -> %d, want %d", test.v, s, test.size)
|
|
||||||
}
|
|
||||||
s = StringSize(string(test.v))
|
|
||||||
if s != test.size {
|
|
||||||
t.Errorf("StringSize(%#x) -> %d, want %d", test.v, s, test.size)
|
|
||||||
}
|
|
||||||
// Sanity check:
|
|
||||||
enc, _ := EncodeToBytes(test.v)
|
|
||||||
if uint64(len(enc)) != test.size {
|
|
||||||
t.Errorf("len(EncodeToBytes(%#x)) -> %d, test says %d", test.v, len(enc), test.size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,800 +0,0 @@
|
||||||
// Copyright 2022 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 main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/format"
|
|
||||||
"go/types"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/rlp/internal/rlpstruct"
|
|
||||||
)
|
|
||||||
|
|
||||||
// buildContext keeps the data needed for make*Op.
|
|
||||||
type buildContext struct {
|
|
||||||
topType *types.Named // the type we're creating methods for
|
|
||||||
|
|
||||||
encoderIface *types.Interface
|
|
||||||
decoderIface *types.Interface
|
|
||||||
rawValueType *types.Named
|
|
||||||
|
|
||||||
typeToStructCache map[types.Type]*rlpstruct.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBuildContext(packageRLP *types.Package) *buildContext {
|
|
||||||
enc := packageRLP.Scope().Lookup("Encoder").Type().Underlying()
|
|
||||||
dec := packageRLP.Scope().Lookup("Decoder").Type().Underlying()
|
|
||||||
rawv := packageRLP.Scope().Lookup("RawValue").Type()
|
|
||||||
return &buildContext{
|
|
||||||
typeToStructCache: make(map[types.Type]*rlpstruct.Type),
|
|
||||||
encoderIface: enc.(*types.Interface),
|
|
||||||
decoderIface: dec.(*types.Interface),
|
|
||||||
rawValueType: rawv.(*types.Named),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bctx *buildContext) isEncoder(typ types.Type) bool {
|
|
||||||
return types.Implements(typ, bctx.encoderIface)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bctx *buildContext) isDecoder(typ types.Type) bool {
|
|
||||||
return types.Implements(typ, bctx.decoderIface)
|
|
||||||
}
|
|
||||||
|
|
||||||
// typeToStructType converts typ to rlpstruct.Type.
|
|
||||||
func (bctx *buildContext) typeToStructType(typ types.Type) *rlpstruct.Type {
|
|
||||||
if prev := bctx.typeToStructCache[typ]; prev != nil {
|
|
||||||
return prev // short-circuit for recursive types.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve named types to their underlying type, but keep the name.
|
|
||||||
name := types.TypeString(typ, nil)
|
|
||||||
for {
|
|
||||||
utype := typ.Underlying()
|
|
||||||
if utype == typ {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
typ = utype
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the type and store it in cache.
|
|
||||||
t := &rlpstruct.Type{
|
|
||||||
Name: name,
|
|
||||||
Kind: typeReflectKind(typ),
|
|
||||||
IsEncoder: bctx.isEncoder(typ),
|
|
||||||
IsDecoder: bctx.isDecoder(typ),
|
|
||||||
}
|
|
||||||
bctx.typeToStructCache[typ] = t
|
|
||||||
|
|
||||||
// Assign element type.
|
|
||||||
switch typ.(type) {
|
|
||||||
case *types.Array, *types.Slice, *types.Pointer:
|
|
||||||
etype := typ.(interface{ Elem() types.Type }).Elem()
|
|
||||||
t.Elem = bctx.typeToStructType(etype)
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// genContext is passed to the gen* methods of op when generating
|
|
||||||
// the output code. It tracks packages to be imported by the output
|
|
||||||
// file and assigns unique names of temporary variables.
|
|
||||||
type genContext struct {
|
|
||||||
inPackage *types.Package
|
|
||||||
imports map[string]struct{}
|
|
||||||
tempCounter int
|
|
||||||
}
|
|
||||||
|
|
||||||
func newGenContext(inPackage *types.Package) *genContext {
|
|
||||||
return &genContext{
|
|
||||||
inPackage: inPackage,
|
|
||||||
imports: make(map[string]struct{}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *genContext) temp() string {
|
|
||||||
v := fmt.Sprintf("_tmp%d", ctx.tempCounter)
|
|
||||||
ctx.tempCounter++
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *genContext) resetTemp() {
|
|
||||||
ctx.tempCounter = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *genContext) addImport(path string) {
|
|
||||||
if path == ctx.inPackage.Path() {
|
|
||||||
return // avoid importing the package that we're generating in.
|
|
||||||
}
|
|
||||||
// TODO: renaming?
|
|
||||||
ctx.imports[path] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// importsList returns all packages that need to be imported.
|
|
||||||
func (ctx *genContext) importsList() []string {
|
|
||||||
imp := make([]string, 0, len(ctx.imports))
|
|
||||||
for k := range ctx.imports {
|
|
||||||
imp = append(imp, k)
|
|
||||||
}
|
|
||||||
sort.Strings(imp)
|
|
||||||
return imp
|
|
||||||
}
|
|
||||||
|
|
||||||
// qualify is the types.Qualifier used for printing types.
|
|
||||||
func (ctx *genContext) qualify(pkg *types.Package) string {
|
|
||||||
if pkg.Path() == ctx.inPackage.Path() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
ctx.addImport(pkg.Path())
|
|
||||||
// TODO: renaming?
|
|
||||||
return pkg.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
type op interface {
|
|
||||||
// genWrite creates the encoder. The generated code should write v,
|
|
||||||
// which is any Go expression, to the rlp.EncoderBuffer 'w'.
|
|
||||||
genWrite(ctx *genContext, v string) string
|
|
||||||
|
|
||||||
// genDecode creates the decoder. The generated code should read
|
|
||||||
// a value from the rlp.Stream 'dec' and store it to dst.
|
|
||||||
genDecode(ctx *genContext) (string, string)
|
|
||||||
}
|
|
||||||
|
|
||||||
// basicOp handles basic types bool, uint*, string.
|
|
||||||
type basicOp struct {
|
|
||||||
typ types.Type
|
|
||||||
writeMethod string // calle write the value
|
|
||||||
writeArgType types.Type // parameter type of writeMethod
|
|
||||||
decMethod string
|
|
||||||
decResultType types.Type // return type of decMethod
|
|
||||||
decUseBitSize bool // if true, result bit size is appended to decMethod
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*buildContext) makeBasicOp(typ *types.Basic) (op, error) {
|
|
||||||
op := basicOp{typ: typ}
|
|
||||||
kind := typ.Kind()
|
|
||||||
switch {
|
|
||||||
case kind == types.Bool:
|
|
||||||
op.writeMethod = "WriteBool"
|
|
||||||
op.writeArgType = types.Typ[types.Bool]
|
|
||||||
op.decMethod = "Bool"
|
|
||||||
op.decResultType = types.Typ[types.Bool]
|
|
||||||
case kind >= types.Uint8 && kind <= types.Uint64:
|
|
||||||
op.writeMethod = "WriteUint64"
|
|
||||||
op.writeArgType = types.Typ[types.Uint64]
|
|
||||||
op.decMethod = "Uint"
|
|
||||||
op.decResultType = typ
|
|
||||||
op.decUseBitSize = true
|
|
||||||
case kind == types.String:
|
|
||||||
op.writeMethod = "WriteString"
|
|
||||||
op.writeArgType = types.Typ[types.String]
|
|
||||||
op.decMethod = "String"
|
|
||||||
op.decResultType = types.Typ[types.String]
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unhandled basic type: %v", typ)
|
|
||||||
}
|
|
||||||
return op, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*buildContext) makeByteSliceOp(typ *types.Slice) op {
|
|
||||||
if !isByte(typ.Elem()) {
|
|
||||||
panic("non-byte slice type in makeByteSliceOp")
|
|
||||||
}
|
|
||||||
bslice := types.NewSlice(types.Typ[types.Uint8])
|
|
||||||
return basicOp{
|
|
||||||
typ: typ,
|
|
||||||
writeMethod: "WriteBytes",
|
|
||||||
writeArgType: bslice,
|
|
||||||
decMethod: "Bytes",
|
|
||||||
decResultType: bslice,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bctx *buildContext) makeRawValueOp() op {
|
|
||||||
bslice := types.NewSlice(types.Typ[types.Uint8])
|
|
||||||
return basicOp{
|
|
||||||
typ: bctx.rawValueType,
|
|
||||||
writeMethod: "Write",
|
|
||||||
writeArgType: bslice,
|
|
||||||
decMethod: "Raw",
|
|
||||||
decResultType: bslice,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op basicOp) writeNeedsConversion() bool {
|
|
||||||
return !types.AssignableTo(op.typ, op.writeArgType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op basicOp) decodeNeedsConversion() bool {
|
|
||||||
return !types.AssignableTo(op.decResultType, op.typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op basicOp) genWrite(ctx *genContext, v string) string {
|
|
||||||
if op.writeNeedsConversion() {
|
|
||||||
v = fmt.Sprintf("%s(%s)", op.writeArgType, v)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("w.%s(%s)\n", op.writeMethod, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op basicOp) genDecode(ctx *genContext) (string, string) {
|
|
||||||
var (
|
|
||||||
resultV = ctx.temp()
|
|
||||||
result = resultV
|
|
||||||
method = op.decMethod
|
|
||||||
)
|
|
||||||
if op.decUseBitSize {
|
|
||||||
// Note: For now, this only works for platform-independent integer
|
|
||||||
// sizes. makeBasicOp forbids the platform-dependent types.
|
|
||||||
var sizes types.StdSizes
|
|
||||||
method = fmt.Sprintf("%s%d", op.decMethod, sizes.Sizeof(op.typ)*8)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the decoder method.
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "%s, err := dec.%s()\n", resultV, method)
|
|
||||||
fmt.Fprintf(&b, "if err != nil { return err }\n")
|
|
||||||
if op.decodeNeedsConversion() {
|
|
||||||
conv := ctx.temp()
|
|
||||||
fmt.Fprintf(&b, "%s := %s(%s)\n", conv, types.TypeString(op.typ, ctx.qualify), resultV)
|
|
||||||
result = conv
|
|
||||||
}
|
|
||||||
return result, b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// byteArrayOp handles [...]byte.
|
|
||||||
type byteArrayOp struct {
|
|
||||||
typ types.Type
|
|
||||||
name types.Type // name != typ for named byte array types (e.g. common.Address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bctx *buildContext) makeByteArrayOp(name *types.Named, typ *types.Array) byteArrayOp {
|
|
||||||
nt := types.Type(name)
|
|
||||||
if name == nil {
|
|
||||||
nt = typ
|
|
||||||
}
|
|
||||||
return byteArrayOp{typ, nt}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op byteArrayOp) genWrite(ctx *genContext, v string) string {
|
|
||||||
return fmt.Sprintf("w.WriteBytes(%s[:])\n", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op byteArrayOp) genDecode(ctx *genContext) (string, string) {
|
|
||||||
var resultV = ctx.temp()
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "var %s %s\n", resultV, types.TypeString(op.name, ctx.qualify))
|
|
||||||
fmt.Fprintf(&b, "if err := dec.ReadBytes(%s[:]); err != nil { return err }\n", resultV)
|
|
||||||
return resultV, b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// bigIntOp handles big.Int.
|
|
||||||
// This exists because big.Int has it's own decoder operation on rlp.Stream,
|
|
||||||
// but the decode method returns *big.Int, so it needs to be dereferenced.
|
|
||||||
type bigIntOp struct {
|
|
||||||
pointer bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op bigIntOp) genWrite(ctx *genContext, v string) string {
|
|
||||||
var b bytes.Buffer
|
|
||||||
|
|
||||||
fmt.Fprintf(&b, "if %s.Sign() == -1 {\n", v)
|
|
||||||
fmt.Fprintf(&b, " return rlp.ErrNegativeBigInt\n")
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
dst := v
|
|
||||||
if !op.pointer {
|
|
||||||
dst = "&" + v
|
|
||||||
}
|
|
||||||
fmt.Fprintf(&b, "w.WriteBigInt(%s)\n", dst)
|
|
||||||
|
|
||||||
// Wrap with nil check.
|
|
||||||
if op.pointer {
|
|
||||||
code := b.String()
|
|
||||||
b.Reset()
|
|
||||||
fmt.Fprintf(&b, "if %s == nil {\n", v)
|
|
||||||
fmt.Fprintf(&b, " w.Write(rlp.EmptyString)")
|
|
||||||
fmt.Fprintf(&b, "} else {\n")
|
|
||||||
fmt.Fprint(&b, code)
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op bigIntOp) genDecode(ctx *genContext) (string, string) {
|
|
||||||
var resultV = ctx.temp()
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "%s, err := dec.BigInt()\n", resultV)
|
|
||||||
fmt.Fprintf(&b, "if err != nil { return err }\n")
|
|
||||||
|
|
||||||
result := resultV
|
|
||||||
if !op.pointer {
|
|
||||||
result = "(*" + resultV + ")"
|
|
||||||
}
|
|
||||||
return result, b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint256Op handles "github.com/holiman/uint256".Int
|
|
||||||
type uint256Op struct {
|
|
||||||
pointer bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op uint256Op) genWrite(ctx *genContext, v string) string {
|
|
||||||
var b bytes.Buffer
|
|
||||||
|
|
||||||
dst := v
|
|
||||||
if !op.pointer {
|
|
||||||
dst = "&" + v
|
|
||||||
}
|
|
||||||
fmt.Fprintf(&b, "w.WriteUint256(%s)\n", dst)
|
|
||||||
|
|
||||||
// Wrap with nil check.
|
|
||||||
if op.pointer {
|
|
||||||
code := b.String()
|
|
||||||
b.Reset()
|
|
||||||
fmt.Fprintf(&b, "if %s == nil {\n", v)
|
|
||||||
fmt.Fprintf(&b, " w.Write(rlp.EmptyString)")
|
|
||||||
fmt.Fprintf(&b, "} else {\n")
|
|
||||||
fmt.Fprint(&b, code)
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op uint256Op) genDecode(ctx *genContext) (string, string) {
|
|
||||||
ctx.addImport("github.com/holiman/uint256")
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
resultV := ctx.temp()
|
|
||||||
fmt.Fprintf(&b, "var %s uint256.Int\n", resultV)
|
|
||||||
fmt.Fprintf(&b, "if err := dec.ReadUint256(&%s); err != nil { return err }\n", resultV)
|
|
||||||
|
|
||||||
result := resultV
|
|
||||||
if op.pointer {
|
|
||||||
result = "&" + resultV
|
|
||||||
}
|
|
||||||
return result, b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// encoderDecoderOp handles rlp.Encoder and rlp.Decoder.
|
|
||||||
// In order to be used with this, the type must implement both interfaces.
|
|
||||||
// This restriction may be lifted in the future by creating separate ops for
|
|
||||||
// encoding and decoding.
|
|
||||||
type encoderDecoderOp struct {
|
|
||||||
typ types.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op encoderDecoderOp) genWrite(ctx *genContext, v string) string {
|
|
||||||
return fmt.Sprintf("if err := %s.EncodeRLP(w); err != nil { return err }\n", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op encoderDecoderOp) genDecode(ctx *genContext) (string, string) {
|
|
||||||
// DecodeRLP must have pointer receiver, and this is verified in makeOp.
|
|
||||||
etyp := op.typ.(*types.Pointer).Elem()
|
|
||||||
var resultV = ctx.temp()
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "%s := new(%s)\n", resultV, types.TypeString(etyp, ctx.qualify))
|
|
||||||
fmt.Fprintf(&b, "if err := %s.DecodeRLP(dec); err != nil { return err }\n", resultV)
|
|
||||||
return resultV, b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ptrOp handles pointer types.
|
|
||||||
type ptrOp struct {
|
|
||||||
elemTyp types.Type
|
|
||||||
elem op
|
|
||||||
nilOK bool
|
|
||||||
nilValue rlpstruct.NilKind
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bctx *buildContext) makePtrOp(elemTyp types.Type, tags rlpstruct.Tags) (op, error) {
|
|
||||||
elemOp, err := bctx.makeOp(nil, elemTyp, rlpstruct.Tags{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
op := ptrOp{elemTyp: elemTyp, elem: elemOp}
|
|
||||||
|
|
||||||
// Determine nil value.
|
|
||||||
if tags.NilOK {
|
|
||||||
op.nilOK = true
|
|
||||||
op.nilValue = tags.NilKind
|
|
||||||
} else {
|
|
||||||
styp := bctx.typeToStructType(elemTyp)
|
|
||||||
op.nilValue = styp.DefaultNilValue()
|
|
||||||
}
|
|
||||||
return op, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op ptrOp) genWrite(ctx *genContext, v string) string {
|
|
||||||
// Note: in writer functions, accesses to v are read-only, i.e. v is any Go
|
|
||||||
// expression. To make all accesses work through the pointer, we substitute
|
|
||||||
// v with (*v). This is required for most accesses including `v`, `call(v)`,
|
|
||||||
// and `v[index]` on slices.
|
|
||||||
//
|
|
||||||
// For `v.field` and `v[:]` on arrays, the dereference operation is not required.
|
|
||||||
var vv string
|
|
||||||
_, isStruct := op.elem.(structOp)
|
|
||||||
_, isByteArray := op.elem.(byteArrayOp)
|
|
||||||
if isStruct || isByteArray {
|
|
||||||
vv = v
|
|
||||||
} else {
|
|
||||||
vv = fmt.Sprintf("(*%s)", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "if %s == nil {\n", v)
|
|
||||||
fmt.Fprintf(&b, " w.Write([]byte{0x%X})\n", op.nilValue)
|
|
||||||
fmt.Fprintf(&b, "} else {\n")
|
|
||||||
fmt.Fprintf(&b, " %s", op.elem.genWrite(ctx, vv))
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op ptrOp) genDecode(ctx *genContext) (string, string) {
|
|
||||||
result, code := op.elem.genDecode(ctx)
|
|
||||||
if !op.nilOK {
|
|
||||||
// If nil pointers are not allowed, we can just decode the element.
|
|
||||||
return "&" + result, code
|
|
||||||
}
|
|
||||||
|
|
||||||
// nil is allowed, so check the kind and size first.
|
|
||||||
// If size is zero and kind matches the nilKind of the type,
|
|
||||||
// the value decodes as a nil pointer.
|
|
||||||
var (
|
|
||||||
resultV = ctx.temp()
|
|
||||||
kindV = ctx.temp()
|
|
||||||
sizeV = ctx.temp()
|
|
||||||
wantKind string
|
|
||||||
)
|
|
||||||
if op.nilValue == rlpstruct.NilKindList {
|
|
||||||
wantKind = "rlp.List"
|
|
||||||
} else {
|
|
||||||
wantKind = "rlp.String"
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "var %s %s\n", resultV, types.TypeString(types.NewPointer(op.elemTyp), ctx.qualify))
|
|
||||||
fmt.Fprintf(&b, "if %s, %s, err := dec.Kind(); err != nil {\n", kindV, sizeV)
|
|
||||||
fmt.Fprintf(&b, " return err\n")
|
|
||||||
fmt.Fprintf(&b, "} else if %s != 0 || %s != %s {\n", sizeV, kindV, wantKind)
|
|
||||||
fmt.Fprint(&b, code)
|
|
||||||
fmt.Fprintf(&b, " %s = &%s\n", resultV, result)
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
return resultV, b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// structOp handles struct types.
|
|
||||||
type structOp struct {
|
|
||||||
named *types.Named
|
|
||||||
typ *types.Struct
|
|
||||||
fields []*structField
|
|
||||||
optionalFields []*structField
|
|
||||||
}
|
|
||||||
|
|
||||||
type structField struct {
|
|
||||||
name string
|
|
||||||
typ types.Type
|
|
||||||
elem op
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bctx *buildContext) makeStructOp(named *types.Named, typ *types.Struct) (op, error) {
|
|
||||||
// Convert fields to []rlpstruct.Field.
|
|
||||||
var allStructFields []rlpstruct.Field
|
|
||||||
for i := 0; i < typ.NumFields(); i++ {
|
|
||||||
f := typ.Field(i)
|
|
||||||
allStructFields = append(allStructFields, rlpstruct.Field{
|
|
||||||
Name: f.Name(),
|
|
||||||
Exported: f.Exported(),
|
|
||||||
Index: i,
|
|
||||||
Tag: typ.Tag(i),
|
|
||||||
Type: *bctx.typeToStructType(f.Type()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter/validate fields.
|
|
||||||
fields, tags, err := rlpstruct.ProcessFields(allStructFields)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create field ops.
|
|
||||||
var op = structOp{named: named, typ: typ}
|
|
||||||
for i, field := range fields {
|
|
||||||
// Advanced struct tags are not supported yet.
|
|
||||||
tag := tags[i]
|
|
||||||
if err := checkUnsupportedTags(field.Name, tag); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
typ := typ.Field(field.Index).Type()
|
|
||||||
elem, err := bctx.makeOp(nil, typ, tags[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("field %s: %v", field.Name, err)
|
|
||||||
}
|
|
||||||
f := &structField{name: field.Name, typ: typ, elem: elem}
|
|
||||||
if tag.Optional {
|
|
||||||
op.optionalFields = append(op.optionalFields, f)
|
|
||||||
} else {
|
|
||||||
op.fields = append(op.fields, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return op, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkUnsupportedTags(field string, tag rlpstruct.Tags) error {
|
|
||||||
if tag.Tail {
|
|
||||||
return fmt.Errorf(`field %s has unsupported struct tag "tail"`, field)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op structOp) genWrite(ctx *genContext, v string) string {
|
|
||||||
var b bytes.Buffer
|
|
||||||
var listMarker = ctx.temp()
|
|
||||||
fmt.Fprintf(&b, "%s := w.List()\n", listMarker)
|
|
||||||
for _, field := range op.fields {
|
|
||||||
selector := v + "." + field.name
|
|
||||||
fmt.Fprint(&b, field.elem.genWrite(ctx, selector))
|
|
||||||
}
|
|
||||||
op.writeOptionalFields(&b, ctx, v)
|
|
||||||
fmt.Fprintf(&b, "w.ListEnd(%s)\n", listMarker)
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op structOp) writeOptionalFields(b *bytes.Buffer, ctx *genContext, v string) {
|
|
||||||
if len(op.optionalFields) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// First check zero-ness of all optional fields.
|
|
||||||
var zeroV = make([]string, len(op.optionalFields))
|
|
||||||
for i, field := range op.optionalFields {
|
|
||||||
selector := v + "." + field.name
|
|
||||||
zeroV[i] = ctx.temp()
|
|
||||||
fmt.Fprintf(b, "%s := %s\n", zeroV[i], nonZeroCheck(selector, field.typ, ctx.qualify))
|
|
||||||
}
|
|
||||||
// Now write the fields.
|
|
||||||
for i, field := range op.optionalFields {
|
|
||||||
selector := v + "." + field.name
|
|
||||||
cond := ""
|
|
||||||
for j := i; j < len(op.optionalFields); j++ {
|
|
||||||
if j > i {
|
|
||||||
cond += " || "
|
|
||||||
}
|
|
||||||
cond += zeroV[j]
|
|
||||||
}
|
|
||||||
fmt.Fprintf(b, "if %s {\n", cond)
|
|
||||||
fmt.Fprint(b, field.elem.genWrite(ctx, selector))
|
|
||||||
fmt.Fprintf(b, "}\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op structOp) genDecode(ctx *genContext) (string, string) {
|
|
||||||
// Get the string representation of the type.
|
|
||||||
// Here, named types are handled separately because the output
|
|
||||||
// would contain a copy of the struct definition otherwise.
|
|
||||||
var typeName string
|
|
||||||
if op.named != nil {
|
|
||||||
typeName = types.TypeString(op.named, ctx.qualify)
|
|
||||||
} else {
|
|
||||||
typeName = types.TypeString(op.typ, ctx.qualify)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create struct object.
|
|
||||||
var resultV = ctx.temp()
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "var %s %s\n", resultV, typeName)
|
|
||||||
|
|
||||||
// Decode fields.
|
|
||||||
fmt.Fprintf(&b, "{\n")
|
|
||||||
fmt.Fprintf(&b, "if _, err := dec.List(); err != nil { return err }\n")
|
|
||||||
for _, field := range op.fields {
|
|
||||||
result, code := field.elem.genDecode(ctx)
|
|
||||||
fmt.Fprintf(&b, "// %s:\n", field.name)
|
|
||||||
fmt.Fprint(&b, code)
|
|
||||||
fmt.Fprintf(&b, "%s.%s = %s\n", resultV, field.name, result)
|
|
||||||
}
|
|
||||||
op.decodeOptionalFields(&b, ctx, resultV)
|
|
||||||
fmt.Fprintf(&b, "if err := dec.ListEnd(); err != nil { return err }\n")
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
return resultV, b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op structOp) decodeOptionalFields(b *bytes.Buffer, ctx *genContext, resultV string) {
|
|
||||||
var suffix bytes.Buffer
|
|
||||||
for _, field := range op.optionalFields {
|
|
||||||
result, code := field.elem.genDecode(ctx)
|
|
||||||
fmt.Fprintf(b, "// %s:\n", field.name)
|
|
||||||
fmt.Fprintf(b, "if dec.MoreDataInList() {\n")
|
|
||||||
fmt.Fprint(b, code)
|
|
||||||
fmt.Fprintf(b, "%s.%s = %s\n", resultV, field.name, result)
|
|
||||||
fmt.Fprintf(&suffix, "}\n")
|
|
||||||
}
|
|
||||||
suffix.WriteTo(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sliceOp handles slice types.
|
|
||||||
type sliceOp struct {
|
|
||||||
typ *types.Slice
|
|
||||||
elemOp op
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bctx *buildContext) makeSliceOp(typ *types.Slice) (op, error) {
|
|
||||||
elemOp, err := bctx.makeOp(nil, typ.Elem(), rlpstruct.Tags{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return sliceOp{typ: typ, elemOp: elemOp}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op sliceOp) genWrite(ctx *genContext, v string) string {
|
|
||||||
var (
|
|
||||||
listMarker = ctx.temp() // holds return value of w.List()
|
|
||||||
iterElemV = ctx.temp() // iteration variable
|
|
||||||
elemCode = op.elemOp.genWrite(ctx, iterElemV)
|
|
||||||
)
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "%s := w.List()\n", listMarker)
|
|
||||||
fmt.Fprintf(&b, "for _, %s := range %s {\n", iterElemV, v)
|
|
||||||
fmt.Fprint(&b, elemCode)
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
fmt.Fprintf(&b, "w.ListEnd(%s)\n", listMarker)
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op sliceOp) genDecode(ctx *genContext) (string, string) {
|
|
||||||
var sliceV = ctx.temp() // holds the output slice
|
|
||||||
elemResult, elemCode := op.elemOp.genDecode(ctx)
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "var %s %s\n", sliceV, types.TypeString(op.typ, ctx.qualify))
|
|
||||||
fmt.Fprintf(&b, "if _, err := dec.List(); err != nil { return err }\n")
|
|
||||||
fmt.Fprintf(&b, "for dec.MoreDataInList() {\n")
|
|
||||||
fmt.Fprintf(&b, " %s", elemCode)
|
|
||||||
fmt.Fprintf(&b, " %s = append(%s, %s)\n", sliceV, sliceV, elemResult)
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
fmt.Fprintf(&b, "if err := dec.ListEnd(); err != nil { return err }\n")
|
|
||||||
return sliceV, b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bctx *buildContext) makeOp(name *types.Named, typ types.Type, tags rlpstruct.Tags) (op, error) {
|
|
||||||
switch typ := typ.(type) {
|
|
||||||
case *types.Named:
|
|
||||||
if isBigInt(typ) {
|
|
||||||
return bigIntOp{}, nil
|
|
||||||
}
|
|
||||||
if isUint256(typ) {
|
|
||||||
return uint256Op{}, nil
|
|
||||||
}
|
|
||||||
if typ == bctx.rawValueType {
|
|
||||||
return bctx.makeRawValueOp(), nil
|
|
||||||
}
|
|
||||||
if bctx.isDecoder(typ) {
|
|
||||||
return nil, fmt.Errorf("type %v implements rlp.Decoder with non-pointer receiver", typ)
|
|
||||||
}
|
|
||||||
// TODO: same check for encoder?
|
|
||||||
return bctx.makeOp(typ, typ.Underlying(), tags)
|
|
||||||
case *types.Pointer:
|
|
||||||
if isBigInt(typ.Elem()) {
|
|
||||||
return bigIntOp{pointer: true}, nil
|
|
||||||
}
|
|
||||||
if isUint256(typ.Elem()) {
|
|
||||||
return uint256Op{pointer: true}, nil
|
|
||||||
}
|
|
||||||
// Encoder/Decoder interfaces.
|
|
||||||
if bctx.isEncoder(typ) {
|
|
||||||
if bctx.isDecoder(typ) {
|
|
||||||
return encoderDecoderOp{typ}, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("type %v implements rlp.Encoder but not rlp.Decoder", typ)
|
|
||||||
}
|
|
||||||
if bctx.isDecoder(typ) {
|
|
||||||
return nil, fmt.Errorf("type %v implements rlp.Decoder but not rlp.Encoder", typ)
|
|
||||||
}
|
|
||||||
// Default pointer handling.
|
|
||||||
return bctx.makePtrOp(typ.Elem(), tags)
|
|
||||||
case *types.Basic:
|
|
||||||
return bctx.makeBasicOp(typ)
|
|
||||||
case *types.Struct:
|
|
||||||
return bctx.makeStructOp(name, typ)
|
|
||||||
case *types.Slice:
|
|
||||||
etyp := typ.Elem()
|
|
||||||
if isByte(etyp) && !bctx.isEncoder(etyp) {
|
|
||||||
return bctx.makeByteSliceOp(typ), nil
|
|
||||||
}
|
|
||||||
return bctx.makeSliceOp(typ)
|
|
||||||
case *types.Array:
|
|
||||||
etyp := typ.Elem()
|
|
||||||
if isByte(etyp) && !bctx.isEncoder(etyp) {
|
|
||||||
return bctx.makeByteArrayOp(name, typ), nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("unhandled array type: %v", typ)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unhandled type: %v", typ)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateDecoder generates the DecodeRLP method on 'typ'.
|
|
||||||
func generateDecoder(ctx *genContext, typ string, op op) []byte {
|
|
||||||
ctx.resetTemp()
|
|
||||||
ctx.addImport(pathOfPackageRLP)
|
|
||||||
|
|
||||||
result, code := op.genDecode(ctx)
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "func (obj *%s) DecodeRLP(dec *rlp.Stream) error {\n", typ)
|
|
||||||
fmt.Fprint(&b, code)
|
|
||||||
fmt.Fprintf(&b, " *obj = %s\n", result)
|
|
||||||
fmt.Fprintf(&b, " return nil\n")
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
return b.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateEncoder generates the EncodeRLP method on 'typ'.
|
|
||||||
func generateEncoder(ctx *genContext, typ string, op op) []byte {
|
|
||||||
ctx.resetTemp()
|
|
||||||
ctx.addImport("io")
|
|
||||||
ctx.addImport(pathOfPackageRLP)
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "func (obj *%s) EncodeRLP(_w io.Writer) error {\n", typ)
|
|
||||||
fmt.Fprintf(&b, " w := rlp.NewEncoderBuffer(_w)\n")
|
|
||||||
fmt.Fprint(&b, op.genWrite(ctx, "obj"))
|
|
||||||
fmt.Fprintf(&b, " return w.Flush()\n")
|
|
||||||
fmt.Fprintf(&b, "}\n")
|
|
||||||
return b.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bctx *buildContext) generate(typ *types.Named, encoder, decoder bool) ([]byte, error) {
|
|
||||||
bctx.topType = typ
|
|
||||||
|
|
||||||
pkg := typ.Obj().Pkg()
|
|
||||||
op, err := bctx.makeOp(nil, typ, rlpstruct.Tags{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
ctx = newGenContext(pkg)
|
|
||||||
encSource []byte
|
|
||||||
decSource []byte
|
|
||||||
)
|
|
||||||
if encoder {
|
|
||||||
encSource = generateEncoder(ctx, typ.Obj().Name(), op)
|
|
||||||
}
|
|
||||||
if decoder {
|
|
||||||
decSource = generateDecoder(ctx, typ.Obj().Name(), op)
|
|
||||||
}
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
fmt.Fprintf(&b, "package %s\n\n", pkg.Name())
|
|
||||||
for _, imp := range ctx.importsList() {
|
|
||||||
fmt.Fprintf(&b, "import %q\n", imp)
|
|
||||||
}
|
|
||||||
if encoder {
|
|
||||||
fmt.Fprintln(&b)
|
|
||||||
b.Write(encSource)
|
|
||||||
}
|
|
||||||
if decoder {
|
|
||||||
fmt.Fprintln(&b)
|
|
||||||
b.Write(decSource)
|
|
||||||
}
|
|
||||||
|
|
||||||
source := b.Bytes()
|
|
||||||
// fmt.Println(string(source))
|
|
||||||
return format.Source(source)
|
|
||||||
}
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
// Copyright 2022 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 main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
"go/importer"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"go/types"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Package RLP is loaded only once and reused for all tests.
|
|
||||||
var (
|
|
||||||
testFset = token.NewFileSet()
|
|
||||||
testImporter = importer.ForCompiler(testFset, "source", nil).(types.ImporterFrom)
|
|
||||||
testPackageRLP *types.Package
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
testPackageRLP, err = testImporter.ImportFrom(pathOfPackageRLP, cwd, 0)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Errorf("can't load package RLP: %v", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256"}
|
|
||||||
|
|
||||||
func TestOutput(t *testing.T) {
|
|
||||||
for _, test := range tests {
|
|
||||||
test := test
|
|
||||||
t.Run(test, func(t *testing.T) {
|
|
||||||
inputFile := filepath.Join("testdata", test+".in.txt")
|
|
||||||
outputFile := filepath.Join("testdata", test+".out.txt")
|
|
||||||
bctx, typ, err := loadTestSource(inputFile, "Test")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("error loading test source:", err)
|
|
||||||
}
|
|
||||||
output, err := bctx.generate(typ, true, true)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("error in generate:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set this environment variable to regenerate the test outputs.
|
|
||||||
if os.Getenv("WRITE_TEST_FILES") != "" {
|
|
||||||
os.WriteFile(outputFile, output, 0644)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if output matches.
|
|
||||||
wantOutput, err := os.ReadFile(outputFile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("error loading expected test output:", err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(output, wantOutput) {
|
|
||||||
t.Fatalf("output mismatch, want: %v got %v", string(wantOutput), string(output))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadTestSource(file string, typeName string) (*buildContext, *types.Named, error) {
|
|
||||||
// Load the test input.
|
|
||||||
content, err := os.ReadFile(file)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
f, err := parser.ParseFile(testFset, file, content, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
conf := types.Config{Importer: testImporter}
|
|
||||||
pkg, err := conf.Check("test", testFset, []*ast.File{f}, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the test struct.
|
|
||||||
bctx := newBuildContext(testPackageRLP)
|
|
||||||
typ, err := lookupStructType(pkg.Scope(), typeName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("can't find type %s: %v", typeName, err)
|
|
||||||
}
|
|
||||||
return bctx, typ, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
// Copyright 2022 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 main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/tools/go/packages"
|
|
||||||
)
|
|
||||||
|
|
||||||
const pathOfPackageRLP = "github.com/ethereum/go-ethereum/rlp"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var (
|
|
||||||
pkgdir = flag.String("dir", ".", "input package")
|
|
||||||
output = flag.String("out", "-", "output file (default is stdout)")
|
|
||||||
genEncoder = flag.Bool("encoder", true, "generate EncodeRLP?")
|
|
||||||
genDecoder = flag.Bool("decoder", false, "generate DecodeRLP?")
|
|
||||||
typename = flag.String("type", "", "type to generate methods for")
|
|
||||||
)
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
cfg := Config{
|
|
||||||
Dir: *pkgdir,
|
|
||||||
Type: *typename,
|
|
||||||
GenerateEncoder: *genEncoder,
|
|
||||||
GenerateDecoder: *genDecoder,
|
|
||||||
}
|
|
||||||
code, err := cfg.process()
|
|
||||||
if err != nil {
|
|
||||||
fatal(err)
|
|
||||||
}
|
|
||||||
if *output == "-" {
|
|
||||||
os.Stdout.Write(code)
|
|
||||||
} else if err := os.WriteFile(*output, code, 0600); err != nil {
|
|
||||||
fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fatal(args ...interface{}) {
|
|
||||||
fmt.Fprintln(os.Stderr, args...)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
Dir string // input package directory
|
|
||||||
Type string
|
|
||||||
|
|
||||||
GenerateEncoder bool
|
|
||||||
GenerateDecoder bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// process generates the Go code.
|
|
||||||
func (cfg *Config) process() (code []byte, err error) {
|
|
||||||
// Load packages.
|
|
||||||
pcfg := &packages.Config{
|
|
||||||
Mode: packages.NeedName | packages.NeedTypes,
|
|
||||||
Dir: cfg.Dir,
|
|
||||||
}
|
|
||||||
ps, err := packages.Load(pcfg, pathOfPackageRLP, ".")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(ps) == 0 {
|
|
||||||
return nil, fmt.Errorf("no Go package found in %s", cfg.Dir)
|
|
||||||
}
|
|
||||||
packages.PrintErrors(ps)
|
|
||||||
|
|
||||||
// Find the packages that were loaded.
|
|
||||||
var (
|
|
||||||
pkg *types.Package
|
|
||||||
packageRLP *types.Package
|
|
||||||
)
|
|
||||||
for _, p := range ps {
|
|
||||||
if len(p.Errors) > 0 {
|
|
||||||
return nil, fmt.Errorf("package %s has errors", p.PkgPath)
|
|
||||||
}
|
|
||||||
if p.PkgPath == pathOfPackageRLP {
|
|
||||||
packageRLP = p.Types
|
|
||||||
} else {
|
|
||||||
pkg = p.Types
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bctx := newBuildContext(packageRLP)
|
|
||||||
|
|
||||||
// Find the type and generate.
|
|
||||||
typ, err := lookupStructType(pkg.Scope(), cfg.Type)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("can't find %s in %s: %v", cfg.Type, pkg, err)
|
|
||||||
}
|
|
||||||
code, err = bctx.generate(typ, cfg.GenerateEncoder, cfg.GenerateDecoder)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add build comments.
|
|
||||||
// This is done here to avoid processing these lines with gofmt.
|
|
||||||
var header bytes.Buffer
|
|
||||||
fmt.Fprint(&header, "// Code generated by rlpgen. DO NOT EDIT.\n\n")
|
|
||||||
return append(header.Bytes(), code...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupStructType(scope *types.Scope, name string) (*types.Named, error) {
|
|
||||||
typ, err := lookupType(scope, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, ok := typ.Underlying().(*types.Struct)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("not a struct type")
|
|
||||||
}
|
|
||||||
return typ, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupType(scope *types.Scope, name string) (*types.Named, error) {
|
|
||||||
obj := scope.Lookup(name)
|
|
||||||
if obj == nil {
|
|
||||||
return nil, errors.New("no such identifier")
|
|
||||||
}
|
|
||||||
typ, ok := obj.(*types.TypeName)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("not a type")
|
|
||||||
}
|
|
||||||
return typ.Type().(*types.Named), nil
|
|
||||||
}
|
|
||||||
10
rlp/rlpgen/testdata/bigint.in.txt
vendored
10
rlp/rlpgen/testdata/bigint.in.txt
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
// -*- mode: go -*-
|
|
||||||
|
|
||||||
package test
|
|
||||||
|
|
||||||
import "math/big"
|
|
||||||
|
|
||||||
type Test struct {
|
|
||||||
Int *big.Int
|
|
||||||
IntNoPtr big.Int
|
|
||||||
}
|
|
||||||
49
rlp/rlpgen/testdata/bigint.out.txt
vendored
49
rlp/rlpgen/testdata/bigint.out.txt
vendored
|
|
@ -1,49 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func (obj *Test) EncodeRLP(_w io.Writer) error {
|
|
||||||
w := rlp.NewEncoderBuffer(_w)
|
|
||||||
_tmp0 := w.List()
|
|
||||||
if obj.Int == nil {
|
|
||||||
w.Write(rlp.EmptyString)
|
|
||||||
} else {
|
|
||||||
if obj.Int.Sign() == -1 {
|
|
||||||
return rlp.ErrNegativeBigInt
|
|
||||||
}
|
|
||||||
w.WriteBigInt(obj.Int)
|
|
||||||
}
|
|
||||||
if obj.IntNoPtr.Sign() == -1 {
|
|
||||||
return rlp.ErrNegativeBigInt
|
|
||||||
}
|
|
||||||
w.WriteBigInt(&obj.IntNoPtr)
|
|
||||||
w.ListEnd(_tmp0)
|
|
||||||
return w.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Test) DecodeRLP(dec *rlp.Stream) error {
|
|
||||||
var _tmp0 Test
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Int:
|
|
||||||
_tmp1, err := dec.BigInt()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.Int = _tmp1
|
|
||||||
// IntNoPtr:
|
|
||||||
_tmp2, err := dec.BigInt()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.IntNoPtr = (*_tmp2)
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*obj = _tmp0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
30
rlp/rlpgen/testdata/nil.in.txt
vendored
30
rlp/rlpgen/testdata/nil.in.txt
vendored
|
|
@ -1,30 +0,0 @@
|
||||||
// -*- mode: go -*-
|
|
||||||
|
|
||||||
package test
|
|
||||||
|
|
||||||
type Aux struct{
|
|
||||||
A uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type Test struct{
|
|
||||||
Uint8 *byte `rlp:"nil"`
|
|
||||||
Uint8List *byte `rlp:"nilList"`
|
|
||||||
|
|
||||||
Uint32 *uint32 `rlp:"nil"`
|
|
||||||
Uint32List *uint32 `rlp:"nilList"`
|
|
||||||
|
|
||||||
Uint64 *uint64 `rlp:"nil"`
|
|
||||||
Uint64List *uint64 `rlp:"nilList"`
|
|
||||||
|
|
||||||
String *string `rlp:"nil"`
|
|
||||||
StringList *string `rlp:"nilList"`
|
|
||||||
|
|
||||||
ByteArray *[3]byte `rlp:"nil"`
|
|
||||||
ByteArrayList *[3]byte `rlp:"nilList"`
|
|
||||||
|
|
||||||
ByteSlice *[]byte `rlp:"nil"`
|
|
||||||
ByteSliceList *[]byte `rlp:"nilList"`
|
|
||||||
|
|
||||||
Struct *Aux `rlp:"nil"`
|
|
||||||
StructString *Aux `rlp:"nilString"`
|
|
||||||
}
|
|
||||||
289
rlp/rlpgen/testdata/nil.out.txt
vendored
289
rlp/rlpgen/testdata/nil.out.txt
vendored
|
|
@ -1,289 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func (obj *Test) EncodeRLP(_w io.Writer) error {
|
|
||||||
w := rlp.NewEncoderBuffer(_w)
|
|
||||||
_tmp0 := w.List()
|
|
||||||
if obj.Uint8 == nil {
|
|
||||||
w.Write([]byte{0x80})
|
|
||||||
} else {
|
|
||||||
w.WriteUint64(uint64((*obj.Uint8)))
|
|
||||||
}
|
|
||||||
if obj.Uint8List == nil {
|
|
||||||
w.Write([]byte{0xC0})
|
|
||||||
} else {
|
|
||||||
w.WriteUint64(uint64((*obj.Uint8List)))
|
|
||||||
}
|
|
||||||
if obj.Uint32 == nil {
|
|
||||||
w.Write([]byte{0x80})
|
|
||||||
} else {
|
|
||||||
w.WriteUint64(uint64((*obj.Uint32)))
|
|
||||||
}
|
|
||||||
if obj.Uint32List == nil {
|
|
||||||
w.Write([]byte{0xC0})
|
|
||||||
} else {
|
|
||||||
w.WriteUint64(uint64((*obj.Uint32List)))
|
|
||||||
}
|
|
||||||
if obj.Uint64 == nil {
|
|
||||||
w.Write([]byte{0x80})
|
|
||||||
} else {
|
|
||||||
w.WriteUint64((*obj.Uint64))
|
|
||||||
}
|
|
||||||
if obj.Uint64List == nil {
|
|
||||||
w.Write([]byte{0xC0})
|
|
||||||
} else {
|
|
||||||
w.WriteUint64((*obj.Uint64List))
|
|
||||||
}
|
|
||||||
if obj.String == nil {
|
|
||||||
w.Write([]byte{0x80})
|
|
||||||
} else {
|
|
||||||
w.WriteString((*obj.String))
|
|
||||||
}
|
|
||||||
if obj.StringList == nil {
|
|
||||||
w.Write([]byte{0xC0})
|
|
||||||
} else {
|
|
||||||
w.WriteString((*obj.StringList))
|
|
||||||
}
|
|
||||||
if obj.ByteArray == nil {
|
|
||||||
w.Write([]byte{0x80})
|
|
||||||
} else {
|
|
||||||
w.WriteBytes(obj.ByteArray[:])
|
|
||||||
}
|
|
||||||
if obj.ByteArrayList == nil {
|
|
||||||
w.Write([]byte{0xC0})
|
|
||||||
} else {
|
|
||||||
w.WriteBytes(obj.ByteArrayList[:])
|
|
||||||
}
|
|
||||||
if obj.ByteSlice == nil {
|
|
||||||
w.Write([]byte{0x80})
|
|
||||||
} else {
|
|
||||||
w.WriteBytes((*obj.ByteSlice))
|
|
||||||
}
|
|
||||||
if obj.ByteSliceList == nil {
|
|
||||||
w.Write([]byte{0xC0})
|
|
||||||
} else {
|
|
||||||
w.WriteBytes((*obj.ByteSliceList))
|
|
||||||
}
|
|
||||||
if obj.Struct == nil {
|
|
||||||
w.Write([]byte{0xC0})
|
|
||||||
} else {
|
|
||||||
_tmp1 := w.List()
|
|
||||||
w.WriteUint64(uint64(obj.Struct.A))
|
|
||||||
w.ListEnd(_tmp1)
|
|
||||||
}
|
|
||||||
if obj.StructString == nil {
|
|
||||||
w.Write([]byte{0x80})
|
|
||||||
} else {
|
|
||||||
_tmp2 := w.List()
|
|
||||||
w.WriteUint64(uint64(obj.StructString.A))
|
|
||||||
w.ListEnd(_tmp2)
|
|
||||||
}
|
|
||||||
w.ListEnd(_tmp0)
|
|
||||||
return w.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Test) DecodeRLP(dec *rlp.Stream) error {
|
|
||||||
var _tmp0 Test
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Uint8:
|
|
||||||
var _tmp2 *byte
|
|
||||||
if _tmp3, _tmp4, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp4 != 0 || _tmp3 != rlp.String {
|
|
||||||
_tmp1, err := dec.Uint8()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp2 = &_tmp1
|
|
||||||
}
|
|
||||||
_tmp0.Uint8 = _tmp2
|
|
||||||
// Uint8List:
|
|
||||||
var _tmp6 *byte
|
|
||||||
if _tmp7, _tmp8, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp8 != 0 || _tmp7 != rlp.List {
|
|
||||||
_tmp5, err := dec.Uint8()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp6 = &_tmp5
|
|
||||||
}
|
|
||||||
_tmp0.Uint8List = _tmp6
|
|
||||||
// Uint32:
|
|
||||||
var _tmp10 *uint32
|
|
||||||
if _tmp11, _tmp12, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp12 != 0 || _tmp11 != rlp.String {
|
|
||||||
_tmp9, err := dec.Uint32()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp10 = &_tmp9
|
|
||||||
}
|
|
||||||
_tmp0.Uint32 = _tmp10
|
|
||||||
// Uint32List:
|
|
||||||
var _tmp14 *uint32
|
|
||||||
if _tmp15, _tmp16, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp16 != 0 || _tmp15 != rlp.List {
|
|
||||||
_tmp13, err := dec.Uint32()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp14 = &_tmp13
|
|
||||||
}
|
|
||||||
_tmp0.Uint32List = _tmp14
|
|
||||||
// Uint64:
|
|
||||||
var _tmp18 *uint64
|
|
||||||
if _tmp19, _tmp20, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp20 != 0 || _tmp19 != rlp.String {
|
|
||||||
_tmp17, err := dec.Uint64()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp18 = &_tmp17
|
|
||||||
}
|
|
||||||
_tmp0.Uint64 = _tmp18
|
|
||||||
// Uint64List:
|
|
||||||
var _tmp22 *uint64
|
|
||||||
if _tmp23, _tmp24, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp24 != 0 || _tmp23 != rlp.List {
|
|
||||||
_tmp21, err := dec.Uint64()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp22 = &_tmp21
|
|
||||||
}
|
|
||||||
_tmp0.Uint64List = _tmp22
|
|
||||||
// String:
|
|
||||||
var _tmp26 *string
|
|
||||||
if _tmp27, _tmp28, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp28 != 0 || _tmp27 != rlp.String {
|
|
||||||
_tmp25, err := dec.String()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp26 = &_tmp25
|
|
||||||
}
|
|
||||||
_tmp0.String = _tmp26
|
|
||||||
// StringList:
|
|
||||||
var _tmp30 *string
|
|
||||||
if _tmp31, _tmp32, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp32 != 0 || _tmp31 != rlp.List {
|
|
||||||
_tmp29, err := dec.String()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp30 = &_tmp29
|
|
||||||
}
|
|
||||||
_tmp0.StringList = _tmp30
|
|
||||||
// ByteArray:
|
|
||||||
var _tmp34 *[3]byte
|
|
||||||
if _tmp35, _tmp36, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp36 != 0 || _tmp35 != rlp.String {
|
|
||||||
var _tmp33 [3]byte
|
|
||||||
if err := dec.ReadBytes(_tmp33[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp34 = &_tmp33
|
|
||||||
}
|
|
||||||
_tmp0.ByteArray = _tmp34
|
|
||||||
// ByteArrayList:
|
|
||||||
var _tmp38 *[3]byte
|
|
||||||
if _tmp39, _tmp40, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp40 != 0 || _tmp39 != rlp.List {
|
|
||||||
var _tmp37 [3]byte
|
|
||||||
if err := dec.ReadBytes(_tmp37[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp38 = &_tmp37
|
|
||||||
}
|
|
||||||
_tmp0.ByteArrayList = _tmp38
|
|
||||||
// ByteSlice:
|
|
||||||
var _tmp42 *[]byte
|
|
||||||
if _tmp43, _tmp44, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp44 != 0 || _tmp43 != rlp.String {
|
|
||||||
_tmp41, err := dec.Bytes()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp42 = &_tmp41
|
|
||||||
}
|
|
||||||
_tmp0.ByteSlice = _tmp42
|
|
||||||
// ByteSliceList:
|
|
||||||
var _tmp46 *[]byte
|
|
||||||
if _tmp47, _tmp48, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp48 != 0 || _tmp47 != rlp.List {
|
|
||||||
_tmp45, err := dec.Bytes()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp46 = &_tmp45
|
|
||||||
}
|
|
||||||
_tmp0.ByteSliceList = _tmp46
|
|
||||||
// Struct:
|
|
||||||
var _tmp51 *Aux
|
|
||||||
if _tmp52, _tmp53, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp53 != 0 || _tmp52 != rlp.List {
|
|
||||||
var _tmp49 Aux
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// A:
|
|
||||||
_tmp50, err := dec.Uint32()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp49.A = _tmp50
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_tmp51 = &_tmp49
|
|
||||||
}
|
|
||||||
_tmp0.Struct = _tmp51
|
|
||||||
// StructString:
|
|
||||||
var _tmp56 *Aux
|
|
||||||
if _tmp57, _tmp58, err := dec.Kind(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _tmp58 != 0 || _tmp57 != rlp.String {
|
|
||||||
var _tmp54 Aux
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// A:
|
|
||||||
_tmp55, err := dec.Uint32()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp54.A = _tmp55
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_tmp56 = &_tmp54
|
|
||||||
}
|
|
||||||
_tmp0.StructString = _tmp56
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*obj = _tmp0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
17
rlp/rlpgen/testdata/optional.in.txt
vendored
17
rlp/rlpgen/testdata/optional.in.txt
vendored
|
|
@ -1,17 +0,0 @@
|
||||||
// -*- mode: go -*-
|
|
||||||
|
|
||||||
package test
|
|
||||||
|
|
||||||
type Aux struct {
|
|
||||||
A uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type Test struct {
|
|
||||||
Uint64 uint64 `rlp:"optional"`
|
|
||||||
Pointer *uint64 `rlp:"optional"`
|
|
||||||
String string `rlp:"optional"`
|
|
||||||
Slice []uint64 `rlp:"optional"`
|
|
||||||
Array [3]byte `rlp:"optional"`
|
|
||||||
NamedStruct Aux `rlp:"optional"`
|
|
||||||
AnonStruct struct{ A string } `rlp:"optional"`
|
|
||||||
}
|
|
||||||
153
rlp/rlpgen/testdata/optional.out.txt
vendored
153
rlp/rlpgen/testdata/optional.out.txt
vendored
|
|
@ -1,153 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func (obj *Test) EncodeRLP(_w io.Writer) error {
|
|
||||||
w := rlp.NewEncoderBuffer(_w)
|
|
||||||
_tmp0 := w.List()
|
|
||||||
_tmp1 := obj.Uint64 != 0
|
|
||||||
_tmp2 := obj.Pointer != nil
|
|
||||||
_tmp3 := obj.String != ""
|
|
||||||
_tmp4 := len(obj.Slice) > 0
|
|
||||||
_tmp5 := obj.Array != ([3]byte{})
|
|
||||||
_tmp6 := obj.NamedStruct != (Aux{})
|
|
||||||
_tmp7 := obj.AnonStruct != (struct{ A string }{})
|
|
||||||
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
|
||||||
w.WriteUint64(obj.Uint64)
|
|
||||||
}
|
|
||||||
if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
|
||||||
if obj.Pointer == nil {
|
|
||||||
w.Write([]byte{0x80})
|
|
||||||
} else {
|
|
||||||
w.WriteUint64((*obj.Pointer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _tmp3 || _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
|
||||||
w.WriteString(obj.String)
|
|
||||||
}
|
|
||||||
if _tmp4 || _tmp5 || _tmp6 || _tmp7 {
|
|
||||||
_tmp8 := w.List()
|
|
||||||
for _, _tmp9 := range obj.Slice {
|
|
||||||
w.WriteUint64(_tmp9)
|
|
||||||
}
|
|
||||||
w.ListEnd(_tmp8)
|
|
||||||
}
|
|
||||||
if _tmp5 || _tmp6 || _tmp7 {
|
|
||||||
w.WriteBytes(obj.Array[:])
|
|
||||||
}
|
|
||||||
if _tmp6 || _tmp7 {
|
|
||||||
_tmp10 := w.List()
|
|
||||||
w.WriteUint64(obj.NamedStruct.A)
|
|
||||||
w.ListEnd(_tmp10)
|
|
||||||
}
|
|
||||||
if _tmp7 {
|
|
||||||
_tmp11 := w.List()
|
|
||||||
w.WriteString(obj.AnonStruct.A)
|
|
||||||
w.ListEnd(_tmp11)
|
|
||||||
}
|
|
||||||
w.ListEnd(_tmp0)
|
|
||||||
return w.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Test) DecodeRLP(dec *rlp.Stream) error {
|
|
||||||
var _tmp0 Test
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Uint64:
|
|
||||||
if dec.MoreDataInList() {
|
|
||||||
_tmp1, err := dec.Uint64()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.Uint64 = _tmp1
|
|
||||||
// Pointer:
|
|
||||||
if dec.MoreDataInList() {
|
|
||||||
_tmp2, err := dec.Uint64()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.Pointer = &_tmp2
|
|
||||||
// String:
|
|
||||||
if dec.MoreDataInList() {
|
|
||||||
_tmp3, err := dec.String()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.String = _tmp3
|
|
||||||
// Slice:
|
|
||||||
if dec.MoreDataInList() {
|
|
||||||
var _tmp4 []uint64
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for dec.MoreDataInList() {
|
|
||||||
_tmp5, err := dec.Uint64()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp4 = append(_tmp4, _tmp5)
|
|
||||||
}
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.Slice = _tmp4
|
|
||||||
// Array:
|
|
||||||
if dec.MoreDataInList() {
|
|
||||||
var _tmp6 [3]byte
|
|
||||||
if err := dec.ReadBytes(_tmp6[:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.Array = _tmp6
|
|
||||||
// NamedStruct:
|
|
||||||
if dec.MoreDataInList() {
|
|
||||||
var _tmp7 Aux
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// A:
|
|
||||||
_tmp8, err := dec.Uint64()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp7.A = _tmp8
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_tmp0.NamedStruct = _tmp7
|
|
||||||
// AnonStruct:
|
|
||||||
if dec.MoreDataInList() {
|
|
||||||
var _tmp9 struct{ A string }
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// A:
|
|
||||||
_tmp10, err := dec.String()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp9.A = _tmp10
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_tmp0.AnonStruct = _tmp9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*obj = _tmp0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
11
rlp/rlpgen/testdata/rawvalue.in.txt
vendored
11
rlp/rlpgen/testdata/rawvalue.in.txt
vendored
|
|
@ -1,11 +0,0 @@
|
||||||
// -*- mode: go -*-
|
|
||||||
|
|
||||||
package test
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
|
||||||
|
|
||||||
type Test struct {
|
|
||||||
RawValue rlp.RawValue
|
|
||||||
PointerToRawValue *rlp.RawValue
|
|
||||||
SliceOfRawValue []rlp.RawValue
|
|
||||||
}
|
|
||||||
64
rlp/rlpgen/testdata/rawvalue.out.txt
vendored
64
rlp/rlpgen/testdata/rawvalue.out.txt
vendored
|
|
@ -1,64 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func (obj *Test) EncodeRLP(_w io.Writer) error {
|
|
||||||
w := rlp.NewEncoderBuffer(_w)
|
|
||||||
_tmp0 := w.List()
|
|
||||||
w.Write(obj.RawValue)
|
|
||||||
if obj.PointerToRawValue == nil {
|
|
||||||
w.Write([]byte{0x80})
|
|
||||||
} else {
|
|
||||||
w.Write((*obj.PointerToRawValue))
|
|
||||||
}
|
|
||||||
_tmp1 := w.List()
|
|
||||||
for _, _tmp2 := range obj.SliceOfRawValue {
|
|
||||||
w.Write(_tmp2)
|
|
||||||
}
|
|
||||||
w.ListEnd(_tmp1)
|
|
||||||
w.ListEnd(_tmp0)
|
|
||||||
return w.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Test) DecodeRLP(dec *rlp.Stream) error {
|
|
||||||
var _tmp0 Test
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// RawValue:
|
|
||||||
_tmp1, err := dec.Raw()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.RawValue = _tmp1
|
|
||||||
// PointerToRawValue:
|
|
||||||
_tmp2, err := dec.Raw()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.PointerToRawValue = &_tmp2
|
|
||||||
// SliceOfRawValue:
|
|
||||||
var _tmp3 []rlp.RawValue
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for dec.MoreDataInList() {
|
|
||||||
_tmp4, err := dec.Raw()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp3 = append(_tmp3, _tmp4)
|
|
||||||
}
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.SliceOfRawValue = _tmp3
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*obj = _tmp0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
10
rlp/rlpgen/testdata/uint256.in.txt
vendored
10
rlp/rlpgen/testdata/uint256.in.txt
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
// -*- mode: go -*-
|
|
||||||
|
|
||||||
package test
|
|
||||||
|
|
||||||
import "github.com/holiman/uint256"
|
|
||||||
|
|
||||||
type Test struct {
|
|
||||||
Int *uint256.Int
|
|
||||||
IntNoPtr uint256.Int
|
|
||||||
}
|
|
||||||
44
rlp/rlpgen/testdata/uint256.out.txt
vendored
44
rlp/rlpgen/testdata/uint256.out.txt
vendored
|
|
@ -1,44 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
|
||||||
import "github.com/holiman/uint256"
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func (obj *Test) EncodeRLP(_w io.Writer) error {
|
|
||||||
w := rlp.NewEncoderBuffer(_w)
|
|
||||||
_tmp0 := w.List()
|
|
||||||
if obj.Int == nil {
|
|
||||||
w.Write(rlp.EmptyString)
|
|
||||||
} else {
|
|
||||||
w.WriteUint256(obj.Int)
|
|
||||||
}
|
|
||||||
w.WriteUint256(&obj.IntNoPtr)
|
|
||||||
w.ListEnd(_tmp0)
|
|
||||||
return w.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Test) DecodeRLP(dec *rlp.Stream) error {
|
|
||||||
var _tmp0 Test
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Int:
|
|
||||||
var _tmp1 uint256.Int
|
|
||||||
if err := dec.ReadUint256(&_tmp1); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.Int = &_tmp1
|
|
||||||
// IntNoPtr:
|
|
||||||
var _tmp2 uint256.Int
|
|
||||||
if err := dec.ReadUint256(&_tmp2); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.IntNoPtr = _tmp2
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*obj = _tmp0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
10
rlp/rlpgen/testdata/uints.in.txt
vendored
10
rlp/rlpgen/testdata/uints.in.txt
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
// -*- mode: go -*-
|
|
||||||
|
|
||||||
package test
|
|
||||||
|
|
||||||
type Test struct{
|
|
||||||
A uint8
|
|
||||||
B uint16
|
|
||||||
C uint32
|
|
||||||
D uint64
|
|
||||||
}
|
|
||||||
53
rlp/rlpgen/testdata/uints.out.txt
vendored
53
rlp/rlpgen/testdata/uints.out.txt
vendored
|
|
@ -1,53 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func (obj *Test) EncodeRLP(_w io.Writer) error {
|
|
||||||
w := rlp.NewEncoderBuffer(_w)
|
|
||||||
_tmp0 := w.List()
|
|
||||||
w.WriteUint64(uint64(obj.A))
|
|
||||||
w.WriteUint64(uint64(obj.B))
|
|
||||||
w.WriteUint64(uint64(obj.C))
|
|
||||||
w.WriteUint64(obj.D)
|
|
||||||
w.ListEnd(_tmp0)
|
|
||||||
return w.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Test) DecodeRLP(dec *rlp.Stream) error {
|
|
||||||
var _tmp0 Test
|
|
||||||
{
|
|
||||||
if _, err := dec.List(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// A:
|
|
||||||
_tmp1, err := dec.Uint8()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.A = _tmp1
|
|
||||||
// B:
|
|
||||||
_tmp2, err := dec.Uint16()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.B = _tmp2
|
|
||||||
// C:
|
|
||||||
_tmp3, err := dec.Uint32()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.C = _tmp3
|
|
||||||
// D:
|
|
||||||
_tmp4, err := dec.Uint64()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_tmp0.D = _tmp4
|
|
||||||
if err := dec.ListEnd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*obj = _tmp0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
// Copyright 2022 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 main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// typeReflectKind gives the reflect.Kind that represents typ.
|
|
||||||
func typeReflectKind(typ types.Type) reflect.Kind {
|
|
||||||
switch typ := typ.(type) {
|
|
||||||
case *types.Basic:
|
|
||||||
k := typ.Kind()
|
|
||||||
if k >= types.Bool && k <= types.Complex128 {
|
|
||||||
// value order matches for Bool..Complex128
|
|
||||||
return reflect.Bool + reflect.Kind(k-types.Bool)
|
|
||||||
}
|
|
||||||
if k == types.String {
|
|
||||||
return reflect.String
|
|
||||||
}
|
|
||||||
if k == types.UnsafePointer {
|
|
||||||
return reflect.UnsafePointer
|
|
||||||
}
|
|
||||||
panic(fmt.Errorf("unhandled BasicKind %v", k))
|
|
||||||
case *types.Array:
|
|
||||||
return reflect.Array
|
|
||||||
case *types.Chan:
|
|
||||||
return reflect.Chan
|
|
||||||
case *types.Interface:
|
|
||||||
return reflect.Interface
|
|
||||||
case *types.Map:
|
|
||||||
return reflect.Map
|
|
||||||
case *types.Pointer:
|
|
||||||
return reflect.Ptr
|
|
||||||
case *types.Signature:
|
|
||||||
return reflect.Func
|
|
||||||
case *types.Slice:
|
|
||||||
return reflect.Slice
|
|
||||||
case *types.Struct:
|
|
||||||
return reflect.Struct
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unhandled type %T", typ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// nonZeroCheck returns the expression that checks whether 'v' is a non-zero value of type 'vtyp'.
|
|
||||||
func nonZeroCheck(v string, vtyp types.Type, qualify types.Qualifier) string {
|
|
||||||
// Resolve type name.
|
|
||||||
typ := resolveUnderlying(vtyp)
|
|
||||||
switch typ := typ.(type) {
|
|
||||||
case *types.Basic:
|
|
||||||
k := typ.Kind()
|
|
||||||
switch {
|
|
||||||
case k == types.Bool:
|
|
||||||
return v
|
|
||||||
case k >= types.Uint && k <= types.Complex128:
|
|
||||||
return fmt.Sprintf("%s != 0", v)
|
|
||||||
case k == types.String:
|
|
||||||
return fmt.Sprintf(`%s != ""`, v)
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unhandled BasicKind %v", k))
|
|
||||||
}
|
|
||||||
case *types.Array, *types.Struct:
|
|
||||||
return fmt.Sprintf("%s != (%s{})", v, types.TypeString(vtyp, qualify))
|
|
||||||
case *types.Interface, *types.Pointer, *types.Signature:
|
|
||||||
return fmt.Sprintf("%s != nil", v)
|
|
||||||
case *types.Slice, *types.Map:
|
|
||||||
return fmt.Sprintf("len(%s) > 0", v)
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unhandled type %T", typ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// isBigInt checks whether 'typ' is "math/big".Int.
|
|
||||||
func isBigInt(typ types.Type) bool {
|
|
||||||
named, ok := typ.(*types.Named)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
name := named.Obj()
|
|
||||||
return name.Pkg().Path() == "math/big" && name.Name() == "Int"
|
|
||||||
}
|
|
||||||
|
|
||||||
// isUint256 checks whether 'typ' is "github.com/holiman/uint256".Int.
|
|
||||||
func isUint256(typ types.Type) bool {
|
|
||||||
named, ok := typ.(*types.Named)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
name := named.Obj()
|
|
||||||
return name.Pkg().Path() == "github.com/holiman/uint256" && name.Name() == "Int"
|
|
||||||
}
|
|
||||||
|
|
||||||
// isByte checks whether the underlying type of 'typ' is uint8.
|
|
||||||
func isByte(typ types.Type) bool {
|
|
||||||
basic, ok := resolveUnderlying(typ).(*types.Basic)
|
|
||||||
return ok && basic.Kind() == types.Uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveUnderlying(typ types.Type) types.Type {
|
|
||||||
for {
|
|
||||||
t := typ.Underlying()
|
|
||||||
if t == typ {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
typ = t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
27
rlp/safe.go
27
rlp/safe.go
|
|
@ -1,27 +0,0 @@
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build nacl || js || !cgo
|
|
||||||
// +build nacl js !cgo
|
|
||||||
|
|
||||||
package rlp
|
|
||||||
|
|
||||||
import "reflect"
|
|
||||||
|
|
||||||
// byteArrayBytes returns a slice of the byte array v.
|
|
||||||
func byteArrayBytes(v reflect.Value, length int) []byte {
|
|
||||||
return v.Slice(0, length).Bytes()
|
|
||||||
}
|
|
||||||
240
rlp/typecache.go
240
rlp/typecache.go
|
|
@ -1,240 +0,0 @@
|
||||||
// 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"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/rlp/internal/rlpstruct"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
rlpstruct.Tags
|
|
||||||
}
|
|
||||||
|
|
||||||
type decoder func(*Stream, reflect.Value) error
|
|
||||||
|
|
||||||
type writer func(reflect.Value, *encBuffer) 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, rlpstruct.Tags{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *typeCache) generate(typ reflect.Type, tags rlpstruct.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 rlpstruct.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) {
|
|
||||||
// Convert fields to rlpstruct.Field.
|
|
||||||
var allStructFields []rlpstruct.Field
|
|
||||||
for i := 0; i < typ.NumField(); i++ {
|
|
||||||
rf := typ.Field(i)
|
|
||||||
allStructFields = append(allStructFields, rlpstruct.Field{
|
|
||||||
Name: rf.Name,
|
|
||||||
Index: i,
|
|
||||||
Exported: rf.PkgPath == "",
|
|
||||||
Tag: string(rf.Tag),
|
|
||||||
Type: *rtypeToStructType(rf.Type, nil),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter/validate fields.
|
|
||||||
structFields, structTags, err := rlpstruct.ProcessFields(allStructFields)
|
|
||||||
if err != nil {
|
|
||||||
if tagErr, ok := err.(rlpstruct.TagError); ok {
|
|
||||||
tagErr.StructType = typ.String()
|
|
||||||
return nil, tagErr
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve typeinfo.
|
|
||||||
for i, sf := range structFields {
|
|
||||||
typ := typ.Field(sf.Index).Type
|
|
||||||
tags := structTags[i]
|
|
||||||
info := theTC.infoWhileGenerating(typ, tags)
|
|
||||||
fields = append(fields, field{sf.Index, info, tags.Optional})
|
|
||||||
}
|
|
||||||
return fields, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// firstOptionalField 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *typeinfo) generate(typ reflect.Type, tags rlpstruct.Tags) {
|
|
||||||
i.decoder, i.decoderErr = makeDecoder(typ, tags)
|
|
||||||
i.writer, i.writerErr = makeWriter(typ, tags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// rtypeToStructType converts typ to rlpstruct.Type.
|
|
||||||
func rtypeToStructType(typ reflect.Type, rec map[reflect.Type]*rlpstruct.Type) *rlpstruct.Type {
|
|
||||||
k := typ.Kind()
|
|
||||||
if k == reflect.Invalid {
|
|
||||||
panic("invalid kind")
|
|
||||||
}
|
|
||||||
|
|
||||||
if prev := rec[typ]; prev != nil {
|
|
||||||
return prev // short-circuit for recursive types
|
|
||||||
}
|
|
||||||
if rec == nil {
|
|
||||||
rec = make(map[reflect.Type]*rlpstruct.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
t := &rlpstruct.Type{
|
|
||||||
Name: typ.String(),
|
|
||||||
Kind: k,
|
|
||||||
IsEncoder: typ.Implements(encoderInterface),
|
|
||||||
IsDecoder: typ.Implements(decoderInterface),
|
|
||||||
}
|
|
||||||
rec[typ] = t
|
|
||||||
if k == reflect.Array || k == reflect.Slice || k == reflect.Ptr {
|
|
||||||
t.Elem = rtypeToStructType(typ.Elem(), rec)
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// typeNilKind gives the RLP value kind for nil pointers to 'typ'.
|
|
||||||
func typeNilKind(typ reflect.Type, tags rlpstruct.Tags) Kind {
|
|
||||||
styp := rtypeToStructType(typ, nil)
|
|
||||||
|
|
||||||
var nk rlpstruct.NilKind
|
|
||||||
if tags.NilOK {
|
|
||||||
nk = tags.NilKind
|
|
||||||
} else {
|
|
||||||
nk = styp.DefaultNilValue()
|
|
||||||
}
|
|
||||||
switch nk {
|
|
||||||
case rlpstruct.NilKindString:
|
|
||||||
return String
|
|
||||||
case rlpstruct.NilKindList:
|
|
||||||
return List
|
|
||||||
default:
|
|
||||||
panic("invalid nil kind value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//go:build !nacl && !js && cgo
|
|
||||||
// +build !nacl,!js,cgo
|
|
||||||
|
|
||||||
package rlp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// byteArrayBytes returns a slice of the byte array v.
|
|
||||||
func byteArrayBytes(v reflect.Value, length int) []byte {
|
|
||||||
var s []byte
|
|
||||||
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s))
|
|
||||||
hdr.Data = v.UnsafeAddr()
|
|
||||||
hdr.Cap = length
|
|
||||||
hdr.Len = length
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue