f447de936c
reflect.PtrTo has been deprecated and superseded by reflect.PointerTo
496 lines
13 KiB
Go
496 lines
13 KiB
Go
// 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.PointerTo(bigInt)):
|
|
return writeBigIntPtr, nil
|
|
case typ.AssignableTo(bigInt):
|
|
return writeBigIntNoPtr, nil
|
|
case typ == reflect.PointerTo(u256Int):
|
|
return writeU256IntPtr, nil
|
|
case typ == u256Int:
|
|
return writeU256IntNoPtr, nil
|
|
case kind == reflect.Ptr:
|
|
return makePtrWriter(typ, ts)
|
|
case reflect.PointerTo(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
|
|
}
|
|
}
|
|
}
|