diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..dfe0770424
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto
diff --git a/.gitignore b/.gitignore
index 4c12be4a81..28b3dc4ff7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,3 +35,4 @@ cmd/mist/assets/ext/expanse.js/
profile.tmp
profile.cov
+.idea/workspace.xml
diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index 2adf87fbaf..0000000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-go-expanse
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index d82104827f..0000000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/go-expanse.iml b/.idea/go-expanse.iml
deleted file mode 100644
index c956989b29..0000000000
--- a/.idea/go-expanse.iml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 8662aa97f9..0000000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 2318fdd1a3..0000000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
deleted file mode 100644
index 922003b843..0000000000
--- a/.idea/scopes/scope_settings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7f4c..0000000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
deleted file mode 100644
index 4f054aeb80..0000000000
--- a/.idea/workspace.xml
+++ /dev/null
@@ -1,567 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1438971860269
-
- 1438971860269
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 2b3ff92f61..13211f7363 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ install:
# - go get code.google.com/p/go.tools/cmd/goimports
# - go get github.com/golang/lint/golint
# - go get golang.org/x/tools/cmd/vet
- - go get golang.org/x/tools/cmd/cover github.com/mattn/goveralls
+ - go get golang.org/x/tools/cmd/cover
before_script:
# - gofmt -l -w .
# - goimports -l -w .
@@ -15,7 +15,7 @@ before_script:
script:
- make travis-test-with-coverage
after_success:
- - if [ "$COVERALLS_TOKEN" ]; then goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN; fi
+ - bash <(curl -s https://codecov.io/bash)
env:
global:
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..5f0f129eb8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,9 @@
+If you'd like to contribute to go-expanse please fork, fix, commit and
+send a pull request. Commits who do not comply with the coding standards
+are ignored (use gofmt!). If you send pull requests make absolute sure that you
+commit on the `develop` branch and that you do not merge to master.
+Commits that are directly based on master are simply ignored.
+
+See [Developers' Guide](https://github.com/expanse-project/go-expanse/wiki/Developers'-Guide)
+for more details on configuring your environment, testing, and
+dependency management.
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index b7e32e489c..25b3793337 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -24,14 +24,18 @@
"Comment": "v23.1-227-g8f6ccaa",
"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",
@@ -45,10 +49,6 @@
"ImportPath": "github.com/kardianos/osext",
"Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a"
},
- {
- "ImportPath": "github.com/mattn/go-colorable",
- "Rev": "043ae16291351db8465272edf465c9f388161627"
- },
{
"ImportPath": "github.com/mattn/go-isatty",
"Rev": "fdbe02a1b44e75977b2690062b83cf507d70c013"
@@ -78,6 +78,10 @@
"ImportPath": "github.com/rs/cors",
"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 0000000000..2405aef3a8
--- /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 0000000000..25fdaf639d
--- /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 0000000000..d6fb06a3e3
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/fatih/color/README.md
@@ -0,0 +1,151 @@
+# Color [](http://godoc.org/github.com/fatih/color) [](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.
+
+
+
+
+
+
+## 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 0000000000..c4a10c3c8d
--- /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 0000000000..a1192b559d
--- /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 0000000000..17908787c9
--- /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/huin/goupnp/httpu/httpu.go b/Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go
index 5077b7127c..862c3def42 100644
--- a/Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go
+++ b/Godeps/_workspace/src/github.com/huin/goupnp/httpu/httpu.go
@@ -9,8 +9,6 @@ import (
"net/http"
"sync"
"time"
-
- "github.com/expanse-project/go-expanse/fdtrack"
)
// HTTPUClient is a client for dealing with HTTPU (HTTP over UDP). Its typical
@@ -27,7 +25,6 @@ func NewHTTPUClient() (*HTTPUClient, error) {
if err != nil {
return nil, err
}
- fdtrack.Open("upnp")
return &HTTPUClient{conn: conn}, nil
}
@@ -36,7 +33,6 @@ func NewHTTPUClient() (*HTTPUClient, error) {
func (httpu *HTTPUClient) Close() error {
httpu.connLock.Lock()
defer httpu.connLock.Unlock()
- fdtrack.Close("upnp")
return httpu.conn.Close()
}
diff --git a/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go b/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go
index 6828f9d59e..815610734c 100644
--- a/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go
+++ b/Godeps/_workspace/src/github.com/huin/goupnp/soap/soap.go
@@ -7,12 +7,9 @@ import (
"encoding/xml"
"fmt"
"io/ioutil"
- "net"
"net/http"
"net/url"
"reflect"
-
- "github.com/expanse-project/go-expanse/fdtrack"
)
const (
@@ -29,17 +26,6 @@ type SOAPClient struct {
func NewSOAPClient(endpointURL url.URL) *SOAPClient {
return &SOAPClient{
EndpointURL: endpointURL,
- HTTPClient: http.Client{
- Transport: &http.Transport{
- Dial: func(network, addr string) (net.Conn, error) {
- c, err := net.Dial(network, addr)
- if c != nil {
- c = fdtrack.WrapConn("upnp", c)
- }
- return c, err
- },
- },
- },
}
}
diff --git a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go
index 6f30456a3b..8ce4e8342e 100644
--- a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go
+++ b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go
@@ -5,8 +5,6 @@ import (
"log"
"net"
"time"
-
- "github.com/expanse-project/go-expanse/fdtrack"
)
// Implement the NAT-PMP protocol, typically supported by Apple routers and open source
@@ -104,8 +102,6 @@ func (n *Client) rpc(msg []byte, resultSize int) (result []byte, err error) {
if err != nil {
return
}
- fdtrack.Open("natpmp")
- defer fdtrack.Close("natpmp")
defer conn.Close()
result = make([]byte, resultSize)
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 c69da4a761..0000000000
--- 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!
-
-
-
-
-## So Good!
-
-
-
-## 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 219f02f62a..0000000000
--- 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 6a27878088..0000000000
--- 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 0000000000..69cec52c4e
--- /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 0000000000..e58473ed94
--- /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 0000000000..7797a4f186
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/shiena/ansicolor/README.md
@@ -0,0 +1,100 @@
+[](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")
+}
+```
+
+
+
+## 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 0000000000..d3ece8fc0c
--- /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 0000000000..d86cfc0f34
--- /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 0000000000..57b4633a77
--- /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 0000000000..4feeb1de67
--- /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 0000000000..d918ffe914
--- /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 0000000000..6c126d517a
--- /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 0000000000..f2ac67c174
--- /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 0000000000..6d2f7c0741
--- /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/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
index 14af07e7fb..46cc9d0701 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
@@ -18,7 +18,6 @@ import (
"sync"
"time"
- "github.com/expanse-project/go-expanse/fdtrack"
"github.com/syndtr/goleveldb/leveldb/util"
)
@@ -370,8 +369,6 @@ func (fw fileWrap) Close() error {
err := fw.File.Close()
if err != nil {
f.fs.log(fmt.Sprintf("close %s.%d: %v", f.Type(), f.Num(), err))
- } else {
- fdtrack.Close("leveldb")
}
return err
}
@@ -403,7 +400,6 @@ func (f *file) Open() (Reader, error) {
return nil, err
}
ok:
- fdtrack.Open("leveldb")
f.open = true
f.fs.open++
return fileWrap{of, f}, nil
@@ -422,7 +418,6 @@ func (f *file) Create() (Writer, error) {
if err != nil {
return nil, err
}
- fdtrack.Open("leveldb")
f.open = true
f.fs.open++
return fileWrap{of, f}, nil
diff --git a/Makefile b/Makefile
index 6260ad7641..3539c4c965 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
# with Go source code. If you know what GOPATH is then you probably
# don't need to bother with make.
-.PHONY: gexp mist all test travis-test-with-coverage clean
+.PHONY: gexp evm mist all test travis-test-with-coverage clean
GOBIN = build/bin
gexp:
@@ -10,6 +10,10 @@ gexp:
@echo "Done building."
@echo "Run \"$(GOBIN)/gexp\" to launch gexp."
+evm:
+ build/env.sh $(GOROOT)/bin/go install -v $(shell build/ldflags.sh) ./cmd/evm
+ @echo "Done building."
+ @echo "Run \"$(GOBIN)/evm to start the evm."
mist:
build/env.sh go install -v $(shell build/ldflags.sh) ./cmd/mist
@echo "Done building."
diff --git a/README.md b/README.md
index d421867180..7be16315d4 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,7 @@ master | [](http://waffle.io/expanse/go-expanse)
[](https://gitter.im/expanse/go-expanse?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
-Automated development builds
-======================
+## Automated development builds
The following builds are build automatically by our build servers after each push to the [develop](https://github.com/expanse-project/go-expanse/tree/develop) branch.
@@ -25,8 +24,7 @@ The following builds are build automatically by our build servers after each pus
* [Windows 64-bit](https://build.ethdev.com/builds/Windows%20Go%20develop%20branch/Gexp-Win64-latest.zip)
* [ARM](https://build.ethdev.com/builds/ARM%20Go%20develop%20branch/gexp-ARM-latest.tar.bz2)
-Building the source
-===================
+## Building the source
For prerequisites and detailed build instructions please read the
[Installation Instructions](https://github.com/expanse-project/go-expanse/wiki/Building-Expanse)
@@ -38,8 +36,7 @@ Once the dependencies are installed, run
make gexp
-Executables
-===========
+## Executables
Go Expanse comes with several wrappers/executables found in
[the `cmd` directory](https://github.com/expanse-project/go-expanse/tree/develop/cmd):
@@ -53,19 +50,17 @@ Go Expanse comes with several wrappers/executables found in
* `disasm` disassembles EVM code: `echo "6001" | disasm`
* `rlpdump` prints RLP structures
-Command line options
-====================
+## Command line options
`gexp` can be configured via command line options, environment variables and config files.
To get the options available:
- gexp --help
+ geth help
For further details on options, see the [wiki](https://github.com/expanse-project/go-expanse/wiki/Command-Line-Options)
-Contribution
-============
+## Contribution
If you'd like to contribute to go-expanse please fork, fix, commit and
send a pull request. Commits who do not comply with the coding standards
diff --git a/build/test-global-coverage.sh b/build/test-global-coverage.sh
index 40df8d4c9c..a51b6a9e57 100755
--- a/build/test-global-coverage.sh
+++ b/build/test-global-coverage.sh
@@ -1,26 +1,15 @@
-#!/bin/bash
-
-# This script runs all package tests and merges the resulting coverage
-# profiles. Coverage is accounted per package under test.
+#!/usr/bin/env bash
set -e
+echo "" > coverage.txt
-if [ ! -f "build/env.sh" ]; then
- echo "$0 must be run from the root of the repository."
- exit 2
-fi
-
-echo "mode: count" > profile.cov
-
-for pkg in $(go list ./...); do
- # drop the namespace prefix.
- dir=${pkg##github.com/expanse-project/go-expanse/}
-
- if [[ $dir != "tests" ]]; then
- go test -covermode=count -coverprofile=$dir/profile.tmp $pkg
- fi
- if [[ -f $dir/profile.tmp ]]; then
- tail -n +2 $dir/profile.tmp >> profile.cov
- rm $dir/profile.tmp
+for d in $(find ./* -maxdepth 10 -type d -not -path "./build" -not -path "./Godeps/*" ); do
+ if ls $d/*.go &> /dev/null; then
+ go test -coverprofile=profile.out -covermode=atomic $d
+ if [ -f profile.out ]; then
+ cat profile.out >> coverage.txt
+ echo '<<<<<< EOF' >> coverage.txt
+ rm profile.out
+ fi
fi
done
diff --git a/cmd/ethtest/main.go b/cmd/ethtest/main.go
index 938effdc6d..8f6e92e9b8 100644
--- a/cmd/ethtest/main.go
+++ b/cmd/ethtest/main.go
@@ -26,6 +26,7 @@ import (
"strings"
"github.com/codegangsta/cli"
+ "github.com/expanse-project/go-expanse/core/vm"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/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 d922de9acf..b9353bacd8 100644
--- a/cmd/evm/main.go
+++ b/cmd/evm/main.go
@@ -32,6 +32,7 @@ import (
"github.com/expanse-project/go-expanse/core/types"
"github.com/expanse-project/go-expanse/core/vm"
"github.com/expanse-project/go-expanse/ethdb"
+ "github.com/expanse-project/go-expanse/logger/glog"
)
var (
@@ -40,6 +41,14 @@ var (
Name: "debug",
Usage: "output full trace logs",
}
+ ForceJitFlag = cli.BoolFlag{
+ Name: "forcejit",
+ Usage: "forces jit compilation",
+ }
+ DisableJitFlag = cli.BoolFlag{
+ Name: "nojit",
+ Usage: "disabled jit compilation",
+ }
CodeFlag = cli.StringFlag{
Name: "code",
Usage: "EVM code",
@@ -77,6 +86,8 @@ func init() {
app = utils.NewApp("0.2", "the evm command line interface")
app.Flags = []cli.Flag{
DebugFlag,
+ ForceJitFlag,
+ DisableJitFlag,
SysStatFlag,
CodeFlag,
GasFlag,
@@ -90,6 +101,10 @@ func init() {
func run(ctx *cli.Context) {
vm.Debug = ctx.GlobalBool(DebugFlag.Name)
+ vm.ForceJit = ctx.GlobalBool(ForceJitFlag.Name)
+ vm.EnableJit = !ctx.GlobalBool(DisableJitFlag.Name)
+
+ glog.SetToStderr(true)
db, _ := ethdb.NewMemDatabase()
statedb := state.New(common.Hash{}, db)
@@ -110,11 +125,6 @@ func run(ctx *cli.Context) {
)
vmdone := time.Since(tstart)
- if e != nil {
- fmt.Println(e)
- os.Exit(1)
- }
-
if ctx.GlobalBool(DumpFlag.Name) {
fmt.Println(string(statedb.Dump()))
}
@@ -133,7 +143,11 @@ num gc: %d
`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC)
}
- fmt.Printf("OUT: 0x%x\n", ret)
+ fmt.Printf("OUT: 0x%x", ret)
+ if e != nil {
+ fmt.Printf(" error: %v", e)
+ }
+ fmt.Println()
}
func main() {
@@ -152,7 +166,7 @@ type VMEnv struct {
depth int
Gas *big.Int
- time uint64
+ time *big.Int
logs []vm.StructLog
}
@@ -161,7 +175,7 @@ func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int) *VM
state: state,
transactor: &transactor,
value: value,
- time: uint64(time.Now().Unix()),
+ time: big.NewInt(time.Now().Unix()),
}
}
@@ -169,7 +183,7 @@ func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) Origin() common.Address { return *self.transactor }
func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 }
func (self *VMEnv) Coinbase() common.Address { return *self.transactor }
-func (self *VMEnv) Time() uint64 { return self.time }
+func (self *VMEnv) Time() *big.Int { return self.time }
func (self *VMEnv) Difficulty() *big.Int { return common.Big1 }
func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) }
func (self *VMEnv) Value() *big.Int { return self.value }
@@ -192,6 +206,9 @@ func (self *VMEnv) StructLogs() []vm.StructLog {
func (self *VMEnv) AddLog(log *state.Log) {
self.state.AddLog(log)
}
+func (self *VMEnv) CanTransfer(from vm.Account, balance *big.Int) bool {
+ return from.Balance().Cmp(balance) >= 0
+}
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
return vm.Transfer(from, to, amount)
}
diff --git a/cmd/gexp/chaincmd.go b/cmd/gexp/chaincmd.go
index e2d833ff8c..3ba3a5f663 100644
--- a/cmd/gexp/chaincmd.go
+++ b/cmd/gexp/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
@@ -115,17 +115,16 @@ func exportChain(ctx *cli.Context) {
}
func removeDB(ctx *cli.Context) {
- confirm, err := utils.PromptConfirm("Remove local databases?")
+ confirm, err := utils.PromptConfirm("Remove local database?")
if err != nil {
utils.Fatalf("%v", err)
}
if confirm {
- fmt.Println("Removing chain and state databases...")
+ fmt.Println("Removing chaindata...")
start := time.Now()
- os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
- os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
+ os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "chaindata"))
fmt.Printf("Removed in %v\n", time.Since(start))
} else {
@@ -136,8 +135,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 +148,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 +165,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 +178,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/gexp/js.go b/cmd/gexp/js.go
index fa2a64843a..4707d732bf 100644
--- a/cmd/gexp/js.go
+++ b/cmd/gexp/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.ExpanseClient, interactive bool, f xeth.Frontend) *jsre {
+func newLightweightJSRE(libPath string, client comms.ExpanseClient, 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 gexp 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: " + exp.coinbase);`)
- self.re.Eval(`var lastBlockTimestamp = 1000 * exp.getBlock(exp.blockNumber).timestamp`)
- self.re.Eval(`console.log("at block: " + exp.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: " + exp.coinbase);
+ var ts = 1000 * exp.getBlock(exp.blockNumber).timestamp;
+ console.log("at block: " + exp.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 = exp.contract(` + registrar.GlobalRegistrarAbi + `); registrar = GlobalRegistrar.at("` + registrar.GlobalRegistrarAddr + `");`)
+ js.re.Run(`var GlobalRegistrar = exp.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/gexp/main.go b/cmd/gexp/main.go
index 7903233ed9..7c418c3588 100644
--- a/cmd/gexp/main.go
+++ b/cmd/gexp/main.go
@@ -19,7 +19,6 @@ package main
import (
"fmt"
- "io"
"io/ioutil"
_ "net/http/pprof"
"os"
@@ -38,19 +37,21 @@ import (
"github.com/expanse-project/go-expanse/core/types"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/ethdb"
- "github.com/expanse-project/go-expanse/fdtrack"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/metrics"
+ "github.com/expanse-project/go-expanse/params"
+ "github.com/expanse-project/go-expanse/rlp"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/comms"
- "github.com/mattn/go-colorable"
- "github.com/mattn/go-isatty"
)
const (
ClientIdentifier = "Gexp"
- Version = "1.0.1"
+ Version = "1.1.2"
+ VersionMajor = 1
+ VersionMinor = 1
+ VersionPatch = 2
)
var (
@@ -307,6 +308,9 @@ JavaScript API. See https://github.com/expanse-project/go-expanse/wiki/Javascipt
utils.ExecFlag,
utils.WhisperEnabledFlag,
utils.VMDebugFlag,
+ utils.VMForceJitFlag,
+ utils.VMJitCacheFlag,
+ utils.VMEnableJitFlag,
utils.NetworkIdFlag,
utils.RPCCORSDomainFlag,
utils.VerbosityFlag,
@@ -328,6 +332,7 @@ JavaScript API. See https://github.com/expanse-project/go-expanse/wiki/Javascipt
}
app.Before = func(ctx *cli.Context) error {
utils.SetupLogger(ctx)
+ utils.SetupVM(ctx)
if ctx.GlobalBool(utils.PProfEanbledFlag.Name) {
utils.StartPProf(ctx)
}
@@ -346,6 +351,27 @@ func main() {
}
}
+func makeDefaultExtra() []byte {
+ var clientInfo = struct {
+ Version uint
+ Name string
+ GoVersion string
+ Os string
+ }{uint(VersionMajor<<16 | VersionMinor<<8 | VersionPatch), ClientIdentifier, runtime.Version(), runtime.GOOS}
+ extra, err := rlp.EncodeToBytes(clientInfo)
+ if err != nil {
+ glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
+ }
+
+ if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
+ glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
+ glog.V(logger.Debug).Infof("extra: %x\n", extra)
+ return nil
+ }
+
+ return extra
+}
+
func run(ctx *cli.Context) {
utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name))
if ctx.GlobalBool(utils.OlympicFlag.Name) {
@@ -353,6 +379,8 @@ func run(ctx *cli.Context) {
}
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
+ cfg.ExtraData = makeDefaultExtra()
+
expanse, err := exp.New(cfg)
if err != nil {
utils.Fatalf("%v", err)
@@ -366,14 +394,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.ExpanseClient
var err error
if ctx.Args().Present() {
@@ -393,7 +413,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))
@@ -406,14 +426,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)
expanse, err := exp.New(cfg)
if err != nil {
@@ -533,9 +545,6 @@ func startEth(ctx *cli.Context, exp *exp.Expanse) {
// Start Expanse itself
utils.StartExpanse(exp)
- // Start logging file descriptor stats.
- fdtrack.Start()
-
am := exp.AccountManager()
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
accounts := strings.Split(account, " ")
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index 0c60da38d2..a03a50d629 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/customflags.go b/cmd/utils/customflags.go
index e730c197d4..63351bec83 100644
--- a/cmd/utils/customflags.go
+++ b/cmd/utils/customflags.go
@@ -21,7 +21,7 @@ import (
"fmt"
"os"
"os/user"
- "path/filepath"
+ "path"
"strings"
"github.com/codegangsta/cli"
@@ -138,11 +138,8 @@ func (self *DirectoryFlag) Set(value string) {
func expandPath(p string) string {
if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
if user, err := user.Current(); err == nil {
- if err == nil {
- p = strings.Replace(p, "~", user.HomeDir, 1)
- }
+ p = user.HomeDir + p[1:]
}
}
-
- return filepath.Clean(os.ExpandEnv(p))
+ return path.Clean(os.ExpandEnv(p))
}
diff --git a/cmd/utils/customflags_test.go b/cmd/utils/customflags_test.go
index 61c000238f..24c6cff635 100644
--- a/cmd/utils/customflags_test.go
+++ b/cmd/utils/customflags_test.go
@@ -23,18 +23,15 @@ import (
)
func TestPathExpansion(t *testing.T) {
-
user, _ := user.Current()
-
tests := map[string]string{
"/home/someuser/tmp": "/home/someuser/tmp",
"~/tmp": user.HomeDir + "/tmp",
+ "~thisOtherUser/b/": "~thisOtherUser/b",
"$DDDXXX/a/b": "/tmp/a/b",
"/a/b/": "/a/b",
}
-
os.Setenv("DDDXXX", "/tmp")
-
for test, expected := range tests {
got := expandPath(test)
if got != expected {
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 01f9976530..63b97970f0 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -21,6 +21,7 @@ import (
"fmt"
"log"
"math/big"
+ "net"
"net/http"
"os"
"path/filepath"
@@ -34,6 +35,7 @@ import (
"github.com/expanse-project/go-expanse/accounts"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/core"
+ "github.com/expanse-project/go-expanse/core/vm"
"github.com/expanse-project/go-expanse/crypto"
"github.com/expanse-project/go-expanse/exp"
"github.com/expanse-project/go-expanse/ethdb"
@@ -44,6 +46,8 @@ import (
"github.com/expanse-project/go-expanse/rpc/api"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/comms"
+ "github.com/expanse-project/go-expanse/rpc/shared"
+ "github.com/expanse-project/go-expanse/rpc/useragent"
"github.com/expanse-project/go-expanse/xeth"
)
@@ -172,6 +176,25 @@ var (
Value: "",
}
+ // vm flags
+ VMDebugFlag = cli.BoolFlag{
+ Name: "vmdebug",
+ Usage: "Virtual Machine debug output",
+ }
+ VMForceJitFlag = cli.BoolFlag{
+ Name: "forcejit",
+ Usage: "Force the JIT VM to take precedence",
+ }
+ VMJitCacheFlag = cli.IntFlag{
+ Name: "jitcache",
+ Usage: "Amount of cached JIT VM programs",
+ Value: 64,
+ }
+ VMEnableJitFlag = cli.BoolFlag{
+ Name: "jitvm",
+ Usage: "Enable the JIT VM",
+ }
+
// logging and debug settings
LogFileFlag = cli.StringFlag{
Name: "logfile",
@@ -196,10 +219,6 @@ var (
Usage: "The syntax of the argument is a comma-separated list of pattern=N, where pattern is a literal file name (minus the \".go\" suffix) or \"glob\" pattern and N is a log verbosity level.",
Value: glog.GetVModule(),
}
- VMDebugFlag = cli.BoolFlag{
- Name: "vmdebug",
- Usage: "Virtual Machine debug output",
- }
BacktraceAtFlag = cli.GenericFlag{
Name: "backtrace_at",
Usage: "If set to a file and line number (e.g., \"block.go:271\") holding a logging statement, a stack trace will be logged",
@@ -434,24 +453,25 @@ func SetupLogger(ctx *cli.Context) {
glog.SetLogDir(ctx.GlobalString(LogFileFlag.Name))
}
+// SetupVM configured the VM package's global settings
+func SetupVM(ctx *cli.Context) {
+ 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)
}
@@ -460,14 +480,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.
@@ -478,7 +498,7 @@ func MakeAccountManager(ctx *cli.Context) *accounts.Manager {
}
func IpcSocketPath(ctx *cli.Context) (ipcpath string) {
- if common.IsWindows() {
+ if runtime.GOOS == "windows" {
ipcpath = common.DefaultIpcPath()
if ctx.GlobalIsSet(IPCPathFlag.Name) {
ipcpath = ctx.GlobalString(IPCPathFlag.Name)
@@ -501,15 +521,20 @@ func StartIPC(exp *exp.Expanse, ctx *cli.Context) error {
Endpoint: IpcSocketPath(ctx),
}
- xeth := xeth.New(exp, nil)
- codec := codec.JSON
+ initializer := func(conn net.Conn) (shared.ExpanseApi, error) {
+ fe := useragent.NewRemoteFrontend(conn, exp.AccountManager())
+ xeth := xeth.New(exp, fe)
+ codec := codec.JSON
- apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec, xeth, exp)
- if err != nil {
- return err
+ apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec, xeth, exp)
+ 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(exp *exp.Expanse, ctx *cli.Context) error {
diff --git a/common/compiler/solidity_test.go b/common/compiler/solidity_test.go
index 780e879709..cf9aec4407 100644
--- a/common/compiler/solidity_test.go
+++ b/common/compiler/solidity_test.go
@@ -20,6 +20,7 @@ import (
"encoding/json"
"io/ioutil"
"os"
+ "path"
"testing"
"github.com/expanse-project/go-expanse/common"
@@ -94,7 +95,7 @@ func TestSaveInfo(t *testing.T) {
if err != nil {
t.Errorf("%v", err)
}
- filename := "/tmp/solctest.info.json"
+ filename := path.Join(os.TempDir(), "solctest.info.json")
os.Remove(filename)
cinfohash, err := SaveInfo(&cinfo, filename)
if err != nil {
diff --git a/common/docserver/docserver.go b/common/docserver/docserver.go
index cc5d17b0b5..bc865b0a5c 100644
--- a/common/docserver/docserver.go
+++ b/common/docserver/docserver.go
@@ -38,7 +38,6 @@ func New(docRoot string) (self *DocServer) {
DocRoot: docRoot,
schemes: []string{"file"},
}
- self.DocRoot = "/tmp/"
self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot)))
return
}
diff --git a/common/docserver/docserver_test.go b/common/docserver/docserver_test.go
index f02a55f75f..70e20e8bde 100644
--- a/common/docserver/docserver_test.go
+++ b/common/docserver/docserver_test.go
@@ -20,6 +20,7 @@ import (
"io/ioutil"
"net/http"
"os"
+ "path"
"testing"
"github.com/expanse-project/go-expanse/common"
@@ -27,12 +28,18 @@ import (
)
func TestGetAuthContent(t *testing.T) {
- text := "test"
- hash := common.Hash{}
- copy(hash[:], crypto.Sha3([]byte(text)))
- ioutil.WriteFile("/tmp/test.content", []byte(text), os.ModePerm)
+ dir, err := ioutil.TempDir("", "docserver-test")
+ if err != nil {
+ t.Fatal("cannot create temporary directory:", err)
+ }
+ defer os.RemoveAll(dir)
+ ds := New(dir)
- ds := New("/tmp/")
+ text := "test"
+ hash := crypto.Sha3Hash([]byte(text))
+ if err := ioutil.WriteFile(path.Join(dir, "test.content"), []byte(text), os.ModePerm); err != nil {
+ t.Fatal("could not write test file", err)
+ }
content, err := ds.GetAuthContent("file:///test.content", hash)
if err != nil {
t.Errorf("no error expected, got %v", err)
diff --git a/common/path.go b/common/path.go
index 80f4fb4ea9..ecc64ecbfa 100644
--- a/common/path.go
+++ b/common/path.go
@@ -116,14 +116,3 @@ func DefaultIpcPath() string {
}
return filepath.Join(DefaultDataDir(), "gexp.ipc")
}
-
-func IsWindows() bool {
- return runtime.GOOS == "windows"
-}
-
-func WindonizePath(path string) string {
- if string(path[0]) == "/" && IsWindows() {
- path = path[1:]
- }
- return path
-}
diff --git a/common/size_test.go b/common/size_test.go
index 0f373c18ef..de6e492f4b 100644
--- a/common/size_test.go
+++ b/common/size_test.go
@@ -40,7 +40,7 @@ func (s *SizeSuite) TestStorageSizeString(c *checker.C) {
c.Assert(StorageSize(data3).String(), checker.Equals, exp3)
}
-func (s *CommonSuite) TestCommon(c *checker.C) {
+func (s *SizeSuite) TestCommon(c *checker.C) {
expanse := CurrencyToString(BigPow(10, 19))
finney := CurrencyToString(BigPow(10, 16))
szabo := CurrencyToString(BigPow(10, 13))
diff --git a/core/bench_test.go b/core/bench_test.go
index 87e3980854..b2a624187a 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 ce811005af..1f1f26daf7 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,25 +56,35 @@ type BlockProcessor struct {
eventMux *event.TypeMux
}
-func NewBlockProcessor(db, extra common.Database, pow pow.PoW, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
+// TODO: type GasPool big.Int
+//
+// GasPool is implemented by state.StateObject. This is a historical
+// coincidence. Gas tracking should move out of StateObject.
+
+// GasPool tracks the amount of gas available during
+// execution of the transactions in a block.
+type GasPool interface {
+ AddGas(gas, price *big.Int)
+ SubGas(gas, price *big.Int) error
+}
+
+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,
eventMux: eventMux,
}
-
return sm
}
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
- coinbase := statedb.GetOrNewStateObject(block.Coinbase())
- coinbase.SetGasLimit(block.GasLimit())
+ gp := statedb.GetOrNewStateObject(block.Coinbase())
+ gp.SetGasLimit(block.GasLimit())
// Process the transactions on to parent state
- receipts, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
+ receipts, err = sm.ApplyTransactions(gp, statedb, block, block.Transactions(), transientProcess)
if err != nil {
return nil, err
}
@@ -83,11 +92,8 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block
return receipts, nil
}
-func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
- // If we are mining this block and validating we want to set the logs back to 0
-
- cb := statedb.GetStateObject(coinbase.Address())
- _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, header), tx, cb)
+func (self *BlockProcessor) ApplyTransaction(gp GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
+ _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, header), tx, gp)
if err != nil {
return nil, nil, err
}
@@ -122,7 +128,7 @@ func (self *BlockProcessor) ChainManager() *ChainManager {
return self.bc
}
-func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, error) {
+func (self *BlockProcessor) ApplyTransactions(gp GasPool, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, error) {
var (
receipts types.Receipts
totalUsedGas = big.NewInt(0)
@@ -134,7 +140,7 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
for i, tx := range txs {
statedb.StartRecord(tx.Hash(), block.Hash(), i)
- receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, header, tx, totalUsedGas, transientProcess)
+ receipt, txGas, err := self.ApplyTransaction(gp, statedb, header, tx, totalUsedGas, transientProcess)
if err != nil {
return nil, err
}
@@ -201,13 +207,13 @@ 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()
// Block validation
- if err = ValidateHeader(sm.Pow, header, parent, false); err != nil {
+ if err = ValidateHeader(sm.Pow, header, parent, false, false); err != nil {
return
}
@@ -331,7 +337,7 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4])
}
- if err := ValidateHeader(sm.Pow, uncle, ancestors[uncle.ParentHash], true); err != nil {
+ if err := ValidateHeader(sm.Pow, uncle, ancestors[uncle.ParentHash], true, true); err != nil {
return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
}
}
@@ -342,7 +348,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
@@ -352,41 +358,35 @@ 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())
- if len(receipts) > 0 {
- // coalesce logs
- for _, receipt := range receipts {
- logs = append(logs, receipt.Logs()...)
- }
- return
+ receipts := GetBlockReceipts(sm.chainDb, block.Hash())
+ // coalesce logs
+ for _, receipt := range receipts {
+ logs = append(logs, receipt.Logs()...)
}
-
- // 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"
// Validates a block. Returns an error if the block is invalid.
-func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, checkPow bool) error {
+func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, checkPow, uncle bool) error {
if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
}
- if block.Time > uint64(time.Now().Unix()) {
- return BlockFutureErr
+ if uncle {
+ if block.Time.Cmp(common.MaxBig) == 1 {
+ return BlockTSTooBigErr
+ }
+ } else {
+ if block.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 {
+ return BlockFutureErr
+ }
}
- if block.Time <= parent.Time() {
+ if block.Time.Cmp(parent.Time()) != 1 {
return BlockEqualTSErr
}
- expd := CalcDifficulty(block.Time, parent.Time(), parent.Number(), parent.Difficulty())
+ expd := CalcDifficulty(block.Time.Uint64(), parent.Time().Uint64(), parent.Number(), parent.Difficulty())
if expd.Cmp(block.Difficulty) != 0 {
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
}
diff --git a/core/block_processor_test.go b/core/block_processor_test.go
index faf74feb3b..3af0926bf1 100644
--- a/core/block_processor_test.go
+++ b/core/block_processor_test.go
@@ -33,28 +33,28 @@ 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)
+ err := ValidateHeader(pow, header, chain.Genesis(), false, false)
if err != BlockNumberErr {
t.Errorf("expected block number error, got %q", err)
}
header = makeHeader(chain.Genesis(), statedb)
- err = ValidateHeader(pow, header, chain.Genesis(), false)
+ err = ValidateHeader(pow, header, chain.Genesis(), false, false)
if err == BlockNumberErr {
t.Errorf("didn't expect block number error")
}
diff --git a/core/blocks.go b/core/blocks.go
index 0903146ae5..f01e6f1bf4 100644
--- a/core/blocks.go
+++ b/core/blocks.go
@@ -20,8 +20,5 @@ import "github.com/expanse-project/go-expanse/common"
// Set of manually tracked bad hashes (usually hard forks)
var BadHashes = map[common.Hash]bool{
- common.HexToHash("f269c503aed286caaa0d114d6a5320e70abbc2febe37953207e76a2873f2ba79"): true,
- common.HexToHash("38f5bbbffd74804820ffa4bab0cd540e9de229725afb98c1a7e57936f4a714bc"): true,
- common.HexToHash("7064455b364775a16afbdecd75370e912c6e2879f202eda85b9beae547fff3ac"): true,
- common.HexToHash("5b7c80070a6eff35f3eb3181edb023465c776d40af2885571e1bc4689f3a44d8"): true,
+ common.HexToHash("05bef30ef572270f654746da22639a7a0c97dd97a7050b9e252391996aaeb689"): true,
}
diff --git a/core/canary.go b/core/canary.go
index 8f99ad036c..be853e6acb 100644
--- a/core/canary.go
+++ b/core/canary.go
@@ -24,10 +24,10 @@ import (
)
var (
- jeff = common.HexToAddress("a8edb1ac2c86d3d9d78f96cd18001f60df29e52c")
- vitalik = common.HexToAddress("1baf27b88c48dd02b744999cf3522766929d2b2a")
- christoph = common.HexToAddress("60d11b58744784dc97f878f7e3749c0f1381a004")
- gav = common.HexToAddress("4bb7e8ae99b645c2b7860b8f3a2328aae28bd80a")
+ jeff = common.HexToAddress("959c33de5961820567930eccce51ea715c496f85")
+ vitalik = common.HexToAddress("c8158da0b567a8cc898991c2c2a073af67dc03a9")
+ christoph = common.HexToAddress("7a19a893f91d5b6e2cdf941b6acbba2cbcf431ee")
+ gav = common.HexToAddress("539dd9aaf45c3feb03f9c004f4098bd3268fef6b")
)
// Canary will check the 0'd address of the 4 contracts above.
diff --git a/core/chain_makers.go b/core/chain_makers.go
index e61efc15a5..2a9be36c91 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -166,16 +166,21 @@ func GenerateChain(parent *types.Block, db common.Database, n int, gen func(int,
}
func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
- time := parent.Time() + 10 // block time is fixed at 10 seconds
+ var time *big.Int
+ if parent.Time() == nil {
+ time = big.NewInt(10)
+ } else {
+ time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
+ }
return &types.Header{
Root: state.Root(),
ParentHash: parent.Hash(),
Coinbase: parent.Coinbase(),
- Difficulty: CalcDifficulty(time, parent.Time(), parent.Number(), parent.Difficulty()),
+ Difficulty: CalcDifficulty(time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
GasLimit: CalcGasLimit(parent),
GasUsed: new(big.Int),
Number: new(big.Int).Add(parent.Number(), common.Big1),
- Time: uint64(time),
+ Time: time,
}
}
@@ -184,9 +189,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 69d739af9f..ffca9e8c93 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 9c352daf55..25515dbd4c 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -55,10 +55,8 @@ const (
)
type ChainManager struct {
- //exp EthManager
- blockDb common.Database
- stateDb common.Database
- extraDb common.Database
+ //eth EthManager
+ 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)
}
@@ -600,7 +596,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
// Allow up to MaxFuture second in the future blocks. If this limit
// is exceeded the chain is discarded and processed at a later time
// if given.
- if max := uint64(time.Now().Unix()) + maxTimeFutureBlocks; block.Time() > max {
+ max := big.NewInt(time.Now().Unix() + maxTimeFutureBlocks)
+ if block.Time().Cmp(max) == 1 {
return i, fmt.Errorf("%v: BlockFutureErr, %v > %v", BlockFutureErr, block.Time(), max)
}
@@ -632,15 +629,15 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
switch status {
case CanonStatTy:
if glog.V(logger.Debug) {
- glog.Infof("[%v] inserted block #%d (%d TXs %d UNCs) (%x...). Took %v\n", time.Now().UnixNano(), block.Number(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
+ glog.Infof("[%v] inserted block #%d (%d TXs %v G %d UNCs) (%x...). Took %v\n", time.Now().UnixNano(), block.Number(), len(block.Transactions()), block.GasUsed(), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
}
queue[i] = ChainEvent{block, block.Hash(), logs}
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 +648,9 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
queue[i] = ChainSplitEvent{block, logs}
queueEvent.splitCount++
}
- PutBlockReceipts(self.extraDb, block, receipts)
+ if err := PutBlockReceipts(self.chainDb, block, receipts); err != nil {
+ glog.V(logger.Warn).Infoln("error writing block receipts:", err)
+ }
stats.processed++
}
@@ -733,8 +732,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 4345e56d9f..b33d5dde7f 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 e7018eaf42..4412137e33 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/error.go b/core/error.go
index 37e4fc0e83..c7e023733d 100644
--- a/core/error.go
+++ b/core/error.go
@@ -25,9 +25,10 @@ import (
)
var (
- BlockNumberErr = errors.New("block number invalid")
- BlockFutureErr = errors.New("block time is in the future")
- BlockEqualTSErr = errors.New("block time stamp equal to previous")
+ BlockNumberErr = errors.New("block number invalid")
+ BlockFutureErr = errors.New("block time is in the future")
+ BlockTSTooBigErr = errors.New("block time too big")
+ BlockEqualTSErr = errors.New("block time stamp equal to previous")
)
// Parent error. In case a parent is unknown this error will be thrown
diff --git a/core/execution.go b/core/execution.go
index a31bc7dccc..91f63d0366 100644
--- a/core/execution.go
+++ b/core/execution.go
@@ -26,6 +26,7 @@ import (
"github.com/expanse-project/go-expanse/params"
)
+// Execution is the execution environment for the given call or create action.
type Execution struct {
env vm.Environment
address *common.Address
@@ -35,12 +36,15 @@ type Execution struct {
Gas, price, value *big.Int
}
+// NewExecution returns a new execution environment that handles all calling
+// and creation logic defined by the YP.
func NewExecution(env vm.Environment, address *common.Address, input []byte, gas, gasPrice, value *big.Int) *Execution {
exe := &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value}
exe.evm = vm.NewVm(env)
return exe
}
+// Call executes within the given context
func (self *Execution) Call(codeAddr common.Address, caller vm.ContextRef) ([]byte, error) {
// Retrieve the executing code
code := self.env.State().GetCode(codeAddr)
@@ -48,6 +52,9 @@ func (self *Execution) Call(codeAddr common.Address, caller vm.ContextRef) ([]by
return self.exec(&codeAddr, code, caller)
}
+// Create creates a new contract and runs the initialisation procedure of the
+// contract. This returns the returned code for the contract and is stored
+// elsewhere.
func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, account *state.StateObject) {
// Input must be nil for create
code := self.input
@@ -63,16 +70,24 @@ func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, acco
return
}
+// exec executes the given code and executes within the contextAddr context.
func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.ContextRef) (ret []byte, err error) {
env := self.env
evm := self.evm
+ // Depth check execution. Fail if we're trying to execute above the
+ // limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(self.Gas, self.price)
return nil, vm.DepthError
}
- vsnapshot := env.State().Copy()
+ if !env.CanTransfer(env.State().GetStateObject(caller.Address()), self.value) {
+ caller.ReturnGas(self.Gas, self.price)
+
+ return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", self.value, env.State().GetBalance(caller.Address()))
+ }
+
var createAccount bool
if self.address == nil {
// Generate a new address
@@ -95,15 +110,7 @@ func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.
} else {
to = env.State().GetOrNewStateObject(*self.address)
}
-
- err = env.Transfer(from, to, self.value)
- if err != nil {
- env.State().Set(vsnapshot)
-
- caller.ReturnGas(self.Gas, self.price)
-
- return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance())
- }
+ vm.Transfer(from, to, self.value)
context := vm.NewContext(caller, to, self.value, self.Gas, self.price)
context.SetCallCode(contextAddr, code)
diff --git a/core/filter.go b/core/filter.go
index d33a446244..26889973ab 100644
--- a/core/filter.go
+++ b/core/filter.go
@@ -22,6 +22,8 @@ import (
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/core/state"
"github.com/expanse-project/go-expanse/core/types"
+ "github.com/expanse-project/go-expanse/logger"
+ "github.com/expanse-project/go-expanse/logger/glog"
)
type AccountChange struct {
@@ -111,7 +113,7 @@ done:
// Get the logs of the block
unfiltered, err := self.exp.BlockProcessor().GetLogs(block)
if err != nil {
- chainlogger.Warnln("err: filter get logs ", err)
+ glog.V(logger.Warn).Infoln("err: filter get logs ", err)
break
}
diff --git a/core/genesis.go b/core/genesis.go
index d98163bff9..ac5ddeed3a 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))
@@ -73,7 +73,7 @@ func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*typ
difficulty := common.String2Big(genesis.Difficulty)
block := types.NewBlock(&types.Header{
Nonce: types.EncodeNonce(common.String2Big(genesis.Nonce).Uint64()),
- Time: common.String2Big(genesis.Timestamp).Uint64(),
+ Time: common.String2Big(genesis.Timestamp),
ParentHash: common.HexToHash(genesis.ParentHash),
Extra: common.FromHex(genesis.ExtraData),
GasLimit: common.String2Big(genesis.GasLimit),
@@ -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 f36ff71548..ce62e63059 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/state/state_object.go b/core/state/state_object.go
index 6fd56139a5..62988ae31d 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -82,8 +82,9 @@ type StateObject struct {
// Mark for deletion
// When an object is marked for deletion it will be delete from the trie
// during the "update" phase of the state transition
- remove bool
- dirty bool
+ remove bool
+ deleted bool
+ dirty bool
}
func (self *StateObject) Reset() {
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 65d09562c4..d4f22877ab 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -203,18 +203,20 @@ func (self *StateDB) UpdateStateObject(stateObject *StateObject) {
// Delete the given state object and delete it from the state trie
func (self *StateDB) DeleteStateObject(stateObject *StateObject) {
+ stateObject.deleted = true
+
addr := stateObject.Address()
self.trie.Delete(addr[:])
-
- //delete(self.stateObjects, addr.Str())
}
// Retrieve a state object given my the address. Nil if not found
-func (self *StateDB) GetStateObject(addr common.Address) *StateObject {
- //addr = common.Address(addr)
-
- stateObject := self.stateObjects[addr.Str()]
+func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObject) {
+ stateObject = self.stateObjects[addr.Str()]
if stateObject != nil {
+ if stateObject.deleted {
+ stateObject = nil
+ }
+
return stateObject
}
@@ -236,7 +238,7 @@ func (self *StateDB) SetStateObject(object *StateObject) {
// Retrieve a state object or create a new state object if nil
func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
stateObject := self.GetStateObject(addr)
- if stateObject == nil {
+ if stateObject == nil || stateObject.deleted {
stateObject = self.CreateAccount(addr)
}
diff --git a/core/state_transition.go b/core/state_transition.go
index b2f305c6cc..7c78f2c16e 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -45,7 +45,7 @@ import (
* 6) Derive new state root
*/
type StateTransition struct {
- coinbase common.Address
+ gp GasPool
msg Message
gas, gasPrice *big.Int
initialGas *big.Int
@@ -53,8 +53,6 @@ type StateTransition struct {
data []byte
state *state.StateDB
- cb, rec, sen *state.StateObject
-
env vm.Environment
}
@@ -96,13 +94,13 @@ func IntrinsicGas(data []byte) *big.Int {
return igas
}
-func ApplyMessage(env vm.Environment, msg Message, coinbase *state.StateObject) ([]byte, *big.Int, error) {
- return NewStateTransition(env, msg, coinbase).transitionState()
+func ApplyMessage(env vm.Environment, msg Message, gp GasPool) ([]byte, *big.Int, error) {
+ return NewStateTransition(env, msg, gp).transitionState()
}
-func NewStateTransition(env vm.Environment, msg Message, coinbase *state.StateObject) *StateTransition {
+func NewStateTransition(env vm.Environment, msg Message, gp GasPool) *StateTransition {
return &StateTransition{
- coinbase: coinbase.Address(),
+ gp: gp,
env: env,
msg: msg,
gas: new(big.Int),
@@ -111,13 +109,9 @@ func NewStateTransition(env vm.Environment, msg Message, coinbase *state.StateOb
value: msg.Value(),
data: msg.Data(),
state: env.State(),
- cb: coinbase,
}
}
-func (self *StateTransition) Coinbase() *state.StateObject {
- return self.state.GetOrNewStateObject(self.coinbase)
-}
func (self *StateTransition) From() (*state.StateObject, error) {
f, err := self.msg.From()
if err != nil {
@@ -160,7 +154,7 @@ func (self *StateTransition) BuyGas() error {
if sender.Balance().Cmp(mgval) < 0 {
return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance())
}
- if err = self.Coinbase().SubGas(mgas, self.gasPrice); err != nil {
+ if err = self.gp.SubGas(mgas, self.gasPrice); err != nil {
return err
}
self.AddGas(mgas)
@@ -241,13 +235,12 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
}
self.refundGas()
- self.state.AddBalance(self.coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
+ self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice))
return ret, self.gasUsed(), err
}
func (self *StateTransition) refundGas() {
- coinbase := self.Coinbase()
sender, _ := self.From() // err already checked
// Return remaining gas
remaining := new(big.Int).Mul(self.gas, self.gasPrice)
@@ -258,7 +251,7 @@ func (self *StateTransition) refundGas() {
self.gas.Add(self.gas, refund)
self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice))
- coinbase.AddGas(self.gas, self.gasPrice)
+ self.gp.AddGas(self.gas, self.gasPrice)
}
func (self *StateTransition) gasUsed() *big.Int {
diff --git a/core/types/block.go b/core/types/block.go
index a7d4037282..7cf9aae5d5 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -60,7 +60,7 @@ type Header struct {
Number *big.Int // The block number
GasLimit *big.Int // Gas limit
GasUsed *big.Int // Gas used
- Time uint64 // Creation time
+ Time *big.Int // Creation time
Extra []byte // Extra data
MixDigest common.Hash // for quick difficulty verification
Nonce BlockNonce
@@ -94,7 +94,7 @@ func (h *Header) UnmarshalJSON(data []byte) error {
Coinbase string
Difficulty string
GasLimit string
- Time uint64
+ Time *big.Int
Extra string
}
dec := json.NewDecoder(bytes.NewReader(data))
@@ -210,6 +210,9 @@ func NewBlockWithHeader(header *Header) *Block {
func copyHeader(h *Header) *Header {
cpy := *h
+ if cpy.Time = new(big.Int); h.Time != nil {
+ cpy.Time.Set(h.Time)
+ }
if cpy.Difficulty = new(big.Int); h.Difficulty != nil {
cpy.Difficulty.Set(h.Difficulty)
}
@@ -301,13 +304,13 @@ func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number)
func (b *Block) GasLimit() *big.Int { return new(big.Int).Set(b.header.GasLimit) }
func (b *Block) GasUsed() *big.Int { return new(big.Int).Set(b.header.GasUsed) }
func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) }
+func (b *Block) Time() *big.Int { return new(big.Int).Set(b.header.Time) }
func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() }
func (b *Block) MixDigest() common.Hash { return b.header.MixDigest }
func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) }
func (b *Block) Bloom() Bloom { return b.header.Bloom }
func (b *Block) Coinbase() common.Address { return b.header.Coinbase }
-func (b *Block) Time() uint64 { return b.header.Time }
func (b *Block) Root() common.Hash { return b.header.Root }
func (b *Block) ParentHash() common.Hash { return b.header.ParentHash }
func (b *Block) TxHash() common.Hash { return b.header.TxHash }
diff --git a/core/types/block_test.go b/core/types/block_test.go
index f884250022..ea2436c02b 100644
--- a/core/types/block_test.go
+++ b/core/types/block_test.go
@@ -47,7 +47,7 @@ func TestBlockEncoding(t *testing.T) {
check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"))
check("Hash", block.Hash(), common.HexToHash("0a5843ac1cb04865017cb35a57b50b07084e5fcee39b5acadade33149f4fff9e"))
check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4))
- check("Time", block.Time(), uint64(1426516743))
+ check("Time", block.Time(), big.NewInt(1426516743))
check("Size", block.Size(), common.StorageSize(len(blockEnc)))
tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)
diff --git a/core/vm/context.go b/core/vm/context.go
index bc8b9f9067..26205f5e0b 100644
--- a/core/vm/context.go
+++ b/core/vm/context.go
@@ -35,6 +35,7 @@ type Context struct {
jumpdests destinations // result of JUMPDEST analysis.
Code []byte
+ Input []byte
CodeAddr *common.Address
value, Gas, UsedGas, Price *big.Int
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 85b15bd60a..8d2c74dd03 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -94,7 +94,7 @@ func ecrecoverFunc(in []byte) []byte {
v := byte(vbig.Uint64())
if !crypto.ValidateSignatureValues(v, r, s) {
- glog.V(logger.Error).Infof("EC RECOVER FAIL: v, r or s value invalid")
+ glog.V(logger.Debug).Infof("EC RECOVER FAIL: v, r or s value invalid")
return nil
}
diff --git a/core/vm/environment.go b/core/vm/environment.go
index 63626f795d..08ebdc875c 100644
--- a/core/vm/environment.go
+++ b/core/vm/environment.go
@@ -33,9 +33,10 @@ type Environment interface {
BlockNumber() *big.Int
GetHash(n uint64) common.Hash
Coinbase() common.Address
- Time() uint64
+ Time() *big.Int
Difficulty() *big.Int
GasLimit() *big.Int
+ CanTransfer(from Account, balance *big.Int) bool
Transfer(from, to Account, amount *big.Int) error
AddLog(*state.Log)
AddStructLog(StructLog)
diff --git a/core/vm/gas.go b/core/vm/gas.go
index 7845acb50b..bd52ba43ed 100644
--- a/core/vm/gas.go
+++ b/core/vm/gas.go
@@ -54,8 +54,8 @@ func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
return err
}
- if r.stackPush > 0 && len(stack.data)-r.stackPop+r.stackPush > int(params.StackLimit.Int64())+1 {
- return fmt.Errorf("stack limit reached %d (%d)", len(stack.data), params.StackLimit.Int64())
+ if r.stackPush > 0 && stack.len()-r.stackPop+r.stackPush > int(params.StackLimit.Int64()) {
+ return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64())
}
gas.Add(gas, r.gas)
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
new file mode 100644
index 0000000000..dd570ead3f
--- /dev/null
+++ b/core/vm/instructions.go
@@ -0,0 +1,534 @@
+// Copyright 2014 The go-expanse Authors
+// This file is part of the go-expanse library.
+//
+// The go-expanse 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-expanse 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-expanse library. If not, see .
+
+package vm
+
+import (
+ "math/big"
+
+ "github.com/expanse-project/go-expanse/common"
+ "github.com/expanse-project/go-expanse/core/state"
+ "github.com/expanse-project/go-expanse/crypto"
+ "github.com/expanse-project/go-expanse/params"
+)
+
+type instrFn func(instr instruction, env Environment, context *Context, memory *Memory, stack *stack)
+type instrExFn func(instr instruction, ret *big.Int, env Environment, context *Context, memory *Memory, stack *stack)
+
+type instruction struct {
+ op OpCode
+ pc uint64
+ fn instrFn
+ specFn instrExFn
+ data *big.Int
+
+ gas *big.Int
+ spop int
+ spush int
+}
+
+func opStaticJump(instr instruction, ret *big.Int, env Environment, context *Context, memory *Memory, stack *stack) {
+ ret.Set(instr.data)
+}
+
+func opAdd(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ stack.push(U256(x.Add(x, y)))
+}
+
+func opSub(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ stack.push(U256(x.Sub(x, y)))
+}
+
+func opMul(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ stack.push(U256(x.Mul(x, y)))
+}
+
+func opDiv(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ if y.Cmp(common.Big0) != 0 {
+ stack.push(U256(x.Div(x, y)))
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+
+func opSdiv(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := S256(stack.pop()), S256(stack.pop())
+ if y.Cmp(common.Big0) == 0 {
+ stack.push(new(big.Int))
+ return
+ } else {
+ n := new(big.Int)
+ if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
+ n.SetInt64(-1)
+ } else {
+ n.SetInt64(1)
+ }
+
+ res := x.Div(x.Abs(x), y.Abs(y))
+ res.Mul(res, n)
+
+ stack.push(U256(res))
+ }
+}
+
+func opMod(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ if y.Cmp(common.Big0) == 0 {
+ stack.push(new(big.Int))
+ } else {
+ stack.push(U256(x.Mod(x, y)))
+ }
+}
+
+func opSmod(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := S256(stack.pop()), S256(stack.pop())
+
+ if y.Cmp(common.Big0) == 0 {
+ stack.push(new(big.Int))
+ } else {
+ n := new(big.Int)
+ if x.Cmp(common.Big0) < 0 {
+ n.SetInt64(-1)
+ } else {
+ n.SetInt64(1)
+ }
+
+ res := x.Mod(x.Abs(x), y.Abs(y))
+ res.Mul(res, n)
+
+ stack.push(U256(res))
+ }
+}
+
+func opExp(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ stack.push(U256(x.Exp(x, y, Pow256)))
+}
+
+func opSignExtend(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ back := stack.pop()
+ if back.Cmp(big.NewInt(31)) < 0 {
+ bit := uint(back.Uint64()*8 + 7)
+ num := stack.pop()
+ mask := back.Lsh(common.Big1, bit)
+ mask.Sub(mask, common.Big1)
+ if common.BitTest(num, int(bit)) {
+ num.Or(num, mask.Not(mask))
+ } else {
+ num.And(num, mask)
+ }
+
+ stack.push(U256(num))
+ }
+}
+
+func opNot(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x := stack.pop()
+ stack.push(U256(x.Not(x)))
+}
+
+func opLt(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ if x.Cmp(y) < 0 {
+ stack.push(big.NewInt(1))
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+
+func opGt(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ if x.Cmp(y) > 0 {
+ stack.push(big.NewInt(1))
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+
+func opSlt(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := S256(stack.pop()), S256(stack.pop())
+ if x.Cmp(S256(y)) < 0 {
+ stack.push(big.NewInt(1))
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+
+func opSgt(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := S256(stack.pop()), S256(stack.pop())
+ if x.Cmp(y) > 0 {
+ stack.push(big.NewInt(1))
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+
+func opEq(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ if x.Cmp(y) == 0 {
+ stack.push(big.NewInt(1))
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+
+func opIszero(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x := stack.pop()
+ if x.Cmp(common.Big0) > 0 {
+ stack.push(new(big.Int))
+ } else {
+ stack.push(big.NewInt(1))
+ }
+}
+
+func opAnd(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ stack.push(x.And(x, y))
+}
+func opOr(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ stack.push(x.Or(x, y))
+}
+func opXor(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y := stack.pop(), stack.pop()
+ stack.push(x.Xor(x, y))
+}
+func opByte(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ th, val := stack.pop(), stack.pop()
+ if th.Cmp(big.NewInt(32)) < 0 {
+ byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
+ stack.push(byte)
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+func opAddmod(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y, z := stack.pop(), stack.pop(), stack.pop()
+ if z.Cmp(Zero) > 0 {
+ add := x.Add(x, y)
+ add.Mod(add, z)
+ stack.push(U256(add))
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+func opMulmod(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ x, y, z := stack.pop(), stack.pop(), stack.pop()
+ if z.Cmp(Zero) > 0 {
+ mul := x.Mul(x, y)
+ mul.Mod(mul, z)
+ stack.push(U256(mul))
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+
+func opSha3(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ offset, size := stack.pop(), stack.pop()
+ hash := crypto.Sha3(memory.Get(offset.Int64(), size.Int64()))
+
+ stack.push(common.BytesToBig(hash))
+}
+
+func opAddress(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(common.Bytes2Big(context.Address().Bytes()))
+}
+
+func opBalance(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ addr := common.BigToAddress(stack.pop())
+ balance := env.State().GetBalance(addr)
+
+ stack.push(new(big.Int).Set(balance))
+}
+
+func opOrigin(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(env.Origin().Big())
+}
+
+func opCaller(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(common.Bytes2Big(context.caller.Address().Bytes()))
+}
+
+func opCallValue(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(new(big.Int).Set(context.value))
+}
+
+func opCalldataLoad(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(common.Bytes2Big(getData(context.Input, stack.pop(), common.Big32)))
+}
+
+func opCalldataSize(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(big.NewInt(int64(len(context.Input))))
+}
+
+func opCalldataCopy(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ var (
+ mOff = stack.pop()
+ cOff = stack.pop()
+ l = stack.pop()
+ )
+ memory.Set(mOff.Uint64(), l.Uint64(), getData(context.Input, cOff, l))
+}
+
+func opExtCodeSize(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ addr := common.BigToAddress(stack.pop())
+ l := big.NewInt(int64(len(env.State().GetCode(addr))))
+ stack.push(l)
+}
+
+func opCodeSize(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ l := big.NewInt(int64(len(context.Code)))
+ stack.push(l)
+}
+
+func opCodeCopy(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ var (
+ mOff = stack.pop()
+ cOff = stack.pop()
+ l = stack.pop()
+ )
+ codeCopy := getData(context.Code, cOff, l)
+
+ memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
+}
+
+func opExtCodeCopy(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ var (
+ addr = common.BigToAddress(stack.pop())
+ mOff = stack.pop()
+ cOff = stack.pop()
+ l = stack.pop()
+ )
+ codeCopy := getData(env.State().GetCode(addr), cOff, l)
+
+ memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
+}
+
+func opGasprice(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(new(big.Int).Set(context.Price))
+}
+
+func opBlockhash(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ num := stack.pop()
+
+ n := new(big.Int).Sub(env.BlockNumber(), common.Big257)
+ if num.Cmp(n) > 0 && num.Cmp(env.BlockNumber()) < 0 {
+ stack.push(env.GetHash(num.Uint64()).Big())
+ } else {
+ stack.push(new(big.Int))
+ }
+}
+
+func opCoinbase(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(env.Coinbase().Big())
+}
+
+func opTimestamp(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(U256(new(big.Int).Set(env.Time())))
+}
+
+func opNumber(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(U256(new(big.Int).Set(env.BlockNumber())))
+}
+
+func opDifficulty(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(U256(new(big.Int).Set(env.Difficulty())))
+}
+
+func opGasLimit(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(U256(new(big.Int).Set(env.GasLimit())))
+}
+
+func opPop(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.pop()
+}
+
+func opPush(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(new(big.Int).Set(instr.data))
+}
+
+func opDup(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.dup(int(instr.data.Int64()))
+}
+
+func opSwap(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.swap(int(instr.data.Int64()))
+}
+
+func opLog(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ n := int(instr.data.Int64())
+ topics := make([]common.Hash, n)
+ mStart, mSize := stack.pop(), stack.pop()
+ for i := 0; i < n; i++ {
+ topics[i] = common.BigToHash(stack.pop())
+ }
+
+ d := memory.Get(mStart.Int64(), mSize.Int64())
+ log := state.NewLog(context.Address(), topics, d, env.BlockNumber().Uint64())
+ env.AddLog(log)
+}
+
+func opMload(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ offset := stack.pop()
+ val := common.BigD(memory.Get(offset.Int64(), 32))
+ stack.push(val)
+}
+
+func opMstore(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ // pop value of the stack
+ mStart, val := stack.pop(), stack.pop()
+ memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
+}
+
+func opMstore8(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ off, val := stack.pop().Int64(), stack.pop().Int64()
+ memory.store[off] = byte(val & 0xff)
+}
+
+func opSload(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ loc := common.BigToHash(stack.pop())
+ val := env.State().GetState(context.Address(), loc).Big()
+ stack.push(val)
+}
+
+func opSstore(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ loc := common.BigToHash(stack.pop())
+ val := stack.pop()
+
+ 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 opPc(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(new(big.Int).Set(instr.data))
+}
+
+func opMsize(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(big.NewInt(int64(memory.Len())))
+}
+
+func opGas(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ stack.push(new(big.Int).Set(context.Gas))
+}
+
+func opCreate(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ var (
+ value = stack.pop()
+ offset, size = stack.pop(), stack.pop()
+ input = memory.Get(offset.Int64(), size.Int64())
+ gas = new(big.Int).Set(context.Gas)
+ addr common.Address
+ )
+
+ context.UseGas(context.Gas)
+ ret, suberr, ref := env.Create(context, input, gas, context.Price, value)
+ if suberr != nil {
+ stack.push(new(big.Int))
+
+ } else {
+ // gas < len(ret) * Createinstr.dataGas == NO_CODE
+ dataGas := big.NewInt(int64(len(ret)))
+ dataGas.Mul(dataGas, params.CreateDataGas)
+ if context.UseGas(dataGas) {
+ ref.SetCode(ret)
+ }
+ addr = ref.Address()
+
+ stack.push(addr.Big())
+
+ }
+}
+
+func opCall(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ gas := stack.pop()
+ // pop gas and value of the stack.
+ addr, value := stack.pop(), stack.pop()
+ value = U256(value)
+ // pop input size and offset
+ inOffset, inSize := stack.pop(), stack.pop()
+ // pop return size and offset
+ retOffset, retSize := stack.pop(), stack.pop()
+
+ address := common.BigToAddress(addr)
+
+ // Get the arguments from the memory
+ args := memory.Get(inOffset.Int64(), inSize.Int64())
+
+ if len(value.Bytes()) > 0 {
+ gas.Add(gas, params.CallStipend)
+ }
+
+ ret, err := env.Call(context, address, args, gas, context.Price, value)
+
+ if err != nil {
+ stack.push(new(big.Int))
+
+ } else {
+ stack.push(big.NewInt(1))
+
+ memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
+ }
+}
+
+func opCallCode(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ gas := stack.pop()
+ // pop gas and value of the stack.
+ addr, value := stack.pop(), stack.pop()
+ value = U256(value)
+ // pop input size and offset
+ inOffset, inSize := stack.pop(), stack.pop()
+ // pop return size and offset
+ retOffset, retSize := stack.pop(), stack.pop()
+
+ address := common.BigToAddress(addr)
+
+ // Get the arguments from the memory
+ args := memory.Get(inOffset.Int64(), inSize.Int64())
+
+ if len(value.Bytes()) > 0 {
+ gas.Add(gas, params.CallStipend)
+ }
+
+ ret, err := env.CallCode(context, address, args, gas, context.Price, value)
+
+ if err != nil {
+ stack.push(new(big.Int))
+
+ } else {
+ stack.push(big.NewInt(1))
+
+ memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
+ }
+}
+
+func opReturn(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {}
+func opStop(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {}
+
+func opSuicide(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
+ receiver := env.State().GetOrNewStateObject(common.BigToAddress(stack.pop()))
+ balance := env.State().GetBalance(context.Address())
+
+ receiver.AddBalance(balance)
+
+ env.State().Delete(context.Address())
+}
diff --git a/core/vm/jit.go b/core/vm/jit.go
new file mode 100644
index 0000000000..4d55d1fed5
--- /dev/null
+++ b/core/vm/jit.go
@@ -0,0 +1,547 @@
+// Copyright 2014 The go-expanse Authors
+// This file is part of the go-expanse library.
+//
+// The go-expanse 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-expanse 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-expanse library. If not, see .
+
+package vm
+
+import (
+ "fmt"
+ "math/big"
+ "sync/atomic"
+
+ "github.com/expanse-project/go-expanse/common"
+ "github.com/expanse-project/go-expanse/core/state"
+ "github.com/expanse-project/go-expanse/crypto"
+ "github.com/expanse-project/go-expanse/params"
+ "github.com/hashicorp/golang-lru"
+)
+
+type progStatus int32
+
+const (
+ progUnknown progStatus = iota
+ progCompile
+ progReady
+ progError
+)
+
+var programs *lru.Cache
+
+func init() {
+ programs, _ = lru.New(defaultJitMaxCache)
+}
+
+// SetJITCacheSize recreates the program cache with the max given size. Setting
+// a new cache is **not** thread safe. Use with caution.
+func SetJITCacheSize(size int) {
+ programs, _ = lru.New(size)
+}
+
+// GetProgram returns the program by id or nil when non-existent
+func GetProgram(id common.Hash) *Program {
+ if p, ok := programs.Get(id); ok {
+ return p.(*Program)
+ }
+
+ return nil
+}
+
+// GenProgramStatus returns the status of the given program id
+func GetProgramStatus(id common.Hash) progStatus {
+ program := GetProgram(id)
+ if program != nil {
+ return progStatus(atomic.LoadInt32(&program.status))
+ }
+
+ return progUnknown
+}
+
+// Program is a compiled program for the JIT VM and holds all required for
+// running a compiled JIT program.
+type Program struct {
+ Id common.Hash // Id of the program
+ status int32 // status should be accessed atomically
+
+ context *Context
+
+ instructions []instruction // instruction set
+ mapping map[uint64]int // real PC mapping to array indices
+ destinations map[uint64]struct{} // cached jump destinations
+
+ code []byte
+}
+
+// NewProgram returns a new JIT program
+func NewProgram(code []byte) *Program {
+ program := &Program{
+ Id: crypto.Sha3Hash(code),
+ mapping: make(map[uint64]int),
+ destinations: make(map[uint64]struct{}),
+ code: code,
+ }
+
+ programs.Add(program.Id, program)
+ return program
+}
+
+func (p *Program) addInstr(op OpCode, pc uint64, fn instrFn, data *big.Int) {
+ // PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
+ // PUSH is also allowed to calculate the same price for all PUSHes
+ // DUP requirements are handled elsewhere (except for the stack limit check)
+ baseOp := op
+ if op >= PUSH1 && op <= PUSH32 {
+ baseOp = PUSH1
+ }
+ if op >= DUP1 && op <= DUP16 {
+ baseOp = DUP1
+ }
+ base := _baseCheck[baseOp]
+ instr := instruction{op, pc, fn, nil, data, base.gas, base.stackPop, base.stackPush}
+
+ p.instructions = append(p.instructions, instr)
+ 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
+ }
+ atomic.StoreInt32(&program.status, int32(progCompile))
+ defer func() {
+ if err != nil {
+ atomic.StoreInt32(&program.status, int32(progError))
+ } else {
+ atomic.StoreInt32(&program.status, int32(progReady))
+ }
+ }()
+
+ // loop thru the opcodes and "compile" in to instructions
+ for pc := uint64(0); pc < uint64(len(program.code)); pc++ {
+ switch op := OpCode(program.code[pc]); op {
+ case ADD:
+ program.addInstr(op, pc, opAdd, nil)
+ case SUB:
+ program.addInstr(op, pc, opSub, nil)
+ case MUL:
+ program.addInstr(op, pc, opMul, nil)
+ case DIV:
+ program.addInstr(op, pc, opDiv, nil)
+ case SDIV:
+ program.addInstr(op, pc, opSdiv, nil)
+ case MOD:
+ program.addInstr(op, pc, opMod, nil)
+ case SMOD:
+ program.addInstr(op, pc, opSmod, nil)
+ case EXP:
+ program.addInstr(op, pc, opExp, nil)
+ case SIGNEXTEND:
+ program.addInstr(op, pc, opSignExtend, nil)
+ case NOT:
+ program.addInstr(op, pc, opNot, nil)
+ case LT:
+ program.addInstr(op, pc, opLt, nil)
+ case GT:
+ program.addInstr(op, pc, opGt, nil)
+ case SLT:
+ program.addInstr(op, pc, opSlt, nil)
+ case SGT:
+ program.addInstr(op, pc, opSgt, nil)
+ case EQ:
+ program.addInstr(op, pc, opEq, nil)
+ case ISZERO:
+ program.addInstr(op, pc, opIszero, nil)
+ case AND:
+ program.addInstr(op, pc, opAnd, nil)
+ case OR:
+ program.addInstr(op, pc, opOr, nil)
+ case XOR:
+ program.addInstr(op, pc, opXor, nil)
+ case BYTE:
+ program.addInstr(op, pc, opByte, nil)
+ case ADDMOD:
+ program.addInstr(op, pc, opAddmod, nil)
+ case MULMOD:
+ program.addInstr(op, pc, opMulmod, nil)
+ case SHA3:
+ program.addInstr(op, pc, opSha3, nil)
+ case ADDRESS:
+ program.addInstr(op, pc, opAddress, nil)
+ case BALANCE:
+ program.addInstr(op, pc, opBalance, nil)
+ case ORIGIN:
+ program.addInstr(op, pc, opOrigin, nil)
+ case CALLER:
+ program.addInstr(op, pc, opCaller, nil)
+ case CALLVALUE:
+ program.addInstr(op, pc, opCallValue, nil)
+ case CALLDATALOAD:
+ program.addInstr(op, pc, opCalldataLoad, nil)
+ case CALLDATASIZE:
+ program.addInstr(op, pc, opCalldataSize, nil)
+ case CALLDATACOPY:
+ program.addInstr(op, pc, opCalldataCopy, nil)
+ case CODESIZE:
+ program.addInstr(op, pc, opCodeSize, nil)
+ case EXTCODESIZE:
+ program.addInstr(op, pc, opExtCodeSize, nil)
+ case CODECOPY:
+ program.addInstr(op, pc, opCodeCopy, nil)
+ case EXTCODECOPY:
+ program.addInstr(op, pc, opExtCodeCopy, nil)
+ case GASPRICE:
+ program.addInstr(op, pc, opGasprice, nil)
+ case BLOCKHASH:
+ program.addInstr(op, pc, opBlockhash, nil)
+ case COINBASE:
+ program.addInstr(op, pc, opCoinbase, nil)
+ case TIMESTAMP:
+ program.addInstr(op, pc, opTimestamp, nil)
+ case NUMBER:
+ program.addInstr(op, pc, opNumber, nil)
+ case DIFFICULTY:
+ program.addInstr(op, pc, opDifficulty, nil)
+ case GASLIMIT:
+ program.addInstr(op, pc, opGasLimit, nil)
+ case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
+ size := uint64(op - PUSH1 + 1)
+ bytes := getData([]byte(program.code), new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size))
+
+ program.addInstr(op, pc, opPush, common.Bytes2Big(bytes))
+
+ pc += size
+
+ case POP:
+ program.addInstr(op, pc, opPop, nil)
+ case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
+ program.addInstr(op, pc, opDup, big.NewInt(int64(op-DUP1+1)))
+ case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
+ program.addInstr(op, pc, opSwap, big.NewInt(int64(op-SWAP1+2)))
+ case LOG0, LOG1, LOG2, LOG3, LOG4:
+ program.addInstr(op, pc, opLog, big.NewInt(int64(op-LOG0)))
+ case MLOAD:
+ program.addInstr(op, pc, opMload, nil)
+ case MSTORE:
+ program.addInstr(op, pc, opMstore, nil)
+ case MSTORE8:
+ program.addInstr(op, pc, opMstore8, nil)
+ case SLOAD:
+ program.addInstr(op, pc, opSload, nil)
+ case SSTORE:
+ program.addInstr(op, pc, opSstore, nil)
+ case JUMP:
+ program.addInstr(op, pc, opJump, nil)
+ case JUMPI:
+ program.addInstr(op, pc, opJumpi, nil)
+ case JUMPDEST:
+ program.addInstr(op, pc, opJumpdest, nil)
+ program.destinations[pc] = struct{}{}
+ case PC:
+ program.addInstr(op, pc, opPc, big.NewInt(int64(pc)))
+ case MSIZE:
+ program.addInstr(op, pc, opMsize, nil)
+ case GAS:
+ program.addInstr(op, pc, opGas, nil)
+ case CREATE:
+ program.addInstr(op, pc, opCreate, nil)
+ case CALL:
+ program.addInstr(op, pc, opCall, nil)
+ case CALLCODE:
+ program.addInstr(op, pc, opCallCode, nil)
+ case RETURN:
+ program.addInstr(op, pc, opReturn, nil)
+ case SUICIDE:
+ program.addInstr(op, pc, opSuicide, nil)
+ case STOP: // Stop the context
+ program.addInstr(op, pc, opStop, nil)
+ default:
+ program.addInstr(op, pc, nil, nil)
+ }
+ }
+
+ 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)
+}
+
+func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env Environment, context *Context, input []byte) ([]byte, error) {
+ context.Input = input
+
+ var (
+ caller = context.caller
+ statedb = env.State()
+ pc int = program.mapping[pcstart]
+
+ jump = func(to *big.Int) error {
+ if !validDest(program.destinations, to) {
+ nop := context.GetOp(to.Uint64())
+ return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
+ }
+
+ pc = program.mapping[to.Uint64()]
+
+ return nil
+ }
+ )
+
+ for pc < len(program.instructions) {
+ instr := program.instructions[pc]
+
+ // calculate the new memory size and gas price for the current executing opcode
+ newMemSize, cost, err := jitCalculateGasAndSize(env, context, caller, instr, statedb, mem, stack)
+ if err != nil {
+ return nil, err
+ }
+
+ // Use the calculated gas. When insufficient gas is present, use all gas and return an
+ // Out Of Gas error
+ if !context.UseGas(cost) {
+ return nil, OutOfGasError
+ }
+ // Resize the memory calculated previously
+ mem.Resize(newMemSize.Uint64())
+
+ // These opcodes return an argument and are thefor handled
+ // differently from the rest of the opcodes
+ switch instr.op {
+ case JUMP:
+ if err := jump(stack.pop()); err != nil {
+ return nil, err
+ }
+ continue
+ case JUMPI:
+ pos, cond := stack.pop(), stack.pop()
+
+ if cond.Cmp(common.BigTrue) >= 0 {
+ if err := jump(pos); err != nil {
+ return nil, err
+ }
+ continue
+ }
+ case RETURN:
+ offset, size := stack.pop(), stack.pop()
+ ret := mem.GetPtr(offset.Int64(), size.Int64())
+
+ return context.Return(ret), nil
+ case SUICIDE:
+ instr.fn(instr, env, context, mem, stack)
+
+ return context.Return(nil), nil
+ case STOP:
+ return context.Return(nil), nil
+ default:
+ if instr.fn == nil {
+ return nil, fmt.Errorf("Invalid opcode %x", instr.op)
+ }
+
+ instr.fn(instr, env, context, mem, stack)
+ }
+
+ pc++
+ }
+
+ context.Input = nil
+
+ return context.Return(nil), nil
+}
+
+// validDest checks if the given distination is a valid one given the
+// destination table of the program
+func validDest(dests map[uint64]struct{}, dest *big.Int) bool {
+ // PC cannot go beyond len(code) and certainly can't be bigger than 64bits.
+ // Don't bother checking for JUMPDEST in that case.
+ if dest.Cmp(bigMaxUint64) > 0 {
+ return false
+ }
+ _, ok := dests[dest.Uint64()]
+ return ok
+}
+
+// jitCalculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
+// the operation. This does not reduce gas or resizes the memory.
+func jitCalculateGasAndSize(env Environment, context *Context, caller ContextRef, instr instruction, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
+ var (
+ gas = new(big.Int)
+ newMemSize *big.Int = new(big.Int)
+ )
+ err := jitBaseCheck(instr, stack, gas)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // stack Check, memory resize & gas phase
+ switch op := instr.op; op {
+ case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
+ n := int(op - SWAP1 + 2)
+ err := stack.require(n)
+ if err != nil {
+ return nil, nil, err
+ }
+ gas.Set(GasFastestStep)
+ case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
+ n := int(op - DUP1 + 1)
+ err := stack.require(n)
+ if err != nil {
+ return nil, nil, err
+ }
+ gas.Set(GasFastestStep)
+ case LOG0, LOG1, LOG2, LOG3, LOG4:
+ n := int(op - LOG0)
+ err := stack.require(n + 2)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
+
+ add := new(big.Int)
+ gas.Add(gas, params.LogGas)
+ gas.Add(gas, add.Mul(big.NewInt(int64(n)), params.LogTopicGas))
+ gas.Add(gas, add.Mul(mSize, params.LogDataGas))
+
+ newMemSize = calcMemSize(mStart, mSize)
+ case EXP:
+ gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
+ case SSTORE:
+ err := stack.require(2)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ var g *big.Int
+ y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
+ val := statedb.GetState(context.Address(), common.BigToHash(x))
+
+ // This checks for 3 scenario's and calculates gas accordingly
+ // 1. From a zero-value address to a non-zero value (NEW VALUE)
+ // 2. From a non-zero value address to a zero-value address (DELETE)
+ // 3. From a nen-zero to a non-zero (CHANGE)
+ if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
+ // 0 => non 0
+ g = params.SstoreSetGas
+ } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
+ statedb.Refund(params.SstoreRefundGas)
+
+ g = params.SstoreClearGas
+ } else {
+ // non 0 => non 0 (or 0 => 0)
+ g = params.SstoreClearGas
+ }
+ gas.Set(g)
+ case SUICIDE:
+ if !statedb.IsDeleted(context.Address()) {
+ statedb.Refund(params.SuicideRefundGas)
+ }
+ case MLOAD:
+ newMemSize = calcMemSize(stack.peek(), u256(32))
+ case MSTORE8:
+ newMemSize = calcMemSize(stack.peek(), u256(1))
+ case MSTORE:
+ newMemSize = calcMemSize(stack.peek(), u256(32))
+ case RETURN:
+ newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
+ case SHA3:
+ newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
+
+ words := toWordSize(stack.data[stack.len()-2])
+ gas.Add(gas, words.Mul(words, params.Sha3WordGas))
+ case CALLDATACOPY:
+ newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
+
+ words := toWordSize(stack.data[stack.len()-3])
+ gas.Add(gas, words.Mul(words, params.CopyGas))
+ case CODECOPY:
+ newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
+
+ words := toWordSize(stack.data[stack.len()-3])
+ gas.Add(gas, words.Mul(words, params.CopyGas))
+ case EXTCODECOPY:
+ newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
+
+ words := toWordSize(stack.data[stack.len()-4])
+ gas.Add(gas, words.Mul(words, params.CopyGas))
+
+ case CREATE:
+ newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
+ case CALL, CALLCODE:
+ gas.Add(gas, stack.data[stack.len()-1])
+
+ if op == CALL {
+ if env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
+ gas.Add(gas, params.CallNewAccountGas)
+ }
+ }
+
+ if len(stack.data[stack.len()-3].Bytes()) > 0 {
+ gas.Add(gas, params.CallValueTransferGas)
+ }
+
+ x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
+ y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
+
+ newMemSize = common.BigMax(x, y)
+ }
+
+ if newMemSize.Cmp(common.Big0) > 0 {
+ newMemSizeWords := toWordSize(newMemSize)
+ newMemSize.Mul(newMemSizeWords, u256(32))
+
+ if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
+ // be careful reusing variables here when changing.
+ // The order has been optimised to reduce allocation
+ oldSize := toWordSize(big.NewInt(int64(mem.Len())))
+ pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
+ linCoef := oldSize.Mul(oldSize, params.MemoryGas)
+ quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
+ oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
+
+ pow.Exp(newMemSizeWords, common.Big2, Zero)
+ linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
+ quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
+ newTotalFee := linCoef.Add(linCoef, quadCoef)
+
+ fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
+ gas.Add(gas, fee)
+ }
+ }
+
+ return newMemSize, gas, nil
+}
+
+// jitBaseCheck is the same as baseCheck except it doesn't do the look up in the
+// gas table. This is done during compilation instead.
+func jitBaseCheck(instr instruction, stack *stack, gas *big.Int) error {
+ err := stack.require(instr.spop)
+ if err != nil {
+ return err
+ }
+
+ if instr.spush > 0 && stack.len()-instr.spop+instr.spush > int(params.StackLimit.Int64()) {
+ return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64())
+ }
+
+ // nil on gas means no base calculation
+ if instr.gas == nil {
+ return nil
+ }
+
+ gas.Add(gas, instr.gas)
+
+ return nil
+}
diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go
new file mode 100644
index 0000000000..9afc85a55d
--- /dev/null
+++ b/core/vm/jit_test.go
@@ -0,0 +1,122 @@
+// Copyright 2014 The go-expanse Authors
+// This file is part of the go-expanse library.
+//
+// The go-expanse 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-expanse 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-expanse library. If not, see .
+package vm
+
+import (
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/expanse-project/go-expanse/common"
+ "github.com/expanse-project/go-expanse/core/state"
+ "github.com/expanse-project/go-expanse/crypto"
+ "github.com/expanse-project/go-expanse/ethdb"
+)
+
+const maxRun = 1000
+
+type vmBench struct {
+ precompile bool // compile prior to executing
+ nojit bool // ignore jit (sets DisbaleJit = true
+ forcejit bool // forces the jit, precompile is ignored
+
+ code []byte
+ input []byte
+}
+
+func runVmBench(test vmBench, b *testing.B) {
+ db, _ := ethdb.NewMemDatabase()
+ sender := state.NewStateObject(common.Address{}, db)
+
+ if test.precompile && !test.forcejit {
+ NewProgram(test.code)
+ }
+ env := NewEnv()
+
+ EnableJit = !test.nojit
+ ForceJit = test.forcejit
+
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ context := NewContext(sender, sender, big.NewInt(100), big.NewInt(10000), big.NewInt(0))
+ context.Code = test.code
+ context.CodeAddr = &common.Address{}
+ _, err := New(env).Run(context, test.input)
+ if err != nil {
+ b.Error(err)
+ b.FailNow()
+ }
+ }
+}
+
+var benchmarks = map[string]vmBench{
+ "pushes": vmBench{
+ false, false, false,
+ common.Hex2Bytes("600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01"), nil,
+ },
+}
+
+func BenchmarkPushes(b *testing.B) {
+ runVmBench(benchmarks["pushes"], b)
+}
+
+type Env struct {
+ gasLimit *big.Int
+ depth int
+}
+
+func NewEnv() *Env {
+ return &Env{big.NewInt(10000), 0}
+}
+
+func (self *Env) Origin() common.Address { return common.Address{} }
+func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
+func (self *Env) AddStructLog(log StructLog) {
+}
+func (self *Env) StructLogs() []StructLog {
+ return nil
+}
+
+//func (self *Env) PrevHash() []byte { return self.parent }
+func (self *Env) Coinbase() common.Address { return common.Address{} }
+func (self *Env) Time() *big.Int { return big.NewInt(time.Now().Unix()) }
+func (self *Env) Difficulty() *big.Int { return big.NewInt(0) }
+func (self *Env) State() *state.StateDB { return nil }
+func (self *Env) GasLimit() *big.Int { return self.gasLimit }
+func (self *Env) VmType() Type { return StdVmTy }
+func (self *Env) GetHash(n uint64) common.Hash {
+ return common.BytesToHash(crypto.Sha3([]byte(big.NewInt(int64(n)).String())))
+}
+func (self *Env) AddLog(log *state.Log) {
+}
+func (self *Env) Depth() int { return self.depth }
+func (self *Env) SetDepth(i int) { self.depth = i }
+func (self *Env) CanTransfer(from Account, balance *big.Int) bool {
+ return from.Balance().Cmp(balance) >= 0
+}
+func (self *Env) Transfer(from, to Account, amount *big.Int) error {
+ return nil
+}
+func (self *Env) Call(caller ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
+ return nil, nil
+}
+func (self *Env) CallCode(caller ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
+ return nil, nil
+}
+func (self *Env) Create(caller ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef) {
+ return nil, nil, nil
+}
diff --git a/core/vm/settings.go b/core/vm/settings.go
new file mode 100644
index 0000000000..1c6d579f92
--- /dev/null
+++ b/core/vm/settings.go
@@ -0,0 +1,25 @@
+// Copyright 2015 The go-expanse Authors
+// This file is part of the go-expanse library.
+//
+// The go-expanse 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-expanse 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-expanse library. If not, see .
+
+package vm
+
+var (
+ 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/stack.go b/core/vm/stack.go
index 20267d5318..13bd53a5df 100644
--- a/core/vm/stack.go
+++ b/core/vm/stack.go
@@ -21,38 +21,36 @@ import (
"math/big"
)
+// stack is an object for basic stack operations. Items popped to the stack are
+// expected to be changed and modified. stack does not take care of adding newly
+// initialised objects.
+type stack struct {
+ data []*big.Int
+}
+
func newstack() *stack {
return &stack{}
}
-type stack struct {
- data []*big.Int
- ptr int
-}
-
func (st *stack) Data() []*big.Int {
- return st.data[:st.ptr]
+ return st.data
}
func (st *stack) push(d *big.Int) {
// NOTE push limit (1024) is checked in baseCheck
- stackItem := new(big.Int).Set(d)
- if len(st.data) > st.ptr {
- st.data[st.ptr] = stackItem
- } else {
- st.data = append(st.data, stackItem)
- }
- st.ptr++
+ //stackItem := new(big.Int).Set(d)
+ //st.data = append(st.data, stackItem)
+ st.data = append(st.data, d)
}
func (st *stack) pop() (ret *big.Int) {
- st.ptr--
- ret = st.data[st.ptr]
+ ret = st.data[len(st.data)-1]
+ st.data = st.data[:len(st.data)-1]
return
}
func (st *stack) len() int {
- return st.ptr
+ return len(st.data)
}
func (st *stack) swap(n int) {
@@ -60,7 +58,7 @@ func (st *stack) swap(n int) {
}
func (st *stack) dup(n int) {
- st.push(st.data[st.len()-n])
+ st.push(new(big.Int).Set(st.data[st.len()-n]))
}
func (st *stack) peek() *big.Int {
diff --git a/core/vm/vm.go b/core/vm/vm.go
index 833f7065c5..66ff122075 100644
--- a/core/vm/vm.go
+++ b/core/vm/vm.go
@@ -24,30 +24,19 @@ import (
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/core/state"
"github.com/expanse-project/go-expanse/crypto"
+ "github.com/expanse-project/go-expanse/logger"
+ "github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/params"
)
// Vm implements VirtualMachine
type Vm struct {
env Environment
-
- err error
- // For logging
- debug bool
-
- BreakPoints []int64
- Stepping bool
- Fn string
-
- Recoverable bool
-
- // Will be called before the vm returns
- After func(*Context, error)
}
// New returns a new Virtual Machine
func New(env Environment) *Vm {
- return &Vm{env: env, debug: Debug, Recoverable: true}
+ return &Vm{env: env}
}
// Run loops and evaluates the contract's code with the given input data
@@ -55,17 +44,67 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
self.env.SetDepth(self.env.Depth() + 1)
defer self.env.SetDepth(self.env.Depth() - 1)
+ // User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
+ defer func() {
+ if err != nil {
+ // In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
+ context.UseGas(context.Gas)
+
+ ret = context.Return(nil)
+ }
+ }()
+
+ if context.CodeAddr != nil {
+ if p := Precompiled[context.CodeAddr.Str()]; p != nil {
+ return self.RunPrecompiled(p, input, context)
+ }
+ }
+
+ var (
+ codehash = crypto.Sha3Hash(context.Code) // codehash is used when doing jump dest caching
+ program *Program
+ )
+ if EnableJit {
+ // Fetch program status.
+ // * If ready run using JIT
+ // * If unknown, compile in a seperate goroutine
+ // * If forced wait for compilation and run once done
+ if status := GetProgramStatus(codehash); status == progReady {
+ return RunProgram(GetProgram(codehash), self.env, context, input)
+ } else if status == progUnknown {
+ if ForceJit {
+ // Create and compile program
+ program = NewProgram(context.Code)
+ perr := CompileProgram(program)
+ if perr == nil {
+ return RunProgram(program, self.env, context, input)
+ }
+ glog.V(logger.Info).Infoln("error compiling program", err)
+ } else {
+ // create and compile the program. Compilation
+ // is done in a seperate goroutine
+ program = NewProgram(context.Code)
+ go func() {
+ err := CompileProgram(program)
+ if err != nil {
+ glog.V(logger.Info).Infoln("error compiling program", err)
+ return
+ }
+ }()
+ }
+ }
+ }
+
var (
caller = context.caller
code = context.Code
value = context.value
price = context.Price
- op OpCode // current opcode
- codehash = crypto.Sha3Hash(code) // codehash is used when doing jump dest caching
- mem = NewMemory() // bound memory
- stack = newstack() // local stack
- statedb = self.env.State() // current state
+ op OpCode // current opcode
+ mem = NewMemory() // bound memory
+ stack = newstack() // local stack
+ statedb = self.env.State() // current state
// For optimisation reason we're using uint64 as the program counter.
// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Pratically much less so feasible.
pc = uint64(0) // program counter
@@ -89,32 +128,25 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
defer func() {
- if self.After != nil {
- self.After(context, err)
- }
-
if err != nil {
self.log(pc, op, context.Gas, cost, mem, stack, context, err)
-
- // In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
- context.UseGas(context.Gas)
-
- ret = context.Return(nil)
}
}()
- if context.CodeAddr != nil {
- if p := Precompiled[context.CodeAddr.Str()]; p != nil {
- return self.RunPrecompiled(p, input, context)
- }
- }
-
// Don't bother with the execution if there's no code.
if len(code) == 0 {
return context.Return(nil), nil
}
for {
+ // Overhead of the atomic read might not be worth it
+ /* TODO this still causes a few issues in the tests
+ if program != nil && progStatus(atomic.LoadInt32(&program.status)) == progReady {
+ // move execution
+ glog.V(logger.Info).Infoln("Moved execution to JIT")
+ return runProgram(program, pc, mem, stack, self.env, context, input)
+ }
+ */
// The base for all big integer arithmetic
base := new(big.Int)
@@ -122,7 +154,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
op = context.GetOp(pc)
// calculate the new memory size and gas price for the current executing opcode
- newMemSize, cost, err = self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
+ newMemSize, cost, err = calculateGasAndSize(self.env, context, caller, op, statedb, mem, stack)
if err != nil {
return nil, err
}
@@ -130,11 +162,9 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
// Use the calculated gas. When insufficient gas is present, use all gas and return an
// Out Of Gas error
if !context.UseGas(cost) {
-
- context.UseGas(context.Gas)
-
- return context.Return(nil), OutOfGasError
+ return nil, OutOfGasError
}
+
// Resize the memory calculated previously
mem.Resize(newMemSize.Uint64())
// Add a log message
@@ -376,7 +406,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
addr := common.BigToAddress(stack.pop())
balance := statedb.GetBalance(addr)
- stack.push(balance)
+ stack.push(new(big.Int).Set(balance))
case ORIGIN:
origin := self.env.Origin()
@@ -388,7 +418,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
stack.push(common.Bytes2Big(caller.Bytes()))
case CALLVALUE:
- stack.push(value)
+ stack.push(new(big.Int).Set(value))
case CALLDATALOAD:
data := getData(input, stack.pop(), common.Big32)
@@ -441,7 +471,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
mem.Set(mOff.Uint64(), l.Uint64(), codeCopy)
case GASPRICE:
- stack.push(context.Price)
+ stack.push(new(big.Int).Set(context.Price))
case BLOCKHASH:
num := stack.pop()
@@ -461,7 +491,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
case TIMESTAMP:
time := self.env.Time()
- stack.push(new(big.Int).SetUint64(time))
+ stack.push(new(big.Int).Set(time))
case NUMBER:
number := self.env.BlockNumber()
@@ -471,11 +501,11 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
case DIFFICULTY:
difficulty := self.env.Difficulty()
- stack.push(difficulty)
+ stack.push(new(big.Int).Set(difficulty))
case GASLIMIT:
- stack.push(self.env.GasLimit())
+ stack.push(new(big.Int).Set(self.env.GasLimit()))
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
size := uint64(op - PUSH1 + 1)
@@ -555,8 +585,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
case MSIZE:
stack.push(big.NewInt(int64(mem.Len())))
case GAS:
- stack.push(context.Gas)
-
+ stack.push(new(big.Int).Set(context.Gas))
case CREATE:
var (
@@ -652,7 +681,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
// calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
// the operation. This does not reduce gas or resizes the memory.
-func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
+func calculateGasAndSize(env Environment, context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
var (
gas = new(big.Int)
newMemSize *big.Int = new(big.Int)
@@ -759,7 +788,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
gas.Add(gas, stack.data[stack.len()-1])
if op == CALL {
- if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
+ if env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
gas.Add(gas, params.CallNewAccountGas)
}
}
diff --git a/core/vm_env.go b/core/vm_env.go
index b4f6666512..77eb5ec012 100644
--- a/core/vm_env.go
+++ b/core/vm_env.go
@@ -49,7 +49,7 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, header *type
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f }
func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
-func (self *VMEnv) Time() uint64 { return self.header.Time }
+func (self *VMEnv) Time() *big.Int { return self.header.Time }
func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty }
func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit }
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
@@ -69,6 +69,10 @@ func (self *VMEnv) GetHash(n uint64) common.Hash {
func (self *VMEnv) AddLog(log *state.Log) {
self.state.AddLog(log)
}
+func (self *VMEnv) CanTransfer(from vm.Account, balance *big.Int) bool {
+ return from.Balance().Cmp(balance) >= 0
+}
+
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
return vm.Transfer(from, to, amount)
}
diff --git a/ethdb/database.go b/ethdb/database.go
index ab5283d9a7..144472ff19 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/exp/backend.go b/exp/backend.go
index 5b4eae80ad..b6fef908f1 100644
--- a/exp/backend.go
+++ b/exp/backend.go
@@ -45,7 +45,6 @@ import (
"github.com/expanse-project/go-expanse/p2p"
"github.com/expanse-project/go-expanse/p2p/discover"
"github.com/expanse-project/go-expanse/p2p/nat"
- "github.com/expanse-project/go-expanse/params"
"github.com/expanse-project/go-expanse/whisper"
)
@@ -92,6 +91,7 @@ type Config struct {
NatSpec bool
AutoDAG bool
PowTest bool
+ ExtraData []byte
MaxPeers int
MaxPendingPeers int
@@ -206,9 +206,8 @@ type Expanse 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 +265,27 @@ func New(config *Config) (*Expanse, 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"))
+
+ // attempt to merge database together, upgrading from an old version
+ if err := mergeDatabases(config.DataDir, newdb); err != nil {
+ return nil, err
+ }
+
+ chainDb, err := newdb(filepath.Join(config.DataDir, "chaindata"))
if err != nil {
return nil, fmt.Errorf("blockchain db err: %v", err)
}
- if db, ok := blockDb.(*ethdb.LDBDatabase); ok {
- db.Meter("exp/db/block/")
+ if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
+ db.Meter("eth/db/chaindata/")
}
- stateDb, err := newdb(filepath.Join(config.DataDir, "state"))
+ dappDb, err := newdb(filepath.Join(config.DataDir, "dapp"))
if err != nil {
- return nil, fmt.Errorf("state db err: %v", err)
+ return nil, fmt.Errorf("dapp db err: %v", err)
}
- if db, ok := stateDb.(*ethdb.LDBDatabase); ok {
- db.Meter("exp/db/state/")
- }
- extraDb, err := newdb(filepath.Join(config.DataDir, "extra"))
- if err != nil {
- return nil, fmt.Errorf("extra db err: %v", err)
- }
- if db, ok := extraDb.(*ethdb.LDBDatabase); ok {
- db.Meter("exp/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 +295,7 @@ func New(config *Config) (*Expanse, 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 +303,7 @@ func New(config *Config) (*Expanse, error) {
}
if config.Olympic {
- _, err := core.WriteTestNetGenesisBlock(stateDb, blockDb, 42)
+ _, err := core.WriteTestNetGenesisBlock(chainDb, 42)
if err != nil {
return nil, err
}
@@ -313,26 +312,25 @@ func New(config *Config) (*Expanse, 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 gexp upgradedb.\n", bcVersion, config.BlockChainVersion)
}
- saveBlockchainVersion(blockDb, config.BlockChainVersion)
+ saveBlockchainVersion(chainDb, config.BlockChainVersion)
}
glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion)
exp := &Expanse{
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 +360,7 @@ func New(config *Config) (*Expanse, error) {
exp.pow = ethash.New()
}
//genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb)
- exp.chainManager, err = core.NewChainManager(blockDb, stateDb, extraDb, exp.pow, exp.EventMux())
+ exp.chainManager, err = core.NewChainManager(chainDb, exp.pow, exp.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,18 +370,13 @@ func New(config *Config) (*Expanse, error) {
}
exp.txPool = core.NewTxPool(exp.EventMux(), exp.chainManager.State, exp.chainManager.GasLimit)
- exp.blockProcessor = core.NewBlockProcessor(stateDb, extraDb, exp.pow, exp.chainManager, exp.EventMux())
+ exp.blockProcessor = core.NewBlockProcessor(chainDb, exp.pow, exp.chainManager, exp.EventMux())
exp.chainManager.SetProcessor(exp.blockProcessor)
exp.protocolManager = NewProtocolManager(config.NetworkId, exp.eventMux, exp.txPool, exp.pow, exp.chainManager)
exp.miner = miner.New(exp, exp.EventMux(), exp.pow)
exp.miner.SetGasPrice(config.GasPrice)
-
- extra := config.Name
- if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
- extra = extra[:params.MaximumExtraDataSize.Uint64()]
- }
- exp.miner.SetExtra([]byte(extra))
+ exp.miner.SetExtra(config.ExtraData)
if config.Shh {
exp.whisper = whisper.New()
@@ -525,9 +518,8 @@ func (s *Expanse) BlockProcessor() *core.BlockProcessor { return s.blockProcesso
func (s *Expanse) TxPool() *core.TxPool { return s.txPool }
func (s *Expanse) Whisper() *whisper.Whisper { return s.whisper }
func (s *Expanse) EventMux() *event.TypeMux { return s.eventMux }
-func (s *Expanse) BlockDb() common.Database { return s.blockDb }
-func (s *Expanse) StateDb() common.Database { return s.stateDb }
-func (s *Expanse) ExtraDb() common.Database { return s.extraDb }
+func (s *Expanse) ChainDb() common.Database { return s.chainDb }
+func (s *Expanse) DappDb() common.Database { return s.dappDb }
func (s *Expanse) IsListening() bool { return true } // Always listening
func (s *Expanse) PeerCount() int { return s.net.PeerCount() }
func (s *Expanse) Peers() []*p2p.Peer { return s.net.Peers() }
@@ -574,23 +566,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)
}
@@ -688,14 +676,6 @@ func (self *Expanse) StartAutoDAG() {
}()
}
-// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
-// 1) - 2) full-R-
-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 *Expanse) StopAutoDAG() {
if self.autodagquit != nil {
@@ -705,30 +685,6 @@ func (self *Expanse) 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 saveProtocolVersion(db common.Database, protov int) {
- d, _ := db.Get([]byte("ProtocolVersion"))
- protocolVersion := common.NewValue(d).Uint()
-
- if protocolVersion == 0 {
- db.Put([]byte("ProtocolVersion"), common.NewValue(protov).Bytes())
- }
- }
-*/
-
-func saveBlockchainVersion(db common.Database, bcVersion int) {
- d, _ := db.Get([]byte("BlockchainVersion"))
- blockchainVersion := common.NewValue(d).Uint()
-
- if blockchainVersion == 0 {
- db.Put([]byte("BlockchainVersion"), common.NewValue(bcVersion).Bytes())
- }
-}
-
func (self *Expanse) Solc() (*compiler.Solidity, error) {
var err error
if self.solc == nil {
@@ -743,3 +699,92 @@ func (self *Expanse) SetSolc(solcPath string) (*compiler.Solidity, error) {
self.solc = nil
return self.Solc()
}
+
+// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
+// 1) - 2) full-R-
+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"))
+ blockchainVersion := common.NewValue(d).Uint()
+
+ if blockchainVersion == 0 {
+ db.Put([]byte("BlockchainVersion"), common.NewValue(bcVersion).Bytes())
+ }
+}
+
+// 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
+ }
+ // 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...")
+
+ 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/exp/gasprice.go b/exp/gasprice.go
index 7a4662a97d..994e72397c 100644
--- a/exp/gasprice.go
+++ b/exp/gasprice.go
@@ -37,12 +37,11 @@ type blockPriceInfo struct {
type GasPriceOracle struct {
exp *Expanse
chain *core.ChainManager
- pool *core.TxPool
events event.Subscription
blocks map[uint64]*blockPriceInfo
firstProcessed, lastProcessed uint64
lastBaseMutex sync.Mutex
- lastBase *big.Int
+ lastBase, minBase *big.Int
}
func NewGasPriceOracle(exp *Expanse) (self *GasPriceOracle) {
@@ -50,13 +49,15 @@ func NewGasPriceOracle(exp *Expanse) (self *GasPriceOracle) {
self.blocks = make(map[uint64]*blockPriceInfo)
self.exp = exp
self.chain = exp.chainManager
- self.pool = exp.txPool
self.events = exp.EventMux().Subscribe(
core.ChainEvent{},
core.ChainSplitEvent{},
- core.TxPreEvent{},
- core.TxPostEvent{},
)
+
+ minbase := new(big.Int).Mul(self.exp.GpoMinGasPrice, big.NewInt(100))
+ minbase = minbase.Div(minbase, big.NewInt(int64(self.exp.GpobaseCorrectionFactor)))
+ self.minBase = minbase
+
self.processPastBlocks()
go self.listenLoop()
return
@@ -93,8 +94,6 @@ func (self *GasPriceOracle) listenLoop() {
self.processBlock(ev.Block)
case core.ChainSplitEvent:
self.processBlock(ev.Block)
- case core.TxPreEvent:
- case core.TxPostEvent:
}
}
self.events.Unsubscribe()
@@ -131,6 +130,10 @@ func (self *GasPriceOracle) processBlock(block *types.Block) {
newBase := new(big.Int).Mul(lastBase, big.NewInt(1000000+crand))
newBase.Div(newBase, big.NewInt(1000000))
+ if newBase.Cmp(self.minBase) < 0 {
+ newBase = self.minBase
+ }
+
bpi := self.blocks[i]
if bpi == nil {
bpi = &blockPriceInfo{}
@@ -146,7 +149,7 @@ func (self *GasPriceOracle) processBlock(block *types.Block) {
// returns the lowers possible price with which a tx was or could have been included
func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
- gasUsed := new(big.Int)
+ gasUsed := big.NewInt(0)
receipts := self.exp.BlockProcessor().GetBlockReceipts(block.Hash())
if len(receipts) > 0 {
@@ -158,12 +161,12 @@ func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
if new(big.Int).Mul(gasUsed, big.NewInt(100)).Cmp(new(big.Int).Mul(block.GasLimit(),
big.NewInt(int64(self.exp.GpoFullBlockRatio)))) < 0 {
// block is not full, could have posted a tx with MinGasPrice
- return self.exp.GpoMinGasPrice
+ return big.NewInt(0)
}
txs := block.Transactions()
if len(txs) == 0 {
- return self.exp.GpoMinGasPrice
+ return big.NewInt(0)
}
// block is full, find smallest gasPrice
minPrice := txs[0].GasPrice()
diff --git a/exp/handler.go b/exp/handler.go
index d2174db1e0..19826a12c1 100644
--- a/exp/handler.go
+++ b/exp/handler.go
@@ -117,7 +117,7 @@ func NewProtocolManager(networkId int, mux *event.TypeMux, txpool txPool, pow po
manager.downloader = downloader.New(manager.eventMux, manager.chainman.HasBlock, manager.chainman.GetBlock, manager.chainman.CurrentBlock, manager.chainman.InsertChain, manager.removePeer)
validator := func(block *types.Block, parent *types.Block) error {
- return core.ValidateHeader(pow, block.Header(), parent, true)
+ return core.ValidateHeader(pow, block.Header(), parent, true, false)
}
heighter := func() uint64 {
return manager.chainman.CurrentBlock().NumberU64()
@@ -413,10 +413,12 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
pm.fetcher.Enqueue(p.id, request.Block)
- // TODO: Schedule a sync to cover potential gaps (this needs proto update)
+ // Update the peers total difficulty if needed, schedule a download if gapped
if request.TD.Cmp(p.Td()) > 0 {
p.SetTd(request.TD)
- go pm.synchronise(p)
+ if request.TD.Cmp(new(big.Int).Add(pm.chainman.Td(), request.Block.Difficulty())) > 0 {
+ go pm.synchronise(p)
+ }
}
case TxMsg:
diff --git a/exp/protocol_test.go b/exp/protocol_test.go
index 2567b30491..ad47d0bb4c 100644
--- a/exp/protocol_test.go
+++ b/exp/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/jsre/ethereum_js.go b/jsre/ethereum_js.go
index a5183b7f50..ddda640a58 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 64 || this.offset !== undefined;
+ return this.offset !== undefined;
};
/**
@@ -708,71 +1360,398 @@ SolidityParam.encodeList = function (params) {
}, ''));
};
-/**
- * This method should be used to decode plain (static) solidity param at given index
- *
- * @method decodeParam
- * @param {String} bytes
- * @param {Number} index
- * @returns {SolidityParam}
- */
-SolidityParam.decodeParam = function (bytes, index) {
- index = index || 0;
- return new SolidityParam(bytes.substr(index * 64, 64));
-};
-/**
- * This method should be called to get offset value from bytes at given index
- *
- * @method getOffset
- * @param {String} bytes
- * @param {Number} index
- * @returns {Number} offset as number
- */
-var getOffset = function (bytes, index) {
- // we can do this cause offset is rather small
- return parseInt('0x' + bytes.substr(index * 64, 64));
-};
-
-/**
- * This method should be called to decode solidity bytes param at given index
- *
- * @method decodeBytes
- * @param {String} bytes
- * @param {Number} index
- * @returns {SolidityParam}
- */
-SolidityParam.decodeBytes = function (bytes, index) {
- index = index || 0;
-
- var offset = getOffset(bytes, index);
-
- var l = parseInt('0x' + bytes.substr(offset * 2, 64));
- l = Math.floor((l + 31) / 32);
-
- // (1 + l) * , cause we also parse length
- return new SolidityParam(bytes.substr(offset * 2, (1 + l) * 64), 0);
-};
-
-/**
- * This method should be used to decode solidity array at given index
- *
- * @method decodeArray
- * @param {String} bytes
- * @param {Number} index
- * @returns {SolidityParam}
- */
-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);
-};
module.exports = SolidityParam;
-},{"../utils/utils":7}],4:[function(require,module,exports){
+},{"../utils/utils":20}],12:[function(require,module,exports){
+var f = require('./formatters');
+var SolidityType = require('./type');
+
+/**
+ * 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 isType
+ * @param {String} name
+ * @return {Bool} true if type match this SolidityType, otherwise false
+ */
+SolidityType.prototype.isType = function (name) {
+ throw "this method should be overrwritten for type " + name;
+};
+
+/**
+ * Should be used to determine what is the length of static part in given type
+ *
+ * @method staticPartLength
+ * @param {String} name
+ * @return {Number} length of static part in bytes
+ */
+SolidityType.prototype.staticPartLength = function (name) {
+ throw "this method should be overrwritten for type: " + name;
+};
+
+/**
+ * Should be used to determine if type is dynamic array
+ * eg:
+ * "type[]" => true
+ * "type[4]" => false
+ *
+ * @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
+ */
+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;
+ })();
+
+ } else if (this.isStaticArray(name)) {
+
+ return (function () {
+ var length = self.staticArrayLength(name); // in int
+ var nestedName = self.nestedName(name);
+
+ var result = [];
+ for (var i = 0; i < length; i++) {
+ result.push(self.encode(value[i], nestedName));
+ }
+
+ return result;
+ })();
+
+ }
+
+ return this._inputFormatter(value, name).encode();
+};
+
+/**
+ * Should be used to decode value from bytes
+ *
+ * @method decode
+ * @param {String} bytes
+ * @param {Number} offset in bytes
+ * @param {String} name type name
+ * @returns {Object} decoded value
+ */
+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 = 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;
+
+},{"./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 expanse.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 expanse.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 expanse.js.
@@ -940,6 +1921,7 @@ module.exports = function (str, isNew) {
* @constructor
*/
+
var BigNumber = require('bignumber.js');
var unitMap = {
@@ -1019,7 +2001,7 @@ var toAscii = function(hex) {
str += String.fromCharCode(code);
}
- return decodeURIComponent(escape(str));
+ return decodeURIComponent(escape(str)); // jshint ignore:line
};
/**
@@ -1030,7 +2012,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);
@@ -1141,10 +2123,10 @@ var toHex = function (val) {
if (isString(val)) {
if (val.indexOf('-0x') === 0)
return fromDecimal(val);
- else if (!isFinite(val))
- return fromAscii(val);
else if(val.indexOf('0x') === 0)
return val;
+ else if (!isFinite(val))
+ return fromAscii(val);
}
return fromDecimal(val);
@@ -1381,18 +2363,6 @@ var isJson = function (str) {
}
};
-/**
- * This method should be called to check if string is valid expanse 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,
@@ -1417,17 +2387,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 expanse.js.
@@ -1604,7 +2573,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/exp":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 expanse.js.
@@ -1632,7 +2601,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;
@@ -1673,6 +2642,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.exp(), formatter, callback);
@@ -1686,7 +2662,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 expanse.js.
@@ -1754,7 +2730,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 expanse.js.
@@ -2033,65 +3009,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 expanse.js.
-
- expanse.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.
-
- expanse.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 expanse.js. If not, see .
-*/
-/** @file db.js
- * @authors:
- * Marek Kotewicz
- * @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 expanse.js.
@@ -2131,300 +3049,7 @@ module.exports = {
};
-},{}],15:[function(require,module,exports){
-/*
- This file is part of expanse.js.
-
- expanse.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.
-
- expanse.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 expanse.js. If not, see .
-*/
-/**
- * @file exp.js
- * @author Marek Kotewicz
- * @author Fabian Vogelsteller
- * @date 2015
- */
-
-/**
- * Web3
- *
- * @module web3
- */
-
-/**
- * Exp 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] exp
- * @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.exp 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.exp 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 expanse.js.
@@ -2452,7 +3077,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
@@ -2480,7 +3105,7 @@ SolidityEvent.prototype.types = function (indexed) {
};
/**
- * Should be used to get event display name
+ * Exp methods and properties
*
* @method displayName
* @return {String} event display name
@@ -2612,7 +3237,7 @@ SolidityEvent.prototype.execute = function (indexed, options, callback) {
var o = this.encode(indexed, options);
var formatter = this.decode.bind(this);
- return new Filter(o, watches.exp(), formatter, callback);
+ return new Filter(o, watches.eth(), formatter, callback);
};
/**
@@ -2632,8 +3257,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 expanse.js.
@@ -2799,6 +3423,7 @@ var Filter = function (options, methods, formatter, callback) {
}
});
+ return this;
};
Filter.prototype.watch = function (callback) {
@@ -2844,7 +3469,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 expanse.js.
@@ -2870,6 +3495,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
@@ -2902,6 +3528,34 @@ var inputBlockNumberFormatter = function (blockNumber) {
return utils.toHex(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
*
@@ -2912,11 +3566,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) {
@@ -3077,10 +3730,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,
@@ -3091,7 +3758,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 expanse.js.
@@ -3328,7 +3995,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 expanse.js.
@@ -3355,51 +4022,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:9656';
};
-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 {
@@ -3411,8 +4088,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;
@@ -3427,9 +4112,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));
@@ -3438,10 +4120,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 expanse.js.
@@ -3459,30 +4161,139 @@ module.exports = HttpProvider;
along with expanse.js. If not, see .
*/
/**
- * @file icap.js
+ * @file iban.js
* @author Marek Kotewicz
* @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 expanse 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 "generation of the IBAN shall be the exclusive responsibility of the bank/branch servicing the account".
+ * 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;
};
/**
@@ -3491,8 +4302,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;
};
/**
@@ -3501,7 +4312,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;
};
@@ -3512,7 +4323,7 @@ ICAP.prototype.isIndirect = function () {
* @method checksum
* @returns {String} checksum
*/
-ICAP.prototype.checksum = function () {
+Iban.prototype.checksum = function () {
return this._iban.substr(2, 2);
};
@@ -3523,7 +4334,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) : '';
};
@@ -3534,7 +4345,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) : '';
};
@@ -3544,14 +4355,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 expanse.js.
@@ -3579,16 +4400,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){
@@ -3705,7 +4533,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];
}
}
@@ -3764,7 +4592,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 expanse.js.
@@ -3857,7 +4685,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) {
module.exports = Jsonrpc;
-},{}],24:[function(require,module,exports){
+},{}],35:[function(require,module,exports){
/*
This file is part of expanse.js.
@@ -4031,7 +4859,594 @@ 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 expanse.js.
+
+ expanse.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.
+
+ expanse.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 expanse.js. If not, see .
+*/
+/** @file db.js
+ * @authors:
+ * Marek Kotewicz
+ * @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 expanse.js.
+
+ expanse.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.
+
+ expanse.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 expanse.js. If not, see .
+*/
+/**
+ * @file exp.js
+ * @author Marek Kotewicz
+ * @author Fabian Vogelsteller
+ * @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: [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 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
+];
+
+/// @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":20,"../formatters":29,"../method":35,"../property":42}],38:[function(require,module,exports){
+/*
+ This file is part of expanse.js.
+
+ expanse.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.
+
+ expanse.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 expanse.js. If not, see .
+*/
+/** @file exp.js
+ * @authors:
+ * Marek Kotewicz
+ * @date 2015
+ */
+
+var utils = require('../../utils/utils');
+var Property = require('../property');
+
+/// @returns an array of objects describing web3.eth api methods
+var methods = [
+];
+
+/// @returns an array of objects describing web3.eth api properties
+var properties = [
+ new Property({
+ name: 'listening',
+ getter: 'net_listening'
+ }),
+ new Property({
+ name: 'peerCount',
+ getter: 'net_peerCount',
+ outputFormatter: utils.toDecimal
+ })
+];
+
+
+module.exports = {
+ methods: methods,
+ properties: properties
+};
+
+
+},{"../../utils/utils":20,"../property":42}],39:[function(require,module,exports){
+/*
+ This file is part of expanse.js.
+
+ expanse.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.
+
+ expanse.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 expanse.js. If not, see .
+*/
+/** @file shh.js
+ * @authors:
+ * Marek Kotewicz
+ * @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 expanse.js.
+
+ expanse.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.
+
+ expanse.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 expanse.js. If not, see .
+*/
+/** @file watches.js
+ * @authors:
+ * Marek Kotewicz
+ * @date 2015
+ */
+
+var Method = require('../method');
+
+/// @returns an array of objects describing web3.exp.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 expanse.js.
@@ -4055,81 +5470,19 @@ module.exports = Method;
*/
var contract = require('./contract');
+var globalRegistrarAbi = require('../contracts/GlobalRegistrar.json');
+var icapRegistrarAbi= require('../contracts/ICAPRegistrar.json');
-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"}
-];
-
-module.exports = contract(abi).at(address);
-
-
-},{"./contract":12}],26:[function(require,module,exports){
-/*
- This file is part of expanse.js.
-
- expanse.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.
-
- expanse.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 expanse.js. If not, see .
-*/
-/** @file exp.js
- * @authors:
- * Marek Kotewicz
- * @date 2015
- */
-
-var utils = require('../utils/utils');
-var Property = require('./property');
-
-/// @returns an array of objects describing web3.exp api methods
-var methods = [
-];
-
-/// @returns an array of objects describing web3.exp api properties
-var properties = [
- new Property({
- name: 'listening',
- getter: 'net_listening'
- }),
- new Property({
- name: 'peerCount',
- getter: 'net_peerCount',
- outputFormatter: utils.toDecimal
- })
-];
-
+var globalNameregAddress = '0xc6d9d2cd449a754c494264e1809c50e34d64562b';
+var ibanNameregAddress = '0xa1a111bc074c9cfa781f0c38e63bd51c91b8af00';
module.exports = {
- methods: methods,
- properties: properties
+ namereg: contract(globalRegistrarAbi).at(globalNameregAddress),
+ ibanNamereg: contract(icapRegistrarAbi).at(ibanNameregAddress)
};
-},{"../utils/utils":7,"./property":27}],27:[function(require,module,exports){
+},{"../contracts/GlobalRegistrar.json":1,"../contracts/ICAPRegistrar.json":2,"./contract":25}],42:[function(require,module,exports){
/*
This file is part of expanse.js.
@@ -4281,7 +5634,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 expanse.js.
@@ -4431,8 +5784,6 @@ RequestManager.prototype.setProvider = function (p) {
}
};
-/*jshint maxparams:4 */
-
/**
* Should be used to start polling
*
@@ -4445,9 +5796,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
@@ -4456,7 +5806,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];
};
/**
@@ -4546,77 +5896,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 expanse.js.
-
- expanse.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.
-
- expanse.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 expanse.js. If not, see .
-*/
-/** @file shh.js
- * @authors:
- * Marek Kotewicz
- * @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 expanse.js.
@@ -4640,36 +5920,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);
});
};
@@ -4678,14 +5959,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.exp.sendTransaction({
- address: address,
+ address: to,
from: from,
value: value
}, callback);
@@ -4695,15 +5976,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);
@@ -4712,125 +5993,8 @@ 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 expanse.js.
-
- expanse.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.
-
- expanse.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 expanse.js. If not, see .
-*/
-/** @file watches.js
- * @authors:
- * Marek Kotewicz
- * @date 2015
- */
-
-var Method = require('./method');
-
-/// @returns an array of objects describing web3.exp.filter api methods
-var exp = 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 = {
- exp: exp,
- shh: shh
-};
-
-
-},{"./method":24}],32:[function(require,module,exports){
-
-},{}],33:[function(require,module,exports){
+},{"../contracts/SmartExchange.json":3,"../web3":22,"./contract":25,"./iban":32,"./namereg":41}],45:[function(require,module,exports){
+},{}],46:[function(require,module,exports){
;(function (root, factory) {
if (typeof exports === "object") {
// CommonJS
@@ -5573,7 +6737,7 @@ module.exports = {
return CryptoJS;
}));
-},{}],34:[function(require,module,exports){
+},{}],47:[function(require,module,exports){
;(function (root, factory, undef) {
if (typeof exports === "object") {
// CommonJS
@@ -5897,7 +7061,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
@@ -6202,7 +7366,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
@@ -6210,13 +7374,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.exp.contract = require('./lib/web3/contract');
-web3.exp.namereg = require('./lib/web3/namereg');
+web3.exp.namereg = namereg.namereg;
+web3.exp.ibanNamereg = namereg.ibanNamereg;
web3.exp.sendIBANTransaction = require('./lib/web3/transfer');
+web3.exp.iban = require('./lib/web3/iban');
// dont override global variable
if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {
@@ -6226,6 +7393,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 b1152a56b2..4efbaa3dce 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 61818c0e8b..570e92ed08 100644
--- a/jsre/jsre_test.go
+++ b/jsre/jsre_test.go
@@ -19,6 +19,7 @@ package jsre
import (
"io/ioutil"
"os"
+ "path"
"testing"
"time"
@@ -40,10 +41,23 @@ func (no *testNativeObjectBinding) TestMethod(call otto.FunctionCall) otto.Value
return v
}
-func TestExec(t *testing.T) {
- jsre := New("/tmp")
+func newWithTestJS(t *testing.T, testjs string) (*JSRE, string) {
+ dir, err := ioutil.TempDir("", "jsre-test")
+ if err != nil {
+ t.Fatal("cannot create temporary directory:", err)
+ }
+ if testjs != "" {
+ if err := ioutil.WriteFile(path.Join(dir, "test.js"), []byte(testjs), os.ModePerm); err != nil {
+ t.Fatal("cannot create test.js:", err)
+ }
+ }
+ return New(dir), dir
+}
+
+func TestExec(t *testing.T) {
+ jsre, dir := newWithTestJS(t, `msg = "testMsg"`)
+ defer os.RemoveAll(dir)
- ioutil.WriteFile("/tmp/test.js", []byte(`msg = "testMsg"`), os.ModePerm)
err := jsre.Exec("test.js")
if err != nil {
t.Errorf("expected no error, got %v", err)
@@ -64,9 +78,9 @@ func TestExec(t *testing.T) {
}
func TestNatto(t *testing.T) {
- jsre := New("/tmp")
+ jsre, dir := newWithTestJS(t, `setTimeout(function(){msg = "testMsg"}, 1);`)
+ defer os.RemoveAll(dir)
- ioutil.WriteFile("/tmp/test.js", []byte(`setTimeout(function(){msg = "testMsg"}, 1);`), os.ModePerm)
err := jsre.Exec("test.js")
if err != nil {
t.Errorf("expected no error, got %v", err)
@@ -88,26 +102,21 @@ func TestNatto(t *testing.T) {
}
func TestBind(t *testing.T) {
- jsre := New("/tmp")
+ 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) {
- jsre := New("/tmp")
+ jsre, dir := newWithTestJS(t, `msg = "testMsg"`)
+ defer os.RemoveAll(dir)
- ioutil.WriteFile("/tmp/test.js", []byte(`msg = "testMsg"`), os.ModePerm)
_, err := jsre.Run(`loadScript("test.js")`)
if err != nil {
t.Errorf("expected no error, got %v", err)
diff --git a/jsre/pretty.go b/jsre/pretty.go
new file mode 100644
index 0000000000..07f414f5d7
--- /dev/null
+++ b/jsre/pretty.go
@@ -0,0 +1,231 @@
+// Copyright 2015 The go-expanse Authors
+// This file is part of the go-expanse library.
+//
+// The go-expanse 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-expanse 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-expanse library. If not, see .
+
+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("")
+ }
+}
+
+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/miner.go b/miner/miner.go
index c203ddf6de..56dff1d9b3 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -18,6 +18,7 @@
package miner
import (
+ "fmt"
"math/big"
"sync/atomic"
@@ -29,6 +30,7 @@ import (
"github.com/expanse-project/go-expanse/event"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
+ "github.com/expanse-project/go-expanse/params"
"github.com/expanse-project/go-expanse/pow"
)
@@ -139,12 +141,24 @@ func (self *Miner) Mining() bool {
return atomic.LoadInt32(&self.mining) > 0
}
-func (self *Miner) HashRate() int64 {
- return self.pow.GetHashrate()
+func (self *Miner) HashRate() (tot int64) {
+ tot += self.pow.GetHashrate()
+ // do we care this might race? is it worth we're rewriting some
+ // aspects of the worker/locking up agents so we can get an accurate
+ // hashrate?
+ for _, agent := range self.worker.agents {
+ tot += agent.GetHashRate()
+ }
+ return
}
-func (self *Miner) SetExtra(extra []byte) {
+func (self *Miner) SetExtra(extra []byte) error {
+ if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
+ return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
+ }
+
self.worker.extra = extra
+ return nil
}
func (self *Miner) PendingState() *state.StateDB {
diff --git a/miner/remote_agent.go b/miner/remote_agent.go
index 6818c67cff..61bf181ec6 100644
--- a/miner/remote_agent.go
+++ b/miner/remote_agent.go
@@ -27,6 +27,11 @@ import (
"github.com/expanse-project/go-expanse/logger/glog"
)
+type hashrate struct {
+ ping time.Time
+ rate uint64
+}
+
type RemoteAgent struct {
mu sync.Mutex
@@ -36,14 +41,24 @@ type RemoteAgent struct {
currentWork *Work
work map[common.Hash]*Work
+
+ hashrateMu sync.RWMutex
+ hashrate map[common.Hash]hashrate
}
func NewRemoteAgent() *RemoteAgent {
- agent := &RemoteAgent{work: make(map[common.Hash]*Work)}
+ agent := &RemoteAgent{work: make(map[common.Hash]*Work), hashrate: make(map[common.Hash]hashrate)}
return agent
}
+func (a *RemoteAgent) SubmitHashrate(id common.Hash, rate uint64) {
+ a.hashrateMu.Lock()
+ defer a.hashrateMu.Unlock()
+
+ a.hashrate[id] = hashrate{time.Now(), rate}
+}
+
func (a *RemoteAgent) Work() chan<- *Work {
return a.workCh
}
@@ -63,7 +78,17 @@ func (a *RemoteAgent) Stop() {
close(a.workCh)
}
-func (a *RemoteAgent) GetHashRate() int64 { return 0 }
+// GetHashRate returns the accumulated hashrate of all identifier combined
+func (a *RemoteAgent) GetHashRate() (tot int64) {
+ a.hashrateMu.RLock()
+ defer a.hashrateMu.RUnlock()
+
+ // this could overflow
+ for _, hashrate := range a.hashrate {
+ tot += int64(hashrate.rate)
+ }
+ return
+}
func (a *RemoteAgent) GetWork() [3]string {
a.mu.Lock()
@@ -131,6 +156,14 @@ out:
}
}
a.mu.Unlock()
+
+ a.hashrateMu.Lock()
+ for id, hashrate := range a.hashrate {
+ if time.Since(hashrate.ping) > 10*time.Second {
+ delete(a.hashrate, id)
+ }
+ }
+ a.hashrateMu.Unlock()
}
}
}
diff --git a/miner/worker.go b/miner/worker.go
index f74e9580a6..a18f6a8df2 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -100,7 +100,7 @@ type worker struct {
exp 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, exp core.Backend) *worker {
worker := &worker{
exp: exp,
mux: exp.EventMux(),
- extraDb: exp.ExtraDb(),
+ chainDb: exp.ChainDb(),
recv: make(chan *Result, resultQueueSize),
gasPrice: new(big.Int),
chain: exp.ChainManager(),
@@ -278,7 +278,7 @@ func (self *worker) wait() {
glog.V(logger.Error).Infoln("Invalid block found during mining")
continue
}
- if err := core.ValidateHeader(self.exp.BlockProcessor().Pow, block.Header(), parent, true); err != nil && err != core.BlockFutureErr {
+ if err := core.ValidateHeader(self.exp.BlockProcessor().Pow, block.Header(), parent, true, false); err != nil && err != core.BlockFutureErr {
glog.V(logger.Error).Infoln("Invalid header on mined block:", err)
continue
}
@@ -291,20 +291,23 @@ 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
- go func(block *types.Block, logs state.Logs) {
+ go func(block *types.Block, logs state.Logs, receipts []*types.Receipt) {
self.mux.Post(core.NewMinedBlockEvent{block})
self.mux.Post(core.ChainEvent{block, block.Hash(), logs})
if stat == core.CanonStatTy {
self.mux.Post(core.ChainHeadEvent{block})
self.mux.Post(logs)
}
- }(block, work.state.Logs())
+ if err := core.PutBlockReceipts(self.chainDb, block, receipts); err != nil {
+ glog.V(logger.Warn).Infoln("error writing block receipts:", err)
+ }
+ }(block, work.state.Logs(), work.receipts)
}
// check staleness and display confirmation
@@ -344,7 +347,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.exp.StateDb())
+ state := state.New(parent.Root(), self.exp.ChainDb())
work := &Work{
state: state,
ancestors: set.New(),
@@ -431,8 +434,8 @@ func (self *worker) commitNewWork() {
tstart := time.Now()
parent := self.chain.CurrentBlock()
tstamp := tstart.Unix()
- if tstamp <= int64(parent.Time()) {
- tstamp = int64(parent.Time()) + 1
+ if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 {
+ tstamp = parent.Time().Int64() + 1
}
// this will ensure we're not going off too far in the future
if now := time.Now().Unix(); tstamp > now+4 {
@@ -445,12 +448,12 @@ func (self *worker) commitNewWork() {
header := &types.Header{
ParentHash: parent.Hash(),
Number: num.Add(num, common.Big1),
- Difficulty: core.CalcDifficulty(uint64(tstamp), parent.Time(), parent.Number(), parent.Difficulty()),
+ Difficulty: core.CalcDifficulty(uint64(tstamp), parent.Time().Uint64(), parent.Number(), parent.Difficulty()),
GasLimit: core.CalcGasLimit(parent),
GasUsed: new(big.Int),
Coinbase: self.coinbase,
Extra: self.extra,
- Time: uint64(tstamp),
+ Time: big.NewInt(tstamp),
}
previous := self.current
diff --git a/p2p/dial.go b/p2p/dial.go
index 9371028324..ab711d0ca9 100644
--- a/p2p/dial.go
+++ b/p2p/dial.go
@@ -23,7 +23,6 @@ import (
"net"
"time"
- "github.com/expanse-project/go-expanse/fdtrack"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/p2p/discover"
@@ -213,7 +212,6 @@ func (t *dialTask) Do(srv *Server) {
glog.V(logger.Detail).Infof("dial error: %v", err)
return
}
- fd = fdtrack.WrapConn("p2p", fd)
mfd := newMeteredConn(fd, false)
srv.setupConn(mfd, t.flags, t.dest)
diff --git a/p2p/discover/node.go b/p2p/discover/node.go
index 4acaef5e80..279b48b4a2 100644
--- a/p2p/discover/node.go
+++ b/p2p/discover/node.go
@@ -48,6 +48,10 @@ type Node struct {
// In those tests, the content of sha will not actually correspond
// with ID.
sha common.Hash
+
+ // whether this node is currently being pinged in order to replace
+ // it in a bucket
+ contested bool
}
func newNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node {
diff --git a/p2p/discover/table.go b/p2p/discover/table.go
index 1156cf0744..62c797aa9c 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
@@ -164,7 +163,9 @@ func randUint(max uint32) uint32 {
// Close terminates the network listener and flushes the node database.
func (tab *Table) Close() {
- tab.net.close()
+ if tab.net != nil {
+ tab.net.close()
+ }
tab.db.close()
}
@@ -233,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)
@@ -399,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
@@ -418,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
@@ -429,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())
@@ -465,24 +443,60 @@ 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()
+ defer tab.mutex.Unlock()
+ if b.bump(new) {
+ return
+ }
+ var oldest *Node
+ if len(b.entries) == bucketSize {
+ oldest = b.entries[bucketSize-1]
+ if oldest.contested {
+ // The node is already being replaced, don't attempt
+ // to replace it.
+ return
+ }
+ oldest.contested = true
+ // Let go of the mutex so other goroutines can access
+ // the table while we ping the least recently active node.
+ tab.mutex.Unlock()
+ err := tab.ping(oldest.ID, oldest.addr())
+ tab.mutex.Lock()
+ oldest.contested = false
+ if err == nil {
+ // The node responded, don't replace it.
+ return
+ }
+ }
+ added := b.replace(new, oldest)
+ 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 {
@@ -494,12 +508,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 {
@@ -509,6 +522,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 d03016cafa..1213d4c277 100644
--- a/p2p/discover/table_test.go
+++ b/p2p/discover/table_test.go
@@ -35,6 +35,7 @@ func TestTable_pingReplace(t *testing.T) {
doit := func(newNodeIsResponding, lastInBucketIsResponding bool) {
transport := newPingRecorder()
tab := newTable(transport, NodeID{}, &net.UDPAddr{}, "")
+ defer tab.Close()
pingSender := newNode(MustHexID("a502af0f59b2aab7746995408c79e9ca312d2793cc997e44fc55eda62f0150bbb8c59a6f9269ba3a081518b62699ee807c7c19c20125ddfccca872608af9e370"), net.IP{}, 99, 99)
// fill up the sender's bucket.
@@ -158,9 +159,7 @@ func newPingRecorder() *pingRecorder {
func (t *pingRecorder) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) {
panic("findnode called on pingRecorder")
}
-func (t *pingRecorder) close() {
- panic("close called on pingRecorder")
-}
+func (t *pingRecorder) close() {}
func (t *pingRecorder) waitping(from NodeID) error {
return nil // remote always pings
}
@@ -179,7 +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
@@ -237,9 +237,10 @@ func TestTable_ReadRandomNodesGetAll(t *testing.T) {
}
test := func(buf []*Node) bool {
tab := newTable(nil, NodeID{}, &net.UDPAddr{}, "")
+ 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() {
@@ -279,6 +280,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value {
func TestTable_Lookup(t *testing.T) {
self := nodeAtDistance(common.Hash{}, 0)
tab := newTable(lookupTestnet, self.ID, &net.UDPAddr{}, "")
+ defer tab.Close()
// lookup on empty table returns no nodes
if results := tab.Lookup(lookupTestnet.target); len(results) > 0 {
@@ -286,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 da68f37567..2bf2faaa33 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"
@@ -25,7 +26,6 @@ import (
"time"
"github.com/expanse-project/go-expanse/crypto"
- "github.com/expanse-project/go-expanse/fdtrack"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/p2p/nat"
@@ -43,6 +43,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")
)
@@ -198,7 +199,6 @@ func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, nodeDBP
if err != nil {
return nil, err
}
- fdtrack.Open("p2p")
conn, err := net.ListenUDP("udp", addr)
if err != nil {
return nil, err
@@ -236,7 +236,6 @@ func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, nodeDBPath strin
func (t *udp) close() {
close(t.closing)
- fdtrack.Close("p2p")
t.conn.Close()
// TODO: wait for the loops to end.
}
@@ -296,7 +295,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 +309,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
+ 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)
+ }
}
- if i > 0 {
- copy(pending, pending[i:])
- pending = pending[:len(pending)-i]
- }
- rearmTimeout()
}
}
}
@@ -385,7 +398,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
@@ -442,6 +455,10 @@ func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) ([]byte,
return packet, nil
}
+type tempError interface {
+ Temporary() bool
+}
+
// readLoop runs in its own goroutine. it handles incoming UDP packets.
func (t *udp) readLoop() {
defer t.conn.Close()
@@ -451,7 +468,13 @@ func (t *udp) readLoop() {
buf := make([]byte, 1280)
for {
nbytes, from, err := t.conn.ReadFromUDP(buf)
- if err != nil {
+ if tempErr, ok := err.(tempError); ok && tempErr.Temporary() {
+ // Ignore temporary read errors.
+ glog.V(logger.Debug).Infof("Temporary read error: %v", err)
+ continue
+ } else if err != nil {
+ // Shut down the loop for permament errors.
+ glog.V(logger.Debug).Infof("Read error: %v", err)
return
}
t.handlePacket(from, buf[:nbytes])
diff --git a/p2p/discover/udp_test.go b/p2p/discover/udp_test.go
index 0704b256d4..f9181d5b4f 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/metrics.go b/p2p/metrics.go
index 4b26104208..9eb6740385 100644
--- a/p2p/metrics.go
+++ b/p2p/metrics.go
@@ -34,7 +34,7 @@ var (
// meteredConn is a wrapper around a network TCP connection that meters both the
// inbound and outbound network traffic.
type meteredConn struct {
- net.Conn
+ *net.TCPConn // Network connection to wrap with metering
}
// newMeteredConn creates a new metered connection, also bumping the ingress or
@@ -45,13 +45,13 @@ func newMeteredConn(conn net.Conn, ingress bool) net.Conn {
} else {
egressConnectMeter.Mark(1)
}
- return &meteredConn{conn}
+ return &meteredConn{conn.(*net.TCPConn)}
}
// Read delegates a network read to the underlying connection, bumping the ingress
// traffic meter along the way.
func (c *meteredConn) Read(b []byte) (n int, err error) {
- n, err = c.Conn.Read(b)
+ n, err = c.TCPConn.Read(b)
ingressTrafficMeter.Mark(int64(n))
return
}
@@ -59,7 +59,7 @@ func (c *meteredConn) Read(b []byte) (n int, err error) {
// Write delegates a network write to the underlying connection, bumping the
// egress traffic meter along the way.
func (c *meteredConn) Write(b []byte) (n int, err error) {
- n, err = c.Conn.Write(b)
+ n, err = c.TCPConn.Write(b)
egressTrafficMeter.Mark(int64(n))
return
}
diff --git a/p2p/nat/natupnp_test.go b/p2p/nat/natupnp_test.go
index 5ac972057f..f575c5e42b 100644
--- a/p2p/nat/natupnp_test.go
+++ b/p2p/nat/natupnp_test.go
@@ -21,6 +21,7 @@ import (
"io"
"net"
"net/http"
+ "runtime"
"strings"
"testing"
@@ -28,6 +29,10 @@ import (
)
func TestUPNP_DDWRT(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skipf("disabled to avoid firewall prompt")
+ }
+
dev := &fakeIGD{
t: t,
ssdpResp: "HTTP/1.1 200 OK\r\n" +
diff --git a/p2p/peer_error.go b/p2p/peer_error.go
index f29edfeec4..1f5a0caf01 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 cd5126db9c..51f3be4434 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/p2p/server.go b/p2p/server.go
index b7f74c4588..690e58daa7 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -25,7 +25,6 @@ import (
"sync"
"time"
- "github.com/expanse-project/go-expanse/fdtrack"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/p2p/discover"
@@ -373,7 +372,7 @@ func (srv *Server) startListening() error {
}
laddr := listener.Addr().(*net.TCPAddr)
srv.ListenAddr = laddr.String()
- srv.listener = fdtrack.WrapListener("p2p", listener)
+ srv.listener = listener
srv.loopWG.Add(1)
go srv.listenLoop()
// Map the TCP listening port if NAT is configured.
@@ -542,6 +541,10 @@ func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn)
}
}
+type tempError interface {
+ Temporary() bool
+}
+
// listenLoop runs in its own goroutine and accepts
// inbound connections.
func (srv *Server) listenLoop() {
@@ -561,16 +564,31 @@ func (srv *Server) listenLoop() {
}
for {
+ // Wait for a handshake slot before accepting.
<-slots
- fd, err := srv.listener.Accept()
- if err != nil {
- return
- }
- mfd := newMeteredConn(fd, true)
- glog.V(logger.Debug).Infof("Accepted conn %v\n", mfd.RemoteAddr())
+ var (
+ fd net.Conn
+ err error
+ )
+ for {
+ fd, err = srv.listener.Accept()
+ if tempErr, ok := err.(tempError); ok && tempErr.Temporary() {
+ glog.V(logger.Debug).Infof("Temporary read error: %v", err)
+ continue
+ } else if err != nil {
+ glog.V(logger.Debug).Infof("Read error: %v", err)
+ return
+ }
+ break
+ }
+ fd = newMeteredConn(fd, true)
+ glog.V(logger.Debug).Infof("Accepted conn %v\n", fd.RemoteAddr())
+
+ // Spawn the handler. It will give the slot back when the connection
+ // has been established.
go func() {
- srv.setupConn(mfd, inboundConn, nil)
+ srv.setupConn(fd, inboundConn, nil)
slots <- struct{}{}
}()
}
diff --git a/rlp/decode.go b/rlp/decode.go
index 3f9e909197..7da365cb00 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 e30dfa3e0e..9fac81b171 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 c9b12a4950..0fa8e4e336 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 dd55b51078..0e9b364a8a 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 d8b09bf9e6..15ff1f96a0 100644
--- a/rpc/api/admin.go
+++ b/rpc/api/admin.go
@@ -37,6 +37,7 @@ import (
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/comms"
"github.com/expanse-project/go-expanse/rpc/shared"
+ "github.com/expanse-project/go-expanse/rpc/useragent"
"github.com/expanse-project/go-expanse/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 64bfd298d8..934a1fca2b 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.expanse.StateDb())
+ stateDb := state.New(block.Root(), self.expanse.ChainDb())
if stateDb == nil {
return nil, nil
}
diff --git a/rpc/api/eth.go b/rpc/api/eth.go
index bb49233d30..6f7734b9d4 100644
--- a/rpc/api/eth.go
+++ b/rpc/api/eth.go
@@ -92,6 +92,7 @@ var (
"eth_hashrate": (*ethApi).Hashrate,
"eth_getWork": (*ethApi).GetWork,
"eth_submitWork": (*ethApi).SubmitWork,
+ "eth_submitHashrate": (*ethApi).SubmitHashrate,
"eth_resend": (*ethApi).Resend,
"eth_pendingTransactions": (*ethApi).PendingTransactions,
"eth_getTransactionReceipt": (*ethApi).GetTransactionReceipt,
@@ -573,6 +574,15 @@ func (self *ethApi) SubmitWork(req *shared.Request) (interface{}, error) {
return self.xeth.RemoteMining().SubmitWork(args.Nonce, common.HexToHash(args.Digest), common.HexToHash(args.Header)), nil
}
+func (self *ethApi) SubmitHashrate(req *shared.Request) (interface{}, error) {
+ args := new(SubmitHashRateArgs)
+ if err := self.codec.Decode(req.Params, &args); err != nil {
+ return false, shared.NewDecodeParamError(err.Error())
+ }
+ self.xeth.RemoteMining().SubmitHashrate(common.HexToHash(args.Id), args.Rate)
+ return true, nil
+}
+
func (self *ethApi) Resend(req *shared.Request) (interface{}, error) {
args := new(ResendArgs)
if err := self.codec.Decode(req.Params, &args); err != nil {
diff --git a/rpc/api/eth_args.go b/rpc/api/eth_args.go
index 5b97d16f6a..c3c56e366f 100644
--- a/rpc/api/eth_args.go
+++ b/rpc/api/eth_args.go
@@ -169,6 +169,37 @@ func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
return nil
}
+type SubmitHashRateArgs struct {
+ Id string
+ Rate uint64
+}
+
+func (args *SubmitHashRateArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []interface{}
+ if err := json.Unmarshal(b, &obj); err != nil {
+ return shared.NewDecodeParamError(err.Error())
+ }
+
+ if len(obj) < 2 {
+ return shared.NewInsufficientParamsError(len(obj), 2)
+ }
+
+ arg0, ok := obj[0].(string)
+ if !ok {
+ return shared.NewInvalidTypeError("hash", "not a string")
+ }
+ args.Id = arg0
+
+ arg1, ok := obj[1].(string)
+ if !ok {
+ return shared.NewInvalidTypeError("rate", "not a string")
+ }
+
+ args.Rate = common.String2Big(arg1).Uint64()
+
+ return nil
+}
+
type HashArgs struct {
Hash string
}
@@ -877,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/miner.go b/rpc/api/miner.go
index e3e71a9ccf..d35558de07 100644
--- a/rpc/api/miner.go
+++ b/rpc/api/miner.go
@@ -17,12 +17,9 @@
package api
import (
- "fmt"
-
"github.com/expanse-project/ethash"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/exp"
- "github.com/expanse-project/go-expanse/params"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
)
@@ -126,11 +123,10 @@ func (self *minerApi) SetExtra(req *shared.Request) (interface{}, error) {
return nil, err
}
- if uint64(len(args.Data)) > params.MaximumExtraDataSize.Uint64()*2 {
- return false, fmt.Errorf("extra datasize can be no longer than %v bytes", params.MaximumExtraDataSize)
+ if err := self.expanse.Miner().SetExtra([]byte(args.Data)); err != nil {
+ return false, err
}
- self.expanse.Miner().SetExtra([]byte(args.Data))
return true, nil
}
diff --git a/rpc/api/net.go b/rpc/api/net.go
index 1d1b0015db..c4a9d4d4f8 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 685a637601..40ba0ab830 100644
--- a/rpc/api/personal.go
+++ b/rpc/api/personal.go
@@ -17,6 +17,7 @@
package api
import (
+ "fmt"
"time"
"github.com/expanse-project/go-expanse/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.expanse.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 809c42698f..cf14942489 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
similarity index 100%
rename from rpc/api/ssh_js.go
rename to rpc/api/shh_js.go
diff --git a/rpc/codec/codec.go b/rpc/codec/codec.go
index 398b18a2c4..a252f182db 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 d517cf83ce..4f8aaa7504 100644
--- a/rpc/codec/json.go
+++ b/rpc/codec/json.go
@@ -21,6 +21,7 @@ import (
"fmt"
"net"
"time"
+ "strings"
"github.com/expanse-project/go-expanse/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)
-
- deadline := time.Now().Add(READ_TIMEOUT * time.Second)
- if err := self.c.SetDeadline(deadline); err != nil {
+func (self *JsonCodec) Recv() (interface{}, error) {
+ var msg json.RawMessage
+ err := self.d.Decode(&msg)
+ if err != nil {
+ self.c.Close()
return nil, err
}
- for {
- n, err := self.c.Read(buf[bytesInBuffer:])
- if err != nil {
- return nil, err
- }
- bytesInBuffer += n
+ return msg, err
+}
- var failure shared.ErrorResponse
- if err = json.Unmarshal(buf[:bytesInBuffer], &failure); err == nil && failure.Error != nil {
+func (self *JsonCodec) ReadResponse() (interface{}, error) {
+ in, err := self.Recv()
+ 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
+ }
+
+ 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/http.go b/rpc/comms/http.go
index 090f2f595d..26fcde11c4 100644
--- a/rpc/comms/http.go
+++ b/rpc/comms/http.go
@@ -29,7 +29,6 @@ import (
"io"
"io/ioutil"
- "github.com/expanse-project/go-expanse/fdtrack"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/codec"
@@ -178,7 +177,6 @@ func listenHTTP(addr string, h http.Handler) (*stopServer, error) {
if err != nil {
return nil, err
}
- l = fdtrack.WrapListener("rpc", l)
s := &stopServer{l: l, idle: make(map[net.Conn]struct{})}
s.Server = &http.Server{
Addr: addr,
diff --git a/rpc/comms/inproc.go b/rpc/comms/inproc.go
index cf4af63340..2c07010969 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 122546c18d..7c4a25cf8f 100644
--- a/rpc/comms/ipc.go
+++ b/rpc/comms/ipc.go
@@ -42,37 +42,18 @@ func (self *ipcClient) Close() {
self.coder.Close()
}
-func (self *ipcClient) Send(req interface{}) error {
+func (self *ipcClient) Send(msg 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(msg); err != nil {
+ if err = self.reconnect(); err == nil {
+ err = self.coder.WriteResponse(msg)
}
- 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 +72,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 +90,8 @@ func NewIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
}
// Start IPC server
-func StartIpc(cfg IpcConfig, codec codec.Codec, offeredApi shared.ExpanseApi) error {
- return startIpc(cfg, codec, offeredApi)
+func StartIpc(cfg IpcConfig, codec codec.Codec, initializer func(conn net.Conn) (shared.ExpanseApi, 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 3e8094445e..9badc7e02f 100644
--- a/rpc/comms/ipc_unix.go
+++ b/rpc/comms/ipc_unix.go
@@ -22,11 +22,11 @@ import (
"net"
"os"
- "github.com/expanse-project/go-expanse/fdtrack"
"github.com/expanse-project/go-expanse/logger"
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
+ "github.com/expanse-project/go-expanse/rpc/useragent"
)
func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
@@ -35,7 +35,18 @@ func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
return nil, err
}
- return &ipcClient{cfg.Endpoint, c, codec, codec.New(c)}, nil
+ coder := codec.New(c)
+ msg := shared.Request{
+ Id: 0,
+ Method: useragent.EnableUserAgentMethod,
+ Jsonrpc: shared.JsonRpcVersion,
+ Params: []byte("[]"),
+ }
+
+ coder.WriteResponse(msg)
+ coder.Recv()
+
+ return &ipcClient{cfg.Endpoint, c, codec, coder}, nil
}
func (self *ipcClient) reconnect() error {
@@ -43,24 +54,32 @@ func (self *ipcClient) reconnect() error {
c, err := net.DialUnix("unix", nil, &net.UnixAddr{self.endpoint, "unix"})
if err == nil {
self.coder = self.codec.New(c)
+
+ msg := shared.Request{
+ Id: 0,
+ Method: useragent.EnableUserAgentMethod,
+ Jsonrpc: shared.JsonRpcVersion,
+ Params: []byte("[]"),
+ }
+ self.coder.WriteResponse(msg)
+ self.coder.Recv()
}
return err
}
-func startIpc(cfg IpcConfig, codec codec.Codec, api shared.ExpanseApi) error {
+func startIpc(cfg IpcConfig, codec codec.Codec, initializer func(conn net.Conn) (shared.ExpanseApi, error)) error {
os.Remove(cfg.Endpoint) // in case it still exists from a previous run
- l, err := net.Listen("unix", cfg.Endpoint)
+ l, err := net.ListenUnix("unix", &net.UnixAddr{Name: cfg.Endpoint, Net: "unix"})
if err != nil {
return err
}
- l = fdtrack.WrapListener("ipc", l)
os.Chmod(cfg.Endpoint, 0600)
go func() {
for {
- conn, err := l.Accept()
+ conn, err := l.AcceptUnix()
if err != nil {
glog.V(logger.Error).Infof("Error accepting ipc connection - %v\n", err)
continue
@@ -69,6 +88,13 @@ func startIpc(cfg IpcConfig, codec codec.Codec, api shared.ExpanseApi) 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 7dd0699d10..48b20664f9 100644
--- a/rpc/comms/ipc_windows.go
+++ b/rpc/comms/ipc_windows.go
@@ -32,6 +32,7 @@ import (
"github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/codec"
"github.com/expanse-project/go-expanse/rpc/shared"
+ "github.com/expanse-project/go-expanse/rpc/useragent"
)
var (
@@ -656,18 +657,38 @@ func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
return nil, err
}
- return &ipcClient{cfg.Endpoint, c, codec, codec.New(c)}, nil
+ coder := codec.New(c)
+ msg := shared.Request{
+ Id: 0,
+ Method: useragent.EnableUserAgentMethod,
+ Jsonrpc: shared.JsonRpcVersion,
+ Params: []byte("[]"),
+ }
+
+ coder.WriteResponse(msg)
+ coder.Recv()
+
+ return &ipcClient{cfg.Endpoint, c, codec, coder}, nil
}
func (self *ipcClient) reconnect() error {
c, err := Dial(self.endpoint)
if err == nil {
self.coder = self.codec.New(c)
+
+ req := shared.Request{
+ Id: 0,
+ Method: useragent.EnableUserAgentMethod,
+ Jsonrpc: shared.JsonRpcVersion,
+ Params: []byte("[]"),
+ }
+ self.coder.WriteResponse(req)
+ self.coder.Recv()
}
return err
}
-func startIpc(cfg IpcConfig, codec codec.Codec, api shared.ExpanseApi) error {
+func startIpc(cfg IpcConfig, codec codec.Codec, initializer func(conn net.Conn) (shared.ExpanseApi, error)) error {
os.Remove(cfg.Endpoint) // in case it still exists from a previous run
l, err := Listen(cfg.Endpoint)
@@ -687,6 +708,13 @@ func startIpc(cfg IpcConfig, codec codec.Codec, api shared.ExpanseApi) 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 86d75e6896..f9429e7294 100644
--- a/rpc/jeth.go
+++ b/rpc/jeth.go
@@ -18,12 +18,17 @@ package rpc
import (
"encoding/json"
-
"fmt"
+ "github.com/expanse-project/go-expanse/cmd/utils"
"github.com/expanse-project/go-expanse/jsre"
+ "github.com/expanse-project/go-expanse/logger"
+ "github.com/expanse-project/go-expanse/logger/glog"
"github.com/expanse-project/go-expanse/rpc/comms"
"github.com/expanse-project/go-expanse/rpc/shared"
+ "github.com/expanse-project/go-expanse/rpc/useragent"
+ "github.com/expanse-project/go-expanse/xeth"
+
"github.com/robertkrimen/otto"
)
@@ -31,10 +36,11 @@ type Jeth struct {
ethApi shared.ExpanseApi
re *jsre.JSRE
client comms.ExpanseClient
+ fe xeth.Frontend
}
-func NewJeth(ethApi shared.ExpanseApi, re *jsre.JSRE, client comms.ExpanseClient) *Jeth {
- return &Jeth{ethApi, re, client}
+func NewJeth(ethApi shared.ExpanseApi, re *jsre.JSRE, client comms.ExpanseClient, fe xeth.Frontend) *Jeth {
+ return &Jeth{ethApi, re, client, fe}
}
func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface{}) (response otto.Value) {
@@ -72,16 +78,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 +129,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 0000000000..6f5c195e98
--- /dev/null
+++ b/rpc/useragent/agent.go
@@ -0,0 +1,24 @@
+// Copyright 2015 The go-expanse Authors
+// This file is part of the go-expanse library.
+//
+// The go-expanse 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-expanse 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-expanse library. If not, see .
+
+// 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 0000000000..63f50d2f75
--- /dev/null
+++ b/rpc/useragent/remote_frontend.go
@@ -0,0 +1,141 @@
+// Copyright 2015 The go-expanse Authors
+// This file is part of the go-expanse library.
+//
+// The go-expanse 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-expanse 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-expanse library. If not, see .
+
+package useragent
+
+import (
+ "encoding/json"
+ "fmt"
+ "net"
+
+ "github.com/expanse-project/go-expanse/accounts"
+ "github.com/expanse-project/go-expanse/common"
+ "github.com/expanse-project/go-expanse/logger"
+ "github.com/expanse-project/go-expanse/logger/glog"
+ "github.com/expanse-project/go-expanse/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/rpc/xeth.go b/rpc/xeth.go
index 8488a88aca..df4f6edff6 100644
--- a/rpc/xeth.go
+++ b/rpc/xeth.go
@@ -53,7 +53,7 @@ func (self *Xeth) Call(method string, params []interface{}) (map[string]interfac
Method: method,
Params: data,
}
- // Send the request over and process the response
+ // Send the request over and retrieve the response
if err := self.client.Send(req); err != nil {
return nil, err
}
@@ -61,9 +61,17 @@ func (self *Xeth) Call(method string, params []interface{}) (map[string]interfac
if err != nil {
return nil, err
}
- value, ok := res.(map[string]interface{})
- if !ok {
- return nil, fmt.Errorf("Invalid response type: have %v, want %v", reflect.TypeOf(res), reflect.TypeOf(make(map[string]interface{})))
+ // Ensure the response is valid, and extract the results
+ success, isSuccessResponse := res.(*shared.SuccessResponse)
+ failure, isFailureResponse := res.(*shared.ErrorResponse)
+ switch {
+ case isFailureResponse:
+ return nil, fmt.Errorf("Method invocation failed: %v", failure.Error)
+
+ case isSuccessResponse:
+ return success.Result.(map[string]interface{}), nil
+
+ default:
+ return nil, fmt.Errorf("Invalid response type: %v", reflect.TypeOf(res))
}
- return value, nil
}
diff --git a/tests/block_test.go b/tests/block_test.go
index 910884fadf..80a9f6609c 100644
--- a/tests/block_test.go
+++ b/tests/block_test.go
@@ -35,6 +35,13 @@ func TestBcUncleHeaderValidityTests(t *testing.T) {
}
}
+func TestBcUncleTests(t *testing.T) {
+ err := RunBlockTest(filepath.Join(blockTestDir, "bcUncleTest.json"), BlockSkipTests)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
func TestBcInvalidHeaderTests(t *testing.T) {
err := RunBlockTest(filepath.Join(blockTestDir, "bcInvalidHeaderTest.json"), BlockSkipTests)
if err != nil {
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 35e086df7a..616f0e26f6 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -150,7 +150,7 @@ func runBlockTests(bt map[string]*BlockTest, skipTests []string) error {
// test the block
if err := runBlockTest(test); err != nil {
- return err
+ return fmt.Errorf("%s: %v", name, err)
}
glog.Infoln("Block test passed: ", name)
@@ -204,7 +204,7 @@ func (test *BlockTest) makeEthConfig() *exp.Config {
// InsertPreState populates the given database with the genesis
// accounts defined by the test.
func (t *BlockTest) InsertPreState(expanse *exp.Expanse) (*state.StateDB, error) {
- db := expanse.StateDb()
+ db := expanse.ChainDb()
statedb := state.New(common.Hash{}, db)
for addrString, acct := range t.preAccounts {
addr, err := hex.DecodeString(addrString)
@@ -365,8 +365,8 @@ func (s *BlockTest) validateBlockHeader(h *btHeader, h2 *types.Header) error {
return fmt.Errorf("GasUsed: expected: %v, decoded: %v", expectedGasUsed, h2.GasUsed)
}
- expectedTimestamp := mustConvertUint(h.Timestamp, 16)
- if expectedTimestamp != h2.Time {
+ expectedTimestamp := mustConvertBigInt(h.Timestamp, 16)
+ if expectedTimestamp.Cmp(h2.Time) != 0 {
return fmt.Errorf("Timestamp: expected: %v, decoded: %v", expectedTimestamp, h2.Time)
}
@@ -461,7 +461,7 @@ func mustConvertHeader(in btHeader) *types.Header {
GasUsed: mustConvertBigInt(in.GasUsed, 16),
GasLimit: mustConvertBigInt(in.GasLimit, 16),
Difficulty: mustConvertBigInt(in.Difficulty, 16),
- Time: mustConvertUint(in.Timestamp, 16),
+ Time: mustConvertBigInt(in.Timestamp, 16),
Nonce: types.EncodeNonce(mustConvertUint(in.Nonce, 16)),
}
return header
diff --git a/tests/files/BlockchainTests/bcUncleTest.json b/tests/files/BlockchainTests/bcUncleTest.json
index bd6326a889..0d0e83c0c1 100755
--- a/tests/files/BlockchainTests/bcUncleTest.json
+++ b/tests/files/BlockchainTests/bcUncleTest.json
@@ -4543,5 +4543,318 @@
}
}
}
+ },
+ "uncleTimestampTooBig" : {
+ "blocks" : [
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020000",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x5208",
+ "hash" : "6bd328a10bb674cc758bd1bccb8afb584808766434c28b85580b422c75d4130e",
+ "mixHash" : "fefce638471ab6b66b1f1423ae574a99a6b2137229fe1846c508554d718d2bc1",
+ "nonce" : "f8cf2912afdd244d",
+ "number" : "0x01",
+ "parentHash" : "b964d0b68e5a3c7265e4087dc2a8aaf599f06b6d6c1316a1b1b6475587f569e2",
+ "receiptTrie" : "e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313",
+ "stateRoot" : "cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878",
+ "timestamp" : "0x55d9d69f",
+ "transactionsTrie" : "5c9151c2413d1cd25c51ffb4ac38948acc1359bf08c6b49f283660e9bcf0f516",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf90261f901f9a0b964d0b68e5a3c7265e4087dc2a8aaf599f06b6d6c1316a1b1b6475587f569e2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a05c9151c2413d1cd25c51ffb4ac38948acc1359bf08c6b49f283660e9bcf0f516a0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd88252088455d9d69f80a0fefce638471ab6b66b1f1423ae574a99a6b2137229fe1846c508554d718d2bc188f8cf2912afdd244df862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba077c7cd36820c71821c1aed59de46e70e701c4a8dd89c9ba508ab722210f60da8a03f29825d40c7c3f7bff3ca69267e0f3fb74b2d18b8c2c4e3c135b5d3b06e288dc0",
+ "transactions" : [
+ {
+ "data" : "0x",
+ "gasLimit" : "0x04cb2f",
+ "gasPrice" : "0x01",
+ "nonce" : "0x00",
+ "r" : "0x77c7cd36820c71821c1aed59de46e70e701c4a8dd89c9ba508ab722210f60da8",
+ "s" : "0x3f29825d40c7c3f7bff3ca69267e0f3fb74b2d18b8c2c4e3c135b5d3b06e288d",
+ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
+ "v" : "0x1b",
+ "value" : "0x0a"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ },
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020040",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x5208",
+ "hash" : "4c179927c9b9897464c7133033b412c9b66ee2bb1fa4a4b2595a6006d4081e3f",
+ "mixHash" : "3449cf46635bab4ae7121dcd145e6ca12ac4337f79e88354c41bff1c48335b48",
+ "nonce" : "4376da5cd48ffb68",
+ "number" : "0x02",
+ "parentHash" : "6bd328a10bb674cc758bd1bccb8afb584808766434c28b85580b422c75d4130e",
+ "receiptTrie" : "5ea1a8b24652fed0ecab4738edd9211891eb8c4353c345973b78a02cc0f32f6b",
+ "stateRoot" : "e7e4760f75476ec7f51869d8bdce5c693058fd5a95c77ea9c0bf7ced1e50d70e",
+ "timestamp" : "0x55d9d6a1",
+ "transactionsTrie" : "c673e076264c4669a5c2e479f1757b78e42511efe33b5fd2c0a23b929c7f87f5",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf90260f901f9a06bd328a10bb674cc758bd1bccb8afb584808766434c28b85580b422c75d4130ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0e7e4760f75476ec7f51869d8bdce5c693058fd5a95c77ea9c0bf7ced1e50d70ea0c673e076264c4669a5c2e479f1757b78e42511efe33b5fd2c0a23b929c7f87f5a05ea1a8b24652fed0ecab4738edd9211891eb8c4353c345973b78a02cc0f32f6bb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd88252088455d9d6a180a03449cf46635bab4ae7121dcd145e6ca12ac4337f79e88354c41bff1c48335b48884376da5cd48ffb68f861f85f01018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba033c86e64d708c97c6b135cadff79dbf45985aa0b53694789e90d15f756765f239f1d0f8caa2a16405148c9d85581be5814960010f3cba938b5501590cea1f7cfc0",
+ "transactions" : [
+ {
+ "data" : "0x",
+ "gasLimit" : "0x04cb2f",
+ "gasPrice" : "0x01",
+ "nonce" : "0x01",
+ "r" : "0x33c86e64d708c97c6b135cadff79dbf45985aa0b53694789e90d15f756765f23",
+ "s" : "0x1d0f8caa2a16405148c9d85581be5814960010f3cba938b5501590cea1f7cf",
+ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
+ "v" : "0x1b",
+ "value" : "0x0a"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ },
+ {
+ "rlp" : "0xf90459f901f9a04c179927c9b9897464c7133033b412c9b66ee2bb1fa4a4b2595a6006d4081e3fa0f4fd3b99eb9b343e87bc472fdcd6b18e5cbcb231b1e70f8948e97b02c008ac26948888f1f195afa192cfee860698584c030f4c9db1a0e9940294a09308406a3d2e09203aed11db40259fac0a25e639ad2b30b82d07dea01722b8a91bfc4f5614ce36ee77c7cce6620ab4af36d3c54baa66d7dbeb7bce1aa04ede0225773c7a517b91994aca65ade45124e7ef4b8be1e6097c9773a11920afb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd88252088455d9d6a680a0caf6f553d8c1394d291caaeabc61bc25f9126f4c313c829b2a51134cbd23d27188e6999e52421f5a38f862f86002018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca015eb1cc916728b9799e55c489857727669afb2986433d5f54cde11faaed9f0eea05d36f6d06c34aae8d0a2a5895c8ba4a17ad46a5fa59f361cb3e7e01a23030e38f901f6f901f3a06bd328a10bb674cc758bd1bccb8afb584808766434c28b85580b422c75d4130ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794bcde5374fce5edbc8e2a8697c15331677e6ebf0ba0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000002832fefd8808080a077355633b05269548d6b3bd8e80d334fcb1a31c566b980dfc56eb57d5c16acc388846c622f81a727e7"
+ }
+ ],
+ "genesisBlockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020000",
+ "extraData" : "0x42",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x00",
+ "hash" : "b964d0b68e5a3c7265e4087dc2a8aaf599f06b6d6c1316a1b1b6475587f569e2",
+ "mixHash" : "b65f3c17c458ce015c087c3e4c0ffeeb010bf648a1faa2585c674d81ea7dcdfd",
+ "nonce" : "0b2ec3394d2421e3",
+ "number" : "0x00",
+ "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "7dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1",
+ "timestamp" : "0x54c98c81",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0b65f3c17c458ce015c087c3e4c0ffeeb010bf648a1faa2585c674d81ea7dcdfd880b2ec3394d2421e3c0c0",
+ "lastblockhash" : "4c179927c9b9897464c7133033b412c9b66ee2bb1fa4a4b2595a6006d4081e3f",
+ "postState" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x14",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "8888f1f195afa192cfee860698584c030f4c9db1" : {
+ "balance" : "0x8ac7230489e8a410",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x09184e71fbdc",
+ "code" : "0x",
+ "nonce" : "0x02",
+ "storage" : {
+ }
+ }
+ },
+ "pre" : {
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x09184e72a000",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ },
+ "uncleTimestampMaxUint256" : {
+ "blocks" : [
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020000",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x5208",
+ "hash" : "19c900975f94fd78dc12ad13740200fbe0a2eba43fd070bedc65588b0c95438a",
+ "mixHash" : "4296af28ea723598c959f1cabc6f01fa0c75d126cfde89f13ccd9debcf3079c3",
+ "nonce" : "3213b3fd7789f5d5",
+ "number" : "0x01",
+ "parentHash" : "e688d736f1307c6f97b6777381b30556137b9d4ca5c43fbd5b30d6b5df315264",
+ "receiptTrie" : "e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313",
+ "stateRoot" : "cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878",
+ "timestamp" : "0x55d9c571",
+ "transactionsTrie" : "5c9151c2413d1cd25c51ffb4ac38948acc1359bf08c6b49f283660e9bcf0f516",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf90261f901f9a0e688d736f1307c6f97b6777381b30556137b9d4ca5c43fbd5b30d6b5df315264a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a05c9151c2413d1cd25c51ffb4ac38948acc1359bf08c6b49f283660e9bcf0f516a0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd88252088455d9c57180a04296af28ea723598c959f1cabc6f01fa0c75d126cfde89f13ccd9debcf3079c3883213b3fd7789f5d5f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba077c7cd36820c71821c1aed59de46e70e701c4a8dd89c9ba508ab722210f60da8a03f29825d40c7c3f7bff3ca69267e0f3fb74b2d18b8c2c4e3c135b5d3b06e288dc0",
+ "transactions" : [
+ {
+ "data" : "0x",
+ "gasLimit" : "0x04cb2f",
+ "gasPrice" : "0x01",
+ "nonce" : "0x00",
+ "r" : "0x77c7cd36820c71821c1aed59de46e70e701c4a8dd89c9ba508ab722210f60da8",
+ "s" : "0x3f29825d40c7c3f7bff3ca69267e0f3fb74b2d18b8c2c4e3c135b5d3b06e288d",
+ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
+ "v" : "0x1b",
+ "value" : "0x0a"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ },
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020040",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x5208",
+ "hash" : "04e0807bea4d9766809afba8f4dbf2e5ab4e522aa4570bb915381c6593530e89",
+ "mixHash" : "782e9bf4a3427dee8cf2494f966830dd04a217eb5cf8769dba0ed6400212264f",
+ "nonce" : "e83b4878a0b9a46f",
+ "number" : "0x02",
+ "parentHash" : "19c900975f94fd78dc12ad13740200fbe0a2eba43fd070bedc65588b0c95438a",
+ "receiptTrie" : "5ea1a8b24652fed0ecab4738edd9211891eb8c4353c345973b78a02cc0f32f6b",
+ "stateRoot" : "e7e4760f75476ec7f51869d8bdce5c693058fd5a95c77ea9c0bf7ced1e50d70e",
+ "timestamp" : "0x55d9c573",
+ "transactionsTrie" : "c673e076264c4669a5c2e479f1757b78e42511efe33b5fd2c0a23b929c7f87f5",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf90260f901f9a019c900975f94fd78dc12ad13740200fbe0a2eba43fd070bedc65588b0c95438aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0e7e4760f75476ec7f51869d8bdce5c693058fd5a95c77ea9c0bf7ced1e50d70ea0c673e076264c4669a5c2e479f1757b78e42511efe33b5fd2c0a23b929c7f87f5a05ea1a8b24652fed0ecab4738edd9211891eb8c4353c345973b78a02cc0f32f6bb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd88252088455d9c57380a0782e9bf4a3427dee8cf2494f966830dd04a217eb5cf8769dba0ed6400212264f88e83b4878a0b9a46ff861f85f01018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba033c86e64d708c97c6b135cadff79dbf45985aa0b53694789e90d15f756765f239f1d0f8caa2a16405148c9d85581be5814960010f3cba938b5501590cea1f7cfc0",
+ "transactions" : [
+ {
+ "data" : "0x",
+ "gasLimit" : "0x04cb2f",
+ "gasPrice" : "0x01",
+ "nonce" : "0x01",
+ "r" : "0x33c86e64d708c97c6b135cadff79dbf45985aa0b53694789e90d15f756765f23",
+ "s" : "0x1d0f8caa2a16405148c9d85581be5814960010f3cba938b5501590cea1f7cf",
+ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
+ "v" : "0x1b",
+ "value" : "0x0a"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ },
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020080",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x5208",
+ "hash" : "eed1b4da708283370856fc76352d68f36d9766b7f366da372e2992ced9a1f663",
+ "mixHash" : "c250fe02a675a64e068023f48df2662ff2269d970f7689bde287228e200d5401",
+ "nonce" : "105781dacf8bcf41",
+ "number" : "0x03",
+ "parentHash" : "04e0807bea4d9766809afba8f4dbf2e5ab4e522aa4570bb915381c6593530e89",
+ "receiptTrie" : "4ede0225773c7a517b91994aca65ade45124e7ef4b8be1e6097c9773a11920af",
+ "stateRoot" : "e9940294a09308406a3d2e09203aed11db40259fac0a25e639ad2b30b82d07de",
+ "timestamp" : "0x55d9c577",
+ "transactionsTrie" : "1722b8a91bfc4f5614ce36ee77c7cce6620ab4af36d3c54baa66d7dbeb7bce1a",
+ "uncleHash" : "1e8797b712282d23d059df15e9082411499795fe2644bdfb35f310c10c78169b"
+ },
+ "rlp" : "0xf90479f901f9a004e0807bea4d9766809afba8f4dbf2e5ab4e522aa4570bb915381c6593530e89a01e8797b712282d23d059df15e9082411499795fe2644bdfb35f310c10c78169b948888f1f195afa192cfee860698584c030f4c9db1a0e9940294a09308406a3d2e09203aed11db40259fac0a25e639ad2b30b82d07dea01722b8a91bfc4f5614ce36ee77c7cce6620ab4af36d3c54baa66d7dbeb7bce1aa04ede0225773c7a517b91994aca65ade45124e7ef4b8be1e6097c9773a11920afb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd88252088455d9c57780a0c250fe02a675a64e068023f48df2662ff2269d970f7689bde287228e200d540188105781dacf8bcf41f862f86002018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca015eb1cc916728b9799e55c489857727669afb2986433d5f54cde11faaed9f0eea05d36f6d06c34aae8d0a2a5895c8ba4a17ad46a5fa59f361cb3e7e01a23030e38f90216f90213a019c900975f94fd78dc12ad13740200fbe0a2eba43fd070bedc65588b0c95438aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794bcde5374fce5edbc8e2a8697c15331677e6ebf0ba0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000002832fefd880a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80a06868c784ca472bb16eb9b23029965a737713003d0da6c006e4923e400cd783fc88d99c24fcd2648302",
+ "transactions" : [
+ {
+ "data" : "0x",
+ "gasLimit" : "0x04cb2f",
+ "gasPrice" : "0x01",
+ "nonce" : "0x02",
+ "r" : "0x15eb1cc916728b9799e55c489857727669afb2986433d5f54cde11faaed9f0ee",
+ "s" : "0x5d36f6d06c34aae8d0a2a5895c8ba4a17ad46a5fa59f361cb3e7e01a23030e38",
+ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
+ "v" : "0x1c",
+ "value" : "0x0a"
+ }
+ ],
+ "uncleHeaders" : [
+ {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "bcde5374fce5edbc8e2a8697c15331677e6ebf0b",
+ "difficulty" : "0x020000",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x00",
+ "hash" : "5264110fedc6f468e9b3c1fead10ee4bdd4957bcb6d193503f8ede6a0d478b95",
+ "mixHash" : "6868c784ca472bb16eb9b23029965a737713003d0da6c006e4923e400cd783fc",
+ "nonce" : "d99c24fcd2648302",
+ "number" : "0x02",
+ "parentHash" : "19c900975f94fd78dc12ad13740200fbe0a2eba43fd070bedc65588b0c95438a",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878",
+ "timestamp" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ }
+ ]
+ }
+ ],
+ "genesisBlockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020000",
+ "extraData" : "0x42",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x00",
+ "hash" : "e688d736f1307c6f97b6777381b30556137b9d4ca5c43fbd5b30d6b5df315264",
+ "mixHash" : "f35b4695bdfef02db19d255636bec7911667c7056df2b2f475053ea78dd1b0ff",
+ "nonce" : "5333c47f947590d8",
+ "number" : "0x00",
+ "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "7dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1",
+ "timestamp" : "0x54c98c81",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0f35b4695bdfef02db19d255636bec7911667c7056df2b2f475053ea78dd1b0ff885333c47f947590d8c0c0",
+ "lastblockhash" : "eed1b4da708283370856fc76352d68f36d9766b7f366da372e2992ced9a1f663",
+ "postState" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x14",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "8888f1f195afa192cfee860698584c030f4c9db1" : {
+ "balance" : "0x8ac7230489e8a410",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x09184e71fbdc",
+ "code" : "0x",
+ "nonce" : "0x02",
+ "storage" : {
+ }
+ }
+ },
+ "pre" : {
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x09184e72a000",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/tests/files/BlockchainTests/bcValidBlockTest.json b/tests/files/BlockchainTests/bcValidBlockTest.json
index 67a4b123a5..66b3c25eb5 100755
--- a/tests/files/BlockchainTests/bcValidBlockTest.json
+++ b/tests/files/BlockchainTests/bcValidBlockTest.json
@@ -2,7 +2,7 @@
"ExtraData1024" : {
"blocks" : [
{
- "rlp" : "0xf90667f905fba0b05b12d82d9f5ea5f1a1d1e0ae300b6765d849c05e85c6e3325adb6a237479e2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b8455b7f276b9040001020304050607080910111213141516171819202122232410000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000a0575d3f5fddc1ae8149849dc8e570ec26acceeb71368b7e110112f91e04df574188a786d7a6465bed98f866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0"
+ "rlp" : "0xf90667f905fba08c2fd497eec8ef215f5314aa333dec79cdd7d3ed4ac4b0278b7cb7e896141beba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fe3de82560b8455d5f36db9040001020304050607080910111213141516171819202122232410000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000a0fd3fc8e3e2037d4da6ddb2cd53ccf71bfe20e0180b750681615da9f392b2b5cb88483597d2f41121d1f866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0"
}
],
"genesisBlockHeader" : {
@@ -12,9 +12,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "b05b12d82d9f5ea5f1a1d1e0ae300b6765d849c05e85c6e3325adb6a237479e2",
- "mixHash" : "2138e36442388fbdac952de3df1f45378988bbc0c9908dc75a088a50118df47a",
- "nonce" : "4d10a3ed53d49c2a",
+ "hash" : "8c2fd497eec8ef215f5314aa333dec79cdd7d3ed4ac4b0278b7cb7e896141beb",
+ "mixHash" : "94113ea0cff9f8e6238d4690bfb792c01f278981cb69324f99b3f7d74a0555f0",
+ "nonce" : "31a7ad4c847d6419",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -23,8 +23,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a02138e36442388fbdac952de3df1f45378988bbc0c9908dc75a088a50118df47a884d10a3ed53d49c2ac0c0",
- "lastblockhash" : "b05b12d82d9f5ea5f1a1d1e0ae300b6765d849c05e85c6e3325adb6a237479e2",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a094113ea0cff9f8e6238d4690bfb792c01f278981cb69324f99b3f7d74a0555f08831a7ad4c847d6419c0c0",
+ "lastblockhash" : "8c2fd497eec8ef215f5314aa333dec79cdd7d3ed4ac4b0278b7cb7e896141beb",
"postState" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x64",
@@ -66,20 +66,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0x9b60",
- "hash" : "4f1efc7a5fc299d3005126217a0a59a1b546d57fba01e9a56ce8d4644989576d",
- "mixHash" : "c767990fd2c6a53ff263f07e4865138f6069150ca9a6795c9cb4445e2f688ea4",
- "nonce" : "babc01507e64ab08",
+ "hash" : "8673ec3c2dc51b15ae7d459f4d1b4fb8c2b0540a6ff36c44a89bdd2635f40259",
+ "mixHash" : "df5262c6a6a63550d25f3f5eb79f0adf4f10bd8d5f391a2e7a0351e042eb3700",
+ "nonce" : "d0a5076139120a1b",
"number" : "0x01",
- "parentHash" : "e1202f3547324ec0e187240fd556e9149c61c0e8f3700f974f33b806ec76015f",
+ "parentHash" : "2dbce99ecc0642021115fd662f970c97db29f0ab77d8cbcfe2fdac5a9c4e751a",
"receiptTrie" : "ec3f8def09644029c390920a2e25d14648d2c1f6244425a15068e8c9f8c19707",
"stateRoot" : "423ca0dbb9d7ea2a10cc94b19ceffab7bf52c6163fb6c6a005a1464748e9d969",
- "timestamp" : "0x55b7f279",
+ "timestamp" : "0x55d5f36f",
"transactionsTrie" : "7f40c85c972d94c1505e6309a763cabd663665e88520dc1df9910bdb2edb80ae",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf902a6f901f9a0e1202f3547324ec0e187240fd556e9149c61c0e8f3700f974f33b806ec76015fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0423ca0dbb9d7ea2a10cc94b19ceffab7bf52c6163fb6c6a005a1464748e9d969a07f40c85c972d94c1505e6309a763cabd663665e88520dc1df9910bdb2edb80aea0ec3f8def09644029c390920a2e25d14648d2c1f6244425a15068e8c9f8c19707b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8829b608455b7f27980a0c767990fd2c6a53ff263f07e4865138f6069150ca9a6795c9cb4445e2f688ea488babc01507e64ab08f8a7f8a5800a8307a1208081ffb857604b80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463cbf0b0c08114602d57005b60006004358073ffffffffffffffffffffffffffffffffffffffff16ff1ca00e7d3c664c49aa9f5ce4eb76c8547450466262a78bd093160f492ea0853c68e9a03f843e72210ff1da4fd9e375339872bcf0fad05c014e280ffc755e173700dd62c0",
+ "rlp" : "0xf902a6f901f9a02dbce99ecc0642021115fd662f970c97db29f0ab77d8cbcfe2fdac5a9c4e751aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0423ca0dbb9d7ea2a10cc94b19ceffab7bf52c6163fb6c6a005a1464748e9d969a07f40c85c972d94c1505e6309a763cabd663665e88520dc1df9910bdb2edb80aea0ec3f8def09644029c390920a2e25d14648d2c1f6244425a15068e8c9f8c19707b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de829b608455d5f36f80a0df5262c6a6a63550d25f3f5eb79f0adf4f10bd8d5f391a2e7a0351e042eb370088d0a5076139120a1bf8a7f8a5800a8307a1208081ffb857604b80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463cbf0b0c08114602d57005b60006004358073ffffffffffffffffffffffffffffffffffffffff16ff1ca00e7d3c664c49aa9f5ce4eb76c8547450466262a78bd093160f492ea0853c68e9a03f843e72210ff1da4fd9e375339872bcf0fad05c014e280ffc755e173700dd62c0",
"transactions" : [
{
"data" : "0x604b80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463cbf0b0c08114602d57005b60006004358073ffffffffffffffffffffffffffffffffffffffff16ff",
@@ -102,20 +102,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020040",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fd815",
"gasUsed" : "0x29e8",
- "hash" : "c4a1935a0c4982b76074c9408d4929a68f4ab126eb3aa9744fbb9c8b5b7108c4",
- "mixHash" : "f7c83c4dd1027d640134a0796c36836f16bb156b9ad6aac4a7be6c03c1bde51c",
- "nonce" : "8a08c681aff3f007",
+ "hash" : "1c9757e5d46f60bdbf30ad82313b09613b3eacd03250d4e57cd64b4c0536a45f",
+ "mixHash" : "e92fb366af9ae483a489a07f3efee04e9a1f37a7f8293743c446e5340007d585",
+ "nonce" : "c80b72a0f5bec0b0",
"number" : "0x02",
- "parentHash" : "4f1efc7a5fc299d3005126217a0a59a1b546d57fba01e9a56ce8d4644989576d",
+ "parentHash" : "8673ec3c2dc51b15ae7d459f4d1b4fb8c2b0540a6ff36c44a89bdd2635f40259",
"receiptTrie" : "f07efe64d675e0da95ad02d9acabe60870e522a1ef3c2703ddcac44b58a3634c",
"stateRoot" : "44b99148dcf8c520293cfa3c86244b4998e57de44313d21d1b0267dc0a68a5d0",
- "timestamp" : "0x55b7f27a",
+ "timestamp" : "0x55d5f371",
"transactionsTrie" : "581b9ae3564d0a429f48551804ec427b549b0f9ff92f0e2e96a4898167f82409",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90285f901f9a04f1efc7a5fc299d3005126217a0a59a1b546d57fba01e9a56ce8d4644989576da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a044b99148dcf8c520293cfa3c86244b4998e57de44313d21d1b0267dc0a68a5d0a0581b9ae3564d0a429f48551804ec427b549b0f9ff92f0e2e96a4898167f82409a0f07efe64d675e0da95ad02d9acabe60870e522a1ef3c2703ddcac44b58a3634cb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd88229e88455b7f27a80a0f7c83c4dd1027d640134a0796c36836f16bb156b9ad6aac4a7be6c03c1bde51c888a08c681aff3f007f886f884010a8307a120946295ee1b4f6dd65047762f924ecd367c17eabf8f01a4cbf0b0c000000000000000000000000000000000000000000000000000000000000000001ba0e9f25400a2683c5323e1f0a2c1d1bbfbc7a525e861993b9f21e414acfa876df0a04e3cb018a144be08a3cf6abc8abfcb0f159190af5d697283f05b326ba59ccc10c0",
+ "rlp" : "0xf90285f901f9a08673ec3c2dc51b15ae7d459f4d1b4fb8c2b0540a6ff36c44a89bdd2635f40259a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a044b99148dcf8c520293cfa3c86244b4998e57de44313d21d1b0267dc0a68a5d0a0581b9ae3564d0a429f48551804ec427b549b0f9ff92f0e2e96a4898167f82409a0f07efe64d675e0da95ad02d9acabe60870e522a1ef3c2703ddcac44b58a3634cb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fd8158229e88455d5f37180a0e92fb366af9ae483a489a07f3efee04e9a1f37a7f8293743c446e5340007d58588c80b72a0f5bec0b0f886f884010a8307a120946295ee1b4f6dd65047762f924ecd367c17eabf8f01a4cbf0b0c000000000000000000000000000000000000000000000000000000000000000001ba0e9f25400a2683c5323e1f0a2c1d1bbfbc7a525e861993b9f21e414acfa876df0a04e3cb018a144be08a3cf6abc8abfcb0f159190af5d697283f05b326ba59ccc10c0",
"transactions" : [
{
"data" : "0xcbf0b0c00000000000000000000000000000000000000000000000000000000000000000",
@@ -138,20 +138,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020080",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fcc2c",
"gasUsed" : "0x5558",
- "hash" : "2bea41e919041367b4b757b26e14a7bf59962caeea87be6970fac230e70277fd",
- "mixHash" : "caf1160147f0e9f35b8040ded51058cdb92ff2c0f5fe17b57377ad04a51eb32f",
- "nonce" : "fa1c1726b129b73d",
+ "hash" : "35f8fc45e4c6c4917c6335ec17af3b62f417d89d7190388bd9ded21937fcb0ec",
+ "mixHash" : "f97c32aacf87573135d2cc28fad71cf7887f12365f789310dd6a0ee8056b36aa",
+ "nonce" : "1cbda4bcf4227d5e",
"number" : "0x03",
- "parentHash" : "c4a1935a0c4982b76074c9408d4929a68f4ab126eb3aa9744fbb9c8b5b7108c4",
+ "parentHash" : "1c9757e5d46f60bdbf30ad82313b09613b3eacd03250d4e57cd64b4c0536a45f",
"receiptTrie" : "826e862432492d77d6484d0bc7f1446ee70b2c65e8375af09c1d03e306c93e96",
"stateRoot" : "bf1799991c6f2f23f1d93ede356e877388ad45e6731ac5e071db76e23df23fc6",
- "timestamp" : "0x55b7f27c",
+ "timestamp" : "0x55d5f373",
"transactionsTrie" : "eb87d8102765efd55c70863ab739867ed1bd718611d2b37058d6b7ebd0941a97",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90285f901f9a0c4a1935a0c4982b76074c9408d4929a68f4ab126eb3aa9744fbb9c8b5b7108c4a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bf1799991c6f2f23f1d93ede356e877388ad45e6731ac5e071db76e23df23fc6a0eb87d8102765efd55c70863ab739867ed1bd718611d2b37058d6b7ebd0941a97a0826e862432492d77d6484d0bc7f1446ee70b2c65e8375af09c1d03e306c93e96b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd88255588455b7f27c80a0caf1160147f0e9f35b8040ded51058cdb92ff2c0f5fe17b57377ad04a51eb32f88fa1c1726b129b73df886f884020a8307a120946295ee1b4f6dd65047762f924ecd367c17eabf8f01a4cbf0b0c001100000000000110000000000000110000000000000110000000000000000111ba02db741161d0014df4fdc93cfb33867295da3b2d9bcc9af8e2d6bb478e1a877d0a0439808cf9ba3e46e97e20a05450daa2a6dca8b21fc47041b5fa492fb322f39e4c0",
+ "rlp" : "0xf90285f901f9a01c9757e5d46f60bdbf30ad82313b09613b3eacd03250d4e57cd64b4c0536a45fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bf1799991c6f2f23f1d93ede356e877388ad45e6731ac5e071db76e23df23fc6a0eb87d8102765efd55c70863ab739867ed1bd718611d2b37058d6b7ebd0941a97a0826e862432492d77d6484d0bc7f1446ee70b2c65e8375af09c1d03e306c93e96b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fcc2c8255588455d5f37380a0f97c32aacf87573135d2cc28fad71cf7887f12365f789310dd6a0ee8056b36aa881cbda4bcf4227d5ef886f884020a8307a120946295ee1b4f6dd65047762f924ecd367c17eabf8f01a4cbf0b0c001100000000000110000000000000110000000000000110000000000000000111ba02db741161d0014df4fdc93cfb33867295da3b2d9bcc9af8e2d6bb478e1a877d0a0439808cf9ba3e46e97e20a05450daa2a6dca8b21fc47041b5fa492fb322f39e4c0",
"transactions" : [
{
"data" : "0xcbf0b0c00110000000000011000000000000011000000000000011000000000000000011",
@@ -176,9 +176,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "e1202f3547324ec0e187240fd556e9149c61c0e8f3700f974f33b806ec76015f",
- "mixHash" : "9e1cfca29377121b0aef8a9236f3b123d49dabd48046861bcc1e25fc62c99ff5",
- "nonce" : "8756853304b83657",
+ "hash" : "2dbce99ecc0642021115fd662f970c97db29f0ab77d8cbcfe2fdac5a9c4e751a",
+ "mixHash" : "e660eaee8fd51b47772bc099e9d42b44b725985863e65c3beaf973aa8c08288d",
+ "nonce" : "6bd62d8354f7f889",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -187,8 +187,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a09e1cfca29377121b0aef8a9236f3b123d49dabd48046861bcc1e25fc62c99ff5888756853304b83657c0c0",
- "lastblockhash" : "2bea41e919041367b4b757b26e14a7bf59962caeea87be6970fac230e70277fd",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0e660eaee8fd51b47772bc099e9d42b44b725985863e65c3beaf973aa8c08288d886bd62d8354f7f889c0c0",
+ "lastblockhash" : "35f8fc45e4c6c4917c6335ec17af3b62f417d89d7190388bd9ded21937fcb0ec",
"postState" : {
"0000000000000000000000000000000000000000" : {
"balance" : "0x0100",
@@ -229,6 +229,152 @@
}
}
},
+ "RecallSuicidedContractInOneBlock" : {
+ "blocks" : [
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020000",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fe3de",
+ "gasUsed" : "0x9b60",
+ "hash" : "cf83ae01626704224c3cb3689a2808d33587e348463bc27db5da8b574b2ed9f4",
+ "mixHash" : "64f49eed71bbc033392ba8543967d7417a677348ccb9125b5e3993b233032d2b",
+ "nonce" : "6afddfbe3fc0727c",
+ "number" : "0x01",
+ "parentHash" : "e0dffadd3df956f9c6dffdad1481b2de060890e85dde5d4c769ed97ca1019a15",
+ "receiptTrie" : "ec3f8def09644029c390920a2e25d14648d2c1f6244425a15068e8c9f8c19707",
+ "stateRoot" : "423ca0dbb9d7ea2a10cc94b19ceffab7bf52c6163fb6c6a005a1464748e9d969",
+ "timestamp" : "0x55d5f375",
+ "transactionsTrie" : "7f40c85c972d94c1505e6309a763cabd663665e88520dc1df9910bdb2edb80ae",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf902a6f901f9a0e0dffadd3df956f9c6dffdad1481b2de060890e85dde5d4c769ed97ca1019a15a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0423ca0dbb9d7ea2a10cc94b19ceffab7bf52c6163fb6c6a005a1464748e9d969a07f40c85c972d94c1505e6309a763cabd663665e88520dc1df9910bdb2edb80aea0ec3f8def09644029c390920a2e25d14648d2c1f6244425a15068e8c9f8c19707b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de829b608455d5f37580a064f49eed71bbc033392ba8543967d7417a677348ccb9125b5e3993b233032d2b886afddfbe3fc0727cf8a7f8a5800a8307a1208081ffb857604b80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463cbf0b0c08114602d57005b60006004358073ffffffffffffffffffffffffffffffffffffffff16ff1ca00e7d3c664c49aa9f5ce4eb76c8547450466262a78bd093160f492ea0853c68e9a03f843e72210ff1da4fd9e375339872bcf0fad05c014e280ffc755e173700dd62c0",
+ "transactions" : [
+ {
+ "data" : "0x604b80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463cbf0b0c08114602d57005b60006004358073ffffffffffffffffffffffffffffffffffffffff16ff",
+ "gasLimit" : "0x07a120",
+ "gasPrice" : "0x0a",
+ "nonce" : "0x00",
+ "r" : "0x0e7d3c664c49aa9f5ce4eb76c8547450466262a78bd093160f492ea0853c68e9",
+ "s" : "0x3f843e72210ff1da4fd9e375339872bcf0fad05c014e280ffc755e173700dd62",
+ "to" : "",
+ "v" : "0x1c",
+ "value" : "0xff"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ },
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020040",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fd815",
+ "gasUsed" : "0x7f40",
+ "hash" : "ac96fa4af300f71025f7442cf278abe45dc789a167bff8e102ea3f3bb1dee2ca",
+ "mixHash" : "55bb9767542a6acd7e02cebbff51330846c1e2c4ca703f4655b8be478165d8bd",
+ "nonce" : "ba79253406610fb9",
+ "number" : "0x02",
+ "parentHash" : "cf83ae01626704224c3cb3689a2808d33587e348463bc27db5da8b574b2ed9f4",
+ "receiptTrie" : "4e6849e0b3c4415a7266cce7d4e494a5a743fca2f95755667fce336c52771c9d",
+ "stateRoot" : "a3c6cbad55204a40a6661061ea40fbc40491d5e97ca2d5858a025ad5f2178edf",
+ "timestamp" : "0x55d5f376",
+ "transactionsTrie" : "4fe1aa9540114cce1ee19a4751bede622013e27f1025c7ef5d955f0132f978db",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf9030cf901f9a0cf83ae01626704224c3cb3689a2808d33587e348463bc27db5da8b574b2ed9f4a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a3c6cbad55204a40a6661061ea40fbc40491d5e97ca2d5858a025ad5f2178edfa04fe1aa9540114cce1ee19a4751bede622013e27f1025c7ef5d955f0132f978dba04e6849e0b3c4415a7266cce7d4e494a5a743fca2f95755667fce336c52771c9db90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fd815827f408455d5f37680a055bb9767542a6acd7e02cebbff51330846c1e2c4ca703f4655b8be478165d8bd88ba79253406610fb9f9010cf884010a8307a120946295ee1b4f6dd65047762f924ecd367c17eabf8f01a4cbf0b0c000000000000000000000000000000000000000000000000000000000000000001ba0e9f25400a2683c5323e1f0a2c1d1bbfbc7a525e861993b9f21e414acfa876df0a04e3cb018a144be08a3cf6abc8abfcb0f159190af5d697283f05b326ba59ccc10f884020a8307a120946295ee1b4f6dd65047762f924ecd367c17eabf8f01a4cbf0b0c001100000000000110000000000000110000000000000110000000000000000111ba02db741161d0014df4fdc93cfb33867295da3b2d9bcc9af8e2d6bb478e1a877d0a0439808cf9ba3e46e97e20a05450daa2a6dca8b21fc47041b5fa492fb322f39e4c0",
+ "transactions" : [
+ {
+ "data" : "0xcbf0b0c00000000000000000000000000000000000000000000000000000000000000000",
+ "gasLimit" : "0x07a120",
+ "gasPrice" : "0x0a",
+ "nonce" : "0x01",
+ "r" : "0xe9f25400a2683c5323e1f0a2c1d1bbfbc7a525e861993b9f21e414acfa876df0",
+ "s" : "0x4e3cb018a144be08a3cf6abc8abfcb0f159190af5d697283f05b326ba59ccc10",
+ "to" : "6295ee1b4f6dd65047762f924ecd367c17eabf8f",
+ "v" : "0x1b",
+ "value" : "0x01"
+ },
+ {
+ "data" : "0xcbf0b0c00110000000000011000000000000011000000000000011000000000000000011",
+ "gasLimit" : "0x07a120",
+ "gasPrice" : "0x0a",
+ "nonce" : "0x02",
+ "r" : "0x2db741161d0014df4fdc93cfb33867295da3b2d9bcc9af8e2d6bb478e1a877d0",
+ "s" : "0x439808cf9ba3e46e97e20a05450daa2a6dca8b21fc47041b5fa492fb322f39e4",
+ "to" : "6295ee1b4f6dd65047762f924ecd367c17eabf8f",
+ "v" : "0x1b",
+ "value" : "0x01"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ }
+ ],
+ "genesisBlockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x020000",
+ "extraData" : "0x42",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x00",
+ "hash" : "e0dffadd3df956f9c6dffdad1481b2de060890e85dde5d4c769ed97ca1019a15",
+ "mixHash" : "13558d7be6a18d42bcf54c92ac59c16de2f867012bf6896ea67fea10d3f5bd02",
+ "nonce" : "515d58cf8b44534a",
+ "number" : "0x00",
+ "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "7dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1",
+ "timestamp" : "0x54c98c81",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a013558d7be6a18d42bcf54c92ac59c16de2f867012bf6896ea67fea10d3f5bd0288515d58cf8b44534ac0c0",
+ "lastblockhash" : "ac96fa4af300f71025f7442cf278abe45dc789a167bff8e102ea3f3bb1dee2ca",
+ "postState" : {
+ "0000000000000000000000000000000000000000" : {
+ "balance" : "0x0100",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "6295ee1b4f6dd65047762f924ecd367c17eabf8f" : {
+ "balance" : "0x01",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "8888f1f195afa192cfee860698584c030f4c9db1" : {
+ "balance" : "0x8ac7230489f30a40",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x09184e6794bf",
+ "code" : "0x",
+ "nonce" : "0x03",
+ "storage" : {
+ }
+ }
+ },
+ "pre" : {
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x09184e72a000",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ },
"SimpleTx" : {
"blocks" : [
{
@@ -239,18 +385,18 @@
"extraData" : "0x",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x5208",
- "hash" : "9a09e1629419f50a178d08223268dce04d3e9b40c47e23b930af5e6f93b2322c",
- "mixHash" : "d72a653d355a6fb95dfca8a70dfb7a1a0c14c43eefd9935d4e2a76863a2675d2",
- "nonce" : "ad238c92cd105000",
+ "hash" : "1233b33c3768c89bd2e949d05a429c8ed5206b1b8bef36d755b088a3c47bf855",
+ "mixHash" : "22b3f6f80e88965d5e57331e657fc2def2969152c348273fd3a556f62dc8825a",
+ "nonce" : "6c9b38c24303299c",
"number" : "0x01",
- "parentHash" : "141fc55a58be70b15bf8449b005772d708f366b088093b57e4c50b31973317f0",
+ "parentHash" : "c6cde6f56d64db59c89e4543a1c2c1264f8190b02bc762683bbea75a6d61784e",
"receiptTrie" : "bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52",
"stateRoot" : "964e6c9995e7e3757e934391b4f16b50c20409ee4eb9abd4c4617cb805449b9a",
- "timestamp" : "0x55b7f27f",
+ "timestamp" : "0x55d5f379",
"transactionsTrie" : "53d5b71a8fbb9590de82d69dfa4ac31923b0c8afce0d30d0d8d1e931f25030dc",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90260f901f9a0141fc55a58be70b15bf8449b005772d708f366b088093b57e4c50b31973317f0a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0964e6c9995e7e3757e934391b4f16b50c20409ee4eb9abd4c4617cb805449b9aa053d5b71a8fbb9590de82d69dfa4ac31923b0c8afce0d30d0d8d1e931f25030dca0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd88252088455b7f27f80a0d72a653d355a6fb95dfca8a70dfb7a1a0c14c43eefd9935d4e2a76863a2675d288ad238c92cd105000f861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0f3266921c93d600c43f6fa4724b7abae079b35b9e95df592f95f9f3445e94c88a012f977552ebdb7a492cf35f3106df16ccb4576ebad4113056ee1f52cbe4978c1c0",
+ "rlp" : "0xf90260f901f9a0c6cde6f56d64db59c89e4543a1c2c1264f8190b02bc762683bbea75a6d61784ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0964e6c9995e7e3757e934391b4f16b50c20409ee4eb9abd4c4617cb805449b9aa053d5b71a8fbb9590de82d69dfa4ac31923b0c8afce0d30d0d8d1e931f25030dca0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd88252088455d5f37980a022b3f6f80e88965d5e57331e657fc2def2969152c348273fd3a556f62dc8825a886c9b38c24303299cf861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0f3266921c93d600c43f6fa4724b7abae079b35b9e95df592f95f9f3445e94c88a012f977552ebdb7a492cf35f3106df16ccb4576ebad4113056ee1f52cbe4978c1c0",
"transactions" : [
{
"data" : "0x",
@@ -275,9 +421,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "141fc55a58be70b15bf8449b005772d708f366b088093b57e4c50b31973317f0",
- "mixHash" : "dc198bc5b76f3985177efaad99b25bccfbfe9d56328e7ab41ab6a8054ae3203a",
- "nonce" : "534d14675dbebd2c",
+ "hash" : "c6cde6f56d64db59c89e4543a1c2c1264f8190b02bc762683bbea75a6d61784e",
+ "mixHash" : "8c73628251e10dcd7cac339d4d5d60c28897d59f832435f77c327e4fc04d5e4b",
+ "nonce" : "a5a076acffc3d021",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -286,8 +432,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0dc198bc5b76f3985177efaad99b25bccfbfe9d56328e7ab41ab6a8054ae3203a88534d14675dbebd2cc0c0",
- "lastblockhash" : "9a09e1629419f50a178d08223268dce04d3e9b40c47e23b930af5e6f93b2322c",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a08c73628251e10dcd7cac339d4d5d60c28897d59f832435f77c327e4fc04d5e4b88a5a076acffc3d021c0c0",
+ "lastblockhash" : "1233b33c3768c89bd2e949d05a429c8ed5206b1b8bef36d755b088a3c47bf855",
"postState" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x0a",
@@ -329,20 +475,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0xf618",
- "hash" : "d0c476cd471208ea9000f14343f820bacf5bb84818f164c91ee482b4d15777e5",
- "mixHash" : "eb2d5fce544f077d65d201bee95b3047c4ae82f2f47c34e07bccd61348827370",
- "nonce" : "3574397101ab284e",
+ "hash" : "7b4977120a0ee41f3f6a37d35887745fa3ec4f040b19c86c04f1705dcc7cb597",
+ "mixHash" : "d94fe632206c4afc4f52a75d128ccc6de848e9a458c2217ac8265a647c907750",
+ "nonce" : "ba192f1cb643c16f",
"number" : "0x01",
- "parentHash" : "d7a1383adceae842ac7e0c749ec52ad9154f0091db88877d81c6ad722c234892",
+ "parentHash" : "37cbb5aa6f955d7fc4048cc3dca511979b8a37679835d510cfeb4c6cbe6cde16",
"receiptTrie" : "86e489f2e34f4665b59315779d2bb5c16dc9bf7066aad3c89557556a40d76492",
"stateRoot" : "63dd9ae8517e40e5e48d7efc1440411c120b3e880ed01d0f6874380cf69d45bf",
- "timestamp" : "0x55b7f280",
+ "timestamp" : "0x55d5f37b",
"transactionsTrie" : "9ca199690a5ad007f08fac5b524d2fa2fa1e0397f7534f1d9c7e388c571aa2c4",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90323f901f9a0d7a1383adceae842ac7e0c749ec52ad9154f0091db88877d81c6ad722c234892a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a063dd9ae8517e40e5e48d7efc1440411c120b3e880ed01d0f6874380cf69d45bfa09ca199690a5ad007f08fac5b524d2fa2fa1e0397f7534f1d9c7e388c571aa2c4a086e489f2e34f4665b59315779d2bb5c16dc9bf7066aad3c89557556a40d76492b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882f6188455b7f28080a0eb2d5fce544f077d65d201bee95b3047c4ae82f2f47c34e07bccd61348827370883574397101ab284ef90123f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0f3266921c93d600c43f6fa4724b7abae079b35b9e95df592f95f9f3445e94c88a012f977552ebdb7a492cf35f3106df16ccb4576ebad4113056ee1f52cbe4978c1f85f800182520894000000000000000000000000000b9331677e6ebf0a801ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3f85f030182520894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3c0",
+ "rlp" : "0xf90323f901f9a037cbb5aa6f955d7fc4048cc3dca511979b8a37679835d510cfeb4c6cbe6cde16a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a063dd9ae8517e40e5e48d7efc1440411c120b3e880ed01d0f6874380cf69d45bfa09ca199690a5ad007f08fac5b524d2fa2fa1e0397f7534f1d9c7e388c571aa2c4a086e489f2e34f4665b59315779d2bb5c16dc9bf7066aad3c89557556a40d76492b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de82f6188455d5f37b80a0d94fe632206c4afc4f52a75d128ccc6de848e9a458c2217ac8265a647c90775088ba192f1cb643c16ff90123f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0f3266921c93d600c43f6fa4724b7abae079b35b9e95df592f95f9f3445e94c88a012f977552ebdb7a492cf35f3106df16ccb4576ebad4113056ee1f52cbe4978c1f85f800182520894000000000000000000000000000b9331677e6ebf0a801ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3f85f030182520894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3c0",
"transactions" : [
{
"data" : "0x",
@@ -389,9 +535,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "d7a1383adceae842ac7e0c749ec52ad9154f0091db88877d81c6ad722c234892",
- "mixHash" : "a4cf31bdf7b647a9c5b4927e113c52fb135ee98648df831149ea161cb06d2291",
- "nonce" : "d71919b098132f9c",
+ "hash" : "37cbb5aa6f955d7fc4048cc3dca511979b8a37679835d510cfeb4c6cbe6cde16",
+ "mixHash" : "d618479348484fbc60b890b62529d620231bb098ed243c6067c7f01c90df9048",
+ "nonce" : "85fb6f380fc20c15",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -400,8 +546,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bba25a960aa5c66a2cbd42582b5859a1b8f01db4ccc9eda59e82c315e50dc871a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0a4cf31bdf7b647a9c5b4927e113c52fb135ee98648df831149ea161cb06d229188d71919b098132f9cc0c0",
- "lastblockhash" : "d0c476cd471208ea9000f14343f820bacf5bb84818f164c91ee482b4d15777e5",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bba25a960aa5c66a2cbd42582b5859a1b8f01db4ccc9eda59e82c315e50dc871a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0d618479348484fbc60b890b62529d620231bb098ed243c6067c7f01c90df90488885fb6f380fc20c15c0c0",
+ "lastblockhash" : "7b4977120a0ee41f3f6a37d35887745fa3ec4f040b19c86c04f1705dcc7cb597",
"postState" : {
"000000000000000000000000000b9331677e6ebf" : {
"balance" : "0x0a",
@@ -485,20 +631,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0xc350",
- "hash" : "3c9b70cb4d3df2d3c3f78efe8ea133e88c229acb0434909b70265424ea0ffc50",
- "mixHash" : "19d3895481b5be9641325654014804396c0032528cc127002e0925ddfb596584",
- "nonce" : "b28baa17581f6103",
+ "hash" : "77a8d519b4f678feecda052fa9cd6bac5c1d7313c66af8b434fdf2afe4c0db70",
+ "mixHash" : "6b4d051c23def9cefc87924bc76619f857a4a6de07a9dadf11552d16b11d00ac",
+ "nonce" : "ff16b3b8f6dc207a",
"number" : "0x01",
- "parentHash" : "6985f169ef6a9a8ee58645e7bd93d825672632f2098640eecfdba0c851ec008b",
+ "parentHash" : "7880053bd588b13a5c3535f212df856c730606b9e51267219e908216bc006a03",
"receiptTrie" : "5e947bdcb71ec84c3e4f884827f8bcc98412c54bffa8ee25770d55ddbcb05f23",
"stateRoot" : "d4d1286d3c22aaacd7bd2adcc2934ba68740c4c5360c89f99a3a6a727a8bcbbd",
- "timestamp" : "0x55b7f282",
+ "timestamp" : "0x55d5f37e",
"transactionsTrie" : "0f6203a75e815282560cdf61871ed2fa253b910d74f0f772bbb980d2f13dedd9",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf903fef901f9a06985f169ef6a9a8ee58645e7bd93d825672632f2098640eecfdba0c851ec008ba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0d4d1286d3c22aaacd7bd2adcc2934ba68740c4c5360c89f99a3a6a727a8bcbbda00f6203a75e815282560cdf61871ed2fa253b910d74f0f772bbb980d2f13dedd9a05e947bdcb71ec84c3e4f884827f8bcc98412c54bffa8ee25770d55ddbcb05f23b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882c3508455b7f28280a019d3895481b5be9641325654014804396c0032528cc127002e0925ddfb59658488b28baa17581f6103f901fef901fb803282c3508080b901ae60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b561ba04d2aeb53154952b3a3d4718d8a11476c1165f8b53fad1c16e7c27d2a0df29298a0695d3859403ff7ae34072e8f48f29d603aef37fff7d01e55f32de724c9492239c0",
+ "rlp" : "0xf903fef901f9a07880053bd588b13a5c3535f212df856c730606b9e51267219e908216bc006a03a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0d4d1286d3c22aaacd7bd2adcc2934ba68740c4c5360c89f99a3a6a727a8bcbbda00f6203a75e815282560cdf61871ed2fa253b910d74f0f772bbb980d2f13dedd9a05e947bdcb71ec84c3e4f884827f8bcc98412c54bffa8ee25770d55ddbcb05f23b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de82c3508455d5f37e80a06b4d051c23def9cefc87924bc76619f857a4a6de07a9dadf11552d16b11d00ac88ff16b3b8f6dc207af901fef901fb803282c3508080b901ae60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b561ba04d2aeb53154952b3a3d4718d8a11476c1165f8b53fad1c16e7c27d2a0df29298a0695d3859403ff7ae34072e8f48f29d603aef37fff7d01e55f32de724c9492239c0",
"transactions" : [
{
"data" : "0x60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b56",
@@ -523,9 +669,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x64",
- "hash" : "6985f169ef6a9a8ee58645e7bd93d825672632f2098640eecfdba0c851ec008b",
- "mixHash" : "f0a4f86d751e9307fadaa929b37cfa5fe1a02999157e04ef9ccc061e85a26981",
- "nonce" : "fb14a9a8b9e31de0",
+ "hash" : "7880053bd588b13a5c3535f212df856c730606b9e51267219e908216bc006a03",
+ "mixHash" : "02f48916fece039bbb816bbc50f0a08ff9ffb5f7c91d66de884e1a0884969b01",
+ "nonce" : "e89cfda8dde9b93f",
"number" : "0x00",
"parentHash" : "efb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -534,8 +680,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a0efb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8648454c98c8142a0f0a4f86d751e9307fadaa929b37cfa5fe1a02999157e04ef9ccc061e85a2698188fb14a9a8b9e31de0c0c0",
- "lastblockhash" : "3c9b70cb4d3df2d3c3f78efe8ea133e88c229acb0434909b70265424ea0ffc50",
+ "genesisRLP" : "0xf901fcf901f7a0efb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8648454c98c8142a002f48916fece039bbb816bbc50f0a08ff9ffb5f7c91d66de884e1a0884969b0188e89cfda8dde9b93fc0c0",
+ "lastblockhash" : "77a8d519b4f678feecda052fa9cd6bac5c1d7313c66af8b434fdf2afe4c0db70",
"postState" : {
"8888f1f195afa192cfee860698584c030f4c9db1" : {
"balance" : "0x45639182451a25a0",
@@ -570,20 +716,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0x5208",
- "hash" : "3fd20fa702f48c4bd057083e98287a1334a132372cee46797c719b49788383d1",
- "mixHash" : "abbe70ebd0a3e21bbb974a81353e9ab7c1aeebec833fc8df6c0691659a1a61ca",
- "nonce" : "255b34be2e6ca2f8",
+ "hash" : "36d8fbfc8833d1fde1acd0117797d69bf3034c07280c7846f4a7c5f690c0d1bd",
+ "mixHash" : "04a94f9f31db791e1c1043f7c2b1a2898df6a80a54ab0878f42473b3c2af5cb9",
+ "nonce" : "bbbb6e598e5760eb",
"number" : "0x01",
- "parentHash" : "3b5df92257c6c44e65ec28717e78f50a0aaa7e01f1cafcb439fd1020a24dfbca",
+ "parentHash" : "859886d7bd1ee6db9677192606fca39f236ad52aa269fd2084f169cdc0184181",
"receiptTrie" : "443970a57a806576827076eb900c8c0727c18df44f4ced9fee3c74f2401617f6",
"stateRoot" : "3087516fb6d1378db34011edb02d4ba48be6b74e60e38163ff4f42097d87215b",
- "timestamp" : "0x55b7f285",
+ "timestamp" : "0x55d5f37f",
"transactionsTrie" : "ac17c4b8de7653cfabc0272d6e1803064949cdd66fd57a713ae1ffe24bfb5293",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90261f901f9a03b5df92257c6c44e65ec28717e78f50a0aaa7e01f1cafcb439fd1020a24dfbcaa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a03087516fb6d1378db34011edb02d4ba48be6b74e60e38163ff4f42097d87215ba0ac17c4b8de7653cfabc0272d6e1803064949cdd66fd57a713ae1ffe24bfb5293a0443970a57a806576827076eb900c8c0727c18df44f4ced9fee3c74f2401617f6b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd88252088455b7f28580a0abbe70ebd0a3e21bbb974a81353e9ab7c1aeebec833fc8df6c0691659a1a61ca88255b34be2e6ca2f8f862f860800183014c0894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca04d52b16e9e2813953622dc36e9fc90c1d12fa114a0f7eec136f8129eef11be4ca039aa3ab1e3a55f591c272f7e48f82d1570d27f64cfcd4abd581c05be11d646c0c0",
+ "rlp" : "0xf90261f901f9a0859886d7bd1ee6db9677192606fca39f236ad52aa269fd2084f169cdc0184181a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a03087516fb6d1378db34011edb02d4ba48be6b74e60e38163ff4f42097d87215ba0ac17c4b8de7653cfabc0272d6e1803064949cdd66fd57a713ae1ffe24bfb5293a0443970a57a806576827076eb900c8c0727c18df44f4ced9fee3c74f2401617f6b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de8252088455d5f37f80a004a94f9f31db791e1c1043f7c2b1a2898df6a80a54ab0878f42473b3c2af5cb988bbbb6e598e5760ebf862f860800183014c0894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca04d52b16e9e2813953622dc36e9fc90c1d12fa114a0f7eec136f8129eef11be4ca039aa3ab1e3a55f591c272f7e48f82d1570d27f64cfcd4abd581c05be11d646c0c0",
"transactions" : [
{
"data" : "0x",
@@ -608,9 +754,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "3b5df92257c6c44e65ec28717e78f50a0aaa7e01f1cafcb439fd1020a24dfbca",
- "mixHash" : "661dd4e25905645d3764cb8919a20028b95c936823f7d2f6857fd244f1c8df0f",
- "nonce" : "e2549b0340f4e9b1",
+ "hash" : "859886d7bd1ee6db9677192606fca39f236ad52aa269fd2084f169cdc0184181",
+ "mixHash" : "44883e5b7f534d928f2e629de72c8c81bb600b74d5ed8205b473a8c55597a540",
+ "nonce" : "475a338100c88919",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -619,8 +765,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0661dd4e25905645d3764cb8919a20028b95c936823f7d2f6857fd244f1c8df0f88e2549b0340f4e9b1c0c0",
- "lastblockhash" : "3fd20fa702f48c4bd057083e98287a1334a132372cee46797c719b49788383d1",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a044883e5b7f534d928f2e629de72c8c81bb600b74d5ed8205b473a8c55597a54088475a338100c88919c0c0",
+ "lastblockhash" : "36d8fbfc8833d1fde1acd0117797d69bf3034c07280c7846f4a7c5f690c0d1bd",
"postState" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x0a",
@@ -662,20 +808,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0x00",
- "hash" : "ff4052223054747805f51212eaa245d7e2d2c1102ceaf68085e67d97f12e7ee3",
- "mixHash" : "6d61bf247c58b5dbc32070eeae92e472e88b57f07bbfcd70d474be3acea3a10b",
- "nonce" : "4effe5f5d22168b2",
+ "hash" : "4518faee37d63fa607e3d185f998608455c1335ff24548396f951d739d84caf6",
+ "mixHash" : "3f8815db0719f146b997d1b87e75ad11c09db9557321074dd38b21d0def784ea",
+ "nonce" : "2357882b0f288034",
"number" : "0x01",
- "parentHash" : "55b8b40d89cec89769874ae436fdb4dba5a76160a1dd002fc17766bcf6a66916",
+ "parentHash" : "8a83ada0e0f4251ae1f4de435f56ed7723df9afd12bba44addff5e5ef41b8e41",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "8503769bb14067be7c5e438c353094e5a9a6c72f375fad4a76878a8882ceb496",
- "timestamp" : "0x55b7f287",
+ "timestamp" : "0x55d5f380",
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf901fcf901f7a055b8b40d89cec89769874ae436fdb4dba5a76160a1dd002fc17766bcf6a66916a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a08503769bb14067be7c5e438c353094e5a9a6c72f375fad4a76878a8882ceb496a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8808455b7f28780a06d61bf247c58b5dbc32070eeae92e472e88b57f07bbfcd70d474be3acea3a10b884effe5f5d22168b2c0c0",
+ "rlp" : "0xf901fcf901f7a08a83ada0e0f4251ae1f4de435f56ed7723df9afd12bba44addff5e5ef41b8e41a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a08503769bb14067be7c5e438c353094e5a9a6c72f375fad4a76878a8882ceb496a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de808455d5f38080a03f8815db0719f146b997d1b87e75ad11c09db9557321074dd38b21d0def784ea882357882b0f288034c0c0",
"transactions" : [
],
"uncleHeaders" : [
@@ -689,9 +835,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "55b8b40d89cec89769874ae436fdb4dba5a76160a1dd002fc17766bcf6a66916",
- "mixHash" : "7fb89eaf6dee42a4e9414aa660f84c738befb439f2b82b0f1bb1973086cc4b67",
- "nonce" : "b9e2a6a44f2d6132",
+ "hash" : "8a83ada0e0f4251ae1f4de435f56ed7723df9afd12bba44addff5e5ef41b8e41",
+ "mixHash" : "5b4b6d03199c1615a7262b7d7a30bdcd948b4f559c8273da457360a140023fcc",
+ "nonce" : "7f37019fd56f6bdb",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -700,8 +846,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a07fb89eaf6dee42a4e9414aa660f84c738befb439f2b82b0f1bb1973086cc4b6788b9e2a6a44f2d6132c0c0",
- "lastblockhash" : "ff4052223054747805f51212eaa245d7e2d2c1102ceaf68085e67d97f12e7ee3",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a05b4b6d03199c1615a7262b7d7a30bdcd948b4f559c8273da457360a140023fcc887f37019fd56f6bdbc0c0",
+ "lastblockhash" : "4518faee37d63fa607e3d185f998608455c1335ff24548396f951d739d84caf6",
"postState" : {
"8888f1f195afa192cfee860698584c030f4c9db1" : {
"balance" : "0x4563918244f40000",
@@ -736,20 +882,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0x014820",
- "hash" : "d83bf2449124bae9734e39cbeef25384762572485cedd6b4e49d9f9d62c3ab27",
- "mixHash" : "eddeaa4c7bd8fb0837d216aee7ee2bc13ec083ed49368611c8db4b22e5717938",
- "nonce" : "ec769ba593955274",
+ "hash" : "274d394e8c4917a6f69a0de847c4a0dea8a6497d4d8ecca7c585f57d903ad72a",
+ "mixHash" : "2e8f712996da2d6de99d6de00d650c1f64b2e1c62387956eba6e75c38a38d1cf",
+ "nonce" : "9b96a98327192017",
"number" : "0x01",
- "parentHash" : "0162a6c3efcdab1d020ee96966b6d2389647b765e854575c6fc51acc1d62a39f",
+ "parentHash" : "2a6269150eab64ecdc6ee16dd899acbf09c2f304c1ab658b4df62b83c234a550",
"receiptTrie" : "4cf33491338ba5c04157a50abc2ba539a9f84a982ff43af45b0b0382e9bbbad7",
"stateRoot" : "374444ef3d413eeeb69c71cfefba8380d463a8fbd233a32b7e0035afa5c400d1",
- "timestamp" : "0x55b7f289",
+ "timestamp" : "0x55d5f382",
"transactionsTrie" : "c52db987225c0bbeb1808b41fa870bc5f134073ed79c2d1a9c8b28545de80f49",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90385f901faa00162a6c3efcdab1d020ee96966b6d2389647b765e854575c6fc51acc1d62a39fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0374444ef3d413eeeb69c71cfefba8380d463a8fbd233a32b7e0035afa5c400d1a0c52db987225c0bbeb1808b41fa870bc5f134073ed79c2d1a9c8b28545de80f49a04cf33491338ba5c04157a50abc2ba539a9f84a982ff43af45b0b0382e9bbbad7b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8830148208455b7f28980a0eddeaa4c7bd8fb0837d216aee7ee2bc13ec083ed49368611c8db4b22e571793888ec769ba593955274f90184f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca0272bb540c27b214d5cb7deb7ee3a5b0045574474f59a494033efa146c67d0cd2a0272179cc62995b02183f47adcc6a11a66b7cc66c543f9bd4eea28c0368415f62f85f010182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca0cd5d6b8050014bc9d170d316d1d5ce8a321e964033c81a267db9abf46871798ba029109ebdc6c46e732e68f26acbc79c4b27ee90123edb2b2d9cc303533584a685f85f020182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca0d9e6314ad1ab598ed8948dcc9e68382e8ea532019c9d6363a30b827237d7c89ba058ab0d9c0d6054dbdb626ae4211aca67517f93ceeebdb71e5a8a06117bf52e3ef85f030182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca07b2200ec5136ce610f849f66d04175024134620b94ee509897025c25b1c1b0e7a076cc6272ea4917f4f3a875030a69b6ceef2e11ad21c9c2acaf4964f2344e665ac0",
+ "rlp" : "0xf90385f901faa02a6269150eab64ecdc6ee16dd899acbf09c2f304c1ab658b4df62b83c234a550a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0374444ef3d413eeeb69c71cfefba8380d463a8fbd233a32b7e0035afa5c400d1a0c52db987225c0bbeb1808b41fa870bc5f134073ed79c2d1a9c8b28545de80f49a04cf33491338ba5c04157a50abc2ba539a9f84a982ff43af45b0b0382e9bbbad7b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de830148208455d5f38280a02e8f712996da2d6de99d6de00d650c1f64b2e1c62387956eba6e75c38a38d1cf889b96a98327192017f90184f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca0272bb540c27b214d5cb7deb7ee3a5b0045574474f59a494033efa146c67d0cd2a0272179cc62995b02183f47adcc6a11a66b7cc66c543f9bd4eea28c0368415f62f85f010182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca0cd5d6b8050014bc9d170d316d1d5ce8a321e964033c81a267db9abf46871798ba029109ebdc6c46e732e68f26acbc79c4b27ee90123edb2b2d9cc303533584a685f85f020182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca0d9e6314ad1ab598ed8948dcc9e68382e8ea532019c9d6363a30b827237d7c89ba058ab0d9c0d6054dbdb626ae4211aca67517f93ceeebdb71e5a8a06117bf52e3ef85f030182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca07b2200ec5136ce610f849f66d04175024134620b94ee509897025c25b1c1b0e7a076cc6272ea4917f4f3a875030a69b6ceef2e11ad21c9c2acaf4964f2344e665ac0",
"transactions" : [
{
"data" : "0x",
@@ -807,9 +953,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "0162a6c3efcdab1d020ee96966b6d2389647b765e854575c6fc51acc1d62a39f",
- "mixHash" : "7b7a8a26a239e764118d70095fd7b09ea8fb472a3d5a9114c10dc0fccbe9a5fd",
- "nonce" : "01e806c57d7064b0",
+ "hash" : "2a6269150eab64ecdc6ee16dd899acbf09c2f304c1ab658b4df62b83c234a550",
+ "mixHash" : "bb09ae3a7189ef5816e52078d798f7fc20db94b79dab95a1c5ef9fbb6e049a6f",
+ "nonce" : "529ca9d230a6b676",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -818,8 +964,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a07b7a8a26a239e764118d70095fd7b09ea8fb472a3d5a9114c10dc0fccbe9a5fd8801e806c57d7064b0c0c0",
- "lastblockhash" : "d83bf2449124bae9734e39cbeef25384762572485cedd6b4e49d9f9d62c3ab27",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0bb09ae3a7189ef5816e52078d798f7fc20db94b79dab95a1c5ef9fbb6e049a6f88529ca9d230a6b676c0c0",
+ "lastblockhash" : "274d394e8c4917a6f69a0de847c4a0dea8a6497d4d8ecca7c585f57d903ad72a",
"postState" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x28",
@@ -861,20 +1007,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0x5208",
- "hash" : "a8b5b078d574e979676b1e08456bd062ac71cfd0c9a7c0730e46a37895f8f0f3",
- "mixHash" : "028f31c5f12a9b859fd49a3d0fde134f95c09a8b55e98654517e7c2c97cd9fac",
- "nonce" : "d1064ddf066b7fef",
+ "hash" : "adc8932eaf583e4b4b34d178d26996631eb75b051772584bf0d6b41600a7b847",
+ "mixHash" : "6c3e4bf7ae0cb93ee67b01ea59a3f20de0a57b3200fdb3e0e955a6324b0a7dde",
+ "nonce" : "8825a74a706f6238",
"number" : "0x01",
- "parentHash" : "3214af7096561dcdb66ed0658d523dc5d88fcad38d837e2a574d6f0f451e2401",
+ "parentHash" : "f7b70a12006718c3e4627bdfe3c919fd9eabbf76ff7479f32cf3ddb49c63e6ad",
"receiptTrie" : "61d9e5e4b662b22b0f085689e02d37aa14ec80fbdf37f867d9e90a6a7faeb8d3",
"stateRoot" : "c1ce557179e21d2943e2a22ceb238403d0f353f1abafc424286cfe27621adcca",
- "timestamp" : "0x55b7f28c",
+ "timestamp" : "0x55d5f384",
"transactionsTrie" : "0b02bd3fe4650efdbb64e9df234e189c6fb8ae493fecf5880a90ba3e322c63a4",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90261f901f9a03214af7096561dcdb66ed0658d523dc5d88fcad38d837e2a574d6f0f451e2401a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c1ce557179e21d2943e2a22ceb238403d0f353f1abafc424286cfe27621adccaa00b02bd3fe4650efdbb64e9df234e189c6fb8ae493fecf5880a90ba3e322c63a4a061d9e5e4b662b22b0f085689e02d37aa14ec80fbdf37f867d9e90a6a7faeb8d3b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd88252088455b7f28c80a0028f31c5f12a9b859fd49a3d0fde134f95c09a8b55e98654517e7c2c97cd9fac88d1064ddf066b7feff862f860808083014c0894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0ecde765b594ddb833b31bf9a628c37b339bf902ee753a33f9c1a97b4926af0e6a03066e5a2a101f72195110cbcf749e379afc6bc8232d7c3ea3d7b81ed5397a5b3c0",
+ "rlp" : "0xf90261f901f9a0f7b70a12006718c3e4627bdfe3c919fd9eabbf76ff7479f32cf3ddb49c63e6ada01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c1ce557179e21d2943e2a22ceb238403d0f353f1abafc424286cfe27621adccaa00b02bd3fe4650efdbb64e9df234e189c6fb8ae493fecf5880a90ba3e322c63a4a061d9e5e4b662b22b0f085689e02d37aa14ec80fbdf37f867d9e90a6a7faeb8d3b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de8252088455d5f38480a06c3e4bf7ae0cb93ee67b01ea59a3f20de0a57b3200fdb3e0e955a6324b0a7dde888825a74a706f6238f862f860808083014c0894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0ecde765b594ddb833b31bf9a628c37b339bf902ee753a33f9c1a97b4926af0e6a03066e5a2a101f72195110cbcf749e379afc6bc8232d7c3ea3d7b81ed5397a5b3c0",
"transactions" : [
{
"data" : "0x",
@@ -899,9 +1045,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "3214af7096561dcdb66ed0658d523dc5d88fcad38d837e2a574d6f0f451e2401",
- "mixHash" : "9ba11764c6f074b44ee8fd4461cfb580cc0fd51fea59e32bfe15bbf127ff2304",
- "nonce" : "690f0fd809cfd732",
+ "hash" : "f7b70a12006718c3e4627bdfe3c919fd9eabbf76ff7479f32cf3ddb49c63e6ad",
+ "mixHash" : "2bc2e574eea3a4fe7f92ec525312ab9b5c350bc0139e1d444d478c06347b29b5",
+ "nonce" : "7ce9a2d4a8a46868",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -910,8 +1056,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a09ba11764c6f074b44ee8fd4461cfb580cc0fd51fea59e32bfe15bbf127ff230488690f0fd809cfd732c0c0",
- "lastblockhash" : "a8b5b078d574e979676b1e08456bd062ac71cfd0c9a7c0730e46a37895f8f0f3",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a02bc2e574eea3a4fe7f92ec525312ab9b5c350bc0139e1d444d478c06347b29b5887ce9a2d4a8a46868c0c0",
+ "lastblockhash" : "adc8932eaf583e4b4b34d178d26996631eb75b051772584bf0d6b41600a7b847",
"postState" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x0a",
@@ -953,20 +1099,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0x560b",
- "hash" : "173d6a2fb94fc7b2710860907f2c6f0ec8d321a559c66fea1c8f85b7642877db",
- "mixHash" : "22324b542887e000ad8e42492e7d92c0b066d4c97c3e9bad41e98e858b4ca664",
- "nonce" : "96b8a08d3ccbe745",
+ "hash" : "9db645ca22e25dbe760ed94e4b979a24aaced81feddf8058f1447b6be2252a9c",
+ "mixHash" : "19077b96c944a3f30c8e3cdc38fd8b2e4ab2fdac14d71c03ea13a416d7ef32ca",
+ "nonce" : "6889326f8c6fb276",
"number" : "0x01",
- "parentHash" : "cef2d831b979a7c3a28438aed5a71f4b5cefae2c2eb8e8ee7d9912b64bb7ab74",
+ "parentHash" : "8e221317873233bc0e5ee34f33c1d376f0db5bc65ba5bd427c02e1ca0663ba25",
"receiptTrie" : "c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296",
"stateRoot" : "bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bf",
- "timestamp" : "0x55b7f28f",
+ "timestamp" : "0x55d5f386",
"transactionsTrie" : "498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90265f901f9a0cef2d831b979a7c3a28438aed5a71f4b5cefae2c2eb8e8ee7d9912b64bb7ab74a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b8455b7f28f80a022324b542887e000ad8e42492e7d92c0b066d4c97c3e9bad41e98e858b4ca6648896b8a08d3ccbe745f866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0",
+ "rlp" : "0xf90265f901f9a08e221317873233bc0e5ee34f33c1d376f0db5bc65ba5bd427c02e1ca0663ba25a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fe3de82560b8455d5f38680a019077b96c944a3f30c8e3cdc38fd8b2e4ab2fdac14d71c03ea13a416d7ef32ca886889326f8c6fb276f866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0",
"transactions" : [
{
"data" : "0x",
@@ -991,9 +1137,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "cef2d831b979a7c3a28438aed5a71f4b5cefae2c2eb8e8ee7d9912b64bb7ab74",
- "mixHash" : "c9897e804a25a198b1fb3c6350d5be02e45d8bbe2ce062bbb14d641490a08c0e",
- "nonce" : "d354735f6dc31f19",
+ "hash" : "8e221317873233bc0e5ee34f33c1d376f0db5bc65ba5bd427c02e1ca0663ba25",
+ "mixHash" : "512588f77e4b6b7deb3651e89214c54ae9d7b0b51650baad9cec23d162ce91c0",
+ "nonce" : "f89ef32e65f27ed8",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -1002,8 +1148,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0c9897e804a25a198b1fb3c6350d5be02e45d8bbe2ce062bbb14d641490a08c0e88d354735f6dc31f19c0c0",
- "lastblockhash" : "173d6a2fb94fc7b2710860907f2c6f0ec8d321a559c66fea1c8f85b7642877db",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0512588f77e4b6b7deb3651e89214c54ae9d7b0b51650baad9cec23d162ce91c088f89ef32e65f27ed8c0c0",
+ "lastblockhash" : "9db645ca22e25dbe760ed94e4b979a24aaced81feddf8058f1447b6be2252a9c",
"postState" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x012a05f264",
@@ -1044,6 +1190,480 @@
}
}
},
+ "timeDiff0" : {
+ "blocks" : [
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x038630",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fe3de",
+ "gasUsed" : "0x560b",
+ "hash" : "e016b3366903c44b33a0b79af1e286fc13b80fb54d2cbaf62c289be14e2bf958",
+ "mixHash" : "5f90930a01b1cc113338264120191d7deb9beaefc6b9c2de9dc604bc3be6dae7",
+ "nonce" : "85aaae2774202ad0",
+ "number" : "0x01",
+ "parentHash" : "5e135c4bdefcd8851f92a3a4670e8bf7662961b66876bbb65b572a31358d6d14",
+ "receiptTrie" : "5e7d8bf8bc817405813b0866e3bfa1ad048f982be5b81ab17b4db03266b24b26",
+ "stateRoot" : "201eacb02252d150f7f1a1dc2440f7fab2f468329953051836f81bae65e26914",
+ "timestamp" : "0x55d5f388",
+ "transactionsTrie" : "c590d5598e571c0acebad12175f241738803400f57cfb272e595999dbbfd08d7",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf90262f901f9a05e135c4bdefcd8851f92a3a4670e8bf7662961b66876bbb65b572a31358d6d14a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0201eacb02252d150f7f1a1dc2440f7fab2f468329953051836f81bae65e26914a0c590d5598e571c0acebad12175f241738803400f57cfb272e595999dbbfd08d7a05e7d8bf8bc817405813b0866e3bfa1ad048f982be5b81ab17b4db03266b24b26b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008303863001832fe3de82560b8455d5f38880a05f90930a01b1cc113338264120191d7deb9beaefc6b9c2de9dc604bc3be6dae78885aaae2774202ad0f863f861800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d87821388801ba0149dedccf5d524176aa17525074acf56f17cd7b472a9860c9d3ec4d87a6d0393a03cf6326d11c57d8b558c21c63fc848f8d0b76582060044e8e48d9d0d29054a36c0",
+ "transactions" : [
+ {
+ "data" : "0x",
+ "gasLimit" : "0xc350",
+ "gasPrice" : "0x0a",
+ "nonce" : "0x00",
+ "r" : "0x149dedccf5d524176aa17525074acf56f17cd7b472a9860c9d3ec4d87a6d0393",
+ "s" : "0x3cf6326d11c57d8b558c21c63fc848f8d0b76582060044e8e48d9d0d29054a36",
+ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
+ "v" : "0x1b",
+ "value" : "0x1388"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ },
+ {
+ "rlp" : "0xf901fcf901f7a0e016b3366903c44b33a0b79af1e286fc13b80fb54d2cbaf62c289be14e2bf958a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0b18395884d55f5dc870bc46e565a5dbdc5659325f66cc457b38bcecb01662f78a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830386a002832fd800808455d5f38880a08f4407a10797e7dffabcf54459eb6f63ba0d6925ba7b6e999848d334123b09fe88436e39fd86607230c0c0"
+ }
+ ],
+ "genesisBlockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x0386a0",
+ "extraData" : "0x42",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x00",
+ "hash" : "5e135c4bdefcd8851f92a3a4670e8bf7662961b66876bbb65b572a31358d6d14",
+ "mixHash" : "cd34e2cf76dab4ec5e90d8aee1c23968edf59d1264c238769b457959768b2792",
+ "nonce" : "0f7a20795f299b7b",
+ "number" : "0x00",
+ "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "b7829295a16db7cae65a071afbb272390f893dc1b0d3f098504148a7056f8056",
+ "timestamp" : "0x54c98c81",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0b7829295a16db7cae65a071afbb272390f893dc1b0d3f098504148a7056f8056a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830386a080832fefd8808454c98c8142a0cd34e2cf76dab4ec5e90d8aee1c23968edf59d1264c238769b457959768b2792880f7a20795f299b7bc0c0",
+ "lastblockhash" : "e016b3366903c44b33a0b79af1e286fc13b80fb54d2cbaf62c289be14e2bf958",
+ "postState" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x13ec",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "8888f1f195afa192cfee860698584c030f4c9db1" : {
+ "balance" : "0x4563918244f75c6e",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x174873780a",
+ "code" : "0x",
+ "nonce" : "0x01",
+ "storage" : {
+ }
+ }
+ },
+ "pre" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x64",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x174876e800",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ },
+ "timeDiff12" : {
+ "blocks" : [
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x038630",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fe3de",
+ "gasUsed" : "0x560b",
+ "hash" : "022df90fbe4b089dfa6b0a879b9787b262ede8171a1170878e0f694e5e13977d",
+ "mixHash" : "8226205217edade35ca29967d4dd7a7aa5d9d2453d2e608d023cd8f5a1fb7298",
+ "nonce" : "27b3c785ac56dee5",
+ "number" : "0x01",
+ "parentHash" : "29b2b142238c3820d4ede0193cf4bf11c7a242c38074e1820d410f54f219cc50",
+ "receiptTrie" : "5e7d8bf8bc817405813b0866e3bfa1ad048f982be5b81ab17b4db03266b24b26",
+ "stateRoot" : "201eacb02252d150f7f1a1dc2440f7fab2f468329953051836f81bae65e26914",
+ "timestamp" : "0x55d5f38c",
+ "transactionsTrie" : "c590d5598e571c0acebad12175f241738803400f57cfb272e595999dbbfd08d7",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf90262f901f9a029b2b142238c3820d4ede0193cf4bf11c7a242c38074e1820d410f54f219cc50a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0201eacb02252d150f7f1a1dc2440f7fab2f468329953051836f81bae65e26914a0c590d5598e571c0acebad12175f241738803400f57cfb272e595999dbbfd08d7a05e7d8bf8bc817405813b0866e3bfa1ad048f982be5b81ab17b4db03266b24b26b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008303863001832fe3de82560b8455d5f38c80a08226205217edade35ca29967d4dd7a7aa5d9d2453d2e608d023cd8f5a1fb72988827b3c785ac56dee5f863f861800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d87821388801ba0149dedccf5d524176aa17525074acf56f17cd7b472a9860c9d3ec4d87a6d0393a03cf6326d11c57d8b558c21c63fc848f8d0b76582060044e8e48d9d0d29054a36c0",
+ "transactions" : [
+ {
+ "data" : "0x",
+ "gasLimit" : "0xc350",
+ "gasPrice" : "0x0a",
+ "nonce" : "0x00",
+ "r" : "0x149dedccf5d524176aa17525074acf56f17cd7b472a9860c9d3ec4d87a6d0393",
+ "s" : "0x3cf6326d11c57d8b558c21c63fc848f8d0b76582060044e8e48d9d0d29054a36",
+ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
+ "v" : "0x1b",
+ "value" : "0x1388"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ },
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x0386a0",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fd800",
+ "gasUsed" : "0x00",
+ "hash" : "5765fc0b211f0686440ad73a8a7b40c2d1bbba1a380755c2fc02ba2fd0ed3920",
+ "mixHash" : "3d33c0eb4de9bd8df7f581bef8f2a8e184bac0f7b49f7b8bf567b0599edfdeef",
+ "nonce" : "d08ba7d2e8860f81",
+ "number" : "0x02",
+ "parentHash" : "022df90fbe4b089dfa6b0a879b9787b262ede8171a1170878e0f694e5e13977d",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "b18395884d55f5dc870bc46e565a5dbdc5659325f66cc457b38bcecb01662f78",
+ "timestamp" : "0x55d5f398",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf901fcf901f7a0022df90fbe4b089dfa6b0a879b9787b262ede8171a1170878e0f694e5e13977da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0b18395884d55f5dc870bc46e565a5dbdc5659325f66cc457b38bcecb01662f78a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830386a002832fd800808455d5f39880a03d33c0eb4de9bd8df7f581bef8f2a8e184bac0f7b49f7b8bf567b0599edfdeef88d08ba7d2e8860f81c0c0",
+ "transactions" : [
+ ],
+ "uncleHeaders" : [
+ ]
+ }
+ ],
+ "genesisBlockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x0386a0",
+ "extraData" : "0x42",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x00",
+ "hash" : "29b2b142238c3820d4ede0193cf4bf11c7a242c38074e1820d410f54f219cc50",
+ "mixHash" : "c3fa7245f0b834661ee019eb3d5c93b1b0feefed21ac808b714e846c4b0f0eb2",
+ "nonce" : "8de870f337f9fdee",
+ "number" : "0x00",
+ "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "b7829295a16db7cae65a071afbb272390f893dc1b0d3f098504148a7056f8056",
+ "timestamp" : "0x54c98c81",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0b7829295a16db7cae65a071afbb272390f893dc1b0d3f098504148a7056f8056a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830386a080832fefd8808454c98c8142a0c3fa7245f0b834661ee019eb3d5c93b1b0feefed21ac808b714e846c4b0f0eb2888de870f337f9fdeec0c0",
+ "lastblockhash" : "5765fc0b211f0686440ad73a8a7b40c2d1bbba1a380755c2fc02ba2fd0ed3920",
+ "postState" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x13ec",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "8888f1f195afa192cfee860698584c030f4c9db1" : {
+ "balance" : "0x8ac7230489eb5c6e",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x174873780a",
+ "code" : "0x",
+ "nonce" : "0x01",
+ "storage" : {
+ }
+ }
+ },
+ "pre" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x64",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x174876e800",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ },
+ "timeDiff13" : {
+ "blocks" : [
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x038630",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fe3de",
+ "gasUsed" : "0x560b",
+ "hash" : "32e292b358e8af8d64ff76b578c54498b589c0796110fce0208ea7b9bac8c823",
+ "mixHash" : "662a7e387a457a9ea534c61809c9b2179a939aeb7b2f43ee99cb79e3acd0a892",
+ "nonce" : "4b4187434fff8ace",
+ "number" : "0x01",
+ "parentHash" : "32a200899b03f628f35544e00bf4df519224e7a2b0bdf4ec17cf49e79d6aba23",
+ "receiptTrie" : "5e7d8bf8bc817405813b0866e3bfa1ad048f982be5b81ab17b4db03266b24b26",
+ "stateRoot" : "201eacb02252d150f7f1a1dc2440f7fab2f468329953051836f81bae65e26914",
+ "timestamp" : "0x55d5f3a4",
+ "transactionsTrie" : "c590d5598e571c0acebad12175f241738803400f57cfb272e595999dbbfd08d7",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf90262f901f9a032a200899b03f628f35544e00bf4df519224e7a2b0bdf4ec17cf49e79d6aba23a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0201eacb02252d150f7f1a1dc2440f7fab2f468329953051836f81bae65e26914a0c590d5598e571c0acebad12175f241738803400f57cfb272e595999dbbfd08d7a05e7d8bf8bc817405813b0866e3bfa1ad048f982be5b81ab17b4db03266b24b26b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008303863001832fe3de82560b8455d5f3a480a0662a7e387a457a9ea534c61809c9b2179a939aeb7b2f43ee99cb79e3acd0a892884b4187434fff8acef863f861800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d87821388801ba0149dedccf5d524176aa17525074acf56f17cd7b472a9860c9d3ec4d87a6d0393a03cf6326d11c57d8b558c21c63fc848f8d0b76582060044e8e48d9d0d29054a36c0",
+ "transactions" : [
+ {
+ "data" : "0x",
+ "gasLimit" : "0xc350",
+ "gasPrice" : "0x0a",
+ "nonce" : "0x00",
+ "r" : "0x149dedccf5d524176aa17525074acf56f17cd7b472a9860c9d3ec4d87a6d0393",
+ "s" : "0x3cf6326d11c57d8b558c21c63fc848f8d0b76582060044e8e48d9d0d29054a36",
+ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
+ "v" : "0x1b",
+ "value" : "0x1388"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ },
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x0385c0",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fd800",
+ "gasUsed" : "0x00",
+ "hash" : "ce62a266c155dbb5a54d1751eff2157eb4aaf30cec6ba4fada794064be5f3c4c",
+ "mixHash" : "47fdbc9960f9e8ac28228008b70eae19c80df8f091df7a2f99f423c458f7cd2a",
+ "nonce" : "1d8e8adcf90009c6",
+ "number" : "0x02",
+ "parentHash" : "32e292b358e8af8d64ff76b578c54498b589c0796110fce0208ea7b9bac8c823",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "b18395884d55f5dc870bc46e565a5dbdc5659325f66cc457b38bcecb01662f78",
+ "timestamp" : "0x55d5f3b1",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf901fcf901f7a032e292b358e8af8d64ff76b578c54498b589c0796110fce0208ea7b9bac8c823a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0b18395884d55f5dc870bc46e565a5dbdc5659325f66cc457b38bcecb01662f78a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830385c002832fd800808455d5f3b180a047fdbc9960f9e8ac28228008b70eae19c80df8f091df7a2f99f423c458f7cd2a881d8e8adcf90009c6c0c0",
+ "transactions" : [
+ ],
+ "uncleHeaders" : [
+ ]
+ }
+ ],
+ "genesisBlockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x0386a0",
+ "extraData" : "0x42",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x00",
+ "hash" : "32a200899b03f628f35544e00bf4df519224e7a2b0bdf4ec17cf49e79d6aba23",
+ "mixHash" : "888f553018e58e19b120c7a23bd9257ce0a5e47674dde39ff5cdc879f1cd89bd",
+ "nonce" : "f5b845e1ecbbcc28",
+ "number" : "0x00",
+ "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "b7829295a16db7cae65a071afbb272390f893dc1b0d3f098504148a7056f8056",
+ "timestamp" : "0x54c98c81",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0b7829295a16db7cae65a071afbb272390f893dc1b0d3f098504148a7056f8056a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830386a080832fefd8808454c98c8142a0888f553018e58e19b120c7a23bd9257ce0a5e47674dde39ff5cdc879f1cd89bd88f5b845e1ecbbcc28c0c0",
+ "lastblockhash" : "ce62a266c155dbb5a54d1751eff2157eb4aaf30cec6ba4fada794064be5f3c4c",
+ "postState" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x13ec",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "8888f1f195afa192cfee860698584c030f4c9db1" : {
+ "balance" : "0x8ac7230489eb5c6e",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x174873780a",
+ "code" : "0x",
+ "nonce" : "0x01",
+ "storage" : {
+ }
+ }
+ },
+ "pre" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x64",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x174876e800",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ },
+ "timeDiff14" : {
+ "blocks" : [
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x038630",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fe3de",
+ "gasUsed" : "0x560b",
+ "hash" : "844baa5fea0b9e184029509c7f0ecdcc88cdd4afa2eb16f47c6e17693228a8d4",
+ "mixHash" : "0132a62f6f12967c7dd21b6293422880c6972a2e4949265d4ad1b7d8cf242990",
+ "nonce" : "7e0dac58cdfdcb85",
+ "number" : "0x01",
+ "parentHash" : "6aab9fc348a1137614fd7493bffd8069faf8623440bf2669f3b3e1b6739d122b",
+ "receiptTrie" : "5e7d8bf8bc817405813b0866e3bfa1ad048f982be5b81ab17b4db03266b24b26",
+ "stateRoot" : "201eacb02252d150f7f1a1dc2440f7fab2f468329953051836f81bae65e26914",
+ "timestamp" : "0x55d5f3b6",
+ "transactionsTrie" : "c590d5598e571c0acebad12175f241738803400f57cfb272e595999dbbfd08d7",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf90262f901f9a06aab9fc348a1137614fd7493bffd8069faf8623440bf2669f3b3e1b6739d122ba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0201eacb02252d150f7f1a1dc2440f7fab2f468329953051836f81bae65e26914a0c590d5598e571c0acebad12175f241738803400f57cfb272e595999dbbfd08d7a05e7d8bf8bc817405813b0866e3bfa1ad048f982be5b81ab17b4db03266b24b26b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008303863001832fe3de82560b8455d5f3b680a00132a62f6f12967c7dd21b6293422880c6972a2e4949265d4ad1b7d8cf242990887e0dac58cdfdcb85f863f861800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d87821388801ba0149dedccf5d524176aa17525074acf56f17cd7b472a9860c9d3ec4d87a6d0393a03cf6326d11c57d8b558c21c63fc848f8d0b76582060044e8e48d9d0d29054a36c0",
+ "transactions" : [
+ {
+ "data" : "0x",
+ "gasLimit" : "0xc350",
+ "gasPrice" : "0x0a",
+ "nonce" : "0x00",
+ "r" : "0x149dedccf5d524176aa17525074acf56f17cd7b472a9860c9d3ec4d87a6d0393",
+ "s" : "0x3cf6326d11c57d8b558c21c63fc848f8d0b76582060044e8e48d9d0d29054a36",
+ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
+ "v" : "0x1b",
+ "value" : "0x1388"
+ }
+ ],
+ "uncleHeaders" : [
+ ]
+ },
+ {
+ "blockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x0385c0",
+ "extraData" : "0x",
+ "gasLimit" : "0x2fd800",
+ "gasUsed" : "0x00",
+ "hash" : "8a2f8db544b6d65d1ca99a61a9afea0f7ff97f253ef293adb764fd893298b986",
+ "mixHash" : "7905c4293448b50ee78be5e43e3cf31950d8743e82c1733b7d0a038f4f8121d5",
+ "nonce" : "1906d96c17fa4d0b",
+ "number" : "0x02",
+ "parentHash" : "844baa5fea0b9e184029509c7f0ecdcc88cdd4afa2eb16f47c6e17693228a8d4",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "b18395884d55f5dc870bc46e565a5dbdc5659325f66cc457b38bcecb01662f78",
+ "timestamp" : "0x55d5f3c4",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "rlp" : "0xf901fcf901f7a0844baa5fea0b9e184029509c7f0ecdcc88cdd4afa2eb16f47c6e17693228a8d4a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0b18395884d55f5dc870bc46e565a5dbdc5659325f66cc457b38bcecb01662f78a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830385c002832fd800808455d5f3c480a07905c4293448b50ee78be5e43e3cf31950d8743e82c1733b7d0a038f4f8121d5881906d96c17fa4d0bc0c0",
+ "transactions" : [
+ ],
+ "uncleHeaders" : [
+ ]
+ }
+ ],
+ "genesisBlockHeader" : {
+ "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
+ "difficulty" : "0x0386a0",
+ "extraData" : "0x42",
+ "gasLimit" : "0x2fefd8",
+ "gasUsed" : "0x00",
+ "hash" : "6aab9fc348a1137614fd7493bffd8069faf8623440bf2669f3b3e1b6739d122b",
+ "mixHash" : "7df1f98666a1a1530a41bdc26363e97d6654bb20824c17bc9f0e53163ca6d655",
+ "nonce" : "94892f238c65f5dd",
+ "number" : "0x00",
+ "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "stateRoot" : "b7829295a16db7cae65a071afbb272390f893dc1b0d3f098504148a7056f8056",
+ "timestamp" : "0x54c98c81",
+ "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
+ },
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0b7829295a16db7cae65a071afbb272390f893dc1b0d3f098504148a7056f8056a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830386a080832fefd8808454c98c8142a07df1f98666a1a1530a41bdc26363e97d6654bb20824c17bc9f0e53163ca6d6558894892f238c65f5ddc0c0",
+ "lastblockhash" : "8a2f8db544b6d65d1ca99a61a9afea0f7ff97f253ef293adb764fd893298b986",
+ "postState" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x13ec",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "8888f1f195afa192cfee860698584c030f4c9db1" : {
+ "balance" : "0x8ac7230489eb5c6e",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x174873780a",
+ "code" : "0x",
+ "nonce" : "0x01",
+ "storage" : {
+ }
+ }
+ },
+ "pre" : {
+ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
+ "balance" : "0x64",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x174876e800",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ },
"txEqualValue" : {
"blocks" : [
{
@@ -1052,20 +1672,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0x5208",
- "hash" : "0d1095c688a64015ceda25220045e676c959383aa5e26b4a96b294291c3c09fa",
- "mixHash" : "278ab67208b96a18d072e19ff9b1ee7e94a02633a9fd4ade2ba9db3d66d3df54",
- "nonce" : "b5f17c43df51ed1d",
+ "hash" : "ed9d2f59e63cdd914799f58ba90cfd88e74fb6cfce9f0471e65ab387edca0186",
+ "mixHash" : "7f2b44632d02c094801cc87f5a4c3b046df84b2560490e387d73e0d03c1cee02",
+ "nonce" : "c91331bc23d7928d",
"number" : "0x01",
- "parentHash" : "a1be177a6a2793204e15c15d4824097984977ed938cf1f067e165059e348c0a7",
+ "parentHash" : "aa26c99940f2c9da1900dd7c8fc3734691572d7f9f323644d8666217bde3cd42",
"receiptTrie" : "e13e6a83dd076e2589464165628f05caf91a7c54975779549344656b17a89962",
"stateRoot" : "ae2d2b287506883322f1c2dae3015b4f2a393332eb0f0aacf11750175ee1ef53",
- "timestamp" : "0x55b7f291",
+ "timestamp" : "0x55d5f3cf",
"transactionsTrie" : "498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90265f901f9a0a1be177a6a2793204e15c15d4824097984977ed938cf1f067e165059e348c0a7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ae2d2b287506883322f1c2dae3015b4f2a393332eb0f0aacf11750175ee1ef53a0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0e13e6a83dd076e2589464165628f05caf91a7c54975779549344656b17a89962b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd88252088455b7f29180a0278ab67208b96a18d072e19ff9b1ee7e94a02633a9fd4ade2ba9db3d66d3df5488b5f17c43df51ed1df866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0",
+ "rlp" : "0xf90265f901f9a0aa26c99940f2c9da1900dd7c8fc3734691572d7f9f323644d8666217bde3cd42a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ae2d2b287506883322f1c2dae3015b4f2a393332eb0f0aacf11750175ee1ef53a0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0e13e6a83dd076e2589464165628f05caf91a7c54975779549344656b17a89962b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de8252088455d5f3cf80a07f2b44632d02c094801cc87f5a4c3b046df84b2560490e387d73e0d03c1cee0288c91331bc23d7928df866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0",
"transactions" : [
{
"data" : "0x",
@@ -1090,9 +1710,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "a1be177a6a2793204e15c15d4824097984977ed938cf1f067e165059e348c0a7",
- "mixHash" : "398a711c44ddec4affa9fe0f6d5a8b661c0e476d4286b0b457d1fa5f949d56d6",
- "nonce" : "854dce3725faf400",
+ "hash" : "aa26c99940f2c9da1900dd7c8fc3734691572d7f9f323644d8666217bde3cd42",
+ "mixHash" : "e7fc98b9e9f997750f11975832e15a84aca2f6c01f81e96e0a3bc1535b17aac6",
+ "nonce" : "5cbb7f6f582ab25c",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -1101,8 +1721,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0398a711c44ddec4affa9fe0f6d5a8b661c0e476d4286b0b457d1fa5f949d56d688854dce3725faf400c0c0",
- "lastblockhash" : "0d1095c688a64015ceda25220045e676c959383aa5e26b4a96b294291c3c09fa",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0e7fc98b9e9f997750f11975832e15a84aca2f6c01f81e96e0a3bc1535b17aac6885cbb7f6f582ab25cc0c0",
+ "lastblockhash" : "ed9d2f59e63cdd914799f58ba90cfd88e74fb6cfce9f0471e65ab387edca0186",
"postState" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x012a05f200",
@@ -1144,20 +1764,20 @@
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x",
- "gasLimit" : "0x2fefd8",
+ "gasLimit" : "0x2fe3de",
"gasUsed" : "0x5208",
- "hash" : "feb5732416765067a7c68878fc57ffbb12277f5ad51afb8cd8da7758bce9d1c4",
- "mixHash" : "dd069a437769855ba9337ae52b802a4ce92f7e54864ae597ec98000175357482",
- "nonce" : "d5854365d85492e6",
+ "hash" : "094eb118175f79f80fdbc3140d379e0c0b04bef7cd285ea61a1184a8201f5a1f",
+ "mixHash" : "c3af16a9ee71f47e48ed294aab34d26141e9b3badbf537f42afba78e73e485fd",
+ "nonce" : "2d1073468aa45fcc",
"number" : "0x01",
- "parentHash" : "28ec23fed489293ad9db90e7745921dcd8cbf31f72ddb2cd3164e120d5c81797",
+ "parentHash" : "4460b49f668be62df7cfb79e680a532688a1ea2b84f31e7c5cfca612871efef8",
"receiptTrie" : "67bf4b6c7db8be32886532357198d3a32f204c9001b0980747ab8fa9e937e1a2",
"stateRoot" : "f0f9da9e88dbc17e483569ef49113473ac1d0fef5f63a3b2564b2c1ee8898ab0",
- "timestamp" : "0x55b7f294",
+ "timestamp" : "0x55d5f3d7",
"transactionsTrie" : "2e4a44bb8e3ee134ec210f7f92c1138ad2e3c29f19a821fd17f262254cd15840",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "rlp" : "0xf90265f901f9a028ec23fed489293ad9db90e7745921dcd8cbf31f72ddb2cd3164e120d5c81797a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0f0f9da9e88dbc17e483569ef49113473ac1d0fef5f63a3b2564b2c1ee8898ab0a02e4a44bb8e3ee134ec210f7f92c1138ad2e3c29f19a821fd17f262254cd15840a067bf4b6c7db8be32886532357198d3a32f204c9001b0980747ab8fa9e937e1a2b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd88252088455b7f29480a0dd069a437769855ba9337ae52b802a4ce92f7e54864ae597ec9800017535748288d5854365d85492e6f866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d878501dcd65000801ba0ebb726ae53468a164a482cd9e3a5a23607185985c93b922e3be620b04b30e9bda0047360f7f081043ccb735c9fa5c20fc4ecba55ceca57bf96f4d7686371af0dc9c0",
+ "rlp" : "0xf90265f901f9a04460b49f668be62df7cfb79e680a532688a1ea2b84f31e7c5cfca612871efef8a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0f0f9da9e88dbc17e483569ef49113473ac1d0fef5f63a3b2564b2c1ee8898ab0a02e4a44bb8e3ee134ec210f7f92c1138ad2e3c29f19a821fd17f262254cd15840a067bf4b6c7db8be32886532357198d3a32f204c9001b0980747ab8fa9e937e1a2b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fe3de8252088455d5f3d780a0c3af16a9ee71f47e48ed294aab34d26141e9b3badbf537f42afba78e73e485fd882d1073468aa45fccf866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d878501dcd65000801ba0ebb726ae53468a164a482cd9e3a5a23607185985c93b922e3be620b04b30e9bda0047360f7f081043ccb735c9fa5c20fc4ecba55ceca57bf96f4d7686371af0dc9c0",
"transactions" : [
{
"data" : "0x",
@@ -1182,9 +1802,9 @@
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"gasUsed" : "0x00",
- "hash" : "28ec23fed489293ad9db90e7745921dcd8cbf31f72ddb2cd3164e120d5c81797",
- "mixHash" : "6c5322280e970809d6bf1811b49359fccf694286ea3be7c8f676666d6771c730",
- "nonce" : "95c7f750a8e77586",
+ "hash" : "4460b49f668be62df7cfb79e680a532688a1ea2b84f31e7c5cfca612871efef8",
+ "mixHash" : "29fc027153197af656eba7187179b7e5e45d6235fe1b26f2e692e084a5c9596d",
+ "nonce" : "f0b89f070195f820",
"number" : "0x00",
"parentHash" : "0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
@@ -1193,8 +1813,8 @@
"transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
- "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a06c5322280e970809d6bf1811b49359fccf694286ea3be7c8f676666d6771c7308895c7f750a8e77586c0c0",
- "lastblockhash" : "feb5732416765067a7c68878fc57ffbb12277f5ad51afb8cd8da7758bce9d1c4",
+ "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a029fc027153197af656eba7187179b7e5e45d6235fe1b26f2e692e084a5c9596d88f0b89f070195f820c0c0",
+ "lastblockhash" : "094eb118175f79f80fdbc3140d379e0c0b04bef7cd285ea61a1184a8201f5a1f",
"postState" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x01dcd65000",
diff --git a/tests/state_test.go b/tests/state_test.go
index a0c98faae8..b450f5e742 100644
--- a/tests/state_test.go
+++ b/tests/state_test.go
@@ -20,8 +20,24 @@ import (
"os"
"path/filepath"
"testing"
+
+ "github.com/expanse-project/go-expanse/core/vm"
)
+func init() {
+ if os.Getenv("JITVM") == "true" {
+ vm.ForceJit = true
+ vm.EnableJit = true
+ }
+}
+
+func BenchmarkStateCall1024(b *testing.B) {
+ fn := filepath.Join(stateTestDir, "stCallCreateCallCodeTest.json")
+ if err := BenchVmTest(fn, bconf{"Call1024BalanceTooLow", true, os.Getenv("JITVM") == "true"}, b); err != nil {
+ b.Error(err)
+ }
+}
+
func TestStateSystemOperations(t *testing.T) {
fn := filepath.Join(stateTestDir, "stSystemOperationsTest.json")
if err := RunStateTest(fn, StateSkipTests); err != nil {
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index 189b61f061..26cd54181f 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -23,6 +23,7 @@ import (
"io"
"math/big"
"strconv"
+ "testing"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/core"
@@ -60,6 +61,61 @@ func RunStateTest(p string, skipTests []string) error {
}
+func BenchStateTest(p string, conf bconf, b *testing.B) error {
+ tests := make(map[string]VmTest)
+ if err := readJsonFile(p, &tests); err != nil {
+ return err
+ }
+ test, ok := tests[conf.name]
+ if !ok {
+ return fmt.Errorf("test not found: %s", conf.name)
+ }
+
+ pJit := vm.EnableJit
+ vm.EnableJit = conf.jit
+ pForceJit := vm.ForceJit
+ vm.ForceJit = conf.precomp
+
+ // XXX Yeah, yeah...
+ env := make(map[string]string)
+ env["currentCoinbase"] = test.Env.CurrentCoinbase
+ env["currentDifficulty"] = test.Env.CurrentDifficulty
+ env["currentGasLimit"] = test.Env.CurrentGasLimit
+ env["currentNumber"] = test.Env.CurrentNumber
+ env["previousHash"] = test.Env.PreviousHash
+ if n, ok := test.Env.CurrentTimestamp.(float64); ok {
+ env["currentTimestamp"] = strconv.Itoa(int(n))
+ } else {
+ env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ benchStateTest(test, env, b)
+ }
+
+ vm.EnableJit = pJit
+ vm.ForceJit = pForceJit
+
+ return nil
+}
+
+func benchStateTest(test VmTest, env map[string]string, b *testing.B) {
+ b.StopTimer()
+ db, _ := ethdb.NewMemDatabase()
+ statedb := state.New(common.Hash{}, db)
+ for addr, account := range test.Pre {
+ obj := StateObjectFromAccount(db, addr, account)
+ statedb.SetStateObject(obj)
+ for a, v := range account.Storage {
+ obj.SetState(common.HexToHash(a), common.HexToHash(v))
+ }
+ }
+ b.StartTimer()
+
+ RunState(statedb, env, test.Exec)
+}
+
func runStateTests(tests map[string]VmTest, skipTests []string) error {
skipTest := make(map[string]bool, len(skipTests))
for _, name := range skipTests {
diff --git a/tests/util.go b/tests/util.go
index caf3ed3947..bec06add2b 100644
--- a/tests/util.go
+++ b/tests/util.go
@@ -18,7 +18,6 @@ package tests
import (
"bytes"
- "errors"
"fmt"
"math/big"
@@ -136,7 +135,7 @@ type Env struct {
coinbase common.Address
number *big.Int
- time uint64
+ time *big.Int
difficulty *big.Int
gasLimit *big.Int
@@ -166,7 +165,7 @@ func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues
//env.parent = common.Hex2Bytes(envValues["previousHash"])
env.coinbase = common.HexToAddress(envValues["currentCoinbase"])
env.number = common.Big(envValues["currentNumber"])
- env.time = common.Big(envValues["currentTimestamp"]).Uint64()
+ env.time = common.Big(envValues["currentTimestamp"])
env.difficulty = common.Big(envValues["currentDifficulty"])
env.gasLimit = common.Big(envValues["currentGasLimit"])
env.Gas = new(big.Int)
@@ -179,7 +178,7 @@ func (self *Env) BlockNumber() *big.Int { return self.number }
//func (self *Env) PrevHash() []byte { return self.parent }
func (self *Env) Coinbase() common.Address { return self.coinbase }
-func (self *Env) Time() uint64 { return self.time }
+func (self *Env) Time() *big.Int { return self.time }
func (self *Env) Difficulty() *big.Int { return self.difficulty }
func (self *Env) State() *state.StateDB { return self.state }
func (self *Env) GasLimit() *big.Int { return self.gasLimit }
@@ -192,18 +191,19 @@ func (self *Env) AddLog(log *state.Log) {
}
func (self *Env) Depth() int { return self.depth }
func (self *Env) SetDepth(i int) { self.depth = i }
-func (self *Env) Transfer(from, to vm.Account, amount *big.Int) error {
+func (self *Env) CanTransfer(from vm.Account, balance *big.Int) bool {
if self.skipTransfer {
- // ugly hack
if self.initial {
self.initial = false
- return nil
+ return true
}
+ }
- if from.Balance().Cmp(amount) < 0 {
- return errors.New("Insufficient balance in account")
- }
+ return from.Balance().Cmp(balance) >= 0
+}
+func (self *Env) Transfer(from, to vm.Account, amount *big.Int) error {
+ if self.skipTransfer {
return nil
}
return vm.Transfer(from, to, amount)
diff --git a/tests/vm_test.go b/tests/vm_test.go
index ec7089a590..035f205589 100644
--- a/tests/vm_test.go
+++ b/tests/vm_test.go
@@ -17,10 +17,25 @@
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, 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, os.Getenv("JITVM") == "true"}, b); err != nil {
+ b.Error(err)
+ }
+}
+
// I've created a new function for each tests so it's easier to identify where the problem lies if any of them fail.
func TestVMArithmetic(t *testing.T) {
fn := filepath.Join(vmTestDir, "vmArithmeticTest.json")
diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go
index b4581c63d8..799206f456 100644
--- a/tests/vm_test_util.go
+++ b/tests/vm_test_util.go
@@ -22,6 +22,7 @@ import (
"io"
"math/big"
"strconv"
+ "testing"
"github.com/expanse-project/go-expanse/common"
"github.com/expanse-project/go-expanse/core/state"
@@ -48,8 +49,79 @@ func RunVmTestWithReader(r io.Reader, skipTests []string) error {
return nil
}
-func RunVmTest(p string, skipTests []string) error {
+type bconf struct {
+ name string
+ precomp bool
+ jit bool
+}
+func BenchVmTest(p string, conf bconf, b *testing.B) error {
+ tests := make(map[string]VmTest)
+ err := readJsonFile(p, &tests)
+ if err != nil {
+ return err
+ }
+
+ test, ok := tests[conf.name]
+ if !ok {
+ return fmt.Errorf("test not found: %s", conf.name)
+ }
+
+ pJit := vm.EnableJit
+ vm.EnableJit = conf.jit
+ pForceJit := vm.ForceJit
+ vm.ForceJit = conf.precomp
+
+ env := make(map[string]string)
+ env["currentCoinbase"] = test.Env.CurrentCoinbase
+ env["currentDifficulty"] = test.Env.CurrentDifficulty
+ env["currentGasLimit"] = test.Env.CurrentGasLimit
+ env["currentNumber"] = test.Env.CurrentNumber
+ env["previousHash"] = test.Env.PreviousHash
+ if n, ok := test.Env.CurrentTimestamp.(float64); ok {
+ env["currentTimestamp"] = strconv.Itoa(int(n))
+ } else {
+ env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
+ }
+
+ /*
+ if conf.precomp {
+ program := vm.NewProgram(test.code)
+ err := vm.AttachProgram(program)
+ if err != nil {
+ return err
+ }
+ }
+ */
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ benchVmTest(test, env, b)
+ }
+
+ vm.EnableJit = pJit
+ vm.ForceJit = pForceJit
+
+ return nil
+}
+
+func benchVmTest(test VmTest, env map[string]string, b *testing.B) {
+ b.StopTimer()
+ db, _ := ethdb.NewMemDatabase()
+ statedb := state.New(common.Hash{}, db)
+ for addr, account := range test.Pre {
+ obj := StateObjectFromAccount(db, addr, account)
+ statedb.SetStateObject(obj)
+ for a, v := range account.Storage {
+ obj.SetState(common.HexToHash(a), common.HexToHash(v))
+ }
+ }
+ b.StartTimer()
+
+ RunVm(statedb, env, test.Exec)
+}
+
+func RunVmTest(p string, skipTests []string) error {
tests := make(map[string]VmTest)
err := readJsonFile(p, &tests)
if err != nil {
diff --git a/trie/cache.go b/trie/cache.go
index b4174f0bdf..12c8e7bbe1 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/trie/encoding.go b/trie/encoding.go
index 1d52e9a869..631ea399a3 100644
--- a/trie/encoding.go
+++ b/trie/encoding.go
@@ -16,13 +16,7 @@
package trie
-import (
- "bytes"
- "encoding/hex"
- "strings"
-)
-
-func CompactEncode(hexSlice []byte) string {
+func CompactEncode(hexSlice []byte) []byte {
terminator := 0
if hexSlice[len(hexSlice)-1] == 16 {
terminator = 1
@@ -40,15 +34,15 @@ func CompactEncode(hexSlice []byte) string {
hexSlice = append([]byte{flags, 0}, hexSlice...)
}
- var buff bytes.Buffer
- for i := 0; i < len(hexSlice); i += 2 {
- buff.WriteByte(byte(16*hexSlice[i] + hexSlice[i+1]))
+ l := len(hexSlice) / 2
+ var buf = make([]byte, l)
+ for i := 0; i < l; i++ {
+ buf[i] = 16*hexSlice[2*i] + hexSlice[2*i+1]
}
-
- return buff.String()
+ return buf
}
-func CompactDecode(str string) []byte {
+func CompactDecode(str []byte) []byte {
base := CompactHexDecode(str)
base = base[:len(base)-1]
if base[0] >= 2 {
@@ -63,30 +57,23 @@ func CompactDecode(str string) []byte {
return base
}
-func CompactHexDecode(str string) []byte {
- base := "0123456789abcdef"
- var hexSlice []byte
-
- enc := hex.EncodeToString([]byte(str))
- for _, v := range enc {
- hexSlice = append(hexSlice, byte(strings.IndexByte(base, byte(v))))
+func CompactHexDecode(str []byte) []byte {
+ l := len(str)*2 + 1
+ var nibbles = make([]byte, l)
+ for i, b := range str {
+ nibbles[i*2] = b / 16
+ nibbles[i*2+1] = b % 16
}
- hexSlice = append(hexSlice, 16)
-
- return hexSlice
+ nibbles[l-1] = 16
+ return nibbles
}
-func DecodeCompact(key []byte) string {
- const base = "0123456789abcdef"
- var str string
-
- for _, v := range key {
- if v < 16 {
- str += string(base[v])
- }
+func DecodeCompact(key []byte) []byte {
+ l := len(key) / 2
+ var res = make([]byte, l)
+ for i := 0; i < l; i++ {
+ v1, v0 := key[2*i], key[2*i+1]
+ res[i] = v1*16 + v0
}
-
- res, _ := hex.DecodeString(str)
-
- return string(res)
+ return res
}
diff --git a/trie/encoding_test.go b/trie/encoding_test.go
index 656e08e938..e1daa90d29 100644
--- a/trie/encoding_test.go
+++ b/trie/encoding_test.go
@@ -17,9 +17,14 @@
package trie
import (
+ "encoding/hex"
+ "testing"
+
checker "gopkg.in/check.v1"
)
+func Test(t *testing.T) { checker.TestingT(t) }
+
type TrieEncodingSuite struct{}
var _ = checker.Suite(&TrieEncodingSuite{})
@@ -28,48 +33,93 @@ func (s *TrieEncodingSuite) TestCompactEncode(c *checker.C) {
// even compact encode
test1 := []byte{1, 2, 3, 4, 5}
res1 := CompactEncode(test1)
- c.Assert(res1, checker.Equals, "\x11\x23\x45")
+ c.Assert(res1, checker.DeepEquals, []byte("\x11\x23\x45"))
// odd compact encode
test2 := []byte{0, 1, 2, 3, 4, 5}
res2 := CompactEncode(test2)
- c.Assert(res2, checker.Equals, "\x00\x01\x23\x45")
+ c.Assert(res2, checker.DeepEquals, []byte("\x00\x01\x23\x45"))
//odd terminated compact encode
test3 := []byte{0, 15, 1, 12, 11, 8 /*term*/, 16}
res3 := CompactEncode(test3)
- c.Assert(res3, checker.Equals, "\x20\x0f\x1c\xb8")
+ c.Assert(res3, checker.DeepEquals, []byte("\x20\x0f\x1c\xb8"))
// even terminated compact encode
test4 := []byte{15, 1, 12, 11, 8 /*term*/, 16}
res4 := CompactEncode(test4)
- c.Assert(res4, checker.Equals, "\x3f\x1c\xb8")
+ c.Assert(res4, checker.DeepEquals, []byte("\x3f\x1c\xb8"))
}
func (s *TrieEncodingSuite) TestCompactHexDecode(c *checker.C) {
exp := []byte{7, 6, 6, 5, 7, 2, 6, 2, 16}
- res := CompactHexDecode("verb")
+ res := CompactHexDecode([]byte("verb"))
c.Assert(res, checker.DeepEquals, exp)
}
func (s *TrieEncodingSuite) TestCompactDecode(c *checker.C) {
// odd compact decode
exp := []byte{1, 2, 3, 4, 5}
- res := CompactDecode("\x11\x23\x45")
+ res := CompactDecode([]byte("\x11\x23\x45"))
c.Assert(res, checker.DeepEquals, exp)
// even compact decode
exp = []byte{0, 1, 2, 3, 4, 5}
- res = CompactDecode("\x00\x01\x23\x45")
+ res = CompactDecode([]byte("\x00\x01\x23\x45"))
c.Assert(res, checker.DeepEquals, exp)
// even terminated compact decode
exp = []byte{0, 15, 1, 12, 11, 8 /*term*/, 16}
- res = CompactDecode("\x20\x0f\x1c\xb8")
+ res = CompactDecode([]byte("\x20\x0f\x1c\xb8"))
c.Assert(res, checker.DeepEquals, exp)
// even terminated compact decode
exp = []byte{15, 1, 12, 11, 8 /*term*/, 16}
- res = CompactDecode("\x3f\x1c\xb8")
+ res = CompactDecode([]byte("\x3f\x1c\xb8"))
c.Assert(res, checker.DeepEquals, exp)
}
+
+func (s *TrieEncodingSuite) TestDecodeCompact(c *checker.C) {
+ exp, _ := hex.DecodeString("012345")
+ res := DecodeCompact([]byte{0, 1, 2, 3, 4, 5})
+ c.Assert(res, checker.DeepEquals, exp)
+
+ exp, _ = hex.DecodeString("012345")
+ res = DecodeCompact([]byte{0, 1, 2, 3, 4, 5, 16})
+ c.Assert(res, checker.DeepEquals, exp)
+
+ exp, _ = hex.DecodeString("abcdef")
+ res = DecodeCompact([]byte{10, 11, 12, 13, 14, 15})
+ c.Assert(res, checker.DeepEquals, exp)
+}
+
+func BenchmarkCompactEncode(b *testing.B) {
+
+ testBytes := []byte{0, 15, 1, 12, 11, 8 /*term*/, 16}
+ for i := 0; i < b.N; i++ {
+ CompactEncode(testBytes)
+ }
+}
+
+func BenchmarkCompactDecode(b *testing.B) {
+ testBytes := []byte{0, 15, 1, 12, 11, 8 /*term*/, 16}
+ for i := 0; i < b.N; i++ {
+ CompactDecode(testBytes)
+ }
+}
+
+func BenchmarkCompactHexDecode(b *testing.B) {
+ testBytes := []byte{7, 6, 6, 5, 7, 2, 6, 2, 16}
+ for i := 0; i < b.N; i++ {
+ CompactHexDecode(testBytes)
+ }
+
+}
+
+func BenchmarkDecodeCompact(b *testing.B) {
+ testBytes := []byte{7, 6, 6, 5, 7, 2, 6, 2, 16}
+ for i := 0; i < b.N; i++ {
+ DecodeCompact(testBytes)
+ }
+
+}
diff --git a/trie/iterator.go b/trie/iterator.go
index b3056fd4b5..6691c602b5 100644
--- a/trie/iterator.go
+++ b/trie/iterator.go
@@ -41,7 +41,7 @@ func (self *Iterator) Next() bool {
self.Key = make([]byte, 32)
}
- key := RemTerm(CompactHexDecode(string(self.Key)))
+ key := RemTerm(CompactHexDecode(self.Key))
k := self.next(self.trie.root, key, isIterStart)
self.Key = []byte(DecodeCompact(k))
diff --git a/trie/shortnode.go b/trie/shortnode.go
index 9d197528c1..cb72455ad3 100644
--- a/trie/shortnode.go
+++ b/trie/shortnode.go
@@ -26,7 +26,7 @@ type ShortNode struct {
}
func NewShortNode(t *Trie, key []byte, value Node) *ShortNode {
- return &ShortNode{t, []byte(CompactEncode(key)), value, false}
+ return &ShortNode{t, CompactEncode(key), value, false}
}
func (self *ShortNode) Value() Node {
self.value = self.trie.trans(self.value)
@@ -49,7 +49,7 @@ func (self *ShortNode) Hash() interface{} {
}
func (self *ShortNode) Key() []byte {
- return CompactDecode(string(self.key))
+ return CompactDecode(self.key)
}
func (self *ShortNode) setDirty(dirty bool) {
diff --git a/trie/trie.go b/trie/trie.go
index 0e803848df..fd393461f1 100644
--- a/trie/trie.go
+++ b/trie/trie.go
@@ -69,7 +69,7 @@ func (self *Trie) Iterator() *Iterator {
func (self *Trie) Copy() *Trie {
cpy := make([]byte, 32)
- copy(cpy, self.roothash)
+ copy(cpy, self.roothash) // NOTE: cpy isn't being used anywhere?
trie := New(nil, nil)
trie.cache = self.cache.Copy()
if self.root != nil {
@@ -131,7 +131,7 @@ func (self *Trie) Update(key, value []byte) Node {
self.mu.Lock()
defer self.mu.Unlock()
- k := CompactHexDecode(string(key))
+ k := CompactHexDecode(key)
if len(value) != 0 {
node := NewValueNode(self, value)
@@ -149,7 +149,7 @@ func (self *Trie) Get(key []byte) []byte {
self.mu.Lock()
defer self.mu.Unlock()
- k := CompactHexDecode(string(key))
+ k := CompactHexDecode(key)
n := self.get(self.root, k)
if n != nil {
@@ -164,7 +164,7 @@ func (self *Trie) Delete(key []byte) Node {
self.mu.Lock()
defer self.mu.Unlock()
- k := CompactHexDecode(string(key))
+ k := CompactHexDecode(key)
self.root = self.delete(self.root, k)
return self.root
@@ -336,7 +336,7 @@ func (self *Trie) mknode(value *common.Value) Node {
case 2:
// A value node may consists of 2 bytes.
if value.Get(0).Len() != 0 {
- key := CompactDecode(string(value.Get(0).Bytes()))
+ key := CompactDecode(value.Get(0).Bytes())
if key[len(key)-1] == 16 {
return NewShortNode(self, key, NewValueNode(self, value.Get(1).Bytes()))
} else {
diff --git a/xeth/state.go b/xeth/state.go
index 03960a8f3e..16c5f1139f 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/types.go b/xeth/types.go
index 9ad9da2f8b..69ef054ad9 100644
--- a/xeth/types.go
+++ b/xeth/types.go
@@ -19,6 +19,7 @@ package xeth
import (
"bytes"
"fmt"
+ "math/big"
"strings"
"github.com/expanse-project/go-expanse/common"
@@ -76,7 +77,7 @@ type Block struct {
Hash string `json:"hash"`
Transactions *common.List `json:"transactions"`
Uncles *common.List `json:"uncles"`
- Time uint64 `json:"time"`
+ Time *big.Int `json:"time"`
Coinbase string `json:"coinbase"`
Name string `json:"name"`
GasLimit string `json:"gasLimit"`
diff --git a/xeth/xeth.go b/xeth/xeth.go
index da44cb2e5a..010d528761 100644
--- a/xeth/xeth.go
+++ b/xeth/xeth.go
@@ -20,8 +20,10 @@ package xeth
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"math/big"
+ "regexp"
"sync"
"time"
@@ -45,6 +47,7 @@ var (
defaultGasPrice = big.NewInt(10000000000000) //150000000000
defaultGas = big.NewInt(90000) //500000
dappStorePre = []byte("dapp-")
+ addrReg = regexp.MustCompile(`^(0x)?[a-fA-F0-9]{40}$`)
)
// byte will be inferred
@@ -86,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
@@ -210,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())
}
}
@@ -256,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:
@@ -308,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 {
@@ -327,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
@@ -362,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 {
@@ -405,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
}
@@ -820,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 {
@@ -878,6 +884,14 @@ func (self *XEth) Sign(fromStr, hashStr string, didUnlock bool) (string, error)
return common.ToHex(sig), nil
}
+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)
@@ -887,6 +901,10 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
return "", err
}
+ if len(toStr) > 0 && toStr != "0x" && !isAddress(toStr) {
+ return "", errors.New("Invalid address")
+ }
+
var (
from = common.HexToAddress(fromStr)
to = common.HexToAddress(toStr)
@@ -937,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()
@@ -983,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
@@ -992,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 }
diff --git a/xeth/xeth_test.go b/xeth/xeth_test.go
new file mode 100644
index 0000000000..e649d20ef1
--- /dev/null
+++ b/xeth/xeth_test.go
@@ -0,0 +1,26 @@
+package xeth
+
+import "testing"
+
+func TestIsAddress(t *testing.T) {
+ for _, invalid := range []string{
+ "0x00",
+ "0xNN",
+ "0x00000000000000000000000000000000000000NN",
+ "0xAAar000000000000000000000000000000000000",
+ } {
+ if isAddress(invalid) {
+ t.Error("Expected", invalid, "to be invalid")
+ }
+ }
+
+ for _, valid := range []string{
+ "0x0000000000000000000000000000000000000000",
+ "0xAABBbbCCccff9900000000000000000000000000",
+ "AABBbbCCccff9900000000000000000000000000",
+ } {
+ if !isAddress(valid) {
+ t.Error("Expected", valid, "to be valid")
+ }
+ }
+}