The great merge

This commit is contained in:
obscuren
2014-02-14 23:56:09 +01:00
parent c2fb9f06ad
commit f6d1bfe45b
43 changed files with 4547 additions and 12 deletions

12
ethutil/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile ~/.gitignore_global
/tmp
*/**/*un~
*un~
.DS_Store
*/**/.DS_Store

3
ethutil/.travil.yml Normal file
View File

@ -0,0 +1,3 @@
language: go
go:
- 1.2

137
ethutil/README.md Normal file
View File

@ -0,0 +1,137 @@
# ethutil
[![Build
Status](https://travis-ci.org/ethereum/go-ethereum.png?branch=master)](https://travis-ci.org/ethereum/go-ethereum)
The ethutil package contains the ethereum utility library.
# Installation
`go get github.com/ethereum/ethutil-go`
# Usage
## RLP (Recursive Linear Prefix) Encoding
RLP Encoding is an encoding scheme utilized by the Ethereum project. It
encodes any native value or list to string.
More in depth information about the Encoding scheme see the [Wiki](http://wiki.ethereum.org/index.php/RLP)
article.
```go
rlp := ethutil.Encode("doge")
fmt.Printf("%q\n", rlp) // => "\0x83dog"
rlp = ethutil.Encode([]interface{}{"dog", "cat"})
fmt.Printf("%q\n", rlp) // => "\0xc8\0x83dog\0x83cat"
decoded := ethutil.Decode(rlp)
fmt.Println(decoded) // => ["dog" "cat"]
```
## Patricia Trie
Patricie Tree is a merkle trie utilized by the Ethereum project.
More in depth information about the (modified) Patricia Trie can be
found on the [Wiki](http://wiki.ethereum.org/index.php/Patricia_Tree).
The patricia trie uses a db as backend and could be anything as long as
it satisfies the Database interface found in `ethutil/db.go`.
```go
db := NewDatabase()
// db, root
trie := ethutil.NewTrie(db, "")
trie.Put("puppy", "dog")
trie.Put("horse", "stallion")
trie.Put("do", "verb")
trie.Put("doge", "coin")
// Look up the key "do" in the trie
out := trie.Get("do")
fmt.Println(out) // => verb
```
The patricia trie, in combination with RLP, provides a robust,
cryptographically authenticated data structure that can be used to store
all (key, value) bindings.
```go
// ... Create db/trie
// Note that RLP uses interface slices as list
value := ethutil.Encode([]interface{}{"one", 2, "three", []interface{}{42}})
// Store the RLP encoded value of the list
trie.Put("mykey", value)
```
## Value
Value is a Generic Value which is used in combination with RLP data or
`([])interface{}` structures. It may serve as a bridge between RLP data
and actual real values and takes care of all the type checking and
casting. Unlike Go's `reflect.Value` it does not panic if it's unable to
cast to the requested value. It simple returns the base value of that
type (e.g. `Slice()` returns []interface{}, `Uint()` return 0, etc).
### Creating a new Value
`NewEmptyValue()` returns a new \*Value with it's initial value set to a
`[]interface{}`
`AppendLint()` appends a list to the current value.
`Append(v)` appends the value (v) to the current value/list.
```go
val := ethutil.NewEmptyValue().Append(1).Append("2")
val.AppendList().Append(3)
```
### Retrieving values
`Get(i)` returns the `i` item in the list.
`Uint()` returns the value as an unsigned int64.
`Slice()` returns the value as a interface slice.
`Str()` returns the value as a string.
`Bytes()` returns the value as a byte slice.
`Len()` assumes current to be a slice and returns its length.
`Byte()` returns the value as a single byte.
```go
val := ethutil.NewValue([]interface{}{1,"2",[]interface{}{3}})
val.Get(0).Uint() // => 1
val.Get(1).Str() // => "2"
s := val.Get(2) // => Value([]interface{}{3})
s.Get(0).Uint() // => 3
```
## Decoding
Decoding streams of RLP data is simplified
```go
val := ethutil.NewValueFromBytes(rlpData)
val.Get(0).Uint()
```
## Encoding
Encoding from Value to RLP is done with the `Encode` method. The
underlying value can be anything RLP can encode (int, str, lists, bytes)
```go
val := ethutil.NewValue([]interface{}{1,"2",[]interface{}{3}})
rlp := val.Encode()
// Store the rlp data
Store(rlp)
```

37
ethutil/big.go Normal file
View File

@ -0,0 +1,37 @@
package ethutil
import (
"math/big"
)
var BigInt0 *big.Int = big.NewInt(0)
// True
var BigTrue *big.Int = big.NewInt(1)
// False
var BigFalse *big.Int = big.NewInt(0)
// Returns the power of two integers
func BigPow(a, b int) *big.Int {
c := new(big.Int)
c.Exp(big.NewInt(int64(a)), big.NewInt(int64(b)), big.NewInt(0))
return c
}
// Like big.NewInt(uint64); this takes a string instead.
func Big(num string) *big.Int {
n := new(big.Int)
n.SetString(num, 0)
return n
}
// Like big.NewInt(uint64); this takes a byte buffer instead.
func BigD(data []byte) *big.Int {
n := new(big.Int)
n.SetBytes(data)
return n
}

64
ethutil/bytes.go Normal file
View File

@ -0,0 +1,64 @@
package ethutil
import (
"bytes"
"encoding/binary"
"fmt"
)
func NumberToBytes(num interface{}, bits int) []byte {
buf := new(bytes.Buffer)
err := binary.Write(buf, binary.BigEndian, num)
if err != nil {
fmt.Println("NumberToBytes failed:", err)
}
return buf.Bytes()[buf.Len()-(bits/8):]
}
func BytesToNumber(b []byte) uint64 {
var number uint64
// Make sure the buffer is 64bits
data := make([]byte, 8)
data = append(data[:len(b)], b...)
buf := bytes.NewReader(data)
err := binary.Read(buf, binary.BigEndian, &number)
if err != nil {
fmt.Println("BytesToNumber failed:", err)
}
return number
}
// Read variable integer in big endian
func ReadVarint(reader *bytes.Reader) (ret uint64) {
if reader.Len() == 8 {
var num uint64
binary.Read(reader, binary.BigEndian, &num)
ret = uint64(num)
} else if reader.Len() == 4 {
var num uint32
binary.Read(reader, binary.BigEndian, &num)
ret = uint64(num)
} else if reader.Len() == 2 {
var num uint16
binary.Read(reader, binary.BigEndian, &num)
ret = uint64(num)
} else {
var num uint8
binary.Read(reader, binary.BigEndian, &num)
ret = uint64(num)
}
return ret
}
func BinaryLength(num int) int {
if num == 0 {
return 0
}
return 1 + BinaryLength(num>>8)
}

106
ethutil/config.go Normal file
View File

@ -0,0 +1,106 @@
package ethutil
import (
"log"
"os"
"os/user"
"path"
)
type LogType byte
const (
LogTypeStdIn = 1
LogTypeFile = 2
)
// Config struct isn't exposed
type config struct {
Db Database
Log Logger
ExecPath string
Debug bool
Ver string
Pubkey []byte
Seed bool
}
var Config *config
// Read config doesn't read anything yet.
func ReadConfig(base string) *config {
if Config == nil {
usr, _ := user.Current()
path := path.Join(usr.HomeDir, base)
//Check if the logging directory already exists, create it if not
_, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
log.Printf("Debug logging directory %s doesn't exist, creating it", path)
os.Mkdir(path, 0777)
}
}
Config = &config{ExecPath: path, Debug: true, Ver: "0.2.1"}
Config.Log = NewLogger(LogFile|LogStd, 0)
}
return Config
}
type LoggerType byte
const (
LogFile = 0x1
LogStd = 0x2
)
type Logger struct {
logSys []*log.Logger
logLevel int
}
func NewLogger(flag LoggerType, level int) Logger {
var loggers []*log.Logger
flags := log.LstdFlags | log.Lshortfile
if flag&LogFile > 0 {
file, err := os.OpenFile(path.Join(Config.ExecPath, "debug.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm)
if err != nil {
log.Panic("unable to create file logger", err)
}
log := log.New(file, "[ETH]", flags)
loggers = append(loggers, log)
}
if flag&LogStd > 0 {
log := log.New(os.Stdout, "[ETH]", flags)
loggers = append(loggers, log)
}
return Logger{logSys: loggers, logLevel: level}
}
func (log Logger) Debugln(v ...interface{}) {
if log.logLevel != 0 {
return
}
for _, logger := range log.logSys {
logger.Println(v...)
}
}
func (log Logger) Debugf(format string, v ...interface{}) {
if log.logLevel != 0 {
return
}
for _, logger := range log.logSys {
logger.Printf(format, v...)
}
}

10
ethutil/db.go Normal file
View File

@ -0,0 +1,10 @@
package ethutil
// Database interface
type Database interface {
Put(key []byte, value []byte)
Get(key []byte) ([]byte, error)
LastKnownTD() []byte
Close()
Print()
}

62
ethutil/encoding.go Normal file
View File

@ -0,0 +1,62 @@
package ethutil
import (
"bytes"
"encoding/hex"
_ "fmt"
"strings"
)
func CompactEncode(hexSlice []int) string {
terminator := 0
if hexSlice[len(hexSlice)-1] == 16 {
terminator = 1
}
if terminator == 1 {
hexSlice = hexSlice[:len(hexSlice)-1]
}
oddlen := len(hexSlice) % 2
flags := 2*terminator + oddlen
if oddlen != 0 {
hexSlice = append([]int{flags}, hexSlice...)
} else {
hexSlice = append([]int{flags, 0}, hexSlice...)
}
var buff bytes.Buffer
for i := 0; i < len(hexSlice); i += 2 {
buff.WriteByte(byte(16*hexSlice[i] + hexSlice[i+1]))
}
return buff.String()
}
func CompactDecode(str string) []int {
base := CompactHexDecode(str)
base = base[:len(base)-1]
if base[0] >= 2 { // && base[len(base)-1] != 16 {
base = append(base, 16)
}
if base[0]%2 == 1 {
base = base[1:]
} else {
base = base[2:]
}
return base
}
func CompactHexDecode(str string) []int {
base := "0123456789abcdef"
hexSlice := make([]int, 0)
enc := hex.EncodeToString([]byte(str))
for _, v := range enc {
hexSlice = append(hexSlice, strings.IndexByte(base, byte(v)))
}
hexSlice = append(hexSlice, 16)
return hexSlice
}

37
ethutil/encoding_test.go Normal file
View File

@ -0,0 +1,37 @@
package ethutil
import (
"fmt"
"testing"
)
func TestCompactEncode(t *testing.T) {
test1 := []int{1, 2, 3, 4, 5}
if res := CompactEncode(test1); res != "\x11\x23\x45" {
t.Error(fmt.Sprintf("even compact encode failed. Got: %q", res))
}
test2 := []int{0, 1, 2, 3, 4, 5}
if res := CompactEncode(test2); res != "\x00\x01\x23\x45" {
t.Error(fmt.Sprintf("odd compact encode failed. Got: %q", res))
}
test3 := []int{0, 15, 1, 12, 11, 8 /*term*/, 16}
if res := CompactEncode(test3); res != "\x20\x0f\x1c\xb8" {
t.Error(fmt.Sprintf("odd terminated compact encode failed. Got: %q", res))
}
test4 := []int{15, 1, 12, 11, 8 /*term*/, 16}
if res := CompactEncode(test4); res != "\x3f\x1c\xb8" {
t.Error(fmt.Sprintf("even terminated compact encode failed. Got: %q", res))
}
}
func TestCompactHexDecode(t *testing.T) {
exp := []int{7, 6, 6, 5, 7, 2, 6, 2, 16}
res := CompactHexDecode("verb")
if !CompareIntSlice(res, exp) {
t.Error("Error compact hex decode. Expected", exp, "got", res)
}
}

61
ethutil/helpers.go Normal file
View File

@ -0,0 +1,61 @@
package ethutil
import (
"code.google.com/p/go.crypto/ripemd160"
"crypto/sha256"
"encoding/hex"
"github.com/obscuren/sha3"
"strconv"
)
func Uitoa(i uint32) string {
return strconv.FormatUint(uint64(i), 10)
}
func Sha256Bin(data []byte) []byte {
hash := sha256.Sum256(data)
return hash[:]
}
func Ripemd160(data []byte) []byte {
ripemd := ripemd160.New()
ripemd.Write(data)
return ripemd.Sum(nil)
}
func Sha3Bin(data []byte) []byte {
d := sha3.NewKeccak256()
d.Reset()
d.Write(data)
return d.Sum(nil)
}
// Helper function for comparing slices
func CompareIntSlice(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
// Returns the amount of nibbles that match each other from 0 ...
func MatchingNibbleLength(a, b []int) int {
i := 0
for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) {
i += 1
}
return i
}
func Hex(d []byte) string {
return hex.EncodeToString(d)
}

108
ethutil/parsing.go Normal file
View File

@ -0,0 +1,108 @@
package ethutil
import (
"errors"
"fmt"
"math/big"
"strconv"
"strings"
)
// Op codes
var OpCodes = map[string]string{
"STOP": "0",
"ADD": "1",
"MUL": "2",
"SUB": "3",
"DIV": "4",
"SDIV": "5",
"MOD": "6",
"SMOD": "7",
"EXP": "8",
"NEG": "9",
"LT": "10",
"LE": "11",
"GT": "12",
"GE": "13",
"EQ": "14",
"NOT": "15",
"MYADDRESS": "16",
"TXSENDER": "17",
"PUSH": "48",
"POP": "49",
"LOAD": "54",
}
func CompileInstr(s string) (string, error) {
tokens := strings.Split(s, " ")
if OpCodes[tokens[0]] == "" {
return s, errors.New(fmt.Sprintf("OP not found: %s", tokens[0]))
}
code := OpCodes[tokens[0]] // Replace op codes with the proper numerical equivalent
op := new(big.Int)
op.SetString(code, 0)
args := make([]*big.Int, 6)
for i, val := range tokens[1:len(tokens)] {
num := new(big.Int)
num.SetString(val, 0)
args[i] = num
}
// Big int equation = op + x * 256 + y * 256**2 + z * 256**3 + a * 256**4 + b * 256**5 + c * 256**6
base := new(big.Int)
x := new(big.Int)
y := new(big.Int)
z := new(big.Int)
a := new(big.Int)
b := new(big.Int)
c := new(big.Int)
if args[0] != nil {
x.Mul(args[0], big.NewInt(256))
}
if args[1] != nil {
y.Mul(args[1], BigPow(256, 2))
}
if args[2] != nil {
z.Mul(args[2], BigPow(256, 3))
}
if args[3] != nil {
a.Mul(args[3], BigPow(256, 4))
}
if args[4] != nil {
b.Mul(args[4], BigPow(256, 5))
}
if args[5] != nil {
c.Mul(args[5], BigPow(256, 6))
}
base.Add(op, x)
base.Add(base, y)
base.Add(base, z)
base.Add(base, a)
base.Add(base, b)
base.Add(base, c)
return base.String(), nil
}
func Instr(instr string) (int, []string, error) {
base := new(big.Int)
base.SetString(instr, 0)
args := make([]string, 7)
for i := 0; i < 7; i++ {
// int(int(val) / int(math.Pow(256,float64(i)))) % 256
exp := BigPow(256, i)
num := new(big.Int)
num.Div(base, exp)
args[i] = num.Mod(num, big.NewInt(256)).String()
}
op, _ := strconv.Atoi(args[0])
return op, args[1:7], nil
}

32
ethutil/parsing_test.go Normal file
View File

@ -0,0 +1,32 @@
package ethutil
import (
"math"
"testing"
)
func TestCompile(t *testing.T) {
instr, err := CompileInstr("PUSH")
if err != nil {
t.Error("Failed compiling instruction")
}
calc := (48 + 0*256 + 0*int64(math.Pow(256, 2)))
if Big(instr).Int64() != calc {
t.Error("Expected", calc, ", got:", instr)
}
}
func TestValidInstr(t *testing.T) {
/*
op, args, err := Instr("68163")
if err != nil {
t.Error("Error decoding instruction")
}
*/
}
func TestInvalidInstr(t *testing.T) {
}

24
ethutil/rand.go Normal file
View File

@ -0,0 +1,24 @@
package ethutil
import (
"crypto/rand"
"encoding/binary"
"io"
)
func randomUint64(r io.Reader) (uint64, error) {
b := make([]byte, 8)
n, err := r.Read(b)
if n != len(b) {
return 0, io.ErrShortBuffer
}
if err != nil {
return 0, err
}
return binary.BigEndian.Uint64(b), nil
}
// RandomUint64 returns a cryptographically random uint64 value.
func RandomUint64() (uint64, error) {
return randomUint64(rand.Reader)
}

418
ethutil/rlp.go Normal file
View File

@ -0,0 +1,418 @@
package ethutil
import (
"bytes"
_ "encoding/binary"
"fmt"
_ "log"
_ "math"
"math/big"
"reflect"
)
///////////////////////////////////////
type EthEncoder interface {
EncodeData(rlpData interface{}) []byte
}
type EthDecoder interface {
Get(idx int) *RlpValue
}
//////////////////////////////////////
type RlpEncoder struct {
rlpData []byte
}
func NewRlpEncoder() *RlpEncoder {
encoder := &RlpEncoder{}
return encoder
}
func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte {
return Encode(rlpData)
}
// Data rlpValueutes are returned by the rlp decoder. The data rlpValueutes represents
// one item within the rlp data structure. It's responsible for all the casting
// It always returns something rlpValueid
type RlpValue struct {
Value interface{}
kind reflect.Value
}
func (rlpValue *RlpValue) String() string {
return fmt.Sprintf("%q", rlpValue.Value)
}
func Conv(rlpValue interface{}) *RlpValue {
return &RlpValue{Value: rlpValue, kind: reflect.ValueOf(rlpValue)}
}
func NewRlpValue(rlpValue interface{}) *RlpValue {
return &RlpValue{Value: rlpValue}
}
func (rlpValue *RlpValue) Type() reflect.Kind {
return reflect.TypeOf(rlpValue.Value).Kind()
}
func (rlpValue *RlpValue) IsNil() bool {
return rlpValue.Value == nil
}
func (rlpValue *RlpValue) Length() int {
//return rlpValue.kind.Len()
if data, ok := rlpValue.Value.([]interface{}); ok {
return len(data)
}
return 0
}
func (rlpValue *RlpValue) AsRaw() interface{} {
return rlpValue.Value
}
func (rlpValue *RlpValue) AsUint() uint64 {
if Value, ok := rlpValue.Value.(uint8); ok {
return uint64(Value)
} else if Value, ok := rlpValue.Value.(uint16); ok {
return uint64(Value)
} else if Value, ok := rlpValue.Value.(uint32); ok {
return uint64(Value)
} else if Value, ok := rlpValue.Value.(uint64); ok {
return Value
}
return 0
}
func (rlpValue *RlpValue) AsByte() byte {
if Value, ok := rlpValue.Value.(byte); ok {
return Value
}
return 0x0
}
func (rlpValue *RlpValue) AsBigInt() *big.Int {
if a, ok := rlpValue.Value.([]byte); ok {
b := new(big.Int)
b.SetBytes(a)
return b
}
return big.NewInt(0)
}
func (rlpValue *RlpValue) AsString() string {
if a, ok := rlpValue.Value.([]byte); ok {
return string(a)
} else if a, ok := rlpValue.Value.(string); ok {
return a
} else {
//panic(fmt.Sprintf("not string %T: %v", rlpValue.Value, rlpValue.Value))
}
return ""
}
func (rlpValue *RlpValue) AsBytes() []byte {
if a, ok := rlpValue.Value.([]byte); ok {
return a
}
return make([]byte, 0)
}
func (rlpValue *RlpValue) AsSlice() []interface{} {
if d, ok := rlpValue.Value.([]interface{}); ok {
return d
}
return []interface{}{}
}
func (rlpValue *RlpValue) AsSliceFrom(from int) *RlpValue {
slice := rlpValue.AsSlice()
return NewRlpValue(slice[from:])
}
func (rlpValue *RlpValue) AsSliceTo(to int) *RlpValue {
slice := rlpValue.AsSlice()
return NewRlpValue(slice[:to])
}
func (rlpValue *RlpValue) AsSliceFromTo(from, to int) *RlpValue {
slice := rlpValue.AsSlice()
return NewRlpValue(slice[from:to])
}
// Threat the rlpValueute as a slice
func (rlpValue *RlpValue) Get(idx int) *RlpValue {
if d, ok := rlpValue.Value.([]interface{}); ok {
// Guard for oob
if len(d) <= idx {
return NewRlpValue(nil)
}
if idx < 0 {
panic("negative idx for Rlp Get")
}
return NewRlpValue(d[idx])
}
// If this wasn't a slice you probably shouldn't be using this function
return NewRlpValue(nil)
}
func (rlpValue *RlpValue) Cmp(o *RlpValue) bool {
return reflect.DeepEqual(rlpValue.Value, o.Value)
}
func (rlpValue *RlpValue) Encode() []byte {
return Encode(rlpValue.Value)
}
func NewRlpValueFromBytes(rlpData []byte) *RlpValue {
if len(rlpData) != 0 {
data, _ := Decode(rlpData, 0)
return NewRlpValue(data)
}
return NewRlpValue(nil)
}
// RlpValue value setters
// An empty rlp value is always a list
func EmptyRlpValue() *RlpValue {
return NewRlpValue([]interface{}{})
}
func (rlpValue *RlpValue) AppendList() *RlpValue {
list := EmptyRlpValue()
rlpValue.Value = append(rlpValue.AsSlice(), list)
return list
}
func (rlpValue *RlpValue) Append(v interface{}) *RlpValue {
rlpValue.Value = append(rlpValue.AsSlice(), v)
return rlpValue
}
/*
func FromBin(data []byte) uint64 {
if len(data) == 0 {
return 0
}
return FromBin(data[:len(data)-1])*256 + uint64(data[len(data)-1])
}
*/
const (
RlpEmptyList = 0x80
RlpEmptyStr = 0x40
)
func Char(c []byte) int {
if len(c) > 0 {
return int(c[0])
}
return 0
}
func DecodeWithReader(reader *bytes.Buffer) interface{} {
var slice []interface{}
// Read the next byte
char := Char(reader.Next(1))
switch {
case char == 0:
return nil
case char <= 0x7c:
return char
case char <= 0xb7:
return reader.Next(int(char - 0x80))
case char <= 0xbf:
buff := bytes.NewReader(reader.Next(int(char - 0xb8)))
length := ReadVarint(buff)
return reader.Next(int(length))
case char <= 0xf7:
length := int(char - 0xc0)
for i := 0; i < length; i++ {
obj := DecodeWithReader(reader)
if obj != nil {
slice = append(slice, obj)
} else {
break
}
}
return slice
}
return slice
}
// 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) {
/*
if pos > uint64(len(data)-1) {
log.Println(data)
log.Panicf("index out of range %d for data %q, l = %d", pos, data, len(data))
}
*/
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(bytes.NewReader(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 := BigD(data[pos+1 : pos+1+l]).Uint64()
b := ReadVarint(bytes.NewReader(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
}
var (
directRlp = big.NewInt(0x7f)
numberRlp = big.NewInt(0xb7)
zeroRlp = big.NewInt(0x0)
)
func Encode(object interface{}) []byte {
var buff bytes.Buffer
if object != nil {
switch t := object.(type) {
case *RlpValue:
buff.Write(Encode(t.AsRaw()))
// 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:
buff.Write(Encode(t.Bytes()))
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())
}
} else {
// Empty list for nil
buff.WriteByte(0xc0)
}
return buff.Bytes()
}

170
ethutil/rlp_test.go Normal file
View File

@ -0,0 +1,170 @@
package ethutil
import (
"bytes"
"encoding/hex"
"fmt"
"math/big"
"reflect"
"testing"
)
func TestRlpValueEncoding(t *testing.T) {
val := EmptyRlpValue()
val.AppendList().Append(1).Append(2).Append(3)
val.Append("4").AppendList().Append(5)
res := val.Encode()
exp := Encode([]interface{}{[]interface{}{1, 2, 3}, "4", []interface{}{5}})
if bytes.Compare(res, exp) != 0 {
t.Errorf("expected %q, got %q", res, exp)
}
}
func TestValueSlice(t *testing.T) {
val := []interface{}{
"value1",
"valeu2",
"value3",
}
value := NewValue(val)
splitVal := value.SliceFrom(1)
if splitVal.Len() != 2 {
t.Error("SliceFrom: Expected len", 2, "got", splitVal.Len())
}
splitVal = value.SliceTo(2)
if splitVal.Len() != 2 {
t.Error("SliceTo: Expected len", 2, "got", splitVal.Len())
}
splitVal = value.SliceFromTo(1, 3)
if splitVal.Len() != 2 {
t.Error("SliceFromTo: Expected len", 2, "got", splitVal.Len())
}
}
func TestValue(t *testing.T) {
value := NewValueFromBytes([]byte("\xcd\x83dog\x83god\x83cat\x01"))
if value.Get(0).Str() != "dog" {
t.Errorf("expected '%v', got '%v'", value.Get(0).Str(), "dog")
}
if value.Get(3).Uint() != 1 {
t.Errorf("expected '%v', got '%v'", value.Get(3).Uint(), 1)
}
}
func TestEncode(t *testing.T) {
strRes := "\x83dog"
bytes := Encode("dog")
str := string(bytes)
if str != strRes {
t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str))
}
sliceRes := "\xcc\x83dog\x83god\x83cat"
strs := []interface{}{"dog", "god", "cat"}
bytes = Encode(strs)
slice := string(bytes)
if slice != sliceRes {
t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice))
}
intRes := "\x82\x04\x00"
bytes = Encode(1024)
if string(bytes) != intRes {
t.Errorf("Expected %q, got %q", intRes, bytes)
}
}
func TestDecode(t *testing.T) {
single := []byte("\x01")
b, _ := Decode(single, 0)
if b.(uint8) != 1 {
t.Errorf("Expected 1, got %q", b)
}
str := []byte("\x83dog")
b, _ = Decode(str, 0)
if bytes.Compare(b.([]byte), []byte("dog")) != 0 {
t.Errorf("Expected dog, got %q", b)
}
slice := []byte("\xcc\x83dog\x83god\x83cat")
res := []interface{}{"dog", "god", "cat"}
b, _ = Decode(slice, 0)
if reflect.DeepEqual(b, res) {
t.Errorf("Expected %q, got %q", res, b)
}
}
func TestEncodeDecodeBigInt(t *testing.T) {
bigInt := big.NewInt(1391787038)
encoded := Encode(bigInt)
value := NewValueFromBytes(encoded)
fmt.Println(value.BigInt(), bigInt)
if value.BigInt().Cmp(bigInt) != 0 {
t.Errorf("Expected %v, got %v", bigInt, value.BigInt())
}
dec, _ := hex.DecodeString("52f4fc1e")
fmt.Println(NewValueFromBytes(dec).BigInt())
}
func TestEncodeDecodeBytes(t *testing.T) {
b := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, byte(6)})
val := NewValueFromBytes(b.Encode())
if !b.Cmp(val) {
t.Errorf("Expected %v, got %v", val, b)
}
}
/*
var ZeroHash256 = make([]byte, 32)
var ZeroHash160 = make([]byte, 20)
var EmptyShaList = Sha3Bin(Encode([]interface{}{}))
var GenisisHeader = []interface{}{
// Previous hash (none)
//"",
ZeroHash256,
// Sha of uncles
Sha3Bin(Encode([]interface{}{})),
// Coinbase
ZeroHash160,
// Root state
"",
// Sha of transactions
//EmptyShaList,
Sha3Bin(Encode([]interface{}{})),
// Difficulty
BigPow(2, 22),
// Time
//big.NewInt(0),
int64(0),
// extra
"",
// Nonce
big.NewInt(42),
}
func TestEnc(t *testing.T) {
//enc := Encode(GenisisHeader)
//fmt.Printf("%x (%d)\n", enc, len(enc))
h, _ := hex.DecodeString("f8a0a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06d076baa9c4074fb2df222dd16a96b0155a1e6686b3e5748b4e9ca0a208a425ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493478340000080802a")
fmt.Printf("%x\n", Sha3Bin(h))
}
*/
func BenchmarkEncodeDecode(b *testing.B) {
for i := 0; i < b.N; i++ {
bytes := Encode([]interface{}{"dog", "god", "cat"})
Decode(bytes, 0)
}
}

354
ethutil/trie.go Normal file
View File

@ -0,0 +1,354 @@
package ethutil
import (
"fmt"
"reflect"
)
type Node struct {
Key []byte
Value *Value
Dirty bool
}
func NewNode(key []byte, val *Value, dirty bool) *Node {
return &Node{Key: key, Value: val, Dirty: dirty}
}
func (n *Node) Copy() *Node {
return NewNode(n.Key, n.Value, n.Dirty)
}
type Cache struct {
nodes map[string]*Node
db Database
}
func NewCache(db Database) *Cache {
return &Cache{db: db, nodes: make(map[string]*Node)}
}
func (cache *Cache) Put(v interface{}) interface{} {
value := NewValue(v)
enc := value.Encode()
if len(enc) >= 32 {
sha := Sha3Bin(enc)
cache.nodes[string(sha)] = NewNode(sha, value, true)
return sha
}
return v
}
func (cache *Cache) Get(key []byte) *Value {
// First check if the key is the cache
if cache.nodes[string(key)] != nil {
return cache.nodes[string(key)].Value
}
// Get the key of the database instead and cache it
data, _ := cache.db.Get(key)
// Create the cached value
value := NewValueFromBytes(data)
// Create caching node
cache.nodes[string(key)] = NewNode(key, value, false)
return value
}
func (cache *Cache) Commit() {
for key, node := range cache.nodes {
if node.Dirty {
cache.db.Put([]byte(key), node.Value.Encode())
node.Dirty = false
}
}
// If the nodes grows beyond the 200 entries we simple empty it
// FIXME come up with something better
if len(cache.nodes) > 200 {
cache.nodes = make(map[string]*Node)
}
}
func (cache *Cache) Undo() {
for key, node := range cache.nodes {
if node.Dirty {
delete(cache.nodes, key)
}
}
}
// A (modified) Radix Trie implementation
type Trie struct {
Root interface{}
//db Database
cache *Cache
}
func NewTrie(db Database, Root interface{}) *Trie {
return &Trie{cache: NewCache(db), Root: Root}
}
func (t *Trie) Sync() {
t.cache.Commit()
}
/*
* Public (query) interface functions
*/
func (t *Trie) Update(key string, value string) {
k := CompactHexDecode(key)
t.Root = t.UpdateState(t.Root, k, value)
}
func (t *Trie) Get(key string) string {
k := CompactHexDecode(key)
c := NewValue(t.GetState(t.Root, k))
return c.Str()
}
func (t *Trie) GetState(node interface{}, key []int) interface{} {
n := NewValue(node)
// Return the node if key is empty (= found)
if len(key) == 0 || n.IsNil() || n.Len() == 0 {
return node
}
currentNode := t.GetNode(node)
length := currentNode.Len()
if length == 0 {
return ""
} else if length == 2 {
// Decode the key
k := CompactDecode(currentNode.Get(0).Str())
v := currentNode.Get(1).Raw()
if len(key) >= len(k) && CompareIntSlice(k, key[:len(k)]) {
return t.GetState(v, key[len(k):])
} else {
return ""
}
} else if length == 17 {
return t.GetState(currentNode.Get(key[0]).Raw(), key[1:])
}
// It shouldn't come this far
fmt.Println("GetState unexpected return")
return ""
}
func (t *Trie) GetNode(node interface{}) *Value {
n := NewValue(node)
if !n.Get(0).IsNil() {
return n
}
str := n.Str()
if len(str) == 0 {
return n
} else if len(str) < 32 {
return NewValueFromBytes([]byte(str))
}
/*
else {
// Fetch the encoded node from the db
o, err := t.db.Get(n.Bytes())
if err != nil {
fmt.Println("Error InsertState", err)
return NewValue("")
}
return NewValueFromBytes(o)
}
*/
return t.cache.Get(n.Bytes())
}
func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} {
if value != "" {
return t.InsertState(node, key, value)
} else {
// delete it
}
return ""
}
func (t *Trie) Put(node interface{}) interface{} {
/*
enc := Encode(node)
if len(enc) >= 32 {
var sha []byte
sha = Sha3Bin(enc)
//t.db.Put([]byte(sha), enc)
return sha
}
return node
*/
/*
TODO?
c := Conv(t.Root)
fmt.Println(c.Type(), c.Length())
if c.Type() == reflect.String && c.AsString() == "" {
return enc
}
*/
return t.cache.Put(node)
}
func EmptyStringSlice(l int) []interface{} {
slice := make([]interface{}, l)
for i := 0; i < l; i++ {
slice[i] = ""
}
return slice
}
func (t *Trie) InsertState(node interface{}, key []int, value interface{}) interface{} {
if len(key) == 0 {
return value
}
// New node
n := NewValue(node)
if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 {
newNode := []interface{}{CompactEncode(key), value}
return t.Put(newNode)
}
currentNode := t.GetNode(node)
// Check for "special" 2 slice type node
if currentNode.Len() == 2 {
// Decode the key
k := CompactDecode(currentNode.Get(0).Str())
v := currentNode.Get(1).Raw()
// Matching key pair (ie. there's already an object with this key)
if CompareIntSlice(k, key) {
newNode := []interface{}{CompactEncode(key), value}
return t.Put(newNode)
}
var newHash interface{}
matchingLength := MatchingNibbleLength(key, k)
if matchingLength == len(k) {
// Insert the hash, creating a new node
newHash = t.InsertState(v, key[matchingLength:], value)
} else {
// Expand the 2 length slice to a 17 length slice
oldNode := t.InsertState("", k[matchingLength+1:], v)
newNode := t.InsertState("", key[matchingLength+1:], value)
// Create an expanded slice
scaledSlice := EmptyStringSlice(17)
// Set the copied and new node
scaledSlice[k[matchingLength]] = oldNode
scaledSlice[key[matchingLength]] = newNode
newHash = t.Put(scaledSlice)
}
if matchingLength == 0 {
// End of the chain, return
return newHash
} else {
newNode := []interface{}{CompactEncode(key[:matchingLength]), newHash}
return t.Put(newNode)
}
} else {
// Copy the current node over to the new node and replace the first nibble in the key
newNode := EmptyStringSlice(17)
for i := 0; i < 17; i++ {
cpy := currentNode.Get(i).Raw()
if cpy != nil {
newNode[i] = cpy
}
}
newNode[key[0]] = t.InsertState(currentNode.Get(key[0]).Raw(), key[1:], value)
return t.Put(newNode)
}
return ""
}
// Simple compare function which creates a rlp value out of the evaluated objects
func (t *Trie) Cmp(trie *Trie) bool {
return NewValue(t.Root).Cmp(NewValue(trie.Root))
}
// Returns a copy of this trie
func (t *Trie) Copy() *Trie {
trie := NewTrie(t.cache.db, t.Root)
for key, node := range t.cache.nodes {
trie.cache.nodes[key] = node.Copy()
}
return trie
}
/*
* Trie helper functions
*/
// Helper function for printing out the raw contents of a slice
func PrintSlice(slice []string) {
fmt.Printf("[")
for i, val := range slice {
fmt.Printf("%q", val)
if i != len(slice)-1 {
fmt.Printf(",")
}
}
fmt.Printf("]\n")
}
func PrintSliceT(slice interface{}) {
c := Conv(slice)
for i := 0; i < c.Length(); i++ {
val := c.Get(i)
if val.Type() == reflect.Slice {
PrintSliceT(val.AsRaw())
} else {
fmt.Printf("%q", val)
if i != c.Length()-1 {
fmt.Printf(",")
}
}
}
}
// RLP Decodes a node in to a [2] or [17] string slice
func DecodeNode(data []byte) []string {
dec, _ := Decode(data, 0)
if slice, ok := dec.([]interface{}); ok {
strSlice := make([]string, len(slice))
for i, s := range slice {
if str, ok := s.([]byte); ok {
strSlice[i] = string(str)
}
}
return strSlice
} else {
fmt.Printf("It wasn't a []. It's a %T\n", dec)
}
return nil
}

40
ethutil/trie_test.go Normal file
View File

@ -0,0 +1,40 @@
package ethutil
import (
_ "encoding/hex"
_ "fmt"
"testing"
)
type MemDatabase struct {
db map[string][]byte
}
func NewMemDatabase() (*MemDatabase, error) {
db := &MemDatabase{db: make(map[string][]byte)}
return db, nil
}
func (db *MemDatabase) Put(key []byte, value []byte) {
db.db[string(key)] = value
}
func (db *MemDatabase) Get(key []byte) ([]byte, error) {
return db.db[string(key)], nil
}
func (db *MemDatabase) Print() {}
func (db *MemDatabase) Close() {}
func (db *MemDatabase) LastKnownTD() []byte { return nil }
func TestTrieSync(t *testing.T) {
db, _ := NewMemDatabase()
trie := NewTrie(db, "")
trie.Update("dog", "kindofalongsentencewhichshouldbeencodedinitsentirety")
if len(db.db) != 0 {
t.Error("Expected no data in database")
}
trie.Sync()
if len(db.db) == 0 {
t.Error("Expected data to be persisted")
}
}

204
ethutil/value.go Normal file
View File

@ -0,0 +1,204 @@
package ethutil
import (
"bytes"
"fmt"
"math/big"
"reflect"
)
// Data values are returned by the rlp decoder. The data values represents
// one item within the rlp data structure. It's responsible for all the casting
// It always returns something valid
type Value struct {
Val interface{}
kind reflect.Value
}
func (val *Value) String() string {
return fmt.Sprintf("%q", val.Val)
}
func NewValue(val interface{}) *Value {
return &Value{Val: val}
}
func (val *Value) Type() reflect.Kind {
return reflect.TypeOf(val.Val).Kind()
}
func (val *Value) IsNil() bool {
return val.Val == nil
}
func (val *Value) Len() int {
//return val.kind.Len()
if data, ok := val.Val.([]interface{}); ok {
return len(data)
} else if data, ok := val.Val.([]byte); ok {
// FIXME
return len(data)
}
return 0
}
func (val *Value) Raw() interface{} {
return val.Val
}
func (val *Value) Interface() interface{} {
return val.Val
}
func (val *Value) Uint() uint64 {
if Val, ok := val.Val.(uint8); ok {
return uint64(Val)
} else if Val, ok := val.Val.(uint16); ok {
return uint64(Val)
} else if Val, ok := val.Val.(uint32); ok {
return uint64(Val)
} else if Val, ok := val.Val.(uint64); ok {
return Val
} else if Val, ok := val.Val.([]byte); ok {
return ReadVarint(bytes.NewReader(Val))
}
return 0
}
func (val *Value) Byte() byte {
if Val, ok := val.Val.(byte); ok {
return Val
}
return 0x0
}
func (val *Value) BigInt() *big.Int {
if a, ok := val.Val.([]byte); ok {
b := new(big.Int).SetBytes(a)
return b
} else {
return big.NewInt(int64(val.Uint()))
}
return big.NewInt(0)
}
func (val *Value) Str() string {
if a, ok := val.Val.([]byte); ok {
return string(a)
} else if a, ok := val.Val.(string); ok {
return a
}
return ""
}
func (val *Value) Bytes() []byte {
if a, ok := val.Val.([]byte); ok {
return a
}
return make([]byte, 0)
}
func (val *Value) Slice() []interface{} {
if d, ok := val.Val.([]interface{}); ok {
return d
}
return []interface{}{}
}
func (val *Value) SliceFrom(from int) *Value {
slice := val.Slice()
return NewValue(slice[from:])
}
func (val *Value) SliceTo(to int) *Value {
slice := val.Slice()
return NewValue(slice[:to])
}
func (val *Value) SliceFromTo(from, to int) *Value {
slice := val.Slice()
return NewValue(slice[from:to])
}
// Threat the value as a slice
func (val *Value) Get(idx int) *Value {
if d, ok := val.Val.([]interface{}); ok {
// Guard for oob
if len(d) <= idx {
return NewValue(nil)
}
if idx < 0 {
panic("negative idx for Rlp Get")
}
return NewValue(d[idx])
}
// If this wasn't a slice you probably shouldn't be using this function
return NewValue(nil)
}
func (val *Value) Cmp(o *Value) bool {
return reflect.DeepEqual(val.Val, o.Val)
}
func (val *Value) Encode() []byte {
return Encode(val.Val)
}
func NewValueFromBytes(rlpData []byte) *Value {
if len(rlpData) != 0 {
data, _ := Decode(rlpData, 0)
return NewValue(data)
}
return NewValue(nil)
}
// Value setters
func NewSliceValue(s interface{}) *Value {
list := EmptyValue()
if s != nil {
if slice, ok := s.([]interface{}); ok {
for _, val := range slice {
list.Append(val)
}
} else if slice, ok := s.([]string); ok {
for _, val := range slice {
list.Append(val)
}
}
}
return list
}
func EmptyValue() *Value {
return NewValue([]interface{}{})
}
func (val *Value) AppendList() *Value {
list := EmptyValue()
val.Val = append(val.Slice(), list)
return list
}
func (val *Value) Append(v interface{}) *Value {
val.Val = append(val.Slice(), v)
return val
}