aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Godeps/Godeps.json18
-rw-r--r--Godeps/_workspace/src/github.com/fatih/color/.travis.yml3
-rw-r--r--Godeps/_workspace/src/github.com/fatih/color/LICENSE.md20
-rw-r--r--Godeps/_workspace/src/github.com/fatih/color/README.md151
-rw-r--r--Godeps/_workspace/src/github.com/fatih/color/color.go353
-rw-r--r--Godeps/_workspace/src/github.com/fatih/color/color_test.go176
-rw-r--r--Godeps/_workspace/src/github.com/fatih/color/doc.go114
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-colorable/README.md42
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go16
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go594
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/.gitignore27
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/LICENSE21
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/README.md100
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor.go20
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor/main.go27
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_ansi.go17
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_test.go25
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows.go351
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows_test.go236
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/example_test.go24
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/export_test.go19
-rw-r--r--cmd/ethtest/main.go8
-rw-r--r--cmd/evm/main.go2
-rw-r--r--cmd/geth/chaincmd.go26
-rw-r--r--cmd/geth/js.go67
-rw-r--r--cmd/geth/main.go23
-rw-r--r--cmd/utils/cmd.go2
-rw-r--r--cmd/utils/flags.go45
-rw-r--r--core/bench_test.go4
-rw-r--r--core/block_processor.go26
-rw-r--r--core/block_processor_test.go8
-rw-r--r--core/chain_makers.go6
-rw-r--r--core/chain_makers_test.go4
-rw-r--r--core/chain_manager.go48
-rw-r--r--core/chain_manager_test.go18
-rw-r--r--core/chain_util.go4
-rw-r--r--core/genesis.go18
-rw-r--r--core/manager.go5
-rw-r--r--core/vm/instructions.go19
-rw-r--r--core/vm/jit.go6
-rw-r--r--core/vm/jit_test.go2
-rw-r--r--core/vm/settings.go6
-rw-r--r--core/vm/vm.go2
-rw-r--r--eth/backend.go201
-rw-r--r--eth/protocol_test.go4
-rw-r--r--ethdb/database.go5
-rw-r--r--jsre/ethereum_js.go3031
-rw-r--r--jsre/jsre.go34
-rw-r--r--jsre/jsre_test.go11
-rw-r--r--jsre/pp_js.go137
-rw-r--r--jsre/pretty.go231
-rw-r--r--miner/worker.go10
-rw-r--r--p2p/discover/table.go121
-rw-r--r--p2p/discover/table_test.go6
-rw-r--r--p2p/discover/udp.go78
-rw-r--r--p2p/discover/udp_test.go75
-rw-r--r--p2p/peer_error.go2
-rw-r--r--p2p/rlpx.go16
-rw-r--r--rlp/decode.go29
-rw-r--r--rlp/decode_test.go9
-rw-r--r--rlp/encode.go11
-rw-r--r--rlp/encode_test.go4
-rw-r--r--rpc/api/admin.go9
-rw-r--r--rpc/api/debug.go2
-rw-r--r--rpc/api/eth_args.go16
-rw-r--r--rpc/api/net.go3
-rw-r--r--rpc/api/personal.go22
-rw-r--r--rpc/api/personal_args.go22
-rw-r--r--rpc/api/shh_js.go (renamed from rpc/api/ssh_js.go)0
-rw-r--r--rpc/codec/codec.go2
-rw-r--r--rpc/codec/json.go39
-rw-r--r--rpc/comms/comms.go2
-rw-r--r--rpc/comms/inproc.go2
-rw-r--r--rpc/comms/ipc.go35
-rw-r--r--rpc/comms/ipc_unix.go9
-rw-r--r--rpc/comms/ipc_windows.go9
-rw-r--r--rpc/jeth.go89
-rw-r--r--rpc/useragent/agent.go24
-rw-r--r--rpc/useragent/remote_frontend.go141
-rw-r--r--tests/block_test_util.go2
-rw-r--r--tests/state_test.go5
-rw-r--r--tests/state_test_util.go6
-rw-r--r--tests/vm_test.go5
-rw-r--r--tests/vm_test_util.go8
-rw-r--r--trie/cache.go2
-rw-r--r--xeth/state.go2
-rw-r--r--xeth/xeth.go42
87 files changed, 4980 insertions, 2236 deletions
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 199914baa..d5c41227d 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -25,13 +25,17 @@
"Rev": "8f6ccaaef9b418553807a73a95cb5f49cd3ea39f"
},
{
+ "ImportPath": "github.com/fatih/color",
+ "Comment": "v0.1-5-gf773d4c",
+ "Rev": "f773d4c806cc8e4a5749d6a35e2a4bbcd71443d6"
+ },
+ {
"ImportPath": "github.com/gizak/termui",
"Rev": "bab8dce01c193d82bc04888a0a9a7814d505f532"
},
{
- "ImportPath": "github.com/howeyc/fsnotify",
- "Comment": "v0.9.0-11-g6b1ef89",
- "Rev": "6b1ef893dc11e0447abda6da20a5203481878dda"
+ "ImportPath": "github.com/hashicorp/golang-lru",
+ "Rev": "7f9ef20a0256f494e24126014135cf893ab71e9e"
},
{
"ImportPath": "github.com/huin/goupnp",
@@ -46,10 +50,6 @@
"Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a"
},
{
- "ImportPath": "github.com/mattn/go-colorable",
- "Rev": "043ae16291351db8465272edf465c9f388161627"
- },
- {
"ImportPath": "github.com/mattn/go-isatty",
"Rev": "fdbe02a1b44e75977b2690062b83cf507d70c013"
},
@@ -79,6 +79,10 @@
"Rev": "6e0c3cb65fc0fdb064c743d176a620e3ca446dfb"
},
{
+ "ImportPath": "github.com/shiena/ansicolor",
+ "Rev": "a5e2b567a4dd6cc74545b8a4f27c9d63b9e7735b"
+ },
+ {
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
"Rev": "4875955338b0a434238a31165cb87255ab6e9e4a"
},
diff --git a/Godeps/_workspace/src/github.com/fatih/color/.travis.yml b/Godeps/_workspace/src/github.com/fatih/color/.travis.yml
new file mode 100644
index 000000000..2405aef3a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/fatih/color/.travis.yml
@@ -0,0 +1,3 @@
+language: go
+go: 1.3
+
diff --git a/Godeps/_workspace/src/github.com/fatih/color/LICENSE.md b/Godeps/_workspace/src/github.com/fatih/color/LICENSE.md
new file mode 100644
index 000000000..25fdaf639
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/fatih/color/LICENSE.md
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Fatih Arslan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Godeps/_workspace/src/github.com/fatih/color/README.md b/Godeps/_workspace/src/github.com/fatih/color/README.md
new file mode 100644
index 000000000..d6fb06a3e
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/fatih/color/README.md
@@ -0,0 +1,151 @@
+# Color [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/color) [![Build Status](http://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color)
+
+
+
+Color lets you use colorized outputs in terms of [ANSI Escape Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It has support for Windows too! The API can be used in several ways, pick one that suits you.
+
+
+
+![Color](http://i.imgur.com/c1JI0lA.png)
+
+
+## Install
+
+```bash
+go get github.com/fatih/color
+```
+
+## Examples
+
+### Standard colors
+
+```go
+// Print with default helper functions
+color.Cyan("Prints text in cyan.")
+
+// A newline will be appended automatically
+color.Blue("Prints %s in blue.", "text")
+
+// These are using the default foreground colors
+color.Red("We have red")
+color.Magenta("And many others ..")
+
+```
+
+### Mix and reuse colors
+
+```go
+// Create a new color object
+c := color.New(color.FgCyan).Add(color.Underline)
+c.Println("Prints cyan text with an underline.")
+
+// Or just add them to New()
+d := color.New(color.FgCyan, color.Bold)
+d.Printf("This prints bold cyan %s\n", "too!.")
+
+// Mix up foreground and background colors, create new mixes!
+red := color.New(color.FgRed)
+
+boldRed := red.Add(color.Bold)
+boldRed.Println("This will print text in bold red.")
+
+whiteBackground := red.Add(color.BgWhite)
+whiteBackground.Println("Red text with white background.")
+```
+
+### Custom print functions (PrintFunc)
+
+```go
+// Create a custom print function for convenience
+red := color.New(color.FgRed).PrintfFunc()
+red("Warning")
+red("Error: %s", err)
+
+// Mix up multiple attributes
+notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
+notice("Don't forget this...")
+```
+
+### Insert into noncolor strings (SprintFunc)
+
+```go
+// Create SprintXxx functions to mix strings with other non-colorized strings:
+yellow := color.New(color.FgYellow).SprintFunc()
+red := color.New(color.FgRed).SprintFunc()
+fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
+
+info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
+fmt.Printf("This %s rocks!\n", info("package"))
+
+// Use helper functions
+fmt.Printf("This", color.RedString("warning"), "should be not neglected.")
+fmt.Printf(color.GreenString("Info:"), "an important message." )
+
+// Windows supported too! Just don't forget to change the output to color.Output
+fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
+```
+
+### Plug into existing code
+
+```go
+// Use handy standard colors
+color.Set(color.FgYellow)
+
+fmt.Println("Existing text will now be in yellow")
+fmt.Printf("This one %s\n", "too")
+
+color.Unset() // Don't forget to unset
+
+// You can mix up parameters
+color.Set(color.FgMagenta, color.Bold)
+defer color.Unset() // Use it in your function
+
+fmt.Println("All text will now be bold magenta.")
+```
+
+### Disable color
+
+There might be a case where you want to disable color output (for example to
+pipe the standard output of your app to somewhere else). `Color` has support to
+disable colors both globally and for single color definition. For example
+suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
+the color output with:
+
+```go
+
+var flagNoColor = flag.Bool("no-color", false, "Disable color output")
+
+if *flagNoColor {
+ color.NoColor = true // disables colorized output
+}
+```
+
+It also has support for single color definitions (local). You can
+disable/enable color output on the fly:
+
+```go
+c := color.New(color.FgCyan)
+c.Println("Prints cyan text")
+
+c.DisableColor()
+c.Println("This is printed without any color")
+
+c.EnableColor()
+c.Println("This prints again cyan...")
+```
+
+## Todo
+
+* Save/Return previous values
+* Evaluate fmt.Formatter interface
+
+
+## Credits
+
+ * [Fatih Arslan](https://github.com/fatih)
+ * Windows support via @shiena: [ansicolor](https://github.com/shiena/ansicolor)
+
+## License
+
+The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details
+
diff --git a/Godeps/_workspace/src/github.com/fatih/color/color.go b/Godeps/_workspace/src/github.com/fatih/color/color.go
new file mode 100644
index 000000000..c4a10c3c8
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/fatih/color/color.go
@@ -0,0 +1,353 @@
+package color
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/mattn/go-isatty"
+ "github.com/shiena/ansicolor"
+)
+
+// NoColor defines if the output is colorized or not. It's dynamically set to
+// false or true based on the stdout's file descriptor referring to a terminal
+// or not. This is a global option and affects all colors. For more control
+// over each color block use the methods DisableColor() individually.
+var NoColor = !isatty.IsTerminal(os.Stdout.Fd())
+
+// Color defines a custom color object which is defined by SGR parameters.
+type Color struct {
+ params []Attribute
+ noColor *bool
+}
+
+// Attribute defines a single SGR Code
+type Attribute int
+
+const escape = "\x1b"
+
+// Base attributes
+const (
+ Reset Attribute = iota
+ Bold
+ Faint
+ Italic
+ Underline
+ BlinkSlow
+ BlinkRapid
+ ReverseVideo
+ Concealed
+ CrossedOut
+)
+
+// Foreground text colors
+const (
+ FgBlack Attribute = iota + 30
+ FgRed
+ FgGreen
+ FgYellow
+ FgBlue
+ FgMagenta
+ FgCyan
+ FgWhite
+)
+
+// Background text colors
+const (
+ BgBlack Attribute = iota + 40
+ BgRed
+ BgGreen
+ BgYellow
+ BgBlue
+ BgMagenta
+ BgCyan
+ BgWhite
+)
+
+// New returns a newly created color object.
+func New(value ...Attribute) *Color {
+ c := &Color{params: make([]Attribute, 0)}
+ c.Add(value...)
+ return c
+}
+
+// Set sets the given parameters immediately. It will change the color of
+// output with the given SGR parameters until color.Unset() is called.
+func Set(p ...Attribute) *Color {
+ c := New(p...)
+ c.Set()
+ return c
+}
+
+// Unset resets all escape attributes and clears the output. Usually should
+// be called after Set().
+func Unset() {
+ if NoColor {
+ return
+ }
+
+ fmt.Fprintf(Output, "%s[%dm", escape, Reset)
+}
+
+// Set sets the SGR sequence.
+func (c *Color) Set() *Color {
+ if c.isNoColorSet() {
+ return c
+ }
+
+ fmt.Fprintf(Output, c.format())
+ return c
+}
+
+func (c *Color) unset() {
+ if c.isNoColorSet() {
+ return
+ }
+
+ Unset()
+}
+
+// Add is used to chain SGR parameters. Use as many as parameters to combine
+// and create custom color objects. Example: Add(color.FgRed, color.Underline).
+func (c *Color) Add(value ...Attribute) *Color {
+ c.params = append(c.params, value...)
+ return c
+}
+
+func (c *Color) prepend(value Attribute) {
+ c.params = append(c.params, 0)
+ copy(c.params[1:], c.params[0:])
+ c.params[0] = value
+}
+
+// Output defines the standard output of the print functions. By default
+// os.Stdout is used.
+var Output = ansicolor.NewAnsiColorWriter(os.Stdout)
+
+// Print formats using the default formats for its operands and writes to
+// standard output. Spaces are added between operands when neither is a
+// string. It returns the number of bytes written and any write error
+// encountered. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Print(a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprint(Output, a...)
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+// This is the standard fmt.Printf() method wrapped with the given color.
+func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprintf(Output, format, a...)
+}
+
+// Println formats using the default formats for its operands and writes to
+// standard output. Spaces are always added between operands and a newline is
+// appended. It returns the number of bytes written and any write error
+// encountered. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Println(a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprintln(Output, a...)
+}
+
+// PrintFunc returns a new function that prints the passed arguments as
+// colorized with color.Print().
+func (c *Color) PrintFunc() func(a ...interface{}) {
+ return func(a ...interface{}) { c.Print(a...) }
+}
+
+// PrintfFunc returns a new function that prints the passed arguments as
+// colorized with color.Printf().
+func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
+ return func(format string, a ...interface{}) { c.Printf(format, a...) }
+}
+
+// PrintlnFunc returns a new function that prints the passed arguments as
+// colorized with color.Println().
+func (c *Color) PrintlnFunc() func(a ...interface{}) {
+ return func(a ...interface{}) { c.Println(a...) }
+}
+
+// SprintFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprint(). Useful to put into or mix into other
+// string. Windows users should use this in conjuction with color.Output, example:
+//
+// put := New(FgYellow).SprintFunc()
+// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
+func (c *Color) SprintFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return c.wrap(fmt.Sprint(a...))
+ }
+}
+
+// SprintfFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintf(). Useful to put into or mix into other
+// string. Windows users should use this in conjuction with color.Output.
+func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
+ return func(format string, a ...interface{}) string {
+ return c.wrap(fmt.Sprintf(format, a...))
+ }
+}
+
+// SprintlnFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintln(). Useful to put into or mix into other
+// string. Windows users should use this in conjuction with color.Output.
+func (c *Color) SprintlnFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return c.wrap(fmt.Sprintln(a...))
+ }
+}
+
+// sequence returns a formated SGR sequence to be plugged into a "\x1b[...m"
+// an example output might be: "1;36" -> bold cyan
+func (c *Color) sequence() string {
+ format := make([]string, len(c.params))
+ for i, v := range c.params {
+ format[i] = strconv.Itoa(int(v))
+ }
+
+ return strings.Join(format, ";")
+}
+
+// wrap wraps the s string with the colors attributes. The string is ready to
+// be printed.
+func (c *Color) wrap(s string) string {
+ if c.isNoColorSet() {
+ return s
+ }
+
+ return c.format() + s + c.unformat()
+}
+
+func (c *Color) format() string {
+ return fmt.Sprintf("%s[%sm", escape, c.sequence())
+}
+
+func (c *Color) unformat() string {
+ return fmt.Sprintf("%s[%dm", escape, Reset)
+}
+
+// DisableColor disables the color output. Useful to not change any existing
+// code and still being able to output. Can be used for flags like
+// "--no-color". To enable back use EnableColor() method.
+func (c *Color) DisableColor() {
+ c.noColor = boolPtr(true)
+}
+
+// EnableColor enables the color output. Use it in conjuction with
+// DisableColor(). Otherwise this method has no side effects.
+func (c *Color) EnableColor() {
+ c.noColor = boolPtr(false)
+}
+
+func (c *Color) isNoColorSet() bool {
+ // check first if we have user setted action
+ if c.noColor != nil {
+ return *c.noColor
+ }
+
+ // if not return the global option, which is disabled by default
+ return NoColor
+}
+
+func boolPtr(v bool) *bool {
+ return &v
+}
+
+// Black is an convenient helper function to print with black foreground. A
+// newline is appended to format by default.
+func Black(format string, a ...interface{}) { printColor(format, FgBlack, a...) }
+
+// Red is an convenient helper function to print with red foreground. A
+// newline is appended to format by default.
+func Red(format string, a ...interface{}) { printColor(format, FgRed, a...) }
+
+// Green is an convenient helper function to print with green foreground. A
+// newline is appended to format by default.
+func Green(format string, a ...interface{}) { printColor(format, FgGreen, a...) }
+
+// Yellow is an convenient helper function to print with yellow foreground.
+// A newline is appended to format by default.
+func Yellow(format string, a ...interface{}) { printColor(format, FgYellow, a...) }
+
+// Blue is an convenient helper function to print with blue foreground. A
+// newline is appended to format by default.
+func Blue(format string, a ...interface{}) { printColor(format, FgBlue, a...) }
+
+// Magenta is an convenient helper function to print with magenta foreground.
+// A newline is appended to format by default.
+func Magenta(format string, a ...interface{}) { printColor(format, FgMagenta, a...) }
+
+// Cyan is an convenient helper function to print with cyan foreground. A
+// newline is appended to format by default.
+func Cyan(format string, a ...interface{}) { printColor(format, FgCyan, a...) }
+
+// White is an convenient helper function to print with white foreground. A
+// newline is appended to format by default.
+func White(format string, a ...interface{}) { printColor(format, FgWhite, a...) }
+
+func printColor(format string, p Attribute, a ...interface{}) {
+ if !strings.HasSuffix(format, "\n") {
+ format += "\n"
+ }
+
+ c := &Color{params: []Attribute{p}}
+ c.Printf(format, a...)
+}
+
+// BlackString is an convenient helper function to return a string with black
+// foreground.
+func BlackString(format string, a ...interface{}) string {
+ return New(FgBlack).SprintfFunc()(format, a...)
+}
+
+// RedString is an convenient helper function to return a string with red
+// foreground.
+func RedString(format string, a ...interface{}) string {
+ return New(FgRed).SprintfFunc()(format, a...)
+}
+
+// GreenString is an convenient helper function to return a string with green
+// foreground.
+func GreenString(format string, a ...interface{}) string {
+ return New(FgGreen).SprintfFunc()(format, a...)
+}
+
+// YellowString is an convenient helper function to return a string with yellow
+// foreground.
+func YellowString(format string, a ...interface{}) string {
+ return New(FgYellow).SprintfFunc()(format, a...)
+}
+
+// BlueString is an convenient helper function to return a string with blue
+// foreground.
+func BlueString(format string, a ...interface{}) string {
+ return New(FgBlue).SprintfFunc()(format, a...)
+}
+
+// MagentaString is an convenient helper function to return a string with magenta
+// foreground.
+func MagentaString(format string, a ...interface{}) string {
+ return New(FgMagenta).SprintfFunc()(format, a...)
+}
+
+// CyanString is an convenient helper function to return a string with cyan
+// foreground.
+func CyanString(format string, a ...interface{}) string {
+ return New(FgCyan).SprintfFunc()(format, a...)
+}
+
+// WhiteString is an convenient helper function to return a string with white
+// foreground.
+func WhiteString(format string, a ...interface{}) string {
+ return New(FgWhite).SprintfFunc()(format, a...)
+}
diff --git a/Godeps/_workspace/src/github.com/fatih/color/color_test.go b/Godeps/_workspace/src/github.com/fatih/color/color_test.go
new file mode 100644
index 000000000..a1192b559
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/fatih/color/color_test.go
@@ -0,0 +1,176 @@
+package color
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/shiena/ansicolor"
+)
+
+// Testing colors is kinda different. First we test for given colors and their
+// escaped formatted results. Next we create some visual tests to be tested.
+// Each visual test includes the color name to be compared.
+func TestColor(t *testing.T) {
+ rb := new(bytes.Buffer)
+ Output = rb
+
+ testColors := []struct {
+ text string
+ code Attribute
+ }{
+ {text: "black", code: FgBlack},
+ {text: "red", code: FgRed},
+ {text: "green", code: FgGreen},
+ {text: "yellow", code: FgYellow},
+ {text: "blue", code: FgBlue},
+ {text: "magent", code: FgMagenta},
+ {text: "cyan", code: FgCyan},
+ {text: "white", code: FgWhite},
+ }
+
+ for _, c := range testColors {
+ New(c.code).Print(c.text)
+
+ line, _ := rb.ReadString('\n')
+ scannedLine := fmt.Sprintf("%q", line)
+ colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
+ escapedForm := fmt.Sprintf("%q", colored)
+
+ fmt.Printf("%s\t: %s\n", c.text, line)
+
+ if scannedLine != escapedForm {
+ t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
+ }
+ }
+}
+
+func TestNoColor(t *testing.T) {
+ rb := new(bytes.Buffer)
+ Output = rb
+
+ testColors := []struct {
+ text string
+ code Attribute
+ }{
+ {text: "black", code: FgBlack},
+ {text: "red", code: FgRed},
+ {text: "green", code: FgGreen},
+ {text: "yellow", code: FgYellow},
+ {text: "blue", code: FgBlue},
+ {text: "magent", code: FgMagenta},
+ {text: "cyan", code: FgCyan},
+ {text: "white", code: FgWhite},
+ }
+
+ for _, c := range testColors {
+ p := New(c.code)
+ p.DisableColor()
+ p.Print(c.text)
+
+ line, _ := rb.ReadString('\n')
+ if line != c.text {
+ t.Errorf("Expecting %s, got '%s'\n", c.text, line)
+ }
+ }
+
+ // global check
+ NoColor = true
+ defer func() {
+ NoColor = false
+ }()
+ for _, c := range testColors {
+ p := New(c.code)
+ p.Print(c.text)
+
+ line, _ := rb.ReadString('\n')
+ if line != c.text {
+ t.Errorf("Expecting %s, got '%s'\n", c.text, line)
+ }
+ }
+
+}
+
+func TestColorVisual(t *testing.T) {
+ // First Visual Test
+ fmt.Println("")
+ Output = ansicolor.NewAnsiColorWriter(os.Stdout)
+
+ New(FgRed).Printf("red\t")
+ New(BgRed).Print(" ")
+ New(FgRed, Bold).Println(" red")
+
+ New(FgGreen).Printf("green\t")
+ New(BgGreen).Print(" ")
+ New(FgGreen, Bold).Println(" green")
+
+ New(FgYellow).Printf("yellow\t")
+ New(BgYellow).Print(" ")
+ New(FgYellow, Bold).Println(" yellow")
+
+ New(FgBlue).Printf("blue\t")
+ New(BgBlue).Print(" ")
+ New(FgBlue, Bold).Println(" blue")
+
+ New(FgMagenta).Printf("magenta\t")
+ New(BgMagenta).Print(" ")
+ New(FgMagenta, Bold).Println(" magenta")
+
+ New(FgCyan).Printf("cyan\t")
+ New(BgCyan).Print(" ")
+ New(FgCyan, Bold).Println(" cyan")
+
+ New(FgWhite).Printf("white\t")
+ New(BgWhite).Print(" ")
+ New(FgWhite, Bold).Println(" white")
+ fmt.Println("")
+
+ // Second Visual test
+ Black("black")
+ Red("red")
+ Green("green")
+ Yellow("yellow")
+ Blue("blue")
+ Magenta("magenta")
+ Cyan("cyan")
+ White("white")
+
+ // Third visual test
+ fmt.Println()
+ Set(FgBlue)
+ fmt.Println("is this blue?")
+ Unset()
+
+ Set(FgMagenta)
+ fmt.Println("and this magenta?")
+ Unset()
+
+ // Fourth Visual test
+ fmt.Println()
+ blue := New(FgBlue).PrintlnFunc()
+ blue("blue text with custom print func")
+
+ red := New(FgRed).PrintfFunc()
+ red("red text with a printf func: %d\n", 123)
+
+ put := New(FgYellow).SprintFunc()
+ warn := New(FgRed).SprintFunc()
+
+ fmt.Fprintf(Output, "this is a %s and this is %s.\n", put("warning"), warn("error"))
+
+ info := New(FgWhite, BgGreen).SprintFunc()
+ fmt.Fprintf(Output, "this %s rocks!\n", info("package"))
+
+ // Fifth Visual Test
+ fmt.Println()
+
+ fmt.Fprintln(Output, BlackString("black"))
+ fmt.Fprintln(Output, RedString("red"))
+ fmt.Fprintln(Output, GreenString("green"))
+ fmt.Fprintln(Output, YellowString("yellow"))
+ fmt.Fprintln(Output, BlueString("blue"))
+ fmt.Fprintln(Output, MagentaString("magenta"))
+ fmt.Fprintln(Output, CyanString("cyan"))
+ fmt.Fprintln(Output, WhiteString("white"))
+}
diff --git a/Godeps/_workspace/src/github.com/fatih/color/doc.go b/Godeps/_workspace/src/github.com/fatih/color/doc.go
new file mode 100644
index 000000000..17908787c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/fatih/color/doc.go
@@ -0,0 +1,114 @@
+/*
+Package color is an ANSI color package to output colorized or SGR defined
+output to the standard output. The API can be used in several way, pick one
+that suits you.
+
+Use simple and default helper functions with predefined foreground colors:
+
+ color.Cyan("Prints text in cyan.")
+
+ // a newline will be appended automatically
+ color.Blue("Prints %s in blue.", "text")
+
+ // More default foreground colors..
+ color.Red("We have red")
+ color.Yellow("Yellow color too!")
+ color.Magenta("And many others ..")
+
+However there are times where custom color mixes are required. Below are some
+examples to create custom color objects and use the print functions of each
+separate color object.
+
+ // Create a new color object
+ c := color.New(color.FgCyan).Add(color.Underline)
+ c.Println("Prints cyan text with an underline.")
+
+ // Or just add them to New()
+ d := color.New(color.FgCyan, color.Bold)
+ d.Printf("This prints bold cyan %s\n", "too!.")
+
+
+ // Mix up foreground and background colors, create new mixes!
+ red := color.New(color.FgRed)
+
+ boldRed := red.Add(color.Bold)
+ boldRed.Println("This will print text in bold red.")
+
+ whiteBackground := red.Add(color.BgWhite)
+ whiteBackground.Println("Red text with White background.")
+
+
+You can create PrintXxx functions to simplify even more:
+
+ // Create a custom print function for convenient
+ red := color.New(color.FgRed).PrintfFunc()
+ red("warning")
+ red("error: %s", err)
+
+ // Mix up multiple attributes
+ notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
+ notice("don't forget this...")
+
+
+Or create SprintXxx functions to mix strings with other non-colorized strings:
+
+ yellow := New(FgYellow).SprintFunc()
+ red := New(FgRed).SprintFunc()
+
+ fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error"))
+
+ info := New(FgWhite, BgGreen).SprintFunc()
+ fmt.Printf("this %s rocks!\n", info("package"))
+
+Windows support is enabled by default. All Print functions works as intended.
+However only for color.SprintXXX functions, user should use fmt.FprintXXX and
+set the output to color.Output:
+
+ fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
+
+ info := New(FgWhite, BgGreen).SprintFunc()
+ fmt.Fprintf(color.Output, "this %s rocks!\n", info("package"))
+
+Using with existing code is possible. Just use the Set() method to set the
+standard output to the given parameters. That way a rewrite of an existing
+code is not required.
+
+ // Use handy standard colors.
+ color.Set(color.FgYellow)
+
+ fmt.Println("Existing text will be now in Yellow")
+ fmt.Printf("This one %s\n", "too")
+
+ color.Unset() // don't forget to unset
+
+ // You can mix up parameters
+ color.Set(color.FgMagenta, color.Bold)
+ defer color.Unset() // use it in your function
+
+ fmt.Println("All text will be now bold magenta.")
+
+There might be a case where you want to disable color output (for example to
+pipe the standard output of your app to somewhere else). `Color` has support to
+disable colors both globally and for single color definition. For example
+suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
+the color output with:
+
+ var flagNoColor = flag.Bool("no-color", false, "Disable color output")
+
+ if *flagNoColor {
+ color.NoColor = true // disables colorized output
+ }
+
+It also has support for single color definitions (local). You can
+disable/enable color output on the fly:
+
+ c := color.New(color.FgCyan)
+ c.Println("Prints cyan text")
+
+ c.DisableColor()
+ c.Println("This is printed without any color")
+
+ c.EnableColor()
+ c.Println("This prints again cyan...")
+*/
+package color
diff --git a/Godeps/_workspace/src/github.com/mattn/go-colorable/README.md b/Godeps/_workspace/src/github.com/mattn/go-colorable/README.md
deleted file mode 100644
index c69da4a76..000000000
--- a/Godeps/_workspace/src/github.com/mattn/go-colorable/README.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# go-colorable
-
-Colorable writer for windows.
-
-For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
-This package is possible to handle escape sequence for ansi color on windows.
-
-## Too Bad!
-
-![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
-
-
-## So Good!
-
-![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
-
-## Usage
-
-```go
-logrus.SetOutput(colorable.NewColorableStdout())
-
-logrus.Info("succeeded")
-logrus.Warn("not correct")
-logrus.Error("something error")
-logrus.Fatal("panic")
-```
-
-You can compile above code on non-windows OSs.
-
-## Installation
-
-```
-$ go get github.com/mattn/go-colorable
-```
-
-# License
-
-MIT
-
-# Author
-
-Yasuhiro Matsumoto (a.k.a mattn)
diff --git a/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go
deleted file mode 100644
index 219f02f62..000000000
--- a/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// +build !windows
-
-package colorable
-
-import (
- "io"
- "os"
-)
-
-func NewColorableStdout() io.Writer {
- return os.Stdout
-}
-
-func NewColorableStderr() io.Writer {
- return os.Stderr
-}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go
deleted file mode 100644
index 6a2787808..000000000
--- a/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go
+++ /dev/null
@@ -1,594 +0,0 @@
-package colorable
-
-import (
- "bytes"
- "fmt"
- "io"
- "os"
- "strconv"
- "strings"
- "syscall"
- "unsafe"
-
- "github.com/mattn/go-isatty"
-)
-
-const (
- foregroundBlue = 0x1
- foregroundGreen = 0x2
- foregroundRed = 0x4
- foregroundIntensity = 0x8
- foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
- backgroundBlue = 0x10
- backgroundGreen = 0x20
- backgroundRed = 0x40
- backgroundIntensity = 0x80
- backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
-)
-
-type wchar uint16
-type short int16
-type dword uint32
-type word uint16
-
-type coord struct {
- x short
- y short
-}
-
-type smallRect struct {
- left short
- top short
- right short
- bottom short
-}
-
-type consoleScreenBufferInfo struct {
- size coord
- cursorPosition coord
- attributes word
- window smallRect
- maximumWindowSize coord
-}
-
-var (
- kernel32 = syscall.NewLazyDLL("kernel32.dll")
- procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
- procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
-)
-
-type Writer struct {
- out io.Writer
- handle syscall.Handle
- lastbuf bytes.Buffer
- oldattr word
-}
-
-func NewColorableStdout() io.Writer {
- var csbi consoleScreenBufferInfo
- out := os.Stdout
- if !isatty.IsTerminal(out.Fd()) {
- return out
- }
- handle := syscall.Handle(out.Fd())
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
-}
-
-func NewColorableStderr() io.Writer {
- var csbi consoleScreenBufferInfo
- out := os.Stderr
- if !isatty.IsTerminal(out.Fd()) {
- return out
- }
- handle := syscall.Handle(out.Fd())
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
-}
-
-var color256 = map[int]int{
- 0: 0x000000,
- 1: 0x800000,
- 2: 0x008000,
- 3: 0x808000,
- 4: 0x000080,
- 5: 0x800080,
- 6: 0x008080,
- 7: 0xc0c0c0,
- 8: 0x808080,
- 9: 0xff0000,
- 10: 0x00ff00,
- 11: 0xffff00,
- 12: 0x0000ff,
- 13: 0xff00ff,
- 14: 0x00ffff,
- 15: 0xffffff,
- 16: 0x000000,
- 17: 0x00005f,
- 18: 0x000087,
- 19: 0x0000af,
- 20: 0x0000d7,
- 21: 0x0000ff,
- 22: 0x005f00,
- 23: 0x005f5f,
- 24: 0x005f87,
- 25: 0x005faf,
- 26: 0x005fd7,
- 27: 0x005fff,
- 28: 0x008700,
- 29: 0x00875f,
- 30: 0x008787,
- 31: 0x0087af,
- 32: 0x0087d7,
- 33: 0x0087ff,
- 34: 0x00af00,
- 35: 0x00af5f,
- 36: 0x00af87,
- 37: 0x00afaf,
- 38: 0x00afd7,
- 39: 0x00afff,
- 40: 0x00d700,
- 41: 0x00d75f,
- 42: 0x00d787,
- 43: 0x00d7af,
- 44: 0x00d7d7,
- 45: 0x00d7ff,
- 46: 0x00ff00,
- 47: 0x00ff5f,
- 48: 0x00ff87,
- 49: 0x00ffaf,
- 50: 0x00ffd7,
- 51: 0x00ffff,
- 52: 0x5f0000,
- 53: 0x5f005f,
- 54: 0x5f0087,
- 55: 0x5f00af,
- 56: 0x5f00d7,
- 57: 0x5f00ff,
- 58: 0x5f5f00,
- 59: 0x5f5f5f,
- 60: 0x5f5f87,
- 61: 0x5f5faf,
- 62: 0x5f5fd7,
- 63: 0x5f5fff,
- 64: 0x5f8700,
- 65: 0x5f875f,
- 66: 0x5f8787,
- 67: 0x5f87af,
- 68: 0x5f87d7,
- 69: 0x5f87ff,
- 70: 0x5faf00,
- 71: 0x5faf5f,
- 72: 0x5faf87,
- 73: 0x5fafaf,
- 74: 0x5fafd7,
- 75: 0x5fafff,
- 76: 0x5fd700,
- 77: 0x5fd75f,
- 78: 0x5fd787,
- 79: 0x5fd7af,
- 80: 0x5fd7d7,
- 81: 0x5fd7ff,
- 82: 0x5fff00,
- 83: 0x5fff5f,
- 84: 0x5fff87,
- 85: 0x5fffaf,
- 86: 0x5fffd7,
- 87: 0x5fffff,
- 88: 0x870000,
- 89: 0x87005f,
- 90: 0x870087,
- 91: 0x8700af,
- 92: 0x8700d7,
- 93: 0x8700ff,
- 94: 0x875f00,
- 95: 0x875f5f,
- 96: 0x875f87,
- 97: 0x875faf,
- 98: 0x875fd7,
- 99: 0x875fff,
- 100: 0x878700,
- 101: 0x87875f,
- 102: 0x878787,
- 103: 0x8787af,
- 104: 0x8787d7,
- 105: 0x8787ff,
- 106: 0x87af00,
- 107: 0x87af5f,
- 108: 0x87af87,
- 109: 0x87afaf,
- 110: 0x87afd7,
- 111: 0x87afff,
- 112: 0x87d700,
- 113: 0x87d75f,
- 114: 0x87d787,
- 115: 0x87d7af,
- 116: 0x87d7d7,
- 117: 0x87d7ff,
- 118: 0x87ff00,
- 119: 0x87ff5f,
- 120: 0x87ff87,
- 121: 0x87ffaf,
- 122: 0x87ffd7,
- 123: 0x87ffff,
- 124: 0xaf0000,
- 125: 0xaf005f,
- 126: 0xaf0087,
- 127: 0xaf00af,
- 128: 0xaf00d7,
- 129: 0xaf00ff,
- 130: 0xaf5f00,
- 131: 0xaf5f5f,
- 132: 0xaf5f87,
- 133: 0xaf5faf,
- 134: 0xaf5fd7,
- 135: 0xaf5fff,
- 136: 0xaf8700,
- 137: 0xaf875f,
- 138: 0xaf8787,
- 139: 0xaf87af,
- 140: 0xaf87d7,
- 141: 0xaf87ff,
- 142: 0xafaf00,
- 143: 0xafaf5f,
- 144: 0xafaf87,
- 145: 0xafafaf,
- 146: 0xafafd7,
- 147: 0xafafff,
- 148: 0xafd700,
- 149: 0xafd75f,
- 150: 0xafd787,
- 151: 0xafd7af,
- 152: 0xafd7d7,
- 153: 0xafd7ff,
- 154: 0xafff00,
- 155: 0xafff5f,
- 156: 0xafff87,
- 157: 0xafffaf,
- 158: 0xafffd7,
- 159: 0xafffff,
- 160: 0xd70000,
- 161: 0xd7005f,
- 162: 0xd70087,
- 163: 0xd700af,
- 164: 0xd700d7,
- 165: 0xd700ff,
- 166: 0xd75f00,
- 167: 0xd75f5f,
- 168: 0xd75f87,
- 169: 0xd75faf,
- 170: 0xd75fd7,
- 171: 0xd75fff,
- 172: 0xd78700,
- 173: 0xd7875f,
- 174: 0xd78787,
- 175: 0xd787af,
- 176: 0xd787d7,
- 177: 0xd787ff,
- 178: 0xd7af00,
- 179: 0xd7af5f,
- 180: 0xd7af87,
- 181: 0xd7afaf,
- 182: 0xd7afd7,
- 183: 0xd7afff,
- 184: 0xd7d700,
- 185: 0xd7d75f,
- 186: 0xd7d787,
- 187: 0xd7d7af,
- 188: 0xd7d7d7,
- 189: 0xd7d7ff,
- 190: 0xd7ff00,
- 191: 0xd7ff5f,
- 192: 0xd7ff87,
- 193: 0xd7ffaf,
- 194: 0xd7ffd7,
- 195: 0xd7ffff,
- 196: 0xff0000,
- 197: 0xff005f,
- 198: 0xff0087,
- 199: 0xff00af,
- 200: 0xff00d7,
- 201: 0xff00ff,
- 202: 0xff5f00,
- 203: 0xff5f5f,
- 204: 0xff5f87,
- 205: 0xff5faf,
- 206: 0xff5fd7,
- 207: 0xff5fff,
- 208: 0xff8700,
- 209: 0xff875f,
- 210: 0xff8787,
- 211: 0xff87af,
- 212: 0xff87d7,
- 213: 0xff87ff,
- 214: 0xffaf00,
- 215: 0xffaf5f,
- 216: 0xffaf87,
- 217: 0xffafaf,
- 218: 0xffafd7,
- 219: 0xffafff,
- 220: 0xffd700,
- 221: 0xffd75f,
- 222: 0xffd787,
- 223: 0xffd7af,
- 224: 0xffd7d7,
- 225: 0xffd7ff,
- 226: 0xffff00,
- 227: 0xffff5f,
- 228: 0xffff87,
- 229: 0xffffaf,
- 230: 0xffffd7,
- 231: 0xffffff,
- 232: 0x080808,
- 233: 0x121212,
- 234: 0x1c1c1c,
- 235: 0x262626,
- 236: 0x303030,
- 237: 0x3a3a3a,
- 238: 0x444444,
- 239: 0x4e4e4e,
- 240: 0x585858,
- 241: 0x626262,
- 242: 0x6c6c6c,
- 243: 0x767676,
- 244: 0x808080,
- 245: 0x8a8a8a,
- 246: 0x949494,
- 247: 0x9e9e9e,
- 248: 0xa8a8a8,
- 249: 0xb2b2b2,
- 250: 0xbcbcbc,
- 251: 0xc6c6c6,
- 252: 0xd0d0d0,
- 253: 0xdadada,
- 254: 0xe4e4e4,
- 255: 0xeeeeee,
-}
-
-func (w *Writer) Write(data []byte) (n int, err error) {
- var csbi consoleScreenBufferInfo
- procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
-
- er := bytes.NewBuffer(data)
-loop:
- for {
- r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
- if r1 == 0 {
- break loop
- }
-
- c1, _, err := er.ReadRune()
- if err != nil {
- break loop
- }
- if c1 != 0x1b {
- fmt.Fprint(w.out, string(c1))
- continue
- }
- c2, _, err := er.ReadRune()
- if err != nil {
- w.lastbuf.WriteRune(c1)
- break loop
- }
- if c2 != 0x5b {
- w.lastbuf.WriteRune(c1)
- w.lastbuf.WriteRune(c2)
- continue
- }
-
- var buf bytes.Buffer
- var m rune
- for {
- c, _, err := er.ReadRune()
- if err != nil {
- w.lastbuf.WriteRune(c1)
- w.lastbuf.WriteRune(c2)
- w.lastbuf.Write(buf.Bytes())
- break loop
- }
- if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
- m = c
- break
- }
- buf.Write([]byte(string(c)))
- }
-
- switch m {
- case 'm':
- attr := csbi.attributes
- cs := buf.String()
- if cs == "" {
- procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
- continue
- }
- token := strings.Split(cs, ";")
- for i, ns := range token {
- if n, err = strconv.Atoi(ns); err == nil {
- switch {
- case n == 0 || n == 100:
- attr = w.oldattr
- case 1 <= n && n <= 5:
- attr |= foregroundIntensity
- case n == 7:
- attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
- case 22 == n || n == 25 || n == 25:
- attr |= foregroundIntensity
- case n == 27:
- attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
- case 30 <= n && n <= 37:
- attr = (attr & backgroundMask)
- if (n-30)&1 != 0 {
- attr |= foregroundRed
- }
- if (n-30)&2 != 0 {
- attr |= foregroundGreen
- }
- if (n-30)&4 != 0 {
- attr |= foregroundBlue
- }
- case n == 38: // set foreground color.
- if i < len(token)-2 && token[i+1] == "5" {
- if n256, err := strconv.Atoi(token[i+2]); err == nil {
- if n256foreAttr == nil {
- n256setup()
- }
- attr &= backgroundMask
- attr |= n256foreAttr[n256]
- i += 2
- }
- } else {
- attr = attr & (w.oldattr & backgroundMask)
- }
- case n == 39: // reset foreground color.
- attr &= backgroundMask
- attr |= w.oldattr & foregroundMask
- case 40 <= n && n <= 47:
- attr = (attr & foregroundMask)
- if (n-40)&1 != 0 {
- attr |= backgroundRed
- }
- if (n-40)&2 != 0 {
- attr |= backgroundGreen
- }
- if (n-40)&4 != 0 {
- attr |= backgroundBlue
- }
- case n == 48: // set background color.
- if i < len(token)-2 && token[i+1] == "5" {
- if n256, err := strconv.Atoi(token[i+2]); err == nil {
- if n256backAttr == nil {
- n256setup()
- }
- attr &= foregroundMask
- attr |= n256backAttr[n256]
- i += 2
- }
- } else {
- attr = attr & (w.oldattr & foregroundMask)
- }
- case n == 49: // reset foreground color.
- attr &= foregroundMask
- attr |= w.oldattr & backgroundMask
- }
- procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
- }
- }
- }
- }
- return len(data) - w.lastbuf.Len(), nil
-}
-
-type consoleColor struct {
- red bool
- green bool
- blue bool
- intensity bool
-}
-
-func minmax3(a, b, c int) (min, max int) {
- if a < b {
- if b < c {
- return a, c
- } else if a < c {
- return a, b
- } else {
- return c, b
- }
- } else {
- if a < c {
- return b, c
- } else if b < c {
- return b, a
- } else {
- return c, a
- }
- }
-}
-
-func toConsoleColor(rgb int) (c consoleColor) {
- r, g, b := (rgb&0xFF0000)>>16, (rgb&0x00FF00)>>8, rgb&0x0000FF
- min, max := minmax3(r, g, b)
- a := (min + max) / 2
- if r < 128 && g < 128 && b < 128 {
- if r >= a {
- c.red = true
- }
- if g >= a {
- c.green = true
- }
- if b >= a {
- c.blue = true
- }
- // non-intensed white is lighter than intensed black, so swap those.
- if c.red && c.green && c.blue {
- c.red, c.green, c.blue = false, false, false
- c.intensity = true
- }
- } else {
- if min < 128 {
- min = 128
- a = (min + max) / 2
- }
- if r >= a {
- c.red = true
- }
- if g >= a {
- c.green = true
- }
- if b >= a {
- c.blue = true
- }
- c.intensity = true
- // intensed black is darker than non-intensed white, so swap those.
- if !c.red && !c.green && !c.blue {
- c.red, c.green, c.blue = true, true, true
- c.intensity = false
- }
- }
- return c
-}
-
-func (c consoleColor) foregroundAttr() (attr word) {
- if c.red {
- attr |= foregroundRed
- }
- if c.green {
- attr |= foregroundGreen
- }
- if c.blue {
- attr |= foregroundBlue
- }
- if c.intensity {
- attr |= foregroundIntensity
- }
- return
-}
-
-func (c consoleColor) backgroundAttr() (attr word) {
- if c.red {
- attr |= backgroundRed
- }
- if c.green {
- attr |= backgroundGreen
- }
- if c.blue {
- attr |= backgroundBlue
- }
- if c.intensity {
- attr |= backgroundIntensity
- }
- return
-}
-
-var n256foreAttr []word
-var n256backAttr []word
-
-func n256setup() {
- n256foreAttr = make([]word, 256)
- n256backAttr = make([]word, 256)
- for i, rgb := range color256 {
- c := toConsoleColor(rgb)
- n256foreAttr[i] = c.foregroundAttr()
- n256backAttr[i] = c.backgroundAttr()
- }
-}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/.gitignore b/Godeps/_workspace/src/github.com/shiena/ansicolor/.gitignore
new file mode 100644
index 000000000..69cec52c4
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/.gitignore
@@ -0,0 +1,27 @@
+# Created by http://www.gitignore.io
+
+### Go ###
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/LICENSE b/Godeps/_workspace/src/github.com/shiena/ansicolor/LICENSE
new file mode 100644
index 000000000..e58473ed9
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) [2014] [shiena]
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/README.md b/Godeps/_workspace/src/github.com/shiena/ansicolor/README.md
new file mode 100644
index 000000000..7797a4f18
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/README.md
@@ -0,0 +1,100 @@
+[![GoDoc](https://godoc.org/github.com/shiena/ansicolor?status.svg)](https://godoc.org/github.com/shiena/ansicolor)
+
+# ansicolor
+
+Ansicolor library provides color console in Windows as ANSICON for Golang.
+
+## Features
+
+|Escape sequence|Text attributes|
+|---------------|----|
+|\x1b[0m|All attributes off(color at startup)|
+|\x1b[1m|Bold on(enable foreground intensity)|
+|\x1b[4m|Underline on|
+|\x1b[5m|Blink on(enable background intensity)|
+|\x1b[21m|Bold off(disable foreground intensity)|
+|\x1b[24m|Underline off|
+|\x1b[25m|Blink off(disable background intensity)|
+
+|Escape sequence|Foreground colors|
+|---------------|----|
+|\x1b[30m|Black|
+|\x1b[31m|Red|
+|\x1b[32m|Green|
+|\x1b[33m|Yellow|
+|\x1b[34m|Blue|
+|\x1b[35m|Magenta|
+|\x1b[36m|Cyan|
+|\x1b[37m|White|
+|\x1b[39m|Default(foreground color at startup)|
+|\x1b[90m|Light Gray|
+|\x1b[91m|Light Red|
+|\x1b[92m|Light Green|
+|\x1b[93m|Light Yellow|
+|\x1b[94m|Light Blue|
+|\x1b[95m|Light Magenta|
+|\x1b[96m|Light Cyan|
+|\x1b[97m|Light White|
+
+|Escape sequence|Background colors|
+|---------------|----|
+|\x1b[40m|Black|
+|\x1b[41m|Red|
+|\x1b[42m|Green|
+|\x1b[43m|Yellow|
+|\x1b[44m|Blue|
+|\x1b[45m|Magenta|
+|\x1b[46m|Cyan|
+|\x1b[47m|White|
+|\x1b[49m|Default(background color at startup)|
+|\x1b[100m|Light Gray|
+|\x1b[101m|Light Red|
+|\x1b[102m|Light Green|
+|\x1b[103m|Light Yellow|
+|\x1b[104m|Light Blue|
+|\x1b[105m|Light Magenta|
+|\x1b[106m|Light Cyan|
+|\x1b[107m|Light White|
+
+## Example
+
+```go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/shiena/ansicolor"
+)
+
+func main() {
+ w := ansicolor.NewAnsiColorWriter(os.Stdout)
+ text := "%sforeground %sbold%s %sbackground%s\n"
+ fmt.Fprintf(w, text, "\x1b[31m", "\x1b[1m", "\x1b[21m", "\x1b[41;32m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[32m", "\x1b[1m", "\x1b[21m", "\x1b[42;31m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[33m", "\x1b[1m", "\x1b[21m", "\x1b[43;34m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[34m", "\x1b[1m", "\x1b[21m", "\x1b[44;33m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[35m", "\x1b[1m", "\x1b[21m", "\x1b[45;36m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[36m", "\x1b[1m", "\x1b[21m", "\x1b[46;35m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[37m", "\x1b[1m", "\x1b[21m", "\x1b[47;30m", "\x1b[0m")
+}
+```
+
+![screenshot](https://gist.githubusercontent.com/shiena/a1bada24b525314a7d5e/raw/c763aa7cda6e4fefaccf831e2617adc40b6151c7/main.png)
+
+## See also:
+
+- https://github.com/daviddengcn/go-colortext
+- https://github.com/adoxa/ansicon
+- https://github.com/aslakhellesoy/wac
+- https://github.com/wsxiaoys/terminal
+
+## Contributing
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Add some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
+
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor.go
new file mode 100644
index 000000000..d3ece8fc0
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor.go
@@ -0,0 +1,20 @@
+// Copyright 2014 shiena Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+// Package ansicolor provides color console in Windows as ANSICON.
+package ansicolor
+
+import "io"
+
+// NewAnsiColorWriter creates and initializes a new ansiColorWriter
+// using io.Writer w as its initial contents.
+// In the console of Windows, which change the foreground and background
+// colors of the text by the escape sequence.
+// In the console of other systems, which writes to w all text.
+func NewAnsiColorWriter(w io.Writer) io.Writer {
+ if _, ok := w.(*ansiColorWriter); !ok {
+ return &ansiColorWriter{w: w}
+ }
+ return w
+}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor/main.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor/main.go
new file mode 100644
index 000000000..d86cfc0f3
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor/main.go
@@ -0,0 +1,27 @@
+// Copyright 2014 shiena Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+/*
+
+The ansicolor command colors a console text by ANSI escape sequence like wac.
+
+ $ go get github.com/shiena/ansicolor/ansicolor
+
+See also:
+ https://github.com/aslakhellesoy/wac
+
+*/
+package main
+
+import (
+ "io"
+ "os"
+
+ "github.com/shiena/ansicolor"
+)
+
+func main() {
+ w := ansicolor.NewAnsiColorWriter(os.Stdout)
+ io.Copy(w, os.Stdin)
+}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_ansi.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_ansi.go
new file mode 100644
index 000000000..57b4633a7
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_ansi.go
@@ -0,0 +1,17 @@
+// Copyright 2014 shiena Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package ansicolor
+
+import "io"
+
+type ansiColorWriter struct {
+ w io.Writer
+}
+
+func (cw *ansiColorWriter) Write(p []byte) (int, error) {
+ return cw.w.Write(p)
+}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_test.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_test.go
new file mode 100644
index 000000000..4feeb1de6
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_test.go
@@ -0,0 +1,25 @@
+package ansicolor_test
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/shiena/ansicolor"
+)
+
+func TestNewAnsiColor1(t *testing.T) {
+ inner := bytes.NewBufferString("")
+ w := ansicolor.NewAnsiColorWriter(inner)
+ if w == inner {
+ t.Errorf("Get %#v, want %#v", w, inner)
+ }
+}
+
+func TestNewAnsiColor2(t *testing.T) {
+ inner := bytes.NewBufferString("")
+ w1 := ansicolor.NewAnsiColorWriter(inner)
+ w2 := ansicolor.NewAnsiColorWriter(w1)
+ if w1 != w2 {
+ t.Errorf("Get %#v, want %#v", w1, w2)
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows.go
new file mode 100644
index 000000000..d918ffe91
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows.go
@@ -0,0 +1,351 @@
+// Copyright 2014 shiena Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package ansicolor
+
+import (
+ "bytes"
+ "io"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+type csiState int
+
+const (
+ outsideCsiCode csiState = iota
+ firstCsiCode
+ secondCsiCode
+)
+
+type ansiColorWriter struct {
+ w io.Writer
+ state csiState
+ paramBuf bytes.Buffer
+}
+
+const (
+ firstCsiChar byte = '\x1b'
+ secondeCsiChar byte = '['
+ separatorChar byte = ';'
+ sgrCode byte = 'm'
+)
+
+const (
+ foregroundBlue = uint16(0x0001)
+ foregroundGreen = uint16(0x0002)
+ foregroundRed = uint16(0x0004)
+ foregroundIntensity = uint16(0x0008)
+ backgroundBlue = uint16(0x0010)
+ backgroundGreen = uint16(0x0020)
+ backgroundRed = uint16(0x0040)
+ backgroundIntensity = uint16(0x0080)
+ underscore = uint16(0x8000)
+
+ foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity
+ backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity
+)
+
+const (
+ ansiReset = "0"
+ ansiIntensityOn = "1"
+ ansiIntensityOff = "21"
+ ansiUnderlineOn = "4"
+ ansiUnderlineOff = "24"
+ ansiBlinkOn = "5"
+ ansiBlinkOff = "25"
+
+ ansiForegroundBlack = "30"
+ ansiForegroundRed = "31"
+ ansiForegroundGreen = "32"
+ ansiForegroundYellow = "33"
+ ansiForegroundBlue = "34"
+ ansiForegroundMagenta = "35"
+ ansiForegroundCyan = "36"
+ ansiForegroundWhite = "37"
+ ansiForegroundDefault = "39"
+
+ ansiBackgroundBlack = "40"
+ ansiBackgroundRed = "41"
+ ansiBackgroundGreen = "42"
+ ansiBackgroundYellow = "43"
+ ansiBackgroundBlue = "44"
+ ansiBackgroundMagenta = "45"
+ ansiBackgroundCyan = "46"
+ ansiBackgroundWhite = "47"
+ ansiBackgroundDefault = "49"
+
+ ansiLightForegroundGray = "90"
+ ansiLightForegroundRed = "91"
+ ansiLightForegroundGreen = "92"
+ ansiLightForegroundYellow = "93"
+ ansiLightForegroundBlue = "94"
+ ansiLightForegroundMagenta = "95"
+ ansiLightForegroundCyan = "96"
+ ansiLightForegroundWhite = "97"
+
+ ansiLightBackgroundGray = "100"
+ ansiLightBackgroundRed = "101"
+ ansiLightBackgroundGreen = "102"
+ ansiLightBackgroundYellow = "103"
+ ansiLightBackgroundBlue = "104"
+ ansiLightBackgroundMagenta = "105"
+ ansiLightBackgroundCyan = "106"
+ ansiLightBackgroundWhite = "107"
+)
+
+type drawType int
+
+const (
+ foreground drawType = iota
+ background
+)
+
+type winColor struct {
+ code uint16
+ drawType drawType
+}
+
+var colorMap = map[string]winColor{
+ ansiForegroundBlack: {0, foreground},
+ ansiForegroundRed: {foregroundRed, foreground},
+ ansiForegroundGreen: {foregroundGreen, foreground},
+ ansiForegroundYellow: {foregroundRed | foregroundGreen, foreground},
+ ansiForegroundBlue: {foregroundBlue, foreground},
+ ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground},
+ ansiForegroundCyan: {foregroundGreen | foregroundBlue, foreground},
+ ansiForegroundWhite: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
+ ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
+
+ ansiBackgroundBlack: {0, background},
+ ansiBackgroundRed: {backgroundRed, background},
+ ansiBackgroundGreen: {backgroundGreen, background},
+ ansiBackgroundYellow: {backgroundRed | backgroundGreen, background},
+ ansiBackgroundBlue: {backgroundBlue, background},
+ ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background},
+ ansiBackgroundCyan: {backgroundGreen | backgroundBlue, background},
+ ansiBackgroundWhite: {backgroundRed | backgroundGreen | backgroundBlue, background},
+ ansiBackgroundDefault: {0, background},
+
+ ansiLightForegroundGray: {foregroundIntensity, foreground},
+ ansiLightForegroundRed: {foregroundIntensity | foregroundRed, foreground},
+ ansiLightForegroundGreen: {foregroundIntensity | foregroundGreen, foreground},
+ ansiLightForegroundYellow: {foregroundIntensity | foregroundRed | foregroundGreen, foreground},
+ ansiLightForegroundBlue: {foregroundIntensity | foregroundBlue, foreground},
+ ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground},
+ ansiLightForegroundCyan: {foregroundIntensity | foregroundGreen | foregroundBlue, foreground},
+ ansiLightForegroundWhite: {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground},
+
+ ansiLightBackgroundGray: {backgroundIntensity, background},
+ ansiLightBackgroundRed: {backgroundIntensity | backgroundRed, background},
+ ansiLightBackgroundGreen: {backgroundIntensity | backgroundGreen, background},
+ ansiLightBackgroundYellow: {backgroundIntensity | backgroundRed | backgroundGreen, background},
+ ansiLightBackgroundBlue: {backgroundIntensity | backgroundBlue, background},
+ ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background},
+ ansiLightBackgroundCyan: {backgroundIntensity | backgroundGreen | backgroundBlue, background},
+ ansiLightBackgroundWhite: {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background},
+}
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
+ procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+ defaultAttr *textAttributes
+)
+
+func init() {
+ screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
+ if screenInfo != nil {
+ colorMap[ansiForegroundDefault] = winColor{
+ screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue),
+ foreground,
+ }
+ colorMap[ansiBackgroundDefault] = winColor{
+ screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue),
+ background,
+ }
+ defaultAttr = convertTextAttr(screenInfo.WAttributes)
+ }
+}
+
+type coord struct {
+ X, Y int16
+}
+
+type smallRect struct {
+ Left, Top, Right, Bottom int16
+}
+
+type consoleScreenBufferInfo struct {
+ DwSize coord
+ DwCursorPosition coord
+ WAttributes uint16
+ SrWindow smallRect
+ DwMaximumWindowSize coord
+}
+
+func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
+ var csbi consoleScreenBufferInfo
+ ret, _, _ := procGetConsoleScreenBufferInfo.Call(
+ hConsoleOutput,
+ uintptr(unsafe.Pointer(&csbi)))
+ if ret == 0 {
+ return nil
+ }
+ return &csbi
+}
+
+func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
+ ret, _, _ := procSetConsoleTextAttribute.Call(
+ hConsoleOutput,
+ uintptr(wAttributes))
+ return ret != 0
+}
+
+type textAttributes struct {
+ foregroundColor uint16
+ backgroundColor uint16
+ foregroundIntensity uint16
+ backgroundIntensity uint16
+ underscore uint16
+ otherAttributes uint16
+}
+
+func convertTextAttr(winAttr uint16) *textAttributes {
+ fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue)
+ bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue)
+ fgIntensity := winAttr & foregroundIntensity
+ bgIntensity := winAttr & backgroundIntensity
+ underline := winAttr & underscore
+ otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore)
+ return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes}
+}
+
+func convertWinAttr(textAttr *textAttributes) uint16 {
+ var winAttr uint16 = 0
+ winAttr |= textAttr.foregroundColor
+ winAttr |= textAttr.backgroundColor
+ winAttr |= textAttr.foregroundIntensity
+ winAttr |= textAttr.backgroundIntensity
+ winAttr |= textAttr.underscore
+ winAttr |= textAttr.otherAttributes
+ return winAttr
+}
+
+func changeColor(param []byte) {
+ if defaultAttr == nil {
+ return
+ }
+
+ screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
+ if screenInfo == nil {
+ return
+ }
+
+ winAttr := convertTextAttr(screenInfo.WAttributes)
+ strParam := string(param)
+ if len(strParam) <= 0 {
+ strParam = "0"
+ }
+ csiParam := strings.Split(strParam, string(separatorChar))
+ for _, p := range csiParam {
+ c, ok := colorMap[p]
+ switch {
+ case !ok:
+ switch p {
+ case ansiReset:
+ winAttr.foregroundColor = defaultAttr.foregroundColor
+ winAttr.backgroundColor = defaultAttr.backgroundColor
+ winAttr.foregroundIntensity = defaultAttr.foregroundIntensity
+ winAttr.backgroundIntensity = defaultAttr.backgroundIntensity
+ winAttr.underscore = 0
+ winAttr.otherAttributes = 0
+ case ansiIntensityOn:
+ winAttr.foregroundIntensity = foregroundIntensity
+ case ansiIntensityOff:
+ winAttr.foregroundIntensity = 0
+ case ansiUnderlineOn:
+ winAttr.underscore = underscore
+ case ansiUnderlineOff:
+ winAttr.underscore = 0
+ case ansiBlinkOn:
+ winAttr.backgroundIntensity = backgroundIntensity
+ case ansiBlinkOff:
+ winAttr.backgroundIntensity = 0
+ default:
+ // unknown code
+ }
+ case c.drawType == foreground:
+ winAttr.foregroundColor = c.code
+ case c.drawType == background:
+ winAttr.backgroundColor = c.code
+ }
+ }
+ winTextAttribute := convertWinAttr(winAttr)
+ setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute)
+}
+
+func parseEscapeSequence(command byte, param []byte) {
+ switch command {
+ case sgrCode:
+ changeColor(param)
+ }
+}
+
+func isParameterChar(b byte) bool {
+ return ('0' <= b && b <= '9') || b == separatorChar
+}
+
+func (cw *ansiColorWriter) Write(p []byte) (int, error) {
+ r, nw, nc, first, last := 0, 0, 0, 0, 0
+ var err error
+ for i, ch := range p {
+ switch cw.state {
+ case outsideCsiCode:
+ if ch == firstCsiChar {
+ nc++
+ cw.state = firstCsiCode
+ }
+ case firstCsiCode:
+ switch ch {
+ case firstCsiChar:
+ nc++
+ break
+ case secondeCsiChar:
+ nc++
+ cw.state = secondCsiCode
+ last = i - 1
+ default:
+ cw.state = outsideCsiCode
+ }
+ case secondCsiCode:
+ nc++
+ if isParameterChar(ch) {
+ cw.paramBuf.WriteByte(ch)
+ } else {
+ nw, err = cw.w.Write(p[first:last])
+ r += nw
+ if err != nil {
+ return r, err
+ }
+ first = i + 1
+ param := cw.paramBuf.Bytes()
+ cw.paramBuf.Reset()
+ parseEscapeSequence(ch, param)
+ cw.state = outsideCsiCode
+ }
+ default:
+ cw.state = outsideCsiCode
+ }
+ }
+
+ if cw.state == outsideCsiCode {
+ nw, err = cw.w.Write(p[first:len(p)])
+ }
+
+ return r + nw + nc, err
+}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows_test.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows_test.go
new file mode 100644
index 000000000..6c126d517
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows_test.go
@@ -0,0 +1,236 @@
+// Copyright 2014 shiena Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package ansicolor_test
+
+import (
+ "bytes"
+ "fmt"
+ "syscall"
+ "testing"
+
+ "github.com/shiena/ansicolor"
+ . "github.com/shiena/ansicolor"
+)
+
+func TestWritePlanText(t *testing.T) {
+ inner := bytes.NewBufferString("")
+ w := ansicolor.NewAnsiColorWriter(inner)
+ expected := "plain text"
+ fmt.Fprintf(w, expected)
+ actual := inner.String()
+ if actual != expected {
+ t.Errorf("Get %s, want %s", actual, expected)
+ }
+}
+
+func TestWriteParseText(t *testing.T) {
+ inner := bytes.NewBufferString("")
+ w := ansicolor.NewAnsiColorWriter(inner)
+
+ inputTail := "\x1b[0mtail text"
+ expectedTail := "tail text"
+ fmt.Fprintf(w, inputTail)
+ actualTail := inner.String()
+ inner.Reset()
+ if actualTail != expectedTail {
+ t.Errorf("Get %s, want %s", actualTail, expectedTail)
+ }
+
+ inputHead := "head text\x1b[0m"
+ expectedHead := "head text"
+ fmt.Fprintf(w, inputHead)
+ actualHead := inner.String()
+ inner.Reset()
+ if actualHead != expectedHead {
+ t.Errorf("Get %s, want %s", actualHead, expectedHead)
+ }
+
+ inputBothEnds := "both ends \x1b[0m text"
+ expectedBothEnds := "both ends text"
+ fmt.Fprintf(w, inputBothEnds)
+ actualBothEnds := inner.String()
+ inner.Reset()
+ if actualBothEnds != expectedBothEnds {
+ t.Errorf("Get %s, want %s", actualBothEnds, expectedBothEnds)
+ }
+
+ inputManyEsc := "\x1b\x1b\x1b\x1b[0m many esc"
+ expectedManyEsc := "\x1b\x1b\x1b many esc"
+ fmt.Fprintf(w, inputManyEsc)
+ actualManyEsc := inner.String()
+ inner.Reset()
+ if actualManyEsc != expectedManyEsc {
+ t.Errorf("Get %s, want %s", actualManyEsc, expectedManyEsc)
+ }
+
+ expectedSplit := "split text"
+ for _, ch := range "split \x1b[0m text" {
+ fmt.Fprintf(w, string(ch))
+ }
+ actualSplit := inner.String()
+ inner.Reset()
+ if actualSplit != expectedSplit {
+ t.Errorf("Get %s, want %s", actualSplit, expectedSplit)
+ }
+}
+
+type screenNotFoundError struct {
+ error
+}
+
+func writeAnsiColor(expectedText, colorCode string) (actualText string, actualAttributes uint16, err error) {
+ inner := bytes.NewBufferString("")
+ w := ansicolor.NewAnsiColorWriter(inner)
+ fmt.Fprintf(w, "\x1b[%sm%s", colorCode, expectedText)
+
+ actualText = inner.String()
+ screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
+ if screenInfo != nil {
+ actualAttributes = screenInfo.WAttributes
+ } else {
+ err = &screenNotFoundError{}
+ }
+ return
+}
+
+type testParam struct {
+ text string
+ attributes uint16
+ ansiColor string
+}
+
+func TestWriteAnsiColorText(t *testing.T) {
+ screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
+ if screenInfo == nil {
+ t.Fatal("Could not get ConsoleScreenBufferInfo")
+ }
+ defer ChangeColor(screenInfo.WAttributes)
+ defaultFgColor := screenInfo.WAttributes & uint16(0x0007)
+ defaultBgColor := screenInfo.WAttributes & uint16(0x0070)
+ defaultFgIntensity := screenInfo.WAttributes & uint16(0x0008)
+ defaultBgIntensity := screenInfo.WAttributes & uint16(0x0080)
+
+ fgParam := []testParam{
+ {"foreground black ", uint16(0x0000 | 0x0000), "30"},
+ {"foreground red ", uint16(0x0004 | 0x0000), "31"},
+ {"foreground green ", uint16(0x0002 | 0x0000), "32"},
+ {"foreground yellow ", uint16(0x0006 | 0x0000), "33"},
+ {"foreground blue ", uint16(0x0001 | 0x0000), "34"},
+ {"foreground magenta", uint16(0x0005 | 0x0000), "35"},
+ {"foreground cyan ", uint16(0x0003 | 0x0000), "36"},
+ {"foreground white ", uint16(0x0007 | 0x0000), "37"},
+ {"foreground default", defaultFgColor | 0x0000, "39"},
+ {"foreground light gray ", uint16(0x0000 | 0x0008 | 0x0000), "90"},
+ {"foreground light red ", uint16(0x0004 | 0x0008 | 0x0000), "91"},
+ {"foreground light green ", uint16(0x0002 | 0x0008 | 0x0000), "92"},
+ {"foreground light yellow ", uint16(0x0006 | 0x0008 | 0x0000), "93"},
+ {"foreground light blue ", uint16(0x0001 | 0x0008 | 0x0000), "94"},
+ {"foreground light magenta", uint16(0x0005 | 0x0008 | 0x0000), "95"},
+ {"foreground light cyan ", uint16(0x0003 | 0x0008 | 0x0000), "96"},
+ {"foreground light white ", uint16(0x0007 | 0x0008 | 0x0000), "97"},
+ }
+
+ bgParam := []testParam{
+ {"background black ", uint16(0x0007 | 0x0000), "40"},
+ {"background red ", uint16(0x0007 | 0x0040), "41"},
+ {"background green ", uint16(0x0007 | 0x0020), "42"},
+ {"background yellow ", uint16(0x0007 | 0x0060), "43"},
+ {"background blue ", uint16(0x0007 | 0x0010), "44"},
+ {"background magenta", uint16(0x0007 | 0x0050), "45"},
+ {"background cyan ", uint16(0x0007 | 0x0030), "46"},
+ {"background white ", uint16(0x0007 | 0x0070), "47"},
+ {"background default", uint16(0x0007) | defaultBgColor, "49"},
+ {"background light gray ", uint16(0x0007 | 0x0000 | 0x0080), "100"},
+ {"background light red ", uint16(0x0007 | 0x0040 | 0x0080), "101"},
+ {"background light green ", uint16(0x0007 | 0x0020 | 0x0080), "102"},
+ {"background light yellow ", uint16(0x0007 | 0x0060 | 0x0080), "103"},
+ {"background light blue ", uint16(0x0007 | 0x0010 | 0x0080), "104"},
+ {"background light magenta", uint16(0x0007 | 0x0050 | 0x0080), "105"},
+ {"background light cyan ", uint16(0x0007 | 0x0030 | 0x0080), "106"},
+ {"background light white ", uint16(0x0007 | 0x0070 | 0x0080), "107"},
+ }
+
+ resetParam := []testParam{
+ {"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, "0"},
+ {"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, ""},
+ }
+
+ boldParam := []testParam{
+ {"bold on", uint16(0x0007 | 0x0008), "1"},
+ {"bold off", uint16(0x0007), "21"},
+ }
+
+ underscoreParam := []testParam{
+ {"underscore on", uint16(0x0007 | 0x8000), "4"},
+ {"underscore off", uint16(0x0007), "24"},
+ }
+
+ blinkParam := []testParam{
+ {"blink on", uint16(0x0007 | 0x0080), "5"},
+ {"blink off", uint16(0x0007), "25"},
+ }
+
+ mixedParam := []testParam{
+ {"both black, bold, underline, blink", uint16(0x0000 | 0x0000 | 0x0008 | 0x8000 | 0x0080), "30;40;1;4;5"},
+ {"both red, bold, underline, blink", uint16(0x0004 | 0x0040 | 0x0008 | 0x8000 | 0x0080), "31;41;1;4;5"},
+ {"both green, bold, underline, blink", uint16(0x0002 | 0x0020 | 0x0008 | 0x8000 | 0x0080), "32;42;1;4;5"},
+ {"both yellow, bold, underline, blink", uint16(0x0006 | 0x0060 | 0x0008 | 0x8000 | 0x0080), "33;43;1;4;5"},
+ {"both blue, bold, underline, blink", uint16(0x0001 | 0x0010 | 0x0008 | 0x8000 | 0x0080), "34;44;1;4;5"},
+ {"both magenta, bold, underline, blink", uint16(0x0005 | 0x0050 | 0x0008 | 0x8000 | 0x0080), "35;45;1;4;5"},
+ {"both cyan, bold, underline, blink", uint16(0x0003 | 0x0030 | 0x0008 | 0x8000 | 0x0080), "36;46;1;4;5"},
+ {"both white, bold, underline, blink", uint16(0x0007 | 0x0070 | 0x0008 | 0x8000 | 0x0080), "37;47;1;4;5"},
+ {"both default, bold, underline, blink", uint16(defaultFgColor | defaultBgColor | 0x0008 | 0x8000 | 0x0080), "39;49;1;4;5"},
+ }
+
+ assertTextAttribute := func(expectedText string, expectedAttributes uint16, ansiColor string) {
+ actualText, actualAttributes, err := writeAnsiColor(expectedText, ansiColor)
+ if actualText != expectedText {
+ t.Errorf("Get %s, want %s", actualText, expectedText)
+ }
+ if err != nil {
+ t.Fatal("Could not get ConsoleScreenBufferInfo")
+ }
+ if actualAttributes != expectedAttributes {
+ t.Errorf("Text: %s, Get 0x%04x, want 0x%04x", expectedText, actualAttributes, expectedAttributes)
+ }
+ }
+
+ for _, v := range fgParam {
+ ResetColor()
+ assertTextAttribute(v.text, v.attributes, v.ansiColor)
+ }
+
+ for _, v := range bgParam {
+ ChangeColor(uint16(0x0070 | 0x0007))
+ assertTextAttribute(v.text, v.attributes, v.ansiColor)
+ }
+
+ for _, v := range resetParam {
+ ChangeColor(uint16(0x0000 | 0x0070 | 0x0008))
+ assertTextAttribute(v.text, v.attributes, v.ansiColor)
+ }
+
+ ResetColor()
+ for _, v := range boldParam {
+ assertTextAttribute(v.text, v.attributes, v.ansiColor)
+ }
+
+ ResetColor()
+ for _, v := range underscoreParam {
+ assertTextAttribute(v.text, v.attributes, v.ansiColor)
+ }
+
+ ResetColor()
+ for _, v := range blinkParam {
+ assertTextAttribute(v.text, v.attributes, v.ansiColor)
+ }
+
+ for _, v := range mixedParam {
+ ResetColor()
+ assertTextAttribute(v.text, v.attributes, v.ansiColor)
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/example_test.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/example_test.go
new file mode 100644
index 000000000..f2ac67c17
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/example_test.go
@@ -0,0 +1,24 @@
+// Copyright 2014 shiena Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package ansicolor_test
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/shiena/ansicolor"
+)
+
+func ExampleNewAnsiColorWriter() {
+ w := ansicolor.NewAnsiColorWriter(os.Stdout)
+ text := "%sforeground %sbold%s %sbackground%s\n"
+ fmt.Fprintf(w, text, "\x1b[31m", "\x1b[1m", "\x1b[21m", "\x1b[41;32m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[32m", "\x1b[1m", "\x1b[21m", "\x1b[42;31m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[33m", "\x1b[1m", "\x1b[21m", "\x1b[43;34m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[34m", "\x1b[1m", "\x1b[21m", "\x1b[44;33m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[35m", "\x1b[1m", "\x1b[21m", "\x1b[45;36m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[36m", "\x1b[1m", "\x1b[21m", "\x1b[46;35m", "\x1b[0m")
+ fmt.Fprintf(w, text, "\x1b[37m", "\x1b[1m", "\x1b[21m", "\x1b[47;30m", "\x1b[0m")
+}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/export_test.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/export_test.go
new file mode 100644
index 000000000..6d2f7c074
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/export_test.go
@@ -0,0 +1,19 @@
+// Copyright 2014 shiena Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package ansicolor
+
+import "syscall"
+
+var GetConsoleScreenBufferInfo = getConsoleScreenBufferInfo
+
+func ChangeColor(color uint16) {
+ setConsoleTextAttribute(uintptr(syscall.Stdout), color)
+}
+
+func ResetColor() {
+ ChangeColor(uint16(0x0007))
+}
diff --git a/cmd/ethtest/main.go b/cmd/ethtest/main.go
index 5429cab31..67b965396 100644
--- a/cmd/ethtest/main.go
+++ b/cmd/ethtest/main.go
@@ -26,6 +26,7 @@ import (
"strings"
"github.com/codegangsta/cli"
+ "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/tests"
)
@@ -62,6 +63,10 @@ var (
Name: "skip",
Usage: "Tests names to skip",
}
+ TraceFlag = cli.BoolFlag{
+ Name: "trace",
+ Usage: "Enable VM tracing",
+ }
)
func runTestWithReader(test string, r io.Reader) error {
@@ -173,7 +178,6 @@ func runSuite(test, file string) {
glog.Fatalln(err)
}
}
-
}
}
}
@@ -184,6 +188,7 @@ func setupApp(c *cli.Context) {
continueOnError = c.GlobalBool(ContinueOnErrorFlag.Name)
useStdIn := c.GlobalBool(ReadStdInFlag.Name)
skipTests = strings.Split(c.GlobalString(SkipTestsFlag.Name), " ")
+ vm.Debug = c.GlobalBool(TraceFlag.Name)
if !useStdIn {
runSuite(flagTest, flagFile)
@@ -211,6 +216,7 @@ func main() {
ContinueOnErrorFlag,
ReadStdInFlag,
SkipTestsFlag,
+ TraceFlag,
}
if err := app.Run(os.Args); err != nil {
diff --git a/cmd/evm/main.go b/cmd/evm/main.go
index be6546c95..6639069b9 100644
--- a/cmd/evm/main.go
+++ b/cmd/evm/main.go
@@ -102,7 +102,7 @@ func init() {
func run(ctx *cli.Context) {
vm.Debug = ctx.GlobalBool(DebugFlag.Name)
vm.ForceJit = ctx.GlobalBool(ForceJitFlag.Name)
- vm.DisableJit = ctx.GlobalBool(DisableJitFlag.Name)
+ vm.EnableJit = !ctx.GlobalBool(DisableJitFlag.Name)
glog.SetToStderr(true)
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index 2d8eb15c2..876b8c6ba 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -74,10 +74,10 @@ func importChain(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
utils.Fatalf("This command requires an argument.")
}
- chain, blockDB, stateDB, extraDB := utils.MakeChain(ctx)
+ chain, chainDb := utils.MakeChain(ctx)
start := time.Now()
err := utils.ImportChain(chain, ctx.Args().First())
- closeAll(blockDB, stateDB, extraDB)
+ chainDb.Close()
if err != nil {
utils.Fatalf("Import error: %v", err)
}
@@ -88,7 +88,7 @@ func exportChain(ctx *cli.Context) {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- chain, _, _, _ := utils.MakeChain(ctx)
+ chain, _ := utils.MakeChain(ctx)
start := time.Now()
var err error
@@ -136,8 +136,8 @@ func removeDB(ctx *cli.Context) {
func upgradeDB(ctx *cli.Context) {
glog.Infoln("Upgrading blockchain database")
- chain, blockDB, stateDB, extraDB := utils.MakeChain(ctx)
- v, _ := blockDB.Get([]byte("BlockchainVersion"))
+ chain, chainDb := utils.MakeChain(ctx)
+ v, _ := chainDb.Get([]byte("BlockchainVersion"))
bcVersion := int(common.NewValue(v).Uint())
if bcVersion == 0 {
bcVersion = core.BlockChainVersion
@@ -149,15 +149,14 @@ func upgradeDB(ctx *cli.Context) {
if err := utils.ExportChain(chain, exportFile); err != nil {
utils.Fatalf("Unable to export chain for reimport %s", err)
}
- closeAll(blockDB, stateDB, extraDB)
- os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
- os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
+ chainDb.Close()
+ os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "chaindata"))
// Import the chain file.
- chain, blockDB, stateDB, extraDB = utils.MakeChain(ctx)
- blockDB.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
+ chain, chainDb = utils.MakeChain(ctx)
+ chainDb.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
err := utils.ImportChain(chain, exportFile)
- closeAll(blockDB, stateDB, extraDB)
+ chainDb.Close()
if err != nil {
utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile)
} else {
@@ -167,7 +166,7 @@ func upgradeDB(ctx *cli.Context) {
}
func dump(ctx *cli.Context) {
- chain, _, stateDB, _ := utils.MakeChain(ctx)
+ chain, chainDb := utils.MakeChain(ctx)
for _, arg := range ctx.Args() {
var block *types.Block
if hashish(arg) {
@@ -180,10 +179,11 @@ func dump(ctx *cli.Context) {
fmt.Println("{}")
utils.Fatalf("block not found")
} else {
- state := state.New(block.Root(), stateDB)
+ state := state.New(block.Root(), chainDb)
fmt.Printf("%s\n", state.Dump())
}
}
+ chainDb.Close()
}
// hashish returns true for strings that look like hashes.
diff --git a/cmd/geth/js.go b/cmd/geth/js.go
index bf56423ec..c31deefdd 100644
--- a/cmd/geth/js.go
+++ b/cmd/geth/js.go
@@ -145,19 +145,15 @@ func apiWordCompleter(line string, pos int) (head string, completions []string,
return begin, completionWords, end
}
-func newLightweightJSRE(libPath string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre {
+func newLightweightJSRE(libPath string, client comms.EthereumClient, interactive bool) *jsre {
js := &jsre{ps1: "> "}
js.wait = make(chan *big.Int)
js.client = client
js.ds = docserver.New("/")
- if f == nil {
- f = js
- }
-
// update state in separare forever blocks
js.re = re.New(libPath)
- if err := js.apiBindings(f); err != nil {
+ if err := js.apiBindings(js); err != nil {
utils.Fatalf("Unable to initialize console - %v", err)
}
@@ -232,15 +228,10 @@ func (self *jsre) loadAutoCompletion() {
}
func (self *jsre) batch(statement string) {
- val, err := self.re.Run(statement)
+ err := self.re.EvalAndPrettyPrint(statement)
if err != nil {
fmt.Printf("error: %v", err)
- } else if val.IsDefined() && val.IsObject() {
- obj, _ := self.re.Get("ret_result")
- fmt.Printf("%v", obj)
- } else if val.IsDefined() {
- fmt.Printf("%v", val)
}
if self.atexit != nil {
@@ -252,22 +243,22 @@ func (self *jsre) batch(statement string) {
// show summary of current geth instance
func (self *jsre) welcome() {
- self.re.Eval(`console.log('instance: ' + web3.version.client);`)
- self.re.Eval(`console.log(' datadir: ' + admin.datadir);`)
- self.re.Eval(`console.log("coinbase: " + eth.coinbase);`)
- self.re.Eval(`var lastBlockTimestamp = 1000 * eth.getBlock(eth.blockNumber).timestamp`)
- self.re.Eval(`console.log("at block: " + eth.blockNumber + " (" + new Date(lastBlockTimestamp).toLocaleDateString()
- + " " + new Date(lastBlockTimestamp).toLocaleTimeString() + ")");`)
-
+ self.re.Run(`
+ (function () {
+ console.log('instance: ' + web3.version.client);
+ console.log(' datadir: ' + admin.datadir);
+ console.log("coinbase: " + eth.coinbase);
+ var ts = 1000 * eth.getBlock(eth.blockNumber).timestamp;
+ console.log("at block: " + eth.blockNumber + " (" + new Date(ts) + ")");
+ })();
+ `)
if modules, err := self.supportedApis(); err == nil {
loadedModules := make([]string, 0)
for api, version := range modules {
loadedModules = append(loadedModules, fmt.Sprintf("%s:%s", api, version))
}
sort.Strings(loadedModules)
-
- self.re.Eval(fmt.Sprintf("var modules = '%s';", strings.Join(loadedModules, " ")))
- self.re.Eval(`console.log(" modules: " + modules);`)
+ fmt.Println("modules:", strings.Join(loadedModules, " "))
}
}
@@ -291,7 +282,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
utils.Fatalf("Unable to determine supported api's: %v", err)
}
- jeth := rpc.NewJeth(api.Merge(apiImpl...), js.re, js.client)
+ jeth := rpc.NewJeth(api.Merge(apiImpl...), js.re, js.client, f)
js.re.Set("jeth", struct{}{})
t, _ := js.re.Get("jeth")
jethObj := t.Object()
@@ -309,12 +300,12 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
utils.Fatalf("Error loading web3.js: %v", err)
}
- _, err = js.re.Eval("var web3 = require('web3');")
+ _, err = js.re.Run("var web3 = require('web3');")
if err != nil {
utils.Fatalf("Error requiring web3: %v", err)
}
- _, err = js.re.Eval("web3.setProvider(jeth)")
+ _, err = js.re.Run("web3.setProvider(jeth)")
if err != nil {
utils.Fatalf("Error setting web3 provider: %v", err)
}
@@ -333,13 +324,13 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
}
}
- _, err = js.re.Eval(shortcuts)
+ _, err = js.re.Run(shortcuts)
if err != nil {
utils.Fatalf("Error setting namespaces: %v", err)
}
- js.re.Eval(`var GlobalRegistrar = eth.contract(` + registrar.GlobalRegistrarAbi + `); registrar = GlobalRegistrar.at("` + registrar.GlobalRegistrarAddr + `");`)
+ js.re.Run(`var GlobalRegistrar = eth.contract(` + registrar.GlobalRegistrarAbi + `); registrar = GlobalRegistrar.at("` + registrar.GlobalRegistrarAddr + `");`)
return nil
}
@@ -387,6 +378,11 @@ func (self *jsre) interactive() {
for {
line, err := self.Prompt(<-prompt)
if err != nil {
+ if err == liner.ErrPromptAborted { // ctrl-C
+ self.resetPrompt()
+ inputln <- ""
+ continue
+ }
return
}
inputln <- line
@@ -458,8 +454,7 @@ func (self *jsre) parseInput(code string) {
fmt.Println("[native] error", r)
}
}()
- value, err := self.re.Run(code)
- if err != nil {
+ if err := self.re.EvalAndPrettyPrint(code); err != nil {
if ottoErr, ok := err.(*otto.Error); ok {
fmt.Println(ottoErr.String())
} else {
@@ -467,12 +462,17 @@ func (self *jsre) parseInput(code string) {
}
return
}
- self.printValue(value)
}
var indentCount = 0
var str = ""
+func (self *jsre) resetPrompt() {
+ indentCount = 0
+ str = ""
+ self.ps1 = "> "
+}
+
func (self *jsre) setIndent() {
open := strings.Count(str, "{")
open += strings.Count(str, "(")
@@ -486,10 +486,3 @@ func (self *jsre) setIndent() {
self.ps1 += " "
}
}
-
-func (self *jsre) printValue(v interface{}) {
- val, err := self.re.PrettyPrint(v)
- if err == nil {
- fmt.Printf("%v", val)
- }
-}
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 895e55b44..2dc3c438f 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -19,7 +19,6 @@ package main
import (
"fmt"
- "io"
"io/ioutil"
_ "net/http/pprof"
"os"
@@ -46,12 +45,10 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms"
- "github.com/mattn/go-colorable"
- "github.com/mattn/go-isatty"
)
const (
- ClientIdentifier = "Geth "
+ ClientIdentifier = "Geth"
Version = "1.0.1"
VersionMajor = 1
VersionMinor = 0
@@ -398,14 +395,6 @@ func run(ctx *cli.Context) {
func attach(ctx *cli.Context) {
utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name))
- // Wrap the standard output with a colorified stream (windows)
- if isatty.IsTerminal(os.Stdout.Fd()) {
- if pr, pw, err := os.Pipe(); err == nil {
- go io.Copy(colorable.NewColorableStdout(), pr)
- os.Stdout = pw
- }
- }
-
var client comms.EthereumClient
var err error
if ctx.Args().Present() {
@@ -425,7 +414,7 @@ func attach(ctx *cli.Context) {
ctx.GlobalString(utils.JSpathFlag.Name),
client,
true,
- nil)
+ )
if ctx.GlobalString(utils.ExecFlag.Name) != "" {
repl.batch(ctx.GlobalString(utils.ExecFlag.Name))
@@ -438,14 +427,6 @@ func attach(ctx *cli.Context) {
func console(ctx *cli.Context) {
utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name))
- // Wrap the standard output with a colorified stream (windows)
- if isatty.IsTerminal(os.Stdout.Fd()) {
- if pr, pw, err := os.Pipe(); err == nil {
- go io.Copy(colorable.NewColorableStdout(), pr)
- os.Stdout = pw
- }
- }
-
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
ethereum, err := eth.New(cfg)
if err != nil {
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index f8f7f6376..983762db8 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -21,6 +21,7 @@ import (
"bufio"
"fmt"
"io"
+ "math"
"math/big"
"os"
"os/signal"
@@ -152,6 +153,7 @@ func InitOlympic() {
params.MaximumExtraDataSize = big.NewInt(1024)
NetworkIdFlag.Value = 0
core.BlockReward = big.NewInt(1.5e+18)
+ core.ExpDiffPeriod = big.NewInt(math.MaxInt64)
}
func FormatTransactionData(data string) []byte {
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index e7b30cfa0..af2929d10 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -21,30 +21,32 @@ import (
"fmt"
"log"
"math/big"
+ "net"
"net/http"
"os"
"path/filepath"
"runtime"
"strconv"
- "github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/metrics"
-
"github.com/codegangsta/cli"
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms"
+ "github.com/ethereum/go-ethereum/rpc/shared"
+ "github.com/ethereum/go-ethereum/rpc/useragent"
"github.com/ethereum/go-ethereum/xeth"
)
@@ -452,29 +454,23 @@ func SetupLogger(ctx *cli.Context) {
// SetupVM configured the VM package's global settings
func SetupVM(ctx *cli.Context) {
- vm.DisableJit = !ctx.GlobalBool(VMEnableJitFlag.Name)
+ vm.EnableJit = ctx.GlobalBool(VMEnableJitFlag.Name)
vm.ForceJit = ctx.GlobalBool(VMForceJitFlag.Name)
vm.SetJITCacheSize(ctx.GlobalInt(VMJitCacheFlag.Name))
}
// MakeChain creates a chain manager from set command line flags.
-func MakeChain(ctx *cli.Context) (chain *core.ChainManager, blockDB, stateDB, extraDB common.Database) {
+func MakeChain(ctx *cli.Context) (chain *core.ChainManager, chainDb common.Database) {
datadir := ctx.GlobalString(DataDirFlag.Name)
cache := ctx.GlobalInt(CacheFlag.Name)
var err error
- if blockDB, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "blockchain"), cache); err != nil {
- Fatalf("Could not open database: %v", err)
- }
- if stateDB, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "state"), cache); err != nil {
- Fatalf("Could not open database: %v", err)
- }
- if extraDB, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "extra"), cache); err != nil {
+ if chainDb, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "chaindata"), cache); err != nil {
Fatalf("Could not open database: %v", err)
}
if ctx.GlobalBool(OlympicFlag.Name) {
InitOlympic()
- _, err := core.WriteTestNetGenesisBlock(stateDB, blockDB, 42)
+ _, err := core.WriteTestNetGenesisBlock(chainDb, 42)
if err != nil {
glog.Fatalln(err)
}
@@ -483,14 +479,14 @@ func MakeChain(ctx *cli.Context) (chain *core.ChainManager, blockDB, stateDB, ex
eventMux := new(event.TypeMux)
pow := ethash.New()
//genesis := core.GenesisBlock(uint64(ctx.GlobalInt(GenesisNonceFlag.Name)), blockDB)
- chain, err = core.NewChainManager(blockDB, stateDB, extraDB, pow, eventMux)
+ chain, err = core.NewChainManager(chainDb, pow, eventMux)
if err != nil {
Fatalf("Could not start chainmanager: %v", err)
}
- proc := core.NewBlockProcessor(stateDB, extraDB, pow, chain, eventMux)
+ proc := core.NewBlockProcessor(chainDb, pow, chain, eventMux)
chain.SetProcessor(proc)
- return chain, blockDB, stateDB, extraDB
+ return chain, chainDb
}
// MakeChain creates an account manager from set command line flags.
@@ -524,15 +520,20 @@ func StartIPC(eth *eth.Ethereum, ctx *cli.Context) error {
Endpoint: IpcSocketPath(ctx),
}
- xeth := xeth.New(eth, nil)
- codec := codec.JSON
+ initializer := func(conn net.Conn) (shared.EthereumApi, error) {
+ fe := useragent.NewRemoteFrontend(conn, eth.AccountManager())
+ xeth := xeth.New(eth, fe)
+ codec := codec.JSON
- apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec, xeth, eth)
- if err != nil {
- return err
+ apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec, xeth, eth)
+ if err != nil {
+ return nil, err
+ }
+
+ return api.Merge(apis...), nil
}
- return comms.StartIpc(config, codec, api.Merge(apis...))
+ return comms.StartIpc(config, codec.JSON, initializer)
}
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) error {
diff --git a/core/bench_test.go b/core/bench_test.go
index 67ba15970..baae8a7a5 100644
--- a/core/bench_test.go
+++ b/core/bench_test.go
@@ -168,8 +168,8 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
// Time the insertion of the new chain.
// State and blocks are stored in the same DB.
evmux := new(event.TypeMux)
- chainman, _ := NewChainManager(db, db, db, FakePow{}, evmux)
- chainman.SetProcessor(NewBlockProcessor(db, db, FakePow{}, chainman, evmux))
+ chainman, _ := NewChainManager(db, FakePow{}, evmux)
+ chainman.SetProcessor(NewBlockProcessor(db, FakePow{}, chainman, evmux))
defer chainman.Stop()
b.ReportAllocs()
b.ResetTimer()
diff --git a/core/block_processor.go b/core/block_processor.go
index 6ed1bc8ef..829e4314c 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -41,8 +41,7 @@ const (
)
type BlockProcessor struct {
- db common.Database
- extraDb common.Database
+ chainDb common.Database
// Mutex for locking the block processor. Blocks can only be handled one at a time
mutex sync.Mutex
// Canonical block chain
@@ -57,10 +56,9 @@ type BlockProcessor struct {
eventMux *event.TypeMux
}
-func NewBlockProcessor(db, extra common.Database, pow pow.PoW, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
+func NewBlockProcessor(db common.Database, pow pow.PoW, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
sm := &BlockProcessor{
- db: db,
- extraDb: extra,
+ chainDb: db,
mem: make(map[string]*big.Int),
Pow: pow,
bc: chainManager,
@@ -199,7 +197,7 @@ func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, receipts
func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, receipts types.Receipts, err error) {
// Create a new state based on the parent's root (e.g., create copy)
- state := state.New(parent.Root(), sm.db)
+ state := state.New(parent.Root(), sm.chainDb)
header := block.Header()
uncles := block.Uncles()
txs := block.Transactions()
@@ -340,7 +338,7 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
// GetBlockReceipts returns the receipts beloniging to the block hash
func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts {
if block := sm.ChainManager().GetBlock(bhash); block != nil {
- return GetBlockReceipts(sm.extraDb, block.Hash())
+ return GetBlockReceipts(sm.chainDb, block.Hash())
}
return nil
@@ -350,24 +348,14 @@ func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts {
// where it tries to get it from the (updated) method which gets them from the receipts or
// the depricated way by re-processing the block.
func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
- receipts := GetBlockReceipts(sm.extraDb, block.Hash())
+ receipts := GetBlockReceipts(sm.chainDb, block.Hash())
if len(receipts) > 0 {
// coalesce logs
for _, receipt := range receipts {
logs = append(logs, receipt.Logs()...)
}
- return
}
-
- // TODO: remove backward compatibility
- var (
- parent = sm.bc.GetBlock(block.ParentHash())
- state = state.New(parent.Root(), sm.db)
- )
-
- sm.TransitionState(state, parent, block, true)
-
- return state.Logs(), nil
+ return logs, nil
}
// See YP section 4.3.4. "Block Header Validity"
diff --git a/core/block_processor_test.go b/core/block_processor_test.go
index f48ce9607..4525f417b 100644
--- a/core/block_processor_test.go
+++ b/core/block_processor_test.go
@@ -33,19 +33,19 @@ func proc() (*BlockProcessor, *ChainManager) {
db, _ := ethdb.NewMemDatabase()
var mux event.TypeMux
- WriteTestNetGenesisBlock(db, db, 0)
- chainMan, err := NewChainManager(db, db, db, thePow(), &mux)
+ WriteTestNetGenesisBlock(db, 0)
+ chainMan, err := NewChainManager(db, thePow(), &mux)
if err != nil {
fmt.Println(err)
}
- return NewBlockProcessor(db, db, ezp.New(), chainMan, &mux), chainMan
+ return NewBlockProcessor(db, ezp.New(), chainMan, &mux), chainMan
}
func TestNumber(t *testing.T) {
pow := ezp.New()
_, chain := proc()
- statedb := state.New(chain.Genesis().Root(), chain.stateDb)
+ statedb := state.New(chain.Genesis().Root(), chain.chainDb)
header := makeHeader(chain.Genesis(), statedb)
header.Number = big.NewInt(3)
err := ValidateHeader(pow, header, chain.Genesis(), false)
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 85a6175dc..0bb1df95a 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -184,9 +184,9 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
func newCanonical(n int, db common.Database) (*BlockProcessor, error) {
evmux := &event.TypeMux{}
- WriteTestNetGenesisBlock(db, db, 0)
- chainman, _ := NewChainManager(db, db, db, FakePow{}, evmux)
- bman := NewBlockProcessor(db, db, FakePow{}, chainman, evmux)
+ WriteTestNetGenesisBlock(db, 0)
+ chainman, _ := NewChainManager(db, FakePow{}, evmux)
+ bman := NewBlockProcessor(db, FakePow{}, chainman, evmux)
bman.bc.SetProcessor(bman)
parent := bman.bc.CurrentBlock()
if n == 0 {
diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go
index 98a585f9b..1c868624d 100644
--- a/core/chain_makers_test.go
+++ b/core/chain_makers_test.go
@@ -77,8 +77,8 @@ func ExampleGenerateChain() {
// Import the chain. This runs all block validation rules.
evmux := &event.TypeMux{}
- chainman, _ := NewChainManager(db, db, db, FakePow{}, evmux)
- chainman.SetProcessor(NewBlockProcessor(db, db, FakePow{}, chainman, evmux))
+ chainman, _ := NewChainManager(db, FakePow{}, evmux)
+ chainman.SetProcessor(NewBlockProcessor(db, FakePow{}, chainman, evmux))
if i, err := chainman.InsertChain(chain); err != nil {
fmt.Printf("insert error (block %d): %v\n", i, err)
return
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 1b792933c..1647031b1 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -56,9 +56,7 @@ const (
type ChainManager struct {
//eth EthManager
- blockDb common.Database
- stateDb common.Database
- extraDb common.Database
+ chainDb common.Database
processor types.BlockProcessor
eventMux *event.TypeMux
genesisBlock *types.Block
@@ -85,12 +83,10 @@ type ChainManager struct {
pow pow.PoW
}
-func NewChainManager(blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux *event.TypeMux) (*ChainManager, error) {
+func NewChainManager(chainDb common.Database, pow pow.PoW, mux *event.TypeMux) (*ChainManager, error) {
cache, _ := lru.New(blockCacheLimit)
bc := &ChainManager{
- blockDb: blockDb,
- stateDb: stateDb,
- extraDb: extraDb,
+ chainDb: chainDb,
eventMux: mux,
quit: make(chan struct{}),
cache: cache,
@@ -103,7 +99,7 @@ func NewChainManager(blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux
if err != nil {
return nil, err
}
- bc.genesisBlock, err = WriteGenesisBlock(stateDb, blockDb, reader)
+ bc.genesisBlock, err = WriteGenesisBlock(chainDb, reader)
if err != nil {
return nil, err
}
@@ -195,15 +191,15 @@ func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
}
func (self *ChainManager) State() *state.StateDB {
- return state.New(self.CurrentBlock().Root(), self.stateDb)
+ return state.New(self.CurrentBlock().Root(), self.chainDb)
}
func (bc *ChainManager) recover() bool {
- data, _ := bc.blockDb.Get([]byte("checkpoint"))
+ data, _ := bc.chainDb.Get([]byte("checkpoint"))
if len(data) != 0 {
block := bc.GetBlock(common.BytesToHash(data))
if block != nil {
- err := bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes())
+ err := bc.chainDb.Put([]byte("LastBlock"), block.Hash().Bytes())
if err != nil {
glog.Fatalln("db write err:", err)
}
@@ -217,7 +213,7 @@ func (bc *ChainManager) recover() bool {
}
func (bc *ChainManager) setLastState() error {
- data, _ := bc.blockDb.Get([]byte("LastBlock"))
+ data, _ := bc.chainDb.Get([]byte("LastBlock"))
if len(data) != 0 {
block := bc.GetBlock(common.BytesToHash(data))
if block != nil {
@@ -264,7 +260,7 @@ func (bc *ChainManager) Reset() {
bc.cache, _ = lru.New(blockCacheLimit)
// Prepare the genesis block
- err := WriteBlock(bc.blockDb, bc.genesisBlock)
+ err := WriteBlock(bc.chainDb, bc.genesisBlock)
if err != nil {
glog.Fatalln("db err:", err)
}
@@ -277,7 +273,7 @@ func (bc *ChainManager) Reset() {
}
func (bc *ChainManager) removeBlock(block *types.Block) {
- bc.blockDb.Delete(append(blockHashPre, block.Hash().Bytes()...))
+ bc.chainDb.Delete(append(blockHashPre, block.Hash().Bytes()...))
}
func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
@@ -292,7 +288,7 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
gb.Td = gb.Difficulty()
bc.genesisBlock = gb
- err := WriteBlock(bc.blockDb, bc.genesisBlock)
+ err := WriteBlock(bc.chainDb, bc.genesisBlock)
if err != nil {
glog.Fatalln("db err:", err)
}
@@ -339,14 +335,14 @@ func (self *ChainManager) ExportN(w io.Writer, first uint64, last uint64) error
// insert injects a block into the current chain block chain. Note, this function
// assumes that the `mu` mutex is held!
func (bc *ChainManager) insert(block *types.Block) {
- err := WriteHead(bc.blockDb, block)
+ err := WriteHead(bc.chainDb, block)
if err != nil {
glog.Fatal("db write fail:", err)
}
bc.checkpoint++
if bc.checkpoint > checkpointLimit {
- err = bc.blockDb.Put([]byte("checkpoint"), block.Hash().Bytes())
+ err = bc.chainDb.Put([]byte("checkpoint"), block.Hash().Bytes())
if err != nil {
glog.Fatal("db write fail:", err)
}
@@ -369,7 +365,7 @@ func (bc *ChainManager) HasBlock(hash common.Hash) bool {
return true
}
- data, _ := bc.blockDb.Get(append(blockHashPre, hash[:]...))
+ data, _ := bc.chainDb.Get(append(blockHashPre, hash[:]...))
return len(data) != 0
}
@@ -399,7 +395,7 @@ func (self *ChainManager) GetBlock(hash common.Hash) *types.Block {
return block.(*types.Block)
}
- block := GetBlockByHash(self.blockDb, hash)
+ block := GetBlockByHash(self.chainDb, hash)
if block == nil {
return nil
}
@@ -433,7 +429,7 @@ func (self *ChainManager) GetBlocksFromHash(hash common.Hash, n int) (blocks []*
// non blocking version
func (self *ChainManager) getBlockByNumber(num uint64) *types.Block {
- return GetBlockByNumber(self.blockDb, num)
+ return GetBlockByNumber(self.chainDb, num)
}
func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) {
@@ -521,7 +517,7 @@ func (self *ChainManager) WriteBlock(block *types.Block, queued bool) (status wr
status = SideStatTy
}
- err = WriteBlock(self.blockDb, block)
+ err = WriteBlock(self.chainDb, block)
if err != nil {
glog.Fatalln("db err:", err)
}
@@ -638,9 +634,9 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
queueEvent.canonicalCount++
// This puts transactions in a extra db for rpc
- PutTransactions(self.extraDb, block, block.Transactions())
+ PutTransactions(self.chainDb, block, block.Transactions())
// store the receipts
- PutReceipts(self.extraDb, receipts)
+ PutReceipts(self.chainDb, receipts)
case SideStatTy:
if glog.V(logger.Detail) {
glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
@@ -651,7 +647,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
queue[i] = ChainSplitEvent{block, logs}
queueEvent.splitCount++
}
- PutBlockReceipts(self.extraDb, block, receipts)
+ PutBlockReceipts(self.chainDb, block, receipts)
stats.processed++
}
@@ -733,8 +729,8 @@ func (self *ChainManager) merge(oldBlock, newBlock *types.Block) error {
// insert the block in the canonical way, re-writing history
self.insert(block)
// write canonical receipts and transactions
- PutTransactions(self.extraDb, block, block.Transactions())
- PutReceipts(self.extraDb, GetBlockReceipts(self.extraDb, block.Hash()))
+ PutTransactions(self.chainDb, block, block.Transactions())
+ PutReceipts(self.chainDb, GetBlockReceipts(self.chainDb, block.Hash()))
}
self.mu.Unlock()
diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go
index f0c097df6..002dcbe44 100644
--- a/core/chain_manager_test.go
+++ b/core/chain_manager_test.go
@@ -48,14 +48,14 @@ func thePow() pow.PoW {
func theChainManager(db common.Database, t *testing.T) *ChainManager {
var eventMux event.TypeMux
- WriteTestNetGenesisBlock(db, db, 0)
- chainMan, err := NewChainManager(db, db, db, thePow(), &eventMux)
+ WriteTestNetGenesisBlock(db, 0)
+ chainMan, err := NewChainManager(db, thePow(), &eventMux)
if err != nil {
t.Error("failed creating chainmanager:", err)
t.FailNow()
return nil
}
- blockMan := NewBlockProcessor(db, db, nil, chainMan, &eventMux)
+ blockMan := NewBlockProcessor(db, nil, chainMan, &eventMux)
chainMan.SetProcessor(blockMan)
return chainMan
@@ -125,7 +125,7 @@ func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
bman.bc.mu.Lock()
{
- WriteBlock(bman.bc.blockDb, block)
+ WriteBlock(bman.bc.chainDb, block)
}
bman.bc.mu.Unlock()
}
@@ -387,7 +387,7 @@ func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block
func chm(genesis *types.Block, db common.Database) *ChainManager {
var eventMux event.TypeMux
- bc := &ChainManager{extraDb: db, blockDb: db, stateDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: FakePow{}}
+ bc := &ChainManager{chainDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: FakePow{}}
bc.cache, _ = lru.New(100)
bc.futureBlocks, _ = lru.New(100)
bc.processor = bproc{}
@@ -399,7 +399,7 @@ func chm(genesis *types.Block, db common.Database) *ChainManager {
func TestReorgLongest(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
- genesis, err := WriteTestNetGenesisBlock(db, db, 0)
+ genesis, err := WriteTestNetGenesisBlock(db, 0)
if err != nil {
t.Error(err)
t.FailNow()
@@ -422,7 +422,7 @@ func TestReorgLongest(t *testing.T) {
func TestReorgShortest(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
- genesis, err := WriteTestNetGenesisBlock(db, db, 0)
+ genesis, err := WriteTestNetGenesisBlock(db, 0)
if err != nil {
t.Error(err)
t.FailNow()
@@ -446,13 +446,13 @@ func TestReorgShortest(t *testing.T) {
func TestInsertNonceError(t *testing.T) {
for i := 1; i < 25 && !t.Failed(); i++ {
db, _ := ethdb.NewMemDatabase()
- genesis, err := WriteTestNetGenesisBlock(db, db, 0)
+ genesis, err := WriteTestNetGenesisBlock(db, 0)
if err != nil {
t.Error(err)
t.FailNow()
}
bc := chm(genesis, db)
- bc.processor = NewBlockProcessor(db, db, bc.pow, bc, bc.eventMux)
+ bc.processor = NewBlockProcessor(db, bc.pow, bc, bc.eventMux)
blocks := makeChain(bc.currentBlock, i, db, 0)
fail := rand.Int() % len(blocks)
diff --git a/core/chain_util.go b/core/chain_util.go
index 34f6c8d0a..84b462ce3 100644
--- a/core/chain_util.go
+++ b/core/chain_util.go
@@ -32,7 +32,7 @@ import (
var (
blockHashPre = []byte("block-hash-")
blockNumPre = []byte("block-num-")
- expDiffPeriod = big.NewInt(100000)
+ ExpDiffPeriod = big.NewInt(100000)
)
// CalcDifficulty is the difficulty adjustment algorithm. It returns
@@ -57,7 +57,7 @@ func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int)
}
periodCount := new(big.Int).Add(parentNumber, common.Big1)
- periodCount.Div(periodCount, expDiffPeriod)
+ periodCount.Div(periodCount, ExpDiffPeriod)
if periodCount.Cmp(common.Big1) > 0 {
// diff = diff + 2^(periodCount - 2)
expDiff := periodCount.Sub(periodCount, common.Big2)
diff --git a/core/genesis.go b/core/genesis.go
index 4c0323c17..97afb3a4a 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -33,7 +33,7 @@ import (
)
// WriteGenesisBlock writes the genesis block to the database as block number 0
-func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*types.Block, error) {
+func WriteGenesisBlock(chainDb common.Database, reader io.Reader) (*types.Block, error) {
contents, err := ioutil.ReadAll(reader)
if err != nil {
return nil, err
@@ -59,7 +59,7 @@ func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*typ
return nil, err
}
- statedb := state.New(common.Hash{}, stateDb)
+ statedb := state.New(common.Hash{}, chainDb)
for addr, account := range genesis.Alloc {
address := common.HexToAddress(addr)
statedb.AddBalance(address, common.String2Big(account.Balance))
@@ -84,9 +84,9 @@ func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*typ
}, nil, nil, nil)
block.Td = difficulty
- if block := GetBlockByHash(blockDb, block.Hash()); block != nil {
+ if block := GetBlockByHash(chainDb, block.Hash()); block != nil {
glog.V(logger.Info).Infoln("Genesis block already in chain. Writing canonical number")
- err := WriteCanonNumber(blockDb, block)
+ err := WriteCanonNumber(chainDb, block)
if err != nil {
return nil, err
}
@@ -95,11 +95,11 @@ func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*typ
statedb.Sync()
- err = WriteBlock(blockDb, block)
+ err = WriteBlock(chainDb, block)
if err != nil {
return nil, err
}
- err = WriteHead(blockDb, block)
+ err = WriteHead(chainDb, block)
if err != nil {
return nil, err
}
@@ -133,11 +133,11 @@ func WriteGenesisBlockForTesting(db common.Database, addr common.Address, balanc
"0x%x":{"balance":"0x%x"}
}
}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), addr, balance.Bytes())
- block, _ := WriteGenesisBlock(db, db, strings.NewReader(testGenesis))
+ block, _ := WriteGenesisBlock(db, strings.NewReader(testGenesis))
return block
}
-func WriteTestNetGenesisBlock(stateDb, blockDb common.Database, nonce uint64) (*types.Block, error) {
+func WriteTestNetGenesisBlock(chainDb common.Database, nonce uint64) (*types.Block, error) {
testGenesis := fmt.Sprintf(`{
"nonce":"0x%x",
"gasLimit":"0x%x",
@@ -157,5 +157,5 @@ func WriteTestNetGenesisBlock(stateDb, blockDb common.Database, nonce uint64) (*
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
}
}`, types.EncodeNonce(nonce), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes())
- return WriteGenesisBlock(stateDb, blockDb, strings.NewReader(testGenesis))
+ return WriteGenesisBlock(chainDb, strings.NewReader(testGenesis))
}
diff --git a/core/manager.go b/core/manager.go
index a07c32659..8b0401b03 100644
--- a/core/manager.go
+++ b/core/manager.go
@@ -28,8 +28,7 @@ type Backend interface {
BlockProcessor() *BlockProcessor
ChainManager() *ChainManager
TxPool() *TxPool
- BlockDb() common.Database
- StateDb() common.Database
- ExtraDb() common.Database
+ ChainDb() common.Database
+ DappDb() common.Database
EventMux() *event.TypeMux
}
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 6b7b41220..2de35a443 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -341,19 +341,19 @@ func opCoinbase(instr instruction, env Environment, context *Context, memory *Me
}
func opTimestamp(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
- stack.push(new(big.Int).SetUint64(env.Time()))
+ stack.push(U256(new(big.Int).SetUint64(env.Time())))
}
func opNumber(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
- stack.push(U256(env.BlockNumber()))
+ stack.push(U256(new(big.Int).Set(env.BlockNumber())))
}
func opDifficulty(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
- stack.push(new(big.Int).Set(env.Difficulty()))
+ stack.push(U256(new(big.Int).Set(env.Difficulty())))
}
func opGasLimit(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
- stack.push(new(big.Int).Set(env.GasLimit()))
+ stack.push(U256(new(big.Int).Set(env.GasLimit())))
}
func opPop(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
@@ -415,15 +415,12 @@ func opSstore(instr instruction, env Environment, context *Context, memory *Memo
env.State().SetState(context.Address(), loc, common.BigToHash(val))
}
-func opJump(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
-}
-func opJumpi(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
-}
-func opJumpdest(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
-}
+func opJump(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {}
+func opJumpi(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {}
+func opJumpdest(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {}
func opPc(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
- stack.push(instr.data)
+ stack.push(new(big.Int).Set(instr.data))
}
func opMsize(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
diff --git a/core/vm/jit.go b/core/vm/jit.go
index d5c2d7830..084d2a3f3 100644
--- a/core/vm/jit.go
+++ b/core/vm/jit.go
@@ -83,6 +83,7 @@ type Program struct {
code []byte
}
+// NewProgram returns a new JIT program
func NewProgram(code []byte) *Program {
program := &Program{
Id: crypto.Sha3Hash(code),
@@ -113,6 +114,7 @@ func (p *Program) addInstr(op OpCode, pc uint64, fn instrFn, data *big.Int) {
p.mapping[pc] = len(p.instructions) - 1
}
+// CompileProgram compiles the given program and return an error when it fails
func CompileProgram(program *Program) (err error) {
if progStatus(atomic.LoadInt32(&program.status)) == progCompile {
return nil
@@ -272,6 +274,8 @@ func CompileProgram(program *Program) (err error) {
return nil
}
+// RunProgram runs the program given the enviroment and context and returns an
+// error if the execution failed (non-consensus)
func RunProgram(program *Program, env Environment, context *Context, input []byte) ([]byte, error) {
return runProgram(program, 0, NewMemory(), newstack(), env, context, input)
}
@@ -352,6 +356,8 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env
pc++
}
+ context.Input = nil
+
return context.Return(nil), nil
}
diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go
index 5b3feea99..b9e2c6999 100644
--- a/core/vm/jit_test.go
+++ b/core/vm/jit_test.go
@@ -46,7 +46,7 @@ func runVmBench(test vmBench, b *testing.B) {
}
env := NewEnv()
- DisableJit = test.nojit
+ EnableJit = !test.nojit
ForceJit = test.forcejit
b.ResetTimer()
diff --git a/core/vm/settings.go b/core/vm/settings.go
index 0cd931b6a..f9296f6c8 100644
--- a/core/vm/settings.go
+++ b/core/vm/settings.go
@@ -17,9 +17,9 @@
package vm
var (
- DisableJit bool = true // Disable the JIT VM
- ForceJit bool // Force the JIT, skip byte VM
- MaxProgSize int // Max cache size for JIT Programs
+ EnableJit bool // Enables the JIT VM
+ ForceJit bool // Force the JIT, skip byte VM
+ MaxProgSize int // Max cache size for JIT Programs
)
const defaultJitMaxCache int = 64
diff --git a/core/vm/vm.go b/core/vm/vm.go
index c292b45d1..da764004a 100644
--- a/core/vm/vm.go
+++ b/core/vm/vm.go
@@ -64,7 +64,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
codehash = crypto.Sha3Hash(context.Code) // codehash is used when doing jump dest caching
program *Program
)
- if !DisableJit {
+ if EnableJit {
// Fetch program status.
// * If ready run using JIT
// * If unknown, compile in a seperate goroutine
diff --git a/eth/backend.go b/eth/backend.go
index ed46a4ab3..2b21a7c96 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -61,10 +61,11 @@ var (
defaultBootNodes = []*discover.Node{
// ETH/DEV Go Bootnodes
- discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"),
- discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"),
+ discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE
+ discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR
+ discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG
// ETH/DEV cpp-ethereum (poc-9.ethdev.com)
- discover.MustParseNode("enode://487611428e6c99a11a9795a6abe7b529e81315ca6aad66e2a2fc76e3adf263faba0d35466c2f8f68d561dbefa8878d4df5f1f2ddb1fbeab7f42ffb8cd328bd4a@5.1.83.226:30303"),
+ discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"),
}
staticNodes = "static-nodes.json" // Path within <datadir> to search for the static node list
@@ -206,9 +207,8 @@ type Ethereum struct {
shutdownChan chan bool
// DB interfaces
- blockDb common.Database // Block chain database
- stateDb common.Database // State changes database
- extraDb common.Database // Extra database (txs, etc)
+ chainDb common.Database // Block chain databe
+ dappDb common.Database // Dapp database
// Closed when databases are flushed and closed
databasesClosed chan bool
@@ -266,27 +266,27 @@ func New(config *Config) (*Ethereum, error) {
if newdb == nil {
newdb = func(path string) (common.Database, error) { return ethdb.NewLDBDatabase(path, config.DatabaseCache) }
}
- blockDb, err := newdb(filepath.Join(config.DataDir, "blockchain"))
- if err != nil {
- return nil, fmt.Errorf("blockchain db err: %v", err)
- }
- if db, ok := blockDb.(*ethdb.LDBDatabase); ok {
- db.Meter("eth/db/block/")
+
+ // attempt to merge database together, upgrading from an old version
+ if err := mergeDatabases(config.DataDir, newdb); err != nil {
+ return nil, err
}
- stateDb, err := newdb(filepath.Join(config.DataDir, "state"))
+
+ chainDb, err := newdb(filepath.Join(config.DataDir, "chaindata"))
if err != nil {
- return nil, fmt.Errorf("state db err: %v", err)
+ return nil, fmt.Errorf("blockchain db err: %v", err)
}
- if db, ok := stateDb.(*ethdb.LDBDatabase); ok {
- db.Meter("eth/db/state/")
+ if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
+ db.Meter("eth/db/chaindata/")
}
- extraDb, err := newdb(filepath.Join(config.DataDir, "extra"))
+ dappDb, err := newdb(filepath.Join(config.DataDir, "dapp"))
if err != nil {
- return nil, fmt.Errorf("extra db err: %v", err)
+ return nil, fmt.Errorf("dapp db err: %v", err)
}
- if db, ok := extraDb.(*ethdb.LDBDatabase); ok {
- db.Meter("eth/db/extra/")
+ if db, ok := dappDb.(*ethdb.LDBDatabase); ok {
+ db.Meter("eth/db/dapp/")
}
+
nodeDb := filepath.Join(config.DataDir, "nodes")
glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId)
@@ -296,7 +296,7 @@ func New(config *Config) (*Ethereum, error) {
return nil, err
}
- block, err := core.WriteGenesisBlock(stateDb, blockDb, fr)
+ block, err := core.WriteGenesisBlock(chainDb, fr)
if err != nil {
return nil, err
}
@@ -304,7 +304,7 @@ func New(config *Config) (*Ethereum, error) {
}
if config.Olympic {
- _, err := core.WriteTestNetGenesisBlock(stateDb, blockDb, 42)
+ _, err := core.WriteTestNetGenesisBlock(chainDb, 42)
if err != nil {
return nil, err
}
@@ -313,26 +313,25 @@ func New(config *Config) (*Ethereum, error) {
// This is for testing only.
if config.GenesisBlock != nil {
- core.WriteBlock(blockDb, config.GenesisBlock)
- core.WriteHead(blockDb, config.GenesisBlock)
+ core.WriteBlock(chainDb, config.GenesisBlock)
+ core.WriteHead(chainDb, config.GenesisBlock)
}
if !config.SkipBcVersionCheck {
- b, _ := blockDb.Get([]byte("BlockchainVersion"))
+ b, _ := chainDb.Get([]byte("BlockchainVersion"))
bcVersion := int(common.NewValue(b).Uint())
if bcVersion != config.BlockChainVersion && bcVersion != 0 {
return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, config.BlockChainVersion)
}
- saveBlockchainVersion(blockDb, config.BlockChainVersion)
+ saveBlockchainVersion(chainDb, config.BlockChainVersion)
}
glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion)
eth := &Ethereum{
shutdownChan: make(chan bool),
databasesClosed: make(chan bool),
- blockDb: blockDb,
- stateDb: stateDb,
- extraDb: extraDb,
+ chainDb: chainDb,
+ dappDb: dappDb,
eventMux: &event.TypeMux{},
accountManager: config.AccountManager,
DataDir: config.DataDir,
@@ -362,7 +361,7 @@ func New(config *Config) (*Ethereum, error) {
eth.pow = ethash.New()
}
//genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb)
- eth.chainManager, err = core.NewChainManager(blockDb, stateDb, extraDb, eth.pow, eth.EventMux())
+ eth.chainManager, err = core.NewChainManager(chainDb, eth.pow, eth.EventMux())
if err != nil {
if err == core.ErrNoGenesis {
return nil, fmt.Errorf(`Genesis block not found. Please supply a genesis block with the "--genesis /path/to/file" argument`)
@@ -372,7 +371,7 @@ func New(config *Config) (*Ethereum, error) {
}
eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit)
- eth.blockProcessor = core.NewBlockProcessor(stateDb, extraDb, eth.pow, eth.chainManager, eth.EventMux())
+ eth.blockProcessor = core.NewBlockProcessor(chainDb, eth.pow, eth.chainManager, eth.EventMux())
eth.chainManager.SetProcessor(eth.blockProcessor)
eth.protocolManager = NewProtocolManager(config.NetworkId, eth.eventMux, eth.txPool, eth.pow, eth.chainManager)
@@ -520,9 +519,8 @@ func (s *Ethereum) BlockProcessor() *core.BlockProcessor { return s.blockProcess
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
func (s *Ethereum) Whisper() *whisper.Whisper { return s.whisper }
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
-func (s *Ethereum) BlockDb() common.Database { return s.blockDb }
-func (s *Ethereum) StateDb() common.Database { return s.stateDb }
-func (s *Ethereum) ExtraDb() common.Database { return s.extraDb }
+func (s *Ethereum) ChainDb() common.Database { return s.chainDb }
+func (s *Ethereum) DappDb() common.Database { return s.dappDb }
func (s *Ethereum) IsListening() bool { return true } // Always listening
func (s *Ethereum) PeerCount() int { return s.net.PeerCount() }
func (s *Ethereum) Peers() []*p2p.Peer { return s.net.Peers() }
@@ -569,23 +567,19 @@ done:
select {
case <-ticker.C:
// don't change the order of database flushes
- if err := s.extraDb.Flush(); err != nil {
- glog.Fatalf("fatal error: flush extraDb: %v (Restart your node. We are aware of this issue)\n", err)
+ if err := s.dappDb.Flush(); err != nil {
+ glog.Fatalf("fatal error: flush dappDb: %v (Restart your node. We are aware of this issue)\n", err)
}
- if err := s.stateDb.Flush(); err != nil {
- glog.Fatalf("fatal error: flush stateDb: %v (Restart your node. We are aware of this issue)\n", err)
- }
- if err := s.blockDb.Flush(); err != nil {
- glog.Fatalf("fatal error: flush blockDb: %v (Restart your node. We are aware of this issue)\n", err)
+ if err := s.chainDb.Flush(); err != nil {
+ glog.Fatalf("fatal error: flush chainDb: %v (Restart your node. We are aware of this issue)\n", err)
}
case <-s.shutdownChan:
break done
}
}
- s.blockDb.Close()
- s.stateDb.Close()
- s.extraDb.Close()
+ s.chainDb.Close()
+ s.dappDb.Close()
close(s.databasesClosed)
}
@@ -683,14 +677,6 @@ func (self *Ethereum) StartAutoDAG() {
}()
}
-// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
-// 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])>
-func dagFiles(epoch uint64) (string, string) {
- seedHash, _ := ethash.GetSeedHash(epoch * epochLength)
- dag := fmt.Sprintf("full-R%d-%x", ethashRevision, seedHash[:8])
- return dag, "full-R" + dag
-}
-
// stopAutoDAG stops automatic DAG pregeneration by quitting the loop
func (self *Ethereum) StopAutoDAG() {
if self.autodagquit != nil {
@@ -700,20 +686,28 @@ func (self *Ethereum) StopAutoDAG() {
glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG OFF (ethash dir: %s)", ethash.DefaultDir)
}
-/*
- // The databases were previously tied to protocol versions. Currently we
- // are moving away from this decision as approaching Frontier. The below
- // code was left in for now but should eventually be just dropped.
+func (self *Ethereum) Solc() (*compiler.Solidity, error) {
+ var err error
+ if self.solc == nil {
+ self.solc, err = compiler.New(self.SolcPath)
+ }
+ return self.solc, err
+}
- func saveProtocolVersion(db common.Database, protov int) {
- d, _ := db.Get([]byte("ProtocolVersion"))
- protocolVersion := common.NewValue(d).Uint()
+// set in js console via admin interface or wrapper from cli flags
+func (self *Ethereum) SetSolc(solcPath string) (*compiler.Solidity, error) {
+ self.SolcPath = solcPath
+ self.solc = nil
+ return self.Solc()
+}
- if protocolVersion == 0 {
- db.Put([]byte("ProtocolVersion"), common.NewValue(protov).Bytes())
- }
- }
-*/
+// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
+// 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])>
+func dagFiles(epoch uint64) (string, string) {
+ seedHash, _ := ethash.GetSeedHash(epoch * epochLength)
+ dag := fmt.Sprintf("full-R%d-%x", ethashRevision, seedHash[:8])
+ return dag, "full-R" + dag
+}
func saveBlockchainVersion(db common.Database, bcVersion int) {
d, _ := db.Get([]byte("BlockchainVersion"))
@@ -724,17 +718,74 @@ func saveBlockchainVersion(db common.Database, bcVersion int) {
}
}
-func (self *Ethereum) Solc() (*compiler.Solidity, error) {
- var err error
- if self.solc == nil {
- self.solc, err = compiler.New(self.SolcPath)
+// mergeDatabases when required merge old database layout to one single database
+func mergeDatabases(datadir string, newdb func(path string) (common.Database, error)) error {
+ // Check if already upgraded
+ data := filepath.Join(datadir, "chaindata")
+ if _, err := os.Stat(data); !os.IsNotExist(err) {
+ return nil
}
- return self.solc, err
-}
+ // make sure it's not just a clean path
+ chainPath := filepath.Join(datadir, "blockchain")
+ if _, err := os.Stat(chainPath); os.IsNotExist(err) {
+ return nil
+ }
+ glog.Infoln("Database upgrade required. Upgrading...")
-// set in js console via admin interface or wrapper from cli flags
-func (self *Ethereum) SetSolc(solcPath string) (*compiler.Solidity, error) {
- self.SolcPath = solcPath
- self.solc = nil
- return self.Solc()
+ database, err := newdb(data)
+ if err != nil {
+ return fmt.Errorf("creating data db err: %v", err)
+ }
+ defer database.Close()
+
+ // Migrate blocks
+ chainDb, err := newdb(chainPath)
+ if err != nil {
+ return fmt.Errorf("state db err: %v", err)
+ }
+ defer chainDb.Close()
+
+ if chain, ok := chainDb.(*ethdb.LDBDatabase); ok {
+ glog.Infoln("Merging blockchain database...")
+ it := chain.NewIterator()
+ for it.Next() {
+ database.Put(it.Key(), it.Value())
+ }
+ it.Release()
+ }
+
+ // Migrate state
+ stateDb, err := newdb(filepath.Join(datadir, "state"))
+ if err != nil {
+ return fmt.Errorf("state db err: %v", err)
+ }
+ defer stateDb.Close()
+
+ if state, ok := stateDb.(*ethdb.LDBDatabase); ok {
+ glog.Infoln("Merging state database...")
+ it := state.NewIterator()
+ for it.Next() {
+ database.Put(it.Key(), it.Value())
+ }
+ it.Release()
+ }
+
+ // Migrate transaction / receipts
+ extraDb, err := newdb(filepath.Join(datadir, "extra"))
+ if err != nil {
+ return fmt.Errorf("state db err: %v", err)
+ }
+ defer extraDb.Close()
+
+ if extra, ok := extraDb.(*ethdb.LDBDatabase); ok {
+ glog.Infoln("Merging transaction database...")
+
+ it := extra.NewIterator()
+ for it.Next() {
+ database.Put(it.Key(), it.Value())
+ }
+ it.Release()
+ }
+
+ return nil
}
diff --git a/eth/protocol_test.go b/eth/protocol_test.go
index a24d98f69..08c9b6a06 100644
--- a/eth/protocol_test.go
+++ b/eth/protocol_test.go
@@ -179,10 +179,10 @@ type testPeer struct {
func newProtocolManagerForTesting(txAdded chan<- []*types.Transaction) *ProtocolManager {
db, _ := ethdb.NewMemDatabase()
- core.WriteTestNetGenesisBlock(db, db, 0)
+ core.WriteTestNetGenesisBlock(db, 0)
var (
em = new(event.TypeMux)
- chain, _ = core.NewChainManager(db, db, db, core.FakePow{}, em)
+ chain, _ = core.NewChainManager(db, core.FakePow{}, em)
txpool = &fakeTxPool{added: txAdded}
pm = NewProtocolManager(NetworkId, em, txpool, core.FakePow{}, chain)
)
diff --git a/ethdb/database.go b/ethdb/database.go
index ace56c6c7..9e80e5409 100644
--- a/ethdb/database.go
+++ b/ethdb/database.go
@@ -39,9 +39,8 @@ var OpenFileLimit = 64
// cacheRatio specifies how the total alloted cache is distributed between the
// various system databases.
var cacheRatio = map[string]float64{
- "blockchain": 1.0 / 13.0,
- "extra": 2.0 / 13.0,
- "state": 10.0 / 13.0,
+ "dapp": 2.0 / 13.0,
+ "chaindata": 11.0 / 13.0,
}
type LDBDatabase struct {
diff --git a/jsre/ethereum_js.go b/jsre/ethereum_js.go
index 012e5af70..f33bb7c25 100644
--- a/jsre/ethereum_js.go
+++ b/jsre/ethereum_js.go
@@ -18,6 +18,622 @@ package jsre
const Web3_JS = `
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+module.exports=[
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_owner",
+ "type": "address"
+ }
+ ],
+ "name": "name",
+ "outputs": [
+ {
+ "name": "o_name",
+ "type": "bytes32"
+ }
+ ],
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "owner",
+ "outputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "content",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "addr",
+ "outputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "reserve",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "subRegistrar",
+ "outputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ },
+ {
+ "name": "_newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ },
+ {
+ "name": "_registrar",
+ "type": "address"
+ }
+ ],
+ "name": "setSubRegistrar",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [],
+ "name": "Registrar",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ },
+ {
+ "name": "_a",
+ "type": "address"
+ },
+ {
+ "name": "_primary",
+ "type": "bool"
+ }
+ ],
+ "name": "setAddress",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ },
+ {
+ "name": "_content",
+ "type": "bytes32"
+ }
+ ],
+ "name": "setContent",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "disown",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "_name",
+ "type": "bytes32"
+ },
+ {
+ "indexed": false,
+ "name": "_winner",
+ "type": "address"
+ }
+ ],
+ "name": "AuctionEnded",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "_name",
+ "type": "bytes32"
+ },
+ {
+ "indexed": false,
+ "name": "_bidder",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "NewBid",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "Changed",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "name",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "name": "addr",
+ "type": "address"
+ }
+ ],
+ "name": "PrimaryChanged",
+ "type": "event"
+ }
+]
+},{}],2:[function(require,module,exports){
+module.exports=[
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "owner",
+ "outputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ },
+ {
+ "name": "_refund",
+ "type": "address"
+ }
+ ],
+ "name": "disown",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "addr",
+ "outputs": [
+ {
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "reserve",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ },
+ {
+ "name": "_newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_name",
+ "type": "bytes32"
+ },
+ {
+ "name": "_a",
+ "type": "address"
+ }
+ ],
+ "name": "setAddr",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "name",
+ "type": "bytes32"
+ }
+ ],
+ "name": "Changed",
+ "type": "event"
+ }
+]
+},{}],3:[function(require,module,exports){
+module.exports=[
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "from",
+ "type": "bytes32"
+ },
+ {
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "from",
+ "type": "bytes32"
+ },
+ {
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "name": "indirectId",
+ "type": "bytes32"
+ },
+ {
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "icapTransfer",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "to",
+ "type": "bytes32"
+ }
+ ],
+ "name": "deposit",
+ "outputs": [],
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "AnonymousDeposit",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "to",
+ "type": "bytes32"
+ },
+ {
+ "indexed": false,
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Deposit",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "from",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "from",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "indirectId",
+ "type": "bytes32"
+ },
+ {
+ "indexed": false,
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "IcapTransfer",
+ "type": "event"
+ }
+]
+},{}],4:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
+/**
+ * SolidityTypeAddress is a prootype that represents address type
+ * It matches:
+ * address
+ * address[]
+ * address[4]
+ * address[][]
+ * address[3][]
+ * address[][6][], ...
+ */
+var SolidityTypeAddress = function () {
+ this._inputFormatter = f.formatInputInt;
+ this._outputFormatter = f.formatOutputAddress;
+};
+
+SolidityTypeAddress.prototype = new SolidityType({});
+SolidityTypeAddress.prototype.constructor = SolidityTypeAddress;
+
+SolidityTypeAddress.prototype.isType = function (name) {
+ return !!name.match(/address(\[([0-9]*)\])?/);
+};
+
+SolidityTypeAddress.prototype.staticPartLength = function (name) {
+ return 32 * this.staticArrayLength(name);
+};
+
+module.exports = SolidityTypeAddress;
+
+
+},{"./formatters":9,"./type":14}],5:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
+/**
+ * SolidityTypeBool is a prootype that represents bool type
+ * It matches:
+ * bool
+ * bool[]
+ * bool[4]
+ * bool[][]
+ * bool[3][]
+ * bool[][6][], ...
+ */
+var SolidityTypeBool = function () {
+ this._inputFormatter = f.formatInputBool;
+ this._outputFormatter = f.formatOutputBool;
+};
+
+SolidityTypeBool.prototype = new SolidityType({});
+SolidityTypeBool.prototype.constructor = SolidityTypeBool;
+
+SolidityTypeBool.prototype.isType = function (name) {
+ return !!name.match(/^bool(\[([0-9]*)\])*$/);
+};
+
+SolidityTypeBool.prototype.staticPartLength = function (name) {
+ return 32 * this.staticArrayLength(name);
+};
+
+module.exports = SolidityTypeBool;
+
+},{"./formatters":9,"./type":14}],6:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
+/**
+ * SolidityTypeBytes is a prootype that represents bytes type
+ * It matches:
+ * bytes
+ * bytes[]
+ * bytes[4]
+ * bytes[][]
+ * bytes[3][]
+ * bytes[][6][], ...
+ * bytes32
+ * bytes64[]
+ * bytes8[4]
+ * bytes256[][]
+ * bytes[3][]
+ * bytes64[][6][], ...
+ */
+var SolidityTypeBytes = function () {
+ this._inputFormatter = f.formatInputBytes;
+ this._outputFormatter = f.formatOutputBytes;
+};
+
+SolidityTypeBytes.prototype = new SolidityType({});
+SolidityTypeBytes.prototype.constructor = SolidityTypeBytes;
+
+SolidityTypeBytes.prototype.isType = function (name) {
+ return !!name.match(/^bytes([0-9]{1,})(\[([0-9]*)\])*$/);
+};
+
+SolidityTypeBytes.prototype.staticPartLength = function (name) {
+ var matches = name.match(/^bytes([0-9]*)/);
+ var size = parseInt(matches[1]);
+ return size * this.staticArrayLength(name);
+};
+
+module.exports = SolidityTypeBytes;
+
+},{"./formatters":9,"./type":14}],7:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -40,107 +656,17 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof requ
* @date 2015
*/
-var BigNumber = require('bignumber.js');
-var utils = require('../utils/utils');
var f = require('./formatters');
-var SolidityParam = require('./param');
-
-/**
- * Should be used to check if a type is an array type
- *
- * @method isArrayType
- * @param {String} type
- * @return {Bool} true is the type is an array, otherwise false
- */
-var isArrayType = function (type) {
- return type.slice(-2) === '[]';
-};
-
-/**
- * SolidityType prototype is used to encode/decode solidity params of certain type
- */
-var SolidityType = function (config) {
- this._name = config.name;
- this._match = config.match;
- this._mode = config.mode;
- this._inputFormatter = config.inputFormatter;
- this._outputFormatter = config.outputFormatter;
-};
-
-/**
- * Should be used to determine if this SolidityType do match given type
- *
- * @method isType
- * @param {String} name
- * @return {Bool} true if type match this SolidityType, otherwise false
- */
-SolidityType.prototype.isType = function (name) {
- if (this._match === 'strict') {
- return this._name === name || (name.indexOf(this._name) === 0 && name.slice(this._name.length) === '[]');
- } else if (this._match === 'prefix') {
- // TODO better type detection!
- return name.indexOf(this._name) === 0;
- }
-};
-
-/**
- * Should be used to transform plain param to SolidityParam object
- *
- * @method formatInput
- * @param {Object} param - plain object, or an array of objects
- * @param {Bool} arrayType - true if a param should be encoded as an array
- * @return {SolidityParam} encoded param wrapped in SolidityParam object
- */
-SolidityType.prototype.formatInput = function (param, arrayType) {
- if (utils.isArray(param) && arrayType) { // TODO: should fail if this two are not the same
- var self = this;
- return param.map(function (p) {
- return self._inputFormatter(p);
- }).reduce(function (acc, current) {
- return acc.combine(current);
- }, f.formatInputInt(param.length)).withOffset(32);
- }
- return this._inputFormatter(param);
-};
-/**
- * Should be used to transoform SolidityParam to plain param
- *
- * @method formatOutput
- * @param {SolidityParam} byteArray
- * @param {Bool} arrayType - true if a param should be decoded as an array
- * @return {Object} plain decoded param
- */
-SolidityType.prototype.formatOutput = function (param, arrayType) {
- if (arrayType) {
- // let's assume, that we solidity will never return long arrays :P
- var result = [];
- var length = new BigNumber(param.dynamicPart().slice(0, 64), 16);
- for (var i = 0; i < length * 64; i += 64) {
- result.push(this._outputFormatter(new SolidityParam(param.dynamicPart().substr(i + 64, 64))));
- }
- return result;
- }
- return this._outputFormatter(param);
-};
-
-/**
- * Should be used to slice single param from bytes
- *
- * @method sliceParam
- * @param {String} bytes
- * @param {Number} index of param to slice
- * @param {String} type
- * @returns {SolidityParam} param
- */
-SolidityType.prototype.sliceParam = function (bytes, index, type) {
- if (this._mode === 'bytes') {
- return SolidityParam.decodeBytes(bytes, index);
- } else if (isArrayType(type)) {
- return SolidityParam.decodeArray(bytes, index);
- }
- return SolidityParam.decodeParam(bytes, index);
-};
+var SolidityTypeAddress = require('./address');
+var SolidityTypeBool = require('./bool');
+var SolidityTypeInt = require('./int');
+var SolidityTypeUInt = require('./uint');
+var SolidityTypeDynamicBytes = require('./dynamicbytes');
+var SolidityTypeString = require('./string');
+var SolidityTypeReal = require('./real');
+var SolidityTypeUReal = require('./ureal');
+var SolidityTypeBytes = require('./bytes');
/**
* SolidityCoder prototype should be used to encode/decode solidity params of any type
@@ -170,18 +696,6 @@ SolidityCoder.prototype._requireType = function (type) {
};
/**
- * Should be used to transform plain param of given type to SolidityParam
- *
- * @method _formatInput
- * @param {String} type of param
- * @param {Object} plain param
- * @return {SolidityParam}
- */
-SolidityCoder.prototype._formatInput = function (type, param) {
- return this._requireType(type).formatInput(param, isArrayType(type));
-};
-
-/**
* Should be used to encode plain param
*
* @method encodeParam
@@ -190,7 +704,7 @@ SolidityCoder.prototype._formatInput = function (type, param) {
* @return {String} encoded plain param
*/
SolidityCoder.prototype.encodeParam = function (type, param) {
- return this._formatInput(type, param).encode();
+ return this.encodeParams([type], [param]);
};
/**
@@ -202,12 +716,113 @@ SolidityCoder.prototype.encodeParam = function (type, param) {
* @return {String} encoded list of params
*/
SolidityCoder.prototype.encodeParams = function (types, params) {
+ var solidityTypes = this.getSolidityTypes(types);
+
+ var encodeds = solidityTypes.map(function (solidityType, index) {
+ return solidityType.encode(params[index], types[index]);
+ });
+
+ var dynamicOffset = solidityTypes.reduce(function (acc, solidityType, index) {
+ return acc + solidityType.staticPartLength(types[index]);
+ }, 0);
+
+ var result = this.encodeMultiWithOffset(types, solidityTypes, encodeds, dynamicOffset);
+
+ return result;
+};
+
+SolidityCoder.prototype.encodeMultiWithOffset = function (types, solidityTypes, encodeds, dynamicOffset) {
+ var result = "";
var self = this;
- var solidityParams = types.map(function (type, index) {
- return self._formatInput(type, params[index]);
+
+ var isDynamic = function (i) {
+ return solidityTypes[i].isDynamicArray(types[i]) || solidityTypes[i].isDynamicType(types[i]);
+ };
+
+ types.forEach(function (type, i) {
+ if (isDynamic(i)) {
+ result += f.formatInputInt(dynamicOffset).encode();
+ var e = self.encodeWithOffset(types[i], solidityTypes[i], encodeds[i], dynamicOffset);
+ dynamicOffset += e.length / 2;
+ } else {
+ // don't add length to dynamicOffset. it's already counted
+ result += self.encodeWithOffset(types[i], solidityTypes[i], encodeds[i], dynamicOffset);
+ }
+
+ // TODO: figure out nested arrays
+ });
+
+ types.forEach(function (type, i) {
+ if (isDynamic(i)) {
+ var e = self.encodeWithOffset(types[i], solidityTypes[i], encodeds[i], dynamicOffset);
+ dynamicOffset += e.length / 2;
+ result += e;
+ }
});
+ return result;
+};
+
+// TODO: refactor whole encoding!
+SolidityCoder.prototype.encodeWithOffset = function (type, solidityType, encoded, offset) {
+ var self = this;
+ if (solidityType.isDynamicArray(type)) {
+ return (function () {
+ // offset was already set
+ var nestedName = solidityType.nestedName(type);
+ var nestedStaticPartLength = solidityType.staticPartLength(nestedName);
+ var result = encoded[0];
+
+ (function () {
+ var previousLength = 2; // in int
+ if (solidityType.isDynamicArray(nestedName)) {
+ for (var i = 1; i < encoded.length; i++) {
+ previousLength += +(encoded[i - 1])[0] || 0;
+ result += f.formatInputInt(offset + i * nestedStaticPartLength + previousLength * 32).encode();
+ }
+ }
+ })();
+
+ // first element is length, skip it
+ (function () {
+ for (var i = 0; i < encoded.length - 1; i++) {
+ var additionalOffset = result / 2;
+ result += self.encodeWithOffset(nestedName, solidityType, encoded[i + 1], offset + additionalOffset);
+ }
+ })();
+
+ return result;
+ })();
+
+ } else if (solidityType.isStaticArray(type)) {
+ return (function () {
+ var nestedName = solidityType.nestedName(type);
+ var nestedStaticPartLength = solidityType.staticPartLength(nestedName);
+ var result = "";
+
+
+ if (solidityType.isDynamicArray(nestedName)) {
+ (function () {
+ var previousLength = 0; // in int
+ for (var i = 0; i < encoded.length; i++) {
+ // calculate length of previous item
+ previousLength += +(encoded[i - 1] || [])[0] || 0;
+ result += f.formatInputInt(offset + i * nestedStaticPartLength + previousLength * 32).encode();
+ }
+ })();
+ }
+
+ (function () {
+ for (var i = 0; i < encoded.length; i++) {
+ var additionalOffset = result / 2;
+ result += self.encodeWithOffset(nestedName, solidityType, encoded[i], offset + additionalOffset);
+ }
+ })();
+
+ return result;
+ })();
+ }
- return SolidityParam.encodeList(solidityParams);
+ return encoded;
};
/**
@@ -231,84 +846,82 @@ SolidityCoder.prototype.decodeParam = function (type, bytes) {
* @return {Array} array of plain params
*/
SolidityCoder.prototype.decodeParams = function (types, bytes) {
+ var solidityTypes = this.getSolidityTypes(types);
+ var offsets = this.getOffsets(types, solidityTypes);
+
+ return solidityTypes.map(function (solidityType, index) {
+ return solidityType.decode(bytes, offsets[index], types[index], index);
+ });
+};
+
+SolidityCoder.prototype.getOffsets = function (types, solidityTypes) {
+ var lengths = solidityTypes.map(function (solidityType, index) {
+ return solidityType.staticPartLength(types[index]);
+ // get length
+ });
+
+ for (var i = 0; i < lengths.length; i++) {
+ // sum with length of previous element
+ var previous = (lengths[i - 1] || 0);
+ lengths[i] += previous;
+ }
+
+ return lengths.map(function (length, index) {
+ // remove the current length, so the length is sum of previous elements
+ return length - solidityTypes[index].staticPartLength(types[index]);
+ });
+};
+
+SolidityCoder.prototype.getSolidityTypes = function (types) {
var self = this;
- return types.map(function (type, index) {
- var solidityType = self._requireType(type);
- var p = solidityType.sliceParam(bytes, index, type);
- return solidityType.formatOutput(p, isArrayType(type));
+ return types.map(function (type) {
+ return self._requireType(type);
});
};
var coder = new SolidityCoder([
- new SolidityType({
- name: 'address',
- match: 'strict',
- mode: 'value',
- inputFormatter: f.formatInputInt,
- outputFormatter: f.formatOutputAddress
- }),
- new SolidityType({
- name: 'bool',
- match: 'strict',
- mode: 'value',
- inputFormatter: f.formatInputBool,
- outputFormatter: f.formatOutputBool
- }),
- new SolidityType({
- name: 'int',
- match: 'prefix',
- mode: 'value',
- inputFormatter: f.formatInputInt,
- outputFormatter: f.formatOutputInt,
- }),
- new SolidityType({
- name: 'uint',
- match: 'prefix',
- mode: 'value',
- inputFormatter: f.formatInputInt,
- outputFormatter: f.formatOutputUInt
- }),
- new SolidityType({
- name: 'bytes',
- match: 'strict',
- mode: 'bytes',
- inputFormatter: f.formatInputDynamicBytes,
- outputFormatter: f.formatOutputDynamicBytes
- }),
- new SolidityType({
- name: 'bytes',
- match: 'prefix',
- mode: 'value',
- inputFormatter: f.formatInputBytes,
- outputFormatter: f.formatOutputBytes
- }),
- new SolidityType({
- name: 'string',
- match: 'strict',
- mode: 'bytes',
- inputFormatter: f.formatInputString,
- outputFormatter: f.formatOutputString
- }),
- new SolidityType({
- name: 'real',
- match: 'prefix',
- mode: 'value',
- inputFormatter: f.formatInputReal,
- outputFormatter: f.formatOutputReal
- }),
- new SolidityType({
- name: 'ureal',
- match: 'prefix',
- mode: 'value',
- inputFormatter: f.formatInputReal,
- outputFormatter: f.formatOutputUReal
- })
+ new SolidityTypeAddress(),
+ new SolidityTypeBool(),
+ new SolidityTypeInt(),
+ new SolidityTypeUInt(),
+ new SolidityTypeDynamicBytes(),
+ new SolidityTypeBytes(),
+ new SolidityTypeString(),
+ new SolidityTypeReal(),
+ new SolidityTypeUReal()
]);
module.exports = coder;
-},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(require,module,exports){
+},{"./address":4,"./bool":5,"./bytes":6,"./dynamicbytes":8,"./formatters":9,"./int":10,"./real":12,"./string":13,"./uint":15,"./ureal":16}],8:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
+var SolidityTypeDynamicBytes = function () {
+ this._inputFormatter = f.formatInputDynamicBytes;
+ this._outputFormatter = f.formatOutputDynamicBytes;
+};
+
+SolidityTypeDynamicBytes.prototype = new SolidityType({});
+SolidityTypeDynamicBytes.prototype.constructor = SolidityTypeDynamicBytes;
+
+SolidityTypeDynamicBytes.prototype.isType = function (name) {
+ return !!name.match(/^bytes(\[([0-9]*)\])*$/);
+};
+
+SolidityTypeDynamicBytes.prototype.staticPartLength = function (name) {
+ return 32 * this.staticArrayLength(name);
+};
+
+SolidityTypeDynamicBytes.prototype.isDynamicType = function () {
+ return true;
+};
+
+module.exports = SolidityTypeDynamicBytes;
+
+
+},{"./formatters":9,"./type":14}],9:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -347,9 +960,8 @@ var SolidityParam = require('./param');
* @returns {SolidityParam}
*/
var formatInputInt = function (value) {
- var padding = c.ETH_PADDING * 2;
BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);
- var result = utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding);
+ var result = utils.padLeft(utils.toTwosComplement(value).round().toString(16), 64);
return new SolidityParam(result);
};
@@ -361,7 +973,9 @@ var formatInputInt = function (value) {
* @returns {SolidityParam}
*/
var formatInputBytes = function (value) {
- var result = utils.padRight(utils.toHex(value).substr(2), 64);
+ var result = utils.toHex(value).substr(2);
+ var l = Math.floor((result.length + 63) / 64);
+ result = utils.padRight(result, l * 64);
return new SolidityParam(result);
};
@@ -376,8 +990,8 @@ var formatInputDynamicBytes = function (value) {
var result = utils.toHex(value).substr(2);
var length = result.length / 2;
var l = Math.floor((result.length + 63) / 64);
- var result = utils.padRight(result, l * 64);
- return new SolidityParam(formatInputInt(length).value + result, 32);
+ result = utils.padRight(result, l * 64);
+ return new SolidityParam(formatInputInt(length).value + result);
};
/**
@@ -392,7 +1006,7 @@ var formatInputString = function (value) {
var length = result.length / 2;
var l = Math.floor((result.length + 63) / 64);
result = utils.padRight(result, l * 64);
- return new SolidityParam(formatInputInt(length).value + result, 32);
+ return new SolidityParam(formatInputInt(length).value + result);
};
/**
@@ -559,7 +1173,45 @@ module.exports = {
};
-},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){
+},{"../utils/config":18,"../utils/utils":20,"./param":11,"bignumber.js":"bignumber.js"}],10:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
+/**
+ * SolidityTypeInt is a prootype that represents int type
+ * It matches:
+ * int
+ * int[]
+ * int[4]
+ * int[][]
+ * int[3][]
+ * int[][6][], ...
+ * int32
+ * int64[]
+ * int8[4]
+ * int256[][]
+ * int[3][]
+ * int64[][6][], ...
+ */
+var SolidityTypeInt = function () {
+ this._inputFormatter = f.formatInputInt;
+ this._outputFormatter = f.formatOutputInt;
+};
+
+SolidityTypeInt.prototype = new SolidityType({});
+SolidityTypeInt.prototype.constructor = SolidityTypeInt;
+
+SolidityTypeInt.prototype.isType = function (name) {
+ return !!name.match(/^int([0-9]*)?(\[([0-9]*)\])*$/);
+};
+
+SolidityTypeInt.prototype.staticPartLength = function (name) {
+ return 32 * this.staticArrayLength(name);
+};
+
+module.exports = SolidityTypeInt;
+
+},{"./formatters":9,"./type":14}],11:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -634,7 +1286,7 @@ SolidityParam.prototype.combine = function (param) {
* @returns {Boolean}
*/
SolidityParam.prototype.isDynamic = function () {
- return this.value.length > 64 || this.offset !== undefined;
+ return this.offset !== undefined;
};
/**
@@ -708,71 +1360,398 @@ SolidityParam.encodeList = function (params) {
}, ''));
};
+
+
+module.exports = SolidityParam;
+
+
+},{"../utils/utils":20}],12:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
/**
- * This method should be used to decode plain (static) solidity param at given index
+ * SolidityTypeReal is a prootype that represents real type
+ * It matches:
+ * real
+ * real[]
+ * real[4]
+ * real[][]
+ * real[3][]
+ * real[][6][], ...
+ * real32
+ * real64[]
+ * real8[4]
+ * real256[][]
+ * real[3][]
+ * real64[][6][], ...
+ */
+var SolidityTypeReal = function () {
+ this._inputFormatter = f.formatInputReal;
+ this._outputFormatter = f.formatOutputReal;
+};
+
+SolidityTypeReal.prototype = new SolidityType({});
+SolidityTypeReal.prototype.constructor = SolidityTypeReal;
+
+SolidityTypeReal.prototype.isType = function (name) {
+ return !!name.match(/real([0-9]*)?(\[([0-9]*)\])?/);
+};
+
+SolidityTypeReal.prototype.staticPartLength = function (name) {
+ return 32 * this.staticArrayLength(name);
+};
+
+module.exports = SolidityTypeReal;
+
+},{"./formatters":9,"./type":14}],13:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
+var SolidityTypeString = function () {
+ this._inputFormatter = f.formatInputString;
+ this._outputFormatter = f.formatOutputString;
+};
+
+SolidityTypeString.prototype = new SolidityType({});
+SolidityTypeString.prototype.constructor = SolidityTypeString;
+
+SolidityTypeString.prototype.isType = function (name) {
+ return !!name.match(/^string(\[([0-9]*)\])*$/);
+};
+
+SolidityTypeString.prototype.staticPartLength = function (name) {
+ return 32 * this.staticArrayLength(name);
+};
+
+SolidityTypeString.prototype.isDynamicType = function () {
+ return true;
+};
+
+module.exports = SolidityTypeString;
+
+
+},{"./formatters":9,"./type":14}],14:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityParam = require('./param');
+
+/**
+ * SolidityType prototype is used to encode/decode solidity params of certain type
+ */
+var SolidityType = function (config) {
+ this._inputFormatter = config.inputFormatter;
+ this._outputFormatter = config.outputFormatter;
+};
+
+/**
+ * Should be used to determine if this SolidityType do match given name
*
- * @method decodeParam
- * @param {String} bytes
- * @param {Number} index
- * @returns {SolidityParam}
+ * @method isType
+ * @param {String} name
+ * @return {Bool} true if type match this SolidityType, otherwise false
*/
-SolidityParam.decodeParam = function (bytes, index) {
- index = index || 0;
- return new SolidityParam(bytes.substr(index * 64, 64));
+SolidityType.prototype.isType = function (name) {
+ throw "this method should be overrwritten for type " + name;
};
/**
- * This method should be called to get offset value from bytes at given index
+ * Should be used to determine what is the length of static part in given type
*
- * @method getOffset
- * @param {String} bytes
- * @param {Number} index
- * @returns {Number} offset as number
+ * @method staticPartLength
+ * @param {String} name
+ * @return {Number} length of static part in bytes
*/
-var getOffset = function (bytes, index) {
- // we can do this cause offset is rather small
- return parseInt('0x' + bytes.substr(index * 64, 64));
+SolidityType.prototype.staticPartLength = function (name) {
+ throw "this method should be overrwritten for type: " + name;
};
/**
- * This method should be called to decode solidity bytes param at given index
+ * Should be used to determine if type is dynamic array
+ * eg:
+ * "type[]" => true
+ * "type[4]" => false
*
- * @method decodeBytes
- * @param {String} bytes
- * @param {Number} index
- * @returns {SolidityParam}
+ * @method isDynamicArray
+ * @param {String} name
+ * @return {Bool} true if the type is dynamic array
+ */
+SolidityType.prototype.isDynamicArray = function (name) {
+ var nestedTypes = this.nestedTypes(name);
+ return !!nestedTypes && !nestedTypes[nestedTypes.length - 1].match(/[0-9]{1,}/g);
+};
+
+/**
+ * Should be used to determine if type is static array
+ * eg:
+ * "type[]" => false
+ * "type[4]" => true
+ *
+ * @method isStaticArray
+ * @param {String} name
+ * @return {Bool} true if the type is static array
+ */
+SolidityType.prototype.isStaticArray = function (name) {
+ var nestedTypes = this.nestedTypes(name);
+ return !!nestedTypes && !!nestedTypes[nestedTypes.length - 1].match(/[0-9]{1,}/g);
+};
+
+/**
+ * Should return length of static array
+ * eg.
+ * "int[32]" => 32
+ * "int256[14]" => 14
+ * "int[2][3]" => 3
+ * "int" => 1
+ * "int[1]" => 1
+ * "int[]" => 1
+ *
+ * @method staticArrayLength
+ * @param {String} name
+ * @return {Number} static array length
+ */
+SolidityType.prototype.staticArrayLength = function (name) {
+ var nestedTypes = this.nestedTypes(name);
+ if (nestedTypes) {
+ return parseInt(nestedTypes[nestedTypes.length - 1].match(/[0-9]{1,}/g) || 1);
+ }
+ return 1;
+};
+
+/**
+ * Should return nested type
+ * eg.
+ * "int[32]" => "int"
+ * "int256[14]" => "int256"
+ * "int[2][3]" => "int[2]"
+ * "int" => "int"
+ * "int[]" => "int"
+ *
+ * @method nestedName
+ * @param {String} name
+ * @return {String} nested name
+ */
+SolidityType.prototype.nestedName = function (name) {
+ // remove last [] in name
+ var nestedTypes = this.nestedTypes(name);
+ if (!nestedTypes) {
+ return name;
+ }
+
+ return name.substr(0, name.length - nestedTypes[nestedTypes.length - 1].length);
+};
+
+/**
+ * Should return true if type has dynamic size by default
+ * such types are "string", "bytes"
+ *
+ * @method isDynamicType
+ * @param {String} name
+ * @return {Bool} true if is dynamic, otherwise false
+ */
+SolidityType.prototype.isDynamicType = function () {
+ return false;
+};
+
+/**
+ * Should return array of nested types
+ * eg.
+ * "int[2][3][]" => ["[2]", "[3]", "[]"]
+ * "int[] => ["[]"]
+ * "int" => null
+ *
+ * @method nestedTypes
+ * @param {String} name
+ * @return {Array} array of nested types
+ */
+SolidityType.prototype.nestedTypes = function (name) {
+ // return list of strings eg. "[]", "[3]", "[]", "[2]"
+ return name.match(/(\[[0-9]*\])/g);
+};
+
+/**
+ * Should be used to encode the value
+ *
+ * @method encode
+ * @param {Object} value
+ * @param {String} name
+ * @return {String} encoded value
*/
-SolidityParam.decodeBytes = function (bytes, index) {
- index = index || 0;
+SolidityType.prototype.encode = function (value, name) {
+ var self = this;
+ if (this.isDynamicArray(name)) {
+
+ return (function () {
+ var length = value.length; // in int
+ var nestedName = self.nestedName(name);
+
+ var result = [];
+ result.push(f.formatInputInt(length).encode());
+
+ value.forEach(function (v) {
+ result.push(self.encode(v, nestedName));
+ });
+
+ return result;
+ })();
- var offset = getOffset(bytes, index);
+ } else if (this.isStaticArray(name)) {
- var l = parseInt('0x' + bytes.substr(offset * 2, 64));
- l = Math.floor((l + 31) / 32);
+ return (function () {
+ var length = self.staticArrayLength(name); // in int
+ var nestedName = self.nestedName(name);
- // (1 + l) * , cause we also parse length
- return new SolidityParam(bytes.substr(offset * 2, (1 + l) * 64), 0);
+ var result = [];
+ for (var i = 0; i < length; i++) {
+ result.push(self.encode(value[i], nestedName));
+ }
+
+ return result;
+ })();
+
+ }
+
+ return this._inputFormatter(value, name).encode();
};
/**
- * This method should be used to decode solidity array at given index
+ * Should be used to decode value from bytes
*
- * @method decodeArray
+ * @method decode
* @param {String} bytes
- * @param {Number} index
- * @returns {SolidityParam}
+ * @param {Number} offset in bytes
+ * @param {String} name type name
+ * @returns {Object} decoded value
*/
-SolidityParam.decodeArray = function (bytes, index) {
- index = index || 0;
- var offset = getOffset(bytes, index);
- var length = parseInt('0x' + bytes.substr(offset * 2, 64));
- return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64), 0);
+SolidityType.prototype.decode = function (bytes, offset, name) {
+ var self = this;
+
+ if (this.isDynamicArray(name)) {
+
+ return (function () {
+ var arrayOffset = parseInt('0x' + bytes.substr(offset * 2, 64)); // in bytes
+ var length = parseInt('0x' + bytes.substr(arrayOffset * 2, 64)); // in int
+ var arrayStart = arrayOffset + 32; // array starts after length; // in bytes
+
+ var nestedName = self.nestedName(name);
+ var nestedStaticPartLength = self.staticPartLength(nestedName); // in bytes
+ var result = [];
+
+ for (var i = 0; i < length * nestedStaticPartLength; i += nestedStaticPartLength) {
+ result.push(self.decode(bytes, arrayStart + i, nestedName));
+ }
+
+ return result;
+ })();
+
+ } else if (this.isStaticArray(name)) {
+
+ return (function () {
+ var length = self.staticArrayLength(name); // in int
+ var arrayStart = offset; // in bytes
+
+ var nestedName = self.nestedName(name);
+ var nestedStaticPartLength = self.staticPartLength(nestedName); // in bytes
+ var result = [];
+
+ for (var i = 0; i < length * nestedStaticPartLength; i += nestedStaticPartLength) {
+ result.push(self.decode(bytes, arrayStart + i, nestedName));
+ }
+
+ return result;
+ })();
+ } else if (this.isDynamicType(name)) {
+
+ return (function () {
+ var dynamicOffset = parseInt('0x' + bytes.substr(offset * 2, 64)); // in bytes
+ var length = parseInt('0x' + bytes.substr(dynamicOffset * 2, 64)); // in bytes
+ var roundedLength = Math.floor((length + 31) / 32); // in int
+
+ return self._outputFormatter(new SolidityParam(bytes.substr(dynamicOffset * 2, ( 1 + roundedLength) * 64), 0));
+ })();
+ }
+
+ var length = this.staticPartLength(name);
+ return this._outputFormatter(new SolidityParam(bytes.substr(offset * 2, length * 2)));
};
-module.exports = SolidityParam;
+module.exports = SolidityType;
+
+},{"./formatters":9,"./param":11}],15:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
+/**
+ * SolidityTypeUInt is a prootype that represents uint type
+ * It matches:
+ * uint
+ * uint[]
+ * uint[4]
+ * uint[][]
+ * uint[3][]
+ * uint[][6][], ...
+ * uint32
+ * uint64[]
+ * uint8[4]
+ * uint256[][]
+ * uint[3][]
+ * uint64[][6][], ...
+ */
+var SolidityTypeUInt = function () {
+ this._inputFormatter = f.formatInputInt;
+ this._outputFormatter = f.formatOutputInt;
+};
+
+SolidityTypeUInt.prototype = new SolidityType({});
+SolidityTypeUInt.prototype.constructor = SolidityTypeUInt;
+
+SolidityTypeUInt.prototype.isType = function (name) {
+ return !!name.match(/^uint([0-9]*)?(\[([0-9]*)\])*$/);
+};
+
+SolidityTypeUInt.prototype.staticPartLength = function (name) {
+ return 32 * this.staticArrayLength(name);
+};
+
+module.exports = SolidityTypeUInt;
+
+},{"./formatters":9,"./type":14}],16:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
+/**
+ * SolidityTypeUReal is a prootype that represents ureal type
+ * It matches:
+ * ureal
+ * ureal[]
+ * ureal[4]
+ * ureal[][]
+ * ureal[3][]
+ * ureal[][6][], ...
+ * ureal32
+ * ureal64[]
+ * ureal8[4]
+ * ureal256[][]
+ * ureal[3][]
+ * ureal64[][6][], ...
+ */
+var SolidityTypeUReal = function () {
+ this._inputFormatter = f.formatInputReal;
+ this._outputFormatter = f.formatOutputUReal;
+};
+
+SolidityTypeUReal.prototype = new SolidityType({});
+SolidityTypeUReal.prototype.constructor = SolidityTypeUReal;
+
+SolidityTypeUReal.prototype.isType = function (name) {
+ return !!name.match(/^ureal([0-9]*)?(\[([0-9]*)\])*$/);
+};
+
+SolidityTypeUReal.prototype.staticPartLength = function (name) {
+ return 32 * this.staticArrayLength(name);
+};
+module.exports = SolidityTypeUReal;
-},{"../utils/utils":7}],4:[function(require,module,exports){
+},{"./formatters":9,"./type":14}],17:[function(require,module,exports){
'use strict';
// go env doesn't have and need XMLHttpRequest
@@ -783,7 +1762,7 @@ if (typeof XMLHttpRequest === 'undefined') {
}
-},{}],5:[function(require,module,exports){
+},{}],18:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -819,6 +1798,7 @@ if (typeof XMLHttpRequest === 'undefined') {
* @constructor
*/
+
/// required to define ETH_BIGNUMBER_ROUNDING_MODE
var BigNumber = require('bignumber.js');
@@ -863,7 +1843,7 @@ module.exports = {
};
-},{"bignumber.js":"bignumber.js"}],6:[function(require,module,exports){
+},{"bignumber.js":"bignumber.js"}],19:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -886,6 +1866,7 @@ module.exports = {
* @date 2015
*/
+
var utils = require('./utils');
var sha3 = require('crypto-js/sha3');
@@ -904,7 +1885,7 @@ module.exports = function (str, isNew) {
};
-},{"./utils":7,"crypto-js/sha3":34}],7:[function(require,module,exports){
+},{"./utils":20,"crypto-js/sha3":47}],20:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -940,6 +1921,7 @@ module.exports = function (str, isNew) {
* @constructor
*/
+
var BigNumber = require('bignumber.js');
var unitMap = {
@@ -1015,7 +1997,7 @@ var toAscii = function(hex) {
str += String.fromCharCode(code);
}
- return decodeURIComponent(escape(str));
+ return decodeURIComponent(escape(str)); // jshint ignore:line
};
/**
@@ -1026,7 +2008,7 @@ var toAscii = function(hex) {
* @returns {String} hex representation of input string
*/
var toHexNative = function(str) {
- str = unescape(encodeURIComponent(str));
+ str = unescape(encodeURIComponent(str)); // jshint ignore:line
var hex = "";
for(var i = 0; i < str.length; i++) {
var n = str.charCodeAt(i).toString(16);
@@ -1377,18 +2359,6 @@ var isJson = function (str) {
}
};
-/**
- * This method should be called to check if string is valid ethereum IBAN number
- * Supports direct and indirect IBANs
- *
- * @method isIBAN
- * @param {String}
- * @return {Boolean}
- */
-var isIBAN = function (iban) {
- return /^XE[0-9]{2}(ETH[0-9A-Z]{13}|[0-9A-Z]{30})$/.test(iban);
-};
-
module.exports = {
padLeft: padLeft,
padRight: padRight,
@@ -1413,17 +2383,16 @@ module.exports = {
isObject: isObject,
isBoolean: isBoolean,
isArray: isArray,
- isJson: isJson,
- isIBAN: isIBAN
+ isJson: isJson
};
-},{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){
+},{"bignumber.js":"bignumber.js"}],21:[function(require,module,exports){
module.exports={
- "version": "0.9.1"
+ "version": "0.12.1"
}
-},{}],9:[function(require,module,exports){
+},{}],22:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -1451,11 +2420,11 @@ module.exports={
*/
var version = require('./version.json');
-var net = require('./web3/net');
-var eth = require('./web3/eth');
-var db = require('./web3/db');
-var shh = require('./web3/shh');
-var watches = require('./web3/watches');
+var net = require('./web3/methods/net');
+var eth = require('./web3/methods/eth');
+var db = require('./web3/methods/db');
+var shh = require('./web3/methods/shh');
+var watches = require('./web3/methods/watches');
var Filter = require('./web3/filter');
var utils = require('./utils/utils');
var formatters = require('./web3/formatters');
@@ -1600,7 +2569,7 @@ setupMethods(web3.shh, shh.methods);
module.exports = web3;
-},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":11,"./web3/db":13,"./web3/eth":15,"./web3/filter":17,"./web3/formatters":18,"./web3/method":24,"./web3/net":26,"./web3/property":27,"./web3/requestmanager":28,"./web3/shh":29,"./web3/watches":31}],10:[function(require,module,exports){
+},{"./utils/config":18,"./utils/sha3":19,"./utils/utils":20,"./version.json":21,"./web3/batch":24,"./web3/filter":28,"./web3/formatters":29,"./web3/method":35,"./web3/methods/db":36,"./web3/methods/eth":37,"./web3/methods/net":38,"./web3/methods/shh":39,"./web3/methods/watches":40,"./web3/property":42,"./web3/requestmanager":43}],23:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -1628,7 +2597,7 @@ var SolidityEvent = require('./event');
var formatters = require('./formatters');
var utils = require('../utils/utils');
var Filter = require('./filter');
-var watches = require('./watches');
+var watches = require('./methods/watches');
var AllSolidityEvents = function (json, address) {
this._json = json;
@@ -1669,6 +2638,13 @@ AllSolidityEvents.prototype.decode = function (data) {
};
AllSolidityEvents.prototype.execute = function (options, callback) {
+
+ if (utils.isFunction(arguments[arguments.length - 1])) {
+ callback = arguments[arguments.length - 1];
+ if(arguments.length === 1)
+ options = null;
+ }
+
var o = this.encode(options);
var formatter = this.decode.bind(this);
return new Filter(o, watches.eth(), formatter, callback);
@@ -1682,7 +2658,7 @@ AllSolidityEvents.prototype.attachToContract = function (contract) {
module.exports = AllSolidityEvents;
-},{"../utils/sha3":6,"../utils/utils":7,"./event":16,"./filter":17,"./formatters":18,"./watches":31}],11:[function(require,module,exports){
+},{"../utils/sha3":19,"../utils/utils":20,"./event":27,"./filter":28,"./formatters":29,"./methods/watches":40}],24:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -1750,7 +2726,7 @@ Batch.prototype.execute = function () {
module.exports = Batch;
-},{"./errors":14,"./jsonrpc":23,"./requestmanager":28}],12:[function(require,module,exports){
+},{"./errors":26,"./jsonrpc":34,"./requestmanager":43}],25:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -2029,65 +3005,7 @@ var Contract = function (abi, address) {
module.exports = contract;
-},{"../solidity/coder":1,"../utils/utils":7,"../web3":9,"./allevents":10,"./event":16,"./function":19}],13:[function(require,module,exports){
-/*
- This file is part of ethereum.js.
-
- ethereum.js is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- ethereum.js is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
-*/
-/** @file db.js
- * @authors:
- * Marek Kotewicz <marek@ethdev.com>
- * @date 2015
- */
-
-var Method = require('./method');
-
-var putString = new Method({
- name: 'putString',
- call: 'db_putString',
- params: 3
-});
-
-
-var getString = new Method({
- name: 'getString',
- call: 'db_getString',
- params: 2
-});
-
-var putHex = new Method({
- name: 'putHex',
- call: 'db_putHex',
- params: 3
-});
-
-var getHex = new Method({
- name: 'getHex',
- call: 'db_getHex',
- params: 2
-});
-
-var methods = [
- putString, getString, putHex, getHex
-];
-
-module.exports = {
- methods: methods
-};
-
-},{"./method":24}],14:[function(require,module,exports){
+},{"../solidity/coder":7,"../utils/utils":20,"../web3":22,"./allevents":23,"./event":27,"./function":30}],26:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -2127,300 +3045,7 @@ module.exports = {
};
-},{}],15:[function(require,module,exports){
-/*
- This file is part of ethereum.js.
-
- ethereum.js is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- ethereum.js is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * @file eth.js
- * @author Marek Kotewicz <marek@ethdev.com>
- * @author Fabian Vogelsteller <fabian@ethdev.com>
- * @date 2015
- */
-
-/**
- * Web3
- *
- * @module web3
- */
-
-/**
- * Eth methods and properties
- *
- * An example method object can look as follows:
- *
- * {
- * name: 'getBlock',
- * call: blockCall,
- * params: 2,
- * outputFormatter: formatters.outputBlockFormatter,
- * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter
- * utils.toHex, // formats paramter 1
- * function(param){ return !!param; } // formats paramter 2
- * ]
- * },
- *
- * @class [web3] eth
- * @constructor
- */
-
-"use strict";
-
-var formatters = require('./formatters');
-var utils = require('../utils/utils');
-var Method = require('./method');
-var Property = require('./property');
-
-var blockCall = function (args) {
- return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? "eth_getBlockByHash" : "eth_getBlockByNumber";
-};
-
-var transactionFromBlockCall = function (args) {
- return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';
-};
-
-var uncleCall = function (args) {
- return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';
-};
-
-var getBlockTransactionCountCall = function (args) {
- return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';
-};
-
-var uncleCountCall = function (args) {
- return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';
-};
-
-/// @returns an array of objects describing web3.eth api methods
-
-var getBalance = new Method({
- name: 'getBalance',
- call: 'eth_getBalance',
- params: 2,
- inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],
- outputFormatter: formatters.outputBigNumberFormatter
-});
-
-var getStorageAt = new Method({
- name: 'getStorageAt',
- call: 'eth_getStorageAt',
- params: 3,
- inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]
-});
-
-var getCode = new Method({
- name: 'getCode',
- call: 'eth_getCode',
- params: 2,
- inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]
-});
-
-var getBlock = new Method({
- name: 'getBlock',
- call: blockCall,
- params: 2,
- inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],
- outputFormatter: formatters.outputBlockFormatter
-});
-
-var getUncle = new Method({
- name: 'getUncle',
- call: uncleCall,
- params: 2,
- inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],
- outputFormatter: formatters.outputBlockFormatter,
-
-});
-
-var getCompilers = new Method({
- name: 'getCompilers',
- call: 'eth_getCompilers',
- params: 0
-});
-
-var getBlockTransactionCount = new Method({
- name: 'getBlockTransactionCount',
- call: getBlockTransactionCountCall,
- params: 1,
- inputFormatter: [formatters.inputBlockNumberFormatter],
- outputFormatter: utils.toDecimal
-});
-
-var getBlockUncleCount = new Method({
- name: 'getBlockUncleCount',
- call: uncleCountCall,
- params: 1,
- inputFormatter: [formatters.inputBlockNumberFormatter],
- outputFormatter: utils.toDecimal
-});
-
-var getTransaction = new Method({
- name: 'getTransaction',
- call: 'eth_getTransactionByHash',
- params: 1,
- outputFormatter: formatters.outputTransactionFormatter
-});
-
-var getTransactionFromBlock = new Method({
- name: 'getTransactionFromBlock',
- call: transactionFromBlockCall,
- params: 2,
- inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],
- outputFormatter: formatters.outputTransactionFormatter
-});
-
-var getTransactionReceipt = new Method({
- name: 'getTransactionReceipt',
- call: 'eth_getTransactionReceipt',
- params: 1,
- outputFormatter: formatters.outputTransactionReceiptFormatter
-});
-
-var getTransactionCount = new Method({
- name: 'getTransactionCount',
- call: 'eth_getTransactionCount',
- params: 2,
- inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],
- outputFormatter: utils.toDecimal
-});
-
-var sendRawTransaction = new Method({
- name: 'sendRawTransaction',
- call: 'eth_sendRawTransaction',
- params: 1,
- inputFormatter: [null]
-});
-
-var sendTransaction = new Method({
- name: 'sendTransaction',
- call: 'eth_sendTransaction',
- params: 1,
- inputFormatter: [formatters.inputTransactionFormatter]
-});
-
-var call = new Method({
- name: 'call',
- call: 'eth_call',
- params: 2,
- inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]
-});
-
-var estimateGas = new Method({
- name: 'estimateGas',
- call: 'eth_estimateGas',
- params: 1,
- inputFormatter: [formatters.inputTransactionFormatter],
- outputFormatter: utils.toDecimal
-});
-
-var compileSolidity = new Method({
- name: 'compile.solidity',
- call: 'eth_compileSolidity',
- params: 1
-});
-
-var compileLLL = new Method({
- name: 'compile.lll',
- call: 'eth_compileLLL',
- params: 1
-});
-
-var compileSerpent = new Method({
- name: 'compile.serpent',
- call: 'eth_compileSerpent',
- params: 1
-});
-
-var submitWork = new Method({
- name: 'submitWork',
- call: 'eth_submitWork',
- params: 3
-});
-
-var getWork = new Method({
- name: 'getWork',
- call: 'eth_getWork',
- params: 0
-});
-
-var methods = [
- getBalance,
- getStorageAt,
- getCode,
- getBlock,
- getUncle,
- getCompilers,
- getBlockTransactionCount,
- getBlockUncleCount,
- getTransaction,
- getTransactionFromBlock,
- getTransactionReceipt,
- getTransactionCount,
- call,
- estimateGas,
- sendRawTransaction,
- sendTransaction,
- compileSolidity,
- compileLLL,
- compileSerpent,
- submitWork,
- getWork
-];
-
-/// @returns an array of objects describing web3.eth api properties
-
-
-
-var properties = [
- new Property({
- name: 'coinbase',
- getter: 'eth_coinbase'
- }),
- new Property({
- name: 'mining',
- getter: 'eth_mining'
- }),
- new Property({
- name: 'hashrate',
- getter: 'eth_hashrate',
- outputFormatter: utils.toDecimal
- }),
- new Property({
- name: 'gasPrice',
- getter: 'eth_gasPrice',
- outputFormatter: formatters.outputBigNumberFormatter
- }),
- new Property({
- name: 'accounts',
- getter: 'eth_accounts'
- }),
- new Property({
- name: 'blockNumber',
- getter: 'eth_blockNumber',
- outputFormatter: utils.toDecimal
- })
-];
-
-module.exports = {
- methods: methods,
- properties: properties
-};
-
-
-},{"../utils/utils":7,"./formatters":18,"./method":24,"./property":27}],16:[function(require,module,exports){
+},{}],27:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -2448,7 +3073,7 @@ var coder = require('../solidity/coder');
var formatters = require('./formatters');
var sha3 = require('../utils/sha3');
var Filter = require('./filter');
-var watches = require('./watches');
+var watches = require('./methods/watches');
/**
* This prototype should be used to create event filters
@@ -2629,7 +3254,7 @@ SolidityEvent.prototype.attachToContract = function (contract) {
module.exports = SolidityEvent;
-},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"./filter":17,"./formatters":18,"./watches":31}],17:[function(require,module,exports){
+},{"../solidity/coder":7,"../utils/sha3":19,"../utils/utils":20,"./filter":28,"./formatters":29,"./methods/watches":40}],28:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -2795,6 +3420,7 @@ var Filter = function (options, methods, formatter, callback) {
}
});
+ return this;
};
Filter.prototype.watch = function (callback) {
@@ -2840,7 +3466,7 @@ Filter.prototype.get = function (callback) {
module.exports = Filter;
-},{"../utils/utils":7,"./formatters":18,"./requestmanager":28}],18:[function(require,module,exports){
+},{"../utils/utils":20,"./formatters":29,"./requestmanager":43}],29:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -2866,6 +3492,7 @@ module.exports = Filter;
var utils = require('../utils/utils');
var config = require('../utils/config');
+var Iban = require('./iban');
/**
* Should the format output to a big number
@@ -2901,6 +3528,34 @@ var inputBlockNumberFormatter = function (blockNumber) {
/**
* Formats the input of a transaction and converts all values to HEX
*
+ * @method inputCallFormatter
+ * @param {Object} transaction options
+ * @returns object
+*/
+var inputCallFormatter = function (options){
+
+ options.from = options.from || config.defaultAccount;
+
+ if (options.from) {
+ options.from = inputAddressFormatter(options.from);
+ }
+
+ if (options.to) { // it might be contract creation
+ options.to = inputAddressFormatter(options.to);
+ }
+
+ ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {
+ return options[key] !== undefined;
+ }).forEach(function(key){
+ options[key] = utils.fromDecimal(options[key]);
+ });
+
+ return options;
+};
+
+/**
+ * Formats the input of a transaction and converts all values to HEX
+ *
* @method inputTransactionFormatter
* @param {Object} transaction options
* @returns object
@@ -2908,11 +3563,10 @@ var inputBlockNumberFormatter = function (blockNumber) {
var inputTransactionFormatter = function (options){
options.from = options.from || config.defaultAccount;
+ options.from = inputAddressFormatter(options.from);
- // make code -> data
- if (options.code) {
- options.data = options.code;
- delete options.code;
+ if (options.to) { // it might be contract creation
+ options.to = inputAddressFormatter(options.to);
}
['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {
@@ -3073,10 +3727,24 @@ var outputPostFormatter = function(post){
return post;
};
+var inputAddressFormatter = function (address) {
+ var iban = new Iban(address);
+ if (iban.isValid() && iban.isDirect()) {
+ return '0x' + iban.address();
+ } else if (utils.isStrictAddress(address)) {
+ return address;
+ } else if (utils.isAddress(address)) {
+ return '0x' + address;
+ }
+ throw 'invalid address';
+};
+
module.exports = {
inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter,
inputBlockNumberFormatter: inputBlockNumberFormatter,
+ inputCallFormatter: inputCallFormatter,
inputTransactionFormatter: inputTransactionFormatter,
+ inputAddressFormatter: inputAddressFormatter,
inputPostFormatter: inputPostFormatter,
outputBigNumberFormatter: outputBigNumberFormatter,
outputTransactionFormatter: outputTransactionFormatter,
@@ -3087,7 +3755,7 @@ module.exports = {
};
-},{"../utils/config":5,"../utils/utils":7}],19:[function(require,module,exports){
+},{"../utils/config":18,"../utils/utils":20,"./iban":32}],30:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -3324,7 +3992,7 @@ SolidityFunction.prototype.attachToContract = function (contract) {
module.exports = SolidityFunction;
-},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":18}],20:[function(require,module,exports){
+},{"../solidity/coder":7,"../utils/sha3":19,"../utils/utils":20,"../web3":22,"./formatters":29}],31:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -3351,51 +4019,61 @@ module.exports = SolidityFunction;
"use strict";
-var XMLHttpRequest = (typeof window !== 'undefined' && window.XMLHttpRequest) ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
var errors = require('./errors');
+// workaround to use httpprovider in different envs
+var XMLHttpRequest; // jshint ignore: line
+
+// meteor server environment
+if (typeof Meteor !== 'undefined' && Meteor.isServer) { // jshint ignore: line
+ XMLHttpRequest = Npm.require('xmlhttprequest').XMLHttpRequest; // jshint ignore: line
+
+// browser
+} else if (typeof window !== 'undefined' && window.XMLHttpRequest) {
+ XMLHttpRequest = window.XMLHttpRequest; // jshint ignore: line
+
+// node
+} else {
+ XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore: line
+}
+
+/**
+ * HttpProvider should be used to send rpc calls over http
+ */
var HttpProvider = function (host) {
this.host = host || 'http://localhost:8545';
};
-HttpProvider.prototype.isConnected = function() {
+/**
+ * Should be called to prepare new XMLHttpRequest
+ *
+ * @method prepareRequest
+ * @param {Boolean} true if request should be async
+ * @return {XMLHttpRequest} object
+ */
+HttpProvider.prototype.prepareRequest = function (async) {
var request = new XMLHttpRequest();
-
- request.open('POST', this.host, false);
- request.setRequestHeader('Content-type','application/json');
-
- try {
- request.send(JSON.stringify({
- id: 9999999999,
- jsonrpc: '2.0',
- method: 'net_listening',
- params: []
- }));
- return true;
- } catch(e) {
- return false;
- }
+ request.open('POST', this.host, async);
+ request.setRequestHeader('Content-Type','application/json');
+ return request;
};
+/**
+ * Should be called to make sync request
+ *
+ * @method send
+ * @param {Object} payload
+ * @return {Object} result
+ */
HttpProvider.prototype.send = function (payload) {
- var request = new XMLHttpRequest();
+ var request = this.prepareRequest(false);
- request.open('POST', this.host, false);
- request.setRequestHeader('Content-type','application/json');
-
try {
request.send(JSON.stringify(payload));
} catch(error) {
throw errors.InvalidConnection(this.host);
}
-
- // check request.status
- // TODO: throw an error here! it cannot silently fail!!!
- //if (request.status !== 200) {
- //return;
- //}
-
var result = request.responseText;
try {
@@ -3407,8 +4085,16 @@ HttpProvider.prototype.send = function (payload) {
return result;
};
+/**
+ * Should be used to make async request
+ *
+ * @method sendAsync
+ * @param {Object} payload
+ * @param {Function} callback triggered on end with (err, result)
+ */
HttpProvider.prototype.sendAsync = function (payload, callback) {
- var request = new XMLHttpRequest();
+ var request = this.prepareRequest(true);
+
request.onreadystatechange = function() {
if (request.readyState === 4) {
var result = request.responseText;
@@ -3423,9 +4109,6 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
callback(error, result);
}
};
-
- request.open('POST', this.host, true);
- request.setRequestHeader('Content-type','application/json');
try {
request.send(JSON.stringify(payload));
@@ -3434,10 +4117,30 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
}
};
+/**
+ * Synchronously tries to make Http request
+ *
+ * @method isConnected
+ * @return {Boolean} returns true if request haven't failed. Otherwise false
+ */
+HttpProvider.prototype.isConnected = function() {
+ try {
+ this.send({
+ id: 9999999999,
+ jsonrpc: '2.0',
+ method: 'net_listening',
+ params: []
+ });
+ return true;
+ } catch(e) {
+ return false;
+ }
+};
+
module.exports = HttpProvider;
-},{"./errors":14,"xmlhttprequest":4}],21:[function(require,module,exports){
+},{"./errors":26,"xmlhttprequest":17}],32:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -3455,30 +4158,139 @@ module.exports = HttpProvider;
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/**
- * @file icap.js
+ * @file iban.js
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
-var utils = require('../utils/utils');
+var BigNumber = require('bignumber.js');
+
+var padLeft = function (string, bytes) {
+ var result = string;
+ while (result.length < bytes * 2) {
+ result = '00' + result;
+ }
+ return result;
+};
/**
- * This prototype should be used to extract necessary information from iban address
+ * Prepare an IBAN for mod 97 computation by moving the first 4 chars to the end and transforming the letters to
+ * numbers (A = 10, B = 11, ..., Z = 35), as specified in ISO13616.
+ *
+ * @method iso13616Prepare
+ * @param {String} iban the IBAN
+ * @returns {String} the prepared IBAN
+ */
+var iso13616Prepare = function (iban) {
+ var A = 'A'.charCodeAt(0);
+ var Z = 'Z'.charCodeAt(0);
+
+ iban = iban.toUpperCase();
+ iban = iban.substr(4) + iban.substr(0,4);
+
+ return iban.split('').map(function(n){
+ var code = n.charCodeAt(0);
+ if (code >= A && code <= Z){
+ // A = 10, B = 11, ... Z = 35
+ return code - A + 10;
+ } else {
+ return n;
+ }
+ }).join('');
+};
+
+/**
+ * Calculates the MOD 97 10 of the passed IBAN as specified in ISO7064.
+ *
+ * @method mod9710
+ * @param {String} iban
+ * @returns {Number}
+ */
+var mod9710 = function (iban) {
+ var remainder = iban,
+ block;
+
+ while (remainder.length > 2){
+ block = remainder.slice(0, 9);
+ remainder = parseInt(block, 10) % 97 + remainder.slice(block.length);
+ }
+
+ return parseInt(remainder, 10) % 97;
+};
+
+/**
+ * This prototype should be used to create iban object from iban correct string
*
* @param {String} iban
*/
-var ICAP = function (iban) {
+var Iban = function (iban) {
this._iban = iban;
};
/**
- * Should be called to check if icap is correct
+ * This method should be used to create iban object from ethereum address
+ *
+ * @method fromAddress
+ * @param {String} address
+ * @return {Iban} the IBAN object
+ */
+Iban.fromAddress = function (address) {
+ var asBn = new BigNumber(address, 16);
+ var base36 = asBn.toString(36);
+ var padded = padLeft(base36, 15);
+ return Iban.fromBban(padded.toUpperCase());
+};
+
+/**
+ * Convert the passed BBAN to an IBAN for this country specification.
+ * Please note that <i>"generation of the IBAN shall be the exclusive responsibility of the bank/branch servicing the account"</i>.
+ * This method implements the preferred algorithm described in http://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits
+ *
+ * @method fromBban
+ * @param {String} bban the BBAN to convert to IBAN
+ * @returns {Iban} the IBAN object
+ */
+Iban.fromBban = function (bban) {
+ var countryCode = 'XE';
+
+ var remainder = mod9710(iso13616Prepare(countryCode + '00' + bban));
+ var checkDigit = ('0' + (98 - remainder)).slice(-2);
+
+ return new Iban(countryCode + checkDigit + bban);
+};
+
+/**
+ * Should be used to create IBAN object for given institution and identifier
+ *
+ * @method createIndirect
+ * @param {Object} options, required options are "institution" and "identifier"
+ * @return {Iban} the IBAN object
+ */
+Iban.createIndirect = function (options) {
+ return Iban.fromBban('ETH' + options.institution + options.identifier);
+};
+
+/**
+ * Thos method should be used to check if given string is valid iban object
+ *
+ * @method isValid
+ * @param {String} iban string
+ * @return {Boolean} true if it is valid IBAN
+ */
+Iban.isValid = function (iban) {
+ var i = new Iban(iban);
+ return i.isValid();
+};
+
+/**
+ * Should be called to check if iban is correct
*
* @method isValid
* @returns {Boolean} true if it is, otherwise false
*/
-ICAP.prototype.isValid = function () {
- return utils.isIBAN(this._iban);
+Iban.prototype.isValid = function () {
+ return /^XE[0-9]{2}(ETH[0-9A-Z]{13}|[0-9A-Z]{30})$/.test(this._iban) &&
+ mod9710(iso13616Prepare(this._iban)) === 1;
};
/**
@@ -3487,8 +4299,8 @@ ICAP.prototype.isValid = function () {
* @method isDirect
* @returns {Boolean} true if it is, otherwise false
*/
-ICAP.prototype.isDirect = function () {
- return this._iban.length === 34;
+Iban.prototype.isDirect = function () {
+ return this._iban.length === 34 || this._iban.length === 35;
};
/**
@@ -3497,7 +4309,7 @@ ICAP.prototype.isDirect = function () {
* @method isIndirect
* @returns {Boolean} true if it is, otherwise false
*/
-ICAP.prototype.isIndirect = function () {
+Iban.prototype.isIndirect = function () {
return this._iban.length === 20;
};
@@ -3508,7 +4320,7 @@ ICAP.prototype.isIndirect = function () {
* @method checksum
* @returns {String} checksum
*/
-ICAP.prototype.checksum = function () {
+Iban.prototype.checksum = function () {
return this._iban.substr(2, 2);
};
@@ -3519,7 +4331,7 @@ ICAP.prototype.checksum = function () {
* @method institution
* @returns {String} institution identifier
*/
-ICAP.prototype.institution = function () {
+Iban.prototype.institution = function () {
return this.isIndirect() ? this._iban.substr(7, 4) : '';
};
@@ -3530,7 +4342,7 @@ ICAP.prototype.institution = function () {
* @method client
* @returns {String} client identifier
*/
-ICAP.prototype.client = function () {
+Iban.prototype.client = function () {
return this.isIndirect() ? this._iban.substr(11) : '';
};
@@ -3540,14 +4352,24 @@ ICAP.prototype.client = function () {
* @method address
* @returns {String} client direct address
*/
-ICAP.prototype.address = function () {
- return this.isDirect() ? this._iban.substr(4) : '';
+Iban.prototype.address = function () {
+ if (this.isDirect()) {
+ var base36 = this._iban.substr(4);
+ var asBn = new BigNumber(base36, 36);
+ return padLeft(asBn.toString(16), 20);
+ }
+
+ return '';
};
-module.exports = ICAP;
+Iban.prototype.toString = function () {
+ return this._iban;
+};
+
+module.exports = Iban;
-},{"../utils/utils":7}],22:[function(require,module,exports){
+},{"bignumber.js":"bignumber.js"}],33:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -3575,16 +4397,23 @@ module.exports = ICAP;
var utils = require('../utils/utils');
var errors = require('./errors');
-var errorTimeout = '{"jsonrpc": "2.0", "error": {"code": -32603, "message": "IPC Request timed out for method \'__method__\'"}, "id": "__id__"}';
-
+var errorTimeout = function (method, id) {
+ var err = {
+ "jsonrpc": "2.0",
+ "error": {
+ "code": -32603,
+ "message": "IPC Request timed out for method \'" + method + "\'"
+ },
+ "id": id
+ };
+ return JSON.stringify(err);
+};
var IpcProvider = function (path, net) {
var _this = this;
this.responseCallbacks = {};
this.path = path;
- net = net || require('net');
-
this.connection = net.connect({path: this.path});
this.connection.on('error', function(e){
@@ -3701,7 +4530,7 @@ Timeout all requests when the end/error event is fired
IpcProvider.prototype._timeout = function() {
for(var key in this.responseCallbacks) {
if(this.responseCallbacks.hasOwnProperty(key)){
- this.responseCallbacks[key](errorTimeout.replace('__id__', key).replace('__method__', this.responseCallbacks[key].method));
+ this.responseCallbacks[key](errorTimeout(this.responseCallbacks[key].method, key));
delete this.responseCallbacks[key];
}
}
@@ -3760,7 +4589,7 @@ IpcProvider.prototype.sendAsync = function (payload, callback) {
module.exports = IpcProvider;
-},{"../utils/utils":7,"./errors":14,"net":32}],23:[function(require,module,exports){
+},{"../utils/utils":20,"./errors":26}],34:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -3853,7 +4682,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) {
module.exports = Jsonrpc;
-},{}],24:[function(require,module,exports){
+},{}],35:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -4027,7 +4856,7 @@ Method.prototype.send = function () {
module.exports = Method;
-},{"../utils/utils":7,"./errors":14,"./requestmanager":28}],25:[function(require,module,exports){
+},{"../utils/utils":20,"./errors":26,"./requestmanager":43}],36:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -4044,38 +4873,341 @@ module.exports = Method;
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * @file namereg.js
+/** @file db.js
+ * @authors:
+ * Marek Kotewicz <marek@ethdev.com>
+ * @date 2015
+ */
+
+var Method = require('../method');
+
+var putString = new Method({
+ name: 'putString',
+ call: 'db_putString',
+ params: 3
+});
+
+
+var getString = new Method({
+ name: 'getString',
+ call: 'db_getString',
+ params: 2
+});
+
+var putHex = new Method({
+ name: 'putHex',
+ call: 'db_putHex',
+ params: 3
+});
+
+var getHex = new Method({
+ name: 'getHex',
+ call: 'db_getHex',
+ params: 2
+});
+
+var methods = [
+ putString, getString, putHex, getHex
+];
+
+module.exports = {
+ methods: methods
+};
+
+},{"../method":35}],37:[function(require,module,exports){
+/*
+ This file is part of ethereum.js.
+
+ ethereum.js is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ ethereum.js is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @file eth.js
* @author Marek Kotewicz <marek@ethdev.com>
+ * @author Fabian Vogelsteller <fabian@ethdev.com>
* @date 2015
*/
-var contract = require('./contract');
+/**
+ * Web3
+ *
+ * @module web3
+ */
+
+/**
+ * Eth methods and properties
+ *
+ * An example method object can look as follows:
+ *
+ * {
+ * name: 'getBlock',
+ * call: blockCall,
+ * params: 2,
+ * outputFormatter: formatters.outputBlockFormatter,
+ * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter
+ * utils.toHex, // formats paramter 1
+ * function(param){ return !!param; } // formats paramter 2
+ * ]
+ * },
+ *
+ * @class [web3] eth
+ * @constructor
+ */
+
+"use strict";
+
+var formatters = require('../formatters');
+var utils = require('../../utils/utils');
+var Method = require('../method');
+var Property = require('../property');
+
+var blockCall = function (args) {
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? "eth_getBlockByHash" : "eth_getBlockByNumber";
+};
+
+var transactionFromBlockCall = function (args) {
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';
+};
+
+var uncleCall = function (args) {
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';
+};
+
+var getBlockTransactionCountCall = function (args) {
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';
+};
+
+var uncleCountCall = function (args) {
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';
+};
+
+/// @returns an array of objects describing web3.eth api methods
+
+var getBalance = new Method({
+ name: 'getBalance',
+ call: 'eth_getBalance',
+ params: 2,
+ inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter],
+ outputFormatter: formatters.outputBigNumberFormatter
+});
+
+var getStorageAt = new Method({
+ name: 'getStorageAt',
+ call: 'eth_getStorageAt',
+ params: 3,
+ inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]
+});
+
+var getCode = new Method({
+ name: 'getCode',
+ call: 'eth_getCode',
+ params: 2,
+ inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter]
+});
-var address = '0xc6d9d2cd449a754c494264e1809c50e34d64562b';
-
-var abi = [
- {"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"},
- {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},
- {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"},
- {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"},
- {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"},
- {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"},
- {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"},
- {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"},
- {"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"},
- {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"},
- {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"},
- {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"},
- {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"},
- {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"},
- {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"}
+var getBlock = new Method({
+ name: 'getBlock',
+ call: blockCall,
+ params: 2,
+ inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],
+ outputFormatter: formatters.outputBlockFormatter
+});
+
+var getUncle = new Method({
+ name: 'getUncle',
+ call: uncleCall,
+ params: 2,
+ inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],
+ outputFormatter: formatters.outputBlockFormatter,
+
+});
+
+var getCompilers = new Method({
+ name: 'getCompilers',
+ call: 'eth_getCompilers',
+ params: 0
+});
+
+var getBlockTransactionCount = new Method({
+ name: 'getBlockTransactionCount',
+ call: getBlockTransactionCountCall,
+ params: 1,
+ inputFormatter: [formatters.inputBlockNumberFormatter],
+ outputFormatter: utils.toDecimal
+});
+
+var getBlockUncleCount = new Method({
+ name: 'getBlockUncleCount',
+ call: uncleCountCall,
+ params: 1,
+ inputFormatter: [formatters.inputBlockNumberFormatter],
+ outputFormatter: utils.toDecimal
+});
+
+var getTransaction = new Method({
+ name: 'getTransaction',
+ call: 'eth_getTransactionByHash',
+ params: 1,
+ outputFormatter: formatters.outputTransactionFormatter
+});
+
+var getTransactionFromBlock = new Method({
+ name: 'getTransactionFromBlock',
+ call: transactionFromBlockCall,
+ params: 2,
+ inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],
+ outputFormatter: formatters.outputTransactionFormatter
+});
+
+var getTransactionReceipt = new Method({
+ name: 'getTransactionReceipt',
+ call: 'eth_getTransactionReceipt',
+ params: 1,
+ outputFormatter: formatters.outputTransactionReceiptFormatter
+});
+
+var getTransactionCount = new Method({
+ name: 'getTransactionCount',
+ call: 'eth_getTransactionCount',
+ params: 2,
+ inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],
+ outputFormatter: utils.toDecimal
+});
+
+var sendRawTransaction = new Method({
+ name: 'sendRawTransaction',
+ call: 'eth_sendRawTransaction',
+ params: 1,
+ inputFormatter: [null]
+});
+
+var sendTransaction = new Method({
+ name: 'sendTransaction',
+ call: 'eth_sendTransaction',
+ params: 1,
+ inputFormatter: [formatters.inputTransactionFormatter]
+});
+
+var call = new Method({
+ name: 'call',
+ call: 'eth_call',
+ params: 2,
+ inputFormatter: [formatters.inputCallFormatter, formatters.inputDefaultBlockNumberFormatter]
+});
+
+var estimateGas = new Method({
+ name: 'estimateGas',
+ call: 'eth_estimateGas',
+ params: 1,
+ inputFormatter: [formatters.inputCallFormatter],
+ outputFormatter: utils.toDecimal
+});
+
+var compileSolidity = new Method({
+ name: 'compile.solidity',
+ call: 'eth_compileSolidity',
+ params: 1
+});
+
+var compileLLL = new Method({
+ name: 'compile.lll',
+ call: 'eth_compileLLL',
+ params: 1
+});
+
+var compileSerpent = new Method({
+ name: 'compile.serpent',
+ call: 'eth_compileSerpent',
+ params: 1
+});
+
+var submitWork = new Method({
+ name: 'submitWork',
+ call: 'eth_submitWork',
+ params: 3
+});
+
+var getWork = new Method({
+ name: 'getWork',
+ call: 'eth_getWork',
+ params: 0
+});
+
+var methods = [
+ getBalance,
+ getStorageAt,
+ getCode,
+ getBlock,
+ getUncle,
+ getCompilers,
+ getBlockTransactionCount,
+ getBlockUncleCount,
+ getTransaction,
+ getTransactionFromBlock,
+ getTransactionReceipt,
+ getTransactionCount,
+ call,
+ estimateGas,
+ sendRawTransaction,
+ sendTransaction,
+ compileSolidity,
+ compileLLL,
+ compileSerpent,
+ submitWork,
+ getWork
];
-module.exports = contract(abi).at(address);
+/// @returns an array of objects describing web3.eth api properties
+
-},{"./contract":12}],26:[function(require,module,exports){
+var properties = [
+ new Property({
+ name: 'coinbase',
+ getter: 'eth_coinbase'
+ }),
+ new Property({
+ name: 'mining',
+ getter: 'eth_mining'
+ }),
+ new Property({
+ name: 'hashrate',
+ getter: 'eth_hashrate',
+ outputFormatter: utils.toDecimal
+ }),
+ new Property({
+ name: 'gasPrice',
+ getter: 'eth_gasPrice',
+ outputFormatter: formatters.outputBigNumberFormatter
+ }),
+ new Property({
+ name: 'accounts',
+ getter: 'eth_accounts'
+ }),
+ new Property({
+ name: 'blockNumber',
+ getter: 'eth_blockNumber',
+ outputFormatter: utils.toDecimal
+ })
+];
+
+module.exports = {
+ methods: methods,
+ properties: properties
+};
+
+
+},{"../../utils/utils":20,"../formatters":29,"../method":35,"../property":42}],38:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -4098,8 +5230,8 @@ module.exports = contract(abi).at(address);
* @date 2015
*/
-var utils = require('../utils/utils');
-var Property = require('./property');
+var utils = require('../../utils/utils');
+var Property = require('../property');
/// @returns an array of objects describing web3.eth api methods
var methods = [
@@ -4125,7 +5257,229 @@ module.exports = {
};
-},{"../utils/utils":7,"./property":27}],27:[function(require,module,exports){
+},{"../../utils/utils":20,"../property":42}],39:[function(require,module,exports){
+/*
+ This file is part of ethereum.js.
+
+ ethereum.js is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ ethereum.js is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file shh.js
+ * @authors:
+ * Marek Kotewicz <marek@ethdev.com>
+ * @date 2015
+ */
+
+var Method = require('../method');
+var formatters = require('../formatters');
+
+var post = new Method({
+ name: 'post',
+ call: 'shh_post',
+ params: 1,
+ inputFormatter: [formatters.inputPostFormatter]
+});
+
+var newIdentity = new Method({
+ name: 'newIdentity',
+ call: 'shh_newIdentity',
+ params: 0
+});
+
+var hasIdentity = new Method({
+ name: 'hasIdentity',
+ call: 'shh_hasIdentity',
+ params: 1
+});
+
+var newGroup = new Method({
+ name: 'newGroup',
+ call: 'shh_newGroup',
+ params: 0
+});
+
+var addToGroup = new Method({
+ name: 'addToGroup',
+ call: 'shh_addToGroup',
+ params: 0
+});
+
+var methods = [
+ post,
+ newIdentity,
+ hasIdentity,
+ newGroup,
+ addToGroup
+];
+
+module.exports = {
+ methods: methods
+};
+
+
+},{"../formatters":29,"../method":35}],40:[function(require,module,exports){
+/*
+ This file is part of ethereum.js.
+
+ ethereum.js is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ ethereum.js is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file watches.js
+ * @authors:
+ * Marek Kotewicz <marek@ethdev.com>
+ * @date 2015
+ */
+
+var Method = require('../method');
+
+/// @returns an array of objects describing web3.eth.filter api methods
+var eth = function () {
+ var newFilterCall = function (args) {
+ var type = args[0];
+
+ switch(type) {
+ case 'latest':
+ args.shift();
+ this.params = 0;
+ return 'eth_newBlockFilter';
+ case 'pending':
+ args.shift();
+ this.params = 0;
+ return 'eth_newPendingTransactionFilter';
+ default:
+ return 'eth_newFilter';
+ }
+ };
+
+ var newFilter = new Method({
+ name: 'newFilter',
+ call: newFilterCall,
+ params: 1
+ });
+
+ var uninstallFilter = new Method({
+ name: 'uninstallFilter',
+ call: 'eth_uninstallFilter',
+ params: 1
+ });
+
+ var getLogs = new Method({
+ name: 'getLogs',
+ call: 'eth_getFilterLogs',
+ params: 1
+ });
+
+ var poll = new Method({
+ name: 'poll',
+ call: 'eth_getFilterChanges',
+ params: 1
+ });
+
+ return [
+ newFilter,
+ uninstallFilter,
+ getLogs,
+ poll
+ ];
+};
+
+/// @returns an array of objects describing web3.shh.watch api methods
+var shh = function () {
+ var newFilter = new Method({
+ name: 'newFilter',
+ call: 'shh_newFilter',
+ params: 1
+ });
+
+ var uninstallFilter = new Method({
+ name: 'uninstallFilter',
+ call: 'shh_uninstallFilter',
+ params: 1
+ });
+
+ var getLogs = new Method({
+ name: 'getLogs',
+ call: 'shh_getMessages',
+ params: 1
+ });
+
+ var poll = new Method({
+ name: 'poll',
+ call: 'shh_getFilterChanges',
+ params: 1
+ });
+
+ return [
+ newFilter,
+ uninstallFilter,
+ getLogs,
+ poll
+ ];
+};
+
+module.exports = {
+ eth: eth,
+ shh: shh
+};
+
+
+},{"../method":35}],41:[function(require,module,exports){
+/*
+ This file is part of ethereum.js.
+
+ ethereum.js is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ ethereum.js is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @file namereg.js
+ * @author Marek Kotewicz <marek@ethdev.com>
+ * @date 2015
+ */
+
+var contract = require('./contract');
+var globalRegistrarAbi = require('../contracts/GlobalRegistrar.json');
+var icapRegistrarAbi= require('../contracts/ICAPRegistrar.json');
+
+var globalNameregAddress = '0xc6d9d2cd449a754c494264e1809c50e34d64562b';
+var ibanNameregAddress = '0xa1a111bc074c9cfa781f0c38e63bd51c91b8af00';
+
+module.exports = {
+ namereg: contract(globalRegistrarAbi).at(globalNameregAddress),
+ ibanNamereg: contract(icapRegistrarAbi).at(ibanNameregAddress)
+};
+
+
+},{"../contracts/GlobalRegistrar.json":1,"../contracts/ICAPRegistrar.json":2,"./contract":25}],42:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -4277,7 +5631,7 @@ Property.prototype.request = function () {
module.exports = Property;
-},{"../utils/utils":7,"./requestmanager":28}],28:[function(require,module,exports){
+},{"../utils/utils":20,"./requestmanager":43}],43:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -4427,8 +5781,6 @@ RequestManager.prototype.setProvider = function (p) {
}
};
-/*jshint maxparams:4 */
-
/**
* Should be used to start polling
*
@@ -4441,9 +5793,8 @@ RequestManager.prototype.setProvider = function (p) {
* @todo cleanup number of params
*/
RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) {
- this.polls['poll_'+ pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall};
+ this.polls[pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall};
};
-/*jshint maxparams:3 */
/**
* Should be used to stop polling for filter with given id
@@ -4452,7 +5803,7 @@ RequestManager.prototype.startPolling = function (data, pollId, callback, uninst
* @param {Number} pollId
*/
RequestManager.prototype.stopPolling = function (pollId) {
- delete this.polls['poll_'+ pollId];
+ delete this.polls[pollId];
};
/**
@@ -4542,77 +5893,7 @@ RequestManager.prototype.poll = function () {
module.exports = RequestManager;
-},{"../utils/config":5,"../utils/utils":7,"./errors":14,"./jsonrpc":23}],29:[function(require,module,exports){
-/*
- This file is part of ethereum.js.
-
- ethereum.js is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- ethereum.js is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
-*/
-/** @file shh.js
- * @authors:
- * Marek Kotewicz <marek@ethdev.com>
- * @date 2015
- */
-
-var Method = require('./method');
-var formatters = require('./formatters');
-
-var post = new Method({
- name: 'post',
- call: 'shh_post',
- params: 1,
- inputFormatter: [formatters.inputPostFormatter]
-});
-
-var newIdentity = new Method({
- name: 'newIdentity',
- call: 'shh_newIdentity',
- params: 0
-});
-
-var hasIdentity = new Method({
- name: 'hasIdentity',
- call: 'shh_hasIdentity',
- params: 1
-});
-
-var newGroup = new Method({
- name: 'newGroup',
- call: 'shh_newGroup',
- params: 0
-});
-
-var addToGroup = new Method({
- name: 'addToGroup',
- call: 'shh_addToGroup',
- params: 0
-});
-
-var methods = [
- post,
- newIdentity,
- hasIdentity,
- newGroup,
- addToGroup
-];
-
-module.exports = {
- methods: methods
-};
-
-
-},{"./formatters":18,"./method":24}],30:[function(require,module,exports){
+},{"../utils/config":18,"../utils/utils":20,"./errors":26,"./jsonrpc":34}],44:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -4636,36 +5917,37 @@ module.exports = {
*/
var web3 = require('../web3');
-var ICAP = require('./icap');
-var namereg = require('./namereg');
+var Iban = require('./iban');
+var namereg = require('./namereg').ibanNamereg;
var contract = require('./contract');
+var exchangeAbi = require('../contracts/SmartExchange.json');
/**
- * Should be used to make ICAP transfer
+ * Should be used to make Iban transfer
*
* @method transfer
- * @param {String} iban number
- * @param {String} from (address)
+ * @param {String} from
+ * @param {String} to iban
* @param {Value} value to be tranfered
* @param {Function} callback, callback
*/
-var transfer = function (from, iban, value, callback) {
- var icap = new ICAP(iban);
- if (!icap.isValid()) {
+var transfer = function (from, to, value, callback) {
+ var iban = new Iban(to);
+ if (!iban.isValid()) {
throw new Error('invalid iban address');
}
- if (icap.isDirect()) {
- return transferToAddress(from, icap.address(), value, callback);
+ if (iban.isDirect()) {
+ return transferToAddress(from, iban.address(), value, callback);
}
if (!callback) {
- var address = namereg.addr(icap.institution());
- return deposit(from, address, value, icap.client());
+ var address = namereg.addr(iban.institution());
+ return deposit(from, address, value, iban.client());
}
- namereg.addr(icap.insitution(), function (err, address) {
- return deposit(from, address, value, icap.client(), callback);
+ namereg.addr(iban.institution(), function (err, address) {
+ return deposit(from, address, value, iban.client(), callback);
});
};
@@ -4674,14 +5956,14 @@ var transfer = function (from, iban, value, callback) {
* Should be used to transfer funds to certain address
*
* @method transferToAddress
- * @param {String} address
- * @param {String} from (address)
+ * @param {String} from
+ * @param {String} to
* @param {Value} value to be tranfered
* @param {Function} callback, callback
*/
-var transferToAddress = function (from, address, value, callback) {
+var transferToAddress = function (from, to, value, callback) {
return web3.eth.sendTransaction({
- address: address,
+ address: to,
from: from,
value: value
}, callback);
@@ -4691,15 +5973,15 @@ var transferToAddress = function (from, address, value, callback) {
* Should be used to deposit funds to generic Exchange contract (must implement deposit(bytes32) method!)
*
* @method deposit
- * @param {String} address
- * @param {String} from (address)
- * @param {Value} value to be tranfered
+ * @param {String} from
+ * @param {String} to
+ * @param {Value} value to be transfered
* @param {String} client unique identifier
* @param {Function} callback, callback
*/
-var deposit = function (from, address, value, client, callback) {
- var abi = [{"constant":false,"inputs":[{"name":"name","type":"bytes32"}],"name":"deposit","outputs":[],"type":"function"}];
- return contract(abi).at(address).deposit(client, {
+var deposit = function (from, to, value, client, callback) {
+ var abi = exchangeAbi;
+ return contract(abi).at(to).deposit(client, {
from: from,
value: value
}, callback);
@@ -4708,125 +5990,9 @@ var deposit = function (from, address, value, client, callback) {
module.exports = transfer;
-},{"../web3":9,"./contract":12,"./icap":21,"./namereg":25}],31:[function(require,module,exports){
-/*
- This file is part of ethereum.js.
-
- ethereum.js is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- ethereum.js is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
-*/
-/** @file watches.js
- * @authors:
- * Marek Kotewicz <marek@ethdev.com>
- * @date 2015
- */
-
-var Method = require('./method');
-
-/// @returns an array of objects describing web3.eth.filter api methods
-var eth = function () {
- var newFilterCall = function (args) {
- var type = args[0];
-
- switch(type) {
- case 'latest':
- args.shift();
- this.params = 0;
- return 'eth_newBlockFilter';
- case 'pending':
- args.shift();
- this.params = 0;
- return 'eth_newPendingTransactionFilter';
- default:
- return 'eth_newFilter';
- }
- };
-
- var newFilter = new Method({
- name: 'newFilter',
- call: newFilterCall,
- params: 1
- });
-
- var uninstallFilter = new Method({
- name: 'uninstallFilter',
- call: 'eth_uninstallFilter',
- params: 1
- });
-
- var getLogs = new Method({
- name: 'getLogs',
- call: 'eth_getFilterLogs',
- params: 1
- });
-
- var poll = new Method({
- name: 'poll',
- call: 'eth_getFilterChanges',
- params: 1
- });
-
- return [
- newFilter,
- uninstallFilter,
- getLogs,
- poll
- ];
-};
-
-/// @returns an array of objects describing web3.shh.watch api methods
-var shh = function () {
- var newFilter = new Method({
- name: 'newFilter',
- call: 'shh_newFilter',
- params: 1
- });
-
- var uninstallFilter = new Method({
- name: 'uninstallFilter',
- call: 'shh_uninstallFilter',
- params: 1
- });
-
- var getLogs = new Method({
- name: 'getLogs',
- call: 'shh_getMessages',
- params: 1
- });
-
- var poll = new Method({
- name: 'poll',
- call: 'shh_getFilterChanges',
- params: 1
- });
-
- return [
- newFilter,
- uninstallFilter,
- getLogs,
- poll
- ];
-};
-
-module.exports = {
- eth: eth,
- shh: shh
-};
-
-
-},{"./method":24}],32:[function(require,module,exports){
+},{"../contracts/SmartExchange.json":3,"../web3":22,"./contract":25,"./iban":32,"./namereg":41}],45:[function(require,module,exports){
-},{}],33:[function(require,module,exports){
+},{}],46:[function(require,module,exports){
;(function (root, factory) {
if (typeof exports === "object") {
// CommonJS
@@ -5569,7 +6735,7 @@ module.exports = {
return CryptoJS;
}));
-},{}],34:[function(require,module,exports){
+},{}],47:[function(require,module,exports){
;(function (root, factory, undef) {
if (typeof exports === "object") {
// CommonJS
@@ -5893,7 +7059,7 @@ module.exports = {
return CryptoJS.SHA3;
}));
-},{"./core":33,"./x64-core":35}],35:[function(require,module,exports){
+},{"./core":46,"./x64-core":48}],48:[function(require,module,exports){
;(function (root, factory) {
if (typeof exports === "object") {
// CommonJS
@@ -6198,7 +7364,7 @@ module.exports = {
return CryptoJS;
}));
-},{"./core":33}],"bignumber.js":[function(require,module,exports){
+},{"./core":46}],"bignumber.js":[function(require,module,exports){
'use strict';
module.exports = BigNumber; // jshint ignore:line
@@ -6206,13 +7372,16 @@ module.exports = BigNumber; // jshint ignore:line
},{}],"web3":[function(require,module,exports){
var web3 = require('./lib/web3');
+var namereg = require('./lib/web3/namereg');
web3.providers.HttpProvider = require('./lib/web3/httpprovider');
web3.providers.IpcProvider = require('./lib/web3/ipcprovider');
web3.eth.contract = require('./lib/web3/contract');
-web3.eth.namereg = require('./lib/web3/namereg');
+web3.eth.namereg = namereg.namereg;
+web3.eth.ibanNamereg = namereg.ibanNamereg;
web3.eth.sendIBANTransaction = require('./lib/web3/transfer');
+web3.eth.iban = require('./lib/web3/iban');
// dont override global variable
if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {
@@ -6222,6 +7391,6 @@ if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {
module.exports = web3;
-},{"./lib/web3":9,"./lib/web3/contract":12,"./lib/web3/httpprovider":20,"./lib/web3/ipcprovider":22,"./lib/web3/namereg":25,"./lib/web3/transfer":30}]},{},["web3"])
+},{"./lib/web3":22,"./lib/web3/contract":25,"./lib/web3/httpprovider":31,"./lib/web3/iban":32,"./lib/web3/ipcprovider":33,"./lib/web3/namereg":41,"./lib/web3/transfer":44}]},{},["web3"])
//# sourceMappingURL=web3-light.js.map
`
diff --git a/jsre/jsre.go b/jsre/jsre.go
index d4c982897..0db9e33fc 100644
--- a/jsre/jsre.go
+++ b/jsre/jsre.go
@@ -65,8 +65,8 @@ func New(assetPath string) *JSRE {
}
re.loopWg.Add(1)
go re.runEventLoop()
- re.Compile("pp.js", pp_js) // load prettyprint func definition
re.Set("loadScript", re.loadScript)
+ re.Set("inspect", prettyPrintJS)
return re
}
@@ -255,35 +255,19 @@ func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value {
return otto.TrueValue()
}
-// PrettyPrint writes v to standard output.
-func (self *JSRE) PrettyPrint(v interface{}) (val otto.Value, err error) {
- var method otto.Value
+// EvalAndPrettyPrint evaluates code and pretty prints the result to
+// standard output.
+func (self *JSRE) EvalAndPrettyPrint(code string) (err error) {
self.do(func(vm *otto.Otto) {
- val, err = vm.ToValue(v)
+ var val otto.Value
+ val, err = vm.Run(code)
if err != nil {
return
}
- method, err = vm.Get("prettyPrint")
- if err != nil {
- return
- }
- val, err = method.Call(method, val)
+ prettyPrint(vm, val)
+ fmt.Println()
})
- return val, err
-}
-
-// Eval evaluates JS function and returns result in a pretty printed string format.
-func (self *JSRE) Eval(code string) (s string, err error) {
- var val otto.Value
- val, err = self.Run(code)
- if err != nil {
- return
- }
- val, err = self.PrettyPrint(val)
- if err != nil {
- return
- }
- return fmt.Sprintf("%v", val), nil
+ return err
}
// Compile compiles and then runs a piece of JS code.
diff --git a/jsre/jsre_test.go b/jsre/jsre_test.go
index 93dc7d1f9..8450f546c 100644
--- a/jsre/jsre_test.go
+++ b/jsre/jsre_test.go
@@ -103,19 +103,14 @@ func TestNatto(t *testing.T) {
func TestBind(t *testing.T) {
jsre := New("")
+ defer jsre.Stop(false)
jsre.Bind("no", &testNativeObjectBinding{})
- val, err := jsre.Run(`no.TestMethod("testMsg")`)
+ _, err := jsre.Run(`no.TestMethod("testMsg")`)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
- pp, err := jsre.PrettyPrint(val)
- if err != nil {
- t.Errorf("expected no error, got %v", err)
- }
- t.Logf("no: %v", pp)
- jsre.Stop(false)
}
func TestLoadScript(t *testing.T) {
@@ -139,4 +134,4 @@ func TestLoadScript(t *testing.T) {
t.Errorf("expected '%v', got '%v'", exp, got)
}
jsre.Stop(false)
-} \ No newline at end of file
+}
diff --git a/jsre/pp_js.go b/jsre/pp_js.go
deleted file mode 100644
index 80fe523c1..000000000
--- a/jsre/pp_js.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package jsre
-
-const pp_js = `
-function pp(object, indent) {
- try {
- JSON.stringify(object)
- } catch(e) {
- return pp(e, indent);
- }
-
- var str = "";
- if(object instanceof Array) {
- str += "[";
- for(var i = 0, l = object.length; i < l; i++) {
- str += pp(object[i], indent);
-
- if(i < l-1) {
- str += ", ";
- }
- }
- str += " ]";
- } else if (object instanceof Error) {
- str += "\033[31m" + "Error:\033[0m " + object.message;
- } else if (isBigNumber(object)) {
- str += "\033[32m'" + object.toString(10) + "'";
- } else if(typeof(object) === "object") {
- str += "{\n";
- indent += " ";
-
- var fields = getFields(object);
- var last = fields[fields.length - 1];
- fields.forEach(function (key) {
- str += indent + key + ": ";
- try {
- str += pp(object[key], indent);
- } catch (e) {
- str += pp(e, indent);
- }
- if(key !== last) {
- str += ",";
- }
- str += "\n";
- });
- str += indent.substr(2, indent.length) + "}";
- } else if(typeof(object) === "string") {
- str += "\033[32m'" + object + "'";
- } else if(typeof(object) === "undefined") {
- str += "\033[1m\033[30m" + object;
- } else if(typeof(object) === "number") {
- str += "\033[31m" + object;
- } else if(typeof(object) === "function") {
- str += "\033[35m" + object.toString().split(" {")[0];
- } else {
- str += object;
- }
-
- str += "\033[0m";
-
- return str;
-}
-
-var redundantFields = [
- 'valueOf',
- 'toString',
- 'toLocaleString',
- 'hasOwnProperty',
- 'isPrototypeOf',
- 'propertyIsEnumerable',
- 'constructor'
-];
-
-var getFields = function (object) {
- var members = Object.getOwnPropertyNames(object);
- if (object.constructor && object.constructor.prototype) {
- members = members.concat(Object.getOwnPropertyNames(object.constructor.prototype));
- }
-
- var fields = members.filter(function (member) {
- return !isMemberFunction(object, member)
- }).sort()
- var funcs = members.filter(function (member) {
- return isMemberFunction(object, member)
- }).sort()
-
- var results = fields.concat(funcs);
- return results.filter(function (field) {
- return redundantFields.indexOf(field) === -1;
- });
-};
-
-var isMemberFunction = function(object, member) {
- try {
- return typeof(object[member]) === "function";
- } catch(e) {
- return false;
- }
-}
-
-var isBigNumber = function (object) {
- var result = typeof BigNumber !== 'undefined' && object instanceof BigNumber;
-
- if (!result) {
- if (typeof(object) === "object" && object.constructor != null) {
- result = object.constructor.toString().indexOf("function BigNumber(") == 0;
- }
- }
-
- return result
-};
-
-function prettyPrint(/* */) {
- var args = arguments;
- var ret = "";
- for(var i = 0, l = args.length; i < l; i++) {
- ret += pp(args[i], "") + "\n";
- }
- return ret;
-}
-
-var print = prettyPrint;
-`
diff --git a/jsre/pretty.go b/jsre/pretty.go
new file mode 100644
index 000000000..99aa9b33e
--- /dev/null
+++ b/jsre/pretty.go
@@ -0,0 +1,231 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package jsre
+
+import (
+ "fmt"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/fatih/color"
+ "github.com/robertkrimen/otto"
+)
+
+const (
+ maxPrettyPrintLevel = 3
+ indentString = " "
+)
+
+var (
+ functionColor = color.New(color.FgMagenta)
+ specialColor = color.New(color.Bold)
+ numberColor = color.New(color.FgRed)
+ stringColor = color.New(color.FgGreen)
+)
+
+// these fields are hidden when printing objects.
+var boringKeys = map[string]bool{
+ "valueOf": true,
+ "toString": true,
+ "toLocaleString": true,
+ "hasOwnProperty": true,
+ "isPrototypeOf": true,
+ "propertyIsEnumerable": true,
+ "constructor": true,
+}
+
+// prettyPrint writes value to standard output.
+func prettyPrint(vm *otto.Otto, value otto.Value) {
+ ppctx{vm}.printValue(value, 0, false)
+}
+
+func prettyPrintJS(call otto.FunctionCall) otto.Value {
+ for _, v := range call.ArgumentList {
+ prettyPrint(call.Otto, v)
+ fmt.Println()
+ }
+ return otto.UndefinedValue()
+}
+
+type ppctx struct{ vm *otto.Otto }
+
+func (ctx ppctx) indent(level int) string {
+ return strings.Repeat(indentString, level)
+}
+
+func (ctx ppctx) printValue(v otto.Value, level int, inArray bool) {
+ switch {
+ case v.IsObject():
+ ctx.printObject(v.Object(), level, inArray)
+ case v.IsNull():
+ specialColor.Print("null")
+ case v.IsUndefined():
+ specialColor.Print("undefined")
+ case v.IsString():
+ s, _ := v.ToString()
+ stringColor.Printf("%q", s)
+ case v.IsBoolean():
+ b, _ := v.ToBoolean()
+ specialColor.Printf("%t", b)
+ case v.IsNaN():
+ numberColor.Printf("NaN")
+ case v.IsNumber():
+ s, _ := v.ToString()
+ numberColor.Printf("%s", s)
+ default:
+ fmt.Printf("<unprintable>")
+ }
+}
+
+func (ctx ppctx) printObject(obj *otto.Object, level int, inArray bool) {
+ switch obj.Class() {
+ case "Array":
+ lv, _ := obj.Get("length")
+ len, _ := lv.ToInteger()
+ if len == 0 {
+ fmt.Printf("[]")
+ return
+ }
+ if level > maxPrettyPrintLevel {
+ fmt.Print("[...]")
+ return
+ }
+ fmt.Print("[")
+ for i := int64(0); i < len; i++ {
+ el, err := obj.Get(strconv.FormatInt(i, 10))
+ if err == nil {
+ ctx.printValue(el, level+1, true)
+ }
+ if i < len-1 {
+ fmt.Printf(", ")
+ }
+ }
+ fmt.Print("]")
+
+ case "Object":
+ // Print values from bignumber.js as regular numbers.
+ if ctx.isBigNumber(obj) {
+ numberColor.Print(toString(obj))
+ return
+ }
+ // Otherwise, print all fields indented, but stop if we're too deep.
+ keys := ctx.fields(obj)
+ if len(keys) == 0 {
+ fmt.Print("{}")
+ return
+ }
+ if level > maxPrettyPrintLevel {
+ fmt.Print("{...}")
+ return
+ }
+ fmt.Println("{")
+ for i, k := range keys {
+ v, _ := obj.Get(k)
+ fmt.Printf("%s%s: ", ctx.indent(level+1), k)
+ ctx.printValue(v, level+1, false)
+ if i < len(keys)-1 {
+ fmt.Printf(",")
+ }
+ fmt.Println()
+ }
+ if inArray {
+ level--
+ }
+ fmt.Printf("%s}", ctx.indent(level))
+
+ case "Function":
+ // Use toString() to display the argument list if possible.
+ if robj, err := obj.Call("toString"); err != nil {
+ functionColor.Print("function()")
+ } else {
+ desc := strings.Trim(strings.Split(robj.String(), "{")[0], " \t\n")
+ desc = strings.Replace(desc, " (", "(", 1)
+ functionColor.Print(desc)
+ }
+
+ case "RegExp":
+ stringColor.Print(toString(obj))
+
+ default:
+ if v, _ := obj.Get("toString"); v.IsFunction() && level <= maxPrettyPrintLevel {
+ s, _ := obj.Call("toString")
+ fmt.Printf("<%s %s>", obj.Class(), s.String())
+ } else {
+ fmt.Printf("<%s>", obj.Class())
+ }
+ }
+}
+
+func (ctx ppctx) fields(obj *otto.Object) []string {
+ var (
+ vals, methods []string
+ seen = make(map[string]bool)
+ )
+ add := func(k string) {
+ if seen[k] || boringKeys[k] {
+ return
+ }
+ seen[k] = true
+ if v, _ := obj.Get(k); v.IsFunction() {
+ methods = append(methods, k)
+ } else {
+ vals = append(vals, k)
+ }
+ }
+ // add own properties
+ ctx.doOwnProperties(obj.Value(), add)
+ // add properties of the constructor
+ if cp := constructorPrototype(obj); cp != nil {
+ ctx.doOwnProperties(cp.Value(), add)
+ }
+ sort.Strings(vals)
+ sort.Strings(methods)
+ return append(vals, methods...)
+}
+
+func (ctx ppctx) doOwnProperties(v otto.Value, f func(string)) {
+ Object, _ := ctx.vm.Object("Object")
+ rv, _ := Object.Call("getOwnPropertyNames", v)
+ gv, _ := rv.Export()
+ for _, v := range gv.([]interface{}) {
+ f(v.(string))
+ }
+}
+
+func (ctx ppctx) isBigNumber(v *otto.Object) bool {
+ BigNumber, err := ctx.vm.Run("BigNumber.prototype")
+ if err != nil {
+ panic(err)
+ }
+ cp := constructorPrototype(v)
+ return cp != nil && cp.Value() == BigNumber
+}
+
+func toString(obj *otto.Object) string {
+ s, _ := obj.Call("toString")
+ return s.String()
+}
+
+func constructorPrototype(obj *otto.Object) *otto.Object {
+ if v, _ := obj.Get("constructor"); v.Object() != nil {
+ if v, _ = v.Object().Get("prototype"); v.Object() != nil {
+ return v.Object()
+ }
+ }
+ return nil
+}
diff --git a/miner/worker.go b/miner/worker.go
index 535ce5144..df3681470 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -100,7 +100,7 @@ type worker struct {
eth core.Backend
chain *core.ChainManager
proc *core.BlockProcessor
- extraDb common.Database
+ chainDb common.Database
coinbase common.Address
gasPrice *big.Int
@@ -126,7 +126,7 @@ func newWorker(coinbase common.Address, eth core.Backend) *worker {
worker := &worker{
eth: eth,
mux: eth.EventMux(),
- extraDb: eth.ExtraDb(),
+ chainDb: eth.ChainDb(),
recv: make(chan *Result, resultQueueSize),
gasPrice: new(big.Int),
chain: eth.ChainManager(),
@@ -291,9 +291,9 @@ func (self *worker) wait() {
// check if canon block and write transactions
if stat == core.CanonStatTy {
// This puts transactions in a extra db for rpc
- core.PutTransactions(self.extraDb, block, block.Transactions())
+ core.PutTransactions(self.chainDb, block, block.Transactions())
// store the receipts
- core.PutReceipts(self.extraDb, work.receipts)
+ core.PutReceipts(self.chainDb, work.receipts)
}
// broadcast before waiting for validation
@@ -344,7 +344,7 @@ func (self *worker) push(work *Work) {
// makeCurrent creates a new environment for the current cycle.
func (self *worker) makeCurrent(parent *types.Block, header *types.Header) {
- state := state.New(parent.Root(), self.eth.StateDb())
+ state := state.New(parent.Root(), self.eth.ChainDb())
work := &Work{
state: state,
ancestors: set.New(),
diff --git a/p2p/discover/table.go b/p2p/discover/table.go
index 67f7ec46f..b077f010c 100644
--- a/p2p/discover/table.go
+++ b/p2p/discover/table.go
@@ -78,9 +78,8 @@ type transport interface {
close()
}
-// bucket contains nodes, ordered by their last activity.
-// the entry that was most recently active is the last element
-// in entries.
+// bucket contains nodes, ordered by their last activity. the entry
+// that was most recently active is the first element in entries.
type bucket struct {
lastLookup time.Time
entries []*Node
@@ -235,7 +234,7 @@ func (tab *Table) Lookup(targetID NodeID) []*Node {
if fails >= maxFindnodeFailures {
glog.V(logger.Detail).Infof("Evacuating node %x: %d findnode failures", n.ID[:8], fails)
- tab.del(n)
+ tab.delete(n)
}
}
reply <- tab.bondall(r)
@@ -401,15 +400,11 @@ func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16
node = w.n
}
}
- // Even if bonding temporarily failed, give the node a chance
if node != nil {
- tab.mutex.Lock()
- defer tab.mutex.Unlock()
-
- b := tab.buckets[logdist(tab.self.sha, node.sha)]
- if !b.bump(node) {
- tab.pingreplace(node, b)
- }
+ // Add the node to the table even if the bonding ping/pong
+ // fails. It will be relaced quickly if it continues to be
+ // unresponsive.
+ tab.add(node)
tab.db.updateFindFails(id, 0)
}
return node, result
@@ -420,7 +415,7 @@ func (tab *Table) pingpong(w *bondproc, pinged bool, id NodeID, addr *net.UDPAdd
<-tab.bondslots
defer func() { tab.bondslots <- struct{}{} }()
- // Ping the remote side and wait for a pong
+ // Ping the remote side and wait for a pong.
if w.err = tab.ping(id, addr); w.err != nil {
close(w.done)
return
@@ -431,33 +426,14 @@ func (tab *Table) pingpong(w *bondproc, pinged bool, id NodeID, addr *net.UDPAdd
// waitping will simply time out.
tab.net.waitping(id)
}
- // Bonding succeeded, update the node database
+ // Bonding succeeded, update the node database.
w.n = newNode(id, addr.IP, uint16(addr.Port), tcpPort)
tab.db.updateNode(w.n)
close(w.done)
}
-func (tab *Table) pingreplace(new *Node, b *bucket) {
- if len(b.entries) == bucketSize {
- oldest := b.entries[bucketSize-1]
- if err := tab.ping(oldest.ID, oldest.addr()); err == nil {
- // The node responded, we don't need to replace it.
- return
- }
- } else {
- // Add a slot at the end so the last entry doesn't
- // fall off when adding the new node.
- b.entries = append(b.entries, nil)
- }
- copy(b.entries[1:], b.entries)
- b.entries[0] = new
- if tab.nodeAddedHook != nil {
- tab.nodeAddedHook(new)
- }
-}
-
-// ping a remote endpoint and wait for a reply, also updating the node database
-// accordingly.
+// ping a remote endpoint and wait for a reply, also updating the node
+// database accordingly.
func (tab *Table) ping(id NodeID, addr *net.UDPAddr) error {
// Update the last ping and send the message
tab.db.updateLastPing(id, time.Now())
@@ -467,24 +443,53 @@ func (tab *Table) ping(id NodeID, addr *net.UDPAddr) error {
// Pong received, update the database and return
tab.db.updateLastPong(id, time.Now())
tab.db.ensureExpirer()
-
return nil
}
-// add puts the entries into the table if their corresponding
-// bucket is not full. The caller must hold tab.mutex.
-func (tab *Table) add(entries []*Node) {
+// add attempts to add the given node its corresponding bucket. If the
+// bucket has space available, adding the node succeeds immediately.
+// Otherwise, the node is added if the least recently active node in
+// the bucket does not respond to a ping packet.
+//
+// The caller must not hold tab.mutex.
+func (tab *Table) add(new *Node) {
+ b := tab.buckets[logdist(tab.self.sha, new.sha)]
+ tab.mutex.Lock()
+ if b.bump(new) {
+ tab.mutex.Unlock()
+ return
+ }
+ var oldest *Node
+ if len(b.entries) == bucketSize {
+ oldest = b.entries[bucketSize-1]
+ // Let go of the mutex so other goroutines can access
+ // the table while we ping the least recently active node.
+ tab.mutex.Unlock()
+ if err := tab.ping(oldest.ID, oldest.addr()); err == nil {
+ // The node responded, don't replace it.
+ return
+ }
+ tab.mutex.Lock()
+ }
+ added := b.replace(new, oldest)
+ tab.mutex.Unlock()
+ if added && tab.nodeAddedHook != nil {
+ tab.nodeAddedHook(new)
+ }
+}
+
+// stuff adds nodes the table to the end of their corresponding bucket
+// if the bucket is not full. The caller must hold tab.mutex.
+func (tab *Table) stuff(nodes []*Node) {
outer:
- for _, n := range entries {
+ for _, n := range nodes {
if n.ID == tab.self.ID {
- // don't add self.
- continue
+ continue // don't add self
}
bucket := tab.buckets[logdist(tab.self.sha, n.sha)]
for i := range bucket.entries {
if bucket.entries[i].ID == n.ID {
- // already in bucket
- continue outer
+ continue outer // already in bucket
}
}
if len(bucket.entries) < bucketSize {
@@ -496,12 +501,11 @@ outer:
}
}
-// del removes an entry from the node table (used to evacuate failed/non-bonded
-// discovery peers).
-func (tab *Table) del(node *Node) {
+// delete removes an entry from the node table (used to evacuate
+// failed/non-bonded discovery peers).
+func (tab *Table) delete(node *Node) {
tab.mutex.Lock()
defer tab.mutex.Unlock()
-
bucket := tab.buckets[logdist(tab.self.sha, node.sha)]
for i := range bucket.entries {
if bucket.entries[i].ID == node.ID {
@@ -511,6 +515,27 @@ func (tab *Table) del(node *Node) {
}
}
+func (b *bucket) replace(n *Node, last *Node) bool {
+ // Don't add if b already contains n.
+ for i := range b.entries {
+ if b.entries[i].ID == n.ID {
+ return false
+ }
+ }
+ // Replace last if it is still the last entry or just add n if b
+ // isn't full. If is no longer the last entry, it has either been
+ // replaced with someone else or became active.
+ if len(b.entries) == bucketSize && (last == nil || b.entries[bucketSize-1].ID != last.ID) {
+ return false
+ }
+ if len(b.entries) < bucketSize {
+ b.entries = append(b.entries, nil)
+ }
+ copy(b.entries[1:], b.entries)
+ b.entries[0] = n
+ return true
+}
+
func (b *bucket) bump(n *Node) bool {
for i := range b.entries {
if b.entries[i].ID == n.ID {
diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go
index d259177bf..426f4e9cc 100644
--- a/p2p/discover/table_test.go
+++ b/p2p/discover/table_test.go
@@ -178,8 +178,8 @@ func TestTable_closest(t *testing.T) {
test := func(test *closeTest) bool {
// for any node table, Target and N
tab := newTable(nil, test.Self, &net.UDPAddr{}, "")
- tab.add(test.All)
defer tab.Close()
+ tab.stuff(test.All)
// check that doClosest(Target, N) returns nodes
result := tab.closest(test.Target, test.N).entries
@@ -240,7 +240,7 @@ func TestTable_ReadRandomNodesGetAll(t *testing.T) {
defer tab.Close()
for i := 0; i < len(buf); i++ {
ld := cfg.Rand.Intn(len(tab.buckets))
- tab.add([]*Node{nodeAtDistance(tab.self.sha, ld)})
+ tab.stuff([]*Node{nodeAtDistance(tab.self.sha, ld)})
}
gotN := tab.ReadRandomNodes(buf)
if gotN != tab.len() {
@@ -288,7 +288,7 @@ func TestTable_Lookup(t *testing.T) {
}
// seed table with initial node (otherwise lookup will terminate immediately)
seed := newNode(lookupTestnet.dists[256][0], net.IP{}, 256, 0)
- tab.add([]*Node{seed})
+ tab.stuff([]*Node{seed})
results := tab.Lookup(lookupTestnet.target)
t.Logf("results:")
diff --git a/p2p/discover/udp.go b/p2p/discover/udp.go
index d7ca9000d..008e63937 100644
--- a/p2p/discover/udp.go
+++ b/p2p/discover/udp.go
@@ -18,6 +18,7 @@ package discover
import (
"bytes"
+ "container/list"
"crypto/ecdsa"
"errors"
"fmt"
@@ -43,6 +44,7 @@ var (
errUnsolicitedReply = errors.New("unsolicited reply")
errUnknownNode = errors.New("unknown node")
errTimeout = errors.New("RPC timeout")
+ errClockWarp = errors.New("reply deadline too far in the future")
errClosed = errors.New("socket closed")
)
@@ -296,7 +298,7 @@ func (t *udp) pending(id NodeID, ptype byte, callback func(interface{}) bool) <-
}
func (t *udp) handleReply(from NodeID, ptype byte, req packet) bool {
- matched := make(chan bool)
+ matched := make(chan bool, 1)
select {
case t.gotreply <- reply{from, ptype, req, matched}:
// loop will handle it
@@ -310,68 +312,82 @@ func (t *udp) handleReply(from NodeID, ptype byte, req packet) bool {
// the refresh timer and the pending reply queue.
func (t *udp) loop() {
var (
- pending []*pending
- nextDeadline time.Time
- timeout = time.NewTimer(0)
- refresh = time.NewTicker(refreshInterval)
+ plist = list.New()
+ timeout = time.NewTimer(0)
+ nextTimeout *pending // head of plist when timeout was last reset
+ refresh = time.NewTicker(refreshInterval)
)
<-timeout.C // ignore first timeout
defer refresh.Stop()
defer timeout.Stop()
- rearmTimeout := func() {
- now := time.Now()
- if len(pending) == 0 || now.Before(nextDeadline) {
+ resetTimeout := func() {
+ if plist.Front() == nil || nextTimeout == plist.Front().Value {
return
}
- nextDeadline = pending[0].deadline
- timeout.Reset(nextDeadline.Sub(now))
+ // Start the timer so it fires when the next pending reply has expired.
+ now := time.Now()
+ for el := plist.Front(); el != nil; el = el.Next() {
+ nextTimeout = el.Value.(*pending)
+ if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout {
+ timeout.Reset(dist)
+ return
+ }
+ // Remove pending replies whose deadline is too far in the
+ // future. These can occur if the system clock jumped
+ // backwards after the deadline was assigned.
+ nextTimeout.errc <- errClockWarp
+ plist.Remove(el)
+ }
+ nextTimeout = nil
+ timeout.Stop()
}
for {
+ resetTimeout()
+
select {
case <-refresh.C:
go t.refresh()
case <-t.closing:
- for _, p := range pending {
- p.errc <- errClosed
+ for el := plist.Front(); el != nil; el = el.Next() {
+ el.Value.(*pending).errc <- errClosed
}
- pending = nil
return
case p := <-t.addpending:
p.deadline = time.Now().Add(respTimeout)
- pending = append(pending, p)
- rearmTimeout()
+ plist.PushBack(p)
case r := <-t.gotreply:
var matched bool
- for i := 0; i < len(pending); i++ {
- if p := pending[i]; p.from == r.from && p.ptype == r.ptype {
+ for el := plist.Front(); el != nil; el = el.Next() {
+ p := el.Value.(*pending)
+ if p.from == r.from && p.ptype == r.ptype {
matched = true
+ // Remove the matcher if its callback indicates
+ // that all replies have been received. This is
+ // required for packet types that expect multiple
+ // reply packets.
if p.callback(r.data) {
- // callback indicates the request is done, remove it.
p.errc <- nil
- copy(pending[i:], pending[i+1:])
- pending = pending[:len(pending)-1]
- i--
+ plist.Remove(el)
}
}
}
r.matched <- matched
case now := <-timeout.C:
- // notify and remove callbacks whose deadline is in the past.
- i := 0
- for ; i < len(pending) && now.After(pending[i].deadline); i++ {
- pending[i].errc <- errTimeout
- }
- if i > 0 {
- copy(pending, pending[i:])
- pending = pending[:len(pending)-i]
+ nextTimeout = nil
+ // Notify and remove callbacks whose deadline is in the past.
+ for el := plist.Front(); el != nil; el = el.Next() {
+ p := el.Value.(*pending)
+ if now.After(p.deadline) || now.Equal(p.deadline) {
+ p.errc <- errTimeout
+ plist.Remove(el)
+ }
}
- rearmTimeout()
}
}
}
@@ -385,7 +401,7 @@ const (
var (
headSpace = make([]byte, headSize)
- // Neighbors responses are sent across multiple packets to
+ // Neighbors replies are sent across multiple packets to
// stay below the 1280 byte limit. We compute the maximum number
// of entries by stuffing a packet until it grows too large.
maxNeighbors int
diff --git a/p2p/discover/udp_test.go b/p2p/discover/udp_test.go
index 8d6d3e855..a86d3737b 100644
--- a/p2p/discover/udp_test.go
+++ b/p2p/discover/udp_test.go
@@ -19,10 +19,12 @@ package discover
import (
"bytes"
"crypto/ecdsa"
+ "encoding/binary"
"errors"
"fmt"
"io"
logpkg "log"
+ "math/rand"
"net"
"os"
"path/filepath"
@@ -138,6 +140,77 @@ func TestUDP_pingTimeout(t *testing.T) {
}
}
+func TestUDP_responseTimeouts(t *testing.T) {
+ t.Parallel()
+ test := newUDPTest(t)
+ defer test.table.Close()
+
+ rand.Seed(time.Now().UnixNano())
+ randomDuration := func(max time.Duration) time.Duration {
+ return time.Duration(rand.Int63n(int64(max)))
+ }
+
+ var (
+ nReqs = 200
+ nTimeouts = 0 // number of requests with ptype > 128
+ nilErr = make(chan error, nReqs) // for requests that get a reply
+ timeoutErr = make(chan error, nReqs) // for requests that time out
+ )
+ for i := 0; i < nReqs; i++ {
+ // Create a matcher for a random request in udp.loop. Requests
+ // with ptype <= 128 will not get a reply and should time out.
+ // For all other requests, a reply is scheduled to arrive
+ // within the timeout window.
+ p := &pending{
+ ptype: byte(rand.Intn(255)),
+ callback: func(interface{}) bool { return true },
+ }
+ binary.BigEndian.PutUint64(p.from[:], uint64(i))
+ if p.ptype <= 128 {
+ p.errc = timeoutErr
+ nTimeouts++
+ } else {
+ p.errc = nilErr
+ time.AfterFunc(randomDuration(60*time.Millisecond), func() {
+ if !test.udp.handleReply(p.from, p.ptype, nil) {
+ t.Logf("not matched: %v", p)
+ }
+ })
+ }
+ test.udp.addpending <- p
+ time.Sleep(randomDuration(30 * time.Millisecond))
+ }
+
+ // Check that all timeouts were delivered and that the rest got nil errors.
+ // The replies must be delivered.
+ var (
+ recvDeadline = time.After(20 * time.Second)
+ nTimeoutsRecv, nNil = 0, 0
+ )
+ for i := 0; i < nReqs; i++ {
+ select {
+ case err := <-timeoutErr:
+ if err != errTimeout {
+ t.Fatalf("got non-timeout error on timeoutErr %d: %v", i, err)
+ }
+ nTimeoutsRecv++
+ case err := <-nilErr:
+ if err != nil {
+ t.Fatalf("got non-nil error on nilErr %d: %v", i, err)
+ }
+ nNil++
+ case <-recvDeadline:
+ t.Fatalf("exceeded recv deadline")
+ }
+ }
+ if nTimeoutsRecv != nTimeouts {
+ t.Errorf("wrong number of timeout errors received: got %d, want %d", nTimeoutsRecv, nTimeouts)
+ }
+ if nNil != nReqs-nTimeouts {
+ t.Errorf("wrong number of successful replies: got %d, want %d", nNil, nReqs-nTimeouts)
+ }
+}
+
func TestUDP_findnodeTimeout(t *testing.T) {
t.Parallel()
test := newUDPTest(t)
@@ -167,7 +240,7 @@ func TestUDP_findnode(t *testing.T) {
for i := 0; i < bucketSize; i++ {
nodes.push(nodeAtDistance(test.table.self.sha, i+2), bucketSize)
}
- test.table.add(nodes.entries)
+ test.table.stuff(nodes.entries)
// ensure there's a bond with the test node,
// findnode won't be accepted otherwise.
diff --git a/p2p/peer_error.go b/p2p/peer_error.go
index b1762a6ee..62c7b665d 100644
--- a/p2p/peer_error.go
+++ b/p2p/peer_error.go
@@ -66,7 +66,7 @@ const (
DiscUnexpectedIdentity
DiscSelf
DiscReadTimeout
- DiscSubprotocolError
+ DiscSubprotocolError = 0x10
)
var discReasonToString = [...]string{
diff --git a/p2p/rlpx.go b/p2p/rlpx.go
index fd43f565e..aaa733854 100644
--- a/p2p/rlpx.go
+++ b/p2p/rlpx.go
@@ -267,6 +267,10 @@ func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID d
}
func newInitiatorHandshake(remoteID discover.NodeID) (*encHandshake, error) {
+ rpub, err := remoteID.Pubkey()
+ if err != nil {
+ return nil, fmt.Errorf("bad remoteID: %v", err)
+ }
// generate random initiator nonce
n := make([]byte, shaLen)
if _, err := rand.Read(n); err != nil {
@@ -277,10 +281,6 @@ func newInitiatorHandshake(remoteID discover.NodeID) (*encHandshake, error) {
if err != nil {
return nil, err
}
- rpub, err := remoteID.Pubkey()
- if err != nil {
- return nil, fmt.Errorf("bad remoteID: %v", err)
- }
h := &encHandshake{
initiator: true,
remoteID: remoteID,
@@ -417,6 +417,14 @@ func decodeAuthMsg(prv *ecdsa.PrivateKey, token []byte, auth []byte) (*encHandsh
if err != nil {
return nil, err
}
+
+ // validate the sha3 of recovered pubkey
+ remoteRandomPubMAC := msg[sigLen : sigLen+shaLen]
+ shaRemoteRandomPub := crypto.Sha3(remoteRandomPub[1:])
+ if !bytes.Equal(remoteRandomPubMAC, shaRemoteRandomPub) {
+ return nil, fmt.Errorf("sha3 of recovered ephemeral pubkey does not match checksum in auth message")
+ }
+
h.remoteRandomPub, _ = importPublicKey(remoteRandomPub)
return h, nil
}
diff --git a/rlp/decode.go b/rlp/decode.go
index c0b5f0699..1381f5274 100644
--- a/rlp/decode.go
+++ b/rlp/decode.go
@@ -183,6 +183,8 @@ func makeDecoder(typ reflect.Type, tags tags) (dec decoder, err error) {
return decodeBigIntNoPtr, nil
case isUint(kind):
return decodeUint, nil
+ case kind == reflect.Bool:
+ return decodeBool, nil
case kind == reflect.String:
return decodeString, nil
case kind == reflect.Slice || kind == reflect.Array:
@@ -211,6 +213,15 @@ func decodeUint(s *Stream, val reflect.Value) error {
return nil
}
+func decodeBool(s *Stream, val reflect.Value) error {
+ b, err := s.Bool()
+ if err != nil {
+ return wrapStreamError(err, val.Type())
+ }
+ val.SetBool(b)
+ return nil
+}
+
func decodeString(s *Stream, val reflect.Value) error {
b, err := s.Bytes()
if err != nil {
@@ -697,6 +708,24 @@ func (s *Stream) uint(maxbits int) (uint64, error) {
}
}
+// Bool reads an RLP string of up to 1 byte and returns its contents
+// as an boolean. If the input does not contain an RLP string, the
+// returned error will be ErrExpectedString.
+func (s *Stream) Bool() (bool, error) {
+ num, err := s.uint(8)
+ if err != nil {
+ return false, err
+ }
+ switch num {
+ case 0:
+ return false, nil
+ case 1:
+ return true, nil
+ default:
+ return false, fmt.Errorf("rlp: invalid boolean value: %d", num)
+ }
+}
+
// List starts decoding an RLP list. If the input does not contain a
// list, the returned error will be ErrExpectedList. When the list's
// end has been reached, any Stream operation will return EOL.
diff --git a/rlp/decode_test.go b/rlp/decode_test.go
index 331faa9d8..d6b0611dd 100644
--- a/rlp/decode_test.go
+++ b/rlp/decode_test.go
@@ -19,6 +19,7 @@ package rlp
import (
"bytes"
"encoding/hex"
+ "errors"
"fmt"
"io"
"math/big"
@@ -116,6 +117,9 @@ func TestStreamErrors(t *testing.T) {
{"817F", calls{"Uint"}, nil, ErrCanonSize},
{"8180", calls{"Uint"}, nil, nil},
+ // Non-valid boolean
+ {"02", calls{"Bool"}, nil, errors.New("rlp: invalid boolean value: 2")},
+
// Size tags must use the smallest possible encoding.
// Leading zero bytes in the size tag are also rejected.
{"8100", calls{"Uint"}, nil, ErrCanonSize},
@@ -315,6 +319,11 @@ var (
)
var decodeTests = []decodeTest{
+ // booleans
+ {input: "01", ptr: new(bool), value: true},
+ {input: "80", ptr: new(bool), value: false},
+ {input: "02", ptr: new(bool), error: "rlp: invalid boolean value: 2"},
+
// integers
{input: "05", ptr: new(uint32), value: uint32(5)},
{input: "80", ptr: new(uint32), value: uint32(0)},
diff --git a/rlp/encode.go b/rlp/encode.go
index 0ddef7bbb..b525ae4e7 100644
--- a/rlp/encode.go
+++ b/rlp/encode.go
@@ -361,6 +361,8 @@ func makeWriter(typ reflect.Type) (writer, error) {
return writeBigIntNoPtr, nil
case isUint(kind):
return writeUint, nil
+ case kind == reflect.Bool:
+ return writeBool, nil
case kind == reflect.String:
return writeString, nil
case kind == reflect.Slice && isByte(typ.Elem()):
@@ -398,6 +400,15 @@ func writeUint(val reflect.Value, w *encbuf) error {
return nil
}
+func writeBool(val reflect.Value, w *encbuf) error {
+ if val.Bool() {
+ w.str = append(w.str, 0x01)
+ } else {
+ w.str = append(w.str, 0x80)
+ }
+ return nil
+}
+
func writeBigIntPtr(val reflect.Value, w *encbuf) error {
ptr := val.Interface().(*big.Int)
if ptr == nil {
diff --git a/rlp/encode_test.go b/rlp/encode_test.go
index e83c76b51..60bd95692 100644
--- a/rlp/encode_test.go
+++ b/rlp/encode_test.go
@@ -71,6 +71,10 @@ type encTest struct {
}
var encTests = []encTest{
+ // booleans
+ {val: true, output: "01"},
+ {val: false, output: "80"},
+
// integers
{val: uint32(0), output: "80"},
{val: uint32(127), output: "7F"},
diff --git a/rpc/api/admin.go b/rpc/api/admin.go
index 29f342ab6..5e392ae32 100644
--- a/rpc/api/admin.go
+++ b/rpc/api/admin.go
@@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms"
"github.com/ethereum/go-ethereum/rpc/shared"
+ "github.com/ethereum/go-ethereum/rpc/useragent"
"github.com/ethereum/go-ethereum/xeth"
)
@@ -71,6 +72,7 @@ var (
"admin_httpGet": (*adminApi).HttpGet,
"admin_sleepBlocks": (*adminApi).SleepBlocks,
"admin_sleep": (*adminApi).Sleep,
+ "admin_enableUserAgent": (*adminApi).EnableUserAgent,
}
)
@@ -474,3 +476,10 @@ func (self *adminApi) HttpGet(req *shared.Request) (interface{}, error) {
return string(resp), nil
}
+
+func (self *adminApi) EnableUserAgent(req *shared.Request) (interface{}, error) {
+ if fe, ok := self.xeth.Frontend().(*useragent.RemoteFrontend); ok {
+ fe.Enable()
+ }
+ return true, nil
+}
diff --git a/rpc/api/debug.go b/rpc/api/debug.go
index cdacd6c62..d325b1720 100644
--- a/rpc/api/debug.go
+++ b/rpc/api/debug.go
@@ -119,7 +119,7 @@ func (self *debugApi) DumpBlock(req *shared.Request) (interface{}, error) {
return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
}
- stateDb := state.New(block.Root(), self.ethereum.StateDb())
+ stateDb := state.New(block.Root(), self.ethereum.ChainDb())
if stateDb == nil {
return nil, nil
}
diff --git a/rpc/api/eth_args.go b/rpc/api/eth_args.go
index 5a1841cbe..8bd077e20 100644
--- a/rpc/api/eth_args.go
+++ b/rpc/api/eth_args.go
@@ -908,14 +908,14 @@ func (args *SubmitWorkArgs) UnmarshalJSON(b []byte) (err error) {
type tx struct {
tx *types.Transaction
- To string
- From string
- Nonce string
- Value string
- Data string
- GasLimit string
- GasPrice string
- Hash string
+ To string `json:"to"`
+ From string `json:"from"`
+ Nonce string `json:"nonce"`
+ Value string `json:"value"`
+ Data string `json:"data"`
+ GasLimit string `json:"gas"`
+ GasPrice string `json:"gasPrice"`
+ Hash string `json:"hash"`
}
func newTx(t *types.Transaction) *tx {
diff --git a/rpc/api/net.go b/rpc/api/net.go
index 39c230e14..9c6369615 100644
--- a/rpc/api/net.go
+++ b/rpc/api/net.go
@@ -32,7 +32,7 @@ var (
netMapping = map[string]nethandler{
"net_peerCount": (*netApi).PeerCount,
"net_listening": (*netApi).IsListening,
- "net_version": (*netApi).Version,
+ "net_version": (*netApi).Version,
}
)
@@ -97,4 +97,3 @@ func (self *netApi) IsListening(req *shared.Request) (interface{}, error) {
func (self *netApi) Version(req *shared.Request) (interface{}, error) {
return self.xeth.NetworkVersion(), nil
}
-
diff --git a/rpc/api/personal.go b/rpc/api/personal.go
index e9942c1e5..6c73ac83d 100644
--- a/rpc/api/personal.go
+++ b/rpc/api/personal.go
@@ -17,6 +17,7 @@
package api
import (
+ "fmt"
"time"
"github.com/ethereum/go-ethereum/common"
@@ -125,18 +126,17 @@ func (self *personalApi) UnlockAccount(req *shared.Request) (interface{}, error)
return nil, shared.NewDecodeParamError(err.Error())
}
- var err error
+ if len(args.Passphrase) == 0 {
+ fe := self.xeth.Frontend()
+ if fe == nil {
+ return false, fmt.Errorf("No password provided")
+ }
+ return fe.UnlockAccount(common.HexToAddress(args.Address).Bytes()), nil
+ }
+
am := self.ethereum.AccountManager()
addr := common.HexToAddress(args.Address)
- if args.Duration == -1 {
- err = am.Unlock(addr, args.Passphrase)
- } else {
- err = am.TimedUnlock(addr, args.Passphrase, time.Duration(args.Duration)*time.Second)
- }
-
- if err == nil {
- return true, nil
- }
- return false, err
+ err := am.TimedUnlock(addr, args.Passphrase, time.Duration(args.Duration)*time.Second)
+ return err == nil, err
}
diff --git a/rpc/api/personal_args.go b/rpc/api/personal_args.go
index 7f00701e3..5a584fb0c 100644
--- a/rpc/api/personal_args.go
+++ b/rpc/api/personal_args.go
@@ -86,10 +86,10 @@ func (args *UnlockAccountArgs) UnmarshalJSON(b []byte) (err error) {
return shared.NewDecodeParamError(err.Error())
}
- args.Duration = -1
+ args.Duration = 0
- if len(obj) < 2 {
- return shared.NewInsufficientParamsError(len(obj), 2)
+ if len(obj) < 1 {
+ return shared.NewInsufficientParamsError(len(obj), 1)
}
if addrstr, ok := obj[0].(string); ok {
@@ -98,10 +98,18 @@ func (args *UnlockAccountArgs) UnmarshalJSON(b []byte) (err error) {
return shared.NewInvalidTypeError("address", "not a string")
}
- if passphrasestr, ok := obj[1].(string); ok {
- args.Passphrase = passphrasestr
- } else {
- return shared.NewInvalidTypeError("passphrase", "not a string")
+ if len(obj) >= 2 && obj[1] != nil {
+ if passphrasestr, ok := obj[1].(string); ok {
+ args.Passphrase = passphrasestr
+ } else {
+ return shared.NewInvalidTypeError("passphrase", "not a string")
+ }
+ }
+
+ if len(obj) >= 3 && obj[2] != nil {
+ if duration, ok := obj[2].(float64); ok {
+ args.Duration = int(duration)
+ }
}
return nil
diff --git a/rpc/api/ssh_js.go b/rpc/api/shh_js.go
index a92ad1644..a92ad1644 100644
--- a/rpc/api/ssh_js.go
+++ b/rpc/api/shh_js.go
diff --git a/rpc/codec/codec.go b/rpc/codec/codec.go
index 2fdb0d8f3..786080b44 100644
--- a/rpc/codec/codec.go
+++ b/rpc/codec/codec.go
@@ -31,6 +31,8 @@ type ApiCoder interface {
ReadRequest() ([]*shared.Request, bool, error)
// Parse response message from underlying stream
ReadResponse() (interface{}, error)
+ // Read raw message from underlying stream
+ Recv() (interface{}, error)
// Encode response to encoded form in underlying stream
WriteResponse(interface{}) error
// Decode single message from data
diff --git a/rpc/codec/json.go b/rpc/codec/json.go
index d811b2096..cfc449143 100644
--- a/rpc/codec/json.go
+++ b/rpc/codec/json.go
@@ -21,6 +21,7 @@ import (
"fmt"
"net"
"time"
+ "strings"
"github.com/ethereum/go-ethereum/rpc/shared"
)
@@ -73,35 +74,41 @@ func (self *JsonCodec) ReadRequest() (requests []*shared.Request, isBatch bool,
return nil, false, err
}
-func (self *JsonCodec) ReadResponse() (interface{}, error) {
- bytesInBuffer := 0
- buf := make([]byte, MAX_RESPONSE_SIZE)
+func (self *JsonCodec) Recv() (interface{}, error) {
+ var msg json.RawMessage
+ err := self.d.Decode(&msg)
+ if err != nil {
+ self.c.Close()
+ return nil, err
+ }
- deadline := time.Now().Add(READ_TIMEOUT * time.Second)
- if err := self.c.SetDeadline(deadline); err != nil {
+ return msg, err
+}
+
+func (self *JsonCodec) ReadResponse() (interface{}, error) {
+ in, err := self.Recv()
+ if err != nil {
return nil, err
}
- for {
- n, err := self.c.Read(buf[bytesInBuffer:])
- if err != nil {
- return nil, err
+ if msg, ok := in.(json.RawMessage); ok {
+ var req *shared.Request
+ if err = json.Unmarshal(msg, &req); err == nil && strings.HasPrefix(req.Method, "agent_") {
+ return req, nil
}
- bytesInBuffer += n
- var failure shared.ErrorResponse
- if err = json.Unmarshal(buf[:bytesInBuffer], &failure); err == nil && failure.Error != nil {
+ var failure *shared.ErrorResponse
+ if err = json.Unmarshal(msg, &failure); err == nil && failure.Error != nil {
return failure, fmt.Errorf(failure.Error.Message)
}
- var success shared.SuccessResponse
- if err = json.Unmarshal(buf[:bytesInBuffer], &success); err == nil {
+ var success *shared.SuccessResponse
+ if err = json.Unmarshal(msg, &success); err == nil {
return success, nil
}
}
- self.c.Close()
- return nil, fmt.Errorf("Unable to read response")
+ return in, err
}
// Decode data
diff --git a/rpc/comms/comms.go b/rpc/comms/comms.go
index f5eeae84f..731b2f62e 100644
--- a/rpc/comms/comms.go
+++ b/rpc/comms/comms.go
@@ -49,7 +49,7 @@ var (
)
type EthereumClient interface {
- // Close underlaying connection
+ // Close underlying connection
Close()
// Send request
Send(interface{}) error
diff --git a/rpc/comms/inproc.go b/rpc/comms/inproc.go
index f279f0163..e8058e32b 100644
--- a/rpc/comms/inproc.go
+++ b/rpc/comms/inproc.go
@@ -60,7 +60,7 @@ func (self *InProcClient) Send(req interface{}) error {
}
func (self *InProcClient) Recv() (interface{}, error) {
- return self.lastRes, self.lastErr
+ return *shared.NewRpcResponse(self.lastId, self.lastJsonrpc, self.lastRes, self.lastErr), nil
}
func (self *InProcClient) SupportedModules() (map[string]string, error) {
diff --git a/rpc/comms/ipc.go b/rpc/comms/ipc.go
index 0250aa01e..e982ada13 100644
--- a/rpc/comms/ipc.go
+++ b/rpc/comms/ipc.go
@@ -44,35 +44,18 @@ func (self *ipcClient) Close() {
func (self *ipcClient) Send(req interface{}) error {
var err error
- if r, ok := req.(*shared.Request); ok {
- if err = self.coder.WriteResponse(r); err != nil {
- if _, ok := err.(*net.OpError); ok { // connection lost, retry once
- if err = self.reconnect(); err == nil {
- err = self.coder.WriteResponse(r)
- }
+ if err = self.coder.WriteResponse(req); err != nil {
+ if _, ok := err.(*net.OpError); ok { // connection lost, retry once
+ if err = self.reconnect(); err == nil {
+ err = self.coder.WriteResponse(req)
}
}
- return err
}
-
- return fmt.Errorf("Invalid request (%T)", req)
+ return err
}
func (self *ipcClient) Recv() (interface{}, error) {
- res, err := self.coder.ReadResponse()
- if err != nil {
- return nil, err
- }
-
- if r, ok := res.(shared.SuccessResponse); ok {
- return r.Result, nil
- }
-
- if r, ok := res.(shared.ErrorResponse); ok {
- return r.Error, nil
- }
-
- return res, err
+ return self.coder.ReadResponse()
}
func (self *ipcClient) SupportedModules() (map[string]string, error) {
@@ -91,7 +74,7 @@ func (self *ipcClient) SupportedModules() (map[string]string, error) {
return nil, err
}
- if sucRes, ok := res.(shared.SuccessResponse); ok {
+ if sucRes, ok := res.(*shared.SuccessResponse); ok {
data, _ := json.Marshal(sucRes.Result)
modules := make(map[string]string)
err = json.Unmarshal(data, &modules)
@@ -109,8 +92,8 @@ func NewIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
}
// Start IPC server
-func StartIpc(cfg IpcConfig, codec codec.Codec, offeredApi shared.EthereumApi) error {
- return startIpc(cfg, codec, offeredApi)
+func StartIpc(cfg IpcConfig, codec codec.Codec, initializer func(conn net.Conn) (shared.EthereumApi, error)) error {
+ return startIpc(cfg, codec, initializer)
}
func newIpcConnId() int {
diff --git a/rpc/comms/ipc_unix.go b/rpc/comms/ipc_unix.go
index 432bf93b5..6968fa844 100644
--- a/rpc/comms/ipc_unix.go
+++ b/rpc/comms/ipc_unix.go
@@ -48,7 +48,7 @@ func (self *ipcClient) reconnect() error {
return err
}
-func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error {
+func startIpc(cfg IpcConfig, codec codec.Codec, initializer func(conn net.Conn) (shared.EthereumApi, error)) error {
os.Remove(cfg.Endpoint) // in case it still exists from a previous run
l, err := net.Listen("unix", cfg.Endpoint)
@@ -69,6 +69,13 @@ func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error {
id := newIpcConnId()
glog.V(logger.Debug).Infof("New IPC connection with id %06d started\n", id)
+ api, err := initializer(conn)
+ if err != nil {
+ glog.V(logger.Error).Infof("Unable to initialize IPC connection - %v\n", err)
+ conn.Close()
+ continue
+ }
+
go handle(id, conn, api, codec)
}
diff --git a/rpc/comms/ipc_windows.go b/rpc/comms/ipc_windows.go
index ee49f069b..b2fe2b29d 100644
--- a/rpc/comms/ipc_windows.go
+++ b/rpc/comms/ipc_windows.go
@@ -667,7 +667,7 @@ func (self *ipcClient) reconnect() error {
return err
}
-func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error {
+func startIpc(cfg IpcConfig, codec codec.Codec, initializer func(conn net.Conn) (shared.EthereumApi, error)) error {
os.Remove(cfg.Endpoint) // in case it still exists from a previous run
l, err := Listen(cfg.Endpoint)
@@ -687,6 +687,13 @@ func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error {
id := newIpcConnId()
glog.V(logger.Debug).Infof("New IPC connection with id %06d started\n", id)
+ api, err := initializer(conn)
+ if err != nil {
+ glog.V(logger.Error).Infof("Unable to initialize IPC connection - %v\n", err)
+ conn.Close()
+ continue
+ }
+
go handle(id, conn, api, codec)
}
diff --git a/rpc/jeth.go b/rpc/jeth.go
index 07add2bad..158bfb64c 100644
--- a/rpc/jeth.go
+++ b/rpc/jeth.go
@@ -18,12 +18,17 @@ package rpc
import (
"encoding/json"
-
"fmt"
+ "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/jsre"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rpc/comms"
"github.com/ethereum/go-ethereum/rpc/shared"
+ "github.com/ethereum/go-ethereum/rpc/useragent"
+ "github.com/ethereum/go-ethereum/xeth"
+
"github.com/robertkrimen/otto"
)
@@ -31,10 +36,21 @@ type Jeth struct {
ethApi shared.EthereumApi
re *jsre.JSRE
client comms.EthereumClient
+ fe xeth.Frontend
}
-func NewJeth(ethApi shared.EthereumApi, re *jsre.JSRE, client comms.EthereumClient) *Jeth {
- return &Jeth{ethApi, re, client}
+func NewJeth(ethApi shared.EthereumApi, re *jsre.JSRE, client comms.EthereumClient, fe xeth.Frontend) *Jeth {
+ // enable the jeth as the user agent
+ req := shared.Request{
+ Id: 0,
+ Method: useragent.EnableUserAgentMethod,
+ Jsonrpc: shared.JsonRpcVersion,
+ Params: []byte("[]"),
+ }
+ client.Send(&req)
+ client.Recv()
+
+ return &Jeth{ethApi, re, client, fe}
}
func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface{}) (response otto.Value) {
@@ -72,16 +88,34 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
if err != nil {
return self.err(call, -32603, err.Error(), req.Id)
}
- respif, err = self.client.Recv()
+ recv:
+ respif, err = self.client.Recv()
if err != nil {
return self.err(call, -32603, err.Error(), req.Id)
}
+ agentreq, isRequest := respif.(*shared.Request)
+ if isRequest {
+ self.handleRequest(agentreq)
+ goto recv // receive response after agent interaction
+ }
+
+ sucres, isSuccessResponse := respif.(*shared.SuccessResponse)
+ errres, isErrorResponse := respif.(*shared.ErrorResponse)
+ if !isSuccessResponse && !isErrorResponse {
+ return self.err(call, -32603, fmt.Sprintf("Invalid response type (%T)", respif), req.Id)
+ }
+
call.Otto.Set("ret_jsonrpc", shared.JsonRpcVersion)
call.Otto.Set("ret_id", req.Id)
- res, _ := json.Marshal(respif)
+ var res []byte
+ if isSuccessResponse {
+ res, err = json.Marshal(sucres.Result)
+ } else if isErrorResponse {
+ res, err = json.Marshal(errres.Error)
+ }
call.Otto.Set("ret_result", string(res))
call.Otto.Set("response_idx", i)
@@ -105,3 +139,48 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
return
}
+
+// handleRequest will handle user agent requests by interacting with the user and sending
+// the user response back to the geth service
+func (self *Jeth) handleRequest(req *shared.Request) bool {
+ var err error
+ var args []interface{}
+ if err = json.Unmarshal(req.Params, &args); err != nil {
+ glog.V(logger.Info).Infof("Unable to parse agent request - %v\n", err)
+ return false
+ }
+
+ switch req.Method {
+ case useragent.AskPasswordMethod:
+ return self.askPassword(req.Id, req.Jsonrpc, args)
+ case useragent.ConfirmTransactionMethod:
+ return self.confirmTransaction(req.Id, req.Jsonrpc, args)
+ }
+
+ return false
+}
+
+// askPassword will ask the user to supply the password for a given account
+func (self *Jeth) askPassword(id interface{}, jsonrpc string, args []interface{}) bool {
+ var err error
+ var passwd string
+ if len(args) >= 1 {
+ if account, ok := args[0].(string); ok {
+ fmt.Printf("Unlock account %s\n", account)
+ passwd, err = utils.PromptPassword("Passphrase: ", true)
+ } else {
+ return false
+ }
+ }
+
+ if err = self.client.Send(shared.NewRpcResponse(id, jsonrpc, passwd, err)); err != nil {
+ glog.V(logger.Info).Infof("Unable to send user agent ask password response - %v\n", err)
+ }
+
+ return err == nil
+}
+
+func (self *Jeth) confirmTransaction(id interface{}, jsonrpc string, args []interface{}) bool {
+ // Accept all tx which are send from this console
+ return self.client.Send(shared.NewRpcResponse(id, jsonrpc, true, nil)) == nil
+}
diff --git a/rpc/useragent/agent.go b/rpc/useragent/agent.go
new file mode 100644
index 000000000..df0739e65
--- /dev/null
+++ b/rpc/useragent/agent.go
@@ -0,0 +1,24 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// package user agent provides frontends and agents which can interact with the user
+package useragent
+
+var (
+ AskPasswordMethod = "agent_askPassword"
+ ConfirmTransactionMethod = "agent_confirmTransaction"
+ EnableUserAgentMethod = "admin_enableUserAgent"
+)
diff --git a/rpc/useragent/remote_frontend.go b/rpc/useragent/remote_frontend.go
new file mode 100644
index 000000000..0dd4a6049
--- /dev/null
+++ b/rpc/useragent/remote_frontend.go
@@ -0,0 +1,141 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package useragent
+
+import (
+ "encoding/json"
+ "fmt"
+ "net"
+
+ "github.com/ethereum/go-ethereum/accounts"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/rpc/shared"
+)
+
+// remoteFrontend implements xeth.Frontend and will communicate with an external
+// user agent over a connection
+type RemoteFrontend struct {
+ enabled bool
+ mgr *accounts.Manager
+ d *json.Decoder
+ e *json.Encoder
+ n int
+}
+
+// NewRemoteFrontend creates a new frontend which will interact with an user agent
+// over the given connection
+func NewRemoteFrontend(conn net.Conn, mgr *accounts.Manager) *RemoteFrontend {
+ return &RemoteFrontend{false, mgr, json.NewDecoder(conn), json.NewEncoder(conn), 0}
+}
+
+// Enable will enable user interaction
+func (fe *RemoteFrontend) Enable() {
+ fe.enabled = true
+}
+
+// UnlockAccount asks the user agent for the user password and tries to unlock the account.
+// It will try 3 attempts before giving up.
+func (fe *RemoteFrontend) UnlockAccount(address []byte) bool {
+ if !fe.enabled {
+ return false
+ }
+
+ err := fe.send(AskPasswordMethod, common.Bytes2Hex(address))
+ if err != nil {
+ glog.V(logger.Error).Infof("Unable to send password request to agent - %v\n", err)
+ return false
+ }
+
+ passwdRes, err := fe.recv()
+ if err != nil {
+ glog.V(logger.Error).Infof("Unable to recv password response from agent - %v\n", err)
+ return false
+ }
+
+ if passwd, ok := passwdRes.Result.(string); ok {
+ err = fe.mgr.Unlock(common.BytesToAddress(address), passwd)
+ }
+
+ if err == nil {
+ return true
+ }
+
+ glog.V(logger.Debug).Infoln("3 invalid account unlock attempts")
+ return false
+}
+
+// ConfirmTransaction asks the user for approval
+func (fe *RemoteFrontend) ConfirmTransaction(tx string) bool {
+ if !fe.enabled {
+ return true // backwards compatibility
+ }
+
+ err := fe.send(ConfirmTransactionMethod, tx)
+ if err != nil {
+ glog.V(logger.Error).Infof("Unable to send tx confirmation request to agent - %v\n", err)
+ return false
+ }
+
+ confirmResponse, err := fe.recv()
+ if err != nil {
+ glog.V(logger.Error).Infof("Unable to recv tx confirmation response from agent - %v\n", err)
+ return false
+ }
+
+ if confirmed, ok := confirmResponse.Result.(bool); ok {
+ return confirmed
+ }
+
+ return false
+}
+
+// send request to the agent
+func (fe *RemoteFrontend) send(method string, params ...interface{}) error {
+ fe.n += 1
+
+ p, err := json.Marshal(params)
+ if err != nil {
+ glog.V(logger.Info).Infof("Unable to send agent request %v\n", err)
+ return err
+ }
+
+ req := shared.Request{
+ Method: method,
+ Jsonrpc: shared.JsonRpcVersion,
+ Id: fe.n,
+ Params: p,
+ }
+
+ return fe.e.Encode(&req)
+}
+
+// recv user response from agent
+func (fe *RemoteFrontend) recv() (*shared.SuccessResponse, error) {
+ var res json.RawMessage
+ if err := fe.d.Decode(&res); err != nil {
+ return nil, err
+ }
+
+ var response shared.SuccessResponse
+ if err := json.Unmarshal(res, &response); err == nil {
+ return &response, nil
+ }
+
+ return nil, fmt.Errorf("Invalid user agent response")
+}
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 42e4383d1..8cb7b7882 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -204,7 +204,7 @@ func (test *BlockTest) makeEthConfig() *eth.Config {
// InsertPreState populates the given database with the genesis
// accounts defined by the test.
func (t *BlockTest) InsertPreState(ethereum *eth.Ethereum) (*state.StateDB, error) {
- db := ethereum.StateDb()
+ db := ethereum.ChainDb()
statedb := state.New(common.Hash{}, db)
for addrString, acct := range t.preAccounts {
addr, err := hex.DecodeString(addrString)
diff --git a/tests/state_test.go b/tests/state_test.go
index eb1900e1b..7090b0541 100644
--- a/tests/state_test.go
+++ b/tests/state_test.go
@@ -27,14 +27,13 @@ import (
func init() {
if os.Getenv("JITVM") == "true" {
vm.ForceJit = true
- } else {
- vm.DisableJit = true
+ vm.EnableJit = true
}
}
func BenchmarkStateCall1024(b *testing.B) {
fn := filepath.Join(stateTestDir, "stCallCreateCallCodeTest.json")
- if err := BenchVmTest(fn, bconf{"Call1024BalanceTooLow", true, false}, b); err != nil {
+ if err := BenchVmTest(fn, bconf{"Call1024BalanceTooLow", true, os.Getenv("JITVM") == "true"}, b); err != nil {
b.Error(err)
}
}
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index 695e50852..def9b0c36 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -71,8 +71,8 @@ func BenchStateTest(p string, conf bconf, b *testing.B) error {
return fmt.Errorf("test not found: %s", conf.name)
}
- pNoJit := vm.DisableJit
- vm.DisableJit = conf.nojit
+ pJit := vm.EnableJit
+ vm.EnableJit = conf.jit
pForceJit := vm.ForceJit
vm.ForceJit = conf.precomp
@@ -94,7 +94,7 @@ func BenchStateTest(p string, conf bconf, b *testing.B) error {
benchStateTest(test, env, b)
}
- vm.DisableJit = pNoJit
+ vm.EnableJit = pJit
vm.ForceJit = pForceJit
return nil
diff --git a/tests/vm_test.go b/tests/vm_test.go
index afa1424d5..96718db3c 100644
--- a/tests/vm_test.go
+++ b/tests/vm_test.go
@@ -17,20 +17,21 @@
package tests
import (
+ "os"
"path/filepath"
"testing"
)
func BenchmarkVmAckermann32Tests(b *testing.B) {
fn := filepath.Join(vmTestDir, "vmPerformanceTest.json")
- if err := BenchVmTest(fn, bconf{"ackermann32", true, false}, b); err != nil {
+ if err := BenchVmTest(fn, bconf{"ackermann32", true, os.Getenv("JITVM") == "true"}, b); err != nil {
b.Error(err)
}
}
func BenchmarkVmFibonacci16Tests(b *testing.B) {
fn := filepath.Join(vmTestDir, "vmPerformanceTest.json")
- if err := BenchVmTest(fn, bconf{"fibonacci16", true, false}, b); err != nil {
+ if err := BenchVmTest(fn, bconf{"fibonacci16", true, os.Getenv("JITVM") == "true"}, b); err != nil {
b.Error(err)
}
}
diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go
index b29dcd20f..71a4f5e33 100644
--- a/tests/vm_test_util.go
+++ b/tests/vm_test_util.go
@@ -52,7 +52,7 @@ func RunVmTestWithReader(r io.Reader, skipTests []string) error {
type bconf struct {
name string
precomp bool
- nojit bool
+ jit bool
}
func BenchVmTest(p string, conf bconf, b *testing.B) error {
@@ -67,8 +67,8 @@ func BenchVmTest(p string, conf bconf, b *testing.B) error {
return fmt.Errorf("test not found: %s", conf.name)
}
- pNoJit := vm.DisableJit
- vm.DisableJit = conf.nojit
+ pJit := vm.EnableJit
+ vm.EnableJit = conf.jit
pForceJit := vm.ForceJit
vm.ForceJit = conf.precomp
@@ -99,7 +99,7 @@ func BenchVmTest(p string, conf bconf, b *testing.B) error {
benchVmTest(test, env, b)
}
- vm.DisableJit = pNoJit
+ vm.EnableJit = pJit
vm.ForceJit = pForceJit
return nil
diff --git a/trie/cache.go b/trie/cache.go
index 2705b0e45..e475fc861 100644
--- a/trie/cache.go
+++ b/trie/cache.go
@@ -47,8 +47,6 @@ func (self *Cache) Get(key []byte) []byte {
}
func (self *Cache) Put(key []byte, data []byte) {
- // write the data to the ldb batch
- //self.batch.Put(key, rle.Compress(data))
self.batch.Put(key, data)
self.store[string(key)] = data
}
diff --git a/xeth/state.go b/xeth/state.go
index 16bfb523d..981fe63b7 100644
--- a/xeth/state.go
+++ b/xeth/state.go
@@ -45,7 +45,7 @@ func (self *State) SafeGet(addr string) *Object {
func (self *State) safeGet(addr string) *state.StateObject {
object := self.state.GetStateObject(common.HexToAddress(addr))
if object == nil {
- object = state.NewStateObject(common.HexToAddress(addr), self.xeth.backend.StateDb())
+ object = state.NewStateObject(common.HexToAddress(addr), self.xeth.backend.ChainDb())
}
return object
diff --git a/xeth/xeth.go b/xeth/xeth.go
index f447a1ac3..8bd45998f 100644
--- a/xeth/xeth.go
+++ b/xeth/xeth.go
@@ -89,8 +89,7 @@ type XEth struct {
messagesMu sync.RWMutex
messages map[int]*whisperFilter
- // regmut sync.Mutex
- // register map[string][]*interface{} // TODO improve return type
+ transactMu sync.Mutex
agent *miner.RemoteAgent
@@ -213,9 +212,9 @@ func (self *XEth) AtStateNum(num int64) *XEth {
st = self.backend.Miner().PendingState().Copy()
default:
if block := self.getBlockByHeight(num); block != nil {
- st = state.New(block.Root(), self.backend.StateDb())
+ st = state.New(block.Root(), self.backend.ChainDb())
} else {
- st = state.New(self.backend.ChainManager().GetBlockByNumber(0).Root(), self.backend.StateDb())
+ st = state.New(self.backend.ChainManager().GetBlockByNumber(0).Root(), self.backend.ChainDb())
}
}
@@ -259,7 +258,7 @@ func (self *XEth) UpdateState() (wait chan *big.Int) {
wait <- n
n = nil
}
- statedb := state.New(ev.Block.Root(), self.backend.StateDb())
+ statedb := state.New(ev.Block.Root(), self.backend.ChainDb())
self.state = NewState(self, statedb)
}
case n, ok = <-wait:
@@ -311,7 +310,7 @@ func (self *XEth) EthBlockByHash(strHash string) *types.Block {
func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blhash common.Hash, blnum *big.Int, txi uint64) {
// Due to increasing return params and need to determine if this is from transaction pool or
// some chain, this probably needs to be refactored for more expressiveness
- data, _ := self.backend.ExtraDb().Get(common.FromHex(hash))
+ data, _ := self.backend.ChainDb().Get(common.FromHex(hash))
if len(data) != 0 {
dtx := new(types.Transaction)
if err := rlp.DecodeBytes(data, dtx); err != nil {
@@ -330,7 +329,7 @@ func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blha
Index uint64
}
- v, dberr := self.backend.ExtraDb().Get(append(common.FromHex(hash), 0x0001))
+ v, dberr := self.backend.ChainDb().Get(append(common.FromHex(hash), 0x0001))
// TODO check specifically for ErrNotFound
if dberr != nil {
return
@@ -365,7 +364,7 @@ func (self *XEth) GetBlockReceipts(bhash common.Hash) types.Receipts {
}
func (self *XEth) GetTxReceipt(txhash common.Hash) *types.Receipt {
- return core.GetReceipt(self.backend.ExtraDb(), txhash)
+ return core.GetReceipt(self.backend.ChainDb(), txhash)
}
func (self *XEth) GasLimit() *big.Int {
@@ -408,13 +407,13 @@ func (self *XEth) SetSolc(solcPath string) (*compiler.Solidity, error) {
// store DApp value in extra database
func (self *XEth) DbPut(key, val []byte) bool {
- self.backend.ExtraDb().Put(append(dappStorePre, key...), val)
+ self.backend.DappDb().Put(append(dappStorePre, key...), val)
return true
}
// retrieve DApp value from extra database
func (self *XEth) DbGet(key []byte) ([]byte, error) {
- val, err := self.backend.ExtraDb().Get(append(dappStorePre, key...))
+ val, err := self.backend.DappDb().Get(append(dappStorePre, key...))
return val, err
}
@@ -823,18 +822,22 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
}
from.SetBalance(common.MaxBig)
- from.SetGasLimit(self.backend.ChainManager().GasLimit())
+ from.SetGasLimit(common.MaxBig)
+
msg := callmsg{
from: from,
- to: common.HexToAddress(toStr),
gas: common.Big(gasStr),
gasPrice: common.Big(gasPriceStr),
value: common.Big(valueStr),
data: common.FromHex(dataStr),
}
+ if len(toStr) > 0 {
+ addr := common.HexToAddress(toStr)
+ msg.to = &addr
+ }
if msg.gas.Cmp(big.NewInt(0)) == 0 {
- msg.gas = DefaultGas()
+ msg.gas = big.NewInt(50000000)
}
if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
@@ -885,6 +888,10 @@ func isAddress(addr string) bool {
return addrReg.MatchString(addr)
}
+func (self *XEth) Frontend() Frontend {
+ return self.frontend
+}
+
func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
// this minimalistic recoding is enough (works for natspec.js)
@@ -948,8 +955,9 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
}
*/
- // TODO: align default values to have the same type, e.g. not depend on
- // common.Value conversions later on
+ self.transactMu.Lock()
+ defer self.transactMu.Unlock()
+
var nonce uint64
if len(nonceStr) != 0 {
nonce = common.Big(nonceStr).Uint64()
@@ -994,7 +1002,7 @@ func (self *XEth) sign(tx *types.Transaction, from common.Address, didUnlock boo
// callmsg is the message type used for call transations.
type callmsg struct {
from *state.StateObject
- to common.Address
+ to *common.Address
gas, gasPrice *big.Int
value *big.Int
data []byte
@@ -1003,7 +1011,7 @@ type callmsg struct {
// accessor boilerplate to implement core.Message
func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil }
func (m callmsg) Nonce() uint64 { return m.from.Nonce() }
-func (m callmsg) To() *common.Address { return &m.to }
+func (m callmsg) To() *common.Address { return m.to }
func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
func (m callmsg) Gas() *big.Int { return m.gas }
func (m callmsg) Value() *big.Int { return m.value }