bal

package
v0.0.0-...-ce7d804 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 21, 2020 License: LGPL-3.0 Imports: 17 Imported by: 2

Documentation

Overview

Package RLP implements the bal serialization format and support interface.

The purpose of RLP (Recursive Linear Prefix) is to encode arbitrarily nested arrays of binary data, and bal is the main encoding method used to serialize objects in Ethereum. The only purpose of bal 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 byte array).

bal 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.

Amino is an encoding library that can handle interfaces (like protobuf "oneof") well. This is achieved by prefixing bytes before each "concrete type". A concrete type is some non-interface value (generally a struct) which implements the interface to be (de)serialized. Not all structures need to be registered as concrete types -- only when they will be stored in interface type fields (or interface type slices) do they need to be registered. Registering types

Index

Examples

Constants

View Source
const (
	PrefixBytesLen = 4
	DisambBytesLen = 3
	DisfixBytesLen = PrefixBytesLen + DisambBytesLen
)

Lengths

View Source
const (
	// Typ3 types
	Typ3_Varint     = Typ3(0)
	Typ3_8Byte      = Typ3(1)
	Typ3_ByteLength = Typ3(2)
	//Typ3_Struct     = Typ3(3)
	//Typ3_StructTerm = Typ3(4)
	Typ3_4Byte = Typ3(5)
)

Variables

View Source
var (
	// EOL is returned when the end of the current list
	// has been reached during streaming.
	EOL = errors.New("bal: end of list")

	// Actual Errors
	ErrExpectedString   = errors.New("bal: expected String or Byte")
	ErrExpectedList     = errors.New("bal: expected List")
	ErrCanonInt         = errors.New("bal: non-canonical integer format")
	ErrCanonSize        = errors.New("bal: non-canonical size information")
	ErrElemTooLarge     = errors.New("bal: element is larger than containing list")
	ErrValueTooLarge    = errors.New("bal: value size exceeds available input length")
	ErrMoreThanOneValue = errors.New("bal: input contains more than one value")
)
View Source
var (
	// Common encoded values.
	// These are useful when implementing EncodeBAL.
	EmptyString = []byte{0x80}
	EmptyList   = []byte{0xC0}
)

Functions

func CountValues

func CountValues(b []byte) (int, error)

CountValues counts the number of encoded values in b.

func Decode

func Decode(r io.Reader, val interface{}) error

Decode parses bal-encoded data from r and stores the result in the value pointed to by val. Val must be a non-nil pointer. If r does not implement ByteReader, Decode will do its own buffering.

Decode uses the following type-dependent decoding rules:

If the type implements the Decoder interface, decode calls DecodeBAL.

To decode into a pointer, Decode will decode into the value pointed to. 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.

To decode into a struct, Decode expects the input to be an bal 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. Decode returns an error if there are too few or too many elements.

The decoding of struct fields honours certain struct tags, "tail", "nil" and "-".

The "-" tag ignores fields.

For an explanation of "tail", see the example.

The "nil" tag applies to pointer-typed fields and changes the decoding rules for the field such that input values of size zero decode as a nil pointer. This tag can be useful when decoding recursive types.

type StructWithEmptyOK struct {
    Foo *[20]byte `bal:"nil"`
}

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 bal string. Array types decode similarly, with the additional restriction that the number of input elements (or bytes) must match the array's length.

To decode into a Go string, the input must be an bal 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 bal string. The bytes are interpreted as a big endian representation of the integer. If the bal string is larger than the bit size of the type, Decode will return an error. Decode also supports *big.Int. There is no size limit for big integers.

To decode into an interface value, Decode stores one of these in the value:

[]interface{}, for bal lists
[]byte, for bal strings

Non-empty interface types are not supported, nor are booleans, signed integers, floating point numbers, maps, channels and functions.

Note that Decode does not set an input limit for all readers and may be vulnerable to panics cause by huge value sizes. If you need an input limit, use

NewStream(r, limit).Decode(val)
Example
input, _ := hex.DecodeString("C90A1486666F6F626172")

type example struct {
	A, B    uint
	private uint // private fields are ignored
	String  string
}

var s example
err := Decode(bytes.NewReader(input), &s)
if err != nil {
	fmt.Printf("Error: %v\n", err)
} else {
	fmt.Printf("Decoded value: %#v\n", s)
}
Output:

Decoded value: bal.example{A:0xa, B:0x14, private:0x0, String:"foobar"}
Example (StructTagNil)
// In this example, we'll use the "nil" struct tag to change
// how a pointer-typed field is decoded. The input contains an bal
// list of one element, an empty string.
input := []byte{0xC1, 0x80}

// This type uses the normal rules.
// The empty input string is decoded as a pointer to an empty Go string.
var normalRules struct {
	String *string
}
Decode(bytes.NewReader(input), &normalRules)
//we add `bal:"nil"` default now
//fmt.Printf("normal: String = %q\n", *normalRules.String)
fmt.Printf("normal: String = %v\n", normalRules.String)

// This type uses the struct tag.
// The empty input string is decoded as a nil pointer.
var withEmptyOK struct {
	String *string `bal:"nil"`
}
Decode(bytes.NewReader(input), &withEmptyOK)
fmt.Printf("with nil tag: String = %v\n", withEmptyOK.String)
Output:

normal: String = <nil>
with nil tag: String = <nil>
Example (StructTagTail)
package main

import (
	"bytes"
	"fmt"
)

type structWithTail struct {
	A, B uint
	C    []uint `bal:"tail"`
}

func main() {
	// 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="bal: too few elements for bal.structWithTail"

func DecodeBytes

func DecodeBytes(b []byte, val interface{}) error

DecodeBytes parses bal data from b into val. Please see the documentation of Decode for the decoding rules. The input must contain exactly one value and no trailing data.

func DecodeBytesWithType

func DecodeBytesWithType(b []byte, val interface{}) error

DecodeBytesWithType decode with prefix

func DecodeReader

func DecodeReader(r io.Reader, val interface{}, inputLimit int64) (n int64, err error)

DecodeReader new stream with limit

func DecodeReaderWithType

func DecodeReaderWithType(r io.Reader, val interface{}, inputLimit int64) (n int64, err error)

DecodeReaderWithType new stream with limit

func DecodeWithType

func DecodeWithType(r io.Reader, val interface{}) error

DecodeWithType decode with prefix

func DeepCopy

func DeepCopy(o interface{}) (r interface{})

Deeply copies an object. If anything implements `.DeepCopy() <any>` along the way, the result of that function will be used. Otherwise, if it implements `.MarshalAmino() (<any>, error)` and `.UnmarshalAmino(<any>) error`, the pair will be used to copy. If .MarshalAmino() or .UnmarshalAmino() returns an error, this function will panic.

func Encode

func Encode(w io.Writer, val interface{}) error

Encode writes the bal encoding of val to w. Note that Encode may perform many small writes in some cases. Consider making w buffered.

Encode uses the following type-dependent encoding rules:

If the type implements the Encoder interface, Encode calls EncodeBAL. This is true even for nil pointers, please see the documentation for Encoder.

To encode a pointer, the value being pointed to is encoded. For nil pointers, Encode will encode the zero value of the type. A nil pointer to a struct type always encodes as an empty bal list. A nil pointer to an array encodes as an empty list (or empty string if the array has element type byte).

Struct values are encoded as an bal list of all their encoded public fields. Recursive struct types are supported.

To encode slices and arrays, the elements are encoded as an bal list of the value's elements. Note that arrays and slices with element type uint8 or byte are always encoded as an bal string.

A Go string is encoded as an bal string.

An unsigned integer value is encoded as an bal string. Zero always encodes as an empty bal string. Encode also supports *big.Int.

An interface value encodes as the value contained in the interface.

Boolean values are not supported, nor are signed integers, floating point numbers, maps, channels and functions.

func EncodeByteSlice

func EncodeByteSlice(w io.Writer, bz []byte) (err error)

EncodeByteSlice wrapper for cdc.EncodeByteSlice, but use bal encode

func EncodeToBytes

func EncodeToBytes(val interface{}) ([]byte, error)

EncodeToBytes returns the bal encoding of val. Please see the documentation of Encode for the encoding rules.

func EncodeToBytesWithType

func EncodeToBytesWithType(val interface{}) ([]byte, error)

EncodeToBytesWithType encode with prefix

func EncodeToReader

func EncodeToReader(val interface{}) (size int, r io.Reader, err error)

EncodeToReader returns a reader from which the bal 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 EncodeUvarint

func EncodeUvarint(w io.Writer, u uint64) (err error)

EncodeUvarint wrapper for cdc.EncodeUvarint, but use bal encode

func EncodeWithType

func EncodeWithType(w io.Writer, val interface{}) error

EncodeWithType return bal encode with 7 bytes prefix when the type of val is registed

func EncodeWriter

func EncodeWriter(w io.Writer, val interface{}) (n int64, err error)

EncodeWriter if err, panic

func EncodeWriterWithType

func EncodeWriterWithType(w io.Writer, val interface{}) (n int64, err error)

EncodeWriterWithType if err, panic

func ListSize

func ListSize(contentSize uint64) uint64

ListSize returns the encoded size of an bal list with the given content size.

func MarshalJSON

func MarshalJSON(o interface{}) ([]byte, error)

MarshalJSON wrapper for cdc.MarshalJSON

func MarshalJSONIndent

func MarshalJSONIndent(o interface{}, prefix, indent string) ([]byte, error)

MarshalJSONIndent wrapper for cdc.MarshalJSONIndent

func MustEncodeToBytes

func MustEncodeToBytes(val interface{}) []byte

MustEncodeToBytes if err, panic

func MustEncodeToBytesWithType

func MustEncodeToBytesWithType(val interface{}) []byte

MustEncodeToBytesWithType if err, panic

func NameToDisfix

func NameToDisfix(name string) (db DisambBytes, pb PrefixBytes)

Return the DisambBytes and the PrefixBytes for a given name.

func PrintTypes

func PrintTypes(out io.Writer) error

PrintTypes wrapper for cdc.PrintTypes

func RegisterConcrete

func RegisterConcrete(o interface{}, name string, opts *ConcreteOptions)

RegisterConcrete wrapper for cdc.RegisterConcrete

func RegisterInterface

func RegisterInterface(ptr interface{}, opts *InterfaceOptions)

RegisterInterface wrapper for cdc.RegisterInterface

func SplitList

func SplitList(b []byte) (content, rest []byte, err error)

SplitList splits b into the content of a list and any remaining bytes after the list.

func SplitString

func SplitString(b []byte) (content, rest []byte, err error)

SplitString splits b into the content of an bal string and any remaining bytes after the string.

func UnmarshalJSON

func UnmarshalJSON(bz []byte, ptr interface{}) error

UnmarshalJSON wrapper for cdc.UnmarshalJSON

Types

type ByteReader

type ByteReader interface {
	io.Reader
	io.ByteReader
}

ByteReader must be implemented by any input reader for a Stream. It is implemented by e.g. bufio.Reader and bytes.Reader.

type Codec

type Codec struct {
	// contains filtered or unexported fields
}

func NewCodec

func NewCodec() *Codec

func (*Codec) MarshalJSON

func (cdc *Codec) MarshalJSON(o interface{}) ([]byte, error)

func (*Codec) MarshalJSONIndent

func (cdc *Codec) MarshalJSONIndent(o interface{}, prefix, indent string) ([]byte, error)

MarshalJSONIndent calls json.Indent on the output of cdc.MarshalJSON using the given prefix and indent string.

func (Codec) PrintTypes

func (cdc Codec) PrintTypes(out io.Writer) error

PrintTypes writes all registered types in a markdown-style table. The table's header is:

| Type | Name | Prefix | Notes |

Where Type is the golang type name and Name is the name the type was registered with.

func (*Codec) RegisterConcrete

func (cdc *Codec) RegisterConcrete(o interface{}, name string, copts *ConcreteOptions)

This function should be used to register concrete types that will appear in interface fields/elements to be encoded/decoded by go-amino. Usage: `amino.RegisterConcrete(MyStruct1{}, "MyStruct1", nil)`

func (*Codec) RegisterInterface

func (cdc *Codec) RegisterInterface(ptr interface{}, iopts *InterfaceOptions)

This function should be used to register all interfaces that will be encoded/decoded by go-amino. Usage: `amino.RegisterInterface((*MyInterface1)(nil), nil)`

func (*Codec) Seal

func (cdc *Codec) Seal() *Codec

func (*Codec) UnmarshalJSON

func (cdc *Codec) UnmarshalJSON(bz []byte, ptr interface{}) error

type ConcreteInfo

type ConcreteInfo struct {

	// These fields are only set when registered (as implementing an interface).
	Registered       bool // Registered with RegisterConcrete().
	PointerPreferred bool // Deserialize to pointer type if possible.
	// NilPreferred     bool        // Deserialize to nil for empty structs if PointerPreferred.
	Name            string      // Registered name.
	Disamb          DisambBytes // Disambiguation bytes derived from name.
	Prefix          PrefixBytes // Prefix bytes derived from name.
	ConcreteOptions             // Registration options.

	// These fields get set for all concrete types,
	// even those not manually registered (e.g. are never interface values).
	IsAminoMarshaler       bool         // Implements MarshalAmino() (<ReprObject>, error).
	AminoMarshalReprType   reflect.Type // <ReprType>
	IsAminoUnmarshaler     bool         // Implements UnmarshalAmino(<ReprObject>) (error).
	AminoUnmarshalReprType reflect.Type // <ReprType>
}

func (ConcreteInfo) GetDisfix

func (cinfo ConcreteInfo) GetDisfix() DisfixBytes

type ConcreteOptions

type ConcreteOptions struct {
}

type Decoder

type Decoder interface {
	DecodeBAL(*Stream) error
}

Decoder is implemented by types that require custom bal decoding rules or need to decode into private fields.

The DecodeBAL method should read one value from the given Stream. It is not forbidden to read less or more, but it might be confusing.

type DisambBytes

type DisambBytes [DisambBytesLen]byte

Prefix types

func (DisambBytes) Bytes

func (db DisambBytes) Bytes() []byte

func (DisambBytes) EqualBytes

func (db DisambBytes) EqualBytes(bz []byte) bool

type DisfixBytes

type DisfixBytes [DisfixBytesLen]byte // Disamb+Prefix

Prefix types

func (DisfixBytes) Bytes

func (df DisfixBytes) Bytes() []byte

func (DisfixBytes) EqualBytes

func (df DisfixBytes) EqualBytes(bz []byte) bool

type Encoder

type Encoder interface {
	// EncodeBAL should write the bal 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 bal. 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.
	EncodeBAL(io.Writer) error
}

Encoder is implemented by types that require custom encoding rules or want to encode private fields.

Example
package main

import (
	"fmt"
	"io"
)

type MyCoolType struct {
	Name string
	a, b uint
}

// EncodeBAL writes x as bal list [a, b] that omits the Name field.
func (x *MyCoolType) EncodeBAL(w io.Writer) (err error) {
	// Note: the receiver can be a nil pointer. This allows you to
	// control the encoding of nil, but it also means that you have to
	// check for a nil receiver.
	if x == nil {
		err = Encode(w, []uint{0, 0})
	} else {
		err = Encode(w, []uint{x.a, x.b})
	}
	return err
}

func main() {
	var t *MyCoolType // t is nil pointer to MyCoolType
	bytes, _ := EncodeToBytes(t)
	fmt.Printf("%v → %X\n", t, bytes)

	t = &MyCoolType{Name: "foobar", a: 5, b: 6}
	bytes, _ = EncodeToBytes(t)
	fmt.Printf("%v → %X\n", t, bytes)

}
Output:

<nil> → C28080
&{foobar 5 6} → C20506

type FieldInfo

type FieldInfo struct {
	Name         string        // Struct field name
	Type         reflect.Type  // Struct field type
	Index        int           // Struct field index
	ZeroValue    reflect.Value // Could be nil pointer unlike TypeInfo.ZeroValue.
	UnpackedList bool          // True iff this field should be encoded as an unpacked list.
	FieldOptions               // Encoding options
}

type FieldOptions

type FieldOptions struct {
	JSONName      string // (JSON) field name
	JSONOmitEmpty bool   // (JSON) omitempty
	BinFixed64    bool   // (Binary) Encode as fixed64
	BinFixed32    bool   // (Binary) Encode as fixed32
	BinFieldNum   uint32 // (Binary) max 1<<29-1
	Unsafe        bool   // e.g. if this field is a float.
}

type InterfaceInfo

type InterfaceInfo struct {
	Priority     []DisfixBytes               // Disfix priority.
	Implementers map[PrefixBytes][]*TypeInfo // Mutated over time.
	InterfaceOptions
}

type InterfaceOptions

type InterfaceOptions struct {
	Priority           []string // Disamb priority.
	AlwaysDisambiguate bool     // If true, include disamb for all types.
}

type Kind

type Kind int

Kind represents the kind of value contained in an bal stream.

const (
	Byte Kind = iota
	String
	List
)

func Split

func Split(b []byte) (k Kind, content, rest []byte, err error)

Split returns the content of first bal value and any bytes after the value as subslices of b.

func (Kind) String

func (k Kind) String() string

type PrefixBytes

type PrefixBytes [PrefixBytesLen]byte

Prefix types

func NewPrefixBytes

func NewPrefixBytes(prefixBytes []byte) PrefixBytes

Copy into PrefixBytes

func (PrefixBytes) Bytes

func (pb PrefixBytes) Bytes() []byte

func (PrefixBytes) EqualBytes

func (pb PrefixBytes) EqualBytes(bz []byte) bool

type RawValue

type RawValue []byte

RawValue represents an encoded bal value and can be used to delay bal decoding or to precompute an encoding. Note that the decoder does not verify whether the content of RawValues is valid bal.

type Stream

type Stream struct {
	// contains filtered or unexported fields
}

Stream can be used for piecemeal decoding of an input stream. This is useful if the input is very large or if the decoding rules for a type depend on the input structure. Stream does not keep an internal buffer. After decoding a value, the input reader will be positioned just before the type information for the next value.

When decoding a list and the input position reaches the declared length of the list, all operations will return error EOL. The end of the list must be acknowledged using ListEnd to continue reading the enclosing list.

Stream is not safe for concurrent use.

Example
input, _ := hex.DecodeString("C90A1486666F6F626172")
s := NewStream(bytes.NewReader(input), 0)

// Check what kind of value lies ahead
kind, size, _ := s.Kind()
fmt.Printf("Kind: %v size:%d\n", kind, size)

// Enter the list
if _, err := s.List(); err != nil {
	fmt.Printf("List error: %v\n", err)
	return
}

// Decode elements
fmt.Println(s.Uint())
fmt.Println(s.Uint())
fmt.Println(s.Bytes())

// Acknowledge end of list
if err := s.ListEnd(); err != nil {
	fmt.Printf("ListEnd error: %v\n", err)
}
Output:

Kind: List size:9
10 <nil>
20 <nil>
[102 111 111 98 97 114] <nil>

func NewListStream

func NewListStream(r io.Reader, len uint64) *Stream

NewListStream creates a new stream that pretends to be positioned at an encoded list of the given length.

func NewStream

func NewStream(r io.Reader, inputLimit uint64) *Stream

NewStream creates a new decoding stream reading from r.

If r implements the ByteReader interface, Stream will not introduce any buffering.

For non-toplevel values, Stream returns ErrElemTooLarge for values that do not fit into the enclosing list.

Stream supports an optional input limit. If a limit is set, the size of any toplevel value will be checked against the remaining input length. Stream operations that encounter a value exceeding the remaining input length will return ErrValueTooLarge. The limit can be set by passing a non-zero value for inputLimit.

If r is a bytes.Reader or strings.Reader, the input limit is set to the length of r's underlying data unless an explicit limit is provided.

func (*Stream) Bool

func (s *Stream) Bool() (bool, error)

Bool reads an bal string of up to 1 byte and returns its contents as a boolean. If the input does not contain an bal string, the returned error will be ErrExpectedString.

func (*Stream) Bytes

func (s *Stream) Bytes() ([]byte, error)

Bytes reads an bal string and returns its contents as a byte slice. If the input does not contain an bal string, the returned error will be ErrExpectedString.

func (*Stream) Decode

func (s *Stream) Decode(val interface{}) error

Decode decodes a value and stores the result in the value pointed to by val. Please see the documentation for the Decode function to learn about the decoding rules.

func (*Stream) DecodeWithPrefix

func (s *Stream) DecodeWithPrefix(val interface{}) error

DecodeWithPrefix decodes a value and stores the result in the value pointed to by val. Please see the documentation for the Decode function to learn about the decoding rules.

func (*Stream) Kind

func (s *Stream) Kind() (kind Kind, size uint64, err error)

Kind returns the kind and size of the next value in the input stream.

The returned size is the number of bytes that make up the value. For kind == Byte, the size is zero because the value is contained in the type tag.

The first call to Kind will read size information from the input reader and leave it positioned at the start of the actual bytes of the value. Subsequent calls to Kind (until the value is decoded) will not advance the input reader and return cached information.

func (*Stream) List

func (s *Stream) List() (size uint64, err error)

List starts decoding an bal list. If the input does not contain a list, the returned error will be ErrExpectedList. When the list's end has been reached, any Stream operation will return EOL.

func (*Stream) ListEnd

func (s *Stream) ListEnd() error

ListEnd returns to the enclosing list. The input reader must be positioned at the end of a list.

func (*Stream) Raw

func (s *Stream) Raw() ([]byte, error)

Raw reads a raw encoded value including bal type information.

func (*Stream) Reset

func (s *Stream) Reset(r io.Reader, inputLimit uint64)

Reset discards any information about the current decoding context and starts reading from r. This method is meant to facilitate reuse of a preallocated Stream across many decoding operations.

If r does not also implement ByteReader, Stream will do its own buffering.

func (*Stream) Uint

func (s *Stream) Uint() (uint64, error)

Uint reads an bal string of up to 8 bytes and returns its contents as an unsigned integer. If the input does not contain an bal string, the returned error will be ErrExpectedString.

type StructInfo

type StructInfo struct {
	Fields []FieldInfo // If a struct.
}

type Typ3

type Typ3 uint8

func (Typ3) String

func (typ Typ3) String() string

type TypeInfo

type TypeInfo struct {
	Type      reflect.Type // Interface type.
	PtrToType reflect.Type
	ZeroValue reflect.Value
	ZeroProto interface{}
	InterfaceInfo
	ConcreteInfo
	StructInfo
}

func (TypeInfo) String

func (ti TypeInfo) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL