Moved ethutil => common
This commit is contained in:
12
common/.gitignore
vendored
Normal file
12
common/.gitignore
vendored
Normal 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
3
common/.travis.yml
Normal file
@ -0,0 +1,3 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.2
|
139
common/README.md
Normal file
139
common/README.md
Normal file
@ -0,0 +1,139 @@
|
||||
# ethutil
|
||||
|
||||
[](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
123
common/big.go
Normal 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
73
common/big_test.go
Normal 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
234
common/bytes.go
Normal 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
193
common/bytes_test.go
Normal 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
165
common/common.go
Normal 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
89
common/common_test.go
Normal 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
67
common/config.go
Normal 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
12
common/db.go
Normal 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
81
common/list.go
Normal 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
9
common/main_test.go
Normal 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
80
common/math/dist.go
Normal 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
66
common/math/dist_test.go
Normal 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
63
common/natspec/natspec.go
Normal 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
|
||||
|
||||
}
|
4
common/natspec/natspec_js.go
Normal file
4
common/natspec/natspec_js.go
Normal file
File diff suppressed because one or more lines are too long
97
common/natspec/natspec_test.go
Normal file
97
common/natspec/natspec_test.go
Normal 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
181
common/number/int.go
Normal 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
|
||||
)
|
92
common/number/uint_test.go
Normal file
92
common/number/uint_test.go
Normal 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
123
common/package.go
Normal 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
68
common/path.go
Normal 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
51
common/path_test.go
Normal 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
276
common/rlp.go
Normal file
@ -0,0 +1,276 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type RlpEncode interface {
|
||||
RlpEncode() []byte
|
||||
}
|
||||
|
||||
type RlpEncodeDecode interface {
|
||||
RlpEncode
|
||||
RlpValue() []interface{}
|
||||
}
|
||||
|
||||
type RlpEncodable interface {
|
||||
RlpData() interface{}
|
||||
}
|
||||
|
||||
func Rlp(encoder RlpEncode) []byte {
|
||||
return encoder.RlpEncode()
|
||||
}
|
||||
|
||||
type RlpEncoder struct {
|
||||
rlpData []byte
|
||||
}
|
||||
|
||||
func NewRlpEncoder() *RlpEncoder {
|
||||
encoder := &RlpEncoder{}
|
||||
|
||||
return encoder
|
||||
}
|
||||
func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte {
|
||||
return Encode(rlpData)
|
||||
}
|
||||
|
||||
const (
|
||||
RlpEmptyList = 0x80
|
||||
RlpEmptyStr = 0x40
|
||||
)
|
||||
|
||||
const rlpEof = -1
|
||||
|
||||
func Char(c []byte) int {
|
||||
if len(c) > 0 {
|
||||
return int(c[0])
|
||||
}
|
||||
|
||||
return rlpEof
|
||||
}
|
||||
|
||||
func DecodeWithReader(reader *bytes.Buffer) interface{} {
|
||||
var slice []interface{}
|
||||
|
||||
// Read the next byte
|
||||
char := Char(reader.Next(1))
|
||||
switch {
|
||||
case char <= 0x7f:
|
||||
return char
|
||||
|
||||
case char <= 0xb7:
|
||||
return reader.Next(int(char - 0x80))
|
||||
|
||||
case char <= 0xbf:
|
||||
length := ReadVarInt(reader.Next(int(char - 0xb7)))
|
||||
|
||||
return reader.Next(int(length))
|
||||
|
||||
case char <= 0xf7:
|
||||
length := int(char - 0xc0)
|
||||
for i := 0; i < length; i++ {
|
||||
obj := DecodeWithReader(reader)
|
||||
slice = append(slice, obj)
|
||||
}
|
||||
|
||||
return slice
|
||||
case char <= 0xff:
|
||||
length := ReadVarInt(reader.Next(int(char - 0xf7)))
|
||||
for i := uint64(0); i < length; i++ {
|
||||
obj := DecodeWithReader(reader)
|
||||
slice = append(slice, obj)
|
||||
}
|
||||
|
||||
return slice
|
||||
default:
|
||||
panic(fmt.Sprintf("byte not supported: %q", char))
|
||||
}
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
var (
|
||||
directRlp = big.NewInt(0x7f)
|
||||
numberRlp = big.NewInt(0xb7)
|
||||
zeroRlp = big.NewInt(0x0)
|
||||
)
|
||||
|
||||
func intlen(i int64) (length int) {
|
||||
for i > 0 {
|
||||
i = i >> 8
|
||||
length++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Encode(object interface{}) []byte {
|
||||
var buff bytes.Buffer
|
||||
|
||||
if object != nil {
|
||||
switch t := object.(type) {
|
||||
case *Value:
|
||||
buff.Write(Encode(t.Raw()))
|
||||
case RlpEncodable:
|
||||
buff.Write(Encode(t.RlpData()))
|
||||
// Code dup :-/
|
||||
case int:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case uint:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int8:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int16:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int32:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int64:
|
||||
buff.Write(Encode(big.NewInt(t)))
|
||||
case uint16:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case uint32:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case uint64:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case byte:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case *big.Int:
|
||||
// Not sure how this is possible while we check for nil
|
||||
if t == nil {
|
||||
buff.WriteByte(0xc0)
|
||||
} else {
|
||||
buff.Write(Encode(t.Bytes()))
|
||||
}
|
||||
case Bytes:
|
||||
buff.Write(Encode([]byte(t)))
|
||||
case []byte:
|
||||
if len(t) == 1 && t[0] <= 0x7f {
|
||||
buff.Write(t)
|
||||
} else if len(t) < 56 {
|
||||
buff.WriteByte(byte(len(t) + 0x80))
|
||||
buff.Write(t)
|
||||
} else {
|
||||
b := big.NewInt(int64(len(t)))
|
||||
buff.WriteByte(byte(len(b.Bytes()) + 0xb7))
|
||||
buff.Write(b.Bytes())
|
||||
buff.Write(t)
|
||||
}
|
||||
case string:
|
||||
buff.Write(Encode([]byte(t)))
|
||||
case []interface{}:
|
||||
// Inline function for writing the slice header
|
||||
WriteSliceHeader := func(length int) {
|
||||
if length < 56 {
|
||||
buff.WriteByte(byte(length + 0xc0))
|
||||
} else {
|
||||
b := big.NewInt(int64(length))
|
||||
buff.WriteByte(byte(len(b.Bytes()) + 0xf7))
|
||||
buff.Write(b.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
for _, val := range t {
|
||||
b.Write(Encode(val))
|
||||
}
|
||||
WriteSliceHeader(len(b.Bytes()))
|
||||
buff.Write(b.Bytes())
|
||||
default:
|
||||
// This is how it should have been from the start
|
||||
// needs refactoring (@fjl)
|
||||
v := reflect.ValueOf(t)
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
var b bytes.Buffer
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
b.Write(Encode(v.Index(i).Interface()))
|
||||
}
|
||||
|
||||
blen := b.Len()
|
||||
if blen < 56 {
|
||||
buff.WriteByte(byte(blen) + 0xc0)
|
||||
} else {
|
||||
ilen := byte(intlen(int64(blen)))
|
||||
buff.WriteByte(ilen + 0xf7)
|
||||
t := make([]byte, ilen)
|
||||
for i := byte(0); i < ilen; i++ {
|
||||
t[ilen-i-1] = byte(blen >> (i * 8))
|
||||
}
|
||||
buff.Write(t)
|
||||
}
|
||||
buff.ReadFrom(&b)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Empty list for nil
|
||||
buff.WriteByte(0xc0)
|
||||
}
|
||||
|
||||
return buff.Bytes()
|
||||
}
|
||||
|
||||
// TODO Use a bytes.Buffer instead of a raw byte slice.
|
||||
// Cleaner code, and use draining instead of seeking the next bytes to read
|
||||
func Decode(data []byte, pos uint64) (interface{}, uint64) {
|
||||
var slice []interface{}
|
||||
char := int(data[pos])
|
||||
switch {
|
||||
case char <= 0x7f:
|
||||
return data[pos], pos + 1
|
||||
|
||||
case char <= 0xb7:
|
||||
b := uint64(data[pos]) - 0x80
|
||||
|
||||
return data[pos+1 : pos+1+b], pos + 1 + b
|
||||
|
||||
case char <= 0xbf:
|
||||
b := uint64(data[pos]) - 0xb7
|
||||
|
||||
b2 := ReadVarInt(data[pos+1 : pos+1+b])
|
||||
|
||||
return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2
|
||||
|
||||
case char <= 0xf7:
|
||||
b := uint64(data[pos]) - 0xc0
|
||||
prevPos := pos
|
||||
pos++
|
||||
for i := uint64(0); i < b; {
|
||||
var obj interface{}
|
||||
|
||||
// Get the next item in the data list and append it
|
||||
obj, prevPos = Decode(data, pos)
|
||||
slice = append(slice, obj)
|
||||
|
||||
// Increment i by the amount bytes read in the previous
|
||||
// read
|
||||
i += (prevPos - pos)
|
||||
pos = prevPos
|
||||
}
|
||||
return slice, pos
|
||||
|
||||
case char <= 0xff:
|
||||
l := uint64(data[pos]) - 0xf7
|
||||
b := ReadVarInt(data[pos+1 : pos+1+l])
|
||||
|
||||
pos = pos + l + 1
|
||||
|
||||
prevPos := b
|
||||
for i := uint64(0); i < uint64(b); {
|
||||
var obj interface{}
|
||||
|
||||
obj, prevPos = Decode(data, pos)
|
||||
slice = append(slice, obj)
|
||||
|
||||
i += (prevPos - pos)
|
||||
pos = prevPos
|
||||
}
|
||||
return slice, pos
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("byte not supported: %q", char))
|
||||
}
|
||||
|
||||
return slice, 0
|
||||
}
|
156
common/rlp_test.go
Normal file
156
common/rlp_test.go
Normal 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
15
common/size.go
Normal 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
23
common/size_test.go
Normal 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
6
common/types.go
Normal file
@ -0,0 +1,6 @@
|
||||
package common
|
||||
|
||||
type (
|
||||
Hash [32]byte
|
||||
Address [20]byte
|
||||
)
|
401
common/value.go
Normal file
401
common/value.go
Normal 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
70
common/value_test.go
Normal 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)
|
||||
}
|
Reference in New Issue
Block a user