Moved ethutil => common
This commit is contained in:
276
common/rlp.go
Normal file
276
common/rlp.go
Normal file
@ -0,0 +1,276 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type RlpEncode interface {
|
||||
RlpEncode() []byte
|
||||
}
|
||||
|
||||
type RlpEncodeDecode interface {
|
||||
RlpEncode
|
||||
RlpValue() []interface{}
|
||||
}
|
||||
|
||||
type RlpEncodable interface {
|
||||
RlpData() interface{}
|
||||
}
|
||||
|
||||
func Rlp(encoder RlpEncode) []byte {
|
||||
return encoder.RlpEncode()
|
||||
}
|
||||
|
||||
type RlpEncoder struct {
|
||||
rlpData []byte
|
||||
}
|
||||
|
||||
func NewRlpEncoder() *RlpEncoder {
|
||||
encoder := &RlpEncoder{}
|
||||
|
||||
return encoder
|
||||
}
|
||||
func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte {
|
||||
return Encode(rlpData)
|
||||
}
|
||||
|
||||
const (
|
||||
RlpEmptyList = 0x80
|
||||
RlpEmptyStr = 0x40
|
||||
)
|
||||
|
||||
const rlpEof = -1
|
||||
|
||||
func Char(c []byte) int {
|
||||
if len(c) > 0 {
|
||||
return int(c[0])
|
||||
}
|
||||
|
||||
return rlpEof
|
||||
}
|
||||
|
||||
func DecodeWithReader(reader *bytes.Buffer) interface{} {
|
||||
var slice []interface{}
|
||||
|
||||
// Read the next byte
|
||||
char := Char(reader.Next(1))
|
||||
switch {
|
||||
case char <= 0x7f:
|
||||
return char
|
||||
|
||||
case char <= 0xb7:
|
||||
return reader.Next(int(char - 0x80))
|
||||
|
||||
case char <= 0xbf:
|
||||
length := ReadVarInt(reader.Next(int(char - 0xb7)))
|
||||
|
||||
return reader.Next(int(length))
|
||||
|
||||
case char <= 0xf7:
|
||||
length := int(char - 0xc0)
|
||||
for i := 0; i < length; i++ {
|
||||
obj := DecodeWithReader(reader)
|
||||
slice = append(slice, obj)
|
||||
}
|
||||
|
||||
return slice
|
||||
case char <= 0xff:
|
||||
length := ReadVarInt(reader.Next(int(char - 0xf7)))
|
||||
for i := uint64(0); i < length; i++ {
|
||||
obj := DecodeWithReader(reader)
|
||||
slice = append(slice, obj)
|
||||
}
|
||||
|
||||
return slice
|
||||
default:
|
||||
panic(fmt.Sprintf("byte not supported: %q", char))
|
||||
}
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
var (
|
||||
directRlp = big.NewInt(0x7f)
|
||||
numberRlp = big.NewInt(0xb7)
|
||||
zeroRlp = big.NewInt(0x0)
|
||||
)
|
||||
|
||||
func intlen(i int64) (length int) {
|
||||
for i > 0 {
|
||||
i = i >> 8
|
||||
length++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Encode(object interface{}) []byte {
|
||||
var buff bytes.Buffer
|
||||
|
||||
if object != nil {
|
||||
switch t := object.(type) {
|
||||
case *Value:
|
||||
buff.Write(Encode(t.Raw()))
|
||||
case RlpEncodable:
|
||||
buff.Write(Encode(t.RlpData()))
|
||||
// Code dup :-/
|
||||
case int:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case uint:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int8:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int16:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int32:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int64:
|
||||
buff.Write(Encode(big.NewInt(t)))
|
||||
case uint16:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case uint32:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case uint64:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case byte:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case *big.Int:
|
||||
// Not sure how this is possible while we check for nil
|
||||
if t == nil {
|
||||
buff.WriteByte(0xc0)
|
||||
} else {
|
||||
buff.Write(Encode(t.Bytes()))
|
||||
}
|
||||
case Bytes:
|
||||
buff.Write(Encode([]byte(t)))
|
||||
case []byte:
|
||||
if len(t) == 1 && t[0] <= 0x7f {
|
||||
buff.Write(t)
|
||||
} else if len(t) < 56 {
|
||||
buff.WriteByte(byte(len(t) + 0x80))
|
||||
buff.Write(t)
|
||||
} else {
|
||||
b := big.NewInt(int64(len(t)))
|
||||
buff.WriteByte(byte(len(b.Bytes()) + 0xb7))
|
||||
buff.Write(b.Bytes())
|
||||
buff.Write(t)
|
||||
}
|
||||
case string:
|
||||
buff.Write(Encode([]byte(t)))
|
||||
case []interface{}:
|
||||
// Inline function for writing the slice header
|
||||
WriteSliceHeader := func(length int) {
|
||||
if length < 56 {
|
||||
buff.WriteByte(byte(length + 0xc0))
|
||||
} else {
|
||||
b := big.NewInt(int64(length))
|
||||
buff.WriteByte(byte(len(b.Bytes()) + 0xf7))
|
||||
buff.Write(b.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
for _, val := range t {
|
||||
b.Write(Encode(val))
|
||||
}
|
||||
WriteSliceHeader(len(b.Bytes()))
|
||||
buff.Write(b.Bytes())
|
||||
default:
|
||||
// This is how it should have been from the start
|
||||
// needs refactoring (@fjl)
|
||||
v := reflect.ValueOf(t)
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
var b bytes.Buffer
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
b.Write(Encode(v.Index(i).Interface()))
|
||||
}
|
||||
|
||||
blen := b.Len()
|
||||
if blen < 56 {
|
||||
buff.WriteByte(byte(blen) + 0xc0)
|
||||
} else {
|
||||
ilen := byte(intlen(int64(blen)))
|
||||
buff.WriteByte(ilen + 0xf7)
|
||||
t := make([]byte, ilen)
|
||||
for i := byte(0); i < ilen; i++ {
|
||||
t[ilen-i-1] = byte(blen >> (i * 8))
|
||||
}
|
||||
buff.Write(t)
|
||||
}
|
||||
buff.ReadFrom(&b)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Empty list for nil
|
||||
buff.WriteByte(0xc0)
|
||||
}
|
||||
|
||||
return buff.Bytes()
|
||||
}
|
||||
|
||||
// TODO Use a bytes.Buffer instead of a raw byte slice.
|
||||
// Cleaner code, and use draining instead of seeking the next bytes to read
|
||||
func Decode(data []byte, pos uint64) (interface{}, uint64) {
|
||||
var slice []interface{}
|
||||
char := int(data[pos])
|
||||
switch {
|
||||
case char <= 0x7f:
|
||||
return data[pos], pos + 1
|
||||
|
||||
case char <= 0xb7:
|
||||
b := uint64(data[pos]) - 0x80
|
||||
|
||||
return data[pos+1 : pos+1+b], pos + 1 + b
|
||||
|
||||
case char <= 0xbf:
|
||||
b := uint64(data[pos]) - 0xb7
|
||||
|
||||
b2 := ReadVarInt(data[pos+1 : pos+1+b])
|
||||
|
||||
return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2
|
||||
|
||||
case char <= 0xf7:
|
||||
b := uint64(data[pos]) - 0xc0
|
||||
prevPos := pos
|
||||
pos++
|
||||
for i := uint64(0); i < b; {
|
||||
var obj interface{}
|
||||
|
||||
// Get the next item in the data list and append it
|
||||
obj, prevPos = Decode(data, pos)
|
||||
slice = append(slice, obj)
|
||||
|
||||
// Increment i by the amount bytes read in the previous
|
||||
// read
|
||||
i += (prevPos - pos)
|
||||
pos = prevPos
|
||||
}
|
||||
return slice, pos
|
||||
|
||||
case char <= 0xff:
|
||||
l := uint64(data[pos]) - 0xf7
|
||||
b := ReadVarInt(data[pos+1 : pos+1+l])
|
||||
|
||||
pos = pos + l + 1
|
||||
|
||||
prevPos := b
|
||||
for i := uint64(0); i < uint64(b); {
|
||||
var obj interface{}
|
||||
|
||||
obj, prevPos = Decode(data, pos)
|
||||
slice = append(slice, obj)
|
||||
|
||||
i += (prevPos - pos)
|
||||
pos = prevPos
|
||||
}
|
||||
return slice, pos
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("byte not supported: %q", char))
|
||||
}
|
||||
|
||||
return slice, 0
|
||||
}
|
Reference in New Issue
Block a user