Moved ethutil => common

This commit is contained in:
obscuren
2015-03-16 11:27:38 +01:00
parent 0b8f66ed9e
commit b523441361
116 changed files with 610 additions and 604 deletions

12
common/.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
common/.travis.yml Normal file
View File

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

139
common/README.md Normal file
View File

@ -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)
```

123
common/big.go Normal file
View File

@ -0,0 +1,123 @@
package common
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 Bytes2Big(data []byte) *big.Int {
n := new(big.Int)
n.SetBytes(data)
return n
}
func BigD(data []byte) *big.Int { return Bytes2Big(data) }
func String2Big(num string) *big.Int {
n := new(big.Int)
n.SetString(num, 0)
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
}

73
common/big_test.go Normal file
View File

@ -0,0 +1,73 @@
package common
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)
}
}

234
common/bytes.go Normal file
View File

@ -0,0 +1,234 @@
package common
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
}

193
common/bytes_test.go Normal file
View File

@ -0,0 +1,193 @@
package common
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)
}

165
common/common.go Normal file
View File

@ -0,0 +1,165 @@
package common
import (
"fmt"
"math/big"
"os"
"os/user"
"path"
"path/filepath"
"runtime"
"time"
"github.com/kardianos/osext"
)
// MakeName creates a node name that follows the ethereum convention
// for such names. It adds the operation system name and Go runtime version
// the name.
func MakeName(name, version string) string {
return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version())
}
func DefaultAssetPath() string {
var assetPath string
pwd, _ := os.Getwd()
srcdir := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist")
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
if pwd == srcdir {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/mist"
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
// Check if the assetPath exists. If not, try the source directory
// This happens when binary is run from outside cmd/mist directory
if _, err := os.Stat(assetPath); os.IsNotExist(err) {
assetPath = path.Join(srcdir, "assets")
}
return assetPath
}
func DefaultDataDir() string {
usr, _ := user.Current()
if runtime.GOOS == "darwin" {
return path.Join(usr.HomeDir, "Library/Ethereum")
} else if runtime.GOOS == "windows" {
return path.Join(usr.HomeDir, "AppData/Roaming/Ethereum")
} else {
return path.Join(usr.HomeDir, ".ethereum")
}
}
func FromHex(s string) []byte {
if len(s) > 1 {
if s[0:2] == "0x" {
s = s[2:]
}
if len(s)%2 == 1 {
s = "0" + s
}
return Hex2Bytes(s)
}
return nil
}
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)
Big257 = big.NewInt(257)
)
func Bench(pre string, cb func()) {
start := time.Now()
cb()
fmt.Println(pre, ": took:", time.Since(start))
}

89
common/common_test.go Normal file
View File

@ -0,0 +1,89 @@
package common
import (
"bytes"
"math/big"
"os"
"testing"
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")
}
//fromHex
func TestFromHex(t *testing.T) {
input := "0x01"
expected := []byte{1}
result := FromHex(input)
if bytes.Compare(expected, result) != 0 {
t.Errorf("Expected % x got % x", expected, result)
}
}
func TestFromHexOddLength(t *testing.T) {
input := "0x1"
expected := []byte{1}
result := FromHex(input)
if bytes.Compare(expected, result) != 0 {
t.Errorf("Expected % x got % x", expected, result)
}
}

67
common/config.go Normal file
View File

@ -0,0 +1,67 @@
package common
import (
"flag"
"fmt"
"os"
"github.com/rakyll/globalconf"
)
// Config struct
type ConfigManager struct {
ExecPath string
Debug bool
Diff bool
DiffType string
Paranoia bool
VmType int
conf *globalconf.GlobalConf
}
// Read config
//
// Initialize Config from Config File
func ReadConfig(ConfigFile string, Datadir string, EnvPrefix string) *ConfigManager {
if !FileExist(ConfigFile) {
// create ConfigFile if it does not exist, otherwise
// globalconf will panic when trying to persist flags.
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()
}
cfg := &ConfigManager{ExecPath: Datadir, Debug: true, conf: g, Paranoia: true}
return cfg
}
// 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 }

12
common/db.go Normal file
View File

@ -0,0 +1,12 @@
package common
// 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()
}

81
common/list.go Normal file
View File

@ -0,0 +1,81 @@
package common
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)
}

9
common/main_test.go Normal file
View File

@ -0,0 +1,9 @@
package common
import (
"testing"
checker "gopkg.in/check.v1"
)
func Test(t *testing.T) { checker.TestingT(t) }

80
common/math/dist.go Normal file
View File

@ -0,0 +1,80 @@
package math
import (
"math/big"
"sort"
"github.com/ethereum/go-ethereum/common"
)
type Summer interface {
Sum(i int) *big.Int
Len() int
}
func Sum(slice Summer) (sum *big.Int) {
sum = new(big.Int)
for i := 0; i < slice.Len(); i++ {
sum.Add(sum, slice.Sum(i))
}
return
}
type Vector struct {
Gas, Price *big.Int
}
type VectorsBy func(v1, v2 Vector) bool
func (self VectorsBy) Sort(vectors []Vector) {
bs := vectorSorter{
vectors: vectors,
by: self,
}
sort.Sort(bs)
}
type vectorSorter struct {
vectors []Vector
by func(v1, v2 Vector) bool
}
func (v vectorSorter) Len() int { return len(v.vectors) }
func (v vectorSorter) Less(i, j int) bool { return v.by(v.vectors[i], v.vectors[j]) }
func (v vectorSorter) Swap(i, j int) { v.vectors[i], v.vectors[j] = v.vectors[j], v.vectors[i] }
func PriceSort(v1, v2 Vector) bool { return v1.Price.Cmp(v2.Price) < 0 }
func GasSort(v1, v2 Vector) bool { return v1.Gas.Cmp(v2.Gas) < 0 }
type vectorSummer struct {
vectors []Vector
by func(v Vector) *big.Int
}
type VectorSum func(v Vector) *big.Int
func (v VectorSum) Sum(vectors []Vector) *big.Int {
vs := vectorSummer{
vectors: vectors,
by: v,
}
return Sum(vs)
}
func (v vectorSummer) Len() int { return len(v.vectors) }
func (v vectorSummer) Sum(i int) *big.Int { return v.by(v.vectors[i]) }
func GasSum(v Vector) *big.Int { return v.Gas }
var etherInWei = new(big.Rat).SetInt(common.String2Big("1000000000000000000"))
func GasPrice(bp, gl, ep *big.Int) *big.Int {
BP := new(big.Rat).SetInt(bp)
GL := new(big.Rat).SetInt(gl)
EP := new(big.Rat).SetInt(ep)
GP := new(big.Rat).Quo(BP, GL)
GP = GP.Quo(GP, EP)
return GP.Mul(GP, etherInWei).Num()
}

66
common/math/dist_test.go Normal file
View File

@ -0,0 +1,66 @@
package math
import (
"fmt"
"math/big"
"testing"
)
type summer struct {
numbers []*big.Int
}
func (s summer) Len() int { return len(s.numbers) }
func (s summer) Sum(i int) *big.Int {
return s.numbers[i]
}
func TestSum(t *testing.T) {
summer := summer{numbers: []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}}
sum := Sum(summer)
if sum.Cmp(big.NewInt(6)) != 0 {
t.Errorf("not 6", sum)
}
}
func TestDist(t *testing.T) {
var vectors = []Vector{
Vector{big.NewInt(1000), big.NewInt(1234)},
Vector{big.NewInt(500), big.NewInt(10023)},
Vector{big.NewInt(1034), big.NewInt(1987)},
Vector{big.NewInt(1034), big.NewInt(1987)},
Vector{big.NewInt(8983), big.NewInt(1977)},
Vector{big.NewInt(98382), big.NewInt(1887)},
Vector{big.NewInt(12398), big.NewInt(1287)},
Vector{big.NewInt(12398), big.NewInt(1487)},
Vector{big.NewInt(12398), big.NewInt(1987)},
Vector{big.NewInt(12398), big.NewInt(128)},
Vector{big.NewInt(12398), big.NewInt(1987)},
Vector{big.NewInt(1398), big.NewInt(187)},
Vector{big.NewInt(12328), big.NewInt(1927)},
Vector{big.NewInt(12398), big.NewInt(1987)},
Vector{big.NewInt(22398), big.NewInt(1287)},
Vector{big.NewInt(1370), big.NewInt(1981)},
Vector{big.NewInt(12398), big.NewInt(1957)},
Vector{big.NewInt(42198), big.NewInt(1987)},
}
VectorsBy(GasSort).Sort(vectors)
fmt.Println(vectors)
BP := big.NewInt(15)
GL := big.NewInt(1000000)
EP := big.NewInt(100)
fmt.Println("BP", BP, "GL", GL, "EP", EP)
GP := GasPrice(BP, GL, EP)
fmt.Println("GP =", GP, "Wei per GU")
S := len(vectors) / 4
fmt.Println("L", len(vectors), "S", S)
for i := 1; i <= S*4; i += S {
fmt.Printf("T%d = %v\n", i, vectors[i])
}
g := VectorSum(GasSum).Sum(vectors)
fmt.Printf("G = ∑g* (%v)\n", g)
}

63
common/natspec/natspec.go Normal file
View File

@ -0,0 +1,63 @@
package natspec
import (
"fmt"
"github.com/obscuren/otto"
)
type NatSpec struct {
jsvm *otto.Otto
}
// TODO: should initialise with abi and userdoc jsons
func New() (self *NatSpec, err error) {
self = new(NatSpec)
self.jsvm = otto.New()
_, err = self.jsvm.Run(natspecJS)
if err != nil {
return
}
_, err = self.jsvm.Run("var natspec = require('natspec');")
if err != nil {
return
}
return
}
func (self *NatSpec) Notice(transaction, abi, method, expression string) (string, error) {
var err error
if _, err = self.jsvm.Run("var transaction = " + transaction + ";"); err != nil {
return "", fmt.Errorf("natspec.js error setting transaction: %v", err)
}
if _, err = self.jsvm.Run("var abi = " + abi + ";"); err != nil {
return "", fmt.Errorf("natspec.js error setting abi: %v", err)
}
if _, err = self.jsvm.Run("var method = '" + method + "';"); err != nil {
return "", fmt.Errorf("natspec.js error setting method: %v", err)
}
if _, err = self.jsvm.Run("var expression = \"" + expression + "\";"); err != nil {
return "", fmt.Errorf("natspec.js error setting expression: %v", err)
}
self.jsvm.Run("var call = {method: method,abi: abi,transaction: transaction};")
value, err := self.jsvm.Run("natspec.evaluateExpression(expression, call);")
if err != nil {
return "", fmt.Errorf("natspec.js error evaluating expression: %v", err)
}
evalError := "Natspec evaluation failed, wrong input params"
if value.String() == evalError {
return "", fmt.Errorf("natspec.js error evaluating expression: wrong input params in expression '%s'", expression)
}
if len(value.String()) == 0 {
return "", fmt.Errorf("natspec.js error evaluating expression")
}
return value.String(), nil
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,97 @@
package natspec
import (
"testing"
)
func TestNotice(t *testing.T) {
tx := `
{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"to": "0x8521742d3f456bd237e312d6e30724960f72517a",
"data": "0xc6888fa1000000000000000000000000000000000000000000000000000000000000007a"
}],
"id": 6
}
`
abi := `
[{
"name": "multiply",
"constant": false,
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}],
"outputs": [{
"name": "d",
"type": "uint256"
}]
}]
`
desc := "Will multiply `a` by 7 and return `a * 7`."
method := "multiply"
ns, err := New()
if err != nil {
t.Errorf("NewNATSpec error %v", err)
}
notice, err := ns.Notice(tx, abi, method, desc)
if err != nil {
t.Errorf("expected no error got %v", err)
}
expected := "Will multiply 122 by 7 and return 854."
if notice != expected {
t.Errorf("incorrect notice. expected %v, got %v", expected, notice)
} else {
t.Logf("returned notice \"%v\"", notice)
}
notice, err = ns.Notice(tx, abi, method, "Will multiply 122 by \"7\" and return 854.")
expected = "natspec.js error setting expression: (anonymous): Line 1:41 Unexpected number"
if err == nil {
t.Errorf("expected error, got nothing (notice: '%v')", err, notice)
} else {
if err.Error() != expected {
t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice)
}
}
// https://github.com/ethereum/natspec.js/issues/1
badDesc := "Will multiply `e` by 7 and return `a * 7`."
notice, err = ns.Notice(tx, abi, method, badDesc)
expected = "natspec.js error evaluating expression: Error: Natspec evaluation failed, wrong input params"
if err == nil {
t.Errorf("expected error, got nothing (notice: '%v')", notice)
} else {
if err.Error() != expected {
t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice)
}
}
notice, err = ns.Notice(tx, abi, "missing_method", desc)
expected = "natspec.js error evaluating expression: Error: Natspec evaluation failed, method does not exist"
if err == nil {
t.Errorf("expected error, got nothing (notice: '%v')", notice)
} else {
if err.Error() != expected {
t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice)
}
}
}

181
common/number/int.go Normal file
View File

@ -0,0 +1,181 @@
package number
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
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 limitUnsigned256(x *Number) *Number {
x.num.And(x.num, tt256m1)
return x
}
func limitSigned256(x *Number) *Number {
if x.num.Cmp(tt255) < 0 {
return x
} else {
x.num.Sub(x.num, tt256)
return x
}
}
// Number function
type Initialiser func(n int64) *Number
// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations
// to give "fake" bounded integers. New types of Number can be created through NewInitialiser returning a lambda
// with the new Initialiser.
type Number struct {
num *big.Int
limit func(n *Number) *Number
}
// Returns a new initialiser for a new *Number without having to expose certain fields
func NewInitialiser(limiter func(*Number) *Number) Initialiser {
return func(n int64) *Number {
return &Number{big.NewInt(n), limiter}
}
}
// Return a Number with a UNSIGNED limiter up to 256 bits
func Uint256(n int64) *Number {
return &Number{big.NewInt(n), limitUnsigned256}
}
// Return a Number with a SIGNED limiter up to 256 bits
func Int256(n int64) *Number {
return &Number{big.NewInt(n), limitSigned256}
}
// Returns a Number with a SIGNED unlimited size
func Big(n int64) *Number {
return &Number{big.NewInt(n), func(x *Number) *Number { return x }}
}
// Sets i to sum of x+y
func (i *Number) Add(x, y *Number) *Number {
i.num.Add(x.num, y.num)
return i.limit(i)
}
// Sets i to difference of x-y
func (i *Number) Sub(x, y *Number) *Number {
i.num.Sub(x.num, y.num)
return i.limit(i)
}
// Sets i to product of x*y
func (i *Number) Mul(x, y *Number) *Number {
i.num.Mul(x.num, y.num)
return i.limit(i)
}
// Sets i to the quotient prodject of x/y
func (i *Number) Div(x, y *Number) *Number {
i.num.Div(x.num, y.num)
return i.limit(i)
}
// Sets i to x % y
func (i *Number) Mod(x, y *Number) *Number {
i.num.Mod(x.num, y.num)
return i.limit(i)
}
// Sets i to x << s
func (i *Number) Lsh(x *Number, s uint) *Number {
i.num.Lsh(x.num, s)
return i.limit(i)
}
// Sets i to x^y
func (i *Number) Pow(x, y *Number) *Number {
i.num.Exp(x.num, y.num, big.NewInt(0))
return i.limit(i)
}
// Setters
// Set x to i
func (i *Number) Set(x *Number) *Number {
i.num.Set(x.num)
return i.limit(i)
}
// Set x bytes to i
func (i *Number) SetBytes(x []byte) *Number {
i.num.SetBytes(x)
return i.limit(i)
}
// Cmp compares x and y and returns:
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
func (i *Number) Cmp(x *Number) int {
return i.num.Cmp(x.num)
}
// Getters
// Returns the string representation of i
func (i *Number) String() string {
return i.num.String()
}
// Returns the byte representation of i
func (i *Number) Bytes() []byte {
return i.num.Bytes()
}
// Uint64 returns the Uint64 representation of x. If x cannot be represented in an int64, the result is undefined.
func (i *Number) Uint64() uint64 {
return i.num.Uint64()
}
// Int64 returns the int64 representation of x. If x cannot be represented in an int64, the result is undefined.
func (i *Number) Int64() int64 {
return i.num.Int64()
}
// Returns the signed version of i
func (i *Number) Int256() *Number {
return Int(0).Set(i)
}
// Returns the unsigned version of i
func (i *Number) Uint256() *Number {
return Uint(0).Set(i)
}
// Returns the index of the first bit that's set to 1
func (i *Number) FirstBitSet() int {
for j := 0; j < i.num.BitLen(); j++ {
if i.num.Bit(j) > 0 {
return j
}
}
return i.num.BitLen()
}
// Variables
var (
Zero = Uint(0)
One = Uint(1)
Two = Uint(2)
MaxUint256 = Uint(0).SetBytes(common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
MinOne = Int(-1)
// "typedefs"
Uint = Uint256
Int = Int256
)

View File

@ -0,0 +1,92 @@
package number
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
)
func TestSet(t *testing.T) {
a := Uint(0)
b := Uint(10)
a.Set(b)
if a.num.Cmp(b.num) != 0 {
t.Error("didn't compare", a, b)
}
c := Uint(0).SetBytes(common.Hex2Bytes("0a"))
if c.num.Cmp(big.NewInt(10)) != 0 {
t.Error("c set bytes failed.")
}
}
func TestInitialiser(t *testing.T) {
check := false
init := NewInitialiser(func(x *Number) *Number {
check = true
return x
})
a := init(0).Add(init(1), init(2))
if a.Cmp(init(3)) != 0 {
t.Error("expected 3. got", a)
}
if !check {
t.Error("expected limiter to be called")
}
}
func TestGet(t *testing.T) {
a := Uint(10)
if a.Uint64() != 10 {
t.Error("expected to get 10. got", a.Uint64())
}
a = Uint(10)
if a.Int64() != 10 {
t.Error("expected to get 10. got", a.Int64())
}
}
func TestCmp(t *testing.T) {
a := Uint(10)
b := Uint(10)
c := Uint(11)
if a.Cmp(b) != 0 {
t.Error("a b == 0 failed", a, b)
}
if a.Cmp(c) >= 0 {
t.Error("a c < 0 failed", a, c)
}
if c.Cmp(b) <= 0 {
t.Error("c b > 0 failed", c, b)
}
}
func TestMaxArith(t *testing.T) {
a := Uint(0).Add(MaxUint256, One)
if a.Cmp(Zero) != 0 {
t.Error("expected max256 + 1 = 0 got", a)
}
a = Uint(0).Sub(Uint(0), One)
if a.Cmp(MaxUint256) != 0 {
t.Error("expected 0 - 1 = max256 got", a)
}
a = Int(0).Sub(Int(0), One)
if a.Cmp(MinOne) != 0 {
t.Error("expected 0 - 1 = -1 got", a)
}
}
func TestConversion(t *testing.T) {
a := Int(-1)
b := a.Uint256()
if b.Cmp(MaxUint256) != 0 {
t.Error("expected -1 => unsigned to return max. got", b)
}
}

123
common/package.go Normal file
View File

@ -0,0 +1,123 @@
package common
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
}

68
common/path.go Normal file
View File

@ -0,0 +1,68 @@
package common
import (
"io/ioutil"
"os"
"os/user"
"path"
"strings"
)
func ExpandHomePath(p string) (path string) {
path = p
// Check in case of paths like "/something/~/something/"
if len(path) > 1 && 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
}
func AbsolutePath(Datadir string, filename string) string {
if path.IsAbs(filename) {
return filename
}
return path.Join(Datadir, filename)
}

51
common/path_test.go Normal file
View File

@ -0,0 +1,51 @@
package common
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)
}
}

276
common/rlp.go Normal file
View File

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

156
common/rlp_test.go Normal file
View File

@ -0,0 +1,156 @@
package common
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)
}
}

15
common/size.go Normal file
View File

@ -0,0 +1,15 @@
package common
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)
}
}

23
common/size_test.go Normal file
View File

@ -0,0 +1,23 @@
package common
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)
}

6
common/types.go Normal file
View File

@ -0,0 +1,6 @@
package common
type (
Hash [32]byte
Address [20]byte
)

401
common/value.go Normal file
View File

@ -0,0 +1,401 @@
package common
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
}

70
common/value_test.go Normal file
View File

@ -0,0 +1,70 @@
package common
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)
}