aboutsummaryrefslogtreecommitdiffstats
path: root/ethutil
diff options
context:
space:
mode:
Diffstat (limited to 'ethutil')
-rw-r--r--ethutil/.gitignore12
-rw-r--r--ethutil/.travis.yml3
-rw-r--r--ethutil/README.md139
-rw-r--r--ethutil/big.go116
-rw-r--r--ethutil/big_test.go73
-rw-r--r--ethutil/bytes.go234
-rw-r--r--ethutil/bytes_test.go193
-rw-r--r--ethutil/common.go87
-rw-r--r--ethutil/common_test.go68
-rw-r--r--ethutil/config.go72
-rw-r--r--ethutil/db.go12
-rw-r--r--ethutil/list.go81
-rw-r--r--ethutil/main_test.go9
-rw-r--r--ethutil/package.go123
-rw-r--r--ethutil/path.go60
-rw-r--r--ethutil/path_test.go51
-rw-r--r--ethutil/rand.go24
-rw-r--r--ethutil/rand_test.go17
-rw-r--r--ethutil/rlp.go276
-rw-r--r--ethutil/rlp_test.go156
-rw-r--r--ethutil/script_unix.go19
-rw-r--r--ethutil/script_windows.go12
-rw-r--r--ethutil/set.go36
-rw-r--r--ethutil/size.go15
-rw-r--r--ethutil/size_test.go23
-rw-r--r--ethutil/value.go401
-rw-r--r--ethutil/value_test.go70
27 files changed, 2382 insertions, 0 deletions
diff --git a/ethutil/.gitignore b/ethutil/.gitignore
new file mode 100644
index 000000000..f725d58d1
--- /dev/null
+++ b/ethutil/.gitignore
@@ -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
+
diff --git a/ethutil/.travis.yml b/ethutil/.travis.yml
new file mode 100644
index 000000000..69359072d
--- /dev/null
+++ b/ethutil/.travis.yml
@@ -0,0 +1,3 @@
+language: go
+go:
+ - 1.2
diff --git a/ethutil/README.md b/ethutil/README.md
new file mode 100644
index 000000000..1ed56b71b
--- /dev/null
+++ b/ethutil/README.md
@@ -0,0 +1,139 @@
+# 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
+
+trie.Delete("puppy")
+```
+
+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{}`
+
+`AppendList()` 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)
+```
diff --git a/ethutil/big.go b/ethutil/big.go
new file mode 100644
index 000000000..2ff1c72d8
--- /dev/null
+++ b/ethutil/big.go
@@ -0,0 +1,116 @@
+package ethutil
+
+import "math/big"
+
+// Big pow
+//
+// Returns the power of two big 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
+}
+
+// Big
+//
+// Shortcut for new(big.Int).SetString(..., 0)
+func Big(num string) *big.Int {
+ n := new(big.Int)
+ n.SetString(num, 0)
+
+ return n
+}
+
+// BigD
+//
+// Shortcut for new(big.Int).SetBytes(...)
+func BigD(data []byte) *big.Int {
+ n := new(big.Int)
+ n.SetBytes(data)
+
+ return n
+}
+
+func BitTest(num *big.Int, i int) bool {
+ return num.Bit(i) > 0
+}
+
+// To256
+//
+// "cast" the big int to a 256 big int (i.e., limit to)
+var tt256 = new(big.Int).Lsh(big.NewInt(1), 256)
+var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
+var tt255 = new(big.Int).Lsh(big.NewInt(1), 255)
+
+func U256(x *big.Int) *big.Int {
+ //if x.Cmp(Big0) < 0 {
+ // return new(big.Int).Add(tt256, x)
+ // }
+
+ x.And(x, tt256m1)
+
+ return x
+}
+
+func S256(x *big.Int) *big.Int {
+ if x.Cmp(tt255) < 0 {
+ return x
+ } else {
+ // We don't want to modify x, ever
+ return new(big.Int).Sub(x, tt256)
+ }
+}
+
+func FirstBitSet(v *big.Int) int {
+ for i := 0; i < v.BitLen(); i++ {
+ if v.Bit(i) > 0 {
+ return i
+ }
+ }
+
+ return v.BitLen()
+}
+
+// Big to bytes
+//
+// Returns the bytes of a big integer with the size specified by **base**
+// Attempts to pad the byte array with zeros.
+func BigToBytes(num *big.Int, base int) []byte {
+ ret := make([]byte, base/8)
+
+ if len(num.Bytes()) > base/8 {
+ return num.Bytes()
+ }
+
+ return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...)
+}
+
+// Big copy
+//
+// Creates a copy of the given big integer
+func BigCopy(src *big.Int) *big.Int {
+ return new(big.Int).Set(src)
+}
+
+// Big max
+//
+// Returns the maximum size big integer
+func BigMax(x, y *big.Int) *big.Int {
+ if x.Cmp(y) <= 0 {
+ return y
+ }
+
+ return x
+}
+
+// Big min
+//
+// Returns the minimum size big integer
+func BigMin(x, y *big.Int) *big.Int {
+ if x.Cmp(y) >= 0 {
+ return y
+ }
+
+ return x
+}
diff --git a/ethutil/big_test.go b/ethutil/big_test.go
new file mode 100644
index 000000000..bf3c96c6d
--- /dev/null
+++ b/ethutil/big_test.go
@@ -0,0 +1,73 @@
+package ethutil
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestMisc(t *testing.T) {
+ a := Big("10")
+ b := Big("57896044618658097711785492504343953926634992332820282019728792003956564819968")
+ c := []byte{1, 2, 3, 4}
+ z := BitTest(a, 1)
+
+ if z != true {
+ t.Error("Expected true got", z)
+ }
+
+ U256(a)
+ S256(a)
+
+ U256(b)
+ S256(b)
+
+ BigD(c)
+}
+
+func TestBigMax(t *testing.T) {
+ a := Big("10")
+ b := Big("5")
+
+ max1 := BigMax(a, b)
+ if max1 != a {
+ t.Errorf("Expected %d got %d", a, max1)
+ }
+
+ max2 := BigMax(b, a)
+ if max2 != a {
+ t.Errorf("Expected %d got %d", a, max2)
+ }
+}
+
+func TestBigMin(t *testing.T) {
+ a := Big("10")
+ b := Big("5")
+
+ min1 := BigMin(a, b)
+ if min1 != b {
+ t.Errorf("Expected %d got %d", b, min1)
+ }
+
+ min2 := BigMin(b, a)
+ if min2 != b {
+ t.Errorf("Expected %d got %d", b, min2)
+ }
+}
+
+func TestBigCopy(t *testing.T) {
+ a := Big("10")
+ b := BigCopy(a)
+ c := Big("1000000000000")
+ y := BigToBytes(b, 16)
+ ybytes := []byte{0, 10}
+ z := BigToBytes(c, 16)
+ zbytes := []byte{232, 212, 165, 16, 0}
+
+ if bytes.Compare(y, ybytes) != 0 {
+ t.Error("Got", ybytes)
+ }
+
+ if bytes.Compare(z, zbytes) != 0 {
+ t.Error("Got", zbytes)
+ }
+}
diff --git a/ethutil/bytes.go b/ethutil/bytes.go
new file mode 100644
index 000000000..bd294f28a
--- /dev/null
+++ b/ethutil/bytes.go
@@ -0,0 +1,234 @@
+package ethutil
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "strings"
+)
+
+type Bytes []byte
+
+func (self Bytes) String() string {
+ return string(self)
+}
+
+func DeleteFromByteSlice(s [][]byte, hash []byte) [][]byte {
+ for i, h := range s {
+ if bytes.Compare(h, hash) == 0 {
+ return append(s[:i:i], s[i+1:]...)
+ }
+ }
+
+ return s
+}
+
+// Number to bytes
+//
+// Returns the number in bytes with the specified base
+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):]
+}
+
+// Bytes to number
+//
+// Attempts to cast a byte slice to a unsigned integer
+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 int
+//
+// Read a variable length number in big endian byte order
+func ReadVarInt(buff []byte) (ret uint64) {
+ switch l := len(buff); {
+ case l > 4:
+ d := LeftPadBytes(buff, 8)
+ binary.Read(bytes.NewReader(d), binary.BigEndian, &ret)
+ case l > 2:
+ var num uint32
+ d := LeftPadBytes(buff, 4)
+ binary.Read(bytes.NewReader(d), binary.BigEndian, &num)
+ ret = uint64(num)
+ case l > 1:
+ var num uint16
+ d := LeftPadBytes(buff, 2)
+ binary.Read(bytes.NewReader(d), binary.BigEndian, &num)
+ ret = uint64(num)
+ default:
+ var num uint8
+ binary.Read(bytes.NewReader(buff), binary.BigEndian, &num)
+ ret = uint64(num)
+ }
+
+ return
+}
+
+// Binary length
+//
+// Returns the true binary length of the given number
+func BinaryLength(num int) int {
+ if num == 0 {
+ return 0
+ }
+
+ return 1 + BinaryLength(num>>8)
+}
+
+// Copy bytes
+//
+// Returns an exact copy of the provided bytes
+func CopyBytes(b []byte) (copiedBytes []byte) {
+ copiedBytes = make([]byte, len(b))
+ copy(copiedBytes, b)
+
+ return
+}
+
+func IsHex(str string) bool {
+ l := len(str)
+ return l >= 4 && l%2 == 0 && str[0:2] == "0x"
+}
+
+func Bytes2Hex(d []byte) string {
+ return hex.EncodeToString(d)
+}
+
+func Hex2Bytes(str string) []byte {
+ h, _ := hex.DecodeString(str)
+
+ return h
+}
+
+func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) {
+ if len(str) > 1 && str[0:2] == "0x" && !strings.Contains(str, "\n") {
+ ret = Hex2Bytes(str[2:])
+ } else {
+ ret = cb(str)
+ }
+
+ return
+}
+
+func FormatData(data string) []byte {
+ if len(data) == 0 {
+ return nil
+ }
+ // Simple stupid
+ d := new(big.Int)
+ if data[0:1] == "\"" && data[len(data)-1:] == "\"" {
+ return RightPadBytes([]byte(data[1:len(data)-1]), 32)
+ } else if len(data) > 1 && data[:2] == "0x" {
+ d.SetBytes(Hex2Bytes(data[2:]))
+ } else {
+ d.SetString(data, 0)
+ }
+
+ return BigToBytes(d, 256)
+}
+
+func ParseData(data ...interface{}) (ret []byte) {
+ for _, item := range data {
+ switch t := item.(type) {
+ case string:
+ var str []byte
+ if IsHex(t) {
+ str = Hex2Bytes(t[2:])
+ } else {
+ str = []byte(t)
+ }
+
+ ret = append(ret, RightPadBytes(str, 32)...)
+ case []byte:
+ ret = append(ret, LeftPadBytes(t, 32)...)
+ }
+ }
+
+ return
+}
+
+func RightPadBytes(slice []byte, l int) []byte {
+ if l < len(slice) {
+ return slice
+ }
+
+ padded := make([]byte, l)
+ copy(padded[0:len(slice)], slice)
+
+ return padded
+}
+
+func LeftPadBytes(slice []byte, l int) []byte {
+ if l < len(slice) {
+ return slice
+ }
+
+ padded := make([]byte, l)
+ copy(padded[l-len(slice):], slice)
+
+ return padded
+}
+
+func LeftPadString(str string, l int) string {
+ if l < len(str) {
+ return str
+ }
+
+ zeros := Bytes2Hex(make([]byte, (l-len(str))/2))
+
+ return zeros + str
+
+}
+
+func RightPadString(str string, l int) string {
+ if l < len(str) {
+ return str
+ }
+
+ zeros := Bytes2Hex(make([]byte, (l-len(str))/2))
+
+ return str + zeros
+
+}
+
+func Address(slice []byte) (addr []byte) {
+ if len(slice) < 20 {
+ addr = LeftPadBytes(slice, 20)
+ } else if len(slice) > 20 {
+ addr = slice[len(slice)-20:]
+ } else {
+ addr = slice
+ }
+
+ addr = CopyBytes(addr)
+
+ return
+}
+
+func ByteSliceToInterface(slice [][]byte) (ret []interface{}) {
+ for _, i := range slice {
+ ret = append(ret, i)
+ }
+
+ return
+}
diff --git a/ethutil/bytes_test.go b/ethutil/bytes_test.go
new file mode 100644
index 000000000..179a8c7ef
--- /dev/null
+++ b/ethutil/bytes_test.go
@@ -0,0 +1,193 @@
+package ethutil
+
+import (
+ checker "gopkg.in/check.v1"
+)
+
+type BytesSuite struct{}
+
+var _ = checker.Suite(&BytesSuite{})
+
+func (s *BytesSuite) TestByteString(c *checker.C) {
+ var data Bytes
+ data = []byte{102, 111, 111}
+ exp := "foo"
+ res := data.String()
+
+ c.Assert(res, checker.Equals, exp)
+}
+
+/*
+func (s *BytesSuite) TestDeleteFromByteSlice(c *checker.C) {
+ data := []byte{1, 2, 3, 4}
+ slice := []byte{1, 2, 3, 4}
+ exp := []byte{1, 4}
+ res := DeleteFromByteSlice(data, slice)
+
+ c.Assert(res, checker.DeepEquals, exp)
+}
+
+*/
+func (s *BytesSuite) TestNumberToBytes(c *checker.C) {
+ // data1 := int(1)
+ // res1 := NumberToBytes(data1, 16)
+ // c.Check(res1, checker.Panics)
+
+ var data2 float64 = 3.141592653
+ exp2 := []byte{0xe9, 0x38}
+ res2 := NumberToBytes(data2, 16)
+ c.Assert(res2, checker.DeepEquals, exp2)
+}
+
+func (s *BytesSuite) TestBytesToNumber(c *checker.C) {
+ datasmall := []byte{0xe9, 0x38, 0xe9, 0x38}
+ datalarge := []byte{0xe9, 0x38, 0xe9, 0x38, 0xe9, 0x38, 0xe9, 0x38}
+
+ var expsmall uint64 = 0xe938e938
+ var explarge uint64 = 0x0
+
+ ressmall := BytesToNumber(datasmall)
+ reslarge := BytesToNumber(datalarge)
+
+ c.Assert(ressmall, checker.Equals, expsmall)
+ c.Assert(reslarge, checker.Equals, explarge)
+
+}
+
+func (s *BytesSuite) TestReadVarInt(c *checker.C) {
+ data8 := []byte{1, 2, 3, 4, 5, 6, 7, 8}
+ data4 := []byte{1, 2, 3, 4}
+ data2 := []byte{1, 2}
+ data1 := []byte{1}
+
+ exp8 := uint64(72623859790382856)
+ exp4 := uint64(16909060)
+ exp2 := uint64(258)
+ exp1 := uint64(1)
+
+ res8 := ReadVarInt(data8)
+ res4 := ReadVarInt(data4)
+ res2 := ReadVarInt(data2)
+ res1 := ReadVarInt(data1)
+
+ c.Assert(res8, checker.Equals, exp8)
+ c.Assert(res4, checker.Equals, exp4)
+ c.Assert(res2, checker.Equals, exp2)
+ c.Assert(res1, checker.Equals, exp1)
+}
+
+func (s *BytesSuite) TestBinaryLength(c *checker.C) {
+ data1 := 0
+ data2 := 920987656789
+
+ exp1 := 0
+ exp2 := 5
+
+ res1 := BinaryLength(data1)
+ res2 := BinaryLength(data2)
+
+ c.Assert(res1, checker.Equals, exp1)
+ c.Assert(res2, checker.Equals, exp2)
+}
+
+func (s *BytesSuite) TestCopyBytes(c *checker.C) {
+ data1 := []byte{1, 2, 3, 4}
+ exp1 := []byte{1, 2, 3, 4}
+ res1 := CopyBytes(data1)
+ c.Assert(res1, checker.DeepEquals, exp1)
+}
+
+func (s *BytesSuite) TestIsHex(c *checker.C) {
+ data1 := "a9e67e"
+ exp1 := false
+ res1 := IsHex(data1)
+ c.Assert(res1, checker.DeepEquals, exp1)
+
+ data2 := "0xa9e67e00"
+ exp2 := true
+ res2 := IsHex(data2)
+ c.Assert(res2, checker.DeepEquals, exp2)
+
+}
+
+func (s *BytesSuite) TestParseDataString(c *checker.C) {
+ res1 := ParseData("hello", "world", "0x0106")
+ data := "68656c6c6f000000000000000000000000000000000000000000000000000000776f726c640000000000000000000000000000000000000000000000000000000106000000000000000000000000000000000000000000000000000000000000"
+ exp1 := Hex2Bytes(data)
+ c.Assert(res1, checker.DeepEquals, exp1)
+}
+
+func (s *BytesSuite) TestParseDataBytes(c *checker.C) {
+ data1 := []byte{232, 212, 165, 16, 0}
+ exp1 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 212, 165, 16, 0}
+
+ res1 := ParseData(data1)
+ c.Assert(res1, checker.DeepEquals, exp1)
+
+}
+
+func (s *BytesSuite) TestLeftPadBytes(c *checker.C) {
+ val1 := []byte{1, 2, 3, 4}
+ exp1 := []byte{0, 0, 0, 0, 1, 2, 3, 4}
+
+ res1 := LeftPadBytes(val1, 8)
+ res2 := LeftPadBytes(val1, 2)
+
+ c.Assert(res1, checker.DeepEquals, exp1)
+ c.Assert(res2, checker.DeepEquals, val1)
+}
+
+func (s *BytesSuite) TestFormatData(c *checker.C) {
+ data1 := ""
+ data2 := "0xa9e67e00"
+ data3 := "a9e67e"
+ data4 := "\"a9e67e00\""
+
+ // exp1 := []byte{}
+ exp2 := []byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0xa9, 0xe6, 0x7e, 00}
+ exp3 := []byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00}
+ exp4 := []byte{0x61, 0x39, 0x65, 0x36, 0x37, 0x65, 0x30, 0x30, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00}
+
+ res1 := FormatData(data1)
+ res2 := FormatData(data2)
+ res3 := FormatData(data3)
+ res4 := FormatData(data4)
+
+ c.Assert(res1, checker.IsNil)
+ c.Assert(res2, checker.DeepEquals, exp2)
+ c.Assert(res3, checker.DeepEquals, exp3)
+ c.Assert(res4, checker.DeepEquals, exp4)
+}
+
+func (s *BytesSuite) TestRightPadBytes(c *checker.C) {
+ val := []byte{1, 2, 3, 4}
+ exp := []byte{1, 2, 3, 4, 0, 0, 0, 0}
+
+ resstd := RightPadBytes(val, 8)
+ resshrt := RightPadBytes(val, 2)
+
+ c.Assert(resstd, checker.DeepEquals, exp)
+ c.Assert(resshrt, checker.DeepEquals, val)
+}
+
+func (s *BytesSuite) TestLeftPadString(c *checker.C) {
+ val := "test"
+ exp := "\x30\x30\x30\x30" + val
+
+ resstd := LeftPadString(val, 8)
+ resshrt := LeftPadString(val, 2)
+
+ c.Assert(resstd, checker.Equals, exp)
+ c.Assert(resshrt, checker.Equals, val)
+}
+
+func (s *BytesSuite) TestRightPadString(c *checker.C) {
+ val := "test"
+ exp := val + "\x30\x30\x30\x30"
+
+ resstd := RightPadString(val, 8)
+ resshrt := RightPadString(val, 2)
+
+ c.Assert(resstd, checker.Equals, exp)
+ c.Assert(resshrt, checker.Equals, val)
+}
diff --git a/ethutil/common.go b/ethutil/common.go
new file mode 100644
index 000000000..0a29cac6c
--- /dev/null
+++ b/ethutil/common.go
@@ -0,0 +1,87 @@
+package ethutil
+
+import (
+ "fmt"
+ "math/big"
+ "runtime"
+)
+
+func IsWindows() bool {
+ return runtime.GOOS == "windows"
+}
+
+func WindonizePath(path string) string {
+ if string(path[0]) == "/" && IsWindows() {
+ path = path[1:]
+ }
+ return path
+}
+
+// The different number of units
+var (
+ Douglas = BigPow(10, 42)
+ Einstein = BigPow(10, 21)
+ Ether = BigPow(10, 18)
+ Finney = BigPow(10, 15)
+ Szabo = BigPow(10, 12)
+ Shannon = BigPow(10, 9)
+ Babbage = BigPow(10, 6)
+ Ada = BigPow(10, 3)
+ Wei = big.NewInt(1)
+)
+
+//
+// Currency to string
+// Returns a string representing a human readable format
+func CurrencyToString(num *big.Int) string {
+ var (
+ fin *big.Int = num
+ denom string = "Wei"
+ )
+
+ switch {
+ case num.Cmp(Douglas) >= 0:
+ fin = new(big.Int).Div(num, Douglas)
+ denom = "Douglas"
+ case num.Cmp(Einstein) >= 0:
+ fin = new(big.Int).Div(num, Einstein)
+ denom = "Einstein"
+ case num.Cmp(Ether) >= 0:
+ fin = new(big.Int).Div(num, Ether)
+ denom = "Ether"
+ case num.Cmp(Finney) >= 0:
+ fin = new(big.Int).Div(num, Finney)
+ denom = "Finney"
+ case num.Cmp(Szabo) >= 0:
+ fin = new(big.Int).Div(num, Szabo)
+ denom = "Szabo"
+ case num.Cmp(Shannon) >= 0:
+ fin = new(big.Int).Div(num, Shannon)
+ denom = "Shannon"
+ case num.Cmp(Babbage) >= 0:
+ fin = new(big.Int).Div(num, Babbage)
+ denom = "Babbage"
+ case num.Cmp(Ada) >= 0:
+ fin = new(big.Int).Div(num, Ada)
+ denom = "Ada"
+ }
+
+ // TODO add comment clarifying expected behavior
+ if len(fin.String()) > 5 {
+ return fmt.Sprintf("%sE%d %s", fin.String()[0:5], len(fin.String())-5, denom)
+ }
+
+ return fmt.Sprintf("%v %s", fin, denom)
+}
+
+// Common big integers often used
+var (
+ Big1 = big.NewInt(1)
+ Big2 = big.NewInt(2)
+ Big3 = big.NewInt(3)
+ Big0 = big.NewInt(0)
+ BigTrue = Big1
+ BigFalse = Big0
+ Big32 = big.NewInt(32)
+ Big256 = big.NewInt(0xff)
+)
diff --git a/ethutil/common_test.go b/ethutil/common_test.go
new file mode 100644
index 000000000..c2b6077e9
--- /dev/null
+++ b/ethutil/common_test.go
@@ -0,0 +1,68 @@
+package ethutil
+
+import (
+ "math/big"
+ "os"
+
+ checker "gopkg.in/check.v1"
+)
+
+type CommonSuite struct{}
+
+var _ = checker.Suite(&CommonSuite{})
+
+func (s *CommonSuite) TestOS(c *checker.C) {
+ expwin := (os.PathSeparator == '\\' && os.PathListSeparator == ';')
+ res := IsWindows()
+
+ if !expwin {
+ c.Assert(res, checker.Equals, expwin, checker.Commentf("IsWindows is", res, "but path is", os.PathSeparator))
+ } else {
+ c.Assert(res, checker.Not(checker.Equals), expwin, checker.Commentf("IsWindows is", res, "but path is", os.PathSeparator))
+ }
+}
+
+func (s *CommonSuite) TestWindonziePath(c *checker.C) {
+ iswindowspath := os.PathSeparator == '\\'
+ path := "/opt/eth/test/file.ext"
+ res := WindonizePath(path)
+ ressep := string(res[0])
+
+ if !iswindowspath {
+ c.Assert(ressep, checker.Equals, "/")
+ } else {
+ c.Assert(ressep, checker.Not(checker.Equals), "/")
+ }
+}
+
+func (s *CommonSuite) TestCommon(c *checker.C) {
+ douglas := CurrencyToString(BigPow(10, 43))
+ einstein := CurrencyToString(BigPow(10, 22))
+ ether := CurrencyToString(BigPow(10, 19))
+ finney := CurrencyToString(BigPow(10, 16))
+ szabo := CurrencyToString(BigPow(10, 13))
+ shannon := CurrencyToString(BigPow(10, 10))
+ babbage := CurrencyToString(BigPow(10, 7))
+ ada := CurrencyToString(BigPow(10, 4))
+ wei := CurrencyToString(big.NewInt(10))
+
+ c.Assert(douglas, checker.Equals, "10 Douglas")
+ c.Assert(einstein, checker.Equals, "10 Einstein")
+ c.Assert(ether, checker.Equals, "10 Ether")
+ c.Assert(finney, checker.Equals, "10 Finney")
+ c.Assert(szabo, checker.Equals, "10 Szabo")
+ c.Assert(shannon, checker.Equals, "10 Shannon")
+ c.Assert(babbage, checker.Equals, "10 Babbage")
+ c.Assert(ada, checker.Equals, "10 Ada")
+ c.Assert(wei, checker.Equals, "10 Wei")
+}
+
+func (s *CommonSuite) TestLarge(c *checker.C) {
+ douglaslarge := CurrencyToString(BigPow(100000000, 43))
+ adalarge := CurrencyToString(BigPow(100000000, 4))
+ weilarge := CurrencyToString(big.NewInt(100000000))
+
+ c.Assert(douglaslarge, checker.Equals, "10000E298 Douglas")
+ c.Assert(adalarge, checker.Equals, "10000E7 Einstein")
+ c.Assert(weilarge, checker.Equals, "100 Babbage")
+}
diff --git a/ethutil/config.go b/ethutil/config.go
new file mode 100644
index 000000000..ccc7714d0
--- /dev/null
+++ b/ethutil/config.go
@@ -0,0 +1,72 @@
+package ethutil
+
+import (
+ "flag"
+ "fmt"
+ "os"
+
+ "github.com/rakyll/globalconf"
+)
+
+// Config struct
+type ConfigManager struct {
+ Db Database
+
+ ExecPath string
+ Debug bool
+ Diff bool
+ DiffType string
+ Paranoia bool
+ VmType int
+
+ conf *globalconf.GlobalConf
+}
+
+var Config *ConfigManager
+
+// Read config
+//
+// Initialize Config from Config File
+func ReadConfig(ConfigFile string, Datadir string, EnvPrefix string) *ConfigManager {
+ if Config == nil {
+ // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags
+ if !FileExist(ConfigFile) {
+ fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile)
+ os.Create(ConfigFile)
+ }
+ g, err := globalconf.NewWithOptions(&globalconf.Options{
+ Filename: ConfigFile,
+ EnvPrefix: EnvPrefix,
+ })
+ if err != nil {
+ fmt.Println(err)
+ } else {
+ g.ParseAll()
+ }
+ Config = &ConfigManager{ExecPath: Datadir, Debug: true, conf: g, Paranoia: true}
+ }
+ return Config
+}
+
+// provides persistence for flags
+func (c *ConfigManager) Save(key string, value interface{}) {
+ f := &flag.Flag{Name: key, Value: newConfValue(value)}
+ c.conf.Set("", f)
+}
+
+func (c *ConfigManager) Delete(key string) {
+ c.conf.Delete("", key)
+}
+
+// private type implementing flag.Value
+type confValue struct {
+ value string
+}
+
+// generic constructor to allow persising non-string values directly
+func newConfValue(value interface{}) *confValue {
+ return &confValue{fmt.Sprintf("%v", value)}
+}
+
+func (self confValue) String() string { return self.value }
+func (self confValue) Set(s string) error { self.value = s; return nil }
diff --git a/ethutil/db.go b/ethutil/db.go
new file mode 100644
index 000000000..e02a80fca
--- /dev/null
+++ b/ethutil/db.go
@@ -0,0 +1,12 @@
+package ethutil
+
+// Database interface
+type Database interface {
+ Put(key []byte, value []byte)
+ Get(key []byte) ([]byte, error)
+ //GetKeys() []*Key
+ Delete(key []byte) error
+ LastKnownTD() []byte
+ Close()
+ Print()
+}
diff --git a/ethutil/list.go b/ethutil/list.go
new file mode 100644
index 000000000..db276f1e3
--- /dev/null
+++ b/ethutil/list.go
@@ -0,0 +1,81 @@
+package ethutil
+
+import (
+ "encoding/json"
+ "reflect"
+ "sync"
+)
+
+// The list type is an anonymous slice handler which can be used
+// for containing any slice type to use in an environment which
+// does not support slice types (e.g., JavaScript, QML)
+type List struct {
+ mut sync.Mutex
+ val interface{}
+ list reflect.Value
+ Length int
+}
+
+// Initialise a new list. Panics if non-slice type is given.
+func NewList(t interface{}) *List {
+ list := reflect.ValueOf(t)
+ if list.Kind() != reflect.Slice {
+ panic("list container initialized with a non-slice type")
+ }
+
+ return &List{sync.Mutex{}, t, list, list.Len()}
+}
+
+func EmptyList() *List {
+ return NewList([]interface{}{})
+}
+
+// Get N element from the embedded slice. Returns nil if OOB.
+func (self *List) Get(i int) interface{} {
+ if self.list.Len() > i {
+ self.mut.Lock()
+ defer self.mut.Unlock()
+
+ i := self.list.Index(i).Interface()
+
+ return i
+ }
+
+ return nil
+}
+
+func (self *List) GetAsJson(i int) interface{} {
+ e := self.Get(i)
+
+ r, _ := json.Marshal(e)
+
+ return string(r)
+}
+
+// Appends value at the end of the slice. Panics when incompatible value
+// is given.
+func (self *List) Append(v interface{}) {
+ self.mut.Lock()
+ defer self.mut.Unlock()
+
+ self.list = reflect.Append(self.list, reflect.ValueOf(v))
+ self.Length = self.list.Len()
+}
+
+// Returns the underlying slice as interface.
+func (self *List) Interface() interface{} {
+ return self.list.Interface()
+}
+
+// For JavaScript <3
+func (self *List) ToJSON() string {
+ // make(T, 0) != nil
+ list := make([]interface{}, 0)
+ for i := 0; i < self.Length; i++ {
+ list = append(list, self.Get(i))
+ }
+
+ data, _ := json.Marshal(list)
+
+ return string(data)
+}
diff --git a/ethutil/main_test.go b/ethutil/main_test.go
new file mode 100644
index 000000000..fd4278ce7
--- /dev/null
+++ b/ethutil/main_test.go
@@ -0,0 +1,9 @@
+package ethutil
+
+import (
+ "testing"
+
+ checker "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) { checker.TestingT(t) }
diff --git a/ethutil/package.go b/ethutil/package.go
new file mode 100644
index 000000000..e5df989d2
--- /dev/null
+++ b/ethutil/package.go
@@ -0,0 +1,123 @@
+package ethutil
+
+import (
+ "archive/zip"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strings"
+)
+
+// Manifest object
+//
+// The manifest object holds all the relevant information supplied with the
+// the manifest specified in the package
+type Manifest struct {
+ Entry string
+ Height, Width int
+}
+
+// External package
+//
+// External package contains the main html file and manifest
+type ExtPackage struct {
+ EntryHtml string
+ Manifest *Manifest
+}
+
+// Read file
+//
+// Read a given compressed file and returns the read bytes.
+// Returns an error otherwise
+func ReadFile(f *zip.File) ([]byte, error) {
+ rc, err := f.Open()
+ if err != nil {
+ return nil, err
+ }
+ defer rc.Close()
+
+ content, err := ioutil.ReadAll(rc)
+ if err != nil {
+ return nil, err
+ }
+
+ return content, nil
+}
+
+// Reads manifest
+//
+// Reads and returns a manifest object. Returns error otherwise
+func ReadManifest(m []byte) (*Manifest, error) {
+ var manifest Manifest
+
+ dec := json.NewDecoder(strings.NewReader(string(m)))
+ if err := dec.Decode(&manifest); err == io.EOF {
+ } else if err != nil {
+ return nil, err
+ }
+
+ return &manifest, nil
+}
+
+// Find file in archive
+//
+// Returns the index of the given file name if it exists. -1 if file not found
+func FindFileInArchive(fn string, files []*zip.File) (index int) {
+ index = -1
+ // Find the manifest first
+ for i, f := range files {
+ if f.Name == fn {
+ index = i
+ }
+ }
+
+ return
+}
+
+// Open package
+//
+// Opens a prepared ethereum package
+// Reads the manifest file and determines file contents and returns and
+// the external package.
+func OpenPackage(fn string) (*ExtPackage, error) {
+ r, err := zip.OpenReader(fn)
+ if err != nil {
+ return nil, err
+ }
+ defer r.Close()
+
+ manifestIndex := FindFileInArchive("manifest.json", r.File)
+
+ if manifestIndex < 0 {
+ return nil, fmt.Errorf("No manifest file found in archive")
+ }
+
+ f, err := ReadFile(r.File[manifestIndex])
+ if err != nil {
+ return nil, err
+ }
+
+ manifest, err := ReadManifest(f)
+ if err != nil {
+ return nil, err
+ }
+
+ if manifest.Entry == "" {
+ return nil, fmt.Errorf("Entry file specified but appears to be empty: %s", manifest.Entry)
+ }
+
+ entryIndex := FindFileInArchive(manifest.Entry, r.File)
+ if entryIndex < 0 {
+ return nil, fmt.Errorf("Entry file not found: '%s'", manifest.Entry)
+ }
+
+ f, err = ReadFile(r.File[entryIndex])
+ if err != nil {
+ return nil, err
+ }
+
+ extPackage := &ExtPackage{string(f), manifest}
+
+ return extPackage, nil
+}
diff --git a/ethutil/path.go b/ethutil/path.go
new file mode 100644
index 000000000..cfbc38950
--- /dev/null
+++ b/ethutil/path.go
@@ -0,0 +1,60 @@
+package ethutil
+
+import (
+ "io/ioutil"
+ "os"
+ "os/user"
+ "strings"
+)
+
+func ExpandHomePath(p string) (path string) {
+ path = p
+
+ // Check in case of paths like "/something/~/something/"
+ if path[:2] == "~/" {
+ usr, _ := user.Current()
+ dir := usr.HomeDir
+
+ path = strings.Replace(p, "~", dir, 1)
+ }
+
+ return
+}
+
+func FileExist(filePath string) bool {
+ _, err := os.Stat(filePath)
+ if err != nil && os.IsNotExist(err) {
+ return false
+ }
+
+ return true
+}
+
+func ReadAllFile(filePath string) (string, error) {
+ file, err := os.Open(filePath)
+ if err != nil {
+ return "", err
+ }
+
+ data, err := ioutil.ReadAll(file)
+ if err != nil {
+ return "", err
+ }
+
+ return string(data), nil
+}
+
+func WriteFile(filePath string, content []byte) error {
+ fh, err := os.OpenFile(filePath, os.O_TRUNC|os.O_RDWR|os.O_CREATE, os.ModePerm)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+
+ _, err = fh.Write(content)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/ethutil/path_test.go b/ethutil/path_test.go
new file mode 100644
index 000000000..908c94ee7
--- /dev/null
+++ b/ethutil/path_test.go
@@ -0,0 +1,51 @@
+package ethutil
+
+import (
+ // "os"
+ "testing"
+)
+
+func TestGoodFile(t *testing.T) {
+ goodpath := "~/goethereumtest.pass"
+ path := ExpandHomePath(goodpath)
+ contentstring := "3.14159265358979323846"
+
+ err := WriteFile(path, []byte(contentstring))
+ if err != nil {
+ t.Error("Could not write file")
+ }
+
+ if !FileExist(path) {
+ t.Error("File not found at", path)
+ }
+
+ v, err := ReadAllFile(path)
+ if err != nil {
+ t.Error("Could not read file", path)
+ }
+ if v != contentstring {
+ t.Error("Expected", contentstring, "Got", v)
+ }
+
+}
+
+func TestBadFile(t *testing.T) {
+ badpath := "/this/path/should/not/exist/goethereumtest.fail"
+ path := ExpandHomePath(badpath)
+ contentstring := "3.14159265358979323846"
+
+ err := WriteFile(path, []byte(contentstring))
+ if err == nil {
+ t.Error("Wrote file, but should not be able to", path)
+ }
+
+ if FileExist(path) {
+ t.Error("Found file, but should not be able to", path)
+ }
+
+ v, err := ReadAllFile(path)
+ if err == nil {
+ t.Error("Read file, but should not be able to", v)
+ }
+
+}
diff --git a/ethutil/rand.go b/ethutil/rand.go
new file mode 100644
index 000000000..91dafec7e
--- /dev/null
+++ b/ethutil/rand.go
@@ -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)
+}
diff --git a/ethutil/rand_test.go b/ethutil/rand_test.go
new file mode 100644
index 000000000..c12698538
--- /dev/null
+++ b/ethutil/rand_test.go
@@ -0,0 +1,17 @@
+package ethutil
+
+import (
+ checker "gopkg.in/check.v1"
+)
+
+type RandomSuite struct{}
+
+var _ = checker.Suite(&RandomSuite{})
+
+func (s *RandomSuite) TestRandomUint64(c *checker.C) {
+ res1, _ := RandomUint64()
+ res2, _ := RandomUint64()
+ c.Assert(res1, checker.NotNil)
+ c.Assert(res2, checker.NotNil)
+ c.Assert(res1, checker.Not(checker.Equals), res2)
+}
diff --git a/ethutil/rlp.go b/ethutil/rlp.go
new file mode 100644
index 000000000..1bc1a58a7
--- /dev/null
+++ b/ethutil/rlp.go
@@ -0,0 +1,276 @@
+package ethutil
+
+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
+ 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
+}
diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go
new file mode 100644
index 000000000..ff98d3269
--- /dev/null
+++ b/ethutil/rlp_test.go
@@ -0,0 +1,156 @@
+package ethutil
+
+import (
+ "bytes"
+ "math/big"
+ "reflect"
+ "testing"
+)
+
+func TestNonInterfaceSlice(t *testing.T) {
+ vala := []string{"value1", "value2", "value3"}
+ valb := []interface{}{"value1", "value2", "value3"}
+ resa := Encode(vala)
+ resb := Encode(valb)
+ if !bytes.Equal(resa, resb) {
+ t.Errorf("expected []string & []interface{} to be equal")
+ }
+}
+
+func TestRlpValueEncoding(t *testing.T) {
+ val := EmptyValue()
+ 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 TestLargeData(t *testing.T) {
+ data := make([]byte, 100000)
+ enc := Encode(data)
+ value := NewValue(enc)
+ value.Decode()
+
+ if value.Len() != len(data) {
+ t.Error("Expected data to be", len(data), "got", value.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.Errorf("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("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)
+ if value.BigInt().Cmp(bigInt) != 0 {
+ t.Errorf("Expected %v, got %v", bigInt, value.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)
+ }
+}
+
+func TestEncodeZero(t *testing.T) {
+ b := NewValue(0).Encode()
+ exp := []byte{0xc0}
+ if bytes.Compare(b, exp) == 0 {
+ t.Error("Expected", exp, "got", b)
+ }
+}
+
+func BenchmarkEncodeDecode(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ bytes := Encode([]interface{}{"dog", "god", "cat"})
+ Decode(bytes, 0)
+ }
+}
diff --git a/ethutil/script_unix.go b/ethutil/script_unix.go
new file mode 100644
index 000000000..9250dda57
--- /dev/null
+++ b/ethutil/script_unix.go
@@ -0,0 +1,19 @@
+// +build !windows
+
+package ethutil
+
+import "github.com/ethereum/serpent-go"
+
+// General compile function
+func Compile(script string, silent bool) (ret []byte, err error) {
+ if len(script) > 2 {
+ byteCode, err := serpent.Compile(script)
+ if err != nil {
+ return nil, err
+ }
+
+ return byteCode, nil
+ }
+
+ return nil, nil
+}
diff --git a/ethutil/script_windows.go b/ethutil/script_windows.go
new file mode 100644
index 000000000..1dedc5f60
--- /dev/null
+++ b/ethutil/script_windows.go
@@ -0,0 +1,12 @@
+// +build windows
+
+package ethutil
+
+// General compile function
+func Compile(script string, silent bool) (ret []byte, err error) {
+ if len(script) > 2 {
+ return nil, nil
+ }
+
+ return nil, nil
+}
diff --git a/ethutil/set.go b/ethutil/set.go
new file mode 100644
index 000000000..7955edac0
--- /dev/null
+++ b/ethutil/set.go
@@ -0,0 +1,36 @@
+package ethutil
+
+type Settable interface {
+ AsSet() UniqueSet
+}
+
+type Stringable interface {
+ String() string
+}
+
+type UniqueSet map[string]struct{}
+
+func NewSet(v ...Stringable) UniqueSet {
+ set := make(UniqueSet)
+ for _, val := range v {
+ set.Insert(val)
+ }
+
+ return set
+}
+
+func (self UniqueSet) Insert(k Stringable) UniqueSet {
+ self[k.String()] = struct{}{}
+
+ return self
+}
+
+func (self UniqueSet) Include(k Stringable) bool {
+ _, ok := self[k.String()]
+
+ return ok
+}
+
+func Set(s Settable) UniqueSet {
+ return s.AsSet()
+}
diff --git a/ethutil/size.go b/ethutil/size.go
new file mode 100644
index 000000000..b4426465e
--- /dev/null
+++ b/ethutil/size.go
@@ -0,0 +1,15 @@
+package ethutil
+
+import "fmt"
+
+type StorageSize float64
+
+func (self StorageSize) String() string {
+ if self > 1000000 {
+ return fmt.Sprintf("%.2f mB", self/1000000)
+ } else if self > 1000 {
+ return fmt.Sprintf("%.2f kB", self/1000)
+ } else {
+ return fmt.Sprintf("%.2f B", self)
+ }
+}
diff --git a/ethutil/size_test.go b/ethutil/size_test.go
new file mode 100644
index 000000000..e0f28abc5
--- /dev/null
+++ b/ethutil/size_test.go
@@ -0,0 +1,23 @@
+package ethutil
+
+import (
+ checker "gopkg.in/check.v1"
+)
+
+type SizeSuite struct{}
+
+var _ = checker.Suite(&SizeSuite{})
+
+func (s *SizeSuite) TestStorageSizeString(c *checker.C) {
+ data1 := 2381273
+ data2 := 2192
+ data3 := 12
+
+ exp1 := "2.38 mB"
+ exp2 := "2.19 kB"
+ exp3 := "12.00 B"
+
+ c.Assert(StorageSize(data1).String(), checker.Equals, exp1)
+ c.Assert(StorageSize(data2).String(), checker.Equals, exp2)
+ c.Assert(StorageSize(data3).String(), checker.Equals, exp3)
+}
diff --git a/ethutil/value.go b/ethutil/value.go
new file mode 100644
index 000000000..7d4a7d98c
--- /dev/null
+++ b/ethutil/value.go
@@ -0,0 +1,401 @@
+package ethutil
+
+import (
+ "bytes"
+ "fmt"
+ "math/big"
+ "reflect"
+ "strconv"
+)
+
+// 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("%x", val.Val)
+}
+
+func NewValue(val interface{}) *Value {
+ t := val
+ if v, ok := val.(*Value); ok {
+ t = v.Val
+ }
+
+ return &Value{Val: t}
+}
+
+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)
+ }
+
+ return len(val.Bytes())
+}
+
+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.(float32); ok {
+ return uint64(Val)
+ } else if Val, ok := val.Val.(float64); ok {
+ return uint64(Val)
+ } else if Val, ok := val.Val.(int); ok {
+ return uint64(Val)
+ } else if Val, ok := val.Val.(uint); ok {
+ return uint64(Val)
+ } else if Val, ok := val.Val.([]byte); ok {
+ return new(big.Int).SetBytes(Val).Uint64()
+ } else if Val, ok := val.Val.(*big.Int); ok {
+ return Val.Uint64()
+ }
+
+ return 0
+}
+
+func (val *Value) Int() int64 {
+ if Val, ok := val.Val.(int8); ok {
+ return int64(Val)
+ } else if Val, ok := val.Val.(int16); ok {
+ return int64(Val)
+ } else if Val, ok := val.Val.(int32); ok {
+ return int64(Val)
+ } else if Val, ok := val.Val.(int64); ok {
+ return Val
+ } else if Val, ok := val.Val.(int); ok {
+ return int64(Val)
+ } else if Val, ok := val.Val.(float32); ok {
+ return int64(Val)
+ } else if Val, ok := val.Val.(float64); ok {
+ return int64(Val)
+ } else if Val, ok := val.Val.([]byte); ok {
+ return new(big.Int).SetBytes(Val).Int64()
+ } else if Val, ok := val.Val.(*big.Int); ok {
+ return Val.Int64()
+ } else if Val, ok := val.Val.(string); ok {
+ n, _ := strconv.Atoi(Val)
+ return int64(n)
+ }
+
+ 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 if a, ok := val.Val.(*big.Int); ok {
+ return a
+ } else if a, ok := val.Val.(string); ok {
+ return Big(a)
+ } 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
+ } else if a, ok := val.Val.(byte); ok {
+ return string(a)
+ }
+
+ return ""
+}
+
+func (val *Value) Bytes() []byte {
+ if a, ok := val.Val.([]byte); ok {
+ return a
+ } else if s, ok := val.Val.(byte); ok {
+ return []byte{s}
+ } else if s, ok := val.Val.(string); ok {
+ return []byte(s)
+ } else if s, ok := val.Val.(*big.Int); ok {
+ return s.Bytes()
+ } else {
+ return big.NewInt(val.Int()).Bytes()
+ }
+
+ return []byte{}
+}
+
+func (val *Value) Err() error {
+ if err, ok := val.Val.(error); ok {
+ return err
+ }
+
+ return nil
+}
+
+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])
+}
+
+// TODO More type checking methods
+func (val *Value) IsSlice() bool {
+ return val.Type() == reflect.Slice
+}
+
+func (val *Value) IsStr() bool {
+ return val.Type() == reflect.String
+}
+
+func (self *Value) IsErr() bool {
+ _, ok := self.Val.(error)
+ return ok
+}
+
+// Special list checking function. Something is considered
+// a list if it's of type []interface{}. The list is usually
+// used in conjunction with rlp decoded streams.
+func (val *Value) IsList() bool {
+ _, ok := val.Val.([]interface{})
+
+ return ok
+}
+
+func (val *Value) IsEmpty() bool {
+ return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0)
+}
+
+// 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 {
+ return NewValue(nil)
+ }
+
+ return NewValue(d[idx])
+ }
+
+ // If this wasn't a slice you probably shouldn't be using this function
+ return NewValue(nil)
+}
+
+func (self *Value) Copy() *Value {
+ switch val := self.Val.(type) {
+ case *big.Int:
+ return NewValue(new(big.Int).Set(val))
+ case []byte:
+ return NewValue(CopyBytes(val))
+ default:
+ return NewValue(self.Val)
+ }
+
+ return nil
+}
+
+func (val *Value) Cmp(o *Value) bool {
+ return reflect.DeepEqual(val.Val, o.Val)
+}
+
+func (self *Value) DeepCmp(o *Value) bool {
+ return bytes.Compare(self.Bytes(), o.Bytes()) == 0
+}
+
+func (val *Value) Encode() []byte {
+ return Encode(val.Val)
+}
+
+// Assume that the data we have is encoded
+func (self *Value) Decode() {
+ v, _ := Decode(self.Bytes(), 0)
+ self.Val = v
+ //self.Val = DecodeWithReader(bytes.NewBuffer(self.Bytes()))
+}
+
+func NewValueFromBytes(data []byte) *Value {
+ if len(data) != 0 {
+ value := NewValue(data)
+ value.Decode()
+
+ return value
+ }
+
+ 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
+}
+
+const (
+ valOpAdd = iota
+ valOpDiv
+ valOpMul
+ valOpPow
+ valOpSub
+)
+
+// Math stuff
+func (self *Value) doOp(op int, other interface{}) *Value {
+ left := self.BigInt()
+ right := NewValue(other).BigInt()
+
+ switch op {
+ case valOpAdd:
+ self.Val = left.Add(left, right)
+ case valOpDiv:
+ self.Val = left.Div(left, right)
+ case valOpMul:
+ self.Val = left.Mul(left, right)
+ case valOpPow:
+ self.Val = left.Exp(left, right, Big0)
+ case valOpSub:
+ self.Val = left.Sub(left, right)
+ }
+
+ return self
+}
+
+func (self *Value) Add(other interface{}) *Value {
+ return self.doOp(valOpAdd, other)
+}
+
+func (self *Value) Sub(other interface{}) *Value {
+ return self.doOp(valOpSub, other)
+}
+
+func (self *Value) Div(other interface{}) *Value {
+ return self.doOp(valOpDiv, other)
+}
+
+func (self *Value) Mul(other interface{}) *Value {
+ return self.doOp(valOpMul, other)
+}
+
+func (self *Value) Pow(other interface{}) *Value {
+ return self.doOp(valOpPow, other)
+}
+
+type ValueIterator struct {
+ value *Value
+ currentValue *Value
+ idx int
+}
+
+func (val *Value) NewIterator() *ValueIterator {
+ return &ValueIterator{value: val}
+}
+
+func (it *ValueIterator) Len() int {
+ return it.value.Len()
+}
+
+func (it *ValueIterator) Next() bool {
+ if it.idx >= it.value.Len() {
+ return false
+ }
+
+ it.currentValue = it.value.Get(it.idx)
+ it.idx++
+
+ return true
+}
+
+func (it *ValueIterator) Value() *Value {
+ return it.currentValue
+}
+
+func (it *ValueIterator) Idx() int {
+ return it.idx - 1
+}
diff --git a/ethutil/value_test.go b/ethutil/value_test.go
new file mode 100644
index 000000000..861d35184
--- /dev/null
+++ b/ethutil/value_test.go
@@ -0,0 +1,70 @@
+package ethutil
+
+import (
+ "math/big"
+
+ checker "gopkg.in/check.v1"
+)
+
+type ValueSuite struct{}
+
+var _ = checker.Suite(&ValueSuite{})
+
+func (s *ValueSuite) TestValueCmp(c *checker.C) {
+ val1 := NewValue("hello")
+ val2 := NewValue("world")
+ c.Assert(val1.Cmp(val2), checker.Equals, false)
+
+ val3 := NewValue("hello")
+ val4 := NewValue("hello")
+ c.Assert(val3.Cmp(val4), checker.Equals, true)
+}
+
+func (s *ValueSuite) TestValueTypes(c *checker.C) {
+ str := NewValue("str")
+ num := NewValue(1)
+ inter := NewValue([]interface{}{1})
+ byt := NewValue([]byte{1, 2, 3, 4})
+ bigInt := NewValue(big.NewInt(10))
+
+ strExp := "str"
+ numExp := uint64(1)
+ interExp := []interface{}{1}
+ bytExp := []byte{1, 2, 3, 4}
+ bigExp := big.NewInt(10)
+
+ c.Assert(str.Str(), checker.Equals, strExp)
+ c.Assert(num.Uint(), checker.Equals, numExp)
+ c.Assert(NewValue(inter.Interface()).Cmp(NewValue(interExp)), checker.Equals, true)
+ c.Assert(byt.Bytes(), checker.DeepEquals, bytExp)
+ c.Assert(bigInt.BigInt(), checker.DeepEquals, bigExp)
+}
+
+func (s *ValueSuite) TestIterator(c *checker.C) {
+ value := NewValue([]interface{}{1, 2, 3})
+ iter := value.NewIterator()
+ values := []uint64{1, 2, 3}
+ i := 0
+ for iter.Next() {
+ c.Assert(values[i], checker.Equals, iter.Value().Uint())
+ i++
+ }
+}
+
+func (s *ValueSuite) TestMath(c *checker.C) {
+ data1 := NewValue(1)
+ data1.Add(1).Add(1)
+ exp1 := NewValue(3)
+ data2 := NewValue(2)
+ data2.Sub(1).Sub(1)
+ exp2 := NewValue(0)
+
+ c.Assert(data1.DeepCmp(exp1), checker.Equals, true)
+ c.Assert(data2.DeepCmp(exp2), checker.Equals, true)
+}
+
+func (s *ValueSuite) TestString(c *checker.C) {
+ data := "10"
+ exp := int64(10)
+ c.Assert(NewValue(data).Int(), checker.DeepEquals, exp)
+}