From f6d1bfe45bf3709d7bad40bf563b5c09228622e3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 14 Feb 2014 23:56:09 +0100 Subject: The great merge --- ethutil/.gitignore | 12 ++ ethutil/.travil.yml | 3 + ethutil/README.md | 137 ++++++++++++++++ ethutil/big.go | 37 +++++ ethutil/bytes.go | 64 ++++++++ ethutil/config.go | 106 ++++++++++++ ethutil/db.go | 10 ++ ethutil/encoding.go | 62 +++++++ ethutil/encoding_test.go | 37 +++++ ethutil/helpers.go | 61 +++++++ ethutil/parsing.go | 108 ++++++++++++ ethutil/parsing_test.go | 32 ++++ ethutil/rand.go | 24 +++ ethutil/rlp.go | 418 +++++++++++++++++++++++++++++++++++++++++++++++ ethutil/rlp_test.go | 170 +++++++++++++++++++ ethutil/trie.go | 354 +++++++++++++++++++++++++++++++++++++++ ethutil/trie_test.go | 40 +++++ ethutil/value.go | 204 +++++++++++++++++++++++ 18 files changed, 1879 insertions(+) create mode 100644 ethutil/.gitignore create mode 100644 ethutil/.travil.yml create mode 100644 ethutil/README.md create mode 100644 ethutil/big.go create mode 100644 ethutil/bytes.go create mode 100644 ethutil/config.go create mode 100644 ethutil/db.go create mode 100644 ethutil/encoding.go create mode 100644 ethutil/encoding_test.go create mode 100644 ethutil/helpers.go create mode 100644 ethutil/parsing.go create mode 100644 ethutil/parsing_test.go create mode 100644 ethutil/rand.go create mode 100644 ethutil/rlp.go create mode 100644 ethutil/rlp_test.go create mode 100644 ethutil/trie.go create mode 100644 ethutil/trie_test.go create mode 100644 ethutil/value.go (limited to 'ethutil') diff --git a/ethutil/.gitignore b/ethutil/.gitignore new file mode 100644 index 000000000..f725d58d1 --- /dev/null +++ b/ethutil/.gitignore @@ -0,0 +1,12 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store + diff --git a/ethutil/.travil.yml b/ethutil/.travil.yml new file mode 100644 index 000000000..69359072d --- /dev/null +++ b/ethutil/.travil.yml @@ -0,0 +1,3 @@ +language: go +go: + - 1.2 diff --git a/ethutil/README.md b/ethutil/README.md new file mode 100644 index 000000000..c98612e1e --- /dev/null +++ b/ethutil/README.md @@ -0,0 +1,137 @@ +# ethutil + +[![Build +Status](https://travis-ci.org/ethereum/go-ethereum.png?branch=master)](https://travis-ci.org/ethereum/go-ethereum) + +The ethutil package contains the ethereum utility library. + +# Installation + +`go get github.com/ethereum/ethutil-go` + +# Usage + +## RLP (Recursive Linear Prefix) Encoding + +RLP Encoding is an encoding scheme utilized by the Ethereum project. It +encodes any native value or list to string. + +More in depth information about the Encoding scheme see the [Wiki](http://wiki.ethereum.org/index.php/RLP) +article. + +```go +rlp := ethutil.Encode("doge") +fmt.Printf("%q\n", rlp) // => "\0x83dog" + +rlp = ethutil.Encode([]interface{}{"dog", "cat"}) +fmt.Printf("%q\n", rlp) // => "\0xc8\0x83dog\0x83cat" +decoded := ethutil.Decode(rlp) +fmt.Println(decoded) // => ["dog" "cat"] +``` + +## Patricia Trie + +Patricie Tree is a merkle trie utilized by the Ethereum project. + +More in depth information about the (modified) Patricia Trie can be +found on the [Wiki](http://wiki.ethereum.org/index.php/Patricia_Tree). + +The patricia trie uses a db as backend and could be anything as long as +it satisfies the Database interface found in `ethutil/db.go`. + +```go +db := NewDatabase() + +// db, root +trie := ethutil.NewTrie(db, "") + +trie.Put("puppy", "dog") +trie.Put("horse", "stallion") +trie.Put("do", "verb") +trie.Put("doge", "coin") + +// Look up the key "do" in the trie +out := trie.Get("do") +fmt.Println(out) // => verb +``` + +The patricia trie, in combination with RLP, provides a robust, +cryptographically authenticated data structure that can be used to store +all (key, value) bindings. + +```go +// ... Create db/trie + +// Note that RLP uses interface slices as list +value := ethutil.Encode([]interface{}{"one", 2, "three", []interface{}{42}}) +// Store the RLP encoded value of the list +trie.Put("mykey", value) +``` + +## Value + +Value is a Generic Value which is used in combination with RLP data or +`([])interface{}` structures. It may serve as a bridge between RLP data +and actual real values and takes care of all the type checking and +casting. Unlike Go's `reflect.Value` it does not panic if it's unable to +cast to the requested value. It simple returns the base value of that +type (e.g. `Slice()` returns []interface{}, `Uint()` return 0, etc). + +### Creating a new Value + +`NewEmptyValue()` returns a new \*Value with it's initial value set to a +`[]interface{}` + +`AppendLint()` appends a list to the current value. + +`Append(v)` appends the value (v) to the current value/list. + +```go +val := ethutil.NewEmptyValue().Append(1).Append("2") +val.AppendList().Append(3) +``` + +### Retrieving values + +`Get(i)` returns the `i` item in the list. + +`Uint()` returns the value as an unsigned int64. + +`Slice()` returns the value as a interface slice. + +`Str()` returns the value as a string. + +`Bytes()` returns the value as a byte slice. + +`Len()` assumes current to be a slice and returns its length. + +`Byte()` returns the value as a single byte. + +```go +val := ethutil.NewValue([]interface{}{1,"2",[]interface{}{3}}) +val.Get(0).Uint() // => 1 +val.Get(1).Str() // => "2" +s := val.Get(2) // => Value([]interface{}{3}) +s.Get(0).Uint() // => 3 +``` + +## Decoding + +Decoding streams of RLP data is simplified + +```go +val := ethutil.NewValueFromBytes(rlpData) +val.Get(0).Uint() +``` + +## Encoding + +Encoding from Value to RLP is done with the `Encode` method. The +underlying value can be anything RLP can encode (int, str, lists, bytes) + +```go +val := ethutil.NewValue([]interface{}{1,"2",[]interface{}{3}}) +rlp := val.Encode() +// Store the rlp data +Store(rlp) +``` diff --git a/ethutil/big.go b/ethutil/big.go new file mode 100644 index 000000000..979078bef --- /dev/null +++ b/ethutil/big.go @@ -0,0 +1,37 @@ +package ethutil + +import ( + "math/big" +) + +var BigInt0 *big.Int = big.NewInt(0) + +// True +var BigTrue *big.Int = big.NewInt(1) + +// False +var BigFalse *big.Int = big.NewInt(0) + +// Returns the power of two integers +func BigPow(a, b int) *big.Int { + c := new(big.Int) + c.Exp(big.NewInt(int64(a)), big.NewInt(int64(b)), big.NewInt(0)) + + return c +} + +// Like big.NewInt(uint64); this takes a string instead. +func Big(num string) *big.Int { + n := new(big.Int) + n.SetString(num, 0) + + return n +} + +// Like big.NewInt(uint64); this takes a byte buffer instead. +func BigD(data []byte) *big.Int { + n := new(big.Int) + n.SetBytes(data) + + return n +} diff --git a/ethutil/bytes.go b/ethutil/bytes.go new file mode 100644 index 000000000..40903a5f1 --- /dev/null +++ b/ethutil/bytes.go @@ -0,0 +1,64 @@ +package ethutil + +import ( + "bytes" + "encoding/binary" + "fmt" +) + +func NumberToBytes(num interface{}, bits int) []byte { + buf := new(bytes.Buffer) + err := binary.Write(buf, binary.BigEndian, num) + if err != nil { + fmt.Println("NumberToBytes failed:", err) + } + + return buf.Bytes()[buf.Len()-(bits/8):] +} + +func BytesToNumber(b []byte) uint64 { + var number uint64 + + // Make sure the buffer is 64bits + data := make([]byte, 8) + data = append(data[:len(b)], b...) + + buf := bytes.NewReader(data) + err := binary.Read(buf, binary.BigEndian, &number) + if err != nil { + fmt.Println("BytesToNumber failed:", err) + } + + return number +} + +// Read variable integer in big endian +func ReadVarint(reader *bytes.Reader) (ret uint64) { + if reader.Len() == 8 { + var num uint64 + binary.Read(reader, binary.BigEndian, &num) + ret = uint64(num) + } else if reader.Len() == 4 { + var num uint32 + binary.Read(reader, binary.BigEndian, &num) + ret = uint64(num) + } else if reader.Len() == 2 { + var num uint16 + binary.Read(reader, binary.BigEndian, &num) + ret = uint64(num) + } else { + var num uint8 + binary.Read(reader, binary.BigEndian, &num) + ret = uint64(num) + } + + return ret +} + +func BinaryLength(num int) int { + if num == 0 { + return 0 + } + + return 1 + BinaryLength(num>>8) +} diff --git a/ethutil/config.go b/ethutil/config.go new file mode 100644 index 000000000..7782e7daa --- /dev/null +++ b/ethutil/config.go @@ -0,0 +1,106 @@ +package ethutil + +import ( + "log" + "os" + "os/user" + "path" +) + +type LogType byte + +const ( + LogTypeStdIn = 1 + LogTypeFile = 2 +) + +// Config struct isn't exposed +type config struct { + Db Database + + Log Logger + ExecPath string + Debug bool + Ver string + Pubkey []byte + Seed bool +} + +var Config *config + +// Read config doesn't read anything yet. +func ReadConfig(base string) *config { + if Config == nil { + usr, _ := user.Current() + path := path.Join(usr.HomeDir, base) + + //Check if the logging directory already exists, create it if not + _, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + log.Printf("Debug logging directory %s doesn't exist, creating it", path) + os.Mkdir(path, 0777) + } + } + + Config = &config{ExecPath: path, Debug: true, Ver: "0.2.1"} + Config.Log = NewLogger(LogFile|LogStd, 0) + } + + return Config +} + +type LoggerType byte + +const ( + LogFile = 0x1 + LogStd = 0x2 +) + +type Logger struct { + logSys []*log.Logger + logLevel int +} + +func NewLogger(flag LoggerType, level int) Logger { + var loggers []*log.Logger + + flags := log.LstdFlags | log.Lshortfile + + if flag&LogFile > 0 { + file, err := os.OpenFile(path.Join(Config.ExecPath, "debug.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + if err != nil { + log.Panic("unable to create file logger", err) + } + + log := log.New(file, "[ETH]", flags) + + loggers = append(loggers, log) + } + if flag&LogStd > 0 { + log := log.New(os.Stdout, "[ETH]", flags) + loggers = append(loggers, log) + } + + return Logger{logSys: loggers, logLevel: level} +} + +func (log Logger) Debugln(v ...interface{}) { + if log.logLevel != 0 { + return + } + + for _, logger := range log.logSys { + logger.Println(v...) + } +} + +func (log Logger) Debugf(format string, v ...interface{}) { + if log.logLevel != 0 { + return + } + + for _, logger := range log.logSys { + logger.Printf(format, v...) + } +} diff --git a/ethutil/db.go b/ethutil/db.go new file mode 100644 index 000000000..3681c4b05 --- /dev/null +++ b/ethutil/db.go @@ -0,0 +1,10 @@ +package ethutil + +// Database interface +type Database interface { + Put(key []byte, value []byte) + Get(key []byte) ([]byte, error) + LastKnownTD() []byte + Close() + Print() +} diff --git a/ethutil/encoding.go b/ethutil/encoding.go new file mode 100644 index 000000000..207548c93 --- /dev/null +++ b/ethutil/encoding.go @@ -0,0 +1,62 @@ +package ethutil + +import ( + "bytes" + "encoding/hex" + _ "fmt" + "strings" +) + +func CompactEncode(hexSlice []int) string { + terminator := 0 + if hexSlice[len(hexSlice)-1] == 16 { + terminator = 1 + } + + if terminator == 1 { + hexSlice = hexSlice[:len(hexSlice)-1] + } + + oddlen := len(hexSlice) % 2 + flags := 2*terminator + oddlen + if oddlen != 0 { + hexSlice = append([]int{flags}, hexSlice...) + } else { + hexSlice = append([]int{flags, 0}, hexSlice...) + } + + var buff bytes.Buffer + for i := 0; i < len(hexSlice); i += 2 { + buff.WriteByte(byte(16*hexSlice[i] + hexSlice[i+1])) + } + + return buff.String() +} + +func CompactDecode(str string) []int { + base := CompactHexDecode(str) + base = base[:len(base)-1] + if base[0] >= 2 { // && base[len(base)-1] != 16 { + base = append(base, 16) + } + if base[0]%2 == 1 { + base = base[1:] + } else { + base = base[2:] + } + + return base +} + +func CompactHexDecode(str string) []int { + base := "0123456789abcdef" + hexSlice := make([]int, 0) + + enc := hex.EncodeToString([]byte(str)) + for _, v := range enc { + hexSlice = append(hexSlice, strings.IndexByte(base, byte(v))) + } + hexSlice = append(hexSlice, 16) + + return hexSlice +} diff --git a/ethutil/encoding_test.go b/ethutil/encoding_test.go new file mode 100644 index 000000000..bcabab0b1 --- /dev/null +++ b/ethutil/encoding_test.go @@ -0,0 +1,37 @@ +package ethutil + +import ( + "fmt" + "testing" +) + +func TestCompactEncode(t *testing.T) { + test1 := []int{1, 2, 3, 4, 5} + if res := CompactEncode(test1); res != "\x11\x23\x45" { + t.Error(fmt.Sprintf("even compact encode failed. Got: %q", res)) + } + + test2 := []int{0, 1, 2, 3, 4, 5} + if res := CompactEncode(test2); res != "\x00\x01\x23\x45" { + t.Error(fmt.Sprintf("odd compact encode failed. Got: %q", res)) + } + + test3 := []int{0, 15, 1, 12, 11, 8 /*term*/, 16} + if res := CompactEncode(test3); res != "\x20\x0f\x1c\xb8" { + t.Error(fmt.Sprintf("odd terminated compact encode failed. Got: %q", res)) + } + + test4 := []int{15, 1, 12, 11, 8 /*term*/, 16} + if res := CompactEncode(test4); res != "\x3f\x1c\xb8" { + t.Error(fmt.Sprintf("even terminated compact encode failed. Got: %q", res)) + } +} + +func TestCompactHexDecode(t *testing.T) { + exp := []int{7, 6, 6, 5, 7, 2, 6, 2, 16} + res := CompactHexDecode("verb") + + if !CompareIntSlice(res, exp) { + t.Error("Error compact hex decode. Expected", exp, "got", res) + } +} diff --git a/ethutil/helpers.go b/ethutil/helpers.go new file mode 100644 index 000000000..1c6adf256 --- /dev/null +++ b/ethutil/helpers.go @@ -0,0 +1,61 @@ +package ethutil + +import ( + "code.google.com/p/go.crypto/ripemd160" + "crypto/sha256" + "encoding/hex" + "github.com/obscuren/sha3" + "strconv" +) + +func Uitoa(i uint32) string { + return strconv.FormatUint(uint64(i), 10) +} + +func Sha256Bin(data []byte) []byte { + hash := sha256.Sum256(data) + + return hash[:] +} + +func Ripemd160(data []byte) []byte { + ripemd := ripemd160.New() + ripemd.Write(data) + + return ripemd.Sum(nil) +} + +func Sha3Bin(data []byte) []byte { + d := sha3.NewKeccak256() + d.Reset() + d.Write(data) + + return d.Sum(nil) +} + +// Helper function for comparing slices +func CompareIntSlice(a, b []int) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} + +// Returns the amount of nibbles that match each other from 0 ... +func MatchingNibbleLength(a, b []int) int { + i := 0 + for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { + i += 1 + } + + return i +} + +func Hex(d []byte) string { + return hex.EncodeToString(d) +} diff --git a/ethutil/parsing.go b/ethutil/parsing.go new file mode 100644 index 000000000..2c41fb4df --- /dev/null +++ b/ethutil/parsing.go @@ -0,0 +1,108 @@ +package ethutil + +import ( + "errors" + "fmt" + "math/big" + "strconv" + "strings" +) + +// Op codes +var OpCodes = map[string]string{ + "STOP": "0", + "ADD": "1", + "MUL": "2", + "SUB": "3", + "DIV": "4", + "SDIV": "5", + "MOD": "6", + "SMOD": "7", + "EXP": "8", + "NEG": "9", + "LT": "10", + "LE": "11", + "GT": "12", + "GE": "13", + "EQ": "14", + "NOT": "15", + "MYADDRESS": "16", + "TXSENDER": "17", + + "PUSH": "48", + "POP": "49", + "LOAD": "54", +} + +func CompileInstr(s string) (string, error) { + tokens := strings.Split(s, " ") + if OpCodes[tokens[0]] == "" { + return s, errors.New(fmt.Sprintf("OP not found: %s", tokens[0])) + } + + code := OpCodes[tokens[0]] // Replace op codes with the proper numerical equivalent + op := new(big.Int) + op.SetString(code, 0) + + args := make([]*big.Int, 6) + for i, val := range tokens[1:len(tokens)] { + num := new(big.Int) + num.SetString(val, 0) + args[i] = num + } + + // Big int equation = op + x * 256 + y * 256**2 + z * 256**3 + a * 256**4 + b * 256**5 + c * 256**6 + base := new(big.Int) + x := new(big.Int) + y := new(big.Int) + z := new(big.Int) + a := new(big.Int) + b := new(big.Int) + c := new(big.Int) + + if args[0] != nil { + x.Mul(args[0], big.NewInt(256)) + } + if args[1] != nil { + y.Mul(args[1], BigPow(256, 2)) + } + if args[2] != nil { + z.Mul(args[2], BigPow(256, 3)) + } + if args[3] != nil { + a.Mul(args[3], BigPow(256, 4)) + } + if args[4] != nil { + b.Mul(args[4], BigPow(256, 5)) + } + if args[5] != nil { + c.Mul(args[5], BigPow(256, 6)) + } + + base.Add(op, x) + base.Add(base, y) + base.Add(base, z) + base.Add(base, a) + base.Add(base, b) + base.Add(base, c) + + return base.String(), nil +} + +func Instr(instr string) (int, []string, error) { + base := new(big.Int) + base.SetString(instr, 0) + + args := make([]string, 7) + for i := 0; i < 7; i++ { + // int(int(val) / int(math.Pow(256,float64(i)))) % 256 + exp := BigPow(256, i) + num := new(big.Int) + num.Div(base, exp) + + args[i] = num.Mod(num, big.NewInt(256)).String() + } + op, _ := strconv.Atoi(args[0]) + + return op, args[1:7], nil +} diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go new file mode 100644 index 000000000..482eef3ee --- /dev/null +++ b/ethutil/parsing_test.go @@ -0,0 +1,32 @@ +package ethutil + +import ( + "math" + "testing" +) + +func TestCompile(t *testing.T) { + instr, err := CompileInstr("PUSH") + + if err != nil { + t.Error("Failed compiling instruction") + } + + calc := (48 + 0*256 + 0*int64(math.Pow(256, 2))) + if Big(instr).Int64() != calc { + t.Error("Expected", calc, ", got:", instr) + } +} + +func TestValidInstr(t *testing.T) { + /* + op, args, err := Instr("68163") + if err != nil { + t.Error("Error decoding instruction") + } + */ + +} + +func TestInvalidInstr(t *testing.T) { +} diff --git a/ethutil/rand.go b/ethutil/rand.go new file mode 100644 index 000000000..91dafec7e --- /dev/null +++ b/ethutil/rand.go @@ -0,0 +1,24 @@ +package ethutil + +import ( + "crypto/rand" + "encoding/binary" + "io" +) + +func randomUint64(r io.Reader) (uint64, error) { + b := make([]byte, 8) + n, err := r.Read(b) + if n != len(b) { + return 0, io.ErrShortBuffer + } + if err != nil { + return 0, err + } + return binary.BigEndian.Uint64(b), nil +} + +// RandomUint64 returns a cryptographically random uint64 value. +func RandomUint64() (uint64, error) { + return randomUint64(rand.Reader) +} diff --git a/ethutil/rlp.go b/ethutil/rlp.go new file mode 100644 index 000000000..0f88933b3 --- /dev/null +++ b/ethutil/rlp.go @@ -0,0 +1,418 @@ +package ethutil + +import ( + "bytes" + _ "encoding/binary" + "fmt" + _ "log" + _ "math" + "math/big" + "reflect" +) + +/////////////////////////////////////// +type EthEncoder interface { + EncodeData(rlpData interface{}) []byte +} +type EthDecoder interface { + Get(idx int) *RlpValue +} + +////////////////////////////////////// + +type RlpEncoder struct { + rlpData []byte +} + +func NewRlpEncoder() *RlpEncoder { + encoder := &RlpEncoder{} + + return encoder +} +func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { + return Encode(rlpData) +} + +// Data rlpValueutes are returned by the rlp decoder. The data rlpValueutes represents +// one item within the rlp data structure. It's responsible for all the casting +// It always returns something rlpValueid +type RlpValue struct { + Value interface{} + kind reflect.Value +} + +func (rlpValue *RlpValue) String() string { + return fmt.Sprintf("%q", rlpValue.Value) +} + +func Conv(rlpValue interface{}) *RlpValue { + return &RlpValue{Value: rlpValue, kind: reflect.ValueOf(rlpValue)} +} + +func NewRlpValue(rlpValue interface{}) *RlpValue { + return &RlpValue{Value: rlpValue} +} + +func (rlpValue *RlpValue) Type() reflect.Kind { + return reflect.TypeOf(rlpValue.Value).Kind() +} + +func (rlpValue *RlpValue) IsNil() bool { + return rlpValue.Value == nil +} + +func (rlpValue *RlpValue) Length() int { + //return rlpValue.kind.Len() + if data, ok := rlpValue.Value.([]interface{}); ok { + return len(data) + } + + return 0 +} + +func (rlpValue *RlpValue) AsRaw() interface{} { + return rlpValue.Value +} + +func (rlpValue *RlpValue) AsUint() uint64 { + if Value, ok := rlpValue.Value.(uint8); ok { + return uint64(Value) + } else if Value, ok := rlpValue.Value.(uint16); ok { + return uint64(Value) + } else if Value, ok := rlpValue.Value.(uint32); ok { + return uint64(Value) + } else if Value, ok := rlpValue.Value.(uint64); ok { + return Value + } + + return 0 +} + +func (rlpValue *RlpValue) AsByte() byte { + if Value, ok := rlpValue.Value.(byte); ok { + return Value + } + + return 0x0 +} + +func (rlpValue *RlpValue) AsBigInt() *big.Int { + if a, ok := rlpValue.Value.([]byte); ok { + b := new(big.Int) + b.SetBytes(a) + return b + } + + return big.NewInt(0) +} + +func (rlpValue *RlpValue) AsString() string { + if a, ok := rlpValue.Value.([]byte); ok { + return string(a) + } else if a, ok := rlpValue.Value.(string); ok { + return a + } else { + //panic(fmt.Sprintf("not string %T: %v", rlpValue.Value, rlpValue.Value)) + } + + return "" +} + +func (rlpValue *RlpValue) AsBytes() []byte { + if a, ok := rlpValue.Value.([]byte); ok { + return a + } + + return make([]byte, 0) +} + +func (rlpValue *RlpValue) AsSlice() []interface{} { + if d, ok := rlpValue.Value.([]interface{}); ok { + return d + } + + return []interface{}{} +} + +func (rlpValue *RlpValue) AsSliceFrom(from int) *RlpValue { + slice := rlpValue.AsSlice() + + return NewRlpValue(slice[from:]) +} + +func (rlpValue *RlpValue) AsSliceTo(to int) *RlpValue { + slice := rlpValue.AsSlice() + + return NewRlpValue(slice[:to]) +} + +func (rlpValue *RlpValue) AsSliceFromTo(from, to int) *RlpValue { + slice := rlpValue.AsSlice() + + return NewRlpValue(slice[from:to]) +} + +// Threat the rlpValueute as a slice +func (rlpValue *RlpValue) Get(idx int) *RlpValue { + if d, ok := rlpValue.Value.([]interface{}); ok { + // Guard for oob + if len(d) <= idx { + return NewRlpValue(nil) + } + + if idx < 0 { + panic("negative idx for Rlp Get") + } + + return NewRlpValue(d[idx]) + } + + // If this wasn't a slice you probably shouldn't be using this function + return NewRlpValue(nil) +} + +func (rlpValue *RlpValue) Cmp(o *RlpValue) bool { + return reflect.DeepEqual(rlpValue.Value, o.Value) +} + +func (rlpValue *RlpValue) Encode() []byte { + return Encode(rlpValue.Value) +} + +func NewRlpValueFromBytes(rlpData []byte) *RlpValue { + if len(rlpData) != 0 { + data, _ := Decode(rlpData, 0) + return NewRlpValue(data) + } + + return NewRlpValue(nil) +} + +// RlpValue value setters +// An empty rlp value is always a list +func EmptyRlpValue() *RlpValue { + return NewRlpValue([]interface{}{}) +} + +func (rlpValue *RlpValue) AppendList() *RlpValue { + list := EmptyRlpValue() + rlpValue.Value = append(rlpValue.AsSlice(), list) + + return list +} + +func (rlpValue *RlpValue) Append(v interface{}) *RlpValue { + rlpValue.Value = append(rlpValue.AsSlice(), v) + + return rlpValue +} + +/* +func FromBin(data []byte) uint64 { + if len(data) == 0 { + return 0 + } + + return FromBin(data[:len(data)-1])*256 + uint64(data[len(data)-1]) +} +*/ + +const ( + RlpEmptyList = 0x80 + RlpEmptyStr = 0x40 +) + +func Char(c []byte) int { + if len(c) > 0 { + return int(c[0]) + } + + return 0 +} + +func DecodeWithReader(reader *bytes.Buffer) interface{} { + var slice []interface{} + + // Read the next byte + char := Char(reader.Next(1)) + switch { + case char == 0: + return nil + case char <= 0x7c: + return char + + case char <= 0xb7: + return reader.Next(int(char - 0x80)) + + case char <= 0xbf: + buff := bytes.NewReader(reader.Next(int(char - 0xb8))) + length := ReadVarint(buff) + + return reader.Next(int(length)) + + case char <= 0xf7: + length := int(char - 0xc0) + for i := 0; i < length; i++ { + obj := DecodeWithReader(reader) + if obj != nil { + slice = append(slice, obj) + } else { + break + } + } + + return slice + + } + + return slice +} + +// TODO Use a bytes.Buffer instead of a raw byte slice. +// Cleaner code, and use draining instead of seeking the next bytes to read +func Decode(data []byte, pos uint64) (interface{}, uint64) { + /* + if pos > uint64(len(data)-1) { + log.Println(data) + log.Panicf("index out of range %d for data %q, l = %d", pos, data, len(data)) + } + */ + + var slice []interface{} + char := int(data[pos]) + switch { + case char <= 0x7f: + return data[pos], pos + 1 + + case char <= 0xb7: + b := uint64(data[pos]) - 0x80 + + return data[pos+1 : pos+1+b], pos + 1 + b + + case char <= 0xbf: + b := uint64(data[pos]) - 0xb7 + + b2 := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+b])) + + return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 + + case char <= 0xf7: + b := uint64(data[pos]) - 0xc0 + prevPos := pos + pos++ + for i := uint64(0); i < b; { + var obj interface{} + + // Get the next item in the data list and append it + obj, prevPos = Decode(data, pos) + slice = append(slice, obj) + + // Increment i by the amount bytes read in the previous + // read + i += (prevPos - pos) + pos = prevPos + } + return slice, pos + + case char <= 0xff: + l := uint64(data[pos]) - 0xf7 + //b := BigD(data[pos+1 : pos+1+l]).Uint64() + b := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+l])) + + pos = pos + l + 1 + + prevPos := b + for i := uint64(0); i < uint64(b); { + var obj interface{} + + obj, prevPos = Decode(data, pos) + slice = append(slice, obj) + + i += (prevPos - pos) + pos = prevPos + } + return slice, pos + + default: + panic(fmt.Sprintf("byte not supported: %q", char)) + } + + return slice, 0 +} + +var ( + directRlp = big.NewInt(0x7f) + numberRlp = big.NewInt(0xb7) + zeroRlp = big.NewInt(0x0) +) + +func Encode(object interface{}) []byte { + var buff bytes.Buffer + + if object != nil { + switch t := object.(type) { + case *RlpValue: + buff.Write(Encode(t.AsRaw())) + // Code dup :-/ + case int: + buff.Write(Encode(big.NewInt(int64(t)))) + case uint: + buff.Write(Encode(big.NewInt(int64(t)))) + case int8: + buff.Write(Encode(big.NewInt(int64(t)))) + case int16: + buff.Write(Encode(big.NewInt(int64(t)))) + case int32: + buff.Write(Encode(big.NewInt(int64(t)))) + case int64: + buff.Write(Encode(big.NewInt(t))) + case uint16: + buff.Write(Encode(big.NewInt(int64(t)))) + case uint32: + buff.Write(Encode(big.NewInt(int64(t)))) + case uint64: + buff.Write(Encode(big.NewInt(int64(t)))) + case byte: + buff.Write(Encode(big.NewInt(int64(t)))) + case *big.Int: + buff.Write(Encode(t.Bytes())) + case []byte: + if len(t) == 1 && t[0] <= 0x7f { + buff.Write(t) + } else if len(t) < 56 { + buff.WriteByte(byte(len(t) + 0x80)) + buff.Write(t) + } else { + b := big.NewInt(int64(len(t))) + buff.WriteByte(byte(len(b.Bytes()) + 0xb7)) + buff.Write(b.Bytes()) + buff.Write(t) + } + case string: + buff.Write(Encode([]byte(t))) + case []interface{}: + // Inline function for writing the slice header + WriteSliceHeader := func(length int) { + if length < 56 { + buff.WriteByte(byte(length + 0xc0)) + } else { + b := big.NewInt(int64(length)) + buff.WriteByte(byte(len(b.Bytes()) + 0xf7)) + buff.Write(b.Bytes()) + } + } + + var b bytes.Buffer + for _, val := range t { + b.Write(Encode(val)) + } + WriteSliceHeader(len(b.Bytes())) + buff.Write(b.Bytes()) + } + } else { + // Empty list for nil + buff.WriteByte(0xc0) + } + + return buff.Bytes() +} diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go new file mode 100644 index 000000000..32bcbdce1 --- /dev/null +++ b/ethutil/rlp_test.go @@ -0,0 +1,170 @@ +package ethutil + +import ( + "bytes" + "encoding/hex" + "fmt" + "math/big" + "reflect" + "testing" +) + +func TestRlpValueEncoding(t *testing.T) { + val := EmptyRlpValue() + val.AppendList().Append(1).Append(2).Append(3) + val.Append("4").AppendList().Append(5) + + res := val.Encode() + exp := Encode([]interface{}{[]interface{}{1, 2, 3}, "4", []interface{}{5}}) + if bytes.Compare(res, exp) != 0 { + t.Errorf("expected %q, got %q", res, exp) + } +} + +func TestValueSlice(t *testing.T) { + val := []interface{}{ + "value1", + "valeu2", + "value3", + } + + value := NewValue(val) + splitVal := value.SliceFrom(1) + + if splitVal.Len() != 2 { + t.Error("SliceFrom: Expected len", 2, "got", splitVal.Len()) + } + + splitVal = value.SliceTo(2) + if splitVal.Len() != 2 { + t.Error("SliceTo: Expected len", 2, "got", splitVal.Len()) + } + + splitVal = value.SliceFromTo(1, 3) + if splitVal.Len() != 2 { + t.Error("SliceFromTo: Expected len", 2, "got", splitVal.Len()) + } +} + +func TestValue(t *testing.T) { + value := NewValueFromBytes([]byte("\xcd\x83dog\x83god\x83cat\x01")) + if value.Get(0).Str() != "dog" { + t.Errorf("expected '%v', got '%v'", value.Get(0).Str(), "dog") + } + + if value.Get(3).Uint() != 1 { + t.Errorf("expected '%v', got '%v'", value.Get(3).Uint(), 1) + } +} + +func TestEncode(t *testing.T) { + strRes := "\x83dog" + bytes := Encode("dog") + + str := string(bytes) + if str != strRes { + t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str)) + } + + sliceRes := "\xcc\x83dog\x83god\x83cat" + strs := []interface{}{"dog", "god", "cat"} + bytes = Encode(strs) + slice := string(bytes) + if slice != sliceRes { + t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice)) + } + + intRes := "\x82\x04\x00" + bytes = Encode(1024) + if string(bytes) != intRes { + t.Errorf("Expected %q, got %q", intRes, bytes) + } +} + +func TestDecode(t *testing.T) { + single := []byte("\x01") + b, _ := Decode(single, 0) + + if b.(uint8) != 1 { + t.Errorf("Expected 1, got %q", b) + } + + str := []byte("\x83dog") + b, _ = Decode(str, 0) + if bytes.Compare(b.([]byte), []byte("dog")) != 0 { + t.Errorf("Expected dog, got %q", b) + } + + slice := []byte("\xcc\x83dog\x83god\x83cat") + res := []interface{}{"dog", "god", "cat"} + b, _ = Decode(slice, 0) + if reflect.DeepEqual(b, res) { + t.Errorf("Expected %q, got %q", res, b) + } +} + +func TestEncodeDecodeBigInt(t *testing.T) { + bigInt := big.NewInt(1391787038) + encoded := Encode(bigInt) + + value := NewValueFromBytes(encoded) + fmt.Println(value.BigInt(), bigInt) + if value.BigInt().Cmp(bigInt) != 0 { + t.Errorf("Expected %v, got %v", bigInt, value.BigInt()) + } + + dec, _ := hex.DecodeString("52f4fc1e") + fmt.Println(NewValueFromBytes(dec).BigInt()) +} + +func TestEncodeDecodeBytes(t *testing.T) { + b := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, byte(6)}) + val := NewValueFromBytes(b.Encode()) + if !b.Cmp(val) { + t.Errorf("Expected %v, got %v", val, b) + } +} + +/* +var ZeroHash256 = make([]byte, 32) +var ZeroHash160 = make([]byte, 20) +var EmptyShaList = Sha3Bin(Encode([]interface{}{})) + +var GenisisHeader = []interface{}{ + // Previous hash (none) + //"", + ZeroHash256, + // Sha of uncles + Sha3Bin(Encode([]interface{}{})), + // Coinbase + ZeroHash160, + // Root state + "", + // Sha of transactions + //EmptyShaList, + Sha3Bin(Encode([]interface{}{})), + // Difficulty + BigPow(2, 22), + // Time + //big.NewInt(0), + int64(0), + // extra + "", + // Nonce + big.NewInt(42), +} + +func TestEnc(t *testing.T) { + //enc := Encode(GenisisHeader) + //fmt.Printf("%x (%d)\n", enc, len(enc)) + h, _ := hex.DecodeString("f8a0a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06d076baa9c4074fb2df222dd16a96b0155a1e6686b3e5748b4e9ca0a208a425ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493478340000080802a") + fmt.Printf("%x\n", Sha3Bin(h)) +} +*/ + +func BenchmarkEncodeDecode(b *testing.B) { + for i := 0; i < b.N; i++ { + bytes := Encode([]interface{}{"dog", "god", "cat"}) + Decode(bytes, 0) + } +} diff --git a/ethutil/trie.go b/ethutil/trie.go new file mode 100644 index 000000000..44d2d5774 --- /dev/null +++ b/ethutil/trie.go @@ -0,0 +1,354 @@ +package ethutil + +import ( + "fmt" + "reflect" +) + +type Node struct { + Key []byte + Value *Value + Dirty bool +} + +func NewNode(key []byte, val *Value, dirty bool) *Node { + return &Node{Key: key, Value: val, Dirty: dirty} +} + +func (n *Node) Copy() *Node { + return NewNode(n.Key, n.Value, n.Dirty) +} + +type Cache struct { + nodes map[string]*Node + db Database +} + +func NewCache(db Database) *Cache { + return &Cache{db: db, nodes: make(map[string]*Node)} +} + +func (cache *Cache) Put(v interface{}) interface{} { + value := NewValue(v) + + enc := value.Encode() + if len(enc) >= 32 { + sha := Sha3Bin(enc) + + cache.nodes[string(sha)] = NewNode(sha, value, true) + + return sha + } + + return v +} + +func (cache *Cache) Get(key []byte) *Value { + // First check if the key is the cache + if cache.nodes[string(key)] != nil { + return cache.nodes[string(key)].Value + } + + // Get the key of the database instead and cache it + data, _ := cache.db.Get(key) + // Create the cached value + value := NewValueFromBytes(data) + // Create caching node + cache.nodes[string(key)] = NewNode(key, value, false) + + return value +} + +func (cache *Cache) Commit() { + for key, node := range cache.nodes { + if node.Dirty { + cache.db.Put([]byte(key), node.Value.Encode()) + node.Dirty = false + } + } + + // If the nodes grows beyond the 200 entries we simple empty it + // FIXME come up with something better + if len(cache.nodes) > 200 { + cache.nodes = make(map[string]*Node) + } +} + +func (cache *Cache) Undo() { + for key, node := range cache.nodes { + if node.Dirty { + delete(cache.nodes, key) + } + } +} + +// A (modified) Radix Trie implementation +type Trie struct { + Root interface{} + //db Database + cache *Cache +} + +func NewTrie(db Database, Root interface{}) *Trie { + return &Trie{cache: NewCache(db), Root: Root} +} + +func (t *Trie) Sync() { + t.cache.Commit() +} + +/* + * Public (query) interface functions + */ +func (t *Trie) Update(key string, value string) { + k := CompactHexDecode(key) + + t.Root = t.UpdateState(t.Root, k, value) +} + +func (t *Trie) Get(key string) string { + k := CompactHexDecode(key) + c := NewValue(t.GetState(t.Root, k)) + + return c.Str() +} + +func (t *Trie) GetState(node interface{}, key []int) interface{} { + n := NewValue(node) + // Return the node if key is empty (= found) + if len(key) == 0 || n.IsNil() || n.Len() == 0 { + return node + } + + currentNode := t.GetNode(node) + length := currentNode.Len() + + if length == 0 { + return "" + } else if length == 2 { + // Decode the key + k := CompactDecode(currentNode.Get(0).Str()) + v := currentNode.Get(1).Raw() + + if len(key) >= len(k) && CompareIntSlice(k, key[:len(k)]) { + return t.GetState(v, key[len(k):]) + } else { + return "" + } + } else if length == 17 { + return t.GetState(currentNode.Get(key[0]).Raw(), key[1:]) + } + + // It shouldn't come this far + fmt.Println("GetState unexpected return") + return "" +} + +func (t *Trie) GetNode(node interface{}) *Value { + n := NewValue(node) + + if !n.Get(0).IsNil() { + return n + } + + str := n.Str() + if len(str) == 0 { + return n + } else if len(str) < 32 { + return NewValueFromBytes([]byte(str)) + } + /* + else { + // Fetch the encoded node from the db + o, err := t.db.Get(n.Bytes()) + if err != nil { + fmt.Println("Error InsertState", err) + return NewValue("") + } + + return NewValueFromBytes(o) + } + */ + return t.cache.Get(n.Bytes()) + +} + +func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { + if value != "" { + return t.InsertState(node, key, value) + } else { + // delete it + } + + return "" +} + +func (t *Trie) Put(node interface{}) interface{} { + /* + enc := Encode(node) + if len(enc) >= 32 { + var sha []byte + sha = Sha3Bin(enc) + //t.db.Put([]byte(sha), enc) + + return sha + } + return node + */ + + /* + TODO? + c := Conv(t.Root) + fmt.Println(c.Type(), c.Length()) + if c.Type() == reflect.String && c.AsString() == "" { + return enc + } + */ + + return t.cache.Put(node) + +} + +func EmptyStringSlice(l int) []interface{} { + slice := make([]interface{}, l) + for i := 0; i < l; i++ { + slice[i] = "" + } + return slice +} + +func (t *Trie) InsertState(node interface{}, key []int, value interface{}) interface{} { + if len(key) == 0 { + return value + } + + // New node + n := NewValue(node) + if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { + newNode := []interface{}{CompactEncode(key), value} + + return t.Put(newNode) + } + + currentNode := t.GetNode(node) + // Check for "special" 2 slice type node + if currentNode.Len() == 2 { + // Decode the key + k := CompactDecode(currentNode.Get(0).Str()) + v := currentNode.Get(1).Raw() + + // Matching key pair (ie. there's already an object with this key) + if CompareIntSlice(k, key) { + newNode := []interface{}{CompactEncode(key), value} + return t.Put(newNode) + } + + var newHash interface{} + matchingLength := MatchingNibbleLength(key, k) + if matchingLength == len(k) { + // Insert the hash, creating a new node + newHash = t.InsertState(v, key[matchingLength:], value) + } else { + // Expand the 2 length slice to a 17 length slice + oldNode := t.InsertState("", k[matchingLength+1:], v) + newNode := t.InsertState("", key[matchingLength+1:], value) + // Create an expanded slice + scaledSlice := EmptyStringSlice(17) + // Set the copied and new node + scaledSlice[k[matchingLength]] = oldNode + scaledSlice[key[matchingLength]] = newNode + + newHash = t.Put(scaledSlice) + } + + if matchingLength == 0 { + // End of the chain, return + return newHash + } else { + newNode := []interface{}{CompactEncode(key[:matchingLength]), newHash} + return t.Put(newNode) + } + } else { + + // Copy the current node over to the new node and replace the first nibble in the key + newNode := EmptyStringSlice(17) + + for i := 0; i < 17; i++ { + cpy := currentNode.Get(i).Raw() + if cpy != nil { + newNode[i] = cpy + } + } + + newNode[key[0]] = t.InsertState(currentNode.Get(key[0]).Raw(), key[1:], value) + + return t.Put(newNode) + } + + return "" +} + +// Simple compare function which creates a rlp value out of the evaluated objects +func (t *Trie) Cmp(trie *Trie) bool { + return NewValue(t.Root).Cmp(NewValue(trie.Root)) +} + +// Returns a copy of this trie +func (t *Trie) Copy() *Trie { + trie := NewTrie(t.cache.db, t.Root) + for key, node := range t.cache.nodes { + trie.cache.nodes[key] = node.Copy() + } + + return trie +} + +/* + * Trie helper functions + */ +// Helper function for printing out the raw contents of a slice +func PrintSlice(slice []string) { + fmt.Printf("[") + for i, val := range slice { + fmt.Printf("%q", val) + if i != len(slice)-1 { + fmt.Printf(",") + } + } + fmt.Printf("]\n") +} + +func PrintSliceT(slice interface{}) { + c := Conv(slice) + for i := 0; i < c.Length(); i++ { + val := c.Get(i) + if val.Type() == reflect.Slice { + PrintSliceT(val.AsRaw()) + } else { + fmt.Printf("%q", val) + if i != c.Length()-1 { + fmt.Printf(",") + } + } + } +} + +// RLP Decodes a node in to a [2] or [17] string slice +func DecodeNode(data []byte) []string { + dec, _ := Decode(data, 0) + if slice, ok := dec.([]interface{}); ok { + strSlice := make([]string, len(slice)) + + for i, s := range slice { + if str, ok := s.([]byte); ok { + strSlice[i] = string(str) + } + } + + return strSlice + } else { + fmt.Printf("It wasn't a []. It's a %T\n", dec) + } + + return nil +} diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go new file mode 100644 index 000000000..b87d35e1a --- /dev/null +++ b/ethutil/trie_test.go @@ -0,0 +1,40 @@ +package ethutil + +import ( + _ "encoding/hex" + _ "fmt" + "testing" +) + +type MemDatabase struct { + db map[string][]byte +} + +func NewMemDatabase() (*MemDatabase, error) { + db := &MemDatabase{db: make(map[string][]byte)} + return db, nil +} +func (db *MemDatabase) Put(key []byte, value []byte) { + db.db[string(key)] = value +} +func (db *MemDatabase) Get(key []byte) ([]byte, error) { + return db.db[string(key)], nil +} +func (db *MemDatabase) Print() {} +func (db *MemDatabase) Close() {} +func (db *MemDatabase) LastKnownTD() []byte { return nil } + +func TestTrieSync(t *testing.T) { + db, _ := NewMemDatabase() + trie := NewTrie(db, "") + + trie.Update("dog", "kindofalongsentencewhichshouldbeencodedinitsentirety") + if len(db.db) != 0 { + t.Error("Expected no data in database") + } + + trie.Sync() + if len(db.db) == 0 { + t.Error("Expected data to be persisted") + } +} diff --git a/ethutil/value.go b/ethutil/value.go new file mode 100644 index 000000000..2a990783e --- /dev/null +++ b/ethutil/value.go @@ -0,0 +1,204 @@ +package ethutil + +import ( + "bytes" + "fmt" + "math/big" + "reflect" +) + +// Data values are returned by the rlp decoder. The data values represents +// one item within the rlp data structure. It's responsible for all the casting +// It always returns something valid +type Value struct { + Val interface{} + kind reflect.Value +} + +func (val *Value) String() string { + return fmt.Sprintf("%q", val.Val) +} + +func NewValue(val interface{}) *Value { + return &Value{Val: val} +} + +func (val *Value) Type() reflect.Kind { + return reflect.TypeOf(val.Val).Kind() +} + +func (val *Value) IsNil() bool { + return val.Val == nil +} + +func (val *Value) Len() int { + //return val.kind.Len() + if data, ok := val.Val.([]interface{}); ok { + return len(data) + } else if data, ok := val.Val.([]byte); ok { + // FIXME + return len(data) + } + + return 0 +} + +func (val *Value) Raw() interface{} { + return val.Val +} + +func (val *Value) Interface() interface{} { + return val.Val +} + +func (val *Value) Uint() uint64 { + if Val, ok := val.Val.(uint8); ok { + return uint64(Val) + } else if Val, ok := val.Val.(uint16); ok { + return uint64(Val) + } else if Val, ok := val.Val.(uint32); ok { + return uint64(Val) + } else if Val, ok := val.Val.(uint64); ok { + return Val + } else if Val, ok := val.Val.([]byte); ok { + return ReadVarint(bytes.NewReader(Val)) + } + + return 0 +} + +func (val *Value) Byte() byte { + if Val, ok := val.Val.(byte); ok { + return Val + } + + return 0x0 +} + +func (val *Value) BigInt() *big.Int { + if a, ok := val.Val.([]byte); ok { + b := new(big.Int).SetBytes(a) + + return b + } else { + return big.NewInt(int64(val.Uint())) + } + + return big.NewInt(0) +} + +func (val *Value) Str() string { + if a, ok := val.Val.([]byte); ok { + return string(a) + } else if a, ok := val.Val.(string); ok { + return a + } + + return "" +} + +func (val *Value) Bytes() []byte { + if a, ok := val.Val.([]byte); ok { + return a + } + + return make([]byte, 0) +} + +func (val *Value) Slice() []interface{} { + if d, ok := val.Val.([]interface{}); ok { + return d + } + + return []interface{}{} +} + +func (val *Value) SliceFrom(from int) *Value { + slice := val.Slice() + + return NewValue(slice[from:]) +} + +func (val *Value) SliceTo(to int) *Value { + slice := val.Slice() + + return NewValue(slice[:to]) +} + +func (val *Value) SliceFromTo(from, to int) *Value { + slice := val.Slice() + + return NewValue(slice[from:to]) +} + +// Threat the value as a slice +func (val *Value) Get(idx int) *Value { + if d, ok := val.Val.([]interface{}); ok { + // Guard for oob + if len(d) <= idx { + return NewValue(nil) + } + + if idx < 0 { + panic("negative idx for Rlp Get") + } + + return NewValue(d[idx]) + } + + // If this wasn't a slice you probably shouldn't be using this function + return NewValue(nil) +} + +func (val *Value) Cmp(o *Value) bool { + return reflect.DeepEqual(val.Val, o.Val) +} + +func (val *Value) Encode() []byte { + return Encode(val.Val) +} + +func NewValueFromBytes(rlpData []byte) *Value { + if len(rlpData) != 0 { + data, _ := Decode(rlpData, 0) + return NewValue(data) + } + + return NewValue(nil) +} + +// Value setters +func NewSliceValue(s interface{}) *Value { + list := EmptyValue() + + if s != nil { + if slice, ok := s.([]interface{}); ok { + for _, val := range slice { + list.Append(val) + } + } else if slice, ok := s.([]string); ok { + for _, val := range slice { + list.Append(val) + } + } + } + + return list +} + +func EmptyValue() *Value { + return NewValue([]interface{}{}) +} + +func (val *Value) AppendList() *Value { + list := EmptyValue() + val.Val = append(val.Slice(), list) + + return list +} + +func (val *Value) Append(v interface{}) *Value { + val.Val = append(val.Slice(), v) + + return val +} -- cgit v1.2.3 From 73fd358d940418b15dec850f50407bd2e504d88c Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 01:34:18 +0100 Subject: Removed RlpValue in favour of Value --- ethutil/rlp.go | 189 +------------------------------------------------------- ethutil/trie.go | 70 +++------------------ 2 files changed, 9 insertions(+), 250 deletions(-) (limited to 'ethutil') diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 0f88933b3..025d269a0 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -7,19 +7,8 @@ import ( _ "log" _ "math" "math/big" - "reflect" ) -/////////////////////////////////////// -type EthEncoder interface { - EncodeData(rlpData interface{}) []byte -} -type EthDecoder interface { - Get(idx int) *RlpValue -} - -////////////////////////////////////// - type RlpEncoder struct { rlpData []byte } @@ -33,180 +22,6 @@ func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { return Encode(rlpData) } -// Data rlpValueutes are returned by the rlp decoder. The data rlpValueutes represents -// one item within the rlp data structure. It's responsible for all the casting -// It always returns something rlpValueid -type RlpValue struct { - Value interface{} - kind reflect.Value -} - -func (rlpValue *RlpValue) String() string { - return fmt.Sprintf("%q", rlpValue.Value) -} - -func Conv(rlpValue interface{}) *RlpValue { - return &RlpValue{Value: rlpValue, kind: reflect.ValueOf(rlpValue)} -} - -func NewRlpValue(rlpValue interface{}) *RlpValue { - return &RlpValue{Value: rlpValue} -} - -func (rlpValue *RlpValue) Type() reflect.Kind { - return reflect.TypeOf(rlpValue.Value).Kind() -} - -func (rlpValue *RlpValue) IsNil() bool { - return rlpValue.Value == nil -} - -func (rlpValue *RlpValue) Length() int { - //return rlpValue.kind.Len() - if data, ok := rlpValue.Value.([]interface{}); ok { - return len(data) - } - - return 0 -} - -func (rlpValue *RlpValue) AsRaw() interface{} { - return rlpValue.Value -} - -func (rlpValue *RlpValue) AsUint() uint64 { - if Value, ok := rlpValue.Value.(uint8); ok { - return uint64(Value) - } else if Value, ok := rlpValue.Value.(uint16); ok { - return uint64(Value) - } else if Value, ok := rlpValue.Value.(uint32); ok { - return uint64(Value) - } else if Value, ok := rlpValue.Value.(uint64); ok { - return Value - } - - return 0 -} - -func (rlpValue *RlpValue) AsByte() byte { - if Value, ok := rlpValue.Value.(byte); ok { - return Value - } - - return 0x0 -} - -func (rlpValue *RlpValue) AsBigInt() *big.Int { - if a, ok := rlpValue.Value.([]byte); ok { - b := new(big.Int) - b.SetBytes(a) - return b - } - - return big.NewInt(0) -} - -func (rlpValue *RlpValue) AsString() string { - if a, ok := rlpValue.Value.([]byte); ok { - return string(a) - } else if a, ok := rlpValue.Value.(string); ok { - return a - } else { - //panic(fmt.Sprintf("not string %T: %v", rlpValue.Value, rlpValue.Value)) - } - - return "" -} - -func (rlpValue *RlpValue) AsBytes() []byte { - if a, ok := rlpValue.Value.([]byte); ok { - return a - } - - return make([]byte, 0) -} - -func (rlpValue *RlpValue) AsSlice() []interface{} { - if d, ok := rlpValue.Value.([]interface{}); ok { - return d - } - - return []interface{}{} -} - -func (rlpValue *RlpValue) AsSliceFrom(from int) *RlpValue { - slice := rlpValue.AsSlice() - - return NewRlpValue(slice[from:]) -} - -func (rlpValue *RlpValue) AsSliceTo(to int) *RlpValue { - slice := rlpValue.AsSlice() - - return NewRlpValue(slice[:to]) -} - -func (rlpValue *RlpValue) AsSliceFromTo(from, to int) *RlpValue { - slice := rlpValue.AsSlice() - - return NewRlpValue(slice[from:to]) -} - -// Threat the rlpValueute as a slice -func (rlpValue *RlpValue) Get(idx int) *RlpValue { - if d, ok := rlpValue.Value.([]interface{}); ok { - // Guard for oob - if len(d) <= idx { - return NewRlpValue(nil) - } - - if idx < 0 { - panic("negative idx for Rlp Get") - } - - return NewRlpValue(d[idx]) - } - - // If this wasn't a slice you probably shouldn't be using this function - return NewRlpValue(nil) -} - -func (rlpValue *RlpValue) Cmp(o *RlpValue) bool { - return reflect.DeepEqual(rlpValue.Value, o.Value) -} - -func (rlpValue *RlpValue) Encode() []byte { - return Encode(rlpValue.Value) -} - -func NewRlpValueFromBytes(rlpData []byte) *RlpValue { - if len(rlpData) != 0 { - data, _ := Decode(rlpData, 0) - return NewRlpValue(data) - } - - return NewRlpValue(nil) -} - -// RlpValue value setters -// An empty rlp value is always a list -func EmptyRlpValue() *RlpValue { - return NewRlpValue([]interface{}{}) -} - -func (rlpValue *RlpValue) AppendList() *RlpValue { - list := EmptyRlpValue() - rlpValue.Value = append(rlpValue.AsSlice(), list) - - return list -} - -func (rlpValue *RlpValue) Append(v interface{}) *RlpValue { - rlpValue.Value = append(rlpValue.AsSlice(), v) - - return rlpValue -} - /* func FromBin(data []byte) uint64 { if len(data) == 0 { @@ -351,8 +166,8 @@ func Encode(object interface{}) []byte { if object != nil { switch t := object.(type) { - case *RlpValue: - buff.Write(Encode(t.AsRaw())) + case *Value: + buff.Write(Encode(t.Raw())) // Code dup :-/ case int: buff.Write(Encode(big.NewInt(int64(t)))) diff --git a/ethutil/trie.go b/ethutil/trie.go index 44d2d5774..0a3f73136 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -82,7 +82,12 @@ func (cache *Cache) Undo() { } } -// A (modified) Radix Trie implementation +// A (modified) Radix Trie implementation. The Trie implements +// a caching mechanism and will used cached values if they are +// present. If a node is not present in the cache it will try to +// fetch it from the database and store the cached value. +// Please note that the data isn't persisted unless `Sync` is +// explicitly called. type Trie struct { Root interface{} //db Database @@ -93,6 +98,7 @@ func NewTrie(db Database, Root interface{}) *Trie { return &Trie{cache: NewCache(db), Root: Root} } +// Save the cached value to the database. func (t *Trie) Sync() { t.cache.Commit() } @@ -157,20 +163,8 @@ func (t *Trie) GetNode(node interface{}) *Value { } else if len(str) < 32 { return NewValueFromBytes([]byte(str)) } - /* - else { - // Fetch the encoded node from the db - o, err := t.db.Get(n.Bytes()) - if err != nil { - fmt.Println("Error InsertState", err) - return NewValue("") - } - return NewValueFromBytes(o) - } - */ return t.cache.Get(n.Bytes()) - } func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { @@ -302,53 +296,3 @@ func (t *Trie) Copy() *Trie { return trie } - -/* - * Trie helper functions - */ -// Helper function for printing out the raw contents of a slice -func PrintSlice(slice []string) { - fmt.Printf("[") - for i, val := range slice { - fmt.Printf("%q", val) - if i != len(slice)-1 { - fmt.Printf(",") - } - } - fmt.Printf("]\n") -} - -func PrintSliceT(slice interface{}) { - c := Conv(slice) - for i := 0; i < c.Length(); i++ { - val := c.Get(i) - if val.Type() == reflect.Slice { - PrintSliceT(val.AsRaw()) - } else { - fmt.Printf("%q", val) - if i != c.Length()-1 { - fmt.Printf(",") - } - } - } -} - -// RLP Decodes a node in to a [2] or [17] string slice -func DecodeNode(data []byte) []string { - dec, _ := Decode(data, 0) - if slice, ok := dec.([]interface{}); ok { - strSlice := make([]string, len(slice)) - - for i, s := range slice { - if str, ok := s.([]byte); ok { - strSlice[i] = string(str) - } - } - - return strSlice - } else { - fmt.Printf("It wasn't a []. It's a %T\n", dec) - } - - return nil -} -- cgit v1.2.3 From fd1aa869e1544fd4d867b8f5a51985e01b692b0d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 11:52:28 +0100 Subject: Bumped version number --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 7782e7daa..2a239f8e2 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.2.1"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.2.2"} Config.Log = NewLogger(LogFile|LogStd, 0) } -- cgit v1.2.3 From 9bcb3d22168f5f02cd32ff23df60239156ddc899 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 12:40:19 +0100 Subject: Fixed test --- ethutil/rlp_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 32bcbdce1..2bddeec8f 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -10,7 +10,7 @@ import ( ) func TestRlpValueEncoding(t *testing.T) { - val := EmptyRlpValue() + val := EmptyValue() val.AppendList().Append(1).Append(2).Append(3) val.Append("4").AppendList().Append(5) -- cgit v1.2.3 From 5883446b219a2980d67ff604c7f227089e5c8619 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 12:41:17 +0100 Subject: Fixed test --- ethutil/rlp_test.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'ethutil') diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 2bddeec8f..54f929ebd 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,8 +2,6 @@ package ethutil import ( "bytes" - "encoding/hex" - "fmt" "math/big" "reflect" "testing" @@ -63,7 +61,7 @@ func TestEncode(t *testing.T) { str := string(bytes) if str != strRes { - t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str)) + t.Errorf("Expected %q, got %q", strRes, str) } sliceRes := "\xcc\x83dog\x83god\x83cat" @@ -71,7 +69,7 @@ func TestEncode(t *testing.T) { bytes = Encode(strs) slice := string(bytes) if slice != sliceRes { - t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice)) + t.Error("Expected %q, got %q", sliceRes, slice) } intRes := "\x82\x04\x00" @@ -108,13 +106,9 @@ func TestEncodeDecodeBigInt(t *testing.T) { encoded := Encode(bigInt) value := NewValueFromBytes(encoded) - fmt.Println(value.BigInt(), bigInt) if value.BigInt().Cmp(bigInt) != 0 { t.Errorf("Expected %v, got %v", bigInt, value.BigInt()) } - - dec, _ := hex.DecodeString("52f4fc1e") - fmt.Println(NewValueFromBytes(dec).BigInt()) } func TestEncodeDecodeBytes(t *testing.T) { -- cgit v1.2.3 From 07c12f0b921a05aec668ae8ce63b6dfac51d76a6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 13:21:11 +0100 Subject: Added trie tests, value tests --- ethutil/trie_test.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++--- ethutil/value.go | 4 ++++ ethutil/value_test.go | 38 ++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 ethutil/value_test.go (limited to 'ethutil') diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index b87d35e1a..94414b82e 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -6,6 +6,8 @@ import ( "testing" ) +const LONG_WORD = "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ" + type MemDatabase struct { db map[string][]byte } @@ -24,11 +26,15 @@ func (db *MemDatabase) Print() {} func (db *MemDatabase) Close() {} func (db *MemDatabase) LastKnownTD() []byte { return nil } -func TestTrieSync(t *testing.T) { +func New() (*MemDatabase, *Trie) { db, _ := NewMemDatabase() - trie := NewTrie(db, "") + return db, NewTrie(db, "") +} - trie.Update("dog", "kindofalongsentencewhichshouldbeencodedinitsentirety") +func TestTrieSync(t *testing.T) { + db, trie := New() + + trie.Update("dog", LONG_WORD) if len(db.db) != 0 { t.Error("Expected no data in database") } @@ -38,3 +44,55 @@ func TestTrieSync(t *testing.T) { t.Error("Expected data to be persisted") } } + +func TestTrieReset(t *testing.T) { + _, trie := New() + + trie.Update("cat", LONG_WORD) + if len(trie.cache.nodes) == 0 { + t.Error("Expected cached nodes") + } + + trie.cache.Undo() + + if len(trie.cache.nodes) != 0 { + t.Error("Expected no nodes after undo") + } +} + +func TestTrieGet(t *testing.T) { + _, trie := New() + + trie.Update("cat", LONG_WORD) + x := trie.Get("cat") + if x != LONG_WORD { + t.Error("expected %s, got %s", LONG_WORD, x) + } +} + +func TestTrieUpdating(t *testing.T) { + _, trie := New() + trie.Update("cat", LONG_WORD) + trie.Update("cat", LONG_WORD+"1") + x := trie.Get("cat") + if x != LONG_WORD+"1" { + t.Error("expected %S, got %s", LONG_WORD+"1", x) + } +} + +func TestTrieCmp(t *testing.T) { + _, trie1 := New() + _, trie2 := New() + + trie1.Update("doge", LONG_WORD) + trie2.Update("doge", LONG_WORD) + if !trie1.Cmp(trie2) { + t.Error("Expected tries to be equal") + } + + trie1.Update("dog", LONG_WORD) + trie2.Update("cat", LONG_WORD) + if trie1.Cmp(trie2) { + t.Errorf("Expected tries not to be equal %x %x", trie1.Root, trie2.Root) + } +} diff --git a/ethutil/value.go b/ethutil/value.go index 2a990783e..f91c33983 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -60,6 +60,10 @@ func (val *Value) Uint() uint64 { return uint64(Val) } else if Val, ok := val.Val.(uint64); ok { return 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 ReadVarint(bytes.NewReader(Val)) } diff --git a/ethutil/value_test.go b/ethutil/value_test.go new file mode 100644 index 000000000..7d41eb1c9 --- /dev/null +++ b/ethutil/value_test.go @@ -0,0 +1,38 @@ +package ethutil + +import ( + "testing" +) + +func TestValueCmp(t *testing.T) { + val1 := NewValue("hello") + val2 := NewValue("world") + if val1.Cmp(val2) { + t.Error("Expected values not to be equal") + } + + val3 := NewValue("hello") + val4 := NewValue("hello") + if !val3.Cmp(val4) { + t.Error("Expected values to be equal") + } +} + +func TestValueTypes(t *testing.T) { + str := NewValue("str") + num := NewValue(1) + inter := NewValue([]interface{}{1}) + + if str.Str() != "str" { + t.Errorf("expected Str to return 'str', got %s", str.Str()) + } + + if num.Uint() != 1 { + t.Errorf("expected Uint to return '1', got %d", num.Uint()) + } + + exp := []interface{}{1} + if !NewValue(inter.Interface()).Cmp(NewValue(exp)) { + t.Errorf("expected Interface to return '%v', got %v", exp, num.Interface()) + } +} -- cgit v1.2.3 From c95a27e39485eeeebd8608537115a4fd246c246c Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:30:33 +0100 Subject: Added more tests --- ethutil/value.go | 12 +++++++----- ethutil/value_test.go | 20 +++++++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index f91c33983..701ece5bb 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -84,6 +84,8 @@ func (val *Value) BigInt() *big.Int { b := new(big.Int).SetBytes(a) return b + } else if a, ok := val.Val.(*big.Int); ok { + return a } else { return big.NewInt(int64(val.Uint())) } @@ -106,7 +108,7 @@ func (val *Value) Bytes() []byte { return a } - return make([]byte, 0) + return []byte{} } func (val *Value) Slice() []interface{} { @@ -144,7 +146,7 @@ func (val *Value) Get(idx int) *Value { } if idx < 0 { - panic("negative idx for Rlp Get") + panic("negative idx for Value Get") } return NewValue(d[idx]) @@ -162,9 +164,9 @@ func (val *Value) Encode() []byte { return Encode(val.Val) } -func NewValueFromBytes(rlpData []byte) *Value { - if len(rlpData) != 0 { - data, _ := Decode(rlpData, 0) +func NewValueFromBytes(data []byte) *Value { + if len(data) != 0 { + data, _ := Decode(data, 0) return NewValue(data) } diff --git a/ethutil/value_test.go b/ethutil/value_test.go index 7d41eb1c9..0e2da5328 100644 --- a/ethutil/value_test.go +++ b/ethutil/value_test.go @@ -1,6 +1,8 @@ package ethutil import ( + "bytes" + "math/big" "testing" ) @@ -22,6 +24,8 @@ func TestValueTypes(t *testing.T) { str := NewValue("str") num := NewValue(1) inter := NewValue([]interface{}{1}) + byt := NewValue([]byte{1, 2, 3, 4}) + bigInt := NewValue(big.NewInt(10)) if str.Str() != "str" { t.Errorf("expected Str to return 'str', got %s", str.Str()) @@ -31,8 +35,18 @@ func TestValueTypes(t *testing.T) { t.Errorf("expected Uint to return '1', got %d", num.Uint()) } - exp := []interface{}{1} - if !NewValue(inter.Interface()).Cmp(NewValue(exp)) { - t.Errorf("expected Interface to return '%v', got %v", exp, num.Interface()) + interExp := []interface{}{1} + if !NewValue(inter.Interface()).Cmp(NewValue(interExp)) { + t.Errorf("expected Interface to return '%v', got %v", interExp, num.Interface()) + } + + bytExp := []byte{1, 2, 3, 4} + if bytes.Compare(byt.Bytes(), bytExp) != 0 { + t.Errorf("expected Bytes to return '%v', got %v", bytExp, byt.Bytes()) + } + + bigExp := big.NewInt(10) + if bigInt.BigInt().Cmp(bigExp) != 0 { + t.Errorf("expected BigInt to return '%v', got %v", bigExp, bigInt.BigInt()) } } -- cgit v1.2.3 From f1d6f1bd1793767a5596d4c277651e2264c1cf8e Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:30:50 +0100 Subject: Removed Reset --- ethutil/helpers.go | 1 - 1 file changed, 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/helpers.go b/ethutil/helpers.go index 1c6adf256..2e3aeb9a3 100644 --- a/ethutil/helpers.go +++ b/ethutil/helpers.go @@ -27,7 +27,6 @@ func Ripemd160(data []byte) []byte { func Sha3Bin(data []byte) []byte { d := sha3.NewKeccak256() - d.Reset() d.Write(data) return d.Sum(nil) -- cgit v1.2.3 From 7264044122d2ceef413667ad8473746a40a44782 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:31:02 +0100 Subject: Added a few tests --- ethutil/rlp_test.go | 37 ------------------------------------- 1 file changed, 37 deletions(-) (limited to 'ethutil') diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 54f929ebd..2a58bfc0f 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -119,43 +119,6 @@ func TestEncodeDecodeBytes(t *testing.T) { } } -/* -var ZeroHash256 = make([]byte, 32) -var ZeroHash160 = make([]byte, 20) -var EmptyShaList = Sha3Bin(Encode([]interface{}{})) - -var GenisisHeader = []interface{}{ - // Previous hash (none) - //"", - ZeroHash256, - // Sha of uncles - Sha3Bin(Encode([]interface{}{})), - // Coinbase - ZeroHash160, - // Root state - "", - // Sha of transactions - //EmptyShaList, - Sha3Bin(Encode([]interface{}{})), - // Difficulty - BigPow(2, 22), - // Time - //big.NewInt(0), - int64(0), - // extra - "", - // Nonce - big.NewInt(42), -} - -func TestEnc(t *testing.T) { - //enc := Encode(GenisisHeader) - //fmt.Printf("%x (%d)\n", enc, len(enc)) - h, _ := hex.DecodeString("f8a0a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06d076baa9c4074fb2df222dd16a96b0155a1e6686b3e5748b4e9ca0a208a425ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493478340000080802a") - fmt.Printf("%x\n", Sha3Bin(h)) -} -*/ - func BenchmarkEncodeDecode(b *testing.B) { for i := 0; i < b.N; i++ { bytes := Encode([]interface{}{"dog", "god", "cat"}) -- cgit v1.2.3 From e4a6ee3d7f8a3876387f837f6fec6822bd97951e Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:32:56 +0100 Subject: Added dirty tracking on the cache --- ethutil/trie.go | 17 +++++++++++++++-- ethutil/trie_test.go | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index 0a3f73136..7140a1b36 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -20,8 +20,9 @@ func (n *Node) Copy() *Node { } type Cache struct { - nodes map[string]*Node - db Database + nodes map[string]*Node + db Database + IsDirty bool } func NewCache(db Database) *Cache { @@ -36,6 +37,7 @@ func (cache *Cache) Put(v interface{}) interface{} { sha := Sha3Bin(enc) cache.nodes[string(sha)] = NewNode(sha, value, true) + cache.IsDirty = true return sha } @@ -60,12 +62,18 @@ func (cache *Cache) Get(key []byte) *Value { } func (cache *Cache) Commit() { + // Don't try to commit if it isn't dirty + if !cache.IsDirty { + return + } + for key, node := range cache.nodes { if node.Dirty { cache.db.Put([]byte(key), node.Value.Encode()) node.Dirty = false } } + cache.IsDirty = false // If the nodes grows beyond the 200 entries we simple empty it // FIXME come up with something better @@ -80,6 +88,7 @@ func (cache *Cache) Undo() { delete(cache.nodes, key) } } + cache.IsDirty = false } // A (modified) Radix Trie implementation. The Trie implements @@ -103,6 +112,10 @@ func (t *Trie) Sync() { t.cache.Commit() } +func (t *Trie) Undo() { + t.cache.Undo() +} + /* * Public (query) interface functions */ diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 94414b82e..fa60c8cfc 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -45,6 +45,26 @@ func TestTrieSync(t *testing.T) { } } +func TestTrieDirtyTracking(t *testing.T) { + _, trie := New() + trie.Update("dog", LONG_WORD) + if !trie.cache.IsDirty { + t.Error("Expected trie to be dirty") + } + + trie.Sync() + if trie.cache.IsDirty { + t.Error("Expected trie not to be dirty") + } + + trie.Update("test", LONG_WORD) + trie.cache.Undo() + if trie.cache.IsDirty { + t.Error("Expected trie not to be dirty") + } + +} + func TestTrieReset(t *testing.T) { _, trie := New() -- cgit v1.2.3 From b7a636b8949a2270ae030f56791c88060fa5483a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Feb 2014 20:29:54 +0100 Subject: Values should accept bytes as valid string output --- ethutil/value.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index 701ece5bb..d3a38f87f 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -98,6 +98,8 @@ func (val *Value) Str() string { 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 "" -- cgit v1.2.3 From 7413552a28c538ca4f33d0dafe28907b7b761863 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Feb 2014 20:40:33 +0100 Subject: Root should reset on undo --- ethutil/trie.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index 7140a1b36..95abca602 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -98,22 +98,25 @@ func (cache *Cache) Undo() { // Please note that the data isn't persisted unless `Sync` is // explicitly called. type Trie struct { - Root interface{} + prevRoot interface{} + Root interface{} //db Database cache *Cache } func NewTrie(db Database, Root interface{}) *Trie { - return &Trie{cache: NewCache(db), Root: Root} + return &Trie{cache: NewCache(db), Root: Root, prevRoot: Root} } // Save the cached value to the database. func (t *Trie) Sync() { t.cache.Commit() + t.prevRoot = t.Root } func (t *Trie) Undo() { t.cache.Undo() + t.Root = t.prevRoot } /* @@ -181,6 +184,7 @@ func (t *Trie) GetNode(node interface{}) *Value { } func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { + if value != "" { return t.InsertState(node, key, value) } else { @@ -241,6 +245,7 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter // Check for "special" 2 slice type node if currentNode.Len() == 2 { // Decode the key + k := CompactDecode(currentNode.Get(0).Str()) v := currentNode.Get(1).Raw() -- cgit v1.2.3 From e72a782bf0e0a0059e8dff83fa5fc80cc6f678e5 Mon Sep 17 00:00:00 2001 From: Joey Zhou Date: Mon, 17 Feb 2014 15:46:16 -0800 Subject: adding compact decode tests --- ethutil/encoding_test.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'ethutil') diff --git a/ethutil/encoding_test.go b/ethutil/encoding_test.go index bcabab0b1..cbfbc0eaf 100644 --- a/ethutil/encoding_test.go +++ b/ethutil/encoding_test.go @@ -35,3 +35,33 @@ func TestCompactHexDecode(t *testing.T) { t.Error("Error compact hex decode. Expected", exp, "got", res) } } + +func TestCompactDecode(t *testing.T) { + exp := []int{1, 2, 3, 4, 5} + res := CompactDecode("\x11\x23\x45") + + if !CompareIntSlice(res, exp) { + t.Error("odd compact decode. Expected", exp, "got", res) + } + + exp = []int{0, 1, 2, 3, 4, 5} + res = CompactDecode("\x00\x01\x23\x45") + + if !CompareIntSlice(res, exp) { + t.Error("even compact decode. Expected", exp, "got", res) + } + + exp = []int{0, 15, 1, 12, 11, 8 /*term*/, 16} + res = CompactDecode("\x20\x0f\x1c\xb8") + + if !CompareIntSlice(res, exp) { + t.Error("even terminated compact decode. Expected", exp, "got", res) + } + + exp = []int{15, 1, 12, 11, 8 /*term*/, 16} + res = CompactDecode("\x3f\x1c\xb8") + + if !CompareIntSlice(res, exp) { + t.Error("even terminated compact decode. Expected", exp, "got", res) + } +} \ No newline at end of file -- cgit v1.2.3 From c5b009ba6f153aa65fa25126bea41d899a436299 Mon Sep 17 00:00:00 2001 From: Joey Zhou Date: Mon, 17 Feb 2014 15:47:33 -0800 Subject: new line --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 2a239f8e2..b361a3079 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -38,7 +38,7 @@ func ReadConfig(base string) *config { _, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { - log.Printf("Debug logging directory %s doesn't exist, creating it", path) + log.Printf("Debug logging directory %s doesn't exist, creating it\n", path) os.Mkdir(path, 0777) } } -- cgit v1.2.3 From ba95849097f7a35d9f315a4f2e340d3ef944a306 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:32:20 +0100 Subject: Added hex method --- ethutil/helpers.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ethutil') diff --git a/ethutil/helpers.go b/ethutil/helpers.go index 2e3aeb9a3..11a474081 100644 --- a/ethutil/helpers.go +++ b/ethutil/helpers.go @@ -58,3 +58,7 @@ func MatchingNibbleLength(a, b []int) int { func Hex(d []byte) string { return hex.EncodeToString(d) } +func ToHex(str string) []byte { + h, _ := hex.DecodeString(str) + return h +} -- cgit v1.2.3 From d7eca7bcc12e940f0aa80d45e6e802ba68143b5c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:34:06 +0100 Subject: Rlp update --- ethutil/encoding.go | 3 +-- ethutil/rlp.go | 8 -------- 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'ethutil') diff --git a/ethutil/encoding.go b/ethutil/encoding.go index 207548c93..1f661947a 100644 --- a/ethutil/encoding.go +++ b/ethutil/encoding.go @@ -3,7 +3,6 @@ package ethutil import ( "bytes" "encoding/hex" - _ "fmt" "strings" ) @@ -36,7 +35,7 @@ func CompactEncode(hexSlice []int) string { func CompactDecode(str string) []int { base := CompactHexDecode(str) base = base[:len(base)-1] - if base[0] >= 2 { // && base[len(base)-1] != 16 { + if base[0] >= 2 { base = append(base, 16) } if base[0]%2 == 1 { diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 025d269a0..e633f5f1d 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -86,13 +86,6 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { // TODO Use a bytes.Buffer instead of a raw byte slice. // Cleaner code, and use draining instead of seeking the next bytes to read func Decode(data []byte, pos uint64) (interface{}, uint64) { - /* - if pos > uint64(len(data)-1) { - log.Println(data) - log.Panicf("index out of range %d for data %q, l = %d", pos, data, len(data)) - } - */ - var slice []interface{} char := int(data[pos]) switch { @@ -131,7 +124,6 @@ func Decode(data []byte, pos uint64) (interface{}, uint64) { case char <= 0xff: l := uint64(data[pos]) - 0xf7 - //b := BigD(data[pos+1 : pos+1+l]).Uint64() b := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+l])) pos = pos + l + 1 -- cgit v1.2.3 From c866fcc5b37b53e0d11c1fd7e6cb971859537f2c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 12:10:21 +0100 Subject: Added new address --- ethutil/config.go | 2 +- ethutil/helpers.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 2a239f8e2..df1772d81 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.2.2"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.2.3"} Config.Log = NewLogger(LogFile|LogStd, 0) } diff --git a/ethutil/helpers.go b/ethutil/helpers.go index 11a474081..aa0f79a04 100644 --- a/ethutil/helpers.go +++ b/ethutil/helpers.go @@ -58,7 +58,7 @@ func MatchingNibbleLength(a, b []int) int { func Hex(d []byte) string { return hex.EncodeToString(d) } -func ToHex(str string) []byte { +func FromHex(str string) []byte { h, _ := hex.DecodeString(str) return h } -- cgit v1.2.3 From 24f2b2afc3a848190822c382e6aa31c8ab120f07 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 11:35:17 +0100 Subject: Running contracts fixed --- ethutil/big.go | 6 ++++++ ethutil/config.go | 14 ++++++++------ ethutil/trie.go | 4 ++++ 3 files changed, 18 insertions(+), 6 deletions(-) (limited to 'ethutil') diff --git a/ethutil/big.go b/ethutil/big.go index 979078bef..c41d63add 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -35,3 +35,9 @@ func BigD(data []byte) *big.Int { return n } + +func BigToBytes(num *big.Int, base int) []byte { + ret := make([]byte, base/8) + + return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) +} diff --git a/ethutil/config.go b/ethutil/config.go index df1772d81..70553fb5b 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -34,12 +34,14 @@ func ReadConfig(base string) *config { usr, _ := user.Current() path := path.Join(usr.HomeDir, base) - //Check if the logging directory already exists, create it if not - _, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - log.Printf("Debug logging directory %s doesn't exist, creating it", path) - os.Mkdir(path, 0777) + if len(base) > 0 { + //Check if the logging directory already exists, create it if not + _, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + log.Printf("Debug logging directory %s doesn't exist, creating it", path) + os.Mkdir(path, 0777) + } } } diff --git a/ethutil/trie.go b/ethutil/trie.go index 95abca602..c25bd80cb 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -119,6 +119,10 @@ func (t *Trie) Undo() { t.Root = t.prevRoot } +func (t *Trie) Cache() *Cache { + return t.cache +} + /* * Public (query) interface functions */ -- cgit v1.2.3 From d4cc125456c2531f133aaac6ea73d5decbb80dc4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:27:22 +0100 Subject: Added more logging functions --- ethutil/config.go | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index e61c347de..607152b5b 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -46,7 +46,7 @@ func ReadConfig(base string) *config { } Config = &config{ExecPath: path, Debug: true, Ver: "0.2.3"} - Config.Log = NewLogger(LogFile|LogStd, 0) + Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) } return Config @@ -67,7 +67,7 @@ type Logger struct { func NewLogger(flag LoggerType, level int) Logger { var loggers []*log.Logger - flags := log.LstdFlags | log.Lshortfile + flags := log.LstdFlags if flag&LogFile > 0 { file, err := os.OpenFile(path.Join(Config.ExecPath, "debug.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) @@ -75,20 +75,25 @@ func NewLogger(flag LoggerType, level int) Logger { log.Panic("unable to create file logger", err) } - log := log.New(file, "[ETH]", flags) + log := log.New(file, "", flags) loggers = append(loggers, log) } if flag&LogStd > 0 { - log := log.New(os.Stdout, "[ETH]", flags) + log := log.New(os.Stdout, "", flags) loggers = append(loggers, log) } return Logger{logSys: loggers, logLevel: level} } +const ( + LogLevelDebug = iota + LogLevelInfo +) + func (log Logger) Debugln(v ...interface{}) { - if log.logLevel != 0 { + if log.logLevel != LogLevelDebug { return } @@ -98,7 +103,27 @@ func (log Logger) Debugln(v ...interface{}) { } func (log Logger) Debugf(format string, v ...interface{}) { - if log.logLevel != 0 { + if log.logLevel != LogLevelDebug { + return + } + + for _, logger := range log.logSys { + logger.Printf(format, v...) + } +} + +func (log Logger) Infoln(v ...interface{}) { + if log.logLevel > LogLevelInfo { + return + } + + for _, logger := range log.logSys { + logger.Println(v...) + } +} + +func (log Logger) Infof(format string, v ...interface{}) { + if log.logLevel > LogLevelInfo { return } -- cgit v1.2.3 From 4afb624c450229b5f0a3554d13de35fd2db8f682 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:28:08 +0100 Subject: WIP state object --- ethutil/trie.go | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index c25bd80cb..e900a0a63 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -5,6 +5,15 @@ import ( "reflect" ) +// TODO +// A StateObject is an object that has a state root +// This is goig to be the object for the second level caching (the caching of object which have a state such as contracts) +type StateObject interface { + State() *Trie + Sync() + Undo() +} + type Node struct { Key []byte Value *Value -- cgit v1.2.3 From 9bc5c4a0c5116cf3b49a55fc2aceb5f5c3b3e34d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 14:40:00 +0100 Subject: Long over due Trie delete implemented --- ethutil/trie.go | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++- ethutil/trie_test.go | 36 +++++++++++++++++++-- 2 files changed, 121 insertions(+), 3 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index e900a0a63..322f77647 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -148,6 +148,10 @@ func (t *Trie) Get(key string) string { return c.Str() } +func (t *Trie) Delete(key string) { + t.Update(key, "") +} + func (t *Trie) GetState(node interface{}, key []int) interface{} { n := NewValue(node) // Return the node if key is empty (= found) @@ -202,9 +206,10 @@ func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{ return t.InsertState(node, key, value) } else { // delete it + return t.DeleteState(node, key) } - return "" + return t.Root } func (t *Trie) Put(node interface{}) interface{} { @@ -313,6 +318,87 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter return "" } +func (t *Trie) DeleteState(node interface{}, key []int) interface{} { + if len(key) == 0 { + return "" + } + + // New node + n := NewValue(node) + if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { + return "" + } + + currentNode := t.GetNode(node) + // Check for "special" 2 slice type node + if currentNode.Len() == 2 { + // Decode the key + k := CompactDecode(currentNode.Get(0).Str()) + v := currentNode.Get(1).Raw() + + // Matching key pair (ie. there's already an object with this key) + if CompareIntSlice(k, key) { + return "" + } else if CompareIntSlice(key[:len(k)], k) { + hash := t.DeleteState(v, key[len(k):]) + child := t.GetNode(hash) + + var newNode []interface{} + if child.Len() == 2 { + newKey := append(k, CompactDecode(child.Get(0).Str())...) + newNode = []interface{}{CompactEncode(newKey), child.Get(1).Raw()} + } else { + newNode = []interface{}{currentNode.Get(0).Str(), hash} + } + + return t.Put(newNode) + } else { + return node + } + } else { + // Copy the current node over to the new node and replace the first nibble in the key + n := EmptyStringSlice(17) + var newNode []interface{} + + for i := 0; i < 17; i++ { + cpy := currentNode.Get(i).Raw() + if cpy != nil { + n[i] = cpy + } + } + + n[key[0]] = t.DeleteState(n[key[0]], key[1:]) + amount := -1 + for i := 0; i < 17; i++ { + if n[i] != "" { + if amount == -1 { + amount = i + } else { + amount = -2 + } + } + } + if amount == 16 { + newNode = []interface{}{CompactEncode([]int{16}), n[amount]} + } else if amount >= 0 { + child := t.GetNode(n[amount]) + if child.Len() == 17 { + newNode = []interface{}{CompactEncode([]int{amount}), n[amount]} + } else if child.Len() == 2 { + key := append([]int{amount}, CompactDecode(child.Get(0).Str())...) + newNode = []interface{}{CompactEncode(key), child.Get(1).Str()} + } + + } else { + newNode = n + } + + return t.Put(newNode) + } + + return "" +} + // Simple compare function which creates a rlp value out of the evaluated objects func (t *Trie) Cmp(trie *Trie) bool { return NewValue(t.Root).Cmp(NewValue(trie.Root)) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index fa60c8cfc..9d2c8e19f 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,8 +1,7 @@ package ethutil import ( - _ "encoding/hex" - _ "fmt" + "reflect" "testing" ) @@ -116,3 +115,36 @@ func TestTrieCmp(t *testing.T) { t.Errorf("Expected tries not to be equal %x %x", trie1.Root, trie2.Root) } } + +func TestTrieDelete(t *testing.T) { + _, trie := New() + trie.Update("cat", LONG_WORD) + exp := trie.Root + trie.Update("dog", LONG_WORD) + trie.Delete("dog") + if !reflect.DeepEqual(exp, trie.Root) { + t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root) + } + + trie.Update("dog", LONG_WORD) + exp = trie.Root + trie.Update("dude", LONG_WORD) + trie.Delete("dude") + if !reflect.DeepEqual(exp, trie.Root) { + t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root) + } +} + +func TestTrieDeleteWithValue(t *testing.T) { + _, trie := New() + trie.Update("c", LONG_WORD) + exp := trie.Root + trie.Update("ca", LONG_WORD) + trie.Update("cat", LONG_WORD) + trie.Delete("ca") + trie.Delete("cat") + if !reflect.DeepEqual(exp, trie.Root) { + t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root) + } + +} -- cgit v1.2.3 From 059ad352156b995aab9132aff9569c2e03c32b9b Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:10:05 +0100 Subject: Type checking --- ethutil/value.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index d3a38f87f..03d23d559 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -36,7 +36,8 @@ func (val *Value) Len() int { if data, ok := val.Val.([]interface{}); ok { return len(data) } else if data, ok := val.Val.([]byte); ok { - // FIXME + return len(data) + } else if data, ok := val.Val.(string); ok { return len(data) } @@ -139,6 +140,19 @@ func (val *Value) SliceFromTo(from, to int) *Value { 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 (val *Value) IsEmpty() bool { + return (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 { -- cgit v1.2.3 From f2a1260294b25a31452fd00fe59820467f5cd86a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 12:36:22 +0100 Subject: Nil is also considered empty --- ethutil/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index 03d23d559..3dd84d12d 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -150,7 +150,7 @@ func (val *Value) IsStr() bool { } func (val *Value) IsEmpty() bool { - return (val.IsSlice() || val.IsStr()) && val.Len() == 0 + return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0) } // Threat the value as a slice -- cgit v1.2.3 From b20c0b1d59f4109c49c7351ddeecbe195912da38 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 12:36:41 +0100 Subject: Removed all old code --- ethutil/parsing.go | 141 +++++++++++++++++++++++++---------------------------- 1 file changed, 67 insertions(+), 74 deletions(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 2c41fb4df..b43dac064 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -1,95 +1,88 @@ package ethutil import ( - "errors" - "fmt" "math/big" "strconv" - "strings" ) // Op codes -var OpCodes = map[string]string{ - "STOP": "0", - "ADD": "1", - "MUL": "2", - "SUB": "3", - "DIV": "4", - "SDIV": "5", - "MOD": "6", - "SMOD": "7", - "EXP": "8", - "NEG": "9", - "LT": "10", - "LE": "11", - "GT": "12", - "GE": "13", - "EQ": "14", - "NOT": "15", - "MYADDRESS": "16", - "TXSENDER": "17", - - "PUSH": "48", - "POP": "49", - "LOAD": "54", +var OpCodes = map[string]byte{ + "STOP": 0, + "ADD": 1, + "MUL": 2, + "SUB": 3, + "DIV": 4, + "SDIV": 5, + "MOD": 6, + "SMOD": 7, + "EXP": 8, + "NEG": 9, + "LT": 10, + "LE": 11, + "GT": 12, + "GE": 13, + "EQ": 14, + "NOT": 15, + "MYADDRESS": 16, + "TXSENDER": 17, + "TXVALUE": 18, + "TXFEE": 19, + "TXDATAN": 20, + "TXDATA": 21, + "BLK_PREVHASH": 22, + "BLK_COINBASE": 23, + "BLK_TIMESTAMP": 24, + "BLK_NUMBER": 25, + "BLK_DIFFICULTY": 26, + "BASEFEE": 27, + "SHA256": 32, + "RIPEMD160": 33, + "ECMUL": 34, + "ECADD": 35, + "ECSIGN": 36, + "ECRECOVER": 37, + "ECVALID": 38, + "SHA3": 39, + "PUSH": 48, + "POP": 49, + "DUP": 50, + "SWAP": 51, + "MLOAD": 52, + "MSTORE": 53, + "SLOAD": 54, + "SSTORE": 55, + "JMP": 56, + "JMPI": 57, + "IND": 58, + "EXTRO": 59, + "BALANCE": 60, + "MKTX": 61, + "SUICIDE": 62, } -func CompileInstr(s string) (string, error) { - tokens := strings.Split(s, " ") - if OpCodes[tokens[0]] == "" { - return s, errors.New(fmt.Sprintf("OP not found: %s", tokens[0])) +func IsOpCode(s string) bool { + for key, _ := range OpCodes { + if key == s { + return true + } } + return false +} - code := OpCodes[tokens[0]] // Replace op codes with the proper numerical equivalent - op := new(big.Int) - op.SetString(code, 0) - - args := make([]*big.Int, 6) - for i, val := range tokens[1:len(tokens)] { - num := new(big.Int) - num.SetString(val, 0) - args[i] = num - } - - // Big int equation = op + x * 256 + y * 256**2 + z * 256**3 + a * 256**4 + b * 256**5 + c * 256**6 - base := new(big.Int) - x := new(big.Int) - y := new(big.Int) - z := new(big.Int) - a := new(big.Int) - b := new(big.Int) - c := new(big.Int) - - if args[0] != nil { - x.Mul(args[0], big.NewInt(256)) - } - if args[1] != nil { - y.Mul(args[1], BigPow(256, 2)) - } - if args[2] != nil { - z.Mul(args[2], BigPow(256, 3)) - } - if args[3] != nil { - a.Mul(args[3], BigPow(256, 4)) - } - if args[4] != nil { - b.Mul(args[4], BigPow(256, 5)) - } - if args[5] != nil { - c.Mul(args[5], BigPow(256, 6)) +func CompileInstr(s string) ([]byte, error) { + isOp := IsOpCode(s) + if isOp { + return []byte{OpCodes[s]}, nil } - base.Add(op, x) - base.Add(base, y) - base.Add(base, z) - base.Add(base, a) - base.Add(base, b) - base.Add(base, c) + num := new(big.Int) + num.SetString(s, 0) - return base.String(), nil + return num.Bytes(), nil } func Instr(instr string) (int, []string, error) { + base := new(big.Int) base.SetString(instr, 0) -- cgit v1.2.3 From 4bfd717ba2b753f183e9e3fecd91d7e4083aaffc Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 22 Feb 2014 01:53:09 +0100 Subject: Added the ability to extend the logger with more sub systems --- ethutil/config.go | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 607152b5b..5bf56134d 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -1,6 +1,7 @@ package ethutil import ( + "fmt" "log" "os" "os/user" @@ -18,7 +19,7 @@ const ( type config struct { Db Database - Log Logger + Log *Logger ExecPath string Debug bool Ver string @@ -45,7 +46,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.2.3"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.3.0"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) } @@ -59,13 +60,18 @@ const ( LogStd = 0x2 ) +type LogSystem interface { + Println(v ...interface{}) + Printf(format string, v ...interface{}) +} + type Logger struct { - logSys []*log.Logger + logSys []LogSystem logLevel int } -func NewLogger(flag LoggerType, level int) Logger { - var loggers []*log.Logger +func NewLogger(flag LoggerType, level int) *Logger { + var loggers []LogSystem flags := log.LstdFlags @@ -84,7 +90,11 @@ func NewLogger(flag LoggerType, level int) Logger { loggers = append(loggers, log) } - return Logger{logSys: loggers, logLevel: level} + return &Logger{logSys: loggers, logLevel: level} +} + +func (log *Logger) AddLogSystem(logger LogSystem) { + log.logSys = append(log.logSys, logger) } const ( @@ -92,7 +102,7 @@ const ( LogLevelInfo ) -func (log Logger) Debugln(v ...interface{}) { +func (log *Logger) Debugln(v ...interface{}) { if log.logLevel != LogLevelDebug { return } @@ -102,7 +112,7 @@ func (log Logger) Debugln(v ...interface{}) { } } -func (log Logger) Debugf(format string, v ...interface{}) { +func (log *Logger) Debugf(format string, v ...interface{}) { if log.logLevel != LogLevelDebug { return } @@ -112,17 +122,18 @@ func (log Logger) Debugf(format string, v ...interface{}) { } } -func (log Logger) Infoln(v ...interface{}) { +func (log *Logger) Infoln(v ...interface{}) { if log.logLevel > LogLevelInfo { return } + fmt.Println(len(log.logSys)) for _, logger := range log.logSys { logger.Println(v...) } } -func (log Logger) Infof(format string, v ...interface{}) { +func (log *Logger) Infof(format string, v ...interface{}) { if log.logLevel > LogLevelInfo { return } -- cgit v1.2.3 From 8ecb24f1141013a935b0f7e858ef7273d67de5e5 Mon Sep 17 00:00:00 2001 From: Joey Zhou Date: Sun, 23 Feb 2014 14:43:18 -0800 Subject: parse now returns byte[] instead of string --- ethutil/parsing_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go index 482eef3ee..69a5e9016 100644 --- a/ethutil/parsing_test.go +++ b/ethutil/parsing_test.go @@ -13,7 +13,7 @@ func TestCompile(t *testing.T) { } calc := (48 + 0*256 + 0*int64(math.Pow(256, 2))) - if Big(instr).Int64() != calc { + if BigD(instr).Int64() != calc { t.Error("Expected", calc, ", got:", instr) } } -- cgit v1.2.3 From 1a98bbf1c858ed4bafcc7ffa146a30e40ef919b0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:11:00 +0100 Subject: Added a trie iterator --- ethutil/trie.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ethutil/trie_test.go | 24 +++++++++++++++ 2 files changed, 109 insertions(+) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index 322f77647..83527d364 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -70,6 +70,12 @@ func (cache *Cache) Get(key []byte) *Value { return value } +func (cache *Cache) Delete(key []byte) { + delete(cache.nodes, string(key)) + + cache.db.Delete(key) +} + func (cache *Cache) Commit() { // Don't try to commit if it isn't dirty if !cache.IsDirty { @@ -413,3 +419,82 @@ func (t *Trie) Copy() *Trie { return trie } + +type TrieIterator struct { + trie *Trie + key string + value string + + shas [][]byte + values []string +} + +func (t *Trie) NewIterator() *TrieIterator { + return &TrieIterator{trie: t} +} + +// Some time in the near future this will need refactoring :-) +// XXX Note to self, IsSlice == inline node. Str == sha3 to node +func (it *TrieIterator) workNode(currentNode *Value) { + if currentNode.Len() == 2 { + k := CompactDecode(currentNode.Get(0).Str()) + + if currentNode.Get(1).IsSlice() { + it.workNode(currentNode.Get(1)) + } else { + if k[len(k)-1] == 16 { + it.values = append(it.values, currentNode.Get(1).Str()) + } else { + it.shas = append(it.shas, currentNode.Get(1).Bytes()) + it.getNode(currentNode.Get(1).Bytes()) + } + } + } else { + for i := 0; i < currentNode.Len(); i++ { + if i == 16 && currentNode.Get(i).Len() != 0 { + it.values = append(it.values, currentNode.Get(i).Str()) + } else { + if currentNode.Get(i).IsSlice() { + it.workNode(currentNode.Get(i)) + } else { + val := currentNode.Get(i).Str() + if val != "" { + it.shas = append(it.shas, currentNode.Get(1).Bytes()) + it.getNode([]byte(val)) + } + } + } + } + } +} + +func (it *TrieIterator) getNode(node []byte) { + currentNode := it.trie.cache.Get(node) + it.workNode(currentNode) +} + +func (it *TrieIterator) Collect() [][]byte { + if it.trie.Root == "" { + return nil + } + + it.getNode(NewValue(it.trie.Root).Bytes()) + + return it.shas +} + +func (it *TrieIterator) Purge() int { + shas := it.Collect() + for _, sha := range shas { + it.trie.cache.Delete(sha) + } + return len(it.values) +} + +func (it *TrieIterator) Key() string { + return "" +} + +func (it *TrieIterator) Value() string { + return "" +} diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 9d2c8e19f..c3a8f224d 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,6 +1,7 @@ package ethutil import ( + "fmt" "reflect" "testing" ) @@ -21,6 +22,10 @@ func (db *MemDatabase) Put(key []byte, value []byte) { func (db *MemDatabase) Get(key []byte) ([]byte, error) { return db.db[string(key)], nil } +func (db *MemDatabase) Delete(key []byte) error { + delete(db.db, string(key)) + return nil +} func (db *MemDatabase) Print() {} func (db *MemDatabase) Close() {} func (db *MemDatabase) LastKnownTD() []byte { return nil } @@ -148,3 +153,22 @@ func TestTrieDeleteWithValue(t *testing.T) { } } + +func TestTrieIterator(t *testing.T) { + _, trie := New() + trie.Update("c", LONG_WORD) + trie.Update("ca", LONG_WORD) + trie.Update("cat", LONG_WORD) + + it := trie.NewIterator() + fmt.Println("purging") + fmt.Println("len =", it.Purge()) + /* + for it.Next() { + k := it.Key() + v := it.Value() + + fmt.Println(k, v) + } + */ +} -- cgit v1.2.3 From 5971c82094b79e7c05bfb652c46fac02381b2816 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:11:42 +0100 Subject: Updated opcodes ... again --- ethutil/parsing.go | 102 ++++++++++++++++++++++++------------------------ ethutil/parsing_test.go | 4 +- 2 files changed, 53 insertions(+), 53 deletions(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index b43dac064..553bb9717 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -7,57 +7,57 @@ import ( // Op codes var OpCodes = map[string]byte{ - "STOP": 0, - "ADD": 1, - "MUL": 2, - "SUB": 3, - "DIV": 4, - "SDIV": 5, - "MOD": 6, - "SMOD": 7, - "EXP": 8, - "NEG": 9, - "LT": 10, - "LE": 11, - "GT": 12, - "GE": 13, - "EQ": 14, - "NOT": 15, - "MYADDRESS": 16, - "TXSENDER": 17, - "TXVALUE": 18, - "TXFEE": 19, - "TXDATAN": 20, - "TXDATA": 21, - "BLK_PREVHASH": 22, - "BLK_COINBASE": 23, - "BLK_TIMESTAMP": 24, - "BLK_NUMBER": 25, - "BLK_DIFFICULTY": 26, - "BASEFEE": 27, - "SHA256": 32, - "RIPEMD160": 33, - "ECMUL": 34, - "ECADD": 35, - "ECSIGN": 36, - "ECRECOVER": 37, - "ECVALID": 38, - "SHA3": 39, - "PUSH": 48, - "POP": 49, - "DUP": 50, - "SWAP": 51, - "MLOAD": 52, - "MSTORE": 53, - "SLOAD": 54, - "SSTORE": 55, - "JMP": 56, - "JMPI": 57, - "IND": 58, - "EXTRO": 59, - "BALANCE": 60, - "MKTX": 61, - "SUICIDE": 62, + "STOP": 0x00, + "ADD": 0x01, + "MUL": 0x02, + "SUB": 0x03, + "DIV": 0x04, + "SDIV": 0x05, + "MOD": 0x06, + "SMOD": 0x07, + "EXP": 0x08, + "NEG": 0x09, + "LT": 0x0a, + "LE": 0x0b, + "GT": 0x0c, + "GE": 0x0d, + "EQ": 0x0e, + "NOT": 0x0f, + "MYADDRESS": 0x10, + "TXSENDER": 0x11, + "TXVALUE": 0x12, + "TXDATAN": 0x13, + "TXDATA": 0x14, + "BLK_PREVHASH": 0x15, + "BLK_COINBASE": 0x16, + "BLK_TIMESTAMP": 0x17, + "BLK_NUMBER": 0x18, + "BLK_DIFFICULTY": 0x19, + "BLK_NONCE": 0x1a, + "BASEFEE": 0x1b, + "SHA256": 0x20, + "RIPEMD160": 0x21, + "ECMUL": 0x22, + "ECADD": 0x23, + "ECSIGN": 0x24, + "ECRECOVER": 0x25, + "ECVALID": 0x26, + "SHA3": 0x27, + "PUSH": 0x30, + "POP": 0x31, + "DUP": 0x32, + "SWAP": 0x33, + "MLOAD": 0x34, + "MSTORE": 0x35, + "SLOAD": 0x36, + "SSTORE": 0x37, + "JMP": 0x38, + "JMPI": 0x39, + "IND": 0x3a, + "EXTRO": 0x3b, + "BALANCE": 0x3c, + "MKTX": 0x3d, + "SUICIDE": 0x3f, } func IsOpCode(s string) bool { diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go index 482eef3ee..c40649187 100644 --- a/ethutil/parsing_test.go +++ b/ethutil/parsing_test.go @@ -1,5 +1,6 @@ package ethutil +/* import ( "math" "testing" @@ -19,14 +20,13 @@ func TestCompile(t *testing.T) { } func TestValidInstr(t *testing.T) { - /* op, args, err := Instr("68163") if err != nil { t.Error("Error decoding instruction") } - */ } func TestInvalidInstr(t *testing.T) { } +*/ -- cgit v1.2.3 From 55c1c220d07c37610c9aa61c583eccb3c8e3829e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:12:01 +0100 Subject: Added delete to database interfaces --- ethutil/db.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethutil') diff --git a/ethutil/db.go b/ethutil/db.go index 3681c4b05..b11d5d726 100644 --- a/ethutil/db.go +++ b/ethutil/db.go @@ -4,6 +4,7 @@ package ethutil type Database interface { Put(key []byte, value []byte) Get(key []byte) ([]byte, error) + Delete(key []byte) error LastKnownTD() []byte Close() Print() -- cgit v1.2.3 From b30b9ab8cb13ddbc68a4912c9f06116c0f59bc27 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 10:50:53 +0100 Subject: Fixed a minor issue where a string is expected but returns slice --- ethutil/trie.go | 4 ++-- ethutil/trie_test.go | 19 ++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index 83527d364..a17dc37ad 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -439,7 +439,7 @@ func (it *TrieIterator) workNode(currentNode *Value) { if currentNode.Len() == 2 { k := CompactDecode(currentNode.Get(0).Str()) - if currentNode.Get(1).IsSlice() { + if currentNode.Get(1).Str() == "" { it.workNode(currentNode.Get(1)) } else { if k[len(k)-1] == 16 { @@ -454,7 +454,7 @@ func (it *TrieIterator) workNode(currentNode *Value) { if i == 16 && currentNode.Get(i).Len() != 0 { it.values = append(it.values, currentNode.Get(i).Str()) } else { - if currentNode.Get(i).IsSlice() { + if currentNode.Get(i).Str() == "" { it.workNode(currentNode.Get(i)) } else { val := currentNode.Get(i).Str() diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index c3a8f224d..645c5a225 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,6 @@ package ethutil import ( - "fmt" "reflect" "testing" ) @@ -160,15 +159,13 @@ func TestTrieIterator(t *testing.T) { trie.Update("ca", LONG_WORD) trie.Update("cat", LONG_WORD) + lenBefore := len(trie.cache.nodes) it := trie.NewIterator() - fmt.Println("purging") - fmt.Println("len =", it.Purge()) - /* - for it.Next() { - k := it.Key() - v := it.Value() - - fmt.Println(k, v) - } - */ + if num := it.Purge(); num != 3 { + t.Errorf("Expected purge to return 3, got %d", num) + } + + if lenBefore == len(trie.cache.nodes) { + t.Errorf("Expected cached nodes to be deleted") + } } -- cgit v1.2.3 From c7e73ba12d747186002433db54d002ab43bed171 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:20:24 +0100 Subject: Added currency converting --- ethutil/common.go | 35 +++++++++++++++++++++++++++++++++++ ethutil/common_test.go | 17 +++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 ethutil/common.go create mode 100644 ethutil/common_test.go (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go new file mode 100644 index 000000000..07df6bb13 --- /dev/null +++ b/ethutil/common.go @@ -0,0 +1,35 @@ +package ethutil + +import ( + "fmt" + "math/big" +) + +var ( + Ether = BigPow(10, 18) + Finney = BigPow(10, 15) + Szabo = BigPow(10, 12) + Vito = BigPow(10, 9) + Turing = BigPow(10, 6) + Eins = BigPow(10, 3) + Wei = big.NewInt(1) +) + +func CurrencyToString(num *big.Int) string { + switch { + case num.Cmp(Ether) >= 0: + return fmt.Sprintf("%v Ether", new(big.Int).Div(num, Ether)) + case num.Cmp(Finney) >= 0: + return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) + case num.Cmp(Szabo) >= 0: + return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) + case num.Cmp(Vito) >= 0: + return fmt.Sprintf("%v Vito", new(big.Int).Div(num, Vito)) + case num.Cmp(Turing) >= 0: + return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing)) + case num.Cmp(Eins) >= 0: + return fmt.Sprintf("%v Eins", new(big.Int).Div(num, Eins)) + } + + return fmt.Sprintf("%v Wei", num) +} diff --git a/ethutil/common_test.go b/ethutil/common_test.go new file mode 100644 index 000000000..3a6a37ff5 --- /dev/null +++ b/ethutil/common_test.go @@ -0,0 +1,17 @@ +package ethutil + +import ( + "fmt" + "math/big" + "testing" +) + +func TestCommon(t *testing.T) { + fmt.Println(CurrencyToString(BigPow(10, 19))) + fmt.Println(CurrencyToString(BigPow(10, 16))) + fmt.Println(CurrencyToString(BigPow(10, 13))) + fmt.Println(CurrencyToString(BigPow(10, 10))) + fmt.Println(CurrencyToString(BigPow(10, 7))) + fmt.Println(CurrencyToString(BigPow(10, 4))) + fmt.Println(CurrencyToString(big.NewInt(10))) +} -- cgit v1.2.3 From c0fcefa3a023c643040b3d9e300980bd32c33dff Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:18:41 +0100 Subject: Added a GetKeys method to support multiple accounts --- ethutil/db.go | 1 + ethutil/key.go | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 ethutil/key.go (limited to 'ethutil') diff --git a/ethutil/db.go b/ethutil/db.go index b11d5d726..abbf4a2b0 100644 --- a/ethutil/db.go +++ b/ethutil/db.go @@ -4,6 +4,7 @@ package ethutil type Database interface { Put(key []byte, value []byte) Get(key []byte) ([]byte, error) + GetKeys() []*Key Delete(key []byte) error LastKnownTD() []byte Close() diff --git a/ethutil/key.go b/ethutil/key.go new file mode 100644 index 000000000..ec195f213 --- /dev/null +++ b/ethutil/key.go @@ -0,0 +1,19 @@ +package ethutil + +type Key struct { + PrivateKey []byte + PublicKey []byte +} + +func NewKeyFromBytes(data []byte) *Key { + val := NewValueFromBytes(data) + return &Key{val.Get(0).Bytes(), val.Get(1).Bytes()} +} + +func (k *Key) Address() []byte { + return Sha3Bin(k.PublicKey[1:])[12:] +} + +func (k *Key) RlpEncode() []byte { + return EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() +} -- cgit v1.2.3 From 9d06f9e6fbc20006df6812ed3feb5d8058c0b0a6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:19:01 +0100 Subject: Updated readme#trie --- ethutil/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/README.md b/ethutil/README.md index c98612e1e..1ed56b71b 100644 --- a/ethutil/README.md +++ b/ethutil/README.md @@ -53,6 +53,8 @@ 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, @@ -82,7 +84,7 @@ type (e.g. `Slice()` returns []interface{}, `Uint()` return 0, etc). `NewEmptyValue()` returns a new \*Value with it's initial value set to a `[]interface{}` -`AppendLint()` appends a list to the current value. +`AppendList()` appends a list to the current value. `Append(v)` appends the value (v) to the current value/list. -- cgit v1.2.3 From 8fa19664e657aca80446e6c3f7868f19ac717a07 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:19:21 +0100 Subject: Added BigCopy --- ethutil/big.go | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'ethutil') diff --git a/ethutil/big.go b/ethutil/big.go index c41d63add..1a3902fa3 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -41,3 +41,12 @@ func BigToBytes(num *big.Int, base int) []byte { return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) } + +// Functions like the build in "copy" function +// but works on big integers +func BigCopy(src *big.Int) (ret *big.Int) { + ret = new(big.Int) + ret.Add(ret, src) + + return +} -- cgit v1.2.3 From 3f7ec1a83fe13dc934d92a405ff01b0be6c04ac0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:19:45 +0100 Subject: Conform to Db interface --- ethutil/trie_test.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethutil') diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 645c5a225..7c398f1de 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -25,6 +25,7 @@ func (db *MemDatabase) Delete(key []byte) error { delete(db.db, string(key)) return nil } +func (db *MemDatabase) GetKeys() []*Key { return nil } func (db *MemDatabase) Print() {} func (db *MemDatabase) Close() {} func (db *MemDatabase) LastKnownTD() []byte { return nil } -- cgit v1.2.3 From b462ca4aade75049a0fcba23c54e340f0f793dfb Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 16:45:46 +0100 Subject: Bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 5bf56134d..5fdc8e1c5 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -46,7 +46,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.3.0"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) } -- cgit v1.2.3 From f1b354e6aa6c4b0330e35ae9011784ff1a0b01ab Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Mar 2014 02:22:20 +0100 Subject: Reactor implemented --- ethutil/reactor.go | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ ethutil/reactor_test.go | 30 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 ethutil/reactor.go create mode 100644 ethutil/reactor_test.go (limited to 'ethutil') diff --git a/ethutil/reactor.go b/ethutil/reactor.go new file mode 100644 index 000000000..b3f8b9b5b --- /dev/null +++ b/ethutil/reactor.go @@ -0,0 +1,77 @@ +package ethutil + +import ( + "sync" +) + +type ReactorEvent struct { + mut sync.Mutex + event string + chans []chan React +} + +// Post the specified reactor resource on the channels +// currently subscribed +func (e *ReactorEvent) Post(react React) { + for _, ch := range e.chans { + go func(ch chan React) { + ch <- react + }(ch) + } +} + +// Add a subscriber to this event +func (e *ReactorEvent) Add(ch chan React) { + e.chans = append(e.chans, ch) +} + +// Remove a subscriber +func (e *ReactorEvent) Remove(ch chan React) { + for i, c := range e.chans { + if c == ch { + e.chans = append(e.chans[:i], e.chans[i+1:]...) + } + } +} + +// Basic reactor resource +type React struct { + Resource interface{} +} + +// The reactor basic engine. Acts as bridge +// between the events and the subscribers/posters +type ReactorEngine struct { + patterns map[string]*ReactorEvent +} + +func NewReactorEngine() *ReactorEngine { + return &ReactorEngine{patterns: make(map[string]*ReactorEvent)} +} + +// Subscribe a channel to the specified event +func (reactor *ReactorEngine) Subscribe(event string, ch chan React) { + ev := reactor.patterns[event] + // Create a new event if one isn't available + if ev == nil { + ev = &ReactorEvent{event: event} + reactor.patterns[event] = ev + } + + // Add the channel to reactor event handler + ev.Add(ch) +} + +func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) { + ev := reactor.patterns[event] + if ev != nil { + ev.Remove(ch) + } +} + +func (reactor *ReactorEngine) Post(event string, resource interface{}) { + ev := reactor.patterns[event] + if ev != nil { + ev.Post(React{Resource: resource}) + } +} diff --git a/ethutil/reactor_test.go b/ethutil/reactor_test.go new file mode 100644 index 000000000..48c2f0df3 --- /dev/null +++ b/ethutil/reactor_test.go @@ -0,0 +1,30 @@ +package ethutil + +import "testing" + +func TestReactorAdd(t *testing.T) { + engine := NewReactorEngine() + ch := make(chan React) + engine.Subscribe("test", ch) + if len(engine.patterns) != 1 { + t.Error("Expected patterns to be 1, got", len(engine.patterns)) + } +} + +func TestReactorEvent(t *testing.T) { + engine := NewReactorEngine() + + // Buffer 1, so it doesn't block for this test + ch := make(chan React, 1) + engine.Subscribe("test", ch) + engine.Post("test", "hello") + + value := <-ch + if val, ok := value.Resource.(string); ok { + if val != "hello" { + t.Error("Expected Resource to be 'hello', got", val) + } + } else { + t.Error("Unable to cast") + } +} -- cgit v1.2.3 From d2bc57cd34fe4da3ecec3ff95bc4ef9e74589e5d Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Mar 2014 00:55:10 +0100 Subject: PoC reactor pattern --- ethutil/common_test.go | 43 +++++++++++++++++++++++++++++++++++-------- ethutil/reactor.go | 9 +++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) (limited to 'ethutil') diff --git a/ethutil/common_test.go b/ethutil/common_test.go index 3a6a37ff5..b5c733ff3 100644 --- a/ethutil/common_test.go +++ b/ethutil/common_test.go @@ -1,17 +1,44 @@ package ethutil import ( - "fmt" "math/big" "testing" ) func TestCommon(t *testing.T) { - fmt.Println(CurrencyToString(BigPow(10, 19))) - fmt.Println(CurrencyToString(BigPow(10, 16))) - fmt.Println(CurrencyToString(BigPow(10, 13))) - fmt.Println(CurrencyToString(BigPow(10, 10))) - fmt.Println(CurrencyToString(BigPow(10, 7))) - fmt.Println(CurrencyToString(BigPow(10, 4))) - fmt.Println(CurrencyToString(big.NewInt(10))) + ether := CurrencyToString(BigPow(10, 19)) + finney := CurrencyToString(BigPow(10, 16)) + szabo := CurrencyToString(BigPow(10, 13)) + vito := CurrencyToString(BigPow(10, 10)) + turing := CurrencyToString(BigPow(10, 7)) + eins := CurrencyToString(BigPow(10, 4)) + wei := CurrencyToString(big.NewInt(10)) + + if ether != "10 Ether" { + t.Error("Got", ether) + } + + if finney != "10 Finney" { + t.Error("Got", finney) + } + + if szabo != "10 Szabo" { + t.Error("Got", szabo) + } + + if vito != "10 Vito" { + t.Error("Got", vito) + } + + if turing != "10 Turing" { + t.Error("Got", turing) + } + + if eins != "10 Eins" { + t.Error("Got", eins) + } + + if wei != "10 Wei" { + t.Error("Got", wei) + } } diff --git a/ethutil/reactor.go b/ethutil/reactor.go index b3f8b9b5b..f8084986c 100644 --- a/ethutil/reactor.go +++ b/ethutil/reactor.go @@ -13,6 +13,9 @@ type ReactorEvent struct { // Post the specified reactor resource on the channels // currently subscribed func (e *ReactorEvent) Post(react React) { + e.mut.Lock() + defer e.mut.Unlock() + for _, ch := range e.chans { go func(ch chan React) { ch <- react @@ -22,11 +25,17 @@ func (e *ReactorEvent) Post(react React) { // Add a subscriber to this event func (e *ReactorEvent) Add(ch chan React) { + e.mut.Lock() + defer e.mut.Unlock() + e.chans = append(e.chans, ch) } // Remove a subscriber func (e *ReactorEvent) Remove(ch chan React) { + e.mut.Lock() + defer e.mut.Unlock() + for i, c := range e.chans { if c == ch { e.chans = append(e.chans[:i], e.chans[i+1:]...) -- cgit v1.2.3 From 8577e9116e87cb67214478a3d86241a3d06b209d Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Mon, 3 Mar 2014 18:13:08 +0100 Subject: Rename .travil.yml to .travis.yml --- ethutil/.travil.yml | 3 --- ethutil/.travis.yml | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 ethutil/.travil.yml create mode 100644 ethutil/.travis.yml (limited to 'ethutil') diff --git a/ethutil/.travil.yml b/ethutil/.travil.yml deleted file mode 100644 index 69359072d..000000000 --- a/ethutil/.travil.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: go -go: - - 1.2 diff --git a/ethutil/.travis.yml b/ethutil/.travis.yml new file mode 100644 index 000000000..69359072d --- /dev/null +++ b/ethutil/.travis.yml @@ -0,0 +1,3 @@ +language: go +go: + - 1.2 -- cgit v1.2.3 From 92f2abdf769f52ea8e5e6d02bf326744e926f5b4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 5 Mar 2014 10:42:51 +0100 Subject: Partially refactored server/txpool/block manager/block chain The Ethereum structure now complies to a EthManager interface which is being used by the tx pool, block manager and block chain in order to gain access to each other. It's become simpeler. TODO: BlockManager => StateManager --- ethutil/value.go | 29 +++++++++++++++++++++++++++++ ethutil/value_test.go | 13 +++++++++++++ 2 files changed, 42 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index 3dd84d12d..46681ec2a 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -224,3 +224,32 @@ func (val *Value) Append(v interface{}) *Value { return val } + +type ValueIterator struct { + value *Value + currentValue *Value + idx int +} + +func (val *Value) NewIterator() *ValueIterator { + return &ValueIterator{value: val} +} + +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 +} diff --git a/ethutil/value_test.go b/ethutil/value_test.go index 0e2da5328..a100f44bc 100644 --- a/ethutil/value_test.go +++ b/ethutil/value_test.go @@ -50,3 +50,16 @@ func TestValueTypes(t *testing.T) { t.Errorf("expected BigInt to return '%v', got %v", bigExp, bigInt.BigInt()) } } + +func TestIterator(t *testing.T) { + value := NewValue([]interface{}{1, 2, 3}) + it := value.NewIterator() + values := []uint64{1, 2, 3} + i := 0 + for it.Next() { + if values[i] != it.Value().Uint() { + t.Errorf("Expected %d, got %d", values[i], it.Value().Uint()) + } + i++ + } +} -- cgit v1.2.3 From f80984491a503f2e6cc0b5845744e943854ecade Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 6 Mar 2014 13:09:55 +0100 Subject: Removed comments --- ethutil/trie.go | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index a17dc37ad..c67f750bc 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -219,18 +219,6 @@ func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{ } func (t *Trie) Put(node interface{}) interface{} { - /* - enc := Encode(node) - if len(enc) >= 32 { - var sha []byte - sha = Sha3Bin(enc) - //t.db.Put([]byte(sha), enc) - - return sha - } - return node - */ - /* TODO? c := Conv(t.Root) -- cgit v1.2.3 From 344e827061c896a17124a65686bdc3fbbd03d7bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Mar 2014 12:08:16 +0100 Subject: Added client string to configuration Clients can set their own client string which will be send to connected peers during the handshake. --- ethutil/config.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 5fdc8e1c5..436c12b92 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -6,6 +6,7 @@ import ( "os" "os/user" "path" + "runtime" ) type LogType byte @@ -19,12 +20,13 @@ const ( type config struct { Db Database - Log *Logger - ExecPath string - Debug bool - Ver string - Pubkey []byte - Seed bool + Log *Logger + ExecPath string + Debug bool + Ver string + ClientString string + Pubkey []byte + Seed bool } var Config *config @@ -48,6 +50,7 @@ func ReadConfig(base string) *config { Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) + Config.ClientString = fmt.Sprintf("/Ethereum(G) v%s/%s", Config.Ver, runtime.GOOS) } return Config -- cgit v1.2.3 From c642094cac6ee6fb0215d7510cc57a719c2a2689 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:27:26 +0100 Subject: Added encoder interface --- ethutil/rlp.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ethutil') diff --git a/ethutil/rlp.go b/ethutil/rlp.go index e633f5f1d..33ec0d359 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -9,6 +9,10 @@ import ( "math/big" ) +type RlpEncodable interface { + RlpEncode() []byte +} + type RlpEncoder struct { rlpData []byte } -- cgit v1.2.3 From f21eb88ad1cf54b342187e8d3b55374a695cd524 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:27:48 +0100 Subject: Some minor updates --- ethutil/config.go | 6 +++++- ethutil/parsing.go | 10 +++++++++- ethutil/trie_test.go | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 436c12b92..54b066fb9 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,12 +50,16 @@ func ReadConfig(base string) *config { Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) - Config.ClientString = fmt.Sprintf("/Ethereum(G) v%s/%s", Config.Ver, runtime.GOOS) + Config.SetClientString("/Ethereum(G)") } return Config } +func (c *config) SetClientString(str string) { + Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS) +} + type LoggerType byte const ( diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 553bb9717..459cdc284 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -58,6 +58,10 @@ var OpCodes = map[string]byte{ "BALANCE": 0x3c, "MKTX": 0x3d, "SUICIDE": 0x3f, + + // TODO FIX OPCODES + "CALL": 0x40, + "RETURN": 0x41, } func IsOpCode(s string) bool { @@ -76,7 +80,11 @@ func CompileInstr(s string) ([]byte, error) { } num := new(big.Int) - num.SetString(s, 0) + _, success := num.SetString(s, 0) + // Assume regular bytes during compilation + if !success { + num.SetBytes([]byte(s)) + } return num.Bytes(), nil } diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 7c398f1de..79e5de921 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,6 +1,7 @@ package ethutil import ( + "fmt" "reflect" "testing" ) -- cgit v1.2.3 From f3d27bf5d878120346f8cdd0744e7f1f8e1ee631 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 22:51:20 +0100 Subject: Rewrote opcodes again --- ethutil/parsing.go | 119 ++++++++++++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 55 deletions(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 459cdc284..9ff2827a0 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -7,61 +7,70 @@ import ( // Op codes var OpCodes = map[string]byte{ - "STOP": 0x00, - "ADD": 0x01, - "MUL": 0x02, - "SUB": 0x03, - "DIV": 0x04, - "SDIV": 0x05, - "MOD": 0x06, - "SMOD": 0x07, - "EXP": 0x08, - "NEG": 0x09, - "LT": 0x0a, - "LE": 0x0b, - "GT": 0x0c, - "GE": 0x0d, - "EQ": 0x0e, - "NOT": 0x0f, - "MYADDRESS": 0x10, - "TXSENDER": 0x11, - "TXVALUE": 0x12, - "TXDATAN": 0x13, - "TXDATA": 0x14, - "BLK_PREVHASH": 0x15, - "BLK_COINBASE": 0x16, - "BLK_TIMESTAMP": 0x17, - "BLK_NUMBER": 0x18, - "BLK_DIFFICULTY": 0x19, - "BLK_NONCE": 0x1a, - "BASEFEE": 0x1b, - "SHA256": 0x20, - "RIPEMD160": 0x21, - "ECMUL": 0x22, - "ECADD": 0x23, - "ECSIGN": 0x24, - "ECRECOVER": 0x25, - "ECVALID": 0x26, - "SHA3": 0x27, - "PUSH": 0x30, - "POP": 0x31, - "DUP": 0x32, - "SWAP": 0x33, - "MLOAD": 0x34, - "MSTORE": 0x35, - "SLOAD": 0x36, - "SSTORE": 0x37, - "JMP": 0x38, - "JMPI": 0x39, - "IND": 0x3a, - "EXTRO": 0x3b, - "BALANCE": 0x3c, - "MKTX": 0x3d, - "SUICIDE": 0x3f, - - // TODO FIX OPCODES - "CALL": 0x40, - "RETURN": 0x41, + // 0x0 range - arithmetic ops + "STOP": 0x00, + "ADD": 0x01, + "MUL": 0x02, + "SUB": 0x03, + "DIV": 0x04, + "SDIV": 0x05, + "MOD": 0x06, + "SMOD": 0x07, + "EXP": 0x08, + "NEG": 0x09, + "LT": 0x0a, + "GT": 0x0b, + "EQ": 0x0c, + "NOT": 0x0d, + + // 0x10 range - bit ops + "AND": 0x10, + "OR": 0x11, + "XOR": 0x12, + "BYTE": 0x13, + + // 0x20 range - crypto + "SHA3": 0x20, + + // 0x30 range - closure state + "ADDRESS": 0x30, + "BALANCE": 0x31, + "ORIGIN": 0x32, + "CALLER": 0x33, + "CALLVALUE": 0x34, + "CALLDATA": 0x35, + "CALLDATASIZE": 0x36, + "RETURNDATASIZE": 0x37, + "TXGASPRICE": 0x38, + + // 0x40 range - block operations + "PREVHASH": 0x40, + "PREVNONCE": 0x41, + "COINBASE": 0x42, + "TIMESTAMP": 0x43, + "NUMBER": 0x44, + "DIFFICULTY": 0x45, + "GASLIMIT": 0x46, + + // 0x50 range - 'storage' and execution + "PUSH": 0x50, + "POP": 0x51, + "DUP": 0x52, + "SWAP": 0x53, + "MLOAD": 0x54, + "MSTORE": 0x55, + "MSTORE8": 0x56, + "SLOAD": 0x57, + "SSTORE": 0x58, + "JUMP": 0x59, + "JUMPI": 0x5a, + "PC": 0x5b, + "MEMSIZE": 0x5c, + + // 0x60 range - closures + "CREATE": 0x60, + "CALL": 0x61, + "RETURN": 0x62, } func IsOpCode(s string) bool { -- cgit v1.2.3 From fa1db8d2dcbc12fd9b343e6572c541d92fe7cb55 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 11:54:36 +0100 Subject: Implemented closure arguments --- ethutil/parsing.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 9ff2827a0..b2e9d9fee 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -65,12 +65,16 @@ var OpCodes = map[string]byte{ "JUMP": 0x59, "JUMPI": 0x5a, "PC": 0x5b, - "MEMSIZE": 0x5c, + "MSIZE": 0x5c, // 0x60 range - closures "CREATE": 0x60, "CALL": 0x61, "RETURN": 0x62, + + // 0x70 range - other + "LOG": 0x70, + "SUICIDE": 0x7f, } func IsOpCode(s string) bool { -- cgit v1.2.3 From 2ea4c632d1673b762c1af11582364d9faa08c413 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 14:47:55 +0100 Subject: Closure return, arguments fixed. Added proper tests --- ethutil/parsing.go | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index b2e9d9fee..f24402623 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -33,24 +33,22 @@ var OpCodes = map[string]byte{ "SHA3": 0x20, // 0x30 range - closure state - "ADDRESS": 0x30, - "BALANCE": 0x31, - "ORIGIN": 0x32, - "CALLER": 0x33, - "CALLVALUE": 0x34, - "CALLDATA": 0x35, - "CALLDATASIZE": 0x36, - "RETURNDATASIZE": 0x37, - "TXGASPRICE": 0x38, + "ADDRESS": 0x30, + "BALANCE": 0x31, + "ORIGIN": 0x32, + "CALLER": 0x33, + "CALLVALUE": 0x34, + "CALLDATA": 0x35, + "CALLDATASIZE": 0x36, + "GASPRICE": 0x38, // 0x40 range - block operations "PREVHASH": 0x40, - "PREVNONCE": 0x41, - "COINBASE": 0x42, - "TIMESTAMP": 0x43, - "NUMBER": 0x44, - "DIFFICULTY": 0x45, - "GASLIMIT": 0x46, + "COINBASE": 0x41, + "TIMESTAMP": 0x42, + "NUMBER": 0x43, + "DIFFICULTY": 0x44, + "GASLIMIT": 0x45, // 0x50 range - 'storage' and execution "PUSH": 0x50, -- cgit v1.2.3 From 9a9e252cabdc6283d7f4e523860f0e4addf62152 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 15:27:18 +0100 Subject: Changes 'compiler' to work with any type --- ethutil/parsing.go | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index f24402623..8929f0829 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -84,20 +84,30 @@ func IsOpCode(s string) bool { return false } -func CompileInstr(s string) ([]byte, error) { - isOp := IsOpCode(s) - if isOp { - return []byte{OpCodes[s]}, nil - } +func CompileInstr(s interface{}) ([]byte, error) { + switch s.(type) { + case string: + str := s.(string) + isOp := IsOpCode(str) + if isOp { + return []byte{OpCodes[str]}, nil + } + + num := new(big.Int) + _, success := num.SetString(str, 0) + // Assume regular bytes during compilation + if !success { + num.SetBytes([]byte(str)) + } - num := new(big.Int) - _, success := num.SetString(s, 0) - // Assume regular bytes during compilation - if !success { - num.SetBytes([]byte(s)) + return num.Bytes(), nil + case int: + return big.NewInt(int64(s.(int))).Bytes(), nil + case []byte: + return BigD(s.([]byte)).Bytes(), nil } - return num.Bytes(), nil + return nil, nil } func Instr(instr string) (int, []string, error) { @@ -118,3 +128,17 @@ func Instr(instr string) (int, []string, error) { return op, args[1:7], nil } + +// Script compilation functions +// Compiles strings to machine code +func Compile(instructions ...interface{}) (script []string) { + script = make([]string, len(instructions)) + + for i, val := range instructions { + instr, _ := CompileInstr(val) + + script[i] = string(instr) + } + + return +} -- cgit v1.2.3 From 01c1bce9c5dfa2b2bcdf934afec3f206823f895f Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 18:22:47 +0100 Subject: Removed regular ints from the virtual machine and closures --- ethutil/common.go | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go index 07df6bb13..f15b10e6d 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -33,3 +33,9 @@ func CurrencyToString(num *big.Int) string { return fmt.Sprintf("%v Wei", num) } + +var ( + Big1 = big.NewInt(1) + Big0 = big.NewInt(0) + Big256 = big.NewInt(0xff) +) -- cgit v1.2.3 From e0b6091d7ef709902f534c1a4b57151f0171e03c Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Mar 2014 13:20:34 +0100 Subject: Test fixes and removed old code. Added VM gas fees --- ethutil/common.go | 1 + ethutil/parsing.go | 2 +- ethutil/rlp_test.go | 6 ++++++ ethutil/trie_test.go | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go index f15b10e6d..c63af29a6 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -36,6 +36,7 @@ func CurrencyToString(num *big.Int) string { var ( Big1 = big.NewInt(1) + Big2 = big.NewInt(1) Big0 = big.NewInt(0) Big256 = big.NewInt(0xff) ) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 8929f0829..16ed2d06d 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -131,7 +131,7 @@ func Instr(instr string) (int, []string, error) { // Script compilation functions // Compiles strings to machine code -func Compile(instructions ...interface{}) (script []string) { +func Assemble(instructions ...interface{}) (script []string) { script = make([]string, len(instructions)) for i, val := range instructions { diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 2a58bfc0f..dc10db632 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,6 +2,7 @@ package ethutil import ( "bytes" + "fmt" "math/big" "reflect" "testing" @@ -119,6 +120,11 @@ func TestEncodeDecodeBytes(t *testing.T) { } } +func TestEncodeZero(t *testing.T) { + b := NewValue(0).Encode() + fmt.Println(b) +} + func BenchmarkEncodeDecode(b *testing.B) { for i := 0; i < b.N; i++ { bytes := Encode([]interface{}{"dog", "god", "cat"}) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 79e5de921..0be512d9f 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,7 @@ package ethutil import ( - "fmt" + _ "fmt" "reflect" "testing" ) -- cgit v1.2.3 From 308c59320c25845f9668e76559b581e2161fec15 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 15:38:55 +0100 Subject: Fixed typo --- ethutil/rlp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 33ec0d359..e6c75696e 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -57,7 +57,7 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { switch { case char == 0: return nil - case char <= 0x7c: + case char <= 0x7f: return char case char <= 0xb7: -- cgit v1.2.3 From 7660e1ed907e213a53408fe60a63619a68fd817b Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 19:42:01 +0100 Subject: Added a IsList method for type checking []interface{} --- ethutil/value.go | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index 46681ec2a..04131aba9 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -149,6 +149,15 @@ func (val *Value) IsStr() bool { return val.Type() == reflect.String } +// 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) } -- cgit v1.2.3 From 5f49a659c36dbfb8c330ddc3d4565c19a9a936b5 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 31 Mar 2014 12:54:37 +0200 Subject: More blockchain testing --- ethutil/rlp_test.go | 10 ++++++++++ ethutil/trie_test.go | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 2a58bfc0f..ce2535663 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,6 +2,7 @@ package ethutil import ( "bytes" + "fmt" "math/big" "reflect" "testing" @@ -55,6 +56,15 @@ func TestValue(t *testing.T) { } } +func TestEncodeDecodeMaran(t *testing.T) { + b := NewValue([]interface{}{"dog", 15, []interface{}{"cat", "cat", []interface{}{}}, 1024, "tachikoma"}) + a := b.Encode() + fmt.Println("voor maran", a) + f, i := Decode(a, 0) + fmt.Println("voor maran 2", f) + fmt.Println(i) +} + func TestEncode(t *testing.T) { strRes := "\x83dog" bytes := Encode("dog") diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 79e5de921..0be512d9f 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,7 @@ package ethutil import ( - "fmt" + _ "fmt" "reflect" "testing" ) -- cgit v1.2.3 From 35a82f8f4a69019d72ff3379e0f61bf2be475e42 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 7 Apr 2014 14:00:02 +0200 Subject: Added support for mneomnic privkeys --- ethutil/mnemonic.go | 1686 ++++++++++++++++++++++++++++++++++++++++++++++ ethutil/mnemonic_test.go | 74 ++ 2 files changed, 1760 insertions(+) create mode 100644 ethutil/mnemonic.go create mode 100644 ethutil/mnemonic_test.go (limited to 'ethutil') diff --git a/ethutil/mnemonic.go b/ethutil/mnemonic.go new file mode 100644 index 000000000..d21c20f00 --- /dev/null +++ b/ethutil/mnemonic.go @@ -0,0 +1,1686 @@ +package ethutil + +import ( + "fmt" + "strconv" +) + +var words []string = []string{ + "like", + "just", + "love", + "know", + "never", + "want", + "time", + "out", + "there", + "make", + "look", + "eye", + "down", + "only", + "think", + "heart", + "back", + "then", + "into", + "about", + "more", + "away", + "still", + "them", + "take", + "thing", + "even", + "through", + "long", + "always", + "world", + "too", + "friend", + "tell", + "try", + "hand", + "thought", + "over", + "here", + "other", + "need", + "smile", + "again", + "much", + "cry", + "been", + "night", + "ever", + "little", + "said", + "end", + "some", + "those", + "around", + "mind", + "people", + "girl", + "leave", + "dream", + "left", + "turn", + "myself", + "give", + "nothing", + "really", + "off", + "before", + "something", + "find", + "walk", + "wish", + "good", + "once", + "place", + "ask", + "stop", + "keep", + "watch", + "seem", + "everything", + "wait", + "got", + "yet", + "made", + "remember", + "start", + "alone", + "run", + "hope", + "maybe", + "believe", + "body", + "hate", + "after", + "close", + "talk", + "stand", + "own", + "each", + "hurt", + "help", + "home", + "god", + "soul", + "new", + "many", + "two", + "inside", + "should", + "true", + "first", + "fear", + "mean", + "better", + "play", + "another", + "gone", + "change", + "use", + "wonder", + "someone", + "hair", + "cold", + "open", + "best", + "any", + "behind", + "happen", + "water", + "dark", + "laugh", + "stay", + "forever", + "name", + "work", + "show", + "sky", + "break", + "came", + "deep", + "door", + "put", + "black", + "together", + "upon", + "happy", + "such", + "great", + "white", + "matter", + "fill", + "past", + "please", + "burn", + "cause", + "enough", + "touch", + "moment", + "soon", + "voice", + "scream", + "anything", + "stare", + "sound", + "red", + "everyone", + "hide", + "kiss", + "truth", + "death", + "beautiful", + "mine", + "blood", + "broken", + "very", + "pass", + "next", + "forget", + "tree", + "wrong", + "air", + "mother", + "understand", + "lip", + "hit", + "wall", + "memory", + "sleep", + "free", + "high", + "realize", + "school", + "might", + "skin", + "sweet", + "perfect", + "blue", + "kill", + "breath", + "dance", + "against", + "fly", + "between", + "grow", + "strong", + "under", + "listen", + "bring", + "sometimes", + "speak", + "pull", + "person", + "become", + "family", + "begin", + "ground", + "real", + "small", + "father", + "sure", + "feet", + "rest", + "young", + "finally", + "land", + "across", + "today", + "different", + "guy", + "line", + "fire", + "reason", + "reach", + "second", + "slowly", + "write", + "eat", + "smell", + "mouth", + "step", + "learn", + "three", + "floor", + "promise", + "breathe", + "darkness", + "push", + "earth", + "guess", + "save", + "song", + "above", + "along", + "both", + "color", + "house", + "almost", + "sorry", + "anymore", + "brother", + "okay", + "dear", + "game", + "fade", + "already", + "apart", + "warm", + "beauty", + "heard", + "notice", + "question", + "shine", + "began", + "piece", + "whole", + "shadow", + "secret", + "street", + "within", + "finger", + "point", + "morning", + "whisper", + "child", + "moon", + "green", + "story", + "glass", + "kid", + "silence", + "since", + "soft", + "yourself", + "empty", + "shall", + "angel", + "answer", + "baby", + "bright", + "dad", + "path", + "worry", + "hour", + "drop", + "follow", + "power", + "war", + "half", + "flow", + "heaven", + "act", + "chance", + "fact", + "least", + "tired", + "children", + "near", + "quite", + "afraid", + "rise", + "sea", + "taste", + "window", + "cover", + "nice", + "trust", + "lot", + "sad", + "cool", + "force", + "peace", + "return", + "blind", + "easy", + "ready", + "roll", + "rose", + "drive", + "held", + "music", + "beneath", + "hang", + "mom", + "paint", + "emotion", + "quiet", + "clear", + "cloud", + "few", + "pretty", + "bird", + "outside", + "paper", + "picture", + "front", + "rock", + "simple", + "anyone", + "meant", + "reality", + "road", + "sense", + "waste", + "bit", + "leaf", + "thank", + "happiness", + "meet", + "men", + "smoke", + "truly", + "decide", + "self", + "age", + "book", + "form", + "alive", + "carry", + "escape", + "damn", + "instead", + "able", + "ice", + "minute", + "throw", + "catch", + "leg", + "ring", + "course", + "goodbye", + "lead", + "poem", + "sick", + "corner", + "desire", + "known", + "problem", + "remind", + "shoulder", + "suppose", + "toward", + "wave", + "drink", + "jump", + "woman", + "pretend", + "sister", + "week", + "human", + "joy", + "crack", + "grey", + "pray", + "surprise", + "dry", + "knee", + "less", + "search", + "bleed", + "caught", + "clean", + "embrace", + "future", + "king", + "son", + "sorrow", + "chest", + "hug", + "remain", + "sat", + "worth", + "blow", + "daddy", + "final", + "parent", + "tight", + "also", + "create", + "lonely", + "safe", + "cross", + "dress", + "evil", + "silent", + "bone", + "fate", + "perhaps", + "anger", + "class", + "scar", + "snow", + "tiny", + "tonight", + "continue", + "control", + "dog", + "edge", + "mirror", + "month", + "suddenly", + "comfort", + "given", + "loud", + "quickly", + "gaze", + "plan", + "rush", + "stone", + "town", + "battle", + "ignore", + "spirit", + "stood", + "stupid", + "yours", + "brown", + "build", + "dust", + "hey", + "kept", + "pay", + "phone", + "twist", + "although", + "ball", + "beyond", + "hidden", + "nose", + "taken", + "fail", + "float", + "pure", + "somehow", + "wash", + "wrap", + "angry", + "cheek", + "creature", + "forgotten", + "heat", + "rip", + "single", + "space", + "special", + "weak", + "whatever", + "yell", + "anyway", + "blame", + "job", + "choose", + "country", + "curse", + "drift", + "echo", + "figure", + "grew", + "laughter", + "neck", + "suffer", + "worse", + "yeah", + "disappear", + "foot", + "forward", + "knife", + "mess", + "somewhere", + "stomach", + "storm", + "beg", + "idea", + "lift", + "offer", + "breeze", + "field", + "five", + "often", + "simply", + "stuck", + "win", + "allow", + "confuse", + "enjoy", + "except", + "flower", + "seek", + "strength", + "calm", + "grin", + "gun", + "heavy", + "hill", + "large", + "ocean", + "shoe", + "sigh", + "straight", + "summer", + "tongue", + "accept", + "crazy", + "everyday", + "exist", + "grass", + "mistake", + "sent", + "shut", + "surround", + "table", + "ache", + "brain", + "destroy", + "heal", + "nature", + "shout", + "sign", + "stain", + "choice", + "doubt", + "glance", + "glow", + "mountain", + "queen", + "stranger", + "throat", + "tomorrow", + "city", + "either", + "fish", + "flame", + "rather", + "shape", + "spin", + "spread", + "ash", + "distance", + "finish", + "image", + "imagine", + "important", + "nobody", + "shatter", + "warmth", + "became", + "feed", + "flesh", + "funny", + "lust", + "shirt", + "trouble", + "yellow", + "attention", + "bare", + "bite", + "money", + "protect", + "amaze", + "appear", + "born", + "choke", + "completely", + "daughter", + "fresh", + "friendship", + "gentle", + "probably", + "six", + "deserve", + "expect", + "grab", + "middle", + "nightmare", + "river", + "thousand", + "weight", + "worst", + "wound", + "barely", + "bottle", + "cream", + "regret", + "relationship", + "stick", + "test", + "crush", + "endless", + "fault", + "itself", + "rule", + "spill", + "art", + "circle", + "join", + "kick", + "mask", + "master", + "passion", + "quick", + "raise", + "smooth", + "unless", + "wander", + "actually", + "broke", + "chair", + "deal", + "favorite", + "gift", + "note", + "number", + "sweat", + "box", + "chill", + "clothes", + "lady", + "mark", + "park", + "poor", + "sadness", + "tie", + "animal", + "belong", + "brush", + "consume", + "dawn", + "forest", + "innocent", + "pen", + "pride", + "stream", + "thick", + "clay", + "complete", + "count", + "draw", + "faith", + "press", + "silver", + "struggle", + "surface", + "taught", + "teach", + "wet", + "bless", + "chase", + "climb", + "enter", + "letter", + "melt", + "metal", + "movie", + "stretch", + "swing", + "vision", + "wife", + "beside", + "crash", + "forgot", + "guide", + "haunt", + "joke", + "knock", + "plant", + "pour", + "prove", + "reveal", + "steal", + "stuff", + "trip", + "wood", + "wrist", + "bother", + "bottom", + "crawl", + "crowd", + "fix", + "forgive", + "frown", + "grace", + "loose", + "lucky", + "party", + "release", + "surely", + "survive", + "teacher", + "gently", + "grip", + "speed", + "suicide", + "travel", + "treat", + "vein", + "written", + "cage", + "chain", + "conversation", + "date", + "enemy", + "however", + "interest", + "million", + "page", + "pink", + "proud", + "sway", + "themselves", + "winter", + "church", + "cruel", + "cup", + "demon", + "experience", + "freedom", + "pair", + "pop", + "purpose", + "respect", + "shoot", + "softly", + "state", + "strange", + "bar", + "birth", + "curl", + "dirt", + "excuse", + "lord", + "lovely", + "monster", + "order", + "pack", + "pants", + "pool", + "scene", + "seven", + "shame", + "slide", + "ugly", + "among", + "blade", + "blonde", + "closet", + "creek", + "deny", + "drug", + "eternity", + "gain", + "grade", + "handle", + "key", + "linger", + "pale", + "prepare", + "swallow", + "swim", + "tremble", + "wheel", + "won", + "cast", + "cigarette", + "claim", + "college", + "direction", + "dirty", + "gather", + "ghost", + "hundred", + "loss", + "lung", + "orange", + "present", + "swear", + "swirl", + "twice", + "wild", + "bitter", + "blanket", + "doctor", + "everywhere", + "flash", + "grown", + "knowledge", + "numb", + "pressure", + "radio", + "repeat", + "ruin", + "spend", + "unknown", + "buy", + "clock", + "devil", + "early", + "false", + "fantasy", + "pound", + "precious", + "refuse", + "sheet", + "teeth", + "welcome", + "add", + "ahead", + "block", + "bury", + "caress", + "content", + "depth", + "despite", + "distant", + "marry", + "purple", + "threw", + "whenever", + "bomb", + "dull", + "easily", + "grasp", + "hospital", + "innocence", + "normal", + "receive", + "reply", + "rhyme", + "shade", + "someday", + "sword", + "toe", + "visit", + "asleep", + "bought", + "center", + "consider", + "flat", + "hero", + "history", + "ink", + "insane", + "muscle", + "mystery", + "pocket", + "reflection", + "shove", + "silently", + "smart", + "soldier", + "spot", + "stress", + "train", + "type", + "view", + "whether", + "bus", + "energy", + "explain", + "holy", + "hunger", + "inch", + "magic", + "mix", + "noise", + "nowhere", + "prayer", + "presence", + "shock", + "snap", + "spider", + "study", + "thunder", + "trail", + "admit", + "agree", + "bag", + "bang", + "bound", + "butterfly", + "cute", + "exactly", + "explode", + "familiar", + "fold", + "further", + "pierce", + "reflect", + "scent", + "selfish", + "sharp", + "sink", + "spring", + "stumble", + "universe", + "weep", + "women", + "wonderful", + "action", + "ancient", + "attempt", + "avoid", + "birthday", + "branch", + "chocolate", + "core", + "depress", + "drunk", + "especially", + "focus", + "fruit", + "honest", + "match", + "palm", + "perfectly", + "pillow", + "pity", + "poison", + "roar", + "shift", + "slightly", + "thump", + "truck", + "tune", + "twenty", + "unable", + "wipe", + "wrote", + "coat", + "constant", + "dinner", + "drove", + "egg", + "eternal", + "flight", + "flood", + "frame", + "freak", + "gasp", + "glad", + "hollow", + "motion", + "peer", + "plastic", + "root", + "screen", + "season", + "sting", + "strike", + "team", + "unlike", + "victim", + "volume", + "warn", + "weird", + "attack", + "await", + "awake", + "built", + "charm", + "crave", + "despair", + "fought", + "grant", + "grief", + "horse", + "limit", + "message", + "ripple", + "sanity", + "scatter", + "serve", + "split", + "string", + "trick", + "annoy", + "blur", + "boat", + "brave", + "clearly", + "cling", + "connect", + "fist", + "forth", + "imagination", + "iron", + "jock", + "judge", + "lesson", + "milk", + "misery", + "nail", + "naked", + "ourselves", + "poet", + "possible", + "princess", + "sail", + "size", + "snake", + "society", + "stroke", + "torture", + "toss", + "trace", + "wise", + "bloom", + "bullet", + "cell", + "check", + "cost", + "darling", + "during", + "footstep", + "fragile", + "hallway", + "hardly", + "horizon", + "invisible", + "journey", + "midnight", + "mud", + "nod", + "pause", + "relax", + "shiver", + "sudden", + "value", + "youth", + "abuse", + "admire", + "blink", + "breast", + "bruise", + "constantly", + "couple", + "creep", + "curve", + "difference", + "dumb", + "emptiness", + "gotta", + "honor", + "plain", + "planet", + "recall", + "rub", + "ship", + "slam", + "soar", + "somebody", + "tightly", + "weather", + "adore", + "approach", + "bond", + "bread", + "burst", + "candle", + "coffee", + "cousin", + "crime", + "desert", + "flutter", + "frozen", + "grand", + "heel", + "hello", + "language", + "level", + "movement", + "pleasure", + "powerful", + "random", + "rhythm", + "settle", + "silly", + "slap", + "sort", + "spoken", + "steel", + "threaten", + "tumble", + "upset", + "aside", + "awkward", + "bee", + "blank", + "board", + "button", + "card", + "carefully", + "complain", + "crap", + "deeply", + "discover", + "drag", + "dread", + "effort", + "entire", + "fairy", + "giant", + "gotten", + "greet", + "illusion", + "jeans", + "leap", + "liquid", + "march", + "mend", + "nervous", + "nine", + "replace", + "rope", + "spine", + "stole", + "terror", + "accident", + "apple", + "balance", + "boom", + "childhood", + "collect", + "demand", + "depression", + "eventually", + "faint", + "glare", + "goal", + "group", + "honey", + "kitchen", + "laid", + "limb", + "machine", + "mere", + "mold", + "murder", + "nerve", + "painful", + "poetry", + "prince", + "rabbit", + "shelter", + "shore", + "shower", + "soothe", + "stair", + "steady", + "sunlight", + "tangle", + "tease", + "treasure", + "uncle", + "begun", + "bliss", + "canvas", + "cheer", + "claw", + "clutch", + "commit", + "crimson", + "crystal", + "delight", + "doll", + "existence", + "express", + "fog", + "football", + "gay", + "goose", + "guard", + "hatred", + "illuminate", + "mass", + "math", + "mourn", + "rich", + "rough", + "skip", + "stir", + "student", + "style", + "support", + "thorn", + "tough", + "yard", + "yearn", + "yesterday", + "advice", + "appreciate", + "autumn", + "bank", + "beam", + "bowl", + "capture", + "carve", + "collapse", + "confusion", + "creation", + "dove", + "feather", + "girlfriend", + "glory", + "government", + "harsh", + "hop", + "inner", + "loser", + "moonlight", + "neighbor", + "neither", + "peach", + "pig", + "praise", + "screw", + "shield", + "shimmer", + "sneak", + "stab", + "subject", + "throughout", + "thrown", + "tower", + "twirl", + "wow", + "army", + "arrive", + "bathroom", + "bump", + "cease", + "cookie", + "couch", + "courage", + "dim", + "guilt", + "howl", + "hum", + "husband", + "insult", + "led", + "lunch", + "mock", + "mostly", + "natural", + "nearly", + "needle", + "nerd", + "peaceful", + "perfection", + "pile", + "price", + "remove", + "roam", + "sanctuary", + "serious", + "shiny", + "shook", + "sob", + "stolen", + "tap", + "vain", + "void", + "warrior", + "wrinkle", + "affection", + "apologize", + "blossom", + "bounce", + "bridge", + "cheap", + "crumble", + "decision", + "descend", + "desperately", + "dig", + "dot", + "flip", + "frighten", + "heartbeat", + "huge", + "lazy", + "lick", + "odd", + "opinion", + "process", + "puzzle", + "quietly", + "retreat", + "score", + "sentence", + "separate", + "situation", + "skill", + "soak", + "square", + "stray", + "taint", + "task", + "tide", + "underneath", + "veil", + "whistle", + "anywhere", + "bedroom", + "bid", + "bloody", + "burden", + "careful", + "compare", + "concern", + "curtain", + "decay", + "defeat", + "describe", + "double", + "dreamer", + "driver", + "dwell", + "evening", + "flare", + "flicker", + "grandma", + "guitar", + "harm", + "horrible", + "hungry", + "indeed", + "lace", + "melody", + "monkey", + "nation", + "object", + "obviously", + "rainbow", + "salt", + "scratch", + "shown", + "shy", + "stage", + "stun", + "third", + "tickle", + "useless", + "weakness", + "worship", + "worthless", + "afternoon", + "beard", + "boyfriend", + "bubble", + "busy", + "certain", + "chin", + "concrete", + "desk", + "diamond", + "doom", + "drawn", + "due", + "felicity", + "freeze", + "frost", + "garden", + "glide", + "harmony", + "hopefully", + "hunt", + "jealous", + "lightning", + "mama", + "mercy", + "peel", + "physical", + "position", + "pulse", + "punch", + "quit", + "rant", + "respond", + "salty", + "sane", + "satisfy", + "savior", + "sheep", + "slept", + "social", + "sport", + "tuck", + "utter", + "valley", + "wolf", + "aim", + "alas", + "alter", + "arrow", + "awaken", + "beaten", + "belief", + "brand", + "ceiling", + "cheese", + "clue", + "confidence", + "connection", + "daily", + "disguise", + "eager", + "erase", + "essence", + "everytime", + "expression", + "fan", + "flag", + "flirt", + "foul", + "fur", + "giggle", + "glorious", + "ignorance", + "law", + "lifeless", + "measure", + "mighty", + "muse", + "north", + "opposite", + "paradise", + "patience", + "patient", + "pencil", + "petal", + "plate", + "ponder", + "possibly", + "practice", + "slice", + "spell", + "stock", + "strife", + "strip", + "suffocate", + "suit", + "tender", + "tool", + "trade", + "velvet", + "verse", + "waist", + "witch", + "aunt", + "bench", + "bold", + "cap", + "certainly", + "click", + "companion", + "creator", + "dart", + "delicate", + "determine", + "dish", + "dragon", + "drama", + "drum", + "dude", + "everybody", + "feast", + "forehead", + "former", + "fright", + "fully", + "gas", + "hook", + "hurl", + "invite", + "juice", + "manage", + "moral", + "possess", + "raw", + "rebel", + "royal", + "scale", + "scary", + "several", + "slight", + "stubborn", + "swell", + "talent", + "tea", + "terrible", + "thread", + "torment", + "trickle", + "usually", + "vast", + "violence", + "weave", + "acid", + "agony", + "ashamed", + "awe", + "belly", + "blend", + "blush", + "character", + "cheat", + "common", + "company", + "coward", + "creak", + "danger", + "deadly", + "defense", + "define", + "depend", + "desperate", + "destination", + "dew", + "duck", + "dusty", + "embarrass", + "engine", + "example", + "explore", + "foe", + "freely", + "frustrate", + "generation", + "glove", + "guilty", + "health", + "hurry", + "idiot", + "impossible", + "inhale", + "jaw", + "kingdom", + "mention", + "mist", + "moan", + "mumble", + "mutter", + "observe", + "ode", + "pathetic", + "pattern", + "pie", + "prefer", + "puff", + "rape", + "rare", + "revenge", + "rude", + "scrape", + "spiral", + "squeeze", + "strain", + "sunset", + "suspend", + "sympathy", + "thigh", + "throne", + "total", + "unseen", + "weapon", + "weary", +} + +var n int64 = 1626 + +func IndexOf(slice []string, value string) int64 { + for p, v := range slice { + if v == value { + return int64(p) + } + } + return -1 +} + +func MnemonicEncode(message string) []string { + var out []string + + for i := 0; i < len(message); i += (len(message) / 8) { + x := message[i : i+8] + bit, _ := strconv.ParseInt(x, 16, 64) + w1 := (bit % n) + w2 := ((bit / n) + w1) % n + w3 := ((bit / n / n) + w2) % n + out = append(out, words[w1], words[w2], words[w3]) + } + return out +} + +func MnemonicDecode(wordsar []string) string { + var out string + for i := 0; i < len(wordsar); i += 3 { + word1 := wordsar[i] + word2 := wordsar[i+1] + word3 := wordsar[i+2] + w1 := IndexOf(words, word1) + w2 := IndexOf(words, word2) + w3 := IndexOf(words, word3) + + y := (w2 - w1) % n + z := (w3 - w2) % n + + // Golang handles modulo with negative numbers different then most languages + if z < 0 { + z += n + } + if y < 0 { + y += n + } + x := w1 + n*(y) + n*n*(z) + out += fmt.Sprintf("%08x", x) + } + return out +} diff --git a/ethutil/mnemonic_test.go b/ethutil/mnemonic_test.go new file mode 100644 index 000000000..ccf3f9883 --- /dev/null +++ b/ethutil/mnemonic_test.go @@ -0,0 +1,74 @@ +package ethutil + +import ( + "testing" +) + +func TestMnDecode(t *testing.T) { + words := []string{ + "ink", + "balance", + "gain", + "fear", + "happen", + "melt", + "mom", + "surface", + "stir", + "bottle", + "unseen", + "expression", + "important", + "curl", + "grant", + "fairy", + "across", + "back", + "figure", + "breast", + "nobody", + "scratch", + "worry", + "yesterday", + } + encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338" + result := MnemonicDecode(words) + if encode != result { + t.Error("We expected", encode, "got", result, "instead") + } +} +func TestMnEncode(t *testing.T) { + encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338" + result := []string{ + "ink", + "balance", + "gain", + "fear", + "happen", + "melt", + "mom", + "surface", + "stir", + "bottle", + "unseen", + "expression", + "important", + "curl", + "grant", + "fairy", + "across", + "back", + "figure", + "breast", + "nobody", + "scratch", + "worry", + "yesterday", + } + words := MnemonicEncode(encode) + for i, word := range words { + if word != result[i] { + t.Error("Mnenonic does not match:", words, result) + } + } +} -- cgit v1.2.3 From 272b135b74931fd159d4e50a2328ea32a73f787c Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 9 Apr 2014 10:40:55 -0400 Subject: One more line of comment --- ethutil/mnemonic.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ethutil') diff --git a/ethutil/mnemonic.go b/ethutil/mnemonic.go index d21c20f00..cc58de84a 100644 --- a/ethutil/mnemonic.go +++ b/ethutil/mnemonic.go @@ -5,6 +5,7 @@ import ( "strconv" ) +// Electrum word list var words []string = []string{ "like", "just", @@ -1673,6 +1674,7 @@ func MnemonicDecode(wordsar []string) string { z := (w3 - w2) % n // Golang handles modulo with negative numbers different then most languages + // The modulo can be negative, we don't want that. if z < 0 { z += n } -- cgit v1.2.3 From 5714a82778c688a332f4b42bee28e99fb2b30e0b Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 9 Apr 2014 11:06:30 -0400 Subject: Small tweaks to mnemonic --- ethutil/mnemonic.go | 106 ++++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 52 deletions(-) (limited to 'ethutil') diff --git a/ethutil/mnemonic.go b/ethutil/mnemonic.go index cc58de84a..00f089e3b 100644 --- a/ethutil/mnemonic.go +++ b/ethutil/mnemonic.go @@ -5,6 +5,60 @@ import ( "strconv" ) +// TODO: See if we can refactor this into a shared util lib if we need it multiple times +func IndexOf(slice []string, value string) int64 { + for p, v := range slice { + if v == value { + return int64(p) + } + } + return -1 +} + +func MnemonicEncode(message string) []string { + var out []string + n := int64(len(words)) + + for i := 0; i < len(message); i += (len(message) / 8) { + x := message[i : i+8] + bit, _ := strconv.ParseInt(x, 16, 64) + w1 := (bit % n) + w2 := ((bit / n) + w1) % n + w3 := ((bit / n / n) + w2) % n + out = append(out, words[w1], words[w2], words[w3]) + } + return out +} + +func MnemonicDecode(wordsar []string) string { + var out string + n := int64(len(words)) + + for i := 0; i < len(wordsar); i += 3 { + word1 := wordsar[i] + word2 := wordsar[i+1] + word3 := wordsar[i+2] + w1 := IndexOf(words, word1) + w2 := IndexOf(words, word2) + w3 := IndexOf(words, word3) + + y := (w2 - w1) % n + z := (w3 - w2) % n + + // Golang handles modulo with negative numbers different then most languages + // The modulo can be negative, we don't want that. + if z < 0 { + z += n + } + if y < 0 { + y += n + } + x := w1 + n*(y) + n*n*(z) + out += fmt.Sprintf("%08x", x) + } + return out +} + // Electrum word list var words []string = []string{ "like", @@ -1634,55 +1688,3 @@ var words []string = []string{ "weapon", "weary", } - -var n int64 = 1626 - -func IndexOf(slice []string, value string) int64 { - for p, v := range slice { - if v == value { - return int64(p) - } - } - return -1 -} - -func MnemonicEncode(message string) []string { - var out []string - - for i := 0; i < len(message); i += (len(message) / 8) { - x := message[i : i+8] - bit, _ := strconv.ParseInt(x, 16, 64) - w1 := (bit % n) - w2 := ((bit / n) + w1) % n - w3 := ((bit / n / n) + w2) % n - out = append(out, words[w1], words[w2], words[w3]) - } - return out -} - -func MnemonicDecode(wordsar []string) string { - var out string - for i := 0; i < len(wordsar); i += 3 { - word1 := wordsar[i] - word2 := wordsar[i+1] - word3 := wordsar[i+2] - w1 := IndexOf(words, word1) - w2 := IndexOf(words, word2) - w3 := IndexOf(words, word3) - - y := (w2 - w1) % n - z := (w3 - w2) % n - - // Golang handles modulo with negative numbers different then most languages - // The modulo can be negative, we don't want that. - if z < 0 { - z += n - } - if y < 0 { - y += n - } - x := w1 + n*(y) + n*n*(z) - out += fmt.Sprintf("%08x", x) - } - return out -} -- cgit v1.2.3 From 4f2e9c2640eaa962d085db329221bfd6f1a1799e Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 12:27:25 -0400 Subject: Check for nil --- ethutil/rlp.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/rlp.go b/ethutil/rlp.go index e6c75696e..d95ace425 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -186,7 +186,12 @@ func Encode(object interface{}) []byte { case byte: buff.Write(Encode(big.NewInt(int64(t)))) case *big.Int: - buff.Write(Encode(t.Bytes())) + // Not sure how this is possible while we check for + if t == nil { + buff.WriteByte(0xc0) + } else { + buff.Write(Encode(t.Bytes())) + } case []byte: if len(t) == 1 && t[0] <= 0x7f { buff.Write(t) -- cgit v1.2.3 From 0fccbeabcc3b8c110ce3712e5488ad99245f92ee Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 12:28:34 -0400 Subject: No longer return a list, but raw bytes --- ethutil/parsing.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 16ed2d06d..a9d50e425 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -131,13 +131,14 @@ func Instr(instr string) (int, []string, error) { // Script compilation functions // Compiles strings to machine code -func Assemble(instructions ...interface{}) (script []string) { - script = make([]string, len(instructions)) +func Assemble(instructions ...interface{}) (script []byte) { + //script = make([]string, len(instructions)) - for i, val := range instructions { + for _, val := range instructions { instr, _ := CompileInstr(val) - script[i] = string(instr) + //script[i] = string(instr) + script = append(script, instr...) } return -- cgit v1.2.3 From 6a530ea3717e592407737c6cd2ebeba0200c9cd8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 14:40:12 -0400 Subject: Call fixed --- ethutil/parsing.go | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index a9d50e425..0de396654 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -1,8 +1,8 @@ package ethutil import ( + _ "fmt" "math/big" - "strconv" ) // Op codes @@ -98,11 +98,16 @@ func CompileInstr(s interface{}) ([]byte, error) { // Assume regular bytes during compilation if !success { num.SetBytes([]byte(str)) + } else { + // tmp fix for 32 bytes + n := BigToBytes(num, 256) + return n, nil } return num.Bytes(), nil case int: - return big.NewInt(int64(s.(int))).Bytes(), nil + num := BigToBytes(big.NewInt(int64(s.(int))), 256) + return num, nil case []byte: return BigD(s.([]byte)).Bytes(), nil } @@ -110,25 +115,6 @@ func CompileInstr(s interface{}) ([]byte, error) { return nil, nil } -func Instr(instr string) (int, []string, error) { - - base := new(big.Int) - base.SetString(instr, 0) - - args := make([]string, 7) - for i := 0; i < 7; i++ { - // int(int(val) / int(math.Pow(256,float64(i)))) % 256 - exp := BigPow(256, i) - num := new(big.Int) - num.Div(base, exp) - - args[i] = num.Mod(num, big.NewInt(256)).String() - } - op, _ := strconv.Atoi(args[0]) - - return op, args[1:7], nil -} - // Script compilation functions // Compiles strings to machine code func Assemble(instructions ...interface{}) (script []byte) { -- cgit v1.2.3 From 891f7259091cba0fe5e8c9370e7b0b1055b56683 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 18:14:19 -0400 Subject: Added better address format --- ethutil/parsing.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 0de396654..278414982 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -51,7 +51,10 @@ var OpCodes = map[string]byte{ "GASLIMIT": 0x45, // 0x50 range - 'storage' and execution - "PUSH": 0x50, + "PUSH": 0x50, + + "PUSH20": 0x80, + "POP": 0x51, "DUP": 0x52, "SWAP": 0x53, -- cgit v1.2.3 From 086acd122b59071255b0c1cfae569748b1d7427a Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 12 Apr 2014 00:13:42 -0400 Subject: Added pre processing of script data --- ethutil/parsing.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 278414982..328704cae 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -3,6 +3,7 @@ package ethutil import ( _ "fmt" "math/big" + "regexp" ) // Op codes @@ -132,3 +133,33 @@ func Assemble(instructions ...interface{}) (script []byte) { return } + +/* +Prepocessing function that takes init and main apart: +init() { + // something +} + +main() { + // main something +} +*/ +func PreProcess(data string) (mainInput, initInput string) { + reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" + mainReg := regexp.MustCompile("main" + reg) + initReg := regexp.MustCompile("init" + reg) + + main := mainReg.FindStringSubmatch(data) + if len(main) > 0 { + mainInput = main[1] + } else { + mainInput = data + } + + init := initReg.FindStringSubmatch(data) + if len(init) > 0 { + initInput = init[1] + } + + return +} -- cgit v1.2.3 From 11c26e32114dabc6524ad9fb1f868440f5d3fff3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 11:50:17 +0200 Subject: Implemented ethereum package reader --- ethutil/package.go | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 ethutil/package.go (limited to 'ethutil') diff --git a/ethutil/package.go b/ethutil/package.go new file mode 100644 index 000000000..e5df989d2 --- /dev/null +++ b/ethutil/package.go @@ -0,0 +1,123 @@ +package ethutil + +import ( + "archive/zip" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "strings" +) + +// Manifest object +// +// The manifest object holds all the relevant information supplied with the +// the manifest specified in the package +type Manifest struct { + Entry string + Height, Width int +} + +// External package +// +// External package contains the main html file and manifest +type ExtPackage struct { + EntryHtml string + Manifest *Manifest +} + +// Read file +// +// Read a given compressed file and returns the read bytes. +// Returns an error otherwise +func ReadFile(f *zip.File) ([]byte, error) { + rc, err := f.Open() + if err != nil { + return nil, err + } + defer rc.Close() + + content, err := ioutil.ReadAll(rc) + if err != nil { + return nil, err + } + + return content, nil +} + +// Reads manifest +// +// Reads and returns a manifest object. Returns error otherwise +func ReadManifest(m []byte) (*Manifest, error) { + var manifest Manifest + + dec := json.NewDecoder(strings.NewReader(string(m))) + if err := dec.Decode(&manifest); err == io.EOF { + } else if err != nil { + return nil, err + } + + return &manifest, nil +} + +// Find file in archive +// +// Returns the index of the given file name if it exists. -1 if file not found +func FindFileInArchive(fn string, files []*zip.File) (index int) { + index = -1 + // Find the manifest first + for i, f := range files { + if f.Name == fn { + index = i + } + } + + return +} + +// Open package +// +// Opens a prepared ethereum package +// Reads the manifest file and determines file contents and returns and +// the external package. +func OpenPackage(fn string) (*ExtPackage, error) { + r, err := zip.OpenReader(fn) + if err != nil { + return nil, err + } + defer r.Close() + + manifestIndex := FindFileInArchive("manifest.json", r.File) + + if manifestIndex < 0 { + return nil, fmt.Errorf("No manifest file found in archive") + } + + f, err := ReadFile(r.File[manifestIndex]) + if err != nil { + return nil, err + } + + manifest, err := ReadManifest(f) + if err != nil { + return nil, err + } + + if manifest.Entry == "" { + return nil, fmt.Errorf("Entry file specified but appears to be empty: %s", manifest.Entry) + } + + entryIndex := FindFileInArchive(manifest.Entry, r.File) + if entryIndex < 0 { + return nil, fmt.Errorf("Entry file not found: '%s'", manifest.Entry) + } + + f, err = ReadFile(r.File[entryIndex]) + if err != nil { + return nil, err + } + + extPackage := &ExtPackage{string(f), manifest} + + return extPackage, nil +} -- cgit v1.2.3 From 3a9a252f6e44abb0f45f57a46c0fa91e2f73c545 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 11:51:04 +0200 Subject: Fixed minor issue with gas and added state object init --- ethutil/parsing.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- ethutil/parsing_test.go | 41 ++++++++++++++++++++--------------------- 2 files changed, 67 insertions(+), 23 deletions(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 328704cae..9775cf328 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -3,7 +3,7 @@ package ethutil import ( _ "fmt" "math/big" - "regexp" + _ "regexp" ) // Op codes @@ -143,7 +143,6 @@ init() { main() { // main something } -*/ func PreProcess(data string) (mainInput, initInput string) { reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" mainReg := regexp.MustCompile("main" + reg) @@ -163,3 +162,49 @@ func PreProcess(data string) (mainInput, initInput string) { return } +*/ + +// Very, very dumb parser. Heed no attention :-) +func FindFor(blockMatcher, input string) string { + curCount := -1 + length := len(blockMatcher) + matchfst := rune(blockMatcher[0]) + var currStr string + + for i, run := range input { + // Find init + if curCount == -1 && run == matchfst && input[i:i+length] == blockMatcher { + curCount = 0 + } else if curCount > -1 { + if run == '{' { + curCount++ + if curCount == 1 { + continue + } + } else if run == '}' { + curCount-- + if curCount == 0 { + // we are done + curCount = -1 + break + } + } + + if curCount > 0 { + currStr += string(run) + } + } + } + + return currStr +} + +func PreProcess(data string) (mainInput, initInput string) { + mainInput = FindFor("main", data) + if mainInput == "" { + mainInput = data + } + initInput = FindFor("init", data) + + return +} diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go index 6b59777e6..a9ad347dd 100644 --- a/ethutil/parsing_test.go +++ b/ethutil/parsing_test.go @@ -1,32 +1,31 @@ package ethutil -/* import ( - "math" + "fmt" "testing" ) -func TestCompile(t *testing.T) { - instr, err := CompileInstr("PUSH") - - if err != nil { - t.Error("Failed compiling instruction") +func TestPreProcess(t *testing.T) { + main, init := PreProcess(` + init { + // init + if a > b { + if { + } + } } - calc := (48 + 0*256 + 0*int64(math.Pow(256, 2))) - if BigD(instr).Int64() != calc { - t.Error("Expected", calc, ", got:", instr) + main { + // main + if a > b { + if c > d { + } + } } -} - -func TestValidInstr(t *testing.T) { - op, args, err := Instr("68163") - if err != nil { - t.Error("Error decoding instruction") - } - -} + `) -func TestInvalidInstr(t *testing.T) { + fmt.Println("main") + fmt.Println(main) + fmt.Println("init") + fmt.Println(init) } -*/ -- cgit v1.2.3 From ef7f3f36e261bc500016dac0a703c5b7931a1721 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 15:53:34 +0200 Subject: Renamed CALLDATA to CALLDATALOAD --- ethutil/parsing.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 9775cf328..514fd92cd 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -39,7 +39,7 @@ var OpCodes = map[string]byte{ "ORIGIN": 0x32, "CALLER": 0x33, "CALLVALUE": 0x34, - "CALLDATA": 0x35, + "CALLDATALOAD": 0x35, "CALLDATASIZE": 0x36, "GASPRICE": 0x38, -- cgit v1.2.3 From 0f93da400ab7fd238eb7286f14c229d780f73636 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Apr 2014 01:47:55 +0200 Subject: Added new state object change echanism --- ethutil/value.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index 04131aba9..b7756f9b1 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -20,7 +20,12 @@ func (val *Value) String() string { } func NewValue(val interface{}) *Value { - return &Value{Val: val} + t := val + if v, ok := val.(*Value); ok { + t = v.Val + } + + return &Value{Val: t} } func (val *Value) Type() reflect.Kind { -- cgit v1.2.3 From 16e52327a4baa5547c38965fce53b3ff40b98173 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 16:50:44 +0200 Subject: Upped version number --- ethutil/big.go | 8 ++++++++ ethutil/common.go | 7 +++++++ ethutil/config.go | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/big.go b/ethutil/big.go index 1a3902fa3..c0488a71f 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -50,3 +50,11 @@ func BigCopy(src *big.Int) (ret *big.Int) { return } + +func BigMax(x, y *big.Int) *big.Int { + if x.Cmp(y) <= 0 { + return x + } + + return y +} diff --git a/ethutil/common.go b/ethutil/common.go index c63af29a6..d0ee7b538 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -38,5 +38,12 @@ var ( Big1 = big.NewInt(1) Big2 = big.NewInt(1) Big0 = big.NewInt(0) + Big32 = big.NewInt(32) Big256 = big.NewInt(0xff) ) + +func CreateAddress(b []byte, nonce *big.Int) []byte { + addrBytes := append(b, nonce.Bytes()...) + + return Sha3Bin(addrBytes)[12:] +} diff --git a/ethutil/config.go b/ethutil/config.go index 54b066fb9..86c0a855d 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -48,7 +48,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } -- cgit v1.2.3 From 338b6980915c990c6e6287a7249ddd98e6be20eb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 17:15:44 +0200 Subject: Refactoring and added documentation comments --- ethutil/asm.go | 193 ++++++++++++++++++++++++++++++++++++++++++++ ethutil/asm_test.go | 31 +++++++ ethutil/big.go | 31 ++++--- ethutil/bytes.go | 13 ++- ethutil/common.go | 12 ++- ethutil/config.go | 9 ++- ethutil/parsing.go | 210 ------------------------------------------------ ethutil/parsing_test.go | 31 ------- ethutil/rlp.go | 10 --- 9 files changed, 273 insertions(+), 267 deletions(-) create mode 100644 ethutil/asm.go create mode 100644 ethutil/asm_test.go delete mode 100644 ethutil/parsing.go delete mode 100644 ethutil/parsing_test.go (limited to 'ethutil') diff --git a/ethutil/asm.go b/ethutil/asm.go new file mode 100644 index 000000000..a547d3ac1 --- /dev/null +++ b/ethutil/asm.go @@ -0,0 +1,193 @@ +package ethutil + +import ( + _ "fmt" + "math/big" + _ "regexp" +) + +// Op codes +var OpCodes = map[string]byte{ + // 0x0 range - arithmetic ops + "STOP": 0x00, + "ADD": 0x01, + "MUL": 0x02, + "SUB": 0x03, + "DIV": 0x04, + "SDIV": 0x05, + "MOD": 0x06, + "SMOD": 0x07, + "EXP": 0x08, + "NEG": 0x09, + "LT": 0x0a, + "GT": 0x0b, + "EQ": 0x0c, + "NOT": 0x0d, + + // 0x10 range - bit ops + "AND": 0x10, + "OR": 0x11, + "XOR": 0x12, + "BYTE": 0x13, + + // 0x20 range - crypto + "SHA3": 0x20, + + // 0x30 range - closure state + "ADDRESS": 0x30, + "BALANCE": 0x31, + "ORIGIN": 0x32, + "CALLER": 0x33, + "CALLVALUE": 0x34, + "CALLDATALOAD": 0x35, + "CALLDATASIZE": 0x36, + "GASPRICE": 0x38, + + // 0x40 range - block operations + "PREVHASH": 0x40, + "COINBASE": 0x41, + "TIMESTAMP": 0x42, + "NUMBER": 0x43, + "DIFFICULTY": 0x44, + "GASLIMIT": 0x45, + + // 0x50 range - 'storage' and execution + "PUSH": 0x50, + + "PUSH20": 0x80, + + "POP": 0x51, + "DUP": 0x52, + "SWAP": 0x53, + "MLOAD": 0x54, + "MSTORE": 0x55, + "MSTORE8": 0x56, + "SLOAD": 0x57, + "SSTORE": 0x58, + "JUMP": 0x59, + "JUMPI": 0x5a, + "PC": 0x5b, + "MSIZE": 0x5c, + + // 0x60 range - closures + "CREATE": 0x60, + "CALL": 0x61, + "RETURN": 0x62, + + // 0x70 range - other + "LOG": 0x70, + "SUICIDE": 0x7f, +} + +// Is op code +// +// Check whether the given string matches anything in +// the OpCode list +func IsOpCode(s string) bool { + for key, _ := range OpCodes { + if key == s { + return true + } + } + return false +} + +// Compile instruction +// +// Attempts to compile and parse the given instruction in "s" +// and returns the byte sequence +func CompileInstr(s interface{}) ([]byte, error) { + switch s.(type) { + case string: + str := s.(string) + isOp := IsOpCode(str) + if isOp { + return []byte{OpCodes[str]}, nil + } + + num := new(big.Int) + _, success := num.SetString(str, 0) + // Assume regular bytes during compilation + if !success { + num.SetBytes([]byte(str)) + } else { + // tmp fix for 32 bytes + n := BigToBytes(num, 256) + return n, nil + } + + return num.Bytes(), nil + case int: + num := BigToBytes(big.NewInt(int64(s.(int))), 256) + return num, nil + case []byte: + return BigD(s.([]byte)).Bytes(), nil + } + + return nil, nil +} + +// Assemble +// +// Assembles the given instructions and returns EVM byte code +func Assemble(instructions ...interface{}) (script []byte) { + //script = make([]string, len(instructions)) + + for _, val := range instructions { + instr, _ := CompileInstr(val) + + //script[i] = string(instr) + script = append(script, instr...) + } + + return +} + +// Pre process script +// +// Take data apart and attempt to find the "init" section and +// "main" section. `main { } init { }` +func PreProcess(data string) (mainInput, initInput string) { + mainInput = getCodeSectionFor("main", data) + if mainInput == "" { + mainInput = data + } + initInput = getCodeSectionFor("init", data) + + return +} + +// Very, very dumb parser. Heed no attention :-) +func getCodeSectionFor(blockMatcher, input string) string { + curCount := -1 + length := len(blockMatcher) + matchfst := rune(blockMatcher[0]) + var currStr string + + for i, run := range input { + // Find init + if curCount == -1 && run == matchfst && input[i:i+length] == blockMatcher { + curCount = 0 + } else if curCount > -1 { + if run == '{' { + curCount++ + if curCount == 1 { + continue + } + } else if run == '}' { + curCount-- + if curCount == 0 { + // we are done + curCount = -1 + break + } + } + + if curCount > 0 { + currStr += string(run) + } + } + } + + return currStr +} diff --git a/ethutil/asm_test.go b/ethutil/asm_test.go new file mode 100644 index 000000000..a9ad347dd --- /dev/null +++ b/ethutil/asm_test.go @@ -0,0 +1,31 @@ +package ethutil + +import ( + "fmt" + "testing" +) + +func TestPreProcess(t *testing.T) { + main, init := PreProcess(` + init { + // init + if a > b { + if { + } + } + } + + main { + // main + if a > b { + if c > d { + } + } + } + `) + + fmt.Println("main") + fmt.Println(main) + fmt.Println("init") + fmt.Println(init) +} diff --git a/ethutil/big.go b/ethutil/big.go index c0488a71f..891d476ad 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -12,7 +12,9 @@ var BigTrue *big.Int = big.NewInt(1) // False var BigFalse *big.Int = big.NewInt(0) -// Returns the power of two integers +// 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)) @@ -20,7 +22,9 @@ func BigPow(a, b int) *big.Int { return c } -// Like big.NewInt(uint64); this takes a string instead. +// Big +// +// Shortcut for new(big.Int).SetString(..., 0) func Big(num string) *big.Int { n := new(big.Int) n.SetString(num, 0) @@ -28,7 +32,9 @@ func Big(num string) *big.Int { return n } -// Like big.NewInt(uint64); this takes a byte buffer instead. +// BigD +// +// Shortcut for new(big.Int).SetBytes(...) func BigD(data []byte) *big.Int { n := new(big.Int) n.SetBytes(data) @@ -36,21 +42,26 @@ func BigD(data []byte) *big.Int { return n } +// 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) return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) } -// Functions like the build in "copy" function -// but works on big integers -func BigCopy(src *big.Int) (ret *big.Int) { - ret = new(big.Int) - ret.Add(ret, src) - - return +// 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 x diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 40903a5f1..957fa254a 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -6,6 +6,9 @@ import ( "fmt" ) +// 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) @@ -16,6 +19,9 @@ func NumberToBytes(num interface{}, bits int) []byte { 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 @@ -32,7 +38,9 @@ func BytesToNumber(b []byte) uint64 { return number } -// Read variable integer in big endian +// Read variable int +// +// Read a variable length number in big endian byte order func ReadVarint(reader *bytes.Reader) (ret uint64) { if reader.Len() == 8 { var num uint64 @@ -55,6 +63,9 @@ func ReadVarint(reader *bytes.Reader) (ret uint64) { return ret } +// Binary length +// +// Returns the true binary length of the given number func BinaryLength(num int) int { if num == 0 { return 0 diff --git a/ethutil/common.go b/ethutil/common.go index d0ee7b538..983ea5d1b 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -5,16 +5,20 @@ import ( "math/big" ) +// The different number of units var ( Ether = BigPow(10, 18) Finney = BigPow(10, 15) Szabo = BigPow(10, 12) - Vito = BigPow(10, 9) + Vita = BigPow(10, 9) Turing = BigPow(10, 6) Eins = BigPow(10, 3) Wei = big.NewInt(1) ) +// Currency to string +// +// Returns a string representing a human readable format func CurrencyToString(num *big.Int) string { switch { case num.Cmp(Ether) >= 0: @@ -23,8 +27,8 @@ func CurrencyToString(num *big.Int) string { return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) case num.Cmp(Szabo) >= 0: return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) - case num.Cmp(Vito) >= 0: - return fmt.Sprintf("%v Vito", new(big.Int).Div(num, Vito)) + case num.Cmp(Vita) >= 0: + return fmt.Sprintf("%v Vita", new(big.Int).Div(num, Vita)) case num.Cmp(Turing) >= 0: return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing)) case num.Cmp(Eins) >= 0: @@ -34,6 +38,7 @@ func CurrencyToString(num *big.Int) string { return fmt.Sprintf("%v Wei", num) } +// Common big integers often used var ( Big1 = big.NewInt(1) Big2 = big.NewInt(1) @@ -42,6 +47,7 @@ var ( Big256 = big.NewInt(0xff) ) +// Creates an ethereum address given the bytes and the nonce func CreateAddress(b []byte, nonce *big.Int) []byte { addrBytes := append(b, nonce.Bytes()...) diff --git a/ethutil/config.go b/ethutil/config.go index 86c0a855d..323773ba7 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -9,6 +9,7 @@ import ( "runtime" ) +// Log types available type LogType byte const ( @@ -16,7 +17,7 @@ const ( LogTypeFile = 2 ) -// Config struct isn't exposed +// Config struct type config struct { Db Database @@ -31,7 +32,9 @@ type config struct { var Config *config -// Read config doesn't read anything yet. +// Read config +// +// Initialize the global Config variable with default settings func ReadConfig(base string) *config { if Config == nil { usr, _ := user.Current() @@ -56,6 +59,8 @@ func ReadConfig(base string) *config { return Config } +// Set client string +// func (c *config) SetClientString(str string) { Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS) } diff --git a/ethutil/parsing.go b/ethutil/parsing.go deleted file mode 100644 index 514fd92cd..000000000 --- a/ethutil/parsing.go +++ /dev/null @@ -1,210 +0,0 @@ -package ethutil - -import ( - _ "fmt" - "math/big" - _ "regexp" -) - -// Op codes -var OpCodes = map[string]byte{ - // 0x0 range - arithmetic ops - "STOP": 0x00, - "ADD": 0x01, - "MUL": 0x02, - "SUB": 0x03, - "DIV": 0x04, - "SDIV": 0x05, - "MOD": 0x06, - "SMOD": 0x07, - "EXP": 0x08, - "NEG": 0x09, - "LT": 0x0a, - "GT": 0x0b, - "EQ": 0x0c, - "NOT": 0x0d, - - // 0x10 range - bit ops - "AND": 0x10, - "OR": 0x11, - "XOR": 0x12, - "BYTE": 0x13, - - // 0x20 range - crypto - "SHA3": 0x20, - - // 0x30 range - closure state - "ADDRESS": 0x30, - "BALANCE": 0x31, - "ORIGIN": 0x32, - "CALLER": 0x33, - "CALLVALUE": 0x34, - "CALLDATALOAD": 0x35, - "CALLDATASIZE": 0x36, - "GASPRICE": 0x38, - - // 0x40 range - block operations - "PREVHASH": 0x40, - "COINBASE": 0x41, - "TIMESTAMP": 0x42, - "NUMBER": 0x43, - "DIFFICULTY": 0x44, - "GASLIMIT": 0x45, - - // 0x50 range - 'storage' and execution - "PUSH": 0x50, - - "PUSH20": 0x80, - - "POP": 0x51, - "DUP": 0x52, - "SWAP": 0x53, - "MLOAD": 0x54, - "MSTORE": 0x55, - "MSTORE8": 0x56, - "SLOAD": 0x57, - "SSTORE": 0x58, - "JUMP": 0x59, - "JUMPI": 0x5a, - "PC": 0x5b, - "MSIZE": 0x5c, - - // 0x60 range - closures - "CREATE": 0x60, - "CALL": 0x61, - "RETURN": 0x62, - - // 0x70 range - other - "LOG": 0x70, - "SUICIDE": 0x7f, -} - -func IsOpCode(s string) bool { - for key, _ := range OpCodes { - if key == s { - return true - } - } - return false -} - -func CompileInstr(s interface{}) ([]byte, error) { - switch s.(type) { - case string: - str := s.(string) - isOp := IsOpCode(str) - if isOp { - return []byte{OpCodes[str]}, nil - } - - num := new(big.Int) - _, success := num.SetString(str, 0) - // Assume regular bytes during compilation - if !success { - num.SetBytes([]byte(str)) - } else { - // tmp fix for 32 bytes - n := BigToBytes(num, 256) - return n, nil - } - - return num.Bytes(), nil - case int: - num := BigToBytes(big.NewInt(int64(s.(int))), 256) - return num, nil - case []byte: - return BigD(s.([]byte)).Bytes(), nil - } - - return nil, nil -} - -// Script compilation functions -// Compiles strings to machine code -func Assemble(instructions ...interface{}) (script []byte) { - //script = make([]string, len(instructions)) - - for _, val := range instructions { - instr, _ := CompileInstr(val) - - //script[i] = string(instr) - script = append(script, instr...) - } - - return -} - -/* -Prepocessing function that takes init and main apart: -init() { - // something -} - -main() { - // main something -} -func PreProcess(data string) (mainInput, initInput string) { - reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" - mainReg := regexp.MustCompile("main" + reg) - initReg := regexp.MustCompile("init" + reg) - - main := mainReg.FindStringSubmatch(data) - if len(main) > 0 { - mainInput = main[1] - } else { - mainInput = data - } - - init := initReg.FindStringSubmatch(data) - if len(init) > 0 { - initInput = init[1] - } - - return -} -*/ - -// Very, very dumb parser. Heed no attention :-) -func FindFor(blockMatcher, input string) string { - curCount := -1 - length := len(blockMatcher) - matchfst := rune(blockMatcher[0]) - var currStr string - - for i, run := range input { - // Find init - if curCount == -1 && run == matchfst && input[i:i+length] == blockMatcher { - curCount = 0 - } else if curCount > -1 { - if run == '{' { - curCount++ - if curCount == 1 { - continue - } - } else if run == '}' { - curCount-- - if curCount == 0 { - // we are done - curCount = -1 - break - } - } - - if curCount > 0 { - currStr += string(run) - } - } - } - - return currStr -} - -func PreProcess(data string) (mainInput, initInput string) { - mainInput = FindFor("main", data) - if mainInput == "" { - mainInput = data - } - initInput = FindFor("init", data) - - return -} diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go deleted file mode 100644 index a9ad347dd..000000000 --- a/ethutil/parsing_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package ethutil - -import ( - "fmt" - "testing" -) - -func TestPreProcess(t *testing.T) { - main, init := PreProcess(` - init { - // init - if a > b { - if { - } - } - } - - main { - // main - if a > b { - if c > d { - } - } - } - `) - - fmt.Println("main") - fmt.Println(main) - fmt.Println("init") - fmt.Println(init) -} diff --git a/ethutil/rlp.go b/ethutil/rlp.go index d95ace425..69f80a0a6 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -26,16 +26,6 @@ func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { return Encode(rlpData) } -/* -func FromBin(data []byte) uint64 { - if len(data) == 0 { - return 0 - } - - return FromBin(data[:len(data)-1])*256 + uint64(data[len(data)-1]) -} -*/ - const ( RlpEmptyList = 0x80 RlpEmptyStr = 0x40 -- cgit v1.2.3 From 21f8806eed4c926ea31144c0e061ca8e0bbe35f8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 18:01:37 +0200 Subject: Moved assembler stage to the mutan compiler --- ethutil/asm.go | 193 ---------------------------------------------------- ethutil/asm_test.go | 31 --------- 2 files changed, 224 deletions(-) delete mode 100644 ethutil/asm.go delete mode 100644 ethutil/asm_test.go (limited to 'ethutil') diff --git a/ethutil/asm.go b/ethutil/asm.go deleted file mode 100644 index a547d3ac1..000000000 --- a/ethutil/asm.go +++ /dev/null @@ -1,193 +0,0 @@ -package ethutil - -import ( - _ "fmt" - "math/big" - _ "regexp" -) - -// Op codes -var OpCodes = map[string]byte{ - // 0x0 range - arithmetic ops - "STOP": 0x00, - "ADD": 0x01, - "MUL": 0x02, - "SUB": 0x03, - "DIV": 0x04, - "SDIV": 0x05, - "MOD": 0x06, - "SMOD": 0x07, - "EXP": 0x08, - "NEG": 0x09, - "LT": 0x0a, - "GT": 0x0b, - "EQ": 0x0c, - "NOT": 0x0d, - - // 0x10 range - bit ops - "AND": 0x10, - "OR": 0x11, - "XOR": 0x12, - "BYTE": 0x13, - - // 0x20 range - crypto - "SHA3": 0x20, - - // 0x30 range - closure state - "ADDRESS": 0x30, - "BALANCE": 0x31, - "ORIGIN": 0x32, - "CALLER": 0x33, - "CALLVALUE": 0x34, - "CALLDATALOAD": 0x35, - "CALLDATASIZE": 0x36, - "GASPRICE": 0x38, - - // 0x40 range - block operations - "PREVHASH": 0x40, - "COINBASE": 0x41, - "TIMESTAMP": 0x42, - "NUMBER": 0x43, - "DIFFICULTY": 0x44, - "GASLIMIT": 0x45, - - // 0x50 range - 'storage' and execution - "PUSH": 0x50, - - "PUSH20": 0x80, - - "POP": 0x51, - "DUP": 0x52, - "SWAP": 0x53, - "MLOAD": 0x54, - "MSTORE": 0x55, - "MSTORE8": 0x56, - "SLOAD": 0x57, - "SSTORE": 0x58, - "JUMP": 0x59, - "JUMPI": 0x5a, - "PC": 0x5b, - "MSIZE": 0x5c, - - // 0x60 range - closures - "CREATE": 0x60, - "CALL": 0x61, - "RETURN": 0x62, - - // 0x70 range - other - "LOG": 0x70, - "SUICIDE": 0x7f, -} - -// Is op code -// -// Check whether the given string matches anything in -// the OpCode list -func IsOpCode(s string) bool { - for key, _ := range OpCodes { - if key == s { - return true - } - } - return false -} - -// Compile instruction -// -// Attempts to compile and parse the given instruction in "s" -// and returns the byte sequence -func CompileInstr(s interface{}) ([]byte, error) { - switch s.(type) { - case string: - str := s.(string) - isOp := IsOpCode(str) - if isOp { - return []byte{OpCodes[str]}, nil - } - - num := new(big.Int) - _, success := num.SetString(str, 0) - // Assume regular bytes during compilation - if !success { - num.SetBytes([]byte(str)) - } else { - // tmp fix for 32 bytes - n := BigToBytes(num, 256) - return n, nil - } - - return num.Bytes(), nil - case int: - num := BigToBytes(big.NewInt(int64(s.(int))), 256) - return num, nil - case []byte: - return BigD(s.([]byte)).Bytes(), nil - } - - return nil, nil -} - -// Assemble -// -// Assembles the given instructions and returns EVM byte code -func Assemble(instructions ...interface{}) (script []byte) { - //script = make([]string, len(instructions)) - - for _, val := range instructions { - instr, _ := CompileInstr(val) - - //script[i] = string(instr) - script = append(script, instr...) - } - - return -} - -// Pre process script -// -// Take data apart and attempt to find the "init" section and -// "main" section. `main { } init { }` -func PreProcess(data string) (mainInput, initInput string) { - mainInput = getCodeSectionFor("main", data) - if mainInput == "" { - mainInput = data - } - initInput = getCodeSectionFor("init", data) - - return -} - -// Very, very dumb parser. Heed no attention :-) -func getCodeSectionFor(blockMatcher, input string) string { - curCount := -1 - length := len(blockMatcher) - matchfst := rune(blockMatcher[0]) - var currStr string - - for i, run := range input { - // Find init - if curCount == -1 && run == matchfst && input[i:i+length] == blockMatcher { - curCount = 0 - } else if curCount > -1 { - if run == '{' { - curCount++ - if curCount == 1 { - continue - } - } else if run == '}' { - curCount-- - if curCount == 0 { - // we are done - curCount = -1 - break - } - } - - if curCount > 0 { - currStr += string(run) - } - } - } - - return currStr -} diff --git a/ethutil/asm_test.go b/ethutil/asm_test.go deleted file mode 100644 index a9ad347dd..000000000 --- a/ethutil/asm_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package ethutil - -import ( - "fmt" - "testing" -) - -func TestPreProcess(t *testing.T) { - main, init := PreProcess(` - init { - // init - if a > b { - if { - } - } - } - - main { - // main - if a > b { - if c > d { - } - } - } - `) - - fmt.Println("main") - fmt.Println(main) - fmt.Println("init") - fmt.Println(init) -} -- cgit v1.2.3 From 38d6b67b5cfbfb63620a244ea01b5b534917128f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Apr 2014 12:36:27 +0200 Subject: Fixed state problem --- ethutil/bytes.go | 10 ++++++++++ ethutil/trie.go | 19 +++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 957fa254a..500368017 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -73,3 +73,13 @@ func BinaryLength(num int) int { 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 +} diff --git a/ethutil/trie.go b/ethutil/trie.go index c67f750bc..4d088ccff 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -119,14 +119,29 @@ type Trie struct { cache *Cache } +func copyRoot(root interface{}) interface{} { + var prevRootCopy interface{} + if b, ok := root.([]byte); ok { + prevRootCopy = CopyBytes(b) + } else { + prevRootCopy = root + } + + return prevRootCopy +} + func NewTrie(db Database, Root interface{}) *Trie { - return &Trie{cache: NewCache(db), Root: Root, prevRoot: Root} + // Make absolute sure the root is copied + r := copyRoot(Root) + p := copyRoot(Root) + + return &Trie{cache: NewCache(db), Root: r, prevRoot: p} } // Save the cached value to the database. func (t *Trie) Sync() { t.cache.Commit() - t.prevRoot = t.Root + t.prevRoot = copyRoot(t.Root) } func (t *Trie) Undo() { -- cgit v1.2.3 From e798f221dd9d6aaffaa709d559f01a41447e4896 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 2 May 2014 13:55:43 +0200 Subject: Added public interface --- ethutil/script.go | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 ethutil/script.go (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go new file mode 100644 index 000000000..620658025 --- /dev/null +++ b/ethutil/script.go @@ -0,0 +1,41 @@ +package ethutil + +import ( + "fmt" + "github.com/obscuren/mutan" + "strings" +) + +// General compile function +func Compile(script string) ([]byte, error) { + byteCode, errors := mutan.Compile(strings.NewReader(script), false) + if len(errors) > 0 { + var errs string + for _, er := range errors { + if er != nil { + errs += er.Error() + } + } + return nil, fmt.Errorf("%v", errs) + } + + return byteCode, nil +} + +func CompileScript(script string) ([]byte, []byte, error) { + // Preprocess + mainInput, initInput := mutan.PreProcess(script) + // Compile main script + mainScript, err := Compile(mainInput) + if err != nil { + return nil, nil, err + } + + // Compile init script + initScript, err := Compile(initInput) + if err != nil { + return nil, nil, err + } + + return mainScript, initScript, nil +} -- cgit v1.2.3 From 9b1f11695d544b99ba0b7ddedc4ac561a68d8197 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 5 May 2014 14:20:20 +0200 Subject: Get rid of that annoying number that keeps popping up in stdout --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 323773ba7..609200649 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -139,7 +139,7 @@ func (log *Logger) Infoln(v ...interface{}) { return } - fmt.Println(len(log.logSys)) + //fmt.Println(len(log.logSys)) for _, logger := range log.logSys { logger.Println(v...) } -- cgit v1.2.3 From 14a6e6a9cea48bcc7f6d5286e4f85b1a0cce84d8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 15:48:17 +0200 Subject: Added the ability to submit byte code for contracts instead of Mutan code. --- ethutil/bytes.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 500368017..b298675a2 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -83,3 +83,8 @@ func CopyBytes(b []byte) (copiedBytes []byte) { return } + +func IsHex(str string) bool { + l := len(str) + return l >= 4 && l%2 == 0 && str[0:2] == "0x" +} -- cgit v1.2.3 From fedd4c906ff9f6139cb2d88e4f1adefbf6ea81a6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 15:55:26 +0200 Subject: bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 609200649..382396ceb 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -51,7 +51,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5 RC1"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } -- cgit v1.2.3 From afe83af219c2146e022f6665cf30097b582d3e79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 9 May 2014 16:09:28 +0200 Subject: Moved seeding and moved manifest --- ethutil/config.go | 1 - 1 file changed, 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 382396ceb..db07e1d18 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -27,7 +27,6 @@ type config struct { Ver string ClientString string Pubkey []byte - Seed bool } var Config *config -- cgit v1.2.3 From c03bf14e02fe7f13944b71f5370b1d7bd5978ffe Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 10 May 2014 02:01:09 +0200 Subject: Fixed some tests --- ethutil/common_test.go | 2 +- ethutil/rlp_test.go | 15 ++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) (limited to 'ethutil') diff --git a/ethutil/common_test.go b/ethutil/common_test.go index b5c733ff3..8031f08ab 100644 --- a/ethutil/common_test.go +++ b/ethutil/common_test.go @@ -26,7 +26,7 @@ func TestCommon(t *testing.T) { t.Error("Got", szabo) } - if vito != "10 Vito" { + if vito != "10 Vita" { t.Error("Got", vito) } diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 9e8127aab..095c01ecc 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,7 +2,6 @@ package ethutil import ( "bytes" - "fmt" "math/big" "reflect" "testing" @@ -56,15 +55,6 @@ func TestValue(t *testing.T) { } } -func TestEncodeDecodeMaran(t *testing.T) { - b := NewValue([]interface{}{"dog", 15, []interface{}{"cat", "cat", []interface{}{}}, 1024, "tachikoma"}) - a := b.Encode() - fmt.Println("voor maran", a) - f, i := Decode(a, 0) - fmt.Println("voor maran 2", f) - fmt.Println(i) -} - func TestEncode(t *testing.T) { strRes := "\x83dog" bytes := Encode("dog") @@ -131,7 +121,10 @@ func TestEncodeDecodeBytes(t *testing.T) { func TestEncodeZero(t *testing.T) { b := NewValue(0).Encode() - fmt.Println(b) + exp := []byte{0xc0} + if bytes.Compare(b, exp) == 0 { + t.Error("Expected", exp, "got", b) + } } func BenchmarkEncodeDecode(b *testing.B) { -- cgit v1.2.3 From dbf8645aafb19837d01b939ba9b1d3e1a2fffbf9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 10 May 2014 02:02:54 +0200 Subject: Bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index db07e1d18..5e36b06d2 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,7 +50,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5 RC1"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC2"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } -- cgit v1.2.3 From d3d9ed62e26247c680e23a94fd84b078d45cb3bc Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 10 May 2014 16:23:07 +0200 Subject: Upgraded to new mutan --- ethutil/config.go | 2 +- ethutil/script.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 5e36b06d2..feab23e02 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,7 +50,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC2"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC3"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } diff --git a/ethutil/script.go b/ethutil/script.go index 620658025..94e401406 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -24,7 +24,7 @@ func Compile(script string) ([]byte, error) { func CompileScript(script string) ([]byte, []byte, error) { // Preprocess - mainInput, initInput := mutan.PreProcess(script) + mainInput, initInput := mutan.PreParse(script) // Compile main script mainScript, err := Compile(mainInput) if err != nil { -- cgit v1.2.3 From 86d6aba0127d6f35f5dda50d08dff05581031701 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 13 May 2014 16:36:43 +0200 Subject: Bumped --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index feab23e02..07dc85f08 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,7 +50,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC3"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC4"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } -- cgit v1.2.3 From f4fa0d48cb10f925908062357be965c54370cba9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 13:54:40 +0200 Subject: Moved keyring to ethutil & removed old methods. Implements #20 --- ethutil/db.go | 2 +- ethutil/key.go | 19 ---------- ethutil/keypair.go | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 20 deletions(-) delete mode 100644 ethutil/key.go create mode 100644 ethutil/keypair.go (limited to 'ethutil') diff --git a/ethutil/db.go b/ethutil/db.go index abbf4a2b0..e02a80fca 100644 --- a/ethutil/db.go +++ b/ethutil/db.go @@ -4,7 +4,7 @@ package ethutil type Database interface { Put(key []byte, value []byte) Get(key []byte) ([]byte, error) - GetKeys() []*Key + //GetKeys() []*Key Delete(key []byte) error LastKnownTD() []byte Close() diff --git a/ethutil/key.go b/ethutil/key.go deleted file mode 100644 index ec195f213..000000000 --- a/ethutil/key.go +++ /dev/null @@ -1,19 +0,0 @@ -package ethutil - -type Key struct { - PrivateKey []byte - PublicKey []byte -} - -func NewKeyFromBytes(data []byte) *Key { - val := NewValueFromBytes(data) - return &Key{val.Get(0).Bytes(), val.Get(1).Bytes()} -} - -func (k *Key) Address() []byte { - return Sha3Bin(k.PublicKey[1:])[12:] -} - -func (k *Key) RlpEncode() []byte { - return EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() -} diff --git a/ethutil/keypair.go b/ethutil/keypair.go new file mode 100644 index 000000000..cf5882e2c --- /dev/null +++ b/ethutil/keypair.go @@ -0,0 +1,109 @@ +package ethutil + +import ( + "github.com/obscuren/secp256k1-go" +) + +type KeyPair struct { + PrivateKey []byte + PublicKey []byte + + // The associated account + account *StateObject +} + +func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { + pubkey, err := secp256k1.GeneratePubKey(seckey) + if err != nil { + return nil, err + } + + return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil +} + +func NewKeyPairFromValue(val *Value) *KeyPair { + v, _ := NewKeyPairFromSec(val.Bytes()) + + return v +} + +func (k *KeyPair) Address() []byte { + return Sha3Bin(k.PublicKey[1:])[12:] +} + +func (k *KeyPair) RlpEncode() []byte { + return k.RlpValue().Encode() +} + +func (k *KeyPair) RlpValue() *Value { + return NewValue(k.PrivateKey) +} + +type KeyRing struct { + keys []*KeyPair +} + +func (k *KeyRing) Add(pair *KeyPair) { + k.keys = append(k.keys, pair) +} + +func (k *KeyRing) Get(i int) *KeyPair { + if len(k.keys) > i { + return k.keys[i] + } + + return nil +} + +func (k *KeyRing) Len() int { + return len(k.keys) +} + +func (k *KeyRing) NewKeyPair(sec []byte) (*KeyPair, error) { + keyPair, err := NewKeyPairFromSec(sec) + if err != nil { + return nil, err + } + + k.Add(keyPair) + Config.Db.Put([]byte("KeyRing"), k.RlpValue().Encode()) + + return keyPair, nil +} + +func (k *KeyRing) Reset() { + Config.Db.Put([]byte("KeyRing"), nil) + k.keys = nil +} + +func (k *KeyRing) RlpValue() *Value { + v := EmptyValue() + for _, keyPair := range k.keys { + v.Append(keyPair.RlpValue()) + } + + return v +} + +// The public "singleton" keyring +var keyRing *KeyRing + +func GetKeyRing() *KeyRing { + if keyRing == nil { + keyRing = &KeyRing{} + + data, _ := Config.Db.Get([]byte("KeyRing")) + it := NewValueFromBytes(data).NewIterator() + for it.Next() { + v := it.Value() + + key, err := NewKeyPairFromSec(v.Bytes()) + if err != nil { + panic(err) + } + keyRing.Add(key) + } + } + + return keyRing +} -- cgit v1.2.3 From ad4ffdc9474aca48ab1d3d361797398f795a6d31 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 21:34:13 +0200 Subject: Bumped version --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 07dc85f08..b4bd9158e 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,7 +50,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC4"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC6"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } -- cgit v1.2.3 From 7bf2ae0b116fff0fede5b1455c5fda20caf98252 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 15 May 2014 14:05:15 +0200 Subject: Removed old tx pool notification system. Fixes #19 --- ethutil/reactor.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/reactor.go b/ethutil/reactor.go index f8084986c..7cf145245 100644 --- a/ethutil/reactor.go +++ b/ethutil/reactor.go @@ -46,6 +46,7 @@ func (e *ReactorEvent) Remove(ch chan React) { // Basic reactor resource type React struct { Resource interface{} + Event string } // The reactor basic engine. Acts as bridge @@ -81,6 +82,6 @@ func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) { func (reactor *ReactorEngine) Post(event string, resource interface{}) { ev := reactor.patterns[event] if ev != nil { - ev.Post(React{Resource: resource}) + ev.Post(React{Resource: resource, Event: event}) } } -- cgit v1.2.3 From 8730dfdcc2e2b40410a57385e4864d15f2f0336b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 17 May 2014 14:07:52 +0200 Subject: Changed how changes are being applied to states --- ethutil/config.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index b4bd9158e..296b72d9e 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -9,14 +9,6 @@ import ( "runtime" ) -// Log types available -type LogType byte - -const ( - LogTypeStdIn = 1 - LogTypeFile = 2 -) - // Config struct type config struct { Db Database @@ -34,7 +26,7 @@ var Config *config // Read config // // Initialize the global Config variable with default settings -func ReadConfig(base string) *config { +func ReadConfig(base string, logTypes LoggerType) *config { if Config == nil { usr, _ := user.Current() path := path.Join(usr.HomeDir, base) @@ -51,7 +43,7 @@ func ReadConfig(base string) *config { } Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC6"} - Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) + Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } -- cgit v1.2.3 From a2fb265563a3a6eb80efc5720bb0c6f3fec6f397 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 19 May 2014 17:02:16 +0200 Subject: Added a fatal method --- ethutil/config.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 296b72d9e..fd590fbdb 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -130,7 +130,6 @@ func (log *Logger) Infoln(v ...interface{}) { return } - //fmt.Println(len(log.logSys)) for _, logger := range log.logSys { logger.Println(v...) } @@ -145,3 +144,15 @@ func (log *Logger) Infof(format string, v ...interface{}) { logger.Printf(format, v...) } } + +func (log *Logger) Fatal(v ...interface{}) { + if log.logLevel > LogLevelInfo { + return + } + + for _, logger := range log.logSys { + logger.Println(v...) + } + + os.Exit(1) +} -- cgit v1.2.3 From 31e44c2ab959124cbcf2de45385373b9898727bc Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 20 May 2014 14:53:34 +0200 Subject: Change shorthands --- ethutil/common.go | 26 +++++++++++++------------- ethutil/common_test.go | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go index 983ea5d1b..771dfc723 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -7,13 +7,13 @@ import ( // The different number of units var ( - Ether = BigPow(10, 18) - Finney = BigPow(10, 15) - Szabo = BigPow(10, 12) - Vita = BigPow(10, 9) - Turing = BigPow(10, 6) - Eins = BigPow(10, 3) - Wei = big.NewInt(1) + 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 @@ -27,12 +27,12 @@ func CurrencyToString(num *big.Int) string { return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) case num.Cmp(Szabo) >= 0: return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) - case num.Cmp(Vita) >= 0: - return fmt.Sprintf("%v Vita", new(big.Int).Div(num, Vita)) - case num.Cmp(Turing) >= 0: - return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing)) - case num.Cmp(Eins) >= 0: - return fmt.Sprintf("%v Eins", new(big.Int).Div(num, Eins)) + case num.Cmp(Shannon) >= 0: + return fmt.Sprintf("%v Shannon", new(big.Int).Div(num, Shannon)) + case num.Cmp(Babbage) >= 0: + return fmt.Sprintf("%v Babbage", new(big.Int).Div(num, Babbage)) + case num.Cmp(Ada) >= 0: + return fmt.Sprintf("%v Ada", new(big.Int).Div(num, Ada)) } return fmt.Sprintf("%v Wei", num) diff --git a/ethutil/common_test.go b/ethutil/common_test.go index 8031f08ab..2667eaf3a 100644 --- a/ethutil/common_test.go +++ b/ethutil/common_test.go @@ -26,15 +26,15 @@ func TestCommon(t *testing.T) { t.Error("Got", szabo) } - if vito != "10 Vita" { + if vito != "10 Shannon" { t.Error("Got", vito) } - if turing != "10 Turing" { + if turing != "10 Babbage" { t.Error("Got", turing) } - if eins != "10 Eins" { + if eins != "10 Ada" { t.Error("Got", eins) } -- cgit v1.2.3 From c37b3cef7dc465832761b1da6761eeaa47e368d1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 17:08:53 +0200 Subject: Bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index fd590fbdb..abe86babe 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -42,7 +42,7 @@ func ReadConfig(base string, logTypes LoggerType) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC6"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC7"} Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } -- cgit v1.2.3 From 3c35ba7c31423da644c5fb73030af4673cff90ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 01:12:28 +0200 Subject: Fixed state overwriting issue --- ethutil/trie.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index 4d088ccff..c993e4d8f 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -3,8 +3,13 @@ package ethutil import ( "fmt" "reflect" + "sync" ) +func (s *Cache) Len() int { + return len(s.nodes) +} + // TODO // A StateObject is an object that has a state root // This is goig to be the object for the second level caching (the caching of object which have a state such as contracts) @@ -113,6 +118,7 @@ func (cache *Cache) Undo() { // Please note that the data isn't persisted unless `Sync` is // explicitly called. type Trie struct { + mut sync.RWMutex prevRoot interface{} Root interface{} //db Database @@ -157,12 +163,18 @@ func (t *Trie) Cache() *Cache { * Public (query) interface functions */ func (t *Trie) Update(key string, value string) { + t.mut.Lock() + defer t.mut.Unlock() + k := CompactHexDecode(key) t.Root = t.UpdateState(t.Root, k, value) } func (t *Trie) Get(key string) string { + t.mut.RLock() + defer t.mut.RUnlock() + k := CompactHexDecode(key) c := NewValue(t.GetState(t.Root, k)) -- cgit v1.2.3 From 8f5eddd0ba9287cfcdc0e1f114c3fb367e54c46c Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 14:04:19 +0200 Subject: Bumped --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index abe86babe..1b41c4634 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -42,7 +42,7 @@ func ReadConfig(base string, logTypes LoggerType) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC7"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC8"} Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } -- cgit v1.2.3 From 230aafbf66ba747fb3796810adf3b1680f368e73 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 17:35:26 +0200 Subject: Working on interop * Receipts after each transaction * Fee structure * Applying fees to miners --- ethutil/config.go | 10 ++++++++-- ethutil/value.go | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 1b41c4634..e6cbde4b6 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -19,6 +19,7 @@ type config struct { Ver string ClientString string Pubkey []byte + Identifier string } var Config *config @@ -26,7 +27,7 @@ var Config *config // Read config // // Initialize the global Config variable with default settings -func ReadConfig(base string, logTypes LoggerType) *config { +func ReadConfig(base string, logTypes LoggerType, id string) *config { if Config == nil { usr, _ := user.Current() path := path.Join(usr.HomeDir, base) @@ -43,6 +44,7 @@ func ReadConfig(base string, logTypes LoggerType) *config { } Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC8"} + Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } @@ -53,7 +55,11 @@ func ReadConfig(base string, logTypes LoggerType) *config { // Set client string // func (c *config) SetClientString(str string) { - Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS) + id := runtime.GOOS + if len(c.Identifier) > 0 { + id = c.Identifier + } + Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, id) } type LoggerType byte diff --git a/ethutil/value.go b/ethutil/value.go index b7756f9b1..83600abc2 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -16,7 +16,7 @@ type Value struct { } func (val *Value) String() string { - return fmt.Sprintf("%q", val.Val) + return fmt.Sprintf("%x", val.Val) } func NewValue(val interface{}) *Value { -- cgit v1.2.3 From 3ebd7f1166f03f94117651d8e74b9603ee7d6966 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 26 May 2014 00:09:38 +0200 Subject: State snapshotting --- ethutil/trie_test.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 0be512d9f..d74d129ac 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,7 @@ package ethutil import ( - _ "fmt" + "fmt" "reflect" "testing" ) @@ -26,7 +26,6 @@ func (db *MemDatabase) Delete(key []byte) error { delete(db.db, string(key)) return nil } -func (db *MemDatabase) GetKeys() []*Key { return nil } func (db *MemDatabase) Print() {} func (db *MemDatabase) Close() {} func (db *MemDatabase) LastKnownTD() []byte { return nil } @@ -171,3 +170,17 @@ func TestTrieIterator(t *testing.T) { t.Errorf("Expected cached nodes to be deleted") } } + +func TestHashes(t *testing.T) { + _, trie := New() + trie.Update("cat", "dog") + trie.Update("ca", "dude") + trie.Update("doge", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ") + trie.Update("dog", "test") + trie.Update("test", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ") + fmt.Printf("%x\n", trie.Root) + trie.Delete("dog") + fmt.Printf("%x\n", trie.Root) + trie.Delete("test") + fmt.Printf("%x\n", trie.Root) +} -- cgit v1.2.3 From 1f3f76cb092e84bd2e90950f0d43d7657eae878e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 26 May 2014 00:38:53 +0200 Subject: bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index e6cbde4b6..40ab3aa69 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string, logTypes LoggerType, id string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC8"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC9"} Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") -- cgit v1.2.3 From 5cdfee51437532ccfb49e874fdbbea2702c3d13f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 27 May 2014 01:08:51 +0200 Subject: New Trie iterator --- ethutil/encoding.go | 15 +++++++++++++++ ethutil/trie.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ ethutil/trie_test.go | 22 ++++++++++------------ 3 files changed, 71 insertions(+), 12 deletions(-) (limited to 'ethutil') diff --git a/ethutil/encoding.go b/ethutil/encoding.go index 1f661947a..9fcdf3edf 100644 --- a/ethutil/encoding.go +++ b/ethutil/encoding.go @@ -59,3 +59,18 @@ func CompactHexDecode(str string) []int { return hexSlice } + +func DecodeCompact(key []int) string { + base := "0123456789abcdef" + var str string + + for _, v := range key { + if v < 16 { + str += string(base[v]) + } + } + + res, _ := hex.DecodeString(str) + + return string(res) +} diff --git a/ethutil/trie.go b/ethutil/trie.go index c993e4d8f..18d0a5f0a 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -442,6 +442,8 @@ type TrieIterator struct { shas [][]byte values []string + + lastNode []byte } func (t *Trie) NewIterator() *TrieIterator { @@ -513,3 +515,47 @@ func (it *TrieIterator) Key() string { func (it *TrieIterator) Value() string { return "" } + +type EachCallback func(key string, node *Value) + +func (it *TrieIterator) Each(cb EachCallback) { + it.fetchNode(nil, NewValue(it.trie.Root).Bytes(), cb) +} + +func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { + it.iterateNode(key, it.trie.cache.Get(node), cb) +} + +func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallback) { + if currentNode.Len() == 2 { + k := CompactDecode(currentNode.Get(0).Str()) + + if currentNode.Get(1).Str() == "" { + it.iterateNode(key, currentNode.Get(1), cb) + } else { + pk := append(key, k...) + + if k[len(k)-1] == 16 { + cb(DecodeCompact(pk), currentNode.Get(1)) + } else { + it.fetchNode(pk, currentNode.Get(1).Bytes(), cb) + } + } + } else { + for i := 0; i < currentNode.Len(); i++ { + pk := append(key, i) + if i == 16 && currentNode.Get(i).Len() != 0 { + cb(DecodeCompact(pk), currentNode.Get(i)) + } else { + if currentNode.Get(i).Str() == "" { + it.iterateNode(pk, currentNode.Get(i), cb) + } else { + val := currentNode.Get(i).Str() + if val != "" { + it.fetchNode(pk, []byte(val), cb) + } + } + } + } + } +} diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index d74d129ac..c89f2fbb7 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -154,7 +154,7 @@ func TestTrieDeleteWithValue(t *testing.T) { } -func TestTrieIterator(t *testing.T) { +func TestTriePurge(t *testing.T) { _, trie := New() trie.Update("c", LONG_WORD) trie.Update("ca", LONG_WORD) @@ -171,16 +171,14 @@ func TestTrieIterator(t *testing.T) { } } -func TestHashes(t *testing.T) { +func TestTrieIt(t *testing.T) { _, trie := New() - trie.Update("cat", "dog") - trie.Update("ca", "dude") - trie.Update("doge", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ") - trie.Update("dog", "test") - trie.Update("test", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ") - fmt.Printf("%x\n", trie.Root) - trie.Delete("dog") - fmt.Printf("%x\n", trie.Root) - trie.Delete("test") - fmt.Printf("%x\n", trie.Root) + trie.Update("c", LONG_WORD) + trie.Update("ca", LONG_WORD) + trie.Update("cat", LONG_WORD) + + it := trie.NewIterator() + it.Each(func(key string, node *Value) { + fmt.Println(key, ":", node.Str()) + }) } -- cgit v1.2.3 From a4285331601d9d77458d0d714dd110144c796023 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 27 May 2014 16:10:18 +0200 Subject: bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 40ab3aa69..a7c318e52 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string, logTypes LoggerType, id string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC9"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC10"} Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") -- cgit v1.2.3 From 65722aeeca0fed685a00d660ddd7bb667ac3be9b Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 13:14:56 +0200 Subject: Added StringToBytesFunc --- ethutil/bytes.go | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index b298675a2..075e40b4c 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -88,3 +88,13 @@ func IsHex(str string) bool { l := len(str) return l >= 4 && l%2 == 0 && str[0:2] == "0x" } + +func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) { + if str[0:2] == "0x" { + ret = FromHex(str[2:]) + } else { + ret = cb(str) + } + + return +} -- cgit v1.2.3 From a98e35d7a048850fb77fad49fff7364cf77a9bae Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 13:55:32 +0200 Subject: Length checking --- ethutil/bytes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 075e40b4c..1c7a43af8 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -90,7 +90,7 @@ func IsHex(str string) bool { } func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) { - if str[0:2] == "0x" { + if len(str) > 1 && str[0:2] == "0x" { ret = FromHex(str[2:]) } else { ret = cb(str) -- cgit v1.2.3 From 76a59274bfce73ec988131804c643be743d2b4d2 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 28 May 2014 16:19:25 +0200 Subject: Bump to RC11 --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index a7c318e52..fb270ce72 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string, logTypes LoggerType, id string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC10"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC11"} Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") -- cgit v1.2.3 From 4d987624867fc02a079d8355c28bad620db85f06 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 23:16:54 +0200 Subject: Fixed state object gas return --- ethutil/bytes.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 1c7a43af8..bd0df68ec 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "fmt" + "math/big" ) // Number to bytes @@ -98,3 +99,20 @@ func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) { 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:] == "\"" { + d.SetBytes([]byte(data[1 : len(data)-1])) + } else if len(data) > 1 && data[:2] == "0x" { + d.SetBytes(FromHex(data[2:])) + } else { + d.SetString(data, 0) + } + + return BigToBytes(d, 256) +} -- cgit v1.2.3 From 6c91ffcfbe1a7b469dc6a8a2676959f0000c925a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 11:48:37 +0200 Subject: Do not panic, but return nil instead --- ethutil/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index 83600abc2..c86c24a7a 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -176,7 +176,7 @@ func (val *Value) Get(idx int) *Value { } if idx < 0 { - panic("negative idx for Value Get") + return NewValue(nil) } return NewValue(d[idx]) -- cgit v1.2.3 From b15e03acd7d6184ad920292a10d9a2bbf2b59f00 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 16:57:40 +0200 Subject: Fixed issue with casting to smaller byte array --- ethutil/big.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ethutil') diff --git a/ethutil/big.go b/ethutil/big.go index 891d476ad..1c25a4784 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -49,6 +49,10 @@ func BigD(data []byte) *big.Int { 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()...) } -- cgit v1.2.3 From 17c825f53a2676ffe17fd7731f8f550aebcb56b0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 16:57:58 +0200 Subject: Peer changes broadcasting and minor miner fix --- ethutil/config.go | 54 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 13 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index fb270ce72..916b0d186 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -22,26 +22,54 @@ type config struct { Identifier string } +const defaultConf = ` +id = "" +port = 30303 +upnp = true +maxpeer = 10 +rpc = false +rpcport = 8080 +` + var Config *config +func ApplicationFolder(base string) string { + usr, _ := user.Current() + p := path.Join(usr.HomeDir, base) + + if len(base) > 0 { + //Check if the logging directory already exists, create it if not + _, err := os.Stat(p) + if err != nil { + if os.IsNotExist(err) { + log.Printf("Debug logging directory %s doesn't exist, creating it\n", p) + os.Mkdir(p, 0777) + + } + } + + iniFilePath := path.Join(p, "conf.ini") + _, err = os.Stat(iniFilePath) + if err != nil && os.IsNotExist(err) { + file, err := os.Create(iniFilePath) + if err != nil { + fmt.Println(err) + } else { + assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal", "assets") + file.Write([]byte(defaultConf + "\nasset_path = " + assetPath)) + } + } + } + + return p +} + // Read config // // Initialize the global Config variable with default settings func ReadConfig(base string, logTypes LoggerType, id string) *config { if Config == nil { - usr, _ := user.Current() - path := path.Join(usr.HomeDir, base) - - if len(base) > 0 { - //Check if the logging directory already exists, create it if not - _, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - log.Printf("Debug logging directory %s doesn't exist, creating it\n", path) - os.Mkdir(path, 0777) - } - } - } + path := ApplicationFolder(base) Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC11"} Config.Identifier = id -- cgit v1.2.3 From 9e8127accba0d926436d3c0adf65b91149a94783 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 19:51:19 +0200 Subject: woops --- ethutil/config.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 916b0d186..4f7820eed 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -1,7 +1,9 @@ package ethutil import ( + "flag" "fmt" + "github.com/rakyll/globalconf" "log" "os" "os/user" @@ -20,6 +22,8 @@ type config struct { ClientString string Pubkey []byte Identifier string + + conf *globalconf.GlobalConf } const defaultConf = ` @@ -67,11 +71,12 @@ func ApplicationFolder(base string) string { // Read config // // Initialize the global Config variable with default settings -func ReadConfig(base string, logTypes LoggerType, id string) *config { +func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id string) *config { if Config == nil { path := ApplicationFolder(base) Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC11"} + Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") @@ -90,6 +95,16 @@ func (c *config) SetClientString(str string) { Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, id) } +func (c *config) SetIdentifier(id string) { + c.Identifier = id + c.Set("id", id) +} + +func (c *config) Set(key, value string) { + f := &flag.Flag{Name: key, Value: &confValue{value}} + c.conf.Set("", f) +} + type LoggerType byte const ( @@ -190,3 +205,10 @@ func (log *Logger) Fatal(v ...interface{}) { os.Exit(1) } + +type confValue struct { + value string +} + +func (self confValue) String() string { return self.value } +func (self confValue) Set(s string) error { self.value = s; return nil } -- cgit v1.2.3 From 1153fd9a0c9310ab70f9b20914071e0184e8020a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 6 Jun 2014 12:12:27 +0200 Subject: Added Douglas and Einstan --- ethutil/common.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go index 771dfc723..c7973eb92 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -7,13 +7,15 @@ import ( // The different number of units var ( - 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) + 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 @@ -21,6 +23,10 @@ var ( // Returns a string representing a human readable format func CurrencyToString(num *big.Int) string { switch { + case num.Cmp(Douglas) >= 0: + return fmt.Sprintf("%v Douglas", new(big.Int).Div(num, Douglas)) + case num.Cmp(Einstein) >= 0: + return fmt.Sprintf("%v Einstein", new(big.Int).Div(num, Einstein)) case num.Cmp(Ether) >= 0: return fmt.Sprintf("%v Ether", new(big.Int).Div(num, Ether)) case num.Cmp(Finney) >= 0: -- cgit v1.2.3 From a51dfe89c05cc12b4a8483f683ff9f49b3a8f1bd Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 9 Jun 2014 22:23:30 +0200 Subject: bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 4f7820eed..e992bda12 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -75,7 +75,7 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s if Config == nil { path := ApplicationFolder(base) - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC11"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC12"} Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) -- cgit v1.2.3 From 2e6cf42011a4176a01f3e3f777cc1ddc4125511f Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:15:18 +0200 Subject: Fix BigMax to return the biggest number, not the smallest --- ethutil/big.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/big.go b/ethutil/big.go index 1c25a4784..7af6f7414 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -68,8 +68,8 @@ func BigCopy(src *big.Int) *big.Int { // Returns the maximum size big integer func BigMax(x, y *big.Int) *big.Int { if x.Cmp(y) <= 0 { - return x + return y } - return y + return x } -- cgit v1.2.3 From 97cc76214350b3ef9b0c15f53d06c684e01ede37 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 11 Jun 2014 10:28:18 +0200 Subject: Expose GasLimit to ethPub --- ethutil/common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go index c7973eb92..ddaf78f88 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -18,8 +18,8 @@ var ( Wei = big.NewInt(1) ) -// Currency to string // +// Currency to string // Returns a string representing a human readable format func CurrencyToString(num *big.Int) string { switch { -- cgit v1.2.3 From 3a9d7d318abb3cd01ecd012ae85da5e586436d65 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 12 Jun 2014 10:07:27 +0200 Subject: log changes --- ethutil/config.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index e992bda12..f935e8f75 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -75,11 +75,11 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s if Config == nil { path := ApplicationFolder(base) - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC12"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.12"} Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) - Config.SetClientString("/Ethereum(G)") + Config.SetClientString("Ethereum(G)") } return Config @@ -88,11 +88,9 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s // Set client string // func (c *config) SetClientString(str string) { - id := runtime.GOOS - if len(c.Identifier) > 0 { - id = c.Identifier - } - Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, id) + os := runtime.GOOS + cust := c.Identifier + Config.ClientString = fmt.Sprintf("%s/v%s/%s/%s/Go", str, c.Ver, cust, os) } func (c *config) SetIdentifier(id string) { -- cgit v1.2.3 From 81245473486dd680b7121d4b227ca8a57d07b4b1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 16:06:27 +0200 Subject: Moving a head closer to interop --- ethutil/common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go index ddaf78f88..f63ba5d83 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -47,7 +47,7 @@ func CurrencyToString(num *big.Int) string { // Common big integers often used var ( Big1 = big.NewInt(1) - Big2 = big.NewInt(1) + Big2 = big.NewInt(2) Big0 = big.NewInt(0) Big32 = big.NewInt(32) Big256 = big.NewInt(0xff) -- cgit v1.2.3 From 6d52da58d9337b786a0c869974daa91ce0e34a98 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 14 Jun 2014 15:44:13 +0200 Subject: Logging mechanism --- ethutil/config.go | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index f935e8f75..90037df87 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -143,12 +143,17 @@ func NewLogger(flag LoggerType, level int) *Logger { return &Logger{logSys: loggers, logLevel: level} } +func (self *Logger) SetLevel(level int) { + self.logLevel = level +} + func (log *Logger) AddLogSystem(logger LogSystem) { log.logSys = append(log.logSys, logger) } const ( - LogLevelDebug = iota + LogLevelSystem = iota + LogLevelDebug LogLevelInfo ) @@ -204,6 +209,26 @@ func (log *Logger) Fatal(v ...interface{}) { os.Exit(1) } +func (log *Logger) Println(level int, v ...interface{}) { + if log.logLevel > level { + return + } + + for _, logger := range log.logSys { + logger.Println(v...) + } +} + +func (log *Logger) Printf(level int, format string, v ...interface{}) { + if log.logLevel > level { + return + } + + for _, logger := range log.logSys { + logger.Printf(format, v...) + } +} + type confValue struct { value string } -- cgit v1.2.3 From dccef707280bd852ae536e69dea82ad0555ba0a9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 00:51:55 +0200 Subject: Method for creating a new key from scratch --- ethutil/keypair.go | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'ethutil') diff --git a/ethutil/keypair.go b/ethutil/keypair.go index cf5882e2c..29fb1bac5 100644 --- a/ethutil/keypair.go +++ b/ethutil/keypair.go @@ -12,6 +12,12 @@ type KeyPair struct { account *StateObject } +func GenerateNewKeyPair() (*KeyPair, error) { + _, prv := secp256k1.GenerateKeyPair() + + return NewKeyPairFromSec(prv) +} + func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { pubkey, err := secp256k1.GeneratePubKey(seckey) if err != nil { -- cgit v1.2.3 From 58a0e8e3e2979b07e9e8f697f947a412ac81e386 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 00:52:10 +0200 Subject: Changed RlpEncodable --- ethutil/rlp.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethutil') diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 69f80a0a6..195ef0efb 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -11,6 +11,7 @@ import ( type RlpEncodable interface { RlpEncode() []byte + RlpValue() []interface{} } type RlpEncoder struct { -- cgit v1.2.3 From ff0f15f7634ca713b0ce8232a8fa63eec5c3fad7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 18:25:21 +0200 Subject: bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 90037df87..a24c39bfe 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -75,7 +75,7 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s if Config == nil { path := ApplicationFolder(base) - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.12"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.13"} Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) -- cgit v1.2.3 From 34c8045d5be6488e9800c24e1e696e1b912f344c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Jun 2014 18:05:46 +0200 Subject: Fixed issue where JUMPI would do an equally check with 1 instead of GT --- ethutil/trie_test.go | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index c89f2fbb7..15dbc5567 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,12 @@ package ethutil import ( + "bytes" + "encoding/json" "fmt" + "io" + "io/ioutil" + "net/http" "reflect" "testing" ) @@ -171,14 +176,34 @@ func TestTriePurge(t *testing.T) { } } +type TestItem struct { + Name string + Inputs [][]string + Expectations string +} + func TestTrieIt(t *testing.T) { - _, trie := New() - trie.Update("c", LONG_WORD) - trie.Update("ca", LONG_WORD) - trie.Update("cat", LONG_WORD) + //_, trie := New() + resp, err := http.Get("https://raw.githubusercontent.com/ethereum/tests/master/trietest.json") + if err != nil { + t.Fail() + } - it := trie.NewIterator() - it.Each(func(key string, node *Value) { - fmt.Println(key, ":", node.Str()) - }) + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fail() + } + + dec := json.NewDecoder(bytes.NewReader(body)) + for { + var test TestItem + if err := dec.Decode(&test); err == io.EOF { + break + } else if err != nil { + t.Error("Fail something", err) + break + } + fmt.Println(test) + } } -- cgit v1.2.3 From 2fbcfd88249de8f55b7f06619d9003fadcc8e1e3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 11:55:05 +0200 Subject: Proper checks for multiple data items. Fixes #80 --- ethutil/bytes.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index bd0df68ec..5e3ee4a6f 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "fmt" "math/big" + "strings" ) // Number to bytes @@ -91,7 +92,7 @@ func IsHex(str string) bool { } func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) { - if len(str) > 1 && str[0:2] == "0x" { + if len(str) > 1 && str[0:2] == "0x" && !strings.Contains(str, "\n") { ret = FromHex(str[2:]) } else { ret = cb(str) -- cgit v1.2.3 From 7f94bd09ae5791836d94d4d9efb9e345212e49b6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 13:47:40 +0200 Subject: Return a single byte if byte get called --- ethutil/value.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index c86c24a7a..ddd864d8a 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -114,6 +114,8 @@ func (val *Value) Str() string { 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} } return []byte{} -- cgit v1.2.3 From c4af1340fac12397b6cc5c9f32a1bea4aa6400f5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 13:48:29 +0200 Subject: Updated test --- ethutil/trie_test.go | 44 ++++++++++++++------------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 15dbc5567..2937b1525 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,12 +1,7 @@ package ethutil import ( - "bytes" - "encoding/json" "fmt" - "io" - "io/ioutil" - "net/http" "reflect" "testing" ) @@ -176,34 +171,23 @@ func TestTriePurge(t *testing.T) { } } -type TestItem struct { - Name string - Inputs [][]string - Expectations string -} - func TestTrieIt(t *testing.T) { - //_, trie := New() - resp, err := http.Get("https://raw.githubusercontent.com/ethereum/tests/master/trietest.json") - if err != nil { - t.Fail() - } + _, trie := New() - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fail() + data := [][]string{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"ether", ""}, + {"dog", "puppy"}, + {"shaman", ""}, } - dec := json.NewDecoder(bytes.NewReader(body)) - for { - var test TestItem - if err := dec.Decode(&test); err == io.EOF { - break - } else if err != nil { - t.Error("Fail something", err) - break - } - fmt.Println(test) + for _, item := range data { + trie.Update(item[0], item[1]) } + + fmt.Printf("root %x", trie.Root) } -- cgit v1.2.3 From 7ad073fb30e92689942d938939223bd01cb5fe38 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:47:50 +0200 Subject: bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index a24c39bfe..a573e108b 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -75,7 +75,7 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s if Config == nil { path := ApplicationFolder(base) - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.13"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.14"} Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) -- cgit v1.2.3 From 299b50a0d4e1ec0d7c6e5820c4f68da4e424f382 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Jun 2014 02:40:25 +0200 Subject: Support serpent lang --- ethutil/script.go | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index 94e401406..c8b1da51c 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -3,23 +3,35 @@ package ethutil import ( "fmt" "github.com/obscuren/mutan" + "github.com/obscuren/serpent-go" "strings" ) // General compile function -func Compile(script string) ([]byte, error) { - byteCode, errors := mutan.Compile(strings.NewReader(script), false) - if len(errors) > 0 { - var errs string - for _, er := range errors { - if er != nil { - errs += er.Error() +func Compile(script string) (ret []byte, err error) { + c := strings.Split(script, "\n")[0] + + if c == "#!serpent" { + byteCode, err := serpent.Compile(script) + if err != nil { + return nil, err + } + + return byteCode, nil + } else { + byteCode, errors := mutan.Compile(strings.NewReader(script), false) + if len(errors) > 0 { + var errs string + for _, er := range errors { + if er != nil { + errs += er.Error() + } } + return nil, fmt.Errorf("%v", errs) } - return nil, fmt.Errorf("%v", errs) - } - return byteCode, nil + return byteCode, nil + } } func CompileScript(script string) ([]byte, []byte, error) { -- cgit v1.2.3 From 63157c798d613f1ca638597515bb89768e2c1aad Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 23 Jun 2014 12:55:38 +0100 Subject: refactor config (transitional). Details: - ReadConfig initialiser sets up global ethutil.Config via config file passed from wrappers - does not write out adhoc default (not meant to) but creates empty config file if it does not exist so that globalconf does not complain if persists a flag - default datadir and default config file set together with other flag defaults in wrappers - default assetpath set together with other command line flags defaults in gui wrapper (not in ethutil.Config or ui/ui_lib) - add EnvPrefix, to handle environment variable options too via globalconf - this is still transitional: global Config should just be a wrapper around globalconfig config handler and should be moved to go-ethereum - actual eth stack config should not be global instead config handled properly with explicit dependency injectioninto eth stack component instances --- ethutil/config.go | 200 ++++++------------------------------------------------ 1 file changed, 20 insertions(+), 180 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index a573e108b..52537ffa6 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -4,18 +4,14 @@ import ( "flag" "fmt" "github.com/rakyll/globalconf" - "log" - "os" - "os/user" - "path" "runtime" + "os" ) // Config struct type config struct { Db Database - Log *Logger ExecPath string Debug bool Ver string @@ -26,62 +22,31 @@ type config struct { conf *globalconf.GlobalConf } -const defaultConf = ` -id = "" -port = 30303 -upnp = true -maxpeer = 10 -rpc = false -rpcport = 8080 -` - var Config *config -func ApplicationFolder(base string) string { - usr, _ := user.Current() - p := path.Join(usr.HomeDir, base) - - if len(base) > 0 { - //Check if the logging directory already exists, create it if not - _, err := os.Stat(p) - if err != nil { - if os.IsNotExist(err) { - log.Printf("Debug logging directory %s doesn't exist, creating it\n", p) - os.Mkdir(p, 0777) - - } - } - - iniFilePath := path.Join(p, "conf.ini") - _, err = os.Stat(iniFilePath) - if err != nil && os.IsNotExist(err) { - file, err := os.Create(iniFilePath) - if err != nil { - fmt.Println(err) - } else { - assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal", "assets") - file.Write([]byte(defaultConf + "\nasset_path = " + assetPath)) - } - } - } - - return p -} - // Read config // -// Initialize the global Config variable with default settings -func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id string) *config { +// Initialize Config from Config File +func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) *config { if Config == nil { - path := ApplicationFolder(base) - - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.14"} - Config.conf = g - Config.Identifier = id - Config.Log = NewLogger(logTypes, LogLevelDebug) + // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags + _, err := os.Stat(ConfigFile) + if err != nil && os.IsNotExist(err) { + fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile) + os.Create(ConfigFile) + } + g, err := globalconf.NewWithOptions(&globalconf.Options{ + Filename: ConfigFile, + EnvPrefix: EnvPrefix, + }) + if err != nil { + fmt.Println(err) + } else { + g.ParseAll() + } + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.14", conf: g, Identifier: Identifier} Config.SetClientString("Ethereum(G)") } - return Config } @@ -98,137 +63,12 @@ func (c *config) SetIdentifier(id string) { c.Set("id", id) } +// provides persistence for flags func (c *config) Set(key, value string) { f := &flag.Flag{Name: key, Value: &confValue{value}} c.conf.Set("", f) } -type LoggerType byte - -const ( - LogFile = 0x1 - LogStd = 0x2 -) - -type LogSystem interface { - Println(v ...interface{}) - Printf(format string, v ...interface{}) -} - -type Logger struct { - logSys []LogSystem - logLevel int -} - -func NewLogger(flag LoggerType, level int) *Logger { - var loggers []LogSystem - - flags := log.LstdFlags - - if flag&LogFile > 0 { - file, err := os.OpenFile(path.Join(Config.ExecPath, "debug.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) - if err != nil { - log.Panic("unable to create file logger", err) - } - - log := log.New(file, "", flags) - - loggers = append(loggers, log) - } - if flag&LogStd > 0 { - log := log.New(os.Stdout, "", flags) - loggers = append(loggers, log) - } - - return &Logger{logSys: loggers, logLevel: level} -} - -func (self *Logger) SetLevel(level int) { - self.logLevel = level -} - -func (log *Logger) AddLogSystem(logger LogSystem) { - log.logSys = append(log.logSys, logger) -} - -const ( - LogLevelSystem = iota - LogLevelDebug - LogLevelInfo -) - -func (log *Logger) Debugln(v ...interface{}) { - if log.logLevel != LogLevelDebug { - return - } - - for _, logger := range log.logSys { - logger.Println(v...) - } -} - -func (log *Logger) Debugf(format string, v ...interface{}) { - if log.logLevel != LogLevelDebug { - return - } - - for _, logger := range log.logSys { - logger.Printf(format, v...) - } -} - -func (log *Logger) Infoln(v ...interface{}) { - if log.logLevel > LogLevelInfo { - return - } - - for _, logger := range log.logSys { - logger.Println(v...) - } -} - -func (log *Logger) Infof(format string, v ...interface{}) { - if log.logLevel > LogLevelInfo { - return - } - - for _, logger := range log.logSys { - logger.Printf(format, v...) - } -} - -func (log *Logger) Fatal(v ...interface{}) { - if log.logLevel > LogLevelInfo { - return - } - - for _, logger := range log.logSys { - logger.Println(v...) - } - - os.Exit(1) -} - -func (log *Logger) Println(level int, v ...interface{}) { - if log.logLevel > level { - return - } - - for _, logger := range log.logSys { - logger.Println(v...) - } -} - -func (log *Logger) Printf(level int, format string, v ...interface{}) { - if log.logLevel > level { - return - } - - for _, logger := range log.logSys { - logger.Printf(format, v...) - } -} - type confValue struct { value string } -- cgit v1.2.3 From b0dc50c2a0e25bf88901f3dd481f14bc3375adc5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 25 Jun 2014 17:26:34 +0200 Subject: New mutan implementation --- ethutil/script.go | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index c8b1da51c..235498df2 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -3,6 +3,7 @@ package ethutil import ( "fmt" "github.com/obscuren/mutan" + "github.com/obscuren/mutan/backends" "github.com/obscuren/serpent-go" "strings" ) @@ -19,7 +20,9 @@ func Compile(script string) (ret []byte, err error) { return byteCode, nil } else { - byteCode, errors := mutan.Compile(strings.NewReader(script), false) + compiler := mutan.NewCompiler(backend.NewEthereumBackend()) + byteCode, errors := compiler.Compile(strings.NewReader(script)) + //byteCode, errors := mutan.Compile(strings.NewReader(script), false) if len(errors) > 0 { var errs string for _, er := range errors { @@ -33,21 +36,3 @@ func Compile(script string) (ret []byte, err error) { return byteCode, nil } } - -func CompileScript(script string) ([]byte, []byte, error) { - // Preprocess - mainInput, initInput := mutan.PreParse(script) - // Compile main script - mainScript, err := Compile(mainInput) - if err != nil { - return nil, nil, err - } - - // Compile init script - initScript, err := Compile(initInput) - if err != nil { - return nil, nil, err - } - - return mainScript, initScript, nil -} -- cgit v1.2.3 From 0ed19d9f2024744ba93d0e34db6939766b3cfed5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Jun 2014 11:26:42 +0200 Subject: Logging, variable rearrangement --- ethutil/script.go | 1 - ethutil/trie.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index 235498df2..af4ca6a38 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -22,7 +22,6 @@ func Compile(script string) (ret []byte, err error) { } else { compiler := mutan.NewCompiler(backend.NewEthereumBackend()) byteCode, errors := compiler.Compile(strings.NewReader(script)) - //byteCode, errors := mutan.Compile(strings.NewReader(script), false) if len(errors) > 0 { var errs string for _, er := range errors { diff --git a/ethutil/trie.go b/ethutil/trie.go index 18d0a5f0a..0c1a6d260 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -47,7 +47,7 @@ func (cache *Cache) Put(v interface{}) interface{} { value := NewValue(v) enc := value.Encode() - if len(enc) >= 32 { + if len(enc) < 32 { sha := Sha3Bin(enc) cache.nodes[string(sha)] = NewNode(sha, value, true) -- cgit v1.2.3 From 853053a3b204ddf4ae935e70e0aa5b5d8994493e Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 26 Jun 2014 18:45:57 +0100 Subject: go fmt --- ethutil/config.go | 26 +++++++++++++------------- ethutil/encoding_test.go | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 52537ffa6..aa4ae9c3e 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -4,8 +4,8 @@ import ( "flag" "fmt" "github.com/rakyll/globalconf" - "runtime" "os" + "runtime" ) // Config struct @@ -29,21 +29,21 @@ var Config *config // Initialize Config from Config File func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) *config { if Config == nil { - // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags - _, err := os.Stat(ConfigFile) - if err != nil && os.IsNotExist(err) { + // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags + _, err := os.Stat(ConfigFile) + if err != nil && os.IsNotExist(err) { 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, + os.Create(ConfigFile) + } + g, err := globalconf.NewWithOptions(&globalconf.Options{ + Filename: ConfigFile, + EnvPrefix: EnvPrefix, }) if err != nil { - fmt.Println(err) - } else { - g.ParseAll() - } + fmt.Println(err) + } else { + g.ParseAll() + } Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.14", conf: g, Identifier: Identifier} Config.SetClientString("Ethereum(G)") } diff --git a/ethutil/encoding_test.go b/ethutil/encoding_test.go index cbfbc0eaf..10e1995c0 100644 --- a/ethutil/encoding_test.go +++ b/ethutil/encoding_test.go @@ -64,4 +64,4 @@ func TestCompactDecode(t *testing.T) { if !CompareIntSlice(res, exp) { t.Error("even terminated compact decode. Expected", exp, "got", res) } -} \ No newline at end of file +} -- cgit v1.2.3 From d551a75c35027a3cf6344293923cdcdab61d5f38 Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 26 Jun 2014 21:20:02 +0100 Subject: bump v5.15 --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index aa4ae9c3e..b253aa203 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -44,7 +44,7 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.14", conf: g, Identifier: Identifier} + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier} Config.SetClientString("Ethereum(G)") } return Config -- cgit v1.2.3 From 8119d77a21d3973fe6379c5d57f393dda8fce392 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 27 Jun 2014 00:08:19 +0200 Subject: :-( --- ethutil/trie.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index 0c1a6d260..18d0a5f0a 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -47,7 +47,7 @@ func (cache *Cache) Put(v interface{}) interface{} { value := NewValue(v) enc := value.Encode() - if len(enc) < 32 { + if len(enc) >= 32 { sha := Sha3Bin(enc) cache.nodes[string(sha)] = NewNode(sha, value, true) -- cgit v1.2.3 From 79009ca074d77561c655b65254103b4070b74c69 Mon Sep 17 00:00:00 2001 From: zelig Date: Fri, 27 Jun 2014 15:56:45 +0100 Subject: transitional ethutil.ReadConfig fixes in ethchain tests (they still fail! FIXME :) --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index aa4ae9c3e..b253aa203 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -44,7 +44,7 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.14", conf: g, Identifier: Identifier} + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier} Config.SetClientString("Ethereum(G)") } return Config -- cgit v1.2.3 From 7489fb784e1dfc780017b105a01fe49d00228c34 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 15:56:19 +0100 Subject: move ethutil helper slice functions -> slice --- ethutil/slice.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 ethutil/slice.go (limited to 'ethutil') diff --git a/ethutil/slice.go b/ethutil/slice.go new file mode 100644 index 000000000..67f43705d --- /dev/null +++ b/ethutil/slice.go @@ -0,0 +1,28 @@ +package ethutil + +import ( + "strconv" +) + +// Helper function for comparing slices +func CompareIntSlice(a, b []int) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} + +// Returns the amount of nibbles that match each other from 0 ... +func MatchingNibbleLength(a, b []int) int { + i := 0 + for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { + i += 1 + } + + return i +} -- cgit v1.2.3 From 5c1e0a6dc4e49154c185503ef7c8e96328dd6492 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 15:56:40 +0100 Subject: move ethutil hex conversion functions to bytes --- ethutil/bytes.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 5e3ee4a6f..c2817946b 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -3,6 +3,7 @@ package ethutil import ( "bytes" "encoding/binary" + "encoding/hex" "fmt" "math/big" "strings" @@ -91,9 +92,18 @@ func IsHex(str string) bool { 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 = FromHex(str[2:]) + ret = Hex2Bytes(str[2:]) } else { ret = cb(str) } @@ -110,7 +120,7 @@ func FormatData(data string) []byte { if data[0:1] == "\"" && data[len(data)-1:] == "\"" { d.SetBytes([]byte(data[1 : len(data)-1])) } else if len(data) > 1 && data[:2] == "0x" { - d.SetBytes(FromHex(data[2:])) + d.SetBytes(Hex2Bytes(data[2:])) } else { d.SetString(data, 0) } -- cgit v1.2.3 From 1db3e2241efe2a358b9c28c21fb2cb7c2f1e55a6 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 15:59:35 +0100 Subject: move ethutil/mnemonic to ethcrypto - electrum word list now sourced from file --- ethutil/mnemonic.go | 1690 ---------------------------------------------- ethutil/mnemonic_test.go | 74 -- 2 files changed, 1764 deletions(-) delete mode 100644 ethutil/mnemonic.go delete mode 100644 ethutil/mnemonic_test.go (limited to 'ethutil') diff --git a/ethutil/mnemonic.go b/ethutil/mnemonic.go deleted file mode 100644 index 00f089e3b..000000000 --- a/ethutil/mnemonic.go +++ /dev/null @@ -1,1690 +0,0 @@ -package ethutil - -import ( - "fmt" - "strconv" -) - -// TODO: See if we can refactor this into a shared util lib if we need it multiple times -func IndexOf(slice []string, value string) int64 { - for p, v := range slice { - if v == value { - return int64(p) - } - } - return -1 -} - -func MnemonicEncode(message string) []string { - var out []string - n := int64(len(words)) - - for i := 0; i < len(message); i += (len(message) / 8) { - x := message[i : i+8] - bit, _ := strconv.ParseInt(x, 16, 64) - w1 := (bit % n) - w2 := ((bit / n) + w1) % n - w3 := ((bit / n / n) + w2) % n - out = append(out, words[w1], words[w2], words[w3]) - } - return out -} - -func MnemonicDecode(wordsar []string) string { - var out string - n := int64(len(words)) - - for i := 0; i < len(wordsar); i += 3 { - word1 := wordsar[i] - word2 := wordsar[i+1] - word3 := wordsar[i+2] - w1 := IndexOf(words, word1) - w2 := IndexOf(words, word2) - w3 := IndexOf(words, word3) - - y := (w2 - w1) % n - z := (w3 - w2) % n - - // Golang handles modulo with negative numbers different then most languages - // The modulo can be negative, we don't want that. - if z < 0 { - z += n - } - if y < 0 { - y += n - } - x := w1 + n*(y) + n*n*(z) - out += fmt.Sprintf("%08x", x) - } - return out -} - -// Electrum word list -var words []string = []string{ - "like", - "just", - "love", - "know", - "never", - "want", - "time", - "out", - "there", - "make", - "look", - "eye", - "down", - "only", - "think", - "heart", - "back", - "then", - "into", - "about", - "more", - "away", - "still", - "them", - "take", - "thing", - "even", - "through", - "long", - "always", - "world", - "too", - "friend", - "tell", - "try", - "hand", - "thought", - "over", - "here", - "other", - "need", - "smile", - "again", - "much", - "cry", - "been", - "night", - "ever", - "little", - "said", - "end", - "some", - "those", - "around", - "mind", - "people", - "girl", - "leave", - "dream", - "left", - "turn", - "myself", - "give", - "nothing", - "really", - "off", - "before", - "something", - "find", - "walk", - "wish", - "good", - "once", - "place", - "ask", - "stop", - "keep", - "watch", - "seem", - "everything", - "wait", - "got", - "yet", - "made", - "remember", - "start", - "alone", - "run", - "hope", - "maybe", - "believe", - "body", - "hate", - "after", - "close", - "talk", - "stand", - "own", - "each", - "hurt", - "help", - "home", - "god", - "soul", - "new", - "many", - "two", - "inside", - "should", - "true", - "first", - "fear", - "mean", - "better", - "play", - "another", - "gone", - "change", - "use", - "wonder", - "someone", - "hair", - "cold", - "open", - "best", - "any", - "behind", - "happen", - "water", - "dark", - "laugh", - "stay", - "forever", - "name", - "work", - "show", - "sky", - "break", - "came", - "deep", - "door", - "put", - "black", - "together", - "upon", - "happy", - "such", - "great", - "white", - "matter", - "fill", - "past", - "please", - "burn", - "cause", - "enough", - "touch", - "moment", - "soon", - "voice", - "scream", - "anything", - "stare", - "sound", - "red", - "everyone", - "hide", - "kiss", - "truth", - "death", - "beautiful", - "mine", - "blood", - "broken", - "very", - "pass", - "next", - "forget", - "tree", - "wrong", - "air", - "mother", - "understand", - "lip", - "hit", - "wall", - "memory", - "sleep", - "free", - "high", - "realize", - "school", - "might", - "skin", - "sweet", - "perfect", - "blue", - "kill", - "breath", - "dance", - "against", - "fly", - "between", - "grow", - "strong", - "under", - "listen", - "bring", - "sometimes", - "speak", - "pull", - "person", - "become", - "family", - "begin", - "ground", - "real", - "small", - "father", - "sure", - "feet", - "rest", - "young", - "finally", - "land", - "across", - "today", - "different", - "guy", - "line", - "fire", - "reason", - "reach", - "second", - "slowly", - "write", - "eat", - "smell", - "mouth", - "step", - "learn", - "three", - "floor", - "promise", - "breathe", - "darkness", - "push", - "earth", - "guess", - "save", - "song", - "above", - "along", - "both", - "color", - "house", - "almost", - "sorry", - "anymore", - "brother", - "okay", - "dear", - "game", - "fade", - "already", - "apart", - "warm", - "beauty", - "heard", - "notice", - "question", - "shine", - "began", - "piece", - "whole", - "shadow", - "secret", - "street", - "within", - "finger", - "point", - "morning", - "whisper", - "child", - "moon", - "green", - "story", - "glass", - "kid", - "silence", - "since", - "soft", - "yourself", - "empty", - "shall", - "angel", - "answer", - "baby", - "bright", - "dad", - "path", - "worry", - "hour", - "drop", - "follow", - "power", - "war", - "half", - "flow", - "heaven", - "act", - "chance", - "fact", - "least", - "tired", - "children", - "near", - "quite", - "afraid", - "rise", - "sea", - "taste", - "window", - "cover", - "nice", - "trust", - "lot", - "sad", - "cool", - "force", - "peace", - "return", - "blind", - "easy", - "ready", - "roll", - "rose", - "drive", - "held", - "music", - "beneath", - "hang", - "mom", - "paint", - "emotion", - "quiet", - "clear", - "cloud", - "few", - "pretty", - "bird", - "outside", - "paper", - "picture", - "front", - "rock", - "simple", - "anyone", - "meant", - "reality", - "road", - "sense", - "waste", - "bit", - "leaf", - "thank", - "happiness", - "meet", - "men", - "smoke", - "truly", - "decide", - "self", - "age", - "book", - "form", - "alive", - "carry", - "escape", - "damn", - "instead", - "able", - "ice", - "minute", - "throw", - "catch", - "leg", - "ring", - "course", - "goodbye", - "lead", - "poem", - "sick", - "corner", - "desire", - "known", - "problem", - "remind", - "shoulder", - "suppose", - "toward", - "wave", - "drink", - "jump", - "woman", - "pretend", - "sister", - "week", - "human", - "joy", - "crack", - "grey", - "pray", - "surprise", - "dry", - "knee", - "less", - "search", - "bleed", - "caught", - "clean", - "embrace", - "future", - "king", - "son", - "sorrow", - "chest", - "hug", - "remain", - "sat", - "worth", - "blow", - "daddy", - "final", - "parent", - "tight", - "also", - "create", - "lonely", - "safe", - "cross", - "dress", - "evil", - "silent", - "bone", - "fate", - "perhaps", - "anger", - "class", - "scar", - "snow", - "tiny", - "tonight", - "continue", - "control", - "dog", - "edge", - "mirror", - "month", - "suddenly", - "comfort", - "given", - "loud", - "quickly", - "gaze", - "plan", - "rush", - "stone", - "town", - "battle", - "ignore", - "spirit", - "stood", - "stupid", - "yours", - "brown", - "build", - "dust", - "hey", - "kept", - "pay", - "phone", - "twist", - "although", - "ball", - "beyond", - "hidden", - "nose", - "taken", - "fail", - "float", - "pure", - "somehow", - "wash", - "wrap", - "angry", - "cheek", - "creature", - "forgotten", - "heat", - "rip", - "single", - "space", - "special", - "weak", - "whatever", - "yell", - "anyway", - "blame", - "job", - "choose", - "country", - "curse", - "drift", - "echo", - "figure", - "grew", - "laughter", - "neck", - "suffer", - "worse", - "yeah", - "disappear", - "foot", - "forward", - "knife", - "mess", - "somewhere", - "stomach", - "storm", - "beg", - "idea", - "lift", - "offer", - "breeze", - "field", - "five", - "often", - "simply", - "stuck", - "win", - "allow", - "confuse", - "enjoy", - "except", - "flower", - "seek", - "strength", - "calm", - "grin", - "gun", - "heavy", - "hill", - "large", - "ocean", - "shoe", - "sigh", - "straight", - "summer", - "tongue", - "accept", - "crazy", - "everyday", - "exist", - "grass", - "mistake", - "sent", - "shut", - "surround", - "table", - "ache", - "brain", - "destroy", - "heal", - "nature", - "shout", - "sign", - "stain", - "choice", - "doubt", - "glance", - "glow", - "mountain", - "queen", - "stranger", - "throat", - "tomorrow", - "city", - "either", - "fish", - "flame", - "rather", - "shape", - "spin", - "spread", - "ash", - "distance", - "finish", - "image", - "imagine", - "important", - "nobody", - "shatter", - "warmth", - "became", - "feed", - "flesh", - "funny", - "lust", - "shirt", - "trouble", - "yellow", - "attention", - "bare", - "bite", - "money", - "protect", - "amaze", - "appear", - "born", - "choke", - "completely", - "daughter", - "fresh", - "friendship", - "gentle", - "probably", - "six", - "deserve", - "expect", - "grab", - "middle", - "nightmare", - "river", - "thousand", - "weight", - "worst", - "wound", - "barely", - "bottle", - "cream", - "regret", - "relationship", - "stick", - "test", - "crush", - "endless", - "fault", - "itself", - "rule", - "spill", - "art", - "circle", - "join", - "kick", - "mask", - "master", - "passion", - "quick", - "raise", - "smooth", - "unless", - "wander", - "actually", - "broke", - "chair", - "deal", - "favorite", - "gift", - "note", - "number", - "sweat", - "box", - "chill", - "clothes", - "lady", - "mark", - "park", - "poor", - "sadness", - "tie", - "animal", - "belong", - "brush", - "consume", - "dawn", - "forest", - "innocent", - "pen", - "pride", - "stream", - "thick", - "clay", - "complete", - "count", - "draw", - "faith", - "press", - "silver", - "struggle", - "surface", - "taught", - "teach", - "wet", - "bless", - "chase", - "climb", - "enter", - "letter", - "melt", - "metal", - "movie", - "stretch", - "swing", - "vision", - "wife", - "beside", - "crash", - "forgot", - "guide", - "haunt", - "joke", - "knock", - "plant", - "pour", - "prove", - "reveal", - "steal", - "stuff", - "trip", - "wood", - "wrist", - "bother", - "bottom", - "crawl", - "crowd", - "fix", - "forgive", - "frown", - "grace", - "loose", - "lucky", - "party", - "release", - "surely", - "survive", - "teacher", - "gently", - "grip", - "speed", - "suicide", - "travel", - "treat", - "vein", - "written", - "cage", - "chain", - "conversation", - "date", - "enemy", - "however", - "interest", - "million", - "page", - "pink", - "proud", - "sway", - "themselves", - "winter", - "church", - "cruel", - "cup", - "demon", - "experience", - "freedom", - "pair", - "pop", - "purpose", - "respect", - "shoot", - "softly", - "state", - "strange", - "bar", - "birth", - "curl", - "dirt", - "excuse", - "lord", - "lovely", - "monster", - "order", - "pack", - "pants", - "pool", - "scene", - "seven", - "shame", - "slide", - "ugly", - "among", - "blade", - "blonde", - "closet", - "creek", - "deny", - "drug", - "eternity", - "gain", - "grade", - "handle", - "key", - "linger", - "pale", - "prepare", - "swallow", - "swim", - "tremble", - "wheel", - "won", - "cast", - "cigarette", - "claim", - "college", - "direction", - "dirty", - "gather", - "ghost", - "hundred", - "loss", - "lung", - "orange", - "present", - "swear", - "swirl", - "twice", - "wild", - "bitter", - "blanket", - "doctor", - "everywhere", - "flash", - "grown", - "knowledge", - "numb", - "pressure", - "radio", - "repeat", - "ruin", - "spend", - "unknown", - "buy", - "clock", - "devil", - "early", - "false", - "fantasy", - "pound", - "precious", - "refuse", - "sheet", - "teeth", - "welcome", - "add", - "ahead", - "block", - "bury", - "caress", - "content", - "depth", - "despite", - "distant", - "marry", - "purple", - "threw", - "whenever", - "bomb", - "dull", - "easily", - "grasp", - "hospital", - "innocence", - "normal", - "receive", - "reply", - "rhyme", - "shade", - "someday", - "sword", - "toe", - "visit", - "asleep", - "bought", - "center", - "consider", - "flat", - "hero", - "history", - "ink", - "insane", - "muscle", - "mystery", - "pocket", - "reflection", - "shove", - "silently", - "smart", - "soldier", - "spot", - "stress", - "train", - "type", - "view", - "whether", - "bus", - "energy", - "explain", - "holy", - "hunger", - "inch", - "magic", - "mix", - "noise", - "nowhere", - "prayer", - "presence", - "shock", - "snap", - "spider", - "study", - "thunder", - "trail", - "admit", - "agree", - "bag", - "bang", - "bound", - "butterfly", - "cute", - "exactly", - "explode", - "familiar", - "fold", - "further", - "pierce", - "reflect", - "scent", - "selfish", - "sharp", - "sink", - "spring", - "stumble", - "universe", - "weep", - "women", - "wonderful", - "action", - "ancient", - "attempt", - "avoid", - "birthday", - "branch", - "chocolate", - "core", - "depress", - "drunk", - "especially", - "focus", - "fruit", - "honest", - "match", - "palm", - "perfectly", - "pillow", - "pity", - "poison", - "roar", - "shift", - "slightly", - "thump", - "truck", - "tune", - "twenty", - "unable", - "wipe", - "wrote", - "coat", - "constant", - "dinner", - "drove", - "egg", - "eternal", - "flight", - "flood", - "frame", - "freak", - "gasp", - "glad", - "hollow", - "motion", - "peer", - "plastic", - "root", - "screen", - "season", - "sting", - "strike", - "team", - "unlike", - "victim", - "volume", - "warn", - "weird", - "attack", - "await", - "awake", - "built", - "charm", - "crave", - "despair", - "fought", - "grant", - "grief", - "horse", - "limit", - "message", - "ripple", - "sanity", - "scatter", - "serve", - "split", - "string", - "trick", - "annoy", - "blur", - "boat", - "brave", - "clearly", - "cling", - "connect", - "fist", - "forth", - "imagination", - "iron", - "jock", - "judge", - "lesson", - "milk", - "misery", - "nail", - "naked", - "ourselves", - "poet", - "possible", - "princess", - "sail", - "size", - "snake", - "society", - "stroke", - "torture", - "toss", - "trace", - "wise", - "bloom", - "bullet", - "cell", - "check", - "cost", - "darling", - "during", - "footstep", - "fragile", - "hallway", - "hardly", - "horizon", - "invisible", - "journey", - "midnight", - "mud", - "nod", - "pause", - "relax", - "shiver", - "sudden", - "value", - "youth", - "abuse", - "admire", - "blink", - "breast", - "bruise", - "constantly", - "couple", - "creep", - "curve", - "difference", - "dumb", - "emptiness", - "gotta", - "honor", - "plain", - "planet", - "recall", - "rub", - "ship", - "slam", - "soar", - "somebody", - "tightly", - "weather", - "adore", - "approach", - "bond", - "bread", - "burst", - "candle", - "coffee", - "cousin", - "crime", - "desert", - "flutter", - "frozen", - "grand", - "heel", - "hello", - "language", - "level", - "movement", - "pleasure", - "powerful", - "random", - "rhythm", - "settle", - "silly", - "slap", - "sort", - "spoken", - "steel", - "threaten", - "tumble", - "upset", - "aside", - "awkward", - "bee", - "blank", - "board", - "button", - "card", - "carefully", - "complain", - "crap", - "deeply", - "discover", - "drag", - "dread", - "effort", - "entire", - "fairy", - "giant", - "gotten", - "greet", - "illusion", - "jeans", - "leap", - "liquid", - "march", - "mend", - "nervous", - "nine", - "replace", - "rope", - "spine", - "stole", - "terror", - "accident", - "apple", - "balance", - "boom", - "childhood", - "collect", - "demand", - "depression", - "eventually", - "faint", - "glare", - "goal", - "group", - "honey", - "kitchen", - "laid", - "limb", - "machine", - "mere", - "mold", - "murder", - "nerve", - "painful", - "poetry", - "prince", - "rabbit", - "shelter", - "shore", - "shower", - "soothe", - "stair", - "steady", - "sunlight", - "tangle", - "tease", - "treasure", - "uncle", - "begun", - "bliss", - "canvas", - "cheer", - "claw", - "clutch", - "commit", - "crimson", - "crystal", - "delight", - "doll", - "existence", - "express", - "fog", - "football", - "gay", - "goose", - "guard", - "hatred", - "illuminate", - "mass", - "math", - "mourn", - "rich", - "rough", - "skip", - "stir", - "student", - "style", - "support", - "thorn", - "tough", - "yard", - "yearn", - "yesterday", - "advice", - "appreciate", - "autumn", - "bank", - "beam", - "bowl", - "capture", - "carve", - "collapse", - "confusion", - "creation", - "dove", - "feather", - "girlfriend", - "glory", - "government", - "harsh", - "hop", - "inner", - "loser", - "moonlight", - "neighbor", - "neither", - "peach", - "pig", - "praise", - "screw", - "shield", - "shimmer", - "sneak", - "stab", - "subject", - "throughout", - "thrown", - "tower", - "twirl", - "wow", - "army", - "arrive", - "bathroom", - "bump", - "cease", - "cookie", - "couch", - "courage", - "dim", - "guilt", - "howl", - "hum", - "husband", - "insult", - "led", - "lunch", - "mock", - "mostly", - "natural", - "nearly", - "needle", - "nerd", - "peaceful", - "perfection", - "pile", - "price", - "remove", - "roam", - "sanctuary", - "serious", - "shiny", - "shook", - "sob", - "stolen", - "tap", - "vain", - "void", - "warrior", - "wrinkle", - "affection", - "apologize", - "blossom", - "bounce", - "bridge", - "cheap", - "crumble", - "decision", - "descend", - "desperately", - "dig", - "dot", - "flip", - "frighten", - "heartbeat", - "huge", - "lazy", - "lick", - "odd", - "opinion", - "process", - "puzzle", - "quietly", - "retreat", - "score", - "sentence", - "separate", - "situation", - "skill", - "soak", - "square", - "stray", - "taint", - "task", - "tide", - "underneath", - "veil", - "whistle", - "anywhere", - "bedroom", - "bid", - "bloody", - "burden", - "careful", - "compare", - "concern", - "curtain", - "decay", - "defeat", - "describe", - "double", - "dreamer", - "driver", - "dwell", - "evening", - "flare", - "flicker", - "grandma", - "guitar", - "harm", - "horrible", - "hungry", - "indeed", - "lace", - "melody", - "monkey", - "nation", - "object", - "obviously", - "rainbow", - "salt", - "scratch", - "shown", - "shy", - "stage", - "stun", - "third", - "tickle", - "useless", - "weakness", - "worship", - "worthless", - "afternoon", - "beard", - "boyfriend", - "bubble", - "busy", - "certain", - "chin", - "concrete", - "desk", - "diamond", - "doom", - "drawn", - "due", - "felicity", - "freeze", - "frost", - "garden", - "glide", - "harmony", - "hopefully", - "hunt", - "jealous", - "lightning", - "mama", - "mercy", - "peel", - "physical", - "position", - "pulse", - "punch", - "quit", - "rant", - "respond", - "salty", - "sane", - "satisfy", - "savior", - "sheep", - "slept", - "social", - "sport", - "tuck", - "utter", - "valley", - "wolf", - "aim", - "alas", - "alter", - "arrow", - "awaken", - "beaten", - "belief", - "brand", - "ceiling", - "cheese", - "clue", - "confidence", - "connection", - "daily", - "disguise", - "eager", - "erase", - "essence", - "everytime", - "expression", - "fan", - "flag", - "flirt", - "foul", - "fur", - "giggle", - "glorious", - "ignorance", - "law", - "lifeless", - "measure", - "mighty", - "muse", - "north", - "opposite", - "paradise", - "patience", - "patient", - "pencil", - "petal", - "plate", - "ponder", - "possibly", - "practice", - "slice", - "spell", - "stock", - "strife", - "strip", - "suffocate", - "suit", - "tender", - "tool", - "trade", - "velvet", - "verse", - "waist", - "witch", - "aunt", - "bench", - "bold", - "cap", - "certainly", - "click", - "companion", - "creator", - "dart", - "delicate", - "determine", - "dish", - "dragon", - "drama", - "drum", - "dude", - "everybody", - "feast", - "forehead", - "former", - "fright", - "fully", - "gas", - "hook", - "hurl", - "invite", - "juice", - "manage", - "moral", - "possess", - "raw", - "rebel", - "royal", - "scale", - "scary", - "several", - "slight", - "stubborn", - "swell", - "talent", - "tea", - "terrible", - "thread", - "torment", - "trickle", - "usually", - "vast", - "violence", - "weave", - "acid", - "agony", - "ashamed", - "awe", - "belly", - "blend", - "blush", - "character", - "cheat", - "common", - "company", - "coward", - "creak", - "danger", - "deadly", - "defense", - "define", - "depend", - "desperate", - "destination", - "dew", - "duck", - "dusty", - "embarrass", - "engine", - "example", - "explore", - "foe", - "freely", - "frustrate", - "generation", - "glove", - "guilty", - "health", - "hurry", - "idiot", - "impossible", - "inhale", - "jaw", - "kingdom", - "mention", - "mist", - "moan", - "mumble", - "mutter", - "observe", - "ode", - "pathetic", - "pattern", - "pie", - "prefer", - "puff", - "rape", - "rare", - "revenge", - "rude", - "scrape", - "spiral", - "squeeze", - "strain", - "sunset", - "suspend", - "sympathy", - "thigh", - "throne", - "total", - "unseen", - "weapon", - "weary", -} diff --git a/ethutil/mnemonic_test.go b/ethutil/mnemonic_test.go deleted file mode 100644 index ccf3f9883..000000000 --- a/ethutil/mnemonic_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package ethutil - -import ( - "testing" -) - -func TestMnDecode(t *testing.T) { - words := []string{ - "ink", - "balance", - "gain", - "fear", - "happen", - "melt", - "mom", - "surface", - "stir", - "bottle", - "unseen", - "expression", - "important", - "curl", - "grant", - "fairy", - "across", - "back", - "figure", - "breast", - "nobody", - "scratch", - "worry", - "yesterday", - } - encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338" - result := MnemonicDecode(words) - if encode != result { - t.Error("We expected", encode, "got", result, "instead") - } -} -func TestMnEncode(t *testing.T) { - encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338" - result := []string{ - "ink", - "balance", - "gain", - "fear", - "happen", - "melt", - "mom", - "surface", - "stir", - "bottle", - "unseen", - "expression", - "important", - "curl", - "grant", - "fairy", - "across", - "back", - "figure", - "breast", - "nobody", - "scratch", - "worry", - "yesterday", - } - words := MnemonicEncode(encode) - for i, word := range words { - if word != result[i] { - t.Error("Mnenonic does not match:", words, result) - } - } -} -- cgit v1.2.3 From d87857ffdb822d0c510bcff385f7ef0328edb2ca Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 15:59:57 +0100 Subject: config Pubkey removed (unused) --- ethutil/config.go | 1 - 1 file changed, 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index b253aa203..8a005670f 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -16,7 +16,6 @@ type config struct { Debug bool Ver string ClientString string - Pubkey []byte Identifier string conf *globalconf.GlobalConf -- cgit v1.2.3 From e1ea41ee9cbe387221874fa6732b11d262a4ff12 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:01:57 +0100 Subject: remove ethutil helpers (refactored), and keypair (key management under ethcrypto package) --- ethutil/helpers.go | 64 ----------------------------- ethutil/keypair.go | 115 ----------------------------------------------------- 2 files changed, 179 deletions(-) delete mode 100644 ethutil/helpers.go delete mode 100644 ethutil/keypair.go (limited to 'ethutil') diff --git a/ethutil/helpers.go b/ethutil/helpers.go deleted file mode 100644 index aa0f79a04..000000000 --- a/ethutil/helpers.go +++ /dev/null @@ -1,64 +0,0 @@ -package ethutil - -import ( - "code.google.com/p/go.crypto/ripemd160" - "crypto/sha256" - "encoding/hex" - "github.com/obscuren/sha3" - "strconv" -) - -func Uitoa(i uint32) string { - return strconv.FormatUint(uint64(i), 10) -} - -func Sha256Bin(data []byte) []byte { - hash := sha256.Sum256(data) - - return hash[:] -} - -func Ripemd160(data []byte) []byte { - ripemd := ripemd160.New() - ripemd.Write(data) - - return ripemd.Sum(nil) -} - -func Sha3Bin(data []byte) []byte { - d := sha3.NewKeccak256() - d.Write(data) - - return d.Sum(nil) -} - -// Helper function for comparing slices -func CompareIntSlice(a, b []int) bool { - if len(a) != len(b) { - return false - } - for i, v := range a { - if v != b[i] { - return false - } - } - return true -} - -// Returns the amount of nibbles that match each other from 0 ... -func MatchingNibbleLength(a, b []int) int { - i := 0 - for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { - i += 1 - } - - return i -} - -func Hex(d []byte) string { - return hex.EncodeToString(d) -} -func FromHex(str string) []byte { - h, _ := hex.DecodeString(str) - return h -} diff --git a/ethutil/keypair.go b/ethutil/keypair.go deleted file mode 100644 index 29fb1bac5..000000000 --- a/ethutil/keypair.go +++ /dev/null @@ -1,115 +0,0 @@ -package ethutil - -import ( - "github.com/obscuren/secp256k1-go" -) - -type KeyPair struct { - PrivateKey []byte - PublicKey []byte - - // The associated account - account *StateObject -} - -func GenerateNewKeyPair() (*KeyPair, error) { - _, prv := secp256k1.GenerateKeyPair() - - return NewKeyPairFromSec(prv) -} - -func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { - pubkey, err := secp256k1.GeneratePubKey(seckey) - if err != nil { - return nil, err - } - - return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil -} - -func NewKeyPairFromValue(val *Value) *KeyPair { - v, _ := NewKeyPairFromSec(val.Bytes()) - - return v -} - -func (k *KeyPair) Address() []byte { - return Sha3Bin(k.PublicKey[1:])[12:] -} - -func (k *KeyPair) RlpEncode() []byte { - return k.RlpValue().Encode() -} - -func (k *KeyPair) RlpValue() *Value { - return NewValue(k.PrivateKey) -} - -type KeyRing struct { - keys []*KeyPair -} - -func (k *KeyRing) Add(pair *KeyPair) { - k.keys = append(k.keys, pair) -} - -func (k *KeyRing) Get(i int) *KeyPair { - if len(k.keys) > i { - return k.keys[i] - } - - return nil -} - -func (k *KeyRing) Len() int { - return len(k.keys) -} - -func (k *KeyRing) NewKeyPair(sec []byte) (*KeyPair, error) { - keyPair, err := NewKeyPairFromSec(sec) - if err != nil { - return nil, err - } - - k.Add(keyPair) - Config.Db.Put([]byte("KeyRing"), k.RlpValue().Encode()) - - return keyPair, nil -} - -func (k *KeyRing) Reset() { - Config.Db.Put([]byte("KeyRing"), nil) - k.keys = nil -} - -func (k *KeyRing) RlpValue() *Value { - v := EmptyValue() - for _, keyPair := range k.keys { - v.Append(keyPair.RlpValue()) - } - - return v -} - -// The public "singleton" keyring -var keyRing *KeyRing - -func GetKeyRing() *KeyRing { - if keyRing == nil { - keyRing = &KeyRing{} - - data, _ := Config.Db.Get([]byte("KeyRing")) - it := NewValueFromBytes(data).NewIterator() - for it.Next() { - v := it.Value() - - key, err := NewKeyPairFromSec(v.Bytes()) - if err != nil { - panic(err) - } - keyRing.Add(key) - } - } - - return keyRing -} -- cgit v1.2.3 From 5e50b50dc379ed1db48912538034414ff94f6531 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:06:54 +0100 Subject: no strconv import needed --- ethutil/slice.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'ethutil') diff --git a/ethutil/slice.go b/ethutil/slice.go index 67f43705d..3cedcb189 100644 --- a/ethutil/slice.go +++ b/ethutil/slice.go @@ -1,8 +1,6 @@ package ethutil -import ( - "strconv" -) +import () // Helper function for comparing slices func CompareIntSlice(a, b []int) bool { -- cgit v1.2.3 From e3b911652dfba1475001137ba8b3687b9fec5331 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:08:33 +0100 Subject: move CreateAddress from ethutil/common to ethcrypto --- ethutil/common.go | 7 ------- 1 file changed, 7 deletions(-) (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go index f63ba5d83..6d88a1ed2 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -52,10 +52,3 @@ var ( Big32 = big.NewInt(32) Big256 = big.NewInt(0xff) ) - -// Creates an ethereum address given the bytes and the nonce -func CreateAddress(b []byte, nonce *big.Int) []byte { - addrBytes := append(b, nonce.Bytes()...) - - return Sha3Bin(addrBytes)[12:] -} -- cgit v1.2.3 From 707d413761927f5ad95298e666e297b820ad0901 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:26:58 +0100 Subject: refactor ethutil/trie to ethtrie --- ethutil/encoding.go | 76 ------- ethutil/encoding_test.go | 67 ------ ethutil/slice.go | 26 --- ethutil/trie.go | 561 ----------------------------------------------- ethutil/trie_test.go | 193 ---------------- 5 files changed, 923 deletions(-) delete mode 100644 ethutil/encoding.go delete mode 100644 ethutil/encoding_test.go delete mode 100644 ethutil/slice.go delete mode 100644 ethutil/trie.go delete mode 100644 ethutil/trie_test.go (limited to 'ethutil') diff --git a/ethutil/encoding.go b/ethutil/encoding.go deleted file mode 100644 index 9fcdf3edf..000000000 --- a/ethutil/encoding.go +++ /dev/null @@ -1,76 +0,0 @@ -package ethutil - -import ( - "bytes" - "encoding/hex" - "strings" -) - -func CompactEncode(hexSlice []int) string { - terminator := 0 - if hexSlice[len(hexSlice)-1] == 16 { - terminator = 1 - } - - if terminator == 1 { - hexSlice = hexSlice[:len(hexSlice)-1] - } - - oddlen := len(hexSlice) % 2 - flags := 2*terminator + oddlen - if oddlen != 0 { - hexSlice = append([]int{flags}, hexSlice...) - } else { - hexSlice = append([]int{flags, 0}, hexSlice...) - } - - var buff bytes.Buffer - for i := 0; i < len(hexSlice); i += 2 { - buff.WriteByte(byte(16*hexSlice[i] + hexSlice[i+1])) - } - - return buff.String() -} - -func CompactDecode(str string) []int { - base := CompactHexDecode(str) - base = base[:len(base)-1] - if base[0] >= 2 { - base = append(base, 16) - } - if base[0]%2 == 1 { - base = base[1:] - } else { - base = base[2:] - } - - return base -} - -func CompactHexDecode(str string) []int { - base := "0123456789abcdef" - hexSlice := make([]int, 0) - - enc := hex.EncodeToString([]byte(str)) - for _, v := range enc { - hexSlice = append(hexSlice, strings.IndexByte(base, byte(v))) - } - hexSlice = append(hexSlice, 16) - - return hexSlice -} - -func DecodeCompact(key []int) string { - base := "0123456789abcdef" - var str string - - for _, v := range key { - if v < 16 { - str += string(base[v]) - } - } - - res, _ := hex.DecodeString(str) - - return string(res) -} diff --git a/ethutil/encoding_test.go b/ethutil/encoding_test.go deleted file mode 100644 index 10e1995c0..000000000 --- a/ethutil/encoding_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package ethutil - -import ( - "fmt" - "testing" -) - -func TestCompactEncode(t *testing.T) { - test1 := []int{1, 2, 3, 4, 5} - if res := CompactEncode(test1); res != "\x11\x23\x45" { - t.Error(fmt.Sprintf("even compact encode failed. Got: %q", res)) - } - - test2 := []int{0, 1, 2, 3, 4, 5} - if res := CompactEncode(test2); res != "\x00\x01\x23\x45" { - t.Error(fmt.Sprintf("odd compact encode failed. Got: %q", res)) - } - - test3 := []int{0, 15, 1, 12, 11, 8 /*term*/, 16} - if res := CompactEncode(test3); res != "\x20\x0f\x1c\xb8" { - t.Error(fmt.Sprintf("odd terminated compact encode failed. Got: %q", res)) - } - - test4 := []int{15, 1, 12, 11, 8 /*term*/, 16} - if res := CompactEncode(test4); res != "\x3f\x1c\xb8" { - t.Error(fmt.Sprintf("even terminated compact encode failed. Got: %q", res)) - } -} - -func TestCompactHexDecode(t *testing.T) { - exp := []int{7, 6, 6, 5, 7, 2, 6, 2, 16} - res := CompactHexDecode("verb") - - if !CompareIntSlice(res, exp) { - t.Error("Error compact hex decode. Expected", exp, "got", res) - } -} - -func TestCompactDecode(t *testing.T) { - exp := []int{1, 2, 3, 4, 5} - res := CompactDecode("\x11\x23\x45") - - if !CompareIntSlice(res, exp) { - t.Error("odd compact decode. Expected", exp, "got", res) - } - - exp = []int{0, 1, 2, 3, 4, 5} - res = CompactDecode("\x00\x01\x23\x45") - - if !CompareIntSlice(res, exp) { - t.Error("even compact decode. Expected", exp, "got", res) - } - - exp = []int{0, 15, 1, 12, 11, 8 /*term*/, 16} - res = CompactDecode("\x20\x0f\x1c\xb8") - - if !CompareIntSlice(res, exp) { - t.Error("even terminated compact decode. Expected", exp, "got", res) - } - - exp = []int{15, 1, 12, 11, 8 /*term*/, 16} - res = CompactDecode("\x3f\x1c\xb8") - - if !CompareIntSlice(res, exp) { - t.Error("even terminated compact decode. Expected", exp, "got", res) - } -} diff --git a/ethutil/slice.go b/ethutil/slice.go deleted file mode 100644 index 3cedcb189..000000000 --- a/ethutil/slice.go +++ /dev/null @@ -1,26 +0,0 @@ -package ethutil - -import () - -// Helper function for comparing slices -func CompareIntSlice(a, b []int) bool { - if len(a) != len(b) { - return false - } - for i, v := range a { - if v != b[i] { - return false - } - } - return true -} - -// Returns the amount of nibbles that match each other from 0 ... -func MatchingNibbleLength(a, b []int) int { - i := 0 - for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { - i += 1 - } - - return i -} diff --git a/ethutil/trie.go b/ethutil/trie.go deleted file mode 100644 index 18d0a5f0a..000000000 --- a/ethutil/trie.go +++ /dev/null @@ -1,561 +0,0 @@ -package ethutil - -import ( - "fmt" - "reflect" - "sync" -) - -func (s *Cache) Len() int { - return len(s.nodes) -} - -// TODO -// A StateObject is an object that has a state root -// This is goig to be the object for the second level caching (the caching of object which have a state such as contracts) -type StateObject interface { - State() *Trie - Sync() - Undo() -} - -type Node struct { - Key []byte - Value *Value - Dirty bool -} - -func NewNode(key []byte, val *Value, dirty bool) *Node { - return &Node{Key: key, Value: val, Dirty: dirty} -} - -func (n *Node) Copy() *Node { - return NewNode(n.Key, n.Value, n.Dirty) -} - -type Cache struct { - nodes map[string]*Node - db Database - IsDirty bool -} - -func NewCache(db Database) *Cache { - return &Cache{db: db, nodes: make(map[string]*Node)} -} - -func (cache *Cache) Put(v interface{}) interface{} { - value := NewValue(v) - - enc := value.Encode() - if len(enc) >= 32 { - sha := Sha3Bin(enc) - - cache.nodes[string(sha)] = NewNode(sha, value, true) - cache.IsDirty = true - - return sha - } - - return v -} - -func (cache *Cache) Get(key []byte) *Value { - // First check if the key is the cache - if cache.nodes[string(key)] != nil { - return cache.nodes[string(key)].Value - } - - // Get the key of the database instead and cache it - data, _ := cache.db.Get(key) - // Create the cached value - value := NewValueFromBytes(data) - // Create caching node - cache.nodes[string(key)] = NewNode(key, value, false) - - return value -} - -func (cache *Cache) Delete(key []byte) { - delete(cache.nodes, string(key)) - - cache.db.Delete(key) -} - -func (cache *Cache) Commit() { - // Don't try to commit if it isn't dirty - if !cache.IsDirty { - return - } - - for key, node := range cache.nodes { - if node.Dirty { - cache.db.Put([]byte(key), node.Value.Encode()) - node.Dirty = false - } - } - cache.IsDirty = false - - // If the nodes grows beyond the 200 entries we simple empty it - // FIXME come up with something better - if len(cache.nodes) > 200 { - cache.nodes = make(map[string]*Node) - } -} - -func (cache *Cache) Undo() { - for key, node := range cache.nodes { - if node.Dirty { - delete(cache.nodes, key) - } - } - cache.IsDirty = false -} - -// A (modified) Radix Trie implementation. The Trie implements -// a caching mechanism and will used cached values if they are -// present. If a node is not present in the cache it will try to -// fetch it from the database and store the cached value. -// Please note that the data isn't persisted unless `Sync` is -// explicitly called. -type Trie struct { - mut sync.RWMutex - prevRoot interface{} - Root interface{} - //db Database - cache *Cache -} - -func copyRoot(root interface{}) interface{} { - var prevRootCopy interface{} - if b, ok := root.([]byte); ok { - prevRootCopy = CopyBytes(b) - } else { - prevRootCopy = root - } - - return prevRootCopy -} - -func NewTrie(db Database, Root interface{}) *Trie { - // Make absolute sure the root is copied - r := copyRoot(Root) - p := copyRoot(Root) - - return &Trie{cache: NewCache(db), Root: r, prevRoot: p} -} - -// Save the cached value to the database. -func (t *Trie) Sync() { - t.cache.Commit() - t.prevRoot = copyRoot(t.Root) -} - -func (t *Trie) Undo() { - t.cache.Undo() - t.Root = t.prevRoot -} - -func (t *Trie) Cache() *Cache { - return t.cache -} - -/* - * Public (query) interface functions - */ -func (t *Trie) Update(key string, value string) { - t.mut.Lock() - defer t.mut.Unlock() - - k := CompactHexDecode(key) - - t.Root = t.UpdateState(t.Root, k, value) -} - -func (t *Trie) Get(key string) string { - t.mut.RLock() - defer t.mut.RUnlock() - - k := CompactHexDecode(key) - c := NewValue(t.GetState(t.Root, k)) - - return c.Str() -} - -func (t *Trie) Delete(key string) { - t.Update(key, "") -} - -func (t *Trie) GetState(node interface{}, key []int) interface{} { - n := NewValue(node) - // Return the node if key is empty (= found) - if len(key) == 0 || n.IsNil() || n.Len() == 0 { - return node - } - - currentNode := t.GetNode(node) - length := currentNode.Len() - - if length == 0 { - return "" - } else if length == 2 { - // Decode the key - k := CompactDecode(currentNode.Get(0).Str()) - v := currentNode.Get(1).Raw() - - if len(key) >= len(k) && CompareIntSlice(k, key[:len(k)]) { - return t.GetState(v, key[len(k):]) - } else { - return "" - } - } else if length == 17 { - return t.GetState(currentNode.Get(key[0]).Raw(), key[1:]) - } - - // It shouldn't come this far - fmt.Println("GetState unexpected return") - return "" -} - -func (t *Trie) GetNode(node interface{}) *Value { - n := NewValue(node) - - if !n.Get(0).IsNil() { - return n - } - - str := n.Str() - if len(str) == 0 { - return n - } else if len(str) < 32 { - return NewValueFromBytes([]byte(str)) - } - - return t.cache.Get(n.Bytes()) -} - -func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { - - if value != "" { - return t.InsertState(node, key, value) - } else { - // delete it - return t.DeleteState(node, key) - } - - return t.Root -} - -func (t *Trie) Put(node interface{}) interface{} { - /* - TODO? - c := Conv(t.Root) - fmt.Println(c.Type(), c.Length()) - if c.Type() == reflect.String && c.AsString() == "" { - return enc - } - */ - - return t.cache.Put(node) - -} - -func EmptyStringSlice(l int) []interface{} { - slice := make([]interface{}, l) - for i := 0; i < l; i++ { - slice[i] = "" - } - return slice -} - -func (t *Trie) InsertState(node interface{}, key []int, value interface{}) interface{} { - if len(key) == 0 { - return value - } - - // New node - n := NewValue(node) - if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { - newNode := []interface{}{CompactEncode(key), value} - - return t.Put(newNode) - } - - currentNode := t.GetNode(node) - // Check for "special" 2 slice type node - if currentNode.Len() == 2 { - // Decode the key - - k := CompactDecode(currentNode.Get(0).Str()) - v := currentNode.Get(1).Raw() - - // Matching key pair (ie. there's already an object with this key) - if CompareIntSlice(k, key) { - newNode := []interface{}{CompactEncode(key), value} - return t.Put(newNode) - } - - var newHash interface{} - matchingLength := MatchingNibbleLength(key, k) - if matchingLength == len(k) { - // Insert the hash, creating a new node - newHash = t.InsertState(v, key[matchingLength:], value) - } else { - // Expand the 2 length slice to a 17 length slice - oldNode := t.InsertState("", k[matchingLength+1:], v) - newNode := t.InsertState("", key[matchingLength+1:], value) - // Create an expanded slice - scaledSlice := EmptyStringSlice(17) - // Set the copied and new node - scaledSlice[k[matchingLength]] = oldNode - scaledSlice[key[matchingLength]] = newNode - - newHash = t.Put(scaledSlice) - } - - if matchingLength == 0 { - // End of the chain, return - return newHash - } else { - newNode := []interface{}{CompactEncode(key[:matchingLength]), newHash} - return t.Put(newNode) - } - } else { - - // Copy the current node over to the new node and replace the first nibble in the key - newNode := EmptyStringSlice(17) - - for i := 0; i < 17; i++ { - cpy := currentNode.Get(i).Raw() - if cpy != nil { - newNode[i] = cpy - } - } - - newNode[key[0]] = t.InsertState(currentNode.Get(key[0]).Raw(), key[1:], value) - - return t.Put(newNode) - } - - return "" -} - -func (t *Trie) DeleteState(node interface{}, key []int) interface{} { - if len(key) == 0 { - return "" - } - - // New node - n := NewValue(node) - if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { - return "" - } - - currentNode := t.GetNode(node) - // Check for "special" 2 slice type node - if currentNode.Len() == 2 { - // Decode the key - k := CompactDecode(currentNode.Get(0).Str()) - v := currentNode.Get(1).Raw() - - // Matching key pair (ie. there's already an object with this key) - if CompareIntSlice(k, key) { - return "" - } else if CompareIntSlice(key[:len(k)], k) { - hash := t.DeleteState(v, key[len(k):]) - child := t.GetNode(hash) - - var newNode []interface{} - if child.Len() == 2 { - newKey := append(k, CompactDecode(child.Get(0).Str())...) - newNode = []interface{}{CompactEncode(newKey), child.Get(1).Raw()} - } else { - newNode = []interface{}{currentNode.Get(0).Str(), hash} - } - - return t.Put(newNode) - } else { - return node - } - } else { - // Copy the current node over to the new node and replace the first nibble in the key - n := EmptyStringSlice(17) - var newNode []interface{} - - for i := 0; i < 17; i++ { - cpy := currentNode.Get(i).Raw() - if cpy != nil { - n[i] = cpy - } - } - - n[key[0]] = t.DeleteState(n[key[0]], key[1:]) - amount := -1 - for i := 0; i < 17; i++ { - if n[i] != "" { - if amount == -1 { - amount = i - } else { - amount = -2 - } - } - } - if amount == 16 { - newNode = []interface{}{CompactEncode([]int{16}), n[amount]} - } else if amount >= 0 { - child := t.GetNode(n[amount]) - if child.Len() == 17 { - newNode = []interface{}{CompactEncode([]int{amount}), n[amount]} - } else if child.Len() == 2 { - key := append([]int{amount}, CompactDecode(child.Get(0).Str())...) - newNode = []interface{}{CompactEncode(key), child.Get(1).Str()} - } - - } else { - newNode = n - } - - return t.Put(newNode) - } - - return "" -} - -// Simple compare function which creates a rlp value out of the evaluated objects -func (t *Trie) Cmp(trie *Trie) bool { - return NewValue(t.Root).Cmp(NewValue(trie.Root)) -} - -// Returns a copy of this trie -func (t *Trie) Copy() *Trie { - trie := NewTrie(t.cache.db, t.Root) - for key, node := range t.cache.nodes { - trie.cache.nodes[key] = node.Copy() - } - - return trie -} - -type TrieIterator struct { - trie *Trie - key string - value string - - shas [][]byte - values []string - - lastNode []byte -} - -func (t *Trie) NewIterator() *TrieIterator { - return &TrieIterator{trie: t} -} - -// Some time in the near future this will need refactoring :-) -// XXX Note to self, IsSlice == inline node. Str == sha3 to node -func (it *TrieIterator) workNode(currentNode *Value) { - if currentNode.Len() == 2 { - k := CompactDecode(currentNode.Get(0).Str()) - - if currentNode.Get(1).Str() == "" { - it.workNode(currentNode.Get(1)) - } else { - if k[len(k)-1] == 16 { - it.values = append(it.values, currentNode.Get(1).Str()) - } else { - it.shas = append(it.shas, currentNode.Get(1).Bytes()) - it.getNode(currentNode.Get(1).Bytes()) - } - } - } else { - for i := 0; i < currentNode.Len(); i++ { - if i == 16 && currentNode.Get(i).Len() != 0 { - it.values = append(it.values, currentNode.Get(i).Str()) - } else { - if currentNode.Get(i).Str() == "" { - it.workNode(currentNode.Get(i)) - } else { - val := currentNode.Get(i).Str() - if val != "" { - it.shas = append(it.shas, currentNode.Get(1).Bytes()) - it.getNode([]byte(val)) - } - } - } - } - } -} - -func (it *TrieIterator) getNode(node []byte) { - currentNode := it.trie.cache.Get(node) - it.workNode(currentNode) -} - -func (it *TrieIterator) Collect() [][]byte { - if it.trie.Root == "" { - return nil - } - - it.getNode(NewValue(it.trie.Root).Bytes()) - - return it.shas -} - -func (it *TrieIterator) Purge() int { - shas := it.Collect() - for _, sha := range shas { - it.trie.cache.Delete(sha) - } - return len(it.values) -} - -func (it *TrieIterator) Key() string { - return "" -} - -func (it *TrieIterator) Value() string { - return "" -} - -type EachCallback func(key string, node *Value) - -func (it *TrieIterator) Each(cb EachCallback) { - it.fetchNode(nil, NewValue(it.trie.Root).Bytes(), cb) -} - -func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { - it.iterateNode(key, it.trie.cache.Get(node), cb) -} - -func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallback) { - if currentNode.Len() == 2 { - k := CompactDecode(currentNode.Get(0).Str()) - - if currentNode.Get(1).Str() == "" { - it.iterateNode(key, currentNode.Get(1), cb) - } else { - pk := append(key, k...) - - if k[len(k)-1] == 16 { - cb(DecodeCompact(pk), currentNode.Get(1)) - } else { - it.fetchNode(pk, currentNode.Get(1).Bytes(), cb) - } - } - } else { - for i := 0; i < currentNode.Len(); i++ { - pk := append(key, i) - if i == 16 && currentNode.Get(i).Len() != 0 { - cb(DecodeCompact(pk), currentNode.Get(i)) - } else { - if currentNode.Get(i).Str() == "" { - it.iterateNode(pk, currentNode.Get(i), cb) - } else { - val := currentNode.Get(i).Str() - if val != "" { - it.fetchNode(pk, []byte(val), cb) - } - } - } - } - } -} diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go deleted file mode 100644 index 2937b1525..000000000 --- a/ethutil/trie_test.go +++ /dev/null @@ -1,193 +0,0 @@ -package ethutil - -import ( - "fmt" - "reflect" - "testing" -) - -const LONG_WORD = "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ" - -type MemDatabase struct { - db map[string][]byte -} - -func NewMemDatabase() (*MemDatabase, error) { - db := &MemDatabase{db: make(map[string][]byte)} - return db, nil -} -func (db *MemDatabase) Put(key []byte, value []byte) { - db.db[string(key)] = value -} -func (db *MemDatabase) Get(key []byte) ([]byte, error) { - return db.db[string(key)], nil -} -func (db *MemDatabase) Delete(key []byte) error { - delete(db.db, string(key)) - return nil -} -func (db *MemDatabase) Print() {} -func (db *MemDatabase) Close() {} -func (db *MemDatabase) LastKnownTD() []byte { return nil } - -func New() (*MemDatabase, *Trie) { - db, _ := NewMemDatabase() - return db, NewTrie(db, "") -} - -func TestTrieSync(t *testing.T) { - db, trie := New() - - trie.Update("dog", LONG_WORD) - if len(db.db) != 0 { - t.Error("Expected no data in database") - } - - trie.Sync() - if len(db.db) == 0 { - t.Error("Expected data to be persisted") - } -} - -func TestTrieDirtyTracking(t *testing.T) { - _, trie := New() - trie.Update("dog", LONG_WORD) - if !trie.cache.IsDirty { - t.Error("Expected trie to be dirty") - } - - trie.Sync() - if trie.cache.IsDirty { - t.Error("Expected trie not to be dirty") - } - - trie.Update("test", LONG_WORD) - trie.cache.Undo() - if trie.cache.IsDirty { - t.Error("Expected trie not to be dirty") - } - -} - -func TestTrieReset(t *testing.T) { - _, trie := New() - - trie.Update("cat", LONG_WORD) - if len(trie.cache.nodes) == 0 { - t.Error("Expected cached nodes") - } - - trie.cache.Undo() - - if len(trie.cache.nodes) != 0 { - t.Error("Expected no nodes after undo") - } -} - -func TestTrieGet(t *testing.T) { - _, trie := New() - - trie.Update("cat", LONG_WORD) - x := trie.Get("cat") - if x != LONG_WORD { - t.Error("expected %s, got %s", LONG_WORD, x) - } -} - -func TestTrieUpdating(t *testing.T) { - _, trie := New() - trie.Update("cat", LONG_WORD) - trie.Update("cat", LONG_WORD+"1") - x := trie.Get("cat") - if x != LONG_WORD+"1" { - t.Error("expected %S, got %s", LONG_WORD+"1", x) - } -} - -func TestTrieCmp(t *testing.T) { - _, trie1 := New() - _, trie2 := New() - - trie1.Update("doge", LONG_WORD) - trie2.Update("doge", LONG_WORD) - if !trie1.Cmp(trie2) { - t.Error("Expected tries to be equal") - } - - trie1.Update("dog", LONG_WORD) - trie2.Update("cat", LONG_WORD) - if trie1.Cmp(trie2) { - t.Errorf("Expected tries not to be equal %x %x", trie1.Root, trie2.Root) - } -} - -func TestTrieDelete(t *testing.T) { - _, trie := New() - trie.Update("cat", LONG_WORD) - exp := trie.Root - trie.Update("dog", LONG_WORD) - trie.Delete("dog") - if !reflect.DeepEqual(exp, trie.Root) { - t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root) - } - - trie.Update("dog", LONG_WORD) - exp = trie.Root - trie.Update("dude", LONG_WORD) - trie.Delete("dude") - if !reflect.DeepEqual(exp, trie.Root) { - t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root) - } -} - -func TestTrieDeleteWithValue(t *testing.T) { - _, trie := New() - trie.Update("c", LONG_WORD) - exp := trie.Root - trie.Update("ca", LONG_WORD) - trie.Update("cat", LONG_WORD) - trie.Delete("ca") - trie.Delete("cat") - if !reflect.DeepEqual(exp, trie.Root) { - t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root) - } - -} - -func TestTriePurge(t *testing.T) { - _, trie := New() - trie.Update("c", LONG_WORD) - trie.Update("ca", LONG_WORD) - trie.Update("cat", LONG_WORD) - - lenBefore := len(trie.cache.nodes) - it := trie.NewIterator() - if num := it.Purge(); num != 3 { - t.Errorf("Expected purge to return 3, got %d", num) - } - - if lenBefore == len(trie.cache.nodes) { - t.Errorf("Expected cached nodes to be deleted") - } -} - -func TestTrieIt(t *testing.T) { - _, trie := New() - - data := [][]string{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"ether", ""}, - {"dog", "puppy"}, - {"shaman", ""}, - } - - for _, item := range data { - trie.Update(item[0], item[1]) - } - - fmt.Printf("root %x", trie.Root) -} -- cgit v1.2.3 From 5a86892ecbd68c3d466cb1ef282c4cb81300abce Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 13:08:00 +0200 Subject: Using remote for test cases --- ethutil/trie.go | 17 ++++++-- ethutil/trie_test.go | 108 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 108 insertions(+), 17 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index 18d0a5f0a..ce9c2da27 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -43,11 +43,11 @@ func NewCache(db Database) *Cache { return &Cache{db: db, nodes: make(map[string]*Node)} } -func (cache *Cache) Put(v interface{}) interface{} { +func (cache *Cache) PutValue(v interface{}, force bool) interface{} { value := NewValue(v) enc := value.Encode() - if len(enc) >= 32 { + if len(enc) >= 32 || force { sha := Sha3Bin(enc) cache.nodes[string(sha)] = NewNode(sha, value, true) @@ -59,6 +59,10 @@ func (cache *Cache) Put(v interface{}) interface{} { return v } +func (cache *Cache) Put(v interface{}) interface{} { + return cache.PutValue(v, false) +} + func (cache *Cache) Get(key []byte) *Value { // First check if the key is the cache if cache.nodes[string(key)] != nil { @@ -168,7 +172,12 @@ func (t *Trie) Update(key string, value string) { k := CompactHexDecode(key) - t.Root = t.UpdateState(t.Root, k, value) + root := t.UpdateState(t.Root, k, value) + if _, ok := root.([]byte); !ok { + t.Root = t.cache.PutValue(root, true) + } else { + t.Root = root + } } func (t *Trie) Get(key string) string { @@ -527,6 +536,8 @@ func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { } func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallback) { + //fmt.Println("node", currentNode) + if currentNode.Len() == 2 { k := CompactDecode(currentNode.Get(0).Str()) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 2937b1525..3ee955b11 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,12 @@ package ethutil import ( + "bytes" + "encoding/hex" + "encoding/json" "fmt" + "io/ioutil" + "net/http" "reflect" "testing" ) @@ -171,23 +176,98 @@ func TestTriePurge(t *testing.T) { } } -func TestTrieIt(t *testing.T) { - _, trie := New() +func h(str string) string { + d, err := hex.DecodeString(str) + if err != nil { + panic(err) + } + + return string(d) +} - data := [][]string{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"ether", ""}, - {"dog", "puppy"}, - {"shaman", ""}, +func get(in string) (out string) { + if len(in) > 2 && in[:2] == "0x" { + out = h(in[2:]) + } else { + out = in } - for _, item := range data { - trie.Update(item[0], item[1]) + return +} + +type Test struct { + Name string + In map[string]string + Root string +} + +func CreateTest(name string, data []byte) (Test, error) { + t := Test{Name: name} + err := json.Unmarshal(data, &t) + if err != nil { + return Test{}, fmt.Errorf("%v", err) } - fmt.Printf("root %x", trie.Root) + return t, nil +} + +func CreateTests(uri string, cb func(Test)) { + resp, err := http.Get(uri) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + + var objmap map[string]*json.RawMessage + err = json.Unmarshal(data, &objmap) + if err != nil { + panic(err) + } + + for name, testData := range objmap { + test, err := CreateTest(name, *testData) + if err != nil { + panic(err) + } + + cb(test) + } +} + +func TestRemote(t *testing.T) { + CreateTests("https://raw.githubusercontent.com/ethereum/tests/develop/trietest.json", func(test Test) { + _, trie := New() + for key, value := range test.In { + trie.Update(get(key), get(value)) + } + fmt.Printf("%-15s: %x\n", test.Name, trie.Root) + + a := NewValue(h(test.Root)).Bytes() + b := NewValue(trie.Root).Bytes() + if bytes.Compare(a, b) != 0 { + t.Errorf("%-10s: %x %x", test.Name, a, b) + } + }) +} + +func TestTrieReplay(t *testing.T) { + CreateTests("https://raw.githubusercontent.com/ethereum/tests/develop/trietest.json", func(test Test) { + _, trie := New() + for key, value := range test.In { + trie.Update(get(key), get(value)) + } + + _, trie2 := New() + trie.NewIterator().Each(func(key string, v *Value) { + trie2.Update(key, string(v.Str())) + }) + + a := NewValue(trie.Root).Bytes() + b := NewValue(trie2.Root).Bytes() + if bytes.Compare(a, b) != 0 { + t.Errorf("root %x %x\n", trie.Root, trie2.Root) + } + }) } -- cgit v1.2.3 From 8ddd4c4c52eef9f382a321fa880adba4a1e35ee2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 13:09:04 +0200 Subject: wip --- ethutil/value.go | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index ddd864d8a..b37b33c28 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -116,6 +116,8 @@ func (val *Value) Bytes() []byte { return a } else if s, ok := val.Val.(byte); ok { return []byte{s} + } else if s, ok := val.Val.(string); ok { + return []byte(s) } return []byte{} @@ -196,6 +198,12 @@ 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 +} + func NewValueFromBytes(data []byte) *Value { if len(data) != 0 { data, _ := Decode(data, 0) -- cgit v1.2.3 From 9ed0d389b2402baf2dbc90fe12e9b4695ee22858 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 13:34:47 +0200 Subject: Generic trie --- ethutil/trie.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index ce9c2da27..26a27a901 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -191,7 +191,17 @@ func (t *Trie) Get(key string) string { } func (t *Trie) Delete(key string) { - t.Update(key, "") + t.mut.Lock() + defer t.mut.Unlock() + + k := CompactHexDecode(key) + + root := t.DeleteState(t.Root, k) + if _, ok := root.([]byte); !ok { + t.Root = t.cache.PutValue(root, true) + } else { + t.Root = root + } } func (t *Trie) GetState(node interface{}, key []int) interface{} { @@ -243,15 +253,7 @@ func (t *Trie) GetNode(node interface{}) *Value { } func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { - - if value != "" { - return t.InsertState(node, key, value) - } else { - // delete it - return t.DeleteState(node, key) - } - - return t.Root + return t.InsertState(node, key, value) } func (t *Trie) Put(node interface{}) interface{} { -- cgit v1.2.3 From 82272ee08a7d72be1cc0947b6a0e8096a0353362 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 14:28:54 +0200 Subject: Iterator fix --- ethutil/trie.go | 10 ++++------ ethutil/trie_test.go | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index 26a27a901..c669bdcb0 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -538,15 +538,13 @@ func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { } func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallback) { - //fmt.Println("node", currentNode) - if currentNode.Len() == 2 { k := CompactDecode(currentNode.Get(0).Str()) - if currentNode.Get(1).Str() == "" { - it.iterateNode(key, currentNode.Get(1), cb) + pk := append(key, k...) + if currentNode.Get(1).Len() != 0 && currentNode.Get(1).Str() == "" { + it.iterateNode(pk, currentNode.Get(1), cb) } else { - pk := append(key, k...) if k[len(k)-1] == 16 { cb(DecodeCompact(pk), currentNode.Get(1)) @@ -560,7 +558,7 @@ func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallba if i == 16 && currentNode.Get(i).Len() != 0 { cb(DecodeCompact(pk), currentNode.Get(i)) } else { - if currentNode.Get(i).Str() == "" { + if currentNode.Get(i).Len() != 0 && currentNode.Get(i).Str() == "" { it.iterateNode(pk, currentNode.Get(i), cb) } else { val := currentNode.Get(i).Str() diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 3ee955b11..d8db8a0d6 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -261,13 +261,13 @@ func TestTrieReplay(t *testing.T) { _, trie2 := New() trie.NewIterator().Each(func(key string, v *Value) { - trie2.Update(key, string(v.Str())) + trie2.Update(key, v.Str()) }) a := NewValue(trie.Root).Bytes() b := NewValue(trie2.Root).Bytes() if bytes.Compare(a, b) != 0 { - t.Errorf("root %x %x\n", trie.Root, trie2.Root) + t.Errorf("%s %x %x\n", test.Name, trie.Root, trie2.Root) } }) } -- cgit v1.2.3 From ed276cd7c241749a9cf8add4e2fae3d3608a7ea4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 20:03:31 +0200 Subject: Added Paranoia check for VM execution --- ethutil/trie.go | 18 ++++++++++++------ ethutil/trie_test.go | 21 ++++++++++++++++++++- 2 files changed, 32 insertions(+), 7 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie.go b/ethutil/trie.go index c669bdcb0..56f1648a6 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -173,10 +173,13 @@ func (t *Trie) Update(key string, value string) { k := CompactHexDecode(key) root := t.UpdateState(t.Root, k, value) - if _, ok := root.([]byte); !ok { - t.Root = t.cache.PutValue(root, true) - } else { + switch root.(type) { + case string: t.Root = root + case []byte: + t.Root = root + default: + t.Root = t.cache.PutValue(root, true) } } @@ -197,10 +200,13 @@ func (t *Trie) Delete(key string) { k := CompactHexDecode(key) root := t.DeleteState(t.Root, k) - if _, ok := root.([]byte); !ok { - t.Root = t.cache.PutValue(root, true) - } else { + switch root.(type) { + case string: t.Root = root + case []byte: + t.Root = root + default: + t.Root = t.cache.PutValue(root, true) } } diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index d8db8a0d6..542af5504 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -242,7 +242,6 @@ func TestRemote(t *testing.T) { for key, value := range test.In { trie.Update(get(key), get(value)) } - fmt.Printf("%-15s: %x\n", test.Name, trie.Root) a := NewValue(h(test.Root)).Bytes() b := NewValue(trie.Root).Bytes() @@ -271,3 +270,23 @@ func TestTrieReplay(t *testing.T) { } }) } + +func TestIt(t *testing.T) { + _, trie := New() + + test := map[string]string{ + "0x000000000000000000000000ec4f34c97e43fbb2816cfd95e388353c7181dab1": "0x4e616d6552656700000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000045": "0x22b224a1420a802ab51d326e29fa98e34c4f24ea", + "0x0000000000000000000000000000000000000000000000000000000000000046": "0x67706c2076330000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000697c7b8c961b56f675d570498424ac8de1a918f6": "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000", + "0x0000000000000000000000007ef9e639e2733cb34e4dfc576d4b23f72db776b2": "0x4655474156000000000000000000000000000000000000000000000000000000", + "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000": "0x697c7b8c961b56f675d570498424ac8de1a918f6", + "0x4655474156000000000000000000000000000000000000000000000000000000": "0x7ef9e639e2733cb34e4dfc576d4b23f72db776b2", + "0x4e616d6552656700000000000000000000000000000000000000000000000000": "0xec4f34c97e43fbb2816cfd95e388353c7181dab1", + } + + for k, v := range test { + trie.Update(k, v) + } + fmt.Printf("root : %x\n", trie.Root) +} -- cgit v1.2.3 From 5f5910c603c107ceaf5f240f9ca23cbf9c951f67 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 09:55:20 +0200 Subject: Regression test for trie --- ethutil/trie_test.go | 70 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 16 deletions(-) (limited to 'ethutil') diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 542af5504..85d81b6f4 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -6,9 +6,11 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math/rand" "net/http" "reflect" "testing" + "time" ) const LONG_WORD = "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ" @@ -211,7 +213,7 @@ func CreateTest(name string, data []byte) (Test, error) { return t, nil } -func CreateTests(uri string, cb func(Test)) { +func CreateTests(uri string, cb func(Test)) map[string]Test { resp, err := http.Get(uri) if err != nil { panic(err) @@ -226,14 +228,20 @@ func CreateTests(uri string, cb func(Test)) { panic(err) } + tests := make(map[string]Test) for name, testData := range objmap { test, err := CreateTest(name, *testData) if err != nil { panic(err) } - cb(test) + if cb != nil { + cb(test) + } + tests[name] = test } + + return tests } func TestRemote(t *testing.T) { @@ -271,22 +279,52 @@ func TestTrieReplay(t *testing.T) { }) } -func TestIt(t *testing.T) { - _, trie := New() +func RandomData() [][]string { + data := [][]string{ + {"0x000000000000000000000000ec4f34c97e43fbb2816cfd95e388353c7181dab1", "0x4e616d6552656700000000000000000000000000000000000000000000000000"}, + {"0x0000000000000000000000000000000000000000000000000000000000000045", "0x22b224a1420a802ab51d326e29fa98e34c4f24ea"}, + {"0x0000000000000000000000000000000000000000000000000000000000000046", "0x67706c2076330000000000000000000000000000000000000000000000000000"}, + {"0x000000000000000000000000697c7b8c961b56f675d570498424ac8de1a918f6", "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000"}, + {"0x0000000000000000000000007ef9e639e2733cb34e4dfc576d4b23f72db776b2", "0x4655474156000000000000000000000000000000000000000000000000000000"}, + {"0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000", "0x697c7b8c961b56f675d570498424ac8de1a918f6"}, + {"0x4655474156000000000000000000000000000000000000000000000000000000", "0x7ef9e639e2733cb34e4dfc576d4b23f72db776b2"}, + {"0x4e616d6552656700000000000000000000000000000000000000000000000000", "0xec4f34c97e43fbb2816cfd95e388353c7181dab1"}, + } + + var c [][]string + for len(data) != 0 { + e := rand.Intn(len(data)) + c = append(c, data[e]) + + copy(data[e:], data[e+1:]) + data[len(data)-1] = nil + data = data[:len(data)-1] + } + + return c +} + +const MaxTest = 1000 + +// This test insert data in random order and seeks to find indifferences between the different tries +func TestRegression(t *testing.T) { + rand.Seed(time.Now().Unix()) + + roots := make(map[string]int) + for i := 0; i < MaxTest; i++ { + _, trie := New() + data := RandomData() + + for _, test := range data { + trie.Update(test[0], test[1]) + } - test := map[string]string{ - "0x000000000000000000000000ec4f34c97e43fbb2816cfd95e388353c7181dab1": "0x4e616d6552656700000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000045": "0x22b224a1420a802ab51d326e29fa98e34c4f24ea", - "0x0000000000000000000000000000000000000000000000000000000000000046": "0x67706c2076330000000000000000000000000000000000000000000000000000", - "0x000000000000000000000000697c7b8c961b56f675d570498424ac8de1a918f6": "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000", - "0x0000000000000000000000007ef9e639e2733cb34e4dfc576d4b23f72db776b2": "0x4655474156000000000000000000000000000000000000000000000000000000", - "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000": "0x697c7b8c961b56f675d570498424ac8de1a918f6", - "0x4655474156000000000000000000000000000000000000000000000000000000": "0x7ef9e639e2733cb34e4dfc576d4b23f72db776b2", - "0x4e616d6552656700000000000000000000000000000000000000000000000000": "0xec4f34c97e43fbb2816cfd95e388353c7181dab1", + roots[string(trie.Root.([]byte))] += 1 } - for k, v := range test { - trie.Update(k, v) + if len(roots) > 1 { + for root, num := range roots { + t.Errorf("%x => %d\n", root, num) + } } - fmt.Printf("root : %x\n", trie.Root) } -- cgit v1.2.3 From 39263b674c1a8a13a1c29349a48b3cdc4c5948db Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 09:56:10 +0200 Subject: Paranoia --- ethutil/config.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index b253aa203..6ebb5e8cd 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -14,6 +14,7 @@ type config struct { ExecPath string Debug bool + Paranoia bool Ver string ClientString string Pubkey []byte @@ -44,7 +45,7 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier} + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier, Paranoia: true} Config.SetClientString("Ethereum(G)") } return Config -- cgit v1.2.3 From 92693e44599c44e606813d2c3259cc9f6f81a644 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 11:26:45 +0200 Subject: The dragon has been slain. Consensus reached! --- ethutil/trie_test.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethutil') diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 85d81b6f4..01207dbc3 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -318,6 +318,7 @@ func TestRegression(t *testing.T) { for _, test := range data { trie.Update(test[0], test[1]) } + trie.Delete("0x4e616d6552656700000000000000000000000000000000000000000000000000") roots[string(trie.Root.([]byte))] += 1 } -- cgit v1.2.3 From 7a9ff4f8d45e741625bc32fde59b3dfe90851492 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 16:28:17 +0200 Subject: bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 675175cdd..d716005b5 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -44,7 +44,7 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier, Paranoia: true} + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.16", conf: g, Identifier: Identifier, Paranoia: true} Config.SetClientString("Ethereum(G)") } return Config -- cgit v1.2.3 From 3889785017a1381d215cb1dc47fd5fb5b38add79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 20:08:18 +0200 Subject: Added Path utility --- ethutil/path.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 ethutil/path.go (limited to 'ethutil') diff --git a/ethutil/path.go b/ethutil/path.go new file mode 100644 index 000000000..97f58ab7e --- /dev/null +++ b/ethutil/path.go @@ -0,0 +1,20 @@ +package ethutil + +import ( + "os/user" + "strings" +) + +func ExpandHomePath(p string) (path string) { + path = p + + // Check in case of paths like "/something/~/something/" + if path[:2] == "~/" { + usr, _ := user.Current() + dir := usr.HomeDir + + path = strings.Replace(p, "~", dir, 1) + } + + return +} -- cgit v1.2.3 From 28ef7d228c4e8e24315eb585e4e0d03a4c652ccb Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 20:08:48 +0200 Subject: Added Left and Right padding utility functions --- ethutil/bytes.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index c2817946b..5737a75c9 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -118,7 +118,8 @@ func FormatData(data string) []byte { // Simple stupid d := new(big.Int) if data[0:1] == "\"" && data[len(data)-1:] == "\"" { - d.SetBytes([]byte(data[1 : len(data)-1])) + return RightPadBytes([]byte(data), 32) + //d.SetBytes([]byte(data[1 : len(data)-1])) } else if len(data) > 1 && data[:2] == "0x" { d.SetBytes(Hex2Bytes(data[2:])) } else { @@ -127,3 +128,25 @@ func FormatData(data string) []byte { return BigToBytes(d, 256) } + +func LeftPadBytes(slice []byte, l int) []byte { + if l <= len(slice) { + return slice + } + + padded := make([]byte, l) + copy(padded[0:len(slice)], slice) + + return padded +} + +func RightPadBytes(slice []byte, l int) []byte { + if l <= len(slice) { + return slice + } + + padded := make([]byte, l) + copy(padded[l-len(slice):], slice) + + return padded +} -- cgit v1.2.3 From d7e396a98ccafb53b4f632228b670634baeb36a0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 23:59:37 +0200 Subject: l <=> r --- ethutil/bytes.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 5737a75c9..ad60e62fd 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -119,7 +119,6 @@ func FormatData(data string) []byte { d := new(big.Int) if data[0:1] == "\"" && data[len(data)-1:] == "\"" { return RightPadBytes([]byte(data), 32) - //d.SetBytes([]byte(data[1 : len(data)-1])) } else if len(data) > 1 && data[:2] == "0x" { d.SetBytes(Hex2Bytes(data[2:])) } else { @@ -129,7 +128,7 @@ func FormatData(data string) []byte { return BigToBytes(d, 256) } -func LeftPadBytes(slice []byte, l int) []byte { +func RightPadBytes(slice []byte, l int) []byte { if l <= len(slice) { return slice } @@ -140,7 +139,7 @@ func LeftPadBytes(slice []byte, l int) []byte { return padded } -func RightPadBytes(slice []byte, l int) []byte { +func LeftPadBytes(slice []byte, l int) []byte { if l <= len(slice) { return slice } -- cgit v1.2.3 From 1954ef47e67762f0308544e3a17976e4c3927e32 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 00:06:21 +0200 Subject: Suicide is deferred to update --- ethutil/bytes.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index ad60e62fd..d68a69433 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -129,7 +129,7 @@ func FormatData(data string) []byte { } func RightPadBytes(slice []byte, l int) []byte { - if l <= len(slice) { + if l < len(slice) { return slice } @@ -140,7 +140,7 @@ func RightPadBytes(slice []byte, l int) []byte { } func LeftPadBytes(slice []byte, l int) []byte { - if l <= len(slice) { + if l < len(slice) { return slice } -- cgit v1.2.3 From f02602d02d12204a10c2aa9d1d43332b1be2fe0a Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 3 Jul 2014 17:30:51 +0100 Subject: ConfigManager (transitional) - remove clientstring handling from ethutil.Config - ReadConfig takes no Identifier argument - members Ver, ClientString, ClientIdentifier removed from Config - type ConfValue removed - expose public type ethutil.ConfigManager - Set -> Save(key string, value interface{}) now takes any value to allow for persisting non-string values directly - TODO: eliminate all eth specific configs, just a wrapper around globalconf --- ethutil/config.go | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index d716005b5..c9b86100b 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -5,29 +5,25 @@ import ( "fmt" "github.com/rakyll/globalconf" "os" - "runtime" ) // Config struct -type config struct { +type ConfigManager struct { Db Database - ExecPath string - Debug bool - Paranoia bool - Ver string - ClientString string - Identifier string + ExecPath string + Debug bool + Paranoia bool conf *globalconf.GlobalConf } -var Config *config +var Config *ConfigManager // Read config // // Initialize Config from Config File -func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) *config { +func ReadConfig(ConfigFile string, Datadir string, EnvPrefix string) *ConfigManager { if Config == nil { // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags _, err := os.Stat(ConfigFile) @@ -44,34 +40,30 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.16", conf: g, Identifier: Identifier, Paranoia: true} - Config.SetClientString("Ethereum(G)") + Config = &ConfigManager{ExecPath: Datadir, Debug: true, conf: g, Paranoia: true} } return Config } -// Set client string -// -func (c *config) SetClientString(str string) { - os := runtime.GOOS - cust := c.Identifier - Config.ClientString = fmt.Sprintf("%s/v%s/%s/%s/Go", str, c.Ver, cust, os) -} - -func (c *config) SetIdentifier(id string) { - c.Identifier = id - c.Set("id", id) -} - // provides persistence for flags -func (c *config) Set(key, value string) { - f := &flag.Flag{Name: key, Value: &confValue{value}} +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 } -- cgit v1.2.3 From d5bcc01eae2912528e8ab2a65733c84fa3f8f4e1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 4 Jul 2014 13:05:07 +0200 Subject: Fixed shebang check. Previously it would hang on an unknown shebang --- ethutil/script.go | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index af4ca6a38..aaa0f8ed8 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -10,28 +10,36 @@ import ( // General compile function func Compile(script string) (ret []byte, err error) { - c := strings.Split(script, "\n")[0] + if len(script) > 2 { + line := strings.Split(script, "\n")[0] - if c == "#!serpent" { - byteCode, err := serpent.Compile(script) - if err != nil { - return nil, err - } + if line[0:2] == "#!" { + switch line { + case "#!serpent": + byteCode, err := serpent.Compile(script) + if err != nil { + return nil, err + } + + return byteCode, nil + } + } else { - return byteCode, nil - } else { - compiler := mutan.NewCompiler(backend.NewEthereumBackend()) - byteCode, errors := compiler.Compile(strings.NewReader(script)) - if len(errors) > 0 { - var errs string - for _, er := range errors { - if er != nil { - errs += er.Error() + compiler := mutan.NewCompiler(backend.NewEthereumBackend()) + byteCode, errors := compiler.Compile(strings.NewReader(script)) + if len(errors) > 0 { + var errs string + for _, er := range errors { + if er != nil { + errs += er.Error() + } } + return nil, fmt.Errorf("%v", errs) } - return nil, fmt.Errorf("%v", errs) - } - return byteCode, nil + return byteCode, nil + } } + + return nil, nil } -- cgit v1.2.3 From 23b5b5fa36530eb82543d7d877f8e9e1900232cf Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 4 Jul 2014 13:34:50 +0200 Subject: Length check --- ethutil/script.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index aaa0f8ed8..fa05094e7 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -13,7 +13,7 @@ func Compile(script string) (ret []byte, err error) { if len(script) > 2 { line := strings.Split(script, "\n")[0] - if line[0:2] == "#!" { + if len(line) > 1 && line[0:2] == "#!" { switch line { case "#!serpent": byteCode, err := serpent.Compile(script) -- cgit v1.2.3 From 90eb4f1939f7b0389d5784b889cc0e5d2b3451f7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 4 Jul 2014 15:32:10 +0200 Subject: Debug output, minor fixes and tweaks * Script compile length fix * Transition fix --- ethutil/script.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index fa05094e7..f5c53f84c 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -9,7 +9,7 @@ import ( ) // General compile function -func Compile(script string) (ret []byte, err error) { +func Compile(script string, silent bool) (ret []byte, err error) { if len(script) > 2 { line := strings.Split(script, "\n")[0] @@ -26,6 +26,7 @@ func Compile(script string) (ret []byte, err error) { } else { compiler := mutan.NewCompiler(backend.NewEthereumBackend()) + compiler.Silent = silent byteCode, errors := compiler.Compile(strings.NewReader(script)) if len(errors) > 0 { var errs string -- cgit v1.2.3 From af2726414078840aae32aa4c982d3a8c5cf66ef5 Mon Sep 17 00:00:00 2001 From: zelig Date: Fri, 4 Jul 2014 19:37:40 +0100 Subject: remove reactor code from ethutil --- ethutil/reactor.go | 87 ------------------------------------------------- ethutil/reactor_test.go | 30 ----------------- 2 files changed, 117 deletions(-) delete mode 100644 ethutil/reactor.go delete mode 100644 ethutil/reactor_test.go (limited to 'ethutil') diff --git a/ethutil/reactor.go b/ethutil/reactor.go deleted file mode 100644 index 7cf145245..000000000 --- a/ethutil/reactor.go +++ /dev/null @@ -1,87 +0,0 @@ -package ethutil - -import ( - "sync" -) - -type ReactorEvent struct { - mut sync.Mutex - event string - chans []chan React -} - -// Post the specified reactor resource on the channels -// currently subscribed -func (e *ReactorEvent) Post(react React) { - e.mut.Lock() - defer e.mut.Unlock() - - for _, ch := range e.chans { - go func(ch chan React) { - ch <- react - }(ch) - } -} - -// Add a subscriber to this event -func (e *ReactorEvent) Add(ch chan React) { - e.mut.Lock() - defer e.mut.Unlock() - - e.chans = append(e.chans, ch) -} - -// Remove a subscriber -func (e *ReactorEvent) Remove(ch chan React) { - e.mut.Lock() - defer e.mut.Unlock() - - for i, c := range e.chans { - if c == ch { - e.chans = append(e.chans[:i], e.chans[i+1:]...) - } - } -} - -// Basic reactor resource -type React struct { - Resource interface{} - Event string -} - -// The reactor basic engine. Acts as bridge -// between the events and the subscribers/posters -type ReactorEngine struct { - patterns map[string]*ReactorEvent -} - -func NewReactorEngine() *ReactorEngine { - return &ReactorEngine{patterns: make(map[string]*ReactorEvent)} -} - -// Subscribe a channel to the specified event -func (reactor *ReactorEngine) Subscribe(event string, ch chan React) { - ev := reactor.patterns[event] - // Create a new event if one isn't available - if ev == nil { - ev = &ReactorEvent{event: event} - reactor.patterns[event] = ev - } - - // Add the channel to reactor event handler - ev.Add(ch) -} - -func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) { - ev := reactor.patterns[event] - if ev != nil { - ev.Remove(ch) - } -} - -func (reactor *ReactorEngine) Post(event string, resource interface{}) { - ev := reactor.patterns[event] - if ev != nil { - ev.Post(React{Resource: resource, Event: event}) - } -} diff --git a/ethutil/reactor_test.go b/ethutil/reactor_test.go deleted file mode 100644 index 48c2f0df3..000000000 --- a/ethutil/reactor_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package ethutil - -import "testing" - -func TestReactorAdd(t *testing.T) { - engine := NewReactorEngine() - ch := make(chan React) - engine.Subscribe("test", ch) - if len(engine.patterns) != 1 { - t.Error("Expected patterns to be 1, got", len(engine.patterns)) - } -} - -func TestReactorEvent(t *testing.T) { - engine := NewReactorEngine() - - // Buffer 1, so it doesn't block for this test - ch := make(chan React, 1) - engine.Subscribe("test", ch) - engine.Post("test", "hello") - - value := <-ch - if val, ok := value.Resource.(string); ok { - if val != "hello" { - t.Error("Expected Resource to be 'hello', got", val) - } - } else { - t.Error("Unable to cast") - } -} -- cgit v1.2.3 From 6fe9b4ab5e839be96eb1c4a619bc14fab622d8d1 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Mon, 7 Jul 2014 10:59:16 +0200 Subject: Revert "ethreact - Feature/ethutil refactor" --- ethutil/reactor.go | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ ethutil/reactor_test.go | 30 +++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 ethutil/reactor.go create mode 100644 ethutil/reactor_test.go (limited to 'ethutil') diff --git a/ethutil/reactor.go b/ethutil/reactor.go new file mode 100644 index 000000000..7cf145245 --- /dev/null +++ b/ethutil/reactor.go @@ -0,0 +1,87 @@ +package ethutil + +import ( + "sync" +) + +type ReactorEvent struct { + mut sync.Mutex + event string + chans []chan React +} + +// Post the specified reactor resource on the channels +// currently subscribed +func (e *ReactorEvent) Post(react React) { + e.mut.Lock() + defer e.mut.Unlock() + + for _, ch := range e.chans { + go func(ch chan React) { + ch <- react + }(ch) + } +} + +// Add a subscriber to this event +func (e *ReactorEvent) Add(ch chan React) { + e.mut.Lock() + defer e.mut.Unlock() + + e.chans = append(e.chans, ch) +} + +// Remove a subscriber +func (e *ReactorEvent) Remove(ch chan React) { + e.mut.Lock() + defer e.mut.Unlock() + + for i, c := range e.chans { + if c == ch { + e.chans = append(e.chans[:i], e.chans[i+1:]...) + } + } +} + +// Basic reactor resource +type React struct { + Resource interface{} + Event string +} + +// The reactor basic engine. Acts as bridge +// between the events and the subscribers/posters +type ReactorEngine struct { + patterns map[string]*ReactorEvent +} + +func NewReactorEngine() *ReactorEngine { + return &ReactorEngine{patterns: make(map[string]*ReactorEvent)} +} + +// Subscribe a channel to the specified event +func (reactor *ReactorEngine) Subscribe(event string, ch chan React) { + ev := reactor.patterns[event] + // Create a new event if one isn't available + if ev == nil { + ev = &ReactorEvent{event: event} + reactor.patterns[event] = ev + } + + // Add the channel to reactor event handler + ev.Add(ch) +} + +func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) { + ev := reactor.patterns[event] + if ev != nil { + ev.Remove(ch) + } +} + +func (reactor *ReactorEngine) Post(event string, resource interface{}) { + ev := reactor.patterns[event] + if ev != nil { + ev.Post(React{Resource: resource, Event: event}) + } +} diff --git a/ethutil/reactor_test.go b/ethutil/reactor_test.go new file mode 100644 index 000000000..48c2f0df3 --- /dev/null +++ b/ethutil/reactor_test.go @@ -0,0 +1,30 @@ +package ethutil + +import "testing" + +func TestReactorAdd(t *testing.T) { + engine := NewReactorEngine() + ch := make(chan React) + engine.Subscribe("test", ch) + if len(engine.patterns) != 1 { + t.Error("Expected patterns to be 1, got", len(engine.patterns)) + } +} + +func TestReactorEvent(t *testing.T) { + engine := NewReactorEngine() + + // Buffer 1, so it doesn't block for this test + ch := make(chan React, 1) + engine.Subscribe("test", ch) + engine.Post("test", "hello") + + value := <-ch + if val, ok := value.Resource.(string); ok { + if val != "hello" { + t.Error("Expected Resource to be 'hello', got", val) + } + } else { + t.Error("Unable to cast") + } +} -- cgit v1.2.3 From 5c7e96d895f18e774c89b26cd99d998d4d08e1f8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 18:19:38 +0200 Subject: Removed serpent --- ethutil/script.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index f5c53f84c..b796e7c1e 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/obscuren/mutan" "github.com/obscuren/mutan/backends" - "github.com/obscuren/serpent-go" "strings" ) @@ -15,13 +14,15 @@ func Compile(script string, silent bool) (ret []byte, err error) { if len(line) > 1 && line[0:2] == "#!" { switch line { - case "#!serpent": - byteCode, err := serpent.Compile(script) - if err != nil { - return nil, err - } + /* + case "#!serpent": + byteCode, err := serpent.Compile(script) + if err != nil { + return nil, err + } - return byteCode, nil + return byteCode, nil + */ } } else { -- cgit v1.2.3 From 9010857677ac374e09bab62a89f2fb52c11ed6d3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 11 Jul 2014 16:04:09 +0200 Subject: Special diff output for execution --- ethutil/config.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index c9b86100b..2f3d706fe 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -13,6 +13,7 @@ type ConfigManager struct { ExecPath string Debug bool + Diff bool Paranoia bool conf *globalconf.GlobalConf -- cgit v1.2.3 From 04f8c455e2d8585902e2c9f0cfb8717ef74a65ca Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 00:37:50 +0200 Subject: Added diff type --- ethutil/config.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 2f3d706fe..41bece21d 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -14,6 +14,7 @@ type ConfigManager struct { ExecPath string Debug bool Diff bool + DiffType string Paranoia bool conf *globalconf.GlobalConf -- cgit v1.2.3 From 8845fb7eae3e51fd3e55c47c377bf1a9e0cfe2a9 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 14 Jul 2014 15:24:38 +0200 Subject: Add windows helper functions --- ethutil/common.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go index 6d88a1ed2..2fd031a20 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -3,8 +3,20 @@ package ethutil import ( "fmt" "math/big" + "runtime" ) +func IsWindows() bool { + return runtime.GOOS == "windows" +} + +func WindonizePath(path string) string { + if string(path[0]) == "/" && IsWindows() { + path = path[1:] + } + return path +} + // The different number of units var ( Douglas = BigPow(10, 42) -- cgit v1.2.3 From 2784e256f1c5f8112486e9037c9b00e628e5aa10 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 00:25:49 +0200 Subject: Vm logging on diff --- ethutil/value.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index b37b33c28..ecb9d1511 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -190,6 +190,19 @@ func (val *Value) Get(idx int) *Value { 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) } -- cgit v1.2.3 From 1735ec0362e84455126d8c1bd380ecae436d1167 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 15 Jul 2014 01:11:06 +0100 Subject: use ethreact.Event and ethreact.ReactorEngine --- ethutil/reactor.go | 87 ------------------------------------------------- ethutil/reactor_test.go | 30 ----------------- 2 files changed, 117 deletions(-) delete mode 100644 ethutil/reactor.go delete mode 100644 ethutil/reactor_test.go (limited to 'ethutil') diff --git a/ethutil/reactor.go b/ethutil/reactor.go deleted file mode 100644 index 7cf145245..000000000 --- a/ethutil/reactor.go +++ /dev/null @@ -1,87 +0,0 @@ -package ethutil - -import ( - "sync" -) - -type ReactorEvent struct { - mut sync.Mutex - event string - chans []chan React -} - -// Post the specified reactor resource on the channels -// currently subscribed -func (e *ReactorEvent) Post(react React) { - e.mut.Lock() - defer e.mut.Unlock() - - for _, ch := range e.chans { - go func(ch chan React) { - ch <- react - }(ch) - } -} - -// Add a subscriber to this event -func (e *ReactorEvent) Add(ch chan React) { - e.mut.Lock() - defer e.mut.Unlock() - - e.chans = append(e.chans, ch) -} - -// Remove a subscriber -func (e *ReactorEvent) Remove(ch chan React) { - e.mut.Lock() - defer e.mut.Unlock() - - for i, c := range e.chans { - if c == ch { - e.chans = append(e.chans[:i], e.chans[i+1:]...) - } - } -} - -// Basic reactor resource -type React struct { - Resource interface{} - Event string -} - -// The reactor basic engine. Acts as bridge -// between the events and the subscribers/posters -type ReactorEngine struct { - patterns map[string]*ReactorEvent -} - -func NewReactorEngine() *ReactorEngine { - return &ReactorEngine{patterns: make(map[string]*ReactorEvent)} -} - -// Subscribe a channel to the specified event -func (reactor *ReactorEngine) Subscribe(event string, ch chan React) { - ev := reactor.patterns[event] - // Create a new event if one isn't available - if ev == nil { - ev = &ReactorEvent{event: event} - reactor.patterns[event] = ev - } - - // Add the channel to reactor event handler - ev.Add(ch) -} - -func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) { - ev := reactor.patterns[event] - if ev != nil { - ev.Remove(ch) - } -} - -func (reactor *ReactorEngine) Post(event string, resource interface{}) { - ev := reactor.patterns[event] - if ev != nil { - ev.Post(React{Resource: resource, Event: event}) - } -} diff --git a/ethutil/reactor_test.go b/ethutil/reactor_test.go deleted file mode 100644 index 48c2f0df3..000000000 --- a/ethutil/reactor_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package ethutil - -import "testing" - -func TestReactorAdd(t *testing.T) { - engine := NewReactorEngine() - ch := make(chan React) - engine.Subscribe("test", ch) - if len(engine.patterns) != 1 { - t.Error("Expected patterns to be 1, got", len(engine.patterns)) - } -} - -func TestReactorEvent(t *testing.T) { - engine := NewReactorEngine() - - // Buffer 1, so it doesn't block for this test - ch := make(chan React, 1) - engine.Subscribe("test", ch) - engine.Post("test", "hello") - - value := <-ch - if val, ok := value.Resource.(string); ok { - if val != "hello" { - t.Error("Expected Resource to be 'hello', got", val) - } - } else { - t.Error("Unable to cast") - } -} -- cgit v1.2.3 From 14c4f06100d9f06592097c4ee588d0f83f6b17bd Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 16 Jul 2014 13:20:57 +0200 Subject: Convert a byte slice to address --- ethutil/bytes.go | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index d68a69433..07584d0bf 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -149,3 +149,13 @@ func LeftPadBytes(slice []byte, l int) []byte { return padded } + +func Address(slice []byte) []byte { + if len(slice) < 20 { + slice = LeftPadBytes(slice, 20) + } else if len(slice) > 20 { + slice = slice[len(slice)-20:] + } + + return slice +} -- cgit v1.2.3 From ed3424ff75b396360990725afc124326dea4ab45 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 11:21:18 +0200 Subject: Trie fixes --- ethutil/bytes.go | 12 ++++++++---- ethutil/value.go | 8 +++----- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 07584d0bf..d16bd6780 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -150,12 +150,16 @@ func LeftPadBytes(slice []byte, l int) []byte { return padded } -func Address(slice []byte) []byte { +func Address(slice []byte) (addr []byte) { if len(slice) < 20 { - slice = LeftPadBytes(slice, 20) + addr = LeftPadBytes(slice, 20) } else if len(slice) > 20 { - slice = slice[len(slice)-20:] + addr = slice[len(slice)-20:] + } else { + addr = slice } - return slice + addr = CopyBytes(addr) + + return } diff --git a/ethutil/value.go b/ethutil/value.go index ecb9d1511..fba7426d1 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -40,13 +40,9 @@ func (val *Value) Len() int { //return val.kind.Len() if data, ok := val.Val.([]interface{}); ok { return len(data) - } else if data, ok := val.Val.([]byte); ok { - return len(data) - } else if data, ok := val.Val.(string); ok { - return len(data) } - return 0 + return len(val.Bytes()) } func (val *Value) Raw() interface{} { @@ -118,6 +114,8 @@ func (val *Value) Bytes() []byte { 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() } return []byte{} -- cgit v1.2.3 From a626b7ebe1fa5f1029840e25e88a4de426cf64c4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 17:11:00 +0200 Subject: Fixed string data --- ethutil/bytes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index d16bd6780..34fff7d42 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -118,7 +118,7 @@ func FormatData(data string) []byte { // Simple stupid d := new(big.Int) if data[0:1] == "\"" && data[len(data)-1:] == "\"" { - return RightPadBytes([]byte(data), 32) + return RightPadBytes([]byte(data[1:len(data)-1]), 32) } else if len(data) > 1 && data[:2] == "0x" { d.SetBytes(Hex2Bytes(data[2:])) } else { -- cgit v1.2.3 From 20ee1ae65e57ef7d60404277162c84c572c6bb10 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 21 Jul 2014 20:38:43 +0200 Subject: Refactored CALLDATALOAD to use big int * Added BigMin --- ethutil/big.go | 19 +++++++++++-------- ethutil/common.go | 12 +++++++----- 2 files changed, 18 insertions(+), 13 deletions(-) (limited to 'ethutil') diff --git a/ethutil/big.go b/ethutil/big.go index 7af6f7414..ec263b818 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -4,14 +4,6 @@ import ( "math/big" ) -var BigInt0 *big.Int = big.NewInt(0) - -// True -var BigTrue *big.Int = big.NewInt(1) - -// False -var BigFalse *big.Int = big.NewInt(0) - // Big pow // // Returns the power of two big integers @@ -73,3 +65,14 @@ func BigMax(x, y *big.Int) *big.Int { return x } + +// Big min +// +// Returns the minimum size big integer +func BigMin(x, y *big.Int) *big.Int { + if x.Cmp(y) >= 0 { + return y + } + + return x +} diff --git a/ethutil/common.go b/ethutil/common.go index 2fd031a20..cbd94e7ad 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -58,9 +58,11 @@ func CurrencyToString(num *big.Int) string { // Common big integers often used var ( - Big1 = big.NewInt(1) - Big2 = big.NewInt(2) - Big0 = big.NewInt(0) - Big32 = big.NewInt(32) - Big256 = big.NewInt(0xff) + Big1 = big.NewInt(1) + Big2 = big.NewInt(2) + Big0 = big.NewInt(0) + BigTrue = Big1 + BigFalse = Big0 + Big32 = big.NewInt(32) + Big256 = big.NewInt(0xff) ) -- cgit v1.2.3 From 5d57b7847105639efe1945e1ff588b1116a11a54 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 22 Jul 2014 16:16:00 +0200 Subject: Added big int to uint switch --- ethutil/value.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index fba7426d1..735a71dbc 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -68,6 +68,8 @@ func (val *Value) Uint() uint64 { return uint64(Val) } else if Val, ok := val.Val.([]byte); ok { return ReadVarint(bytes.NewReader(Val)) + } else if Val, ok := val.Val.(*big.Int); ok { + return Val.Uint64() } return 0 -- cgit v1.2.3 From 41bd38147c2e5968283facf641b2444c09f53d14 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Jul 2014 11:24:44 +0200 Subject: Clean up and util methods --- ethutil/bytes.go | 1 + ethutil/config.go | 6 +++--- ethutil/path.go | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 34fff7d42..53b8cf645 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -98,6 +98,7 @@ func Bytes2Hex(d []byte) string { func Hex2Bytes(str string) []byte { h, _ := hex.DecodeString(str) + return h } diff --git a/ethutil/config.go b/ethutil/config.go index 41bece21d..81052318e 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -3,8 +3,9 @@ package ethutil import ( "flag" "fmt" - "github.com/rakyll/globalconf" "os" + + "github.com/rakyll/globalconf" ) // Config struct @@ -28,8 +29,7 @@ var Config *ConfigManager func ReadConfig(ConfigFile string, Datadir string, EnvPrefix string) *ConfigManager { if Config == nil { // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags - _, err := os.Stat(ConfigFile) - if err != nil && os.IsNotExist(err) { + if !FileExist(ConfigFile) { fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile) os.Create(ConfigFile) } diff --git a/ethutil/path.go b/ethutil/path.go index 97f58ab7e..27022bcfa 100644 --- a/ethutil/path.go +++ b/ethutil/path.go @@ -1,6 +1,8 @@ package ethutil import ( + "io/ioutil" + "os" "os/user" "strings" ) @@ -18,3 +20,41 @@ func ExpandHomePath(p string) (path string) { 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_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 +} -- cgit v1.2.3 From 8e7c4f91e33bd99d3a4d320cdc59cf0bab3831b6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 10:33:30 +0200 Subject: Added ops --- ethutil/value.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-- ethutil/value_test.go | 15 +++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index 735a71dbc..635683e66 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -1,7 +1,6 @@ package ethutil import ( - "bytes" "fmt" "math/big" "reflect" @@ -67,7 +66,8 @@ func (val *Value) Uint() uint64 { } else if Val, ok := val.Val.(uint); ok { return uint64(Val) } else if Val, ok := val.Val.([]byte); ok { - return ReadVarint(bytes.NewReader(Val)) + return new(big.Int).SetBytes(Val).Uint64() + //return ReadVarint(bytes.NewReader(Val)) } else if Val, ok := val.Val.(*big.Int); ok { return Val.Uint64() } @@ -207,6 +207,13 @@ func (val *Value) Cmp(o *Value) bool { return reflect.DeepEqual(val.Val, o.Val) } +func (self *Value) DeepCmp(o *Value) bool { + a := NewValue(self.BigInt()) + b := NewValue(o.BigInt()) + + return a.Cmp(b) +} + func (val *Value) Encode() []byte { return Encode(val.Val) } @@ -262,6 +269,55 @@ func (val *Value) Append(v interface{}) *Value { 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 diff --git a/ethutil/value_test.go b/ethutil/value_test.go index a100f44bc..710cbd887 100644 --- a/ethutil/value_test.go +++ b/ethutil/value_test.go @@ -63,3 +63,18 @@ func TestIterator(t *testing.T) { i++ } } + +func TestMath(t *testing.T) { + a := NewValue(1) + a.Add(1).Add(1) + + if !a.DeepCmp(NewValue(3)) { + t.Error("Expected 3, got", a) + } + + a = NewValue(2) + a.Sub(1).Sub(1) + if !a.DeepCmp(NewValue(0)) { + t.Error("Expected 0, got", a) + } +} -- cgit v1.2.3 From 6e94c024e476a0e96b81d1cdd60dbb88b723593a Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 23:31:33 +0200 Subject: Added big data test and updating to reader --- ethutil/rlp.go | 139 ++++++++++++++++++++++++++++------------------------ ethutil/rlp_test.go | 11 +++++ 2 files changed, 85 insertions(+), 65 deletions(-) (limited to 'ethutil') diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 195ef0efb..333a84927 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -55,8 +55,7 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { return reader.Next(int(char - 0x80)) case char <= 0xbf: - buff := bytes.NewReader(reader.Next(int(char - 0xb8))) - length := ReadVarint(buff) + length := ReadVarInt(reader.Next(int(char - 0xb7))) return reader.Next(int(length)) @@ -72,74 +71,20 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { } return slice - - } - - return slice -} - -// TODO Use a bytes.Buffer instead of a raw byte slice. -// Cleaner code, and use draining instead of seeking the next bytes to read -func Decode(data []byte, pos uint64) (interface{}, uint64) { - var slice []interface{} - char := int(data[pos]) - switch { - case char <= 0x7f: - return data[pos], pos + 1 - - case char <= 0xb7: - b := uint64(data[pos]) - 0x80 - - return data[pos+1 : pos+1+b], pos + 1 + b - - case char <= 0xbf: - b := uint64(data[pos]) - 0xb7 - - b2 := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+b])) - - return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 - - case char <= 0xf7: - b := uint64(data[pos]) - 0xc0 - prevPos := pos - pos++ - for i := uint64(0); i < b; { - var obj interface{} - - // Get the next item in the data list and append it - obj, prevPos = Decode(data, pos) - slice = append(slice, obj) - - // Increment i by the amount bytes read in the previous - // read - i += (prevPos - pos) - pos = prevPos - } - return slice, pos - case char <= 0xff: - l := uint64(data[pos]) - 0xf7 - b := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+l])) - - pos = pos + l + 1 - - prevPos := b - for i := uint64(0); i < uint64(b); { - var obj interface{} - - obj, prevPos = Decode(data, pos) - slice = append(slice, obj) - - i += (prevPos - pos) - pos = prevPos + length := ReadVarInt(reader.Next(int(char - 0xf7))) + for i := uint64(0); i < length; i++ { + obj := DecodeWithReader(reader) + if obj != nil { + slice = append(slice, obj) + } else { + break + } } - return slice, pos - default: - panic(fmt.Sprintf("byte not supported: %q", char)) } - return slice, 0 + return slice } var ( @@ -223,3 +168,67 @@ func Encode(object interface{}) []byte { return buff.Bytes() } + +// TODO Use a bytes.Buffer instead of a raw byte slice. +// Cleaner code, and use draining instead of seeking the next bytes to read +func Decode(data []byte, pos uint64) (interface{}, uint64) { + var slice []interface{} + char := int(data[pos]) + switch { + case char <= 0x7f: + return data[pos], pos + 1 + + case char <= 0xb7: + b := uint64(data[pos]) - 0x80 + + return data[pos+1 : pos+1+b], pos + 1 + b + + case char <= 0xbf: + b := uint64(data[pos]) - 0xb7 + + b2 := ReadVarInt(data[pos+1 : pos+1+b]) + + return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 + + case char <= 0xf7: + b := uint64(data[pos]) - 0xc0 + prevPos := pos + pos++ + for i := uint64(0); i < b; { + var obj interface{} + + // Get the next item in the data list and append it + obj, prevPos = Decode(data, pos) + slice = append(slice, obj) + + // Increment i by the amount bytes read in the previous + // read + i += (prevPos - pos) + pos = prevPos + } + return slice, pos + + case char <= 0xff: + l := uint64(data[pos]) - 0xf7 + b := ReadVarInt(data[pos+1 : pos+1+l]) + + pos = pos + l + 1 + + prevPos := b + for i := uint64(0); i < uint64(b); { + var obj interface{} + + obj, prevPos = Decode(data, pos) + slice = append(slice, obj) + + i += (prevPos - pos) + pos = prevPos + } + return slice, pos + + default: + panic(fmt.Sprintf("byte not supported: %q", char)) + } + + return slice, 0 +} diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 095c01ecc..90057ab42 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -44,6 +44,17 @@ func TestValueSlice(t *testing.T) { } } +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" { -- cgit v1.2.3 From 6fd2401cdf792996c0183f896412831dd335377a Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 23:33:18 +0200 Subject: Fixed issue with var int reading. Reading uneven byte slices were broken. --- ethutil/bytes.go | 30 +++++++++++++++++++++++++++--- ethutil/value.go | 1 - 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 53b8cf645..eca2cc366 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -45,15 +45,15 @@ func BytesToNumber(b []byte) uint64 { // // Read a variable length number in big endian byte order func ReadVarint(reader *bytes.Reader) (ret uint64) { - if reader.Len() == 8 { + if reader.Len() > 4 { var num uint64 binary.Read(reader, binary.BigEndian, &num) ret = uint64(num) - } else if reader.Len() == 4 { + } else if reader.Len() > 2 { var num uint32 binary.Read(reader, binary.BigEndian, &num) ret = uint64(num) - } else if reader.Len() == 2 { + } else if reader.Len() > 0 { var num uint16 binary.Read(reader, binary.BigEndian, &num) ret = uint64(num) @@ -66,6 +66,30 @@ func ReadVarint(reader *bytes.Reader) (ret uint64) { return ret } +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 diff --git a/ethutil/value.go b/ethutil/value.go index 635683e66..85dc44ed6 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -67,7 +67,6 @@ func (val *Value) Uint() uint64 { return uint64(Val) } else if Val, ok := val.Val.([]byte); ok { return new(big.Int).SetBytes(Val).Uint64() - //return ReadVarint(bytes.NewReader(Val)) } else if Val, ok := val.Val.(*big.Int); ok { return Val.Uint64() } -- cgit v1.2.3 From 5ca29381175d553bb764040e8cd892a4ba370645 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 23:33:33 +0200 Subject: Fixed --- ethutil/bytes.go | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index eca2cc366..4027e3986 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -44,28 +44,6 @@ func BytesToNumber(b []byte) uint64 { // Read variable int // // Read a variable length number in big endian byte order -func ReadVarint(reader *bytes.Reader) (ret uint64) { - if reader.Len() > 4 { - var num uint64 - binary.Read(reader, binary.BigEndian, &num) - ret = uint64(num) - } else if reader.Len() > 2 { - var num uint32 - binary.Read(reader, binary.BigEndian, &num) - ret = uint64(num) - } else if reader.Len() > 0 { - var num uint16 - binary.Read(reader, binary.BigEndian, &num) - ret = uint64(num) - } else { - var num uint8 - binary.Read(reader, binary.BigEndian, &num) - ret = uint64(num) - } - - return ret -} - func ReadVarInt(buff []byte) (ret uint64) { switch l := len(buff); { case l > 4: -- cgit v1.2.3 From 5a2d62e4d9e551f16f094216da70b7a6f5d2bf00 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Jul 2014 13:06:59 +0200 Subject: Added better data parser --- ethutil/bytes.go | 20 ++++++++++++++++++++ ethutil/bytes_test.go | 14 ++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 ethutil/bytes_test.go (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 4027e3986..49fc229d3 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -131,6 +131,26 @@ func FormatData(data string) []byte { 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 diff --git a/ethutil/bytes_test.go b/ethutil/bytes_test.go new file mode 100644 index 000000000..381efe7a2 --- /dev/null +++ b/ethutil/bytes_test.go @@ -0,0 +1,14 @@ +package ethutil + +import ( + "bytes" + "testing" +) + +func TestParseData(t *testing.T) { + data := ParseData("hello", "world", "0x0106") + exp := "68656c6c6f000000000000000000000000000000000000000000000000000000776f726c640000000000000000000000000000000000000000000000000000000106000000000000000000000000000000000000000000000000000000000000" + if bytes.Compare(data, Hex2Bytes(exp)) != 0 { + t.Error("Error parsing data") + } +} -- cgit v1.2.3 From 5ede1224e48fd82961bd4a0b2ec1a3eda0b6d99b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 1 Aug 2014 10:21:43 +0200 Subject: minor rlp things --- ethutil/rlp.go | 21 ++++++++------------- ethutil/value.go | 7 +++++-- 2 files changed, 13 insertions(+), 15 deletions(-) (limited to 'ethutil') diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 333a84927..cf7f97ffd 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -32,12 +32,14 @@ const ( RlpEmptyStr = 0x40 ) +const rlpEof = -1 + func Char(c []byte) int { if len(c) > 0 { return int(c[0]) } - return 0 + return rlpEof } func DecodeWithReader(reader *bytes.Buffer) interface{} { @@ -46,8 +48,6 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { // Read the next byte char := Char(reader.Next(1)) switch { - case char == 0: - return nil case char <= 0x7f: return char @@ -63,11 +63,7 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { length := int(char - 0xc0) for i := 0; i < length; i++ { obj := DecodeWithReader(reader) - if obj != nil { - slice = append(slice, obj) - } else { - break - } + slice = append(slice, obj) } return slice @@ -75,13 +71,12 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { length := ReadVarInt(reader.Next(int(char - 0xf7))) for i := uint64(0); i < length; i++ { obj := DecodeWithReader(reader) - if obj != nil { - slice = append(slice, obj) - } else { - break - } + slice = append(slice, obj) } + + return slice default: + panic(fmt.Sprintf("byte not supported: %q", char)) } return slice diff --git a/ethutil/value.go b/ethutil/value.go index 85dc44ed6..3128cd724 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -221,12 +221,15 @@ func (val *Value) Encode() []byte { 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 { - data, _ := Decode(data, 0) - return NewValue(data) + value := NewValue(data) + value.Decode() + + return value } return NewValue(nil) -- cgit v1.2.3 From 342cc122b43f01301d0188de1e333c32ed64ae8c Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 4 Aug 2014 16:25:53 +0200 Subject: Added general Pipe API --- ethutil/value.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index 3128cd724..2233b978c 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -122,6 +122,14 @@ func (val *Value) Bytes() []byte { 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 @@ -157,6 +165,11 @@ 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. -- cgit v1.2.3 From a760ce05b948e89bc564af20599dcf95698ac0eb Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 11 Aug 2014 16:23:38 +0200 Subject: Updated chain for filtering --- ethutil/rlp.go | 9 +++++---- ethutil/value.go | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) (limited to 'ethutil') diff --git a/ethutil/rlp.go b/ethutil/rlp.go index cf7f97ffd..17ff627eb 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -2,15 +2,16 @@ package ethutil import ( "bytes" - _ "encoding/binary" "fmt" - _ "log" - _ "math" "math/big" ) -type RlpEncodable interface { +type RlpEncode interface { RlpEncode() []byte +} + +type RlpEncodeDecode interface { + RlpEncode RlpValue() []interface{} } diff --git a/ethutil/value.go b/ethutil/value.go index 2233b978c..608d332ba 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -74,6 +74,30 @@ func (val *Value) Uint() 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() + } + + return 0 +} + func (val *Value) Byte() byte { if Val, ok := val.Val.(byte); ok { return Val -- cgit v1.2.3 From 793e666f36e512bceb0d92d0a8dfe1d7c508c0e2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 17 Aug 2014 12:42:32 +0200 Subject: Dump bytes instead of strings --- ethutil/common.go | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'ethutil') diff --git a/ethutil/common.go b/ethutil/common.go index cbd94e7ad..8532d80f2 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -34,26 +34,43 @@ var ( // 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: - return fmt.Sprintf("%v Douglas", new(big.Int).Div(num, Douglas)) + fin = new(big.Int).Div(num, Douglas) + denom = "Douglas" case num.Cmp(Einstein) >= 0: - return fmt.Sprintf("%v Einstein", new(big.Int).Div(num, Einstein)) + fin = new(big.Int).Div(num, Einstein) + denom = "Einstein" case num.Cmp(Ether) >= 0: - return fmt.Sprintf("%v Ether", new(big.Int).Div(num, Ether)) + fin = new(big.Int).Div(num, Ether) + denom = "Ether" case num.Cmp(Finney) >= 0: - return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) + fin = new(big.Int).Div(num, Finney) + denom = "Finney" case num.Cmp(Szabo) >= 0: - return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) + fin = new(big.Int).Div(num, Szabo) + denom = "Szabo" case num.Cmp(Shannon) >= 0: - return fmt.Sprintf("%v Shannon", new(big.Int).Div(num, Shannon)) + fin = new(big.Int).Div(num, Shannon) + denom = "Shannon" case num.Cmp(Babbage) >= 0: - return fmt.Sprintf("%v Babbage", new(big.Int).Div(num, Babbage)) + fin = new(big.Int).Div(num, Babbage) + denom = "Babbage" case num.Cmp(Ada) >= 0: - return fmt.Sprintf("%v Ada", new(big.Int).Div(num, Ada)) + fin = new(big.Int).Div(num, Ada) + denom = "Ada" + } + + if len(fin.String()) > 5 { + return fmt.Sprintf("%sE%d %s", fin.String()[0:5], len(fin.String())-5, denom) } - return fmt.Sprintf("%v Wei", num) + return fmt.Sprintf("%v %s", fin, denom) } // Common big integers often used -- cgit v1.2.3 From 55a2f35a648ef70cdcc88bd751265e30831b54e5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 20 Aug 2014 13:05:26 +0200 Subject: JS Filter --- ethutil/bytes.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 49fc229d3..63c1606c2 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -173,6 +173,28 @@ func LeftPadBytes(slice []byte, l int) []byte { 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) -- cgit v1.2.3 From eaa2e8900d1036e09b002c4e20fc6e4f9cd031bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 14:47:58 +0200 Subject: PoC 6 networking code. * Added block pool for gathering blocks from the network (chunks) * Re wrote syncing --- ethutil/bytes.go | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 63c1606c2..e38f89454 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -208,3 +208,11 @@ func Address(slice []byte) (addr []byte) { return } + +func ByteSliceToInterface(slice [][]byte) (ret []interface{}) { + for _, i := range slice { + ret = append(ret, i) + } + + return +} -- cgit v1.2.3 From 836ed9d6b70e3ae928624f9ed81ed206a66b85b8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 22 Aug 2014 11:34:59 +0200 Subject: Write Protocol version to the db so we can perform sanity checks --- ethutil/value.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index 608d332ba..b336345ca 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -141,6 +141,8 @@ func (val *Value) Bytes() []byte { return []byte(s) } else if s, ok := val.Val.(*big.Int); ok { return s.Bytes() + } else { + return big.NewInt(val.Int()).Bytes() } return []byte{} -- cgit v1.2.3 From cdbc3ecc2a738a4b8803c40dfc510fd099ce8584 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 24 Aug 2014 00:16:32 +0200 Subject: Serpent! :-) --- ethutil/script.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index b796e7c1e..bd087e7e0 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -2,9 +2,11 @@ package ethutil import ( "fmt" + "strings" + "github.com/obscuren/mutan" "github.com/obscuren/mutan/backends" - "strings" + "github.com/obscuren/serpent-go" ) // General compile function @@ -14,15 +16,13 @@ func Compile(script string, silent bool) (ret []byte, err error) { if len(line) > 1 && line[0:2] == "#!" { switch line { - /* - case "#!serpent": - byteCode, err := serpent.Compile(script) - if err != nil { - return nil, err - } + case "#!serpent": + byteCode, err := serpent.Compile(script) + if err != nil { + return nil, err + } - return byteCode, nil - */ + return byteCode, nil } } else { -- cgit v1.2.3 From 6afc16399f9624663579ad72950b4ea3b887db57 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 25 Aug 2014 12:53:06 +0200 Subject: Block size --- ethutil/size.go | 15 +++++++++++++++ ethutil/size_test.go | 12 ++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 ethutil/size.go create mode 100644 ethutil/size_test.go (limited to 'ethutil') diff --git a/ethutil/size.go b/ethutil/size.go new file mode 100644 index 000000000..b4426465e --- /dev/null +++ b/ethutil/size.go @@ -0,0 +1,15 @@ +package ethutil + +import "fmt" + +type StorageSize float64 + +func (self StorageSize) String() string { + if self > 1000000 { + return fmt.Sprintf("%.2f mB", self/1000000) + } else if self > 1000 { + return fmt.Sprintf("%.2f kB", self/1000) + } else { + return fmt.Sprintf("%.2f B", self) + } +} diff --git a/ethutil/size_test.go b/ethutil/size_test.go new file mode 100644 index 000000000..82aa1c653 --- /dev/null +++ b/ethutil/size_test.go @@ -0,0 +1,12 @@ +package ethutil + +import ( + "fmt" + "testing" +) + +func TestSize(t *testing.T) { + fmt.Println(StorageSize(2381273)) + fmt.Println(StorageSize(2192)) + fmt.Println(StorageSize(12)) +} -- cgit v1.2.3 From ff27df78fc5d638b562bae9b4515eb5f5735d45d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 7 Sep 2014 10:18:54 +0200 Subject: Added new list type which can embed any slice type --- ethutil/list.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 ethutil/list.go (limited to 'ethutil') diff --git a/ethutil/list.go b/ethutil/list.go new file mode 100644 index 000000000..18bf04792 --- /dev/null +++ b/ethutil/list.go @@ -0,0 +1,42 @@ +package ethutil + +import "reflect" + +// 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 { + 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{list, list.Len()} +} + +// Get N element from the embedded slice. Returns nil if OOB. +func (self *List) Get(i int) interface{} { + if self.list.Len() > i { + return self.list.Index(i).Interface() + } + + return nil +} + +// Appends value at the end of the slice. Panics when incompatible value +// is given. +func (self *List) Append(v interface{}) { + 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() +} -- cgit v1.2.3 From 10564723b9ffa14904907a0ebc984fa25e4f1eab Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 13 Sep 2014 13:14:24 +0200 Subject: added string casting --- ethutil/value.go | 10 ++++++---- ethutil/value_test.go | 6 ++++++ 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index b336345ca..e8148b990 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -1,9 +1,11 @@ package ethutil import ( + "bytes" "fmt" "math/big" "reflect" + "strconv" ) // Data values are returned by the rlp decoder. The data values represents @@ -93,6 +95,9 @@ func (val *Value) Int() int64 { 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 @@ -246,10 +251,7 @@ func (val *Value) Cmp(o *Value) bool { } func (self *Value) DeepCmp(o *Value) bool { - a := NewValue(self.BigInt()) - b := NewValue(o.BigInt()) - - return a.Cmp(b) + return bytes.Compare(self.Bytes(), o.Bytes()) == 0 } func (val *Value) Encode() []byte { diff --git a/ethutil/value_test.go b/ethutil/value_test.go index 710cbd887..5452a0790 100644 --- a/ethutil/value_test.go +++ b/ethutil/value_test.go @@ -2,6 +2,7 @@ package ethutil import ( "bytes" + "fmt" "math/big" "testing" ) @@ -78,3 +79,8 @@ func TestMath(t *testing.T) { t.Error("Expected 0, got", a) } } + +func TestString(t *testing.T) { + a := NewValue("10") + fmt.Println("VALUE WITH STRING:", a.Int()) +} -- cgit v1.2.3 From 2fb57b2ea7b7f697ddc4811c471d87116eae07cc Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 00:13:23 +0200 Subject: Reworked filters --- ethutil/list.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ethutil') diff --git a/ethutil/list.go b/ethutil/list.go index 18bf04792..0aa657a14 100644 --- a/ethutil/list.go +++ b/ethutil/list.go @@ -20,6 +20,10 @@ func NewList(t interface{}) *List { return &List{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 { -- cgit v1.2.3 From 4db4ec1621767513ed2bd99d835c3e2f1c2b0e7e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 15 Sep 2014 01:10:50 +0200 Subject: Added unique set --- ethutil/set.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 ethutil/set.go (limited to 'ethutil') diff --git a/ethutil/set.go b/ethutil/set.go new file mode 100644 index 000000000..80e2edde2 --- /dev/null +++ b/ethutil/set.go @@ -0,0 +1,32 @@ +package ethutil + +type Settable interface { + AsSet() UniqueSet +} + +type UniqueSet map[interface{}]struct{} + +func NewSet(v ...interface{}) UniqueSet { + set := make(UniqueSet) + for _, val := range v { + set.Insert(val) + } + + return set +} + +func (self UniqueSet) Insert(k interface{}) UniqueSet { + self[k] = struct{}{} + + return self +} + +func (self UniqueSet) Include(k interface{}) bool { + _, ok := self[k] + + return ok +} + +func Set(s Settable) UniqueSet { + return s.AsSet() +} -- cgit v1.2.3 From 33a0dec8a157b9687ca6038f4deb011f3f1f7bdc Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 15 Sep 2014 15:42:12 +0200 Subject: Improved catching up and refactored --- ethutil/bytes.go | 16 ++++++++++++++++ ethutil/rlp.go | 2 ++ ethutil/set.go | 16 ++++++++++------ 3 files changed, 28 insertions(+), 6 deletions(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index e38f89454..f151d16ee 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -9,6 +9,22 @@ import ( "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], s[i+1:]...) + } + } + + return s +} + // Number to bytes // // Returns the number in bytes with the specified base diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 17ff627eb..febfb78e1 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -124,6 +124,8 @@ func Encode(object interface{}) []byte { } 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) diff --git a/ethutil/set.go b/ethutil/set.go index 80e2edde2..7955edac0 100644 --- a/ethutil/set.go +++ b/ethutil/set.go @@ -4,9 +4,13 @@ type Settable interface { AsSet() UniqueSet } -type UniqueSet map[interface{}]struct{} +type Stringable interface { + String() string +} + +type UniqueSet map[string]struct{} -func NewSet(v ...interface{}) UniqueSet { +func NewSet(v ...Stringable) UniqueSet { set := make(UniqueSet) for _, val := range v { set.Insert(val) @@ -15,14 +19,14 @@ func NewSet(v ...interface{}) UniqueSet { return set } -func (self UniqueSet) Insert(k interface{}) UniqueSet { - self[k] = struct{}{} +func (self UniqueSet) Insert(k Stringable) UniqueSet { + self[k.String()] = struct{}{} return self } -func (self UniqueSet) Include(k interface{}) bool { - _, ok := self[k] +func (self UniqueSet) Include(k Stringable) bool { + _, ok := self[k.String()] return ok } -- cgit v1.2.3 From fd041d91ee9f4be2d4705a32dc16698c89622c85 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 17 Sep 2014 15:57:07 +0200 Subject: Truncate when writing --- ethutil/path.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/path.go b/ethutil/path.go index 27022bcfa..cfbc38950 100644 --- a/ethutil/path.go +++ b/ethutil/path.go @@ -45,7 +45,7 @@ func ReadAllFile(filePath string) (string, error) { } func WriteFile(filePath string, content []byte) error { - fh, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, os.ModePerm) + fh, err := os.OpenFile(filePath, os.O_TRUNC|os.O_RDWR|os.O_CREATE, os.ModePerm) if err != nil { return err } -- cgit v1.2.3 From 80261c803a82e51413608a3dc5273c982844d135 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 19 Sep 2014 13:19:19 +0200 Subject: Fixed deref ptr --- ethutil/rlp.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ethutil') diff --git a/ethutil/rlp.go b/ethutil/rlp.go index febfb78e1..55406133b 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -15,6 +15,10 @@ type RlpEncodeDecode interface { RlpValue() []interface{} } +func Rlp(encoder RlpEncode) []byte { + return encoder.RlpEncode() +} + type RlpEncoder struct { rlpData []byte } -- cgit v1.2.3 From 151f9c7f8214a2702a76f36f566b52266949ac89 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 14:50:53 +0200 Subject: BigInt accept string --- ethutil/value.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index e8148b990..b1f887f29 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -118,6 +118,8 @@ func (val *Value) BigInt() *big.Int { 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())) } -- cgit v1.2.3 From b65f29f8faa20a93bd83c18232326c935cb16981 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 22 Sep 2014 14:51:41 +0200 Subject: Added JavaScript JSON helper --- ethutil/list.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/list.go b/ethutil/list.go index 0aa657a14..9db96cf18 100644 --- a/ethutil/list.go +++ b/ethutil/list.go @@ -1,6 +1,9 @@ package ethutil -import "reflect" +import ( + "encoding/json" + "reflect" +) // The list type is an anonymous slice handler which can be used // for containing any slice type to use in an environment which @@ -44,3 +47,15 @@ func (self *List) Append(v interface{}) { func (self *List) Interface() interface{} { return self.list.Interface() } + +// For JavaScript <3 +func (self *List) ToJSON() string { + var list []interface{} + for i := 0; i < self.Length; i++ { + list = append(list, self.Get(i)) + } + + data, _ := json.Marshal(list) + + return string(data) +} -- cgit v1.2.3 From ac5e86b7aee5715ca19a7c9fac56c62e7fcd7325 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 23 Sep 2014 12:00:01 +0200 Subject: Removed windows support for serpent :-( --- ethutil/script.go | 1 + ethutil/script_windows.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 ethutil/script_windows.go (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index bd087e7e0..a103fb8f0 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -1,3 +1,4 @@ +// +build !windows package ethutil import ( diff --git a/ethutil/script_windows.go b/ethutil/script_windows.go new file mode 100644 index 000000000..4f94c6448 --- /dev/null +++ b/ethutil/script_windows.go @@ -0,0 +1,31 @@ +package ethutil + +import ( + "fmt" + "strings" + + "github.com/obscuren/mutan" + "github.com/obscuren/mutan/backends" +) + +// General compile function +func Compile(script string, silent bool) (ret []byte, err error) { + if len(script) > 2 { + compiler := mutan.NewCompiler(backend.NewEthereumBackend()) + compiler.Silent = silent + byteCode, errors := compiler.Compile(strings.NewReader(script)) + if len(errors) > 0 { + var errs string + for _, er := range errors { + if er != nil { + errs += er.Error() + } + } + return nil, fmt.Errorf("%v", errs) + } + + return byteCode, nil + } + + return nil, nil +} -- cgit v1.2.3 From 6800c3665a50f7ac624f4ecbaa474b8a81336143 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 23 Sep 2014 17:55:34 +0200 Subject: Re-added min gas price check on tx pool --- ethutil/script.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index a103fb8f0..34eadff85 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -1,4 +1,4 @@ -// +build !windows +// +build !windows !cgo package ethutil import ( -- cgit v1.2.3 From c5828905905cca068e9f2fe3ad7072623a05958c Mon Sep 17 00:00:00 2001 From: nicksavers Date: Tue, 23 Sep 2014 20:04:06 +0200 Subject: Add blank line after +build comment --- ethutil/script.go | 1 + ethutil/script_windows.go | 2 ++ 2 files changed, 3 insertions(+) (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go index 34eadff85..8301466cc 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -1,4 +1,5 @@ // +build !windows !cgo + package ethutil import ( diff --git a/ethutil/script_windows.go b/ethutil/script_windows.go index 4f94c6448..c1b2d1b21 100644 --- a/ethutil/script_windows.go +++ b/ethutil/script_windows.go @@ -1,3 +1,5 @@ +// +build windows, cgo + package ethutil import ( -- cgit v1.2.3 From 57dc435f9b928f5de2a49736a2c71a7bf611289a Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 24 Sep 2014 11:39:17 +0200 Subject: Added TD for each block --- ethutil/list.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'ethutil') diff --git a/ethutil/list.go b/ethutil/list.go index 9db96cf18..a5147573a 100644 --- a/ethutil/list.go +++ b/ethutil/list.go @@ -2,6 +2,7 @@ package ethutil import ( "encoding/json" + "fmt" "reflect" ) @@ -29,6 +30,10 @@ func EmptyList() *List { // Get N element from the embedded slice. Returns nil if OOB. func (self *List) Get(i int) interface{} { + if self.list.Len() == 3 { + fmt.Println("get", i, self.list.Index(i).Interface()) + } + if self.list.Len() > i { return self.list.Index(i).Interface() } -- cgit v1.2.3 From 1118aaf840a6f6b4dd6b137f39ab895a0cbd5a56 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 24 Sep 2014 20:40:40 +0200 Subject: Temp work around --- ethutil/list.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'ethutil') diff --git a/ethutil/list.go b/ethutil/list.go index a5147573a..4fb36224f 100644 --- a/ethutil/list.go +++ b/ethutil/list.go @@ -2,7 +2,6 @@ package ethutil import ( "encoding/json" - "fmt" "reflect" ) @@ -10,6 +9,7 @@ import ( // for containing any slice type to use in an environment which // does not support slice types (e.g., JavaScript, QML) type List struct { + val interface{} list reflect.Value Length int } @@ -21,7 +21,7 @@ func NewList(t interface{}) *List { panic("list container initialized with a non-slice type") } - return &List{list, list.Len()} + return &List{t, list, list.Len()} } func EmptyList() *List { @@ -30,17 +30,24 @@ func EmptyList() *List { // Get N element from the embedded slice. Returns nil if OOB. func (self *List) Get(i int) interface{} { - if self.list.Len() == 3 { - fmt.Println("get", i, self.list.Index(i).Interface()) - } if self.list.Len() > i { - return self.list.Index(i).Interface() + 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{}) { -- cgit v1.2.3 From 68119d0929adebdbd39dd40982264f86164bd6e6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 26 Sep 2014 13:32:54 +0200 Subject: Fixed messages to use proper numbers --- ethutil/value.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ethutil') diff --git a/ethutil/value.go b/ethutil/value.go index b1f887f29..dd777fa43 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -63,6 +63,10 @@ func (val *Value) Uint() uint64 { 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 { -- cgit v1.2.3 From b55e017e620d8049788eda91424d4944ac934613 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 2 Oct 2014 17:03:36 +0200 Subject: Proper delete --- ethutil/bytes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/bytes.go b/ethutil/bytes.go index f151d16ee..bd294f28a 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -18,7 +18,7 @@ func (self Bytes) String() string { func DeleteFromByteSlice(s [][]byte, hash []byte) [][]byte { for i, h := range s { if bytes.Compare(h, hash) == 0 { - return append(s[:i], s[i+1:]...) + return append(s[:i:i], s[i+1:]...) } } -- cgit v1.2.3 From 0015ce1e353f52cca818d11f566b9a656fb85f24 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 7 Oct 2014 11:18:46 +0200 Subject: kick of bad peers --- ethutil/list.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'ethutil') diff --git a/ethutil/list.go b/ethutil/list.go index 4fb36224f..6919a02f5 100644 --- a/ethutil/list.go +++ b/ethutil/list.go @@ -3,12 +3,14 @@ package ethutil import ( "encoding/json" "reflect" + "sync" ) // The list type is an anonymous slice handler which can be used // for containing any slice type to use in an environment which // does not support slice types (e.g., JavaScript, QML) type List struct { + mut sync.Mutex val interface{} list reflect.Value Length int @@ -21,7 +23,7 @@ func NewList(t interface{}) *List { panic("list container initialized with a non-slice type") } - return &List{t, list, list.Len()} + return &List{sync.Mutex{}, t, list, list.Len()} } func EmptyList() *List { @@ -30,8 +32,10 @@ func EmptyList() *List { // 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 @@ -51,6 +55,9 @@ func (self *List) GetAsJson(i int) interface{} { // 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() } -- cgit v1.2.3 From a38dafcc57d296447db9748c8c85df6c58b243fb Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 8 Oct 2014 16:11:36 +0200 Subject: Moved the To256 --- ethutil/big.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'ethutil') diff --git a/ethutil/big.go b/ethutil/big.go index ec263b818..d8f54ad10 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -34,6 +34,19 @@ func BigD(data []byte) *big.Int { return n } +// To256 +// +// "cast" the big int to a 256 big int (i.e., limit to) +var tt256 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) + +func To256(x *big.Int) { + x.And(x, tt256) + + if x.Cmp(new(big.Int)) < 0 { + x.SetInt64(0) + } +} + // Big to bytes // // Returns the bytes of a big integer with the size specified by **base** -- cgit v1.2.3 From e02c0fa8088943bc995d290e58a7226f4a0ece91 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 10 Oct 2014 17:00:06 +0200 Subject: Added generic big to 256 method. Implemented new iterator --- ethutil/big.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'ethutil') diff --git a/ethutil/big.go b/ethutil/big.go index d8f54ad10..e23d8f659 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -39,12 +39,14 @@ func BigD(data []byte) *big.Int { // "cast" the big int to a 256 big int (i.e., limit to) var tt256 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) -func To256(x *big.Int) { +func To256(x *big.Int) *big.Int { x.And(x, tt256) if x.Cmp(new(big.Int)) < 0 { x.SetInt64(0) } + + return x } // Big to bytes -- cgit v1.2.3 From c5bd32b0ad1a3d0fd20a3d1014cc8a97d889dc28 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 14 Oct 2014 11:48:52 +0200 Subject: Refactored VM to two separate VMs; std & debug Standard VM should be about 10x faster than the debug VM. Some error checking has been removed, all of the log statements and therefor quite some unnecessary if-statements. --- ethutil/config.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethutil') diff --git a/ethutil/config.go b/ethutil/config.go index 81052318e..ccc7714d0 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -17,6 +17,7 @@ type ConfigManager struct { Diff bool DiffType string Paranoia bool + VmType int conf *globalconf.GlobalConf } -- cgit v1.2.3 From 311c6f8a3fed5ac03ee4b442fd0f420072bc41b4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 15 Oct 2014 17:12:26 +0200 Subject: Fixed remote Arithmetic tests --- ethutil/big.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'ethutil') diff --git a/ethutil/big.go b/ethutil/big.go index e23d8f659..bdcf86421 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -1,8 +1,8 @@ package ethutil -import ( - "math/big" -) +import "math/big" + +var MaxInt256 *big.Int = BigD(Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) // Big pow // @@ -37,18 +37,29 @@ func BigD(data []byte) *big.Int { // To256 // // "cast" the big int to a 256 big int (i.e., limit to) -var tt256 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) +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 To256(x *big.Int) *big.Int { - x.And(x, tt256) +func U256(x *big.Int) *big.Int { + //if x.Cmp(Big0) < 0 { + // return new(big.Int).Add(tt256, x) + // } - if x.Cmp(new(big.Int)) < 0 { - x.SetInt64(0) - } + 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) + } +} + // Big to bytes // // Returns the bytes of a big integer with the size specified by **base** -- cgit v1.2.3 From a02dc4ccc321bdee2a670eecdf5c3bac01fc290b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 18 Oct 2014 13:23:01 +0200 Subject: Using proper naming scheme. Fixes #63 --- ethutil/script.go | 49 ----------------------------------------------- ethutil/script_unix.go | 47 +++++++++++++++++++++++++++++++++++++++++++++ ethutil/script_windows.go | 2 -- 3 files changed, 47 insertions(+), 51 deletions(-) delete mode 100644 ethutil/script.go create mode 100644 ethutil/script_unix.go (limited to 'ethutil') diff --git a/ethutil/script.go b/ethutil/script.go deleted file mode 100644 index 8301466cc..000000000 --- a/ethutil/script.go +++ /dev/null @@ -1,49 +0,0 @@ -// +build !windows !cgo - -package ethutil - -import ( - "fmt" - "strings" - - "github.com/obscuren/mutan" - "github.com/obscuren/mutan/backends" - "github.com/obscuren/serpent-go" -) - -// General compile function -func Compile(script string, silent bool) (ret []byte, err error) { - if len(script) > 2 { - line := strings.Split(script, "\n")[0] - - if len(line) > 1 && line[0:2] == "#!" { - switch line { - case "#!serpent": - byteCode, err := serpent.Compile(script) - if err != nil { - return nil, err - } - - return byteCode, nil - } - } else { - - compiler := mutan.NewCompiler(backend.NewEthereumBackend()) - compiler.Silent = silent - byteCode, errors := compiler.Compile(strings.NewReader(script)) - if len(errors) > 0 { - var errs string - for _, er := range errors { - if er != nil { - errs += er.Error() - } - } - return nil, fmt.Errorf("%v", errs) - } - - return byteCode, nil - } - } - - return nil, nil -} diff --git a/ethutil/script_unix.go b/ethutil/script_unix.go new file mode 100644 index 000000000..bd087e7e0 --- /dev/null +++ b/ethutil/script_unix.go @@ -0,0 +1,47 @@ +package ethutil + +import ( + "fmt" + "strings" + + "github.com/obscuren/mutan" + "github.com/obscuren/mutan/backends" + "github.com/obscuren/serpent-go" +) + +// General compile function +func Compile(script string, silent bool) (ret []byte, err error) { + if len(script) > 2 { + line := strings.Split(script, "\n")[0] + + if len(line) > 1 && line[0:2] == "#!" { + switch line { + case "#!serpent": + byteCode, err := serpent.Compile(script) + if err != nil { + return nil, err + } + + return byteCode, nil + } + } else { + + compiler := mutan.NewCompiler(backend.NewEthereumBackend()) + compiler.Silent = silent + byteCode, errors := compiler.Compile(strings.NewReader(script)) + if len(errors) > 0 { + var errs string + for _, er := range errors { + if er != nil { + errs += er.Error() + } + } + return nil, fmt.Errorf("%v", errs) + } + + return byteCode, nil + } + } + + return nil, nil +} diff --git a/ethutil/script_windows.go b/ethutil/script_windows.go index c1b2d1b21..4f94c6448 100644 --- a/ethutil/script_windows.go +++ b/ethutil/script_windows.go @@ -1,5 +1,3 @@ -// +build windows, cgo - package ethutil import ( -- cgit v1.2.3