Merge branch 'develop' into bzz

This commit is contained in:
Daniel A. Nagy 2015-04-02 10:30:27 +02:00
commit b083b0329a
77 changed files with 4001 additions and 1051 deletions

4
Godeps/Godeps.json generated
View file

@ -90,6 +90,10 @@
"ImportPath": "github.com/robertkrimen/otto/token", "ImportPath": "github.com/robertkrimen/otto/token",
"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba" "Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba"
}, },
{
"ImportPath": "github.com/rs/cors",
"Rev": "6e0c3cb65fc0fdb064c743d176a620e3ca446dfb"
},
{ {
"ImportPath": "github.com/syndtr/goleveldb/leveldb", "ImportPath": "github.com/syndtr/goleveldb/leveldb",
"Rev": "832fa7ed4d28545eab80f19e1831fc004305cade" "Rev": "832fa7ed4d28545eab80f19e1831fc004305cade"

4
Godeps/_workspace/src/github.com/rs/cors/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,4 @@
language: go
go:
- 1.3
- 1.4

19
Godeps/_workspace/src/github.com/rs/cors/LICENSE generated vendored Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2014 Olivier Poitrey <rs@dailymotion.com>
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.

84
Godeps/_workspace/src/github.com/rs/cors/README.md generated vendored Normal file
View file

@ -0,0 +1,84 @@
# Go CORS handler [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/cors) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/cors/master/LICENSE) [![build](https://img.shields.io/travis/rs/cors.svg?style=flat)](https://travis-ci.org/rs/cors)
CORS is a `net/http` handler implementing [Cross Origin Resource Sharing W3 specification](http://www.w3.org/TR/cors/) in Golang.
## Getting Started
After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`.
```go
package main
import (
"net/http"
"github.com/rs/cors"
)
func main() {
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"hello\": \"world\"}"))
})
// cors.Default() setup the middleware with default options being
// all origins accepted with simple methods (GET, POST). See
// documentation below for more options.
handler = cors.Default().Handler(h)
http.ListenAndServe(":8080", handler)
}
```
Install `cors`:
go get github.com/rs/cors
Then run your server:
go run server.go
The server now runs on `localhost:8080`:
$ curl -D - -H 'Origin: http://foo.com' http://localhost:8080/
HTTP/1.1 200 OK
Access-Control-Allow-Origin: foo.com
Content-Type: application/json
Date: Sat, 25 Oct 2014 03:43:57 GMT
Content-Length: 18
{"hello": "world"}
### More Examples
* `net/http`: [examples/nethttp/server.go](https://github.com/rs/cors/blob/master/examples/nethttp/server.go)
* [Goji](https://goji.io): [examples/goji/server.go](https://github.com/rs/cors/blob/master/examples/goji/server.go)
* [Martini](http://martini.codegangsta.io): [examples/martini/server.go](https://github.com/rs/cors/blob/master/examples/martini/server.go)
* [Negroni](https://github.com/codegangsta/negroni): [examples/negroni/server.go](https://github.com/rs/cors/blob/master/examples/negroni/server.go)
* [Alice](https://github.com/justinas/alice): [examples/alice/server.go](https://github.com/rs/cors/blob/master/examples/alice/server.go)
## Parameters
Parameters are passed to the middleware thru the `cors.New` method as follow:
```go
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://foo.com"},
AllowCredentials: true,
})
// Insert the middleware
handler = c.Handler(handler)
```
* **AllowedOrigins** `[]string`: A list of origins a cross-domain request can be executed from. If the special `*` value is present in the list, all origins will be allowed. The default value is `*`.
* **AllowedMethods** `[]string`: A list of methods the client is allowed to use with cross-domain requests.
* **AllowedHeaders** `[]string`: A list of non simple headers the client is allowed to use with cross-domain requests. Default value is simple methods (`GET` and `POST`)
* **ExposedHeaders** `[]string`: Indicates which headers are safe to expose to the API of a CORS API specification
* **AllowCredentials** `bool`: Indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates. The default is `false`.
* **MaxAge** `int`: Indicates how long (in seconds) the results of a preflight request can be cached. The default is `0` which stands for no max age.
See [API documentation](http://godoc.org/github.com/rs/cors) for more info.
## Licenses
All source code is licensed under the [MIT License](https://raw.github.com/rs/cors/master/LICENSE).

37
Godeps/_workspace/src/github.com/rs/cors/bench_test.go generated vendored Normal file
View file

@ -0,0 +1,37 @@
package cors
import (
"net/http"
"net/http/httptest"
"testing"
)
func BenchmarkWithout(b *testing.B) {
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
for i := 0; i < b.N; i++ {
testHandler.ServeHTTP(res, req)
}
}
func BenchmarkDefault(b *testing.B) {
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
handler := Default()
for i := 0; i < b.N; i++ {
handler.Handler(testHandler).ServeHTTP(res, req)
}
}
func BenchmarkPreflight(b *testing.B) {
res := httptest.NewRecorder()
req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
req.Header.Add("Access-Control-Request-Method", "GET")
handler := Default()
for i := 0; i < b.N; i++ {
handler.Handler(testHandler).ServeHTTP(res, req)
}
}

308
Godeps/_workspace/src/github.com/rs/cors/cors.go generated vendored Normal file
View file

@ -0,0 +1,308 @@
/*
Package cors is net/http handler to handle CORS related requests
as defined by http://www.w3.org/TR/cors/
You can configure it by passing an option struct to cors.New:
c := cors.New(cors.Options{
AllowedOrigins: []string{"foo.com"},
AllowedMethods: []string{"GET", "POST", "DELETE"},
AllowCredentials: true,
})
Then insert the handler in the chain:
handler = c.Handler(handler)
See Options documentation for more options.
The resulting handler is a standard net/http handler.
*/
package cors
import (
"log"
"net/http"
"os"
"strconv"
"strings"
)
// Options is a configuration container to setup the CORS middleware.
type Options struct {
// AllowedOrigins is a list of origins a cross-domain request can be executed from.
// If the special "*" value is present in the list, all origins will be allowed.
// Default value is ["*"]
AllowedOrigins []string
// AllowedMethods is a list of methods the client is allowed to use with
// cross-domain requests. Default value is simple methods (GET and POST)
AllowedMethods []string
// AllowedHeaders is list of non simple headers the client is allowed to use with
// cross-domain requests.
// If the special "*" value is present in the list, all headers will be allowed.
// Default value is [] but "Origin" is always appended to the list.
AllowedHeaders []string
// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
// API specification
ExposedHeaders []string
// AllowCredentials indicates whether the request can include user credentials like
// cookies, HTTP authentication or client side SSL certificates.
AllowCredentials bool
// MaxAge indicates how long (in seconds) the results of a preflight request
// can be cached
MaxAge int
// Debugging flag adds additional output to debug server side CORS issues
Debug bool
// log object to use when debugging
log *log.Logger
}
type Cors struct {
// The CORS Options
options Options
}
// New creates a new Cors handler with the provided options.
func New(options Options) *Cors {
// Normalize options
// Note: for origins and methods matching, the spec requires a case-sensitive matching.
// As it may error prone, we chose to ignore the spec here.
normOptions := Options{
AllowedOrigins: convert(options.AllowedOrigins, strings.ToLower),
AllowedMethods: convert(options.AllowedMethods, strings.ToUpper),
// Origin is always appended as some browsers will always request
// for this header at preflight
AllowedHeaders: convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey),
ExposedHeaders: convert(options.ExposedHeaders, http.CanonicalHeaderKey),
AllowCredentials: options.AllowCredentials,
MaxAge: options.MaxAge,
Debug: options.Debug,
log: log.New(os.Stdout, "[cors] ", log.LstdFlags),
}
if len(normOptions.AllowedOrigins) == 0 {
// Default is all origins
normOptions.AllowedOrigins = []string{"*"}
}
if len(normOptions.AllowedHeaders) == 1 {
// Add some sensible defaults
normOptions.AllowedHeaders = []string{"Origin", "Accept", "Content-Type"}
}
if len(normOptions.AllowedMethods) == 0 {
// Default is simple methods
normOptions.AllowedMethods = []string{"GET", "POST"}
}
if normOptions.Debug {
normOptions.log.Printf("Options: %v", normOptions)
}
return &Cors{
options: normOptions,
}
}
// Default creates a new Cors handler with default options
func Default() *Cors {
return New(Options{})
}
// Handler apply the CORS specification on the request, and add relevant CORS headers
// as necessary.
func (cors *Cors) Handler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "OPTIONS" {
cors.logf("Handler: Preflight request")
cors.handlePreflight(w, r)
// Preflight requests are standalone and should stop the chain as some other
// middleware may not handle OPTIONS requests correctly. One typical example
// is authentication middleware ; OPTIONS requests won't carry authentication
// headers (see #1)
} else {
cors.logf("Handler: Actual request")
cors.handleActualRequest(w, r)
h.ServeHTTP(w, r)
}
})
}
// Martini compatible handler
func (cors *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) {
if r.Method == "OPTIONS" {
cors.logf("HandlerFunc: Preflight request")
cors.handlePreflight(w, r)
} else {
cors.logf("HandlerFunc: Actual request")
cors.handleActualRequest(w, r)
}
}
// Negroni compatible interface
func (cors *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if r.Method == "OPTIONS" {
cors.logf("ServeHTTP: Preflight request")
cors.handlePreflight(w, r)
// Preflight requests are standalone and should stop the chain as some other
// middleware may not handle OPTIONS requests correctly. One typical example
// is authentication middleware ; OPTIONS requests won't carry authentication
// headers (see #1)
} else {
cors.logf("ServeHTTP: Actual request")
cors.handleActualRequest(w, r)
next(w, r)
}
}
// handlePreflight handles pre-flight CORS requests
func (cors *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
options := cors.options
headers := w.Header()
origin := r.Header.Get("Origin")
if r.Method != "OPTIONS" {
cors.logf(" Preflight aborted: %s!=OPTIONS", r.Method)
return
}
if origin == "" {
cors.logf(" Preflight aborted: empty origin")
return
}
if !cors.isOriginAllowed(origin) {
cors.logf(" Preflight aborted: origin '%s' not allowed", origin)
return
}
reqMethod := r.Header.Get("Access-Control-Request-Method")
if !cors.isMethodAllowed(reqMethod) {
cors.logf(" Preflight aborted: method '%s' not allowed", reqMethod)
return
}
reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers"))
if !cors.areHeadersAllowed(reqHeaders) {
cors.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders)
return
}
headers.Set("Access-Control-Allow-Origin", origin)
headers.Add("Vary", "Origin")
// Spec says: Since the list of methods can be unbounded, simply returning the method indicated
// by Access-Control-Request-Method (if supported) can be enough
headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod))
if len(reqHeaders) > 0 {
// Spec says: Since the list of headers can be unbounded, simply returning supported headers
// from Access-Control-Request-Headers can be enough
headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
}
if options.AllowCredentials {
headers.Set("Access-Control-Allow-Credentials", "true")
}
if options.MaxAge > 0 {
headers.Set("Access-Control-Max-Age", strconv.Itoa(options.MaxAge))
}
cors.logf(" Preflight response headers: %v", headers)
}
// handleActualRequest handles simple cross-origin requests, actual request or redirects
func (cors *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
options := cors.options
headers := w.Header()
origin := r.Header.Get("Origin")
if r.Method == "OPTIONS" {
cors.logf(" Actual request no headers added: method == %s", r.Method)
return
}
if origin == "" {
cors.logf(" Actual request no headers added: missing origin")
return
}
if !cors.isOriginAllowed(origin) {
cors.logf(" Actual request no headers added: origin '%s' not allowed", origin)
return
}
// Note that spec does define a way to specifically disallow a simple method like GET or
// POST. Access-Control-Allow-Methods is only used for pre-flight requests and the
// spec doesn't instruct to check the allowed methods for simple cross-origin requests.
// We think it's a nice feature to be able to have control on those methods though.
if !cors.isMethodAllowed(r.Method) {
if cors.options.Debug {
cors.logf(" Actual request no headers added: method '%s' not allowed",
r.Method)
}
return
}
headers.Set("Access-Control-Allow-Origin", origin)
headers.Add("Vary", "Origin")
if len(options.ExposedHeaders) > 0 {
headers.Set("Access-Control-Expose-Headers", strings.Join(options.ExposedHeaders, ", "))
}
if options.AllowCredentials {
headers.Set("Access-Control-Allow-Credentials", "true")
}
cors.logf(" Actual response added headers: %v", headers)
}
// convenience method. checks if debugging is turned on before printing
func (cors *Cors) logf(format string, a ...interface{}) {
if cors.options.Debug {
cors.options.log.Printf(format, a...)
}
}
// isOriginAllowed checks if a given origin is allowed to perform cross-domain requests
// on the endpoint
func (cors *Cors) isOriginAllowed(origin string) bool {
allowedOrigins := cors.options.AllowedOrigins
origin = strings.ToLower(origin)
for _, allowedOrigin := range allowedOrigins {
switch allowedOrigin {
case "*":
return true
case origin:
return true
}
}
return false
}
// isMethodAllowed checks if a given method can be used as part of a cross-domain request
// on the endpoing
func (cors *Cors) isMethodAllowed(method string) bool {
allowedMethods := cors.options.AllowedMethods
if len(allowedMethods) == 0 {
// If no method allowed, always return false, even for preflight request
return false
}
method = strings.ToUpper(method)
if method == "OPTIONS" {
// Always allow preflight requests
return true
}
for _, allowedMethod := range allowedMethods {
if allowedMethod == method {
return true
}
}
return false
}
// areHeadersAllowed checks if a given list of headers are allowed to used within
// a cross-domain request.
func (cors *Cors) areHeadersAllowed(requestedHeaders []string) bool {
if len(requestedHeaders) == 0 {
return true
}
for _, header := range requestedHeaders {
found := false
for _, allowedHeader := range cors.options.AllowedHeaders {
if allowedHeader == "*" || allowedHeader == header {
found = true
break
}
}
if !found {
return false
}
}
return true
}

288
Godeps/_workspace/src/github.com/rs/cors/cors_test.go generated vendored Normal file
View file

@ -0,0 +1,288 @@
package cors
import (
"net/http"
"net/http/httptest"
"testing"
)
var testHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("bar"))
})
func assertHeaders(t *testing.T, resHeaders http.Header, reqHeaders map[string]string) {
for name, value := range reqHeaders {
if resHeaders.Get(name) != value {
t.Errorf("Invalid header `%s', wanted `%s', got `%s'", name, value, resHeaders.Get(name))
}
}
}
func TestNoConfig(t *testing.T) {
s := New(Options{
// Intentionally left blank.
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "",
"Access-Control-Allow-Methods": "",
"Access-Control-Allow-Headers": "",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestWildcardOrigin(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"*"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "",
"Access-Control-Allow-Headers": "",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestAllowedOrigin(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "",
"Access-Control-Allow-Headers": "",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestDisallowedOrigin(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://barbaz.com")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "",
"Access-Control-Allow-Methods": "",
"Access-Control-Allow-Headers": "",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestAllowedMethod(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
AllowedMethods: []string{"PUT", "DELETE"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
req.Header.Add("Access-Control-Request-Method", "PUT")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "PUT",
"Access-Control-Allow-Headers": "",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestDisallowedMethod(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
AllowedMethods: []string{"PUT", "DELETE"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
req.Header.Add("Access-Control-Request-Method", "PATCH")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "",
"Access-Control-Allow-Methods": "",
"Access-Control-Allow-Headers": "",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestAllowedHeader(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
AllowedHeaders: []string{"X-Header-1", "x-header-2"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
req.Header.Add("Access-Control-Request-Method", "GET")
req.Header.Add("Access-Control-Request-Headers", "X-Header-2, X-HEADER-1")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Headers": "X-Header-2, X-Header-1",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestAllowedWildcardHeader(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
AllowedHeaders: []string{"*"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
req.Header.Add("Access-Control-Request-Method", "GET")
req.Header.Add("Access-Control-Request-Headers", "X-Header-2, X-HEADER-1")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Headers": "X-Header-2, X-Header-1",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestDisallowedHeader(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
AllowedHeaders: []string{"X-Header-1", "x-header-2"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
req.Header.Add("Access-Control-Request-Method", "GET")
req.Header.Add("Access-Control-Request-Headers", "X-Header-3, X-Header-1")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "",
"Access-Control-Allow-Methods": "",
"Access-Control-Allow-Headers": "",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestOriginHeader(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
req.Header.Add("Access-Control-Request-Method", "GET")
req.Header.Add("Access-Control-Request-Headers", "origin")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Headers": "Origin",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}
func TestExposedHeader(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
ExposedHeaders: []string{"X-Header-1", "x-header-2"},
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "",
"Access-Control-Allow-Headers": "",
"Access-Control-Allow-Credentials": "",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "X-Header-1, X-Header-2",
})
}
func TestAllowedCredentials(t *testing.T) {
s := New(Options{
AllowedOrigins: []string{"http://foobar.com"},
AllowCredentials: true,
})
res := httptest.NewRecorder()
req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil)
req.Header.Add("Origin", "http://foobar.com")
req.Header.Add("Access-Control-Request-Method", "GET")
s.Handler(testHandler).ServeHTTP(res, req)
assertHeaders(t, res.Header(), map[string]string{
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Headers": "",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Max-Age": "",
"Access-Control-Expose-Headers": "",
})
}

View file

@ -0,0 +1,24 @@
package main
import (
"net/http"
"github.com/justinas/alice"
"github.com/rs/cors"
)
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://foo.com"},
})
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"hello\": \"world\"}"))
})
chain := alice.New(c.Handler).Then(mux)
http.ListenAndServe(":8080", chain)
}

View file

@ -0,0 +1,18 @@
package main
import (
"net/http"
"github.com/rs/cors"
)
func main() {
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"hello\": \"world\"}"))
})
// Use default options
handler := cors.Default().Handler(h)
http.ListenAndServe(":8080", handler)
}

View file

@ -0,0 +1,22 @@
package main
import (
"net/http"
"github.com/rs/cors"
"github.com/zenazn/goji"
)
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://foo.com"},
})
goji.Use(c.Handler)
goji.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"hello\": \"world\"}"))
})
goji.Serve()
}

View file

@ -0,0 +1,23 @@
package main
import (
"github.com/go-martini/martini"
"github.com/martini-contrib/render"
"github.com/rs/cors"
)
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://foo.com"},
})
m := martini.Classic()
m.Use(render.Renderer())
m.Use(c.HandlerFunc)
m.Get("/", func(r render.Render) {
r.JSON(200, map[string]interface{}{"hello": "world"})
})
m.Run()
}

View file

@ -0,0 +1,26 @@
package main
import (
"net/http"
"github.com/codegangsta/negroni"
"github.com/rs/cors"
)
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://foo.com"},
})
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"hello\": \"world\"}"))
})
n := negroni.Classic()
n.Use(c)
n.UseHandler(mux)
n.Run(":3000")
}

View file

@ -0,0 +1,20 @@
package main
import (
"net/http"
"github.com/rs/cors"
)
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://foo.com"},
})
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"hello\": \"world\"}"))
})
http.ListenAndServe(":8080", c.Handler(handler))
}

View file

@ -0,0 +1,22 @@
package main
import (
"net/http"
"github.com/rs/cors"
)
func main() {
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowCredentials: true,
})
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"hello\": \"world\"}"))
})
http.ListenAndServe(":8080", c.Handler(h))
}

27
Godeps/_workspace/src/github.com/rs/cors/utils.go generated vendored Normal file
View file

@ -0,0 +1,27 @@
package cors
import (
"net/http"
"strings"
)
type converter func(string) string
// convert converts a list of string using the passed converter function
func convert(s []string, c converter) []string {
out := []string{}
for _, i := range s {
out = append(out, c(i))
}
return out
}
func parseHeaderList(headerList string) (headers []string) {
for _, header := range strings.Split(headerList, ",") {
header = http.CanonicalHeaderKey(strings.TrimSpace(header))
if header != "" {
headers = append(headers, header)
}
}
return headers
}

28
Godeps/_workspace/src/github.com/rs/cors/utils_test.go generated vendored Normal file
View file

@ -0,0 +1,28 @@
package cors
import (
"strings"
"testing"
)
func TestConvert(t *testing.T) {
s := convert([]string{"A", "b", "C"}, strings.ToLower)
e := []string{"a", "b", "c"}
if s[0] != e[0] || s[1] != e[1] || s[2] != e[2] {
t.Errorf("%v != %v", s, e)
}
}
func TestParseHeaderList(t *testing.T) {
h := parseHeaderList("header, second-header, THIRD-HEADER")
e := []string{"Header", "Second-Header", "Third-Header"}
if h[0] != e[0] || h[1] != e[1] || h[2] != e[2] {
t.Errorf("%v != %v", h, e)
}
}
func TestParseHeaderListEmpty(t *testing.T) {
if len(parseHeaderList("")) != 0 {
t.Error("should be empty sclice")
}
}

View file

@ -61,8 +61,8 @@ func main() {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
statedb := state.New(common.Hash{}, db) statedb := state.New(common.Hash{}, db)
sender := statedb.NewStateObject(common.StringToAddress("sender")) sender := statedb.CreateAccount(common.StringToAddress("sender"))
receiver := statedb.NewStateObject(common.StringToAddress("receiver")) receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
receiver.SetCode(common.Hex2Bytes(*code)) receiver.SetCode(common.Hex2Bytes(*code))
vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(*value)) vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(*value))

View file

@ -2,8 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"net"
"net/http"
"os" "os"
"time" "time"
@ -70,12 +68,20 @@ func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
return otto.FalseValue() return otto.FalseValue()
} }
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port)) config := rpc.RpcConfig{
ListenAddress: addr,
ListenPort: uint(port),
// CorsDomain: ctx.GlobalString(RPCCORSDomainFlag.Name),
}
xeth := xeth.New(js.ethereum, nil)
err = rpc.Start(xeth, config)
if err != nil { if err != nil {
fmt.Printf("Can't listen on %s:%d: %v", addr, port, err) fmt.Printf(err.Error())
return otto.FalseValue() return otto.FalseValue()
} }
go http.Serve(l, rpc.JSONRPC(xeth.New(js.ethereum, nil)))
return otto.TrueValue() return otto.TrueValue()
} }

View file

@ -60,7 +60,7 @@ func runblocktest(ctx *cli.Context) {
// insert the test blocks, which will execute all transactions // insert the test blocks, which will execute all transactions
chain := ethereum.ChainManager() chain := ethereum.ChainManager()
if err := chain.InsertChain(test.Blocks); err != nil { if err := chain.InsertChain(test.Blocks); err != nil {
utils.Fatalf("Block Test load error: %v", err) utils.Fatalf("Block Test load error: %v %T", err, err)
} else { } else {
fmt.Println("Block Test chain loaded") fmt.Println("Block Test chain loaded")
} }

View file

@ -233,6 +233,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
utils.VMDebugFlag, utils.VMDebugFlag,
utils.ProtocolVersionFlag, utils.ProtocolVersionFlag,
utils.NetworkIdFlag, utils.NetworkIdFlag,
utils.RPCCORSDomainFlag,
} }
// missing: // missing:

@ -1 +1 @@
Subproject commit 17164bea8b330d6a118b40d6fbe222ffb12a0e9f Subproject commit 2536888f817a1a15b05dab4727d30f73d6763f07

View file

@ -47,12 +47,19 @@ var (
Usage: "absolute path to GUI assets directory", Usage: "absolute path to GUI assets directory",
Value: common.DefaultAssetPath(), Value: common.DefaultAssetPath(),
} }
rpcCorsFlag = utils.RPCCORSDomainFlag
) )
func init() { func init() {
// Mist-specific default
if len(rpcCorsFlag.Value) == 0 {
rpcCorsFlag.Value = "http://localhost"
}
app.Action = run app.Action = run
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
assetPathFlag, assetPathFlag,
rpcCorsFlag,
utils.BootnodesFlag, utils.BootnodesFlag,
utils.DataDirFlag, utils.DataDirFlag,

View file

@ -2,9 +2,6 @@ package utils
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt"
"net"
"net/http"
"os" "os"
"path" "path"
"runtime" "runtime"
@ -148,7 +145,11 @@ var (
Usage: "Port on which the JSON-RPC server should listen", Usage: "Port on which the JSON-RPC server should listen",
Value: 8545, Value: 8545,
} }
RPCCORSDomainFlag = cli.StringFlag{
Name: "rpccorsdomain",
Usage: "Domain on which to send Access-Control-Allow-Origin header",
Value: "",
}
// Network Settings // Network Settings
MaxPeersFlag = cli.IntFlag{ MaxPeersFlag = cli.IntFlag{
Name: "maxpeers", Name: "maxpeers",
@ -255,12 +256,12 @@ func GetAccountManager(ctx *cli.Context) *accounts.Manager {
} }
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) { func StartRPC(eth *eth.Ethereum, ctx *cli.Context) {
addr := ctx.GlobalString(RPCListenAddrFlag.Name) config := rpc.RpcConfig{
port := ctx.GlobalInt(RPCPortFlag.Name) ListenAddress: ctx.GlobalString(RPCListenAddrFlag.Name),
fmt.Println("Starting RPC on port: ", port) ListenPort: uint(ctx.GlobalInt(RPCPortFlag.Name)),
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port)) CorsDomain: ctx.GlobalString(RPCCORSDomainFlag.Name),
if err != nil {
Fatalf("Can't listen on %s:%d: %v", addr, port, err)
} }
go http.Serve(l, rpc.JSONRPC(xeth.New(eth, nil)))
xeth := xeth.New(eth, nil)
_ = rpc.Start(xeth, config)
} }

View file

@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"gopkg.in/fatih/set.v0" "gopkg.in/fatih/set.v0"
@ -83,7 +84,7 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
} }
// Update the state with pending changes // Update the state with pending changes
statedb.Update(nil) statedb.Update()
cumulative := new(big.Int).Set(usedGas.Add(usedGas, gas)) cumulative := new(big.Int).Set(usedGas.Add(usedGas, gas))
receipt := types.NewReceipt(statedb.Root().Bytes(), cumulative) receipt := types.NewReceipt(statedb.Root().Bytes(), cumulative)
@ -210,14 +211,16 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
return return
} }
// Accumulate static rewards; block reward, uncle's and uncle inclusion. // Verify uncles
if err = sm.AccumulateRewards(state, block, parent); err != nil { if err = sm.VerifyUncles(state, block, parent); err != nil {
return return
} }
// Accumulate static rewards; block reward, uncle's and uncle inclusion.
AccumulateRewards(state, block)
// Commit state objects/accounts to a temporary trie (does not save) // Commit state objects/accounts to a temporary trie (does not save)
// used to calculate the state root. // used to calculate the state root.
state.Update(common.Big0) state.Update()
if header.Root != state.Root() { if header.Root != state.Root() {
err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root()) err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root())
return return
@ -233,8 +236,9 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
sm.txpool.RemoveSet(block.Transactions()) sm.txpool.RemoveSet(block.Transactions())
} }
for _, tx := range block.Transactions() { // This puts transactions in a extra db for rpc
putTx(sm.extraDb, tx) for i, tx := range block.Transactions() {
putTx(sm.extraDb, tx, block, uint64(i))
} }
if uncle { if uncle {
@ -251,7 +255,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
// an uncle or anything that isn't on the current block chain. // an uncle or anything that isn't on the current block chain.
// Validation validates easy over difficult (dagger takes longer time = difficult) // Validation validates easy over difficult (dagger takes longer time = difficult)
func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error { func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error {
if len(block.Extra) > 1024 { if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
return fmt.Errorf("Block extra data too long (%d)", len(block.Extra)) return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
} }
@ -260,10 +264,11 @@ func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error {
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
} }
// block.gasLimit - parent.gasLimit <= parent.gasLimit / 1024 // block.gasLimit - parent.gasLimit <= parent.gasLimit / GasLimitBoundDivisor
a := new(big.Int).Sub(block.GasLimit, parent.GasLimit) a := new(big.Int).Sub(block.GasLimit, parent.GasLimit)
b := new(big.Int).Div(parent.GasLimit, big.NewInt(1024)) a.Abs(a)
if a.Cmp(b) > 0 { b := new(big.Int).Div(parent.GasLimit, params.GasLimitBoundDivisor)
if !(a.Cmp(b) < 0) || (block.GasLimit.Cmp(params.MinGasLimit) == -1) {
return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b) return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b)
} }
@ -287,9 +292,27 @@ func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error {
return nil return nil
} }
func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, parent *types.Block) error { func AccumulateRewards(statedb *state.StateDB, block *types.Block) {
reward := new(big.Int).Set(BlockReward) reward := new(big.Int).Set(BlockReward)
for _, uncle := range block.Uncles() {
num := new(big.Int).Add(big.NewInt(8), uncle.Number)
num.Sub(num, block.Number())
r := new(big.Int)
r.Mul(BlockReward, num)
r.Div(r, big.NewInt(8))
statedb.AddBalance(uncle.Coinbase, r)
reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
}
// Get the account associated with the coinbase
statedb.AddBalance(block.Header().Coinbase, reward)
}
func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error {
ancestors := set.New() ancestors := set.New()
uncles := set.New() uncles := set.New()
ancestorHeaders := make(map[common.Hash]*types.Header) ancestorHeaders := make(map[common.Hash]*types.Header)
@ -323,17 +346,8 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren
return ValidationError(fmt.Sprintf("%v", err)) return ValidationError(fmt.Sprintf("%v", err))
} }
r := new(big.Int)
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
statedb.AddBalance(uncle.Coinbase, r)
reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
} }
// Get the account associated with the coinbase
statedb.AddBalance(block.Header().Coinbase, reward)
return nil return nil
} }
@ -350,16 +364,30 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
) )
sm.TransitionState(state, parent, block, true) sm.TransitionState(state, parent, block, true)
sm.AccumulateRewards(state, block, parent)
return state.Logs(), nil return state.Logs(), nil
} }
func putTx(db common.Database, tx *types.Transaction) { func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint64) {
rlpEnc, err := rlp.EncodeToBytes(tx) rlpEnc, err := rlp.EncodeToBytes(tx)
if err != nil { if err != nil {
statelogger.Infoln("Failed encoding tx", err) statelogger.Infoln("Failed encoding tx", err)
return return
} }
db.Put(tx.Hash().Bytes(), rlpEnc) db.Put(tx.Hash().Bytes(), rlpEnc)
var txExtra struct {
BlockHash common.Hash
BlockIndex uint64
Index uint64
}
txExtra.BlockHash = block.Hash()
txExtra.BlockIndex = block.NumberU64()
txExtra.Index = i
rlpMeta, err := rlp.EncodeToBytes(txExtra)
if err != nil {
statelogger.Infoln("Failed encoding meta", err)
return
}
db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
} }

View file

@ -5,10 +5,10 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/core/state"
) )
// So we can generate blocks easily // So we can generate blocks easily
@ -81,7 +81,7 @@ func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db common.Datab
cbase := state.GetOrNewStateObject(addr) cbase := state.GetOrNewStateObject(addr)
cbase.SetGasPool(CalcGasLimit(parent, block)) cbase.SetGasPool(CalcGasLimit(parent, block))
cbase.AddBalance(BlockReward) cbase.AddBalance(BlockReward)
state.Update(common.Big0) state.Update()
block.SetRoot(state.Root()) block.SetRoot(state.Root())
return block return block
} }

View file

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -32,18 +33,15 @@ type StateQuery interface {
func CalcDifficulty(block, parent *types.Header) *big.Int { func CalcDifficulty(block, parent *types.Header) *big.Int {
diff := new(big.Int) diff := new(big.Int)
diffBoundDiv := big.NewInt(2048) adjust := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor)
min := big.NewInt(131072) if big.NewInt(int64(block.Time)-int64(parent.Time)).Cmp(params.DurationLimit) < 0 {
adjust := new(big.Int).Div(parent.Difficulty, diffBoundDiv)
if (block.Time - parent.Time) < 8 {
diff.Add(parent.Difficulty, adjust) diff.Add(parent.Difficulty, adjust)
} else { } else {
diff.Sub(parent.Difficulty, adjust) diff.Sub(parent.Difficulty, adjust)
} }
if diff.Cmp(min) < 0 { if diff.Cmp(params.MinimumDifficulty) < 0 {
return min return params.MinimumDifficulty
} }
return diff return diff
@ -76,7 +74,7 @@ func CalcGasLimit(parent, block *types.Block) *big.Int {
result := new(big.Int).Add(previous, curInt) result := new(big.Int).Add(previous, curInt)
result.Div(result, big.NewInt(1024)) result.Div(result, big.NewInt(1024))
return common.BigMax(GenesisGasLimit, result) return common.BigMax(params.GenesisGasLimit, result)
} }
type ChainManager struct { type ChainManager struct {

View file

@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
) )
type Execution struct { type Execution struct {
@ -43,23 +44,36 @@ func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.
env := self.env env := self.env
evm := self.evm evm := self.evm
if env.Depth() == vm.MaxCallDepth { if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(self.Gas, self.price) caller.ReturnGas(self.Gas, self.price)
return nil, vm.DepthError{} return nil, vm.DepthError{}
} }
vsnapshot := env.State().Copy() vsnapshot := env.State().Copy()
var createAccount bool
if self.address == nil { if self.address == nil {
// Generate a new address // Generate a new address
nonce := env.State().GetNonce(caller.Address()) nonce := env.State().GetNonce(caller.Address())
addr := crypto.CreateAddress(caller.Address(), nonce)
env.State().SetNonce(caller.Address(), nonce+1) env.State().SetNonce(caller.Address(), nonce+1)
addr := crypto.CreateAddress(caller.Address(), nonce)
self.address = &addr self.address = &addr
createAccount = true
} }
snapshot := env.State().Copy() snapshot := env.State().Copy()
from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(*self.address) var (
from = env.State().GetStateObject(caller.Address())
to *state.StateObject
)
if createAccount {
to = env.State().CreateAccount(*self.address)
} else {
to = env.State().GetOrNewStateObject(*self.address)
}
err = env.Transfer(from, to, self.value) err = env.Transfer(from, to, self.value)
if err != nil { if err != nil {
env.State().Set(vsnapshot) env.State().Set(vsnapshot)

View file

@ -3,12 +3,12 @@ package core
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/big"
"os" "os"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
) )
/* /*
@ -18,13 +18,11 @@ import (
var ZeroHash256 = make([]byte, 32) var ZeroHash256 = make([]byte, 32)
var ZeroHash160 = make([]byte, 20) var ZeroHash160 = make([]byte, 20)
var ZeroHash512 = make([]byte, 64) var ZeroHash512 = make([]byte, 64)
var GenesisDiff = big.NewInt(131072)
var GenesisGasLimit = big.NewInt(3141592)
func GenesisBlock(db common.Database) *types.Block { func GenesisBlock(db common.Database) *types.Block {
genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, GenesisDiff, 42, "") genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, params.GenesisDifficulty, 42, "")
genesis.Header().Number = common.Big0 genesis.Header().Number = common.Big0
genesis.Header().GasLimit = GenesisGasLimit genesis.Header().GasLimit = params.GenesisGasLimit
genesis.Header().GasUsed = common.Big0 genesis.Header().GasUsed = common.Big0
genesis.Header().Time = 0 genesis.Header().Time = 0
@ -34,7 +32,10 @@ func GenesisBlock(db common.Database) *types.Block {
genesis.SetTransactions(types.Transactions{}) genesis.SetTransactions(types.Transactions{})
genesis.SetReceipts(types.Receipts{}) genesis.SetReceipts(types.Receipts{})
var accounts map[string]struct{ Balance string } var accounts map[string]struct {
Balance string
Code string
}
err := json.Unmarshal(genesisData, &accounts) err := json.Unmarshal(genesisData, &accounts)
if err != nil { if err != nil {
fmt.Println("enable to decode genesis json data:", err) fmt.Println("enable to decode genesis json data:", err)
@ -44,8 +45,9 @@ func GenesisBlock(db common.Database) *types.Block {
statedb := state.New(genesis.Root(), db) statedb := state.New(genesis.Root(), db)
for addr, account := range accounts { for addr, account := range accounts {
codedAddr := common.Hex2Bytes(addr) codedAddr := common.Hex2Bytes(addr)
accountState := statedb.GetAccount(common.BytesToAddress(codedAddr)) accountState := statedb.CreateAccount(common.BytesToAddress(codedAddr))
accountState.SetBalance(common.Big(account.Balance)) accountState.SetBalance(common.Big(account.Balance))
accountState.SetCode(common.FromHex(account.Code))
statedb.UpdateStateObject(accountState) statedb.UpdateStateObject(accountState)
} }
statedb.Sync() statedb.Sync()

View file

@ -68,11 +68,11 @@ func TestNull(t *testing.T) {
state := New(common.Hash{}, db) state := New(common.Hash{}, db)
address := common.HexToAddress("0x823140710bf13990e4500136726d8b55") address := common.HexToAddress("0x823140710bf13990e4500136726d8b55")
state.NewStateObject(address) state.CreateAccount(address)
//value := common.FromHex("0x823140710bf13990e4500136726d8b55") //value := common.FromHex("0x823140710bf13990e4500136726d8b55")
value := make([]byte, 16) value := make([]byte, 16)
state.SetState(address, common.Hash{}, value) state.SetState(address, common.Hash{}, value)
state.Update(nil) state.Update()
state.Sync() state.Sync()
value = state.GetState(address, common.Hash{}) value = state.GetState(address, common.Hash{})
} }

View file

@ -57,6 +57,10 @@ func (self *StateDB) Refund(address common.Address, gas *big.Int) {
self.refund[addr].Add(self.refund[addr], gas) self.refund[addr].Add(self.refund[addr], gas)
} }
/*
* GETTERS
*/
// Retrieve the balance from the given address or 0 if object not found // Retrieve the balance from the given address or 0 if object not found
func (self *StateDB) GetBalance(addr common.Address) *big.Int { func (self *StateDB) GetBalance(addr common.Address) *big.Int {
stateObject := self.GetStateObject(addr) stateObject := self.GetStateObject(addr)
@ -67,13 +71,6 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
return common.Big0 return common.Big0
} }
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
stateObject := self.GetStateObject(addr)
if stateObject != nil {
stateObject.AddBalance(amount)
}
}
func (self *StateDB) GetNonce(addr common.Address) uint64 { func (self *StateDB) GetNonce(addr common.Address) uint64 {
stateObject := self.GetStateObject(addr) stateObject := self.GetStateObject(addr)
if stateObject != nil { if stateObject != nil {
@ -101,22 +98,41 @@ func (self *StateDB) GetState(a common.Address, b common.Hash) []byte {
return nil return nil
} }
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) { func (self *StateDB) IsDeleted(addr common.Address) bool {
stateObject := self.GetStateObject(addr) stateObject := self.GetStateObject(addr)
if stateObject != nil {
return stateObject.remove
}
return false
}
/*
* SETTERS
*/
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.AddBalance(amount)
}
}
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) {
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetNonce(nonce) stateObject.SetNonce(nonce)
} }
} }
func (self *StateDB) SetCode(addr common.Address, code []byte) { func (self *StateDB) SetCode(addr common.Address, code []byte) {
stateObject := self.GetStateObject(addr) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetCode(code) stateObject.SetCode(code)
} }
} }
func (self *StateDB) SetState(addr common.Address, key common.Hash, value interface{}) { func (self *StateDB) SetState(addr common.Address, key common.Hash, value interface{}) {
stateObject := self.GetStateObject(addr) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetState(key, common.NewValue(value)) stateObject.SetState(key, common.NewValue(value))
} }
@ -134,14 +150,6 @@ func (self *StateDB) Delete(addr common.Address) bool {
return false return false
} }
func (self *StateDB) IsDeleted(addr common.Address) bool {
stateObject := self.GetStateObject(addr)
if stateObject != nil {
return stateObject.remove
}
return false
}
// //
// Setting, updating & deleting state object methods // Setting, updating & deleting state object methods
// //
@ -194,16 +202,14 @@ func (self *StateDB) SetStateObject(object *StateObject) {
func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject { func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
stateObject := self.GetStateObject(addr) stateObject := self.GetStateObject(addr)
if stateObject == nil { if stateObject == nil {
stateObject = self.NewStateObject(addr) stateObject = self.CreateAccount(addr)
} }
return stateObject return stateObject
} }
// Create a state object whether it exist in the trie or not // NewStateObject create a state object whether it exist in the trie or not
func (self *StateDB) NewStateObject(addr common.Address) *StateObject { func (self *StateDB) newStateObject(addr common.Address) *StateObject {
//addr = common.Address(addr)
statelogger.Debugf("(+) %x\n", addr) statelogger.Debugf("(+) %x\n", addr)
stateObject := NewStateObject(addr, self.db) stateObject := NewStateObject(addr, self.db)
@ -212,9 +218,19 @@ func (self *StateDB) NewStateObject(addr common.Address) *StateObject {
return stateObject return stateObject
} }
// Deprecated // Creates creates a new state object and takes ownership. This is different from "NewStateObject"
func (self *StateDB) GetAccount(addr common.Address) *StateObject { func (self *StateDB) CreateAccount(addr common.Address) *StateObject {
return self.GetOrNewStateObject(addr) // Get previous (if any)
so := self.GetStateObject(addr)
// Create a new one
newSo := self.newStateObject(addr)
// If it existed set the balance to the new account
if so != nil {
newSo.balance = so.balance
}
return newSo
} }
// //
@ -300,7 +316,7 @@ func (self *StateDB) Refunds() map[string]*big.Int {
return self.refund return self.refund
} }
func (self *StateDB) Update(gasUsed *big.Int) { func (self *StateDB) Update() {
self.refund = make(map[string]*big.Int) self.refund = make(map[string]*big.Int)
for _, stateObject := range self.stateObjects { for _, stateObject := range self.stateObjects {

View file

@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
) )
const tryJit = false const tryJit = false
@ -178,20 +179,21 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
) )
// Transaction gas // Transaction gas
if err = self.UseGas(vm.GasTx); err != nil { if err = self.UseGas(params.TxGas); err != nil {
return nil, nil, InvalidTxError(err) return nil, nil, InvalidTxError(err)
} }
// Pay data gas // Pay data gas
var dgas int64 dgas := new(big.Int)
for _, byt := range self.data { for _, byt := range self.data {
if byt != 0 { if byt != 0 {
dgas += vm.GasTxDataNonzeroByte.Int64() dgas.Add(dgas, params.TxDataNonZeroGas)
} else { } else {
dgas += vm.GasTxDataZeroByte.Int64() dgas.Add(dgas, params.TxDataZeroGas)
} }
} }
if err = self.UseGas(big.NewInt(dgas)); err != nil {
if err = self.UseGas(dgas); err != nil {
return nil, nil, InvalidTxError(err) return nil, nil, InvalidTxError(err)
} }
@ -201,7 +203,7 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
ret, err, ref = vmenv.Create(sender, self.msg.Data(), self.gas, self.gasPrice, self.value) ret, err, ref = vmenv.Create(sender, self.msg.Data(), self.gas, self.gasPrice, self.value)
if err == nil { if err == nil {
dataGas := big.NewInt(int64(len(ret))) dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, vm.GasCreateByte) dataGas.Mul(dataGas, params.CreateDataGas)
if err := self.UseGas(dataGas); err == nil { if err := self.UseGas(dataGas); err == nil {
ref.SetCode(ret) ref.SetCode(ret)
} else { } else {

View file

@ -148,6 +148,23 @@ func NewBlockWithHeader(header *Header) *Block {
return &Block{header: header} return &Block{header: header}
} }
func (self *Block) ValidateFields() error {
if self.header == nil {
return fmt.Errorf("header is nil")
}
for i, transaction := range self.transactions {
if transaction == nil {
return fmt.Errorf("transaction %d is nil", i)
}
}
for i, uncle := range self.uncles {
if uncle == nil {
return fmt.Errorf("uncle %d is nil", i)
}
}
return nil
}
func (self *Block) DecodeRLP(s *rlp.Stream) error { func (self *Block) DecodeRLP(s *rlp.Stream) error {
var eb extblock var eb extblock
if err := s.Decode(&eb); err != nil { if err := s.Decode(&eb); err != nil {

View file

@ -5,6 +5,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
) )
type Address interface { type Address interface {
@ -27,28 +28,28 @@ func PrecompiledContracts() map[string]*PrecompiledAccount {
return map[string]*PrecompiledAccount{ return map[string]*PrecompiledAccount{
// ECRECOVER // ECRECOVER
string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int { string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int {
return GasEcrecover return params.EcrecoverGas
}, ecrecoverFunc}, }, ecrecoverFunc},
// SHA256 // SHA256
string(common.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int { string(common.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int {
n := big.NewInt(int64(l+31) / 32) n := big.NewInt(int64(l+31) / 32)
n.Mul(n, GasSha256Word) n.Mul(n, params.Sha256WordGas)
return n.Add(n, GasSha256Base) return n.Add(n, params.Sha256Gas)
}, sha256Func}, }, sha256Func},
// RIPEMD160 // RIPEMD160
string(common.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int { string(common.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int {
n := big.NewInt(int64(l+31) / 32) n := big.NewInt(int64(l+31) / 32)
n.Mul(n, GasRipemdWord) n.Mul(n, params.Ripemd160WordGas)
return n.Add(n, GasRipemdBase) return n.Add(n, params.Ripemd160Gas)
}, ripemd160Func}, }, ripemd160Func},
string(common.LeftPadBytes([]byte{4}, 20)): &PrecompiledAccount{func(l int) *big.Int { string(common.LeftPadBytes([]byte{4}, 20)): &PrecompiledAccount{func(l int) *big.Int {
n := big.NewInt(int64(l+31) / 32) n := big.NewInt(int64(l+31) / 32)
n.Mul(n, GasIdentityWord) n.Mul(n, params.IdentityWordGas)
return n.Add(n, GasIdentityBase) return n.Add(n, params.IdentityGas)
}, memCpy}, }, memCpy},
} }
} }

View file

@ -20,8 +20,6 @@ const (
JitVmTy JitVmTy
MaxVmTy MaxVmTy
MaxCallDepth = 1025
LogTyPretty byte = 0x1 LogTyPretty byte = 0x1
LogTyDiff byte = 0x2 LogTyDiff byte = 0x2
) )

View file

@ -2,6 +2,7 @@ package vm
import ( import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/params"
"math/big" "math/big"
) )
@ -42,7 +43,7 @@ func IsStack(err error) bool {
type DepthError struct{} type DepthError struct{}
func (self DepthError) Error() string { func (self DepthError) Error() string {
return fmt.Sprintf("Max call depth exceeded (%d)", MaxCallDepth) return fmt.Sprintf("Max call depth exceeded (%d)", params.CallCreateDepth)
} }
func IsDepthErr(err error) bool { func IsDepthErr(err error) bool {

View file

@ -2,6 +2,7 @@ package vm
import ( import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/params"
"math/big" "math/big"
) )
@ -13,45 +14,10 @@ var (
GasSlowStep = big.NewInt(10) GasSlowStep = big.NewInt(10)
GasExtStep = big.NewInt(20) GasExtStep = big.NewInt(20)
GasStorageGet = big.NewInt(50)
GasStorageAdd = big.NewInt(20000)
GasStorageMod = big.NewInt(5000)
GasLogBase = big.NewInt(375)
GasLogTopic = big.NewInt(375)
GasLogByte = big.NewInt(8)
GasCreate = big.NewInt(32000)
GasCreateByte = big.NewInt(200)
GasCall = big.NewInt(40)
GasCallValueTransfer = big.NewInt(9000)
GasStipend = big.NewInt(2300)
GasCallNewAccount = big.NewInt(25000)
GasReturn = big.NewInt(0) GasReturn = big.NewInt(0)
GasStop = big.NewInt(0) GasStop = big.NewInt(0)
GasJumpDest = big.NewInt(1)
RefundStorage = big.NewInt(15000)
RefundSuicide = big.NewInt(24000)
GasMemWord = big.NewInt(3)
GasQuadCoeffDenom = big.NewInt(512)
GasContractByte = big.NewInt(200) GasContractByte = big.NewInt(200)
GasTransaction = big.NewInt(21000)
GasTxDataNonzeroByte = big.NewInt(68)
GasTxDataZeroByte = big.NewInt(4)
GasTx = big.NewInt(21000)
GasExp = big.NewInt(10)
GasExpByte = big.NewInt(10)
GasSha3Base = big.NewInt(30)
GasSha3Word = big.NewInt(6)
GasSha256Base = big.NewInt(60)
GasSha256Word = big.NewInt(12)
GasRipemdBase = big.NewInt(600)
GasRipemdWord = big.NewInt(12)
GasEcrecover = big.NewInt(3000)
GasIdentityBase = big.NewInt(15)
GasIdentityWord = big.NewInt(3)
GasCopyWord = big.NewInt(3)
) )
func baseCheck(op OpCode, stack *stack, gas *big.Int) error { func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
@ -71,8 +37,8 @@ func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
return err return err
} }
if r.stackPush && len(stack.data)-r.stackPop+1 > 1024 { if r.stackPush && len(stack.data)-r.stackPop+1 > int(params.StackLimit.Int64()) {
return fmt.Errorf("stack limit reached (%d)", maxStack) return fmt.Errorf("stack limit reached (%d)", params.StackLimit.Int64())
} }
gas.Add(gas, r.gas) gas.Add(gas, r.gas)
@ -142,16 +108,16 @@ var _baseCheck = map[OpCode]req{
MSIZE: {0, GasQuickStep, true}, MSIZE: {0, GasQuickStep, true},
GAS: {0, GasQuickStep, true}, GAS: {0, GasQuickStep, true},
BLOCKHASH: {1, GasExtStep, true}, BLOCKHASH: {1, GasExtStep, true},
BALANCE: {0, GasExtStep, true}, BALANCE: {1, GasExtStep, true},
EXTCODESIZE: {1, GasExtStep, true}, EXTCODESIZE: {1, GasExtStep, true},
EXTCODECOPY: {4, GasExtStep, false}, EXTCODECOPY: {4, GasExtStep, false},
SLOAD: {1, GasStorageGet, true}, SLOAD: {1, params.SloadGas, true},
SSTORE: {2, Zero, false}, SSTORE: {2, Zero, false},
SHA3: {1, GasSha3Base, true}, SHA3: {2, params.Sha3Gas, true},
CREATE: {3, GasCreate, true}, CREATE: {3, params.CreateGas, true},
CALL: {7, GasCall, true}, CALL: {7, params.CallGas, true},
CALLCODE: {7, GasCall, true}, CALLCODE: {7, params.CallGas, true},
JUMPDEST: {0, GasJumpDest, false}, JUMPDEST: {0, params.JumpdestGas, false},
SUICIDE: {1, Zero, false}, SUICIDE: {1, Zero, false},
RETURN: {2, Zero, false}, RETURN: {2, Zero, false},
PUSH1: {0, GasFastestStep, true}, PUSH1: {0, GasFastestStep, true},

View file

@ -5,8 +5,6 @@ import (
"math/big" "math/big"
) )
const maxStack = 1024
func newStack() *stack { func newStack() *stack {
return &stack{} return &stack{}
} }

View file

@ -7,6 +7,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
) )
type Vm struct { type Vm struct {
@ -640,7 +641,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
} else { } else {
// gas < len(ret) * CreateDataGas == NO_CODE // gas < len(ret) * CreateDataGas == NO_CODE
dataGas := big.NewInt(int64(len(ret))) dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, GasCreateByte) dataGas.Mul(dataGas, params.CreateDataGas)
if context.UseGas(dataGas) { if context.UseGas(dataGas) {
ref.SetCode(ret) ref.SetCode(ret)
} }
@ -667,7 +668,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
args := mem.Get(inOffset.Int64(), inSize.Int64()) args := mem.Get(inOffset.Int64(), inSize.Int64())
if len(value.Bytes()) > 0 { if len(value.Bytes()) > 0 {
gas.Add(gas, GasStipend) gas.Add(gas, params.CallStipend)
} }
var ( var (
@ -759,13 +760,13 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1] mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
gas.Add(gas, GasLogBase) gas.Add(gas, params.LogGas)
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), GasLogTopic)) gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas))
gas.Add(gas, new(big.Int).Mul(mSize, GasLogByte)) gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
newMemSize = calcMemSize(mStart, mSize) newMemSize = calcMemSize(mStart, mSize)
case EXP: case EXP:
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte)) gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
case SSTORE: case SSTORE:
err := stack.require(2) err := stack.require(2)
if err != nil { if err != nil {
@ -777,19 +778,19 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
val := statedb.GetState(context.Address(), common.BigToHash(x)) val := statedb.GetState(context.Address(), common.BigToHash(x))
if len(val) == 0 && len(y.Bytes()) > 0 { if len(val) == 0 && len(y.Bytes()) > 0 {
// 0 => non 0 // 0 => non 0
g = GasStorageAdd g = params.SstoreSetGas
} else if len(val) > 0 && len(y.Bytes()) == 0 { } else if len(val) > 0 && len(y.Bytes()) == 0 {
statedb.Refund(self.env.Origin(), RefundStorage) statedb.Refund(self.env.Origin(), params.SstoreRefundGas)
g = GasStorageMod g = params.SstoreClearGas
} else { } else {
// non 0 => non 0 (or 0 => 0) // non 0 => non 0 (or 0 => 0)
g = GasStorageMod g = params.SstoreClearGas
} }
gas.Set(g) gas.Set(g)
case SUICIDE: case SUICIDE:
if !statedb.IsDeleted(context.Address()) { if !statedb.IsDeleted(context.Address()) {
statedb.Refund(self.env.Origin(), RefundSuicide) statedb.Refund(self.env.Origin(), params.SuicideRefundGas)
} }
case MLOAD: case MLOAD:
newMemSize = calcMemSize(stack.peek(), u256(32)) newMemSize = calcMemSize(stack.peek(), u256(32))
@ -803,22 +804,22 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
words := toWordSize(stack.data[stack.len()-2]) words := toWordSize(stack.data[stack.len()-2])
gas.Add(gas, words.Mul(words, GasSha3Word)) gas.Add(gas, words.Mul(words, params.Sha3WordGas))
case CALLDATACOPY: case CALLDATACOPY:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
words := toWordSize(stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, GasCopyWord)) gas.Add(gas, words.Mul(words, params.CopyGas))
case CODECOPY: case CODECOPY:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
words := toWordSize(stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, GasCopyWord)) gas.Add(gas, words.Mul(words, params.CopyGas))
case EXTCODECOPY: case EXTCODECOPY:
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4]) newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
words := toWordSize(stack.data[stack.len()-4]) words := toWordSize(stack.data[stack.len()-4])
gas.Add(gas, words.Mul(words, GasCopyWord)) gas.Add(gas, words.Mul(words, params.CopyGas))
case CREATE: case CREATE:
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3]) newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
@ -827,12 +828,12 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
if op == CALL { if op == CALL {
if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil { if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
gas.Add(gas, GasCallNewAccount) gas.Add(gas, params.CallNewAccountGas)
} }
} }
if len(stack.data[stack.len()-3].Bytes()) > 0 { if len(stack.data[stack.len()-3].Bytes()) > 0 {
gas.Add(gas, GasCallValueTransfer) gas.Add(gas, params.CallValueTransferGas)
} }
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7]) x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
@ -848,16 +849,17 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
oldSize := toWordSize(big.NewInt(int64(mem.Len()))) oldSize := toWordSize(big.NewInt(int64(mem.Len())))
pow := new(big.Int).Exp(oldSize, common.Big2, Zero) pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
linCoef := new(big.Int).Mul(oldSize, GasMemWord) linCoef := new(big.Int).Mul(oldSize, params.MemoryGas)
quadCoef := new(big.Int).Div(pow, GasQuadCoeffDenom) quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
oldTotalFee := new(big.Int).Add(linCoef, quadCoef) oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
pow.Exp(newMemSizeWords, common.Big2, Zero) pow.Exp(newMemSizeWords, common.Big2, Zero)
linCoef = new(big.Int).Mul(newMemSizeWords, GasMemWord) linCoef = new(big.Int).Mul(newMemSizeWords, params.MemoryGas)
quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom) quadCoef = new(big.Int).Div(pow, params.QuadCoeffDiv)
newTotalFee := new(big.Int).Add(linCoef, quadCoef) newTotalFee := new(big.Int).Add(linCoef, quadCoef)
gas.Add(gas, new(big.Int).Sub(newTotalFee, oldTotalFee)) fee := new(big.Int).Sub(newTotalFee, oldTotalFee)
gas.Add(gas, fee)
} }
} }

View file

@ -18,8 +18,8 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto"
"math/big" "math/big"
"unsafe" "unsafe"
) )
@ -330,7 +330,7 @@ func env_create(_vm unsafe.Pointer, _gas *int64, _value unsafe.Pointer, initData
ret, suberr, ref := vm.env.Create(vm.me, nil, initData, gas, vm.price, value) ret, suberr, ref := vm.env.Create(vm.me, nil, initData, gas, vm.price, value)
if suberr == nil { if suberr == nil {
dataGas := big.NewInt(int64(len(ret))) // TODO: Nto the best design. env.Create can do it, it has the reference to gas counter dataGas := big.NewInt(int64(len(ret))) // TODO: Nto the best design. env.Create can do it, it has the reference to gas counter
dataGas.Mul(dataGas, GasCreateByte) dataGas.Mul(dataGas, params.CreateDataGas)
gas.Sub(gas, dataGas) gas.Sub(gas, dataGas)
*result = hash2llvm(ref.Address()) *result = hash2llvm(ref.Address())
} }

View file

@ -31,9 +31,9 @@ var (
defaultBootNodes = []*discover.Node{ defaultBootNodes = []*discover.Node{
// ETH/DEV cmd/bootnode // ETH/DEV cmd/bootnode
discover.MustParseNode("enode://6cdd090303f394a1cac34ecc9f7cda18127eafa2a3a06de39f6d920b0e583e062a7362097c7c65ee490a758b442acd5c80c6fce4b148c6a391e946b45131365b@54.169.166.226:30303"), discover.MustParseNode("enode://09fbeec0d047e9a37e63f60f8618aa9df0e49271f3fadb2c070dc09e2099b95827b63a8b837c6fd01d0802d457dd83e3bd48bd3e6509f8209ed90dabbc30e3d3@52.16.188.185:30303"),
// ETH/DEV cpp-ethereum (poc-8.ethdev.com) // ETH/DEV cpp-ethereum (poc-9.ethdev.com)
discover.MustParseNode("enode://4a44599974518ea5b0f14c31c4463692ac0329cb84851f3435e6d1b18ee4eae4aa495f846a0fa1219bd58035671881d44423876e57db2abd57254d0197da0ebe@5.1.83.226:30303"), discover.MustParseNode("enode://487611428e6c99a11a9795a6abe7b529e81315ca6aad66e2a2fc76e3adf263faba0d35466c2f8f68d561dbefa8878d4df5f1f2ddb1fbeab7f42ffb8cd328bd4a@5.1.83.226:30303"),
} }
) )

View file

@ -13,7 +13,7 @@ import (
) )
const ( const (
ProtocolVersion = 59 ProtocolVersion = 60
NetworkId = 0 NetworkId = 0
ProtocolLength = uint64(8) ProtocolLength = uint64(8)
ProtocolMaxMsgSize = 10 * 1024 * 1024 ProtocolMaxMsgSize = 10 * 1024 * 1024
@ -185,7 +185,10 @@ func (self *ethProtocol) handle() error {
if err := msg.Decode(&txs); err != nil { if err := msg.Decode(&txs); err != nil {
return self.protoError(ErrDecode, "msg %v: %v", msg, err) return self.protoError(ErrDecode, "msg %v: %v", msg, err)
} }
for _, tx := range txs { for i, tx := range txs {
if tx == nil {
return self.protoError(ErrDecode, "transaction %d is nil", i)
}
jsonlogger.LogJson(&logger.EthTxReceived{ jsonlogger.LogJson(&logger.EthTxReceived{
TxHash: tx.Hash().Hex(), TxHash: tx.Hash().Hex(),
RemoteId: self.peer.ID().String(), RemoteId: self.peer.ID().String(),
@ -268,6 +271,9 @@ func (self *ethProtocol) handle() error {
return self.protoError(ErrDecode, "msg %v: %v", msg, err) return self.protoError(ErrDecode, "msg %v: %v", msg, err)
} }
} }
if err := block.ValidateFields(); err != nil {
return self.protoError(ErrDecode, "block validation %v: %v", msg, err)
}
self.blockPool.AddBlock(&block, self.id) self.blockPool.AddBlock(&block, self.id)
} }
@ -276,6 +282,9 @@ func (self *ethProtocol) handle() error {
if err := msg.Decode(&request); err != nil { if err := msg.Decode(&request); err != nil {
return self.protoError(ErrDecode, "%v: %v", msg, err) return self.protoError(ErrDecode, "%v: %v", msg, err)
} }
if err := request.Block.ValidateFields(); err != nil {
return self.protoError(ErrDecode, "block validation %v: %v", msg, err)
}
hash := request.Block.Hash() hash := request.Block.Hash()
_, chainHead, _ := self.chainManager.Status() _, chainHead, _ := self.chainManager.Status()

View file

@ -63,6 +63,10 @@ func (self *testChainManager) GetBlockHashesFromHash(hash common.Hash, amount ui
func (self *testChainManager) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) { func (self *testChainManager) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) {
if self.status != nil { if self.status != nil {
td, currentBlock, genesisBlock = self.status() td, currentBlock, genesisBlock = self.status()
} else {
td = common.Big1
currentBlock = common.Hash{1}
genesisBlock = common.Hash{2}
} }
return return
} }
@ -163,14 +167,29 @@ func (self *ethProtocolTester) run() {
self.quit <- err self.quit <- err
} }
func (self *ethProtocolTester) handshake(t *testing.T, mock bool) {
td, currentBlock, genesis := self.chainManager.Status()
// first outgoing msg should be StatusMsg.
err := p2p.ExpectMsg(self, StatusMsg, &statusMsgData{
ProtocolVersion: ProtocolVersion,
NetworkId: NetworkId,
TD: td,
CurrentBlock: currentBlock,
GenesisBlock: genesis,
})
if err != nil {
t.Fatalf("incorrect outgoing status: %v", err)
}
if mock {
go p2p.Send(self, StatusMsg, &statusMsgData{ProtocolVersion, NetworkId, td, currentBlock, genesis})
}
}
func TestStatusMsgErrors(t *testing.T) { func TestStatusMsgErrors(t *testing.T) {
logInit() logInit()
eth := newEth(t) eth := newEth(t)
td := common.Big1
currentBlock := common.Hash{1}
genesis := common.Hash{2}
eth.chainManager.status = func() (*big.Int, common.Hash, common.Hash) { return td, currentBlock, genesis }
go eth.run() go eth.run()
td, currentBlock, genesis := eth.chainManager.Status()
tests := []struct { tests := []struct {
code uint64 code uint64
@ -195,18 +214,7 @@ func TestStatusMsgErrors(t *testing.T) {
}, },
} }
for _, test := range tests { for _, test := range tests {
// first outgoing msg should be StatusMsg. eth.handshake(t, false)
err := p2p.ExpectMsg(eth, StatusMsg, &statusMsgData{
ProtocolVersion: ProtocolVersion,
NetworkId: NetworkId,
TD: td,
CurrentBlock: currentBlock,
GenesisBlock: genesis,
})
if err != nil {
t.Fatalf("incorrect outgoing status: %v", err)
}
// the send call might hang until reset because // the send call might hang until reset because
// the protocol might not read the payload. // the protocol might not read the payload.
go p2p.Send(eth, test.code, test.data) go p2p.Send(eth, test.code, test.data)
@ -216,3 +224,177 @@ func TestStatusMsgErrors(t *testing.T) {
go eth.run() go eth.run()
} }
} }
func TestNewBlockMsg(t *testing.T) {
// logInit()
eth := newEth(t)
var disconnected bool
eth.blockPool.removePeer = func(peerId string) {
disconnected = true
}
go eth.run()
eth.handshake(t, true)
err := p2p.ExpectMsg(eth, TxMsg, []interface{}{})
if err != nil {
t.Errorf("transactions expected, got %v", err)
}
var tds = make(chan *big.Int)
eth.blockPool.addPeer = func(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool, suspended bool) {
tds <- td
return
}
var delay = 1 * time.Second
// eth.reset()
block := types.NewBlock(common.Hash{1}, common.Address{1}, common.Hash{1}, common.Big1, 1, "extra")
go p2p.Send(eth, NewBlockMsg, &newBlockMsgData{Block: block})
timer := time.After(delay)
select {
case td := <-tds:
if td.Cmp(common.Big0) != 0 {
t.Errorf("incorrect td %v, expected %v", td, common.Big0)
}
case <-timer:
t.Errorf("no td recorded after %v", delay)
return
case err := <-eth.quit:
t.Errorf("no error expected, got %v", err)
return
}
go p2p.Send(eth, NewBlockMsg, &newBlockMsgData{block, common.Big2})
timer = time.After(delay)
select {
case td := <-tds:
if td.Cmp(common.Big2) != 0 {
t.Errorf("incorrect td %v, expected %v", td, common.Big2)
}
case <-timer:
t.Errorf("no td recorded after %v", delay)
return
case err := <-eth.quit:
t.Errorf("no error expected, got %v", err)
return
}
go p2p.Send(eth, NewBlockMsg, []interface{}{})
// Block.DecodeRLP: validation failed: header is nil
eth.checkError(ErrDecode, delay)
}
func TestBlockMsg(t *testing.T) {
// logInit()
eth := newEth(t)
blocks := make(chan *types.Block)
eth.blockPool.addBlock = func(block *types.Block, peerId string) (err error) {
blocks <- block
return
}
var disconnected bool
eth.blockPool.removePeer = func(peerId string) {
disconnected = true
}
go eth.run()
eth.handshake(t, true)
err := p2p.ExpectMsg(eth, TxMsg, []interface{}{})
if err != nil {
t.Errorf("transactions expected, got %v", err)
}
var delay = 3 * time.Second
// eth.reset()
newblock := func(i int64) *types.Block {
return types.NewBlock(common.Hash{byte(i)}, common.Address{byte(i)}, common.Hash{byte(i)}, big.NewInt(i), uint64(i), string(i))
}
b := newblock(0)
b.Header().Difficulty = nil // check if nil as *big.Int decodes as 0
go p2p.Send(eth, BlocksMsg, types.Blocks{b, newblock(1), newblock(2)})
timer := time.After(delay)
for i := int64(0); i < 3; i++ {
select {
case block := <-blocks:
if (block.ParentHash() != common.Hash{byte(i)}) {
t.Errorf("incorrect block %v, expected %v", block.ParentHash(), common.Hash{byte(i)})
}
if block.Difficulty().Cmp(big.NewInt(i)) != 0 {
t.Errorf("incorrect block %v, expected %v", block.Difficulty(), big.NewInt(i))
}
case <-timer:
t.Errorf("no td recorded after %v", delay)
return
case err := <-eth.quit:
t.Errorf("no error expected, got %v", err)
return
}
}
go p2p.Send(eth, BlocksMsg, []interface{}{[]interface{}{}})
eth.checkError(ErrDecode, delay)
if !disconnected {
t.Errorf("peer not disconnected after error")
}
// test empty transaction
eth.reset()
go eth.run()
eth.handshake(t, true)
err = p2p.ExpectMsg(eth, TxMsg, []interface{}{})
if err != nil {
t.Errorf("transactions expected, got %v", err)
}
b = newblock(0)
b.AddTransaction(nil)
go p2p.Send(eth, BlocksMsg, types.Blocks{b})
eth.checkError(ErrDecode, delay)
}
func TestTransactionsMsg(t *testing.T) {
logInit()
eth := newEth(t)
txs := make(chan *types.Transaction)
eth.txPool.addTransactions = func(t []*types.Transaction) {
for _, tx := range t {
txs <- tx
}
}
go eth.run()
eth.handshake(t, true)
err := p2p.ExpectMsg(eth, TxMsg, []interface{}{})
if err != nil {
t.Errorf("transactions expected, got %v", err)
}
var delay = 3 * time.Second
tx := &types.Transaction{}
go p2p.Send(eth, TxMsg, []interface{}{tx, tx})
timer := time.After(delay)
for i := int64(0); i < 2; i++ {
select {
case <-txs:
case <-timer:
return
case err := <-eth.quit:
t.Errorf("no error expected, got %v", err)
return
}
}
go p2p.Send(eth, TxMsg, []interface{}{[]interface{}{}})
eth.checkError(ErrDecode, delay)
}

65
generators/defaults.go Normal file
View file

@ -0,0 +1,65 @@
//go:generate go run defaults.go default.json defs.go
package main //build !none
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"strings"
)
func fatal(str string, v ...interface{}) {
fmt.Fprintf(os.Stderr, str, v...)
os.Exit(1)
}
type setting struct {
Value int64 `json:"v"`
Comment string `json:"d"`
}
func main() {
if len(os.Args) < 3 {
fatal("usage %s <input> <output>\n", os.Args[0])
}
content, err := ioutil.ReadFile(os.Args[1])
if err != nil {
fatal("error reading file %v\n", err)
}
m := make(map[string]setting)
json.Unmarshal(content, &m)
filepath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "params", os.Args[2])
output, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE, os.ModePerm /*0777*/)
if err != nil {
fatal("error opening file for writing %v\n", err)
}
output.WriteString(`// DO NOT EDIT!!!
// AUTOGENERATED FROM generators/defaults.go
package params
import "math/big"
var (
`)
for name, setting := range m {
output.WriteString(fmt.Sprintf("%s=big.NewInt(%d) // %s\n", strings.Title(name), setting.Value, setting.Comment))
}
output.WriteString(")\n")
output.Close()
cmd := exec.Command("gofmt", "-w", filepath)
if err := cmd.Run(); err != nil {
fatal("gofmt failed: %v\n", err)
}
}

File diff suppressed because one or more lines are too long

View file

@ -60,7 +60,7 @@ out:
} }
} }
close(self.quitCurrentOp) //close(self.quitCurrentOp)
done: done:
// Empty channel // Empty channel
for { for {

View file

@ -270,9 +270,9 @@ gasLimit:
self.current.block.SetUncles(uncles) self.current.block.SetUncles(uncles)
self.current.state.AddBalance(self.coinbase, core.BlockReward) core.AccumulateRewards(self.current.state, self.current.block)
self.current.state.Update(common.Big0) self.current.state.Update()
self.push() self.push()
} }
@ -297,9 +297,6 @@ func (self *worker) commitUncle(uncle *types.Header) error {
return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", uncle.Hash())) return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", uncle.Hash()))
} }
self.current.state.AddBalance(uncle.Coinbase, uncleReward)
self.current.state.AddBalance(self.coinbase, inclusionReward)
return nil return nil
} }

View file

@ -13,6 +13,8 @@ import (
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
"sync"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -30,7 +32,8 @@ type Node struct {
DiscPort int // UDP listening port for discovery protocol DiscPort int // UDP listening port for discovery protocol
TCPPort int // TCP listening port for RLPx TCPPort int // TCP listening port for RLPx
active time.Time // this must be set/read using atomic load and store.
activeStamp int64
} }
func newNode(id NodeID, addr *net.UDPAddr) *Node { func newNode(id NodeID, addr *net.UDPAddr) *Node {
@ -39,7 +42,6 @@ func newNode(id NodeID, addr *net.UDPAddr) *Node {
IP: addr.IP, IP: addr.IP,
DiscPort: addr.Port, DiscPort: addr.Port,
TCPPort: addr.Port, TCPPort: addr.Port,
active: time.Now(),
} }
} }
@ -48,6 +50,20 @@ func (n *Node) isValid() bool {
return !n.IP.IsMulticast() && !n.IP.IsUnspecified() && n.TCPPort != 0 && n.DiscPort != 0 return !n.IP.IsMulticast() && !n.IP.IsUnspecified() && n.TCPPort != 0 && n.DiscPort != 0
} }
func (n *Node) bumpActive() {
stamp := time.Now().Unix()
atomic.StoreInt64(&n.activeStamp, stamp)
}
func (n *Node) active() time.Time {
stamp := atomic.LoadInt64(&n.activeStamp)
return time.Unix(stamp, 0)
}
func (n *Node) addr() *net.UDPAddr {
return &net.UDPAddr{IP: n.IP, Port: n.DiscPort}
}
// The string representation of a Node is a URL. // The string representation of a Node is a URL.
// Please see ParseNode for a description of the format. // Please see ParseNode for a description of the format.
func (n *Node) String() string { func (n *Node) String() string {
@ -304,3 +320,26 @@ func randomID(a NodeID, n int) (b NodeID) {
} }
return b return b
} }
// nodeDB stores all nodes we know about.
type nodeDB struct {
mu sync.RWMutex
byID map[NodeID]*Node
}
func (db *nodeDB) get(id NodeID) *Node {
db.mu.RLock()
defer db.mu.RUnlock()
return db.byID[id]
}
func (db *nodeDB) add(id NodeID, addr *net.UDPAddr, tcpPort uint16) *Node {
db.mu.Lock()
defer db.mu.Unlock()
if db.byID == nil {
db.byID = make(map[NodeID]*Node)
}
n := &Node{ID: id, IP: addr.IP, DiscPort: addr.Port, TCPPort: int(tcpPort)}
db.byID[n.ID] = n
return n
}

View file

@ -17,6 +17,7 @@ const (
alpha = 3 // Kademlia concurrency factor alpha = 3 // Kademlia concurrency factor
bucketSize = 16 // Kademlia bucket size bucketSize = 16 // Kademlia bucket size
nBuckets = nodeIDBits + 1 // Number of buckets nBuckets = nodeIDBits + 1 // Number of buckets
maxBondingPingPongs = 10
) )
type Table struct { type Table struct {
@ -24,27 +25,50 @@ type Table struct {
buckets [nBuckets]*bucket // index of known nodes by distance buckets [nBuckets]*bucket // index of known nodes by distance
nursery []*Node // bootstrap nodes nursery []*Node // bootstrap nodes
bondmu sync.Mutex
bonding map[NodeID]*bondproc
bondslots chan struct{} // limits total number of active bonding processes
net transport net transport
self *Node // metadata of the local node self *Node // metadata of the local node
db *nodeDB
}
type bondproc struct {
err error
n *Node
done chan struct{}
} }
// transport is implemented by the UDP transport. // transport is implemented by the UDP transport.
// it is an interface so we can test without opening lots of UDP // it is an interface so we can test without opening lots of UDP
// sockets and without generating a private key. // sockets and without generating a private key.
type transport interface { type transport interface {
ping(*Node) error ping(NodeID, *net.UDPAddr) error
findnode(e *Node, target NodeID) ([]*Node, error) waitping(NodeID) error
findnode(toid NodeID, addr *net.UDPAddr, target NodeID) ([]*Node, error)
close() close()
} }
// bucket contains nodes, ordered by their last activity. // bucket contains nodes, ordered by their last activity.
// the entry that was most recently active is the last element
// in entries.
type bucket struct { type bucket struct {
lastLookup time.Time lastLookup time.Time
entries []*Node entries []*Node
} }
func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr) *Table { func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr) *Table {
tab := &Table{net: t, self: newNode(ourID, ourAddr)} tab := &Table{
net: t,
db: new(nodeDB),
self: newNode(ourID, ourAddr),
bonding: make(map[NodeID]*bondproc),
bondslots: make(chan struct{}, maxBondingPingPongs),
}
for i := 0; i < cap(tab.bondslots); i++ {
tab.bondslots <- struct{}{}
}
for i := range tab.buckets { for i := range tab.buckets {
tab.buckets[i] = new(bucket) tab.buckets[i] = new(bucket)
} }
@ -107,8 +131,8 @@ func (tab *Table) Lookup(target NodeID) []*Node {
asked[n.ID] = true asked[n.ID] = true
pendingQueries++ pendingQueries++
go func() { go func() {
result, _ := tab.net.findnode(n, target) r, _ := tab.net.findnode(n.ID, n.addr(), target)
reply <- result reply <- tab.bondall(r)
}() }()
} }
} }
@ -116,13 +140,11 @@ func (tab *Table) Lookup(target NodeID) []*Node {
// we have asked all closest nodes, stop the search // we have asked all closest nodes, stop the search
break break
} }
// wait for the next reply // wait for the next reply
for _, n := range <-reply { for _, n := range <-reply {
cn := n if n != nil && !seen[n.ID] {
if !seen[n.ID] {
seen[n.ID] = true seen[n.ID] = true
result.push(cn, bucketSize) result.push(n, bucketSize)
} }
} }
pendingQueries-- pendingQueries--
@ -145,8 +167,9 @@ func (tab *Table) refresh() {
result := tab.Lookup(randomID(tab.self.ID, ld)) result := tab.Lookup(randomID(tab.self.ID, ld))
if len(result) == 0 { if len(result) == 0 {
// bootstrap the table with a self lookup // bootstrap the table with a self lookup
all := tab.bondall(tab.nursery)
tab.mutex.Lock() tab.mutex.Lock()
tab.add(tab.nursery) tab.add(all)
tab.mutex.Unlock() tab.mutex.Unlock()
tab.Lookup(tab.self.ID) tab.Lookup(tab.self.ID)
// TODO: the Kademlia paper says that we're supposed to perform // TODO: the Kademlia paper says that we're supposed to perform
@ -176,45 +199,105 @@ func (tab *Table) len() (n int) {
return n return n
} }
// bumpOrAdd updates the activity timestamp for the given node and // bondall bonds with all given nodes concurrently and returns
// attempts to insert the node into a bucket. The returned Node might // those nodes for which bonding has probably succeeded.
// not be part of the table. The caller must hold tab.mutex. func (tab *Table) bondall(nodes []*Node) (result []*Node) {
func (tab *Table) bumpOrAdd(node NodeID, from *net.UDPAddr) (n *Node) { rc := make(chan *Node, len(nodes))
b := tab.buckets[logdist(tab.self.ID, node)] for i := range nodes {
if n = b.bump(node); n == nil { go func(n *Node) {
n = newNode(node, from) nn, _ := tab.bond(false, n.ID, n.addr(), uint16(n.TCPPort))
if len(b.entries) == bucketSize { rc <- nn
tab.pingReplace(n, b) }(nodes[i])
} else { }
b.entries = append(b.entries, n) for _ = range nodes {
if n := <-rc; n != nil {
result = append(result, n)
} }
} }
return n return result
} }
func (tab *Table) pingReplace(n *Node, b *bucket) { // bond ensures the local node has a bond with the given remote node.
old := b.entries[bucketSize-1] // It also attempts to insert the node into the table if bonding succeeds.
go func() { // The caller must not hold tab.mutex.
if err := tab.net.ping(old); err == nil { //
// it responded, we don't need to replace it. // A bond is must be established before sending findnode requests.
// Both sides must have completed a ping/pong exchange for a bond to
// exist. The total number of active bonding processes is limited in
// order to restrain network use.
//
// bond is meant to operate idempotently in that bonding with a remote
// node which still remembers a previously established bond will work.
// The remote node will simply not send a ping back, causing waitping
// to time out.
//
// If pinged is true, the remote node has just pinged us and one half
// of the process can be skipped.
func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16) (*Node, error) {
var n *Node
if n = tab.db.get(id); n == nil {
tab.bondmu.Lock()
w := tab.bonding[id]
if w != nil {
// Wait for an existing bonding process to complete.
tab.bondmu.Unlock()
<-w.done
} else {
// Register a new bonding process.
w = &bondproc{done: make(chan struct{})}
tab.bonding[id] = w
tab.bondmu.Unlock()
// Do the ping/pong. The result goes into w.
tab.pingpong(w, pinged, id, addr, tcpPort)
// Unregister the process after it's done.
tab.bondmu.Lock()
delete(tab.bonding, id)
tab.bondmu.Unlock()
}
n = w.n
if w.err != nil {
return nil, w.err
}
}
tab.mutex.Lock()
defer tab.mutex.Unlock()
if b := tab.buckets[logdist(tab.self.ID, n.ID)]; !b.bump(n) {
tab.pingreplace(n, b)
}
return n, nil
}
func (tab *Table) pingpong(w *bondproc, pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16) {
<-tab.bondslots
defer func() { tab.bondslots <- struct{}{} }()
if w.err = tab.net.ping(id, addr); w.err != nil {
close(w.done)
return return
} }
// it didn't respond, replace the node if it is still the oldest node. if !pinged {
tab.mutex.Lock() // Give the remote node a chance to ping us before we start
if len(b.entries) > 0 && b.entries[len(b.entries)-1] == old { // sending findnode requests. If they still remember us,
// slide down other entries and put the new one in front. // waitping will simply time out.
// TODO: insert in correct position to keep the order tab.net.waitping(id)
copy(b.entries[1:], b.entries)
b.entries[0] = n
} }
tab.mutex.Unlock() w.n = tab.db.add(id, addr, tcpPort)
}() close(w.done)
} }
// bump updates the activity timestamp for the given node. func (tab *Table) pingreplace(new *Node, b *bucket) {
// The caller must hold tab.mutex. if len(b.entries) == bucketSize {
func (tab *Table) bump(node NodeID) { oldest := b.entries[bucketSize-1]
tab.buckets[logdist(tab.self.ID, node)].bump(node) if err := tab.net.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
} }
// add puts the entries into the table if their corresponding // add puts the entries into the table if their corresponding
@ -240,17 +323,17 @@ outer:
} }
} }
func (b *bucket) bump(id NodeID) *Node { func (b *bucket) bump(n *Node) bool {
for i, n := range b.entries { for i := range b.entries {
if n.ID == id { if b.entries[i].ID == n.ID {
n.active = time.Now() n.bumpActive()
// move it to the front // move it to the front
copy(b.entries[1:], b.entries[:i+1]) copy(b.entries[1:], b.entries[:i])
b.entries[0] = n b.entries[0] = n
return n return true
} }
} }
return nil return false
} }
// nodesByDistance is a list of nodes, ordered by // nodesByDistance is a list of nodes, ordered by

View file

@ -2,79 +2,110 @@ package discover
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"errors"
"fmt" "fmt"
"math/rand" "math/rand"
"net" "net"
"reflect" "reflect"
"testing" "testing"
"testing/quick" "testing/quick"
"time"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
) )
func TestTable_bumpOrAddBucketAssign(t *testing.T) { func TestTable_pingReplace(t *testing.T) {
tab := newTable(nil, NodeID{}, &net.UDPAddr{}) doit := func(newNodeIsResponding, lastInBucketIsResponding bool) {
for i := 1; i < len(tab.buckets); i++ { transport := newPingRecorder()
tab.bumpOrAdd(randomID(tab.self.ID, i), &net.UDPAddr{}) tab := newTable(transport, NodeID{}, &net.UDPAddr{})
}
for i, b := range tab.buckets {
if i > 0 && len(b.entries) != 1 {
t.Errorf("bucket %d has %d entries, want 1", i, len(b.entries))
}
}
}
func TestTable_bumpOrAddPingReplace(t *testing.T) {
pingC := make(pingC)
tab := newTable(pingC, NodeID{}, &net.UDPAddr{})
last := fillBucket(tab, 200) last := fillBucket(tab, 200)
pingSender := randomID(tab.self.ID, 200)
// this bumpOrAdd should not replace the last node // this gotPing should replace the last node
// because the node replies to ping. // if the last node is not responding.
new := tab.bumpOrAdd(randomID(tab.self.ID, 200), &net.UDPAddr{}) transport.responding[last.ID] = lastInBucketIsResponding
transport.responding[pingSender] = newNodeIsResponding
tab.bond(true, pingSender, &net.UDPAddr{}, 0)
pinged := <-pingC // first ping goes to sender (bonding pingback)
if pinged != last.ID { if !transport.pinged[pingSender] {
t.Fatalf("pinged wrong node: %v\nwant %v", pinged, last.ID) t.Error("table did not ping back sender")
}
if newNodeIsResponding {
// second ping goes to oldest node in bucket
// to see whether it is still alive.
if !transport.pinged[last.ID] {
t.Error("table did not ping last node in bucket")
}
} }
tab.mutex.Lock() tab.mutex.Lock()
defer tab.mutex.Unlock() defer tab.mutex.Unlock()
if l := len(tab.buckets[200].entries); l != bucketSize { if l := len(tab.buckets[200].entries); l != bucketSize {
t.Errorf("wrong bucket size after bumpOrAdd: got %d, want %d", bucketSize, l) t.Errorf("wrong bucket size after gotPing: got %d, want %d", bucketSize, l)
} }
if lastInBucketIsResponding || !newNodeIsResponding {
if !contains(tab.buckets[200].entries, last.ID) { if !contains(tab.buckets[200].entries, last.ID) {
t.Error("last entry was removed") t.Error("last entry was removed")
} }
if contains(tab.buckets[200].entries, new.ID) { if contains(tab.buckets[200].entries, pingSender) {
t.Error("new entry was added") t.Error("new entry was added")
} }
} } else {
func TestTable_bumpOrAddPingTimeout(t *testing.T) {
tab := newTable(pingC(nil), NodeID{}, &net.UDPAddr{})
last := fillBucket(tab, 200)
// this bumpOrAdd should replace the last node
// because the node does not reply to ping.
new := tab.bumpOrAdd(randomID(tab.self.ID, 200), &net.UDPAddr{})
// wait for async bucket update. damn. this needs to go away.
time.Sleep(2 * time.Millisecond)
tab.mutex.Lock()
defer tab.mutex.Unlock()
if l := len(tab.buckets[200].entries); l != bucketSize {
t.Errorf("wrong bucket size after bumpOrAdd: got %d, want %d", bucketSize, l)
}
if contains(tab.buckets[200].entries, last.ID) { if contains(tab.buckets[200].entries, last.ID) {
t.Error("last entry was not removed") t.Error("last entry was not removed")
} }
if !contains(tab.buckets[200].entries, new.ID) { if !contains(tab.buckets[200].entries, pingSender) {
t.Error("new entry was not added") t.Error("new entry was not added")
} }
}
}
doit(true, true)
doit(false, true)
doit(false, true)
doit(false, false)
}
func TestBucket_bumpNoDuplicates(t *testing.T) {
t.Parallel()
cfg := &quick.Config{
MaxCount: 1000,
Rand: quickrand,
Values: func(args []reflect.Value, rand *rand.Rand) {
// generate a random list of nodes. this will be the content of the bucket.
n := rand.Intn(bucketSize-1) + 1
nodes := make([]*Node, n)
for i := range nodes {
nodes[i] = &Node{ID: randomID(NodeID{}, 200)}
}
args[0] = reflect.ValueOf(nodes)
// generate random bump positions.
bumps := make([]int, rand.Intn(100))
for i := range bumps {
bumps[i] = rand.Intn(len(nodes))
}
args[1] = reflect.ValueOf(bumps)
},
}
prop := func(nodes []*Node, bumps []int) (ok bool) {
b := &bucket{entries: make([]*Node, len(nodes))}
copy(b.entries, nodes)
for i, pos := range bumps {
b.bump(b.entries[pos])
if hasDuplicates(b.entries) {
t.Logf("bucket has duplicates after %d/%d bumps:", i+1, len(bumps))
for _, n := range b.entries {
t.Logf(" %p", n)
}
return false
}
}
return true
}
if err := quick.Check(prop, cfg); err != nil {
t.Error(err)
}
} }
func fillBucket(tab *Table, ld int) (last *Node) { func fillBucket(tab *Table, ld int) (last *Node) {
@ -85,44 +116,27 @@ func fillBucket(tab *Table, ld int) (last *Node) {
return b.entries[bucketSize-1] return b.entries[bucketSize-1]
} }
type pingC chan NodeID type pingRecorder struct{ responding, pinged map[NodeID]bool }
func (t pingC) findnode(n *Node, target NodeID) ([]*Node, error) { func newPingRecorder() *pingRecorder {
return &pingRecorder{make(map[NodeID]bool), make(map[NodeID]bool)}
}
func (t *pingRecorder) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) {
panic("findnode called on pingRecorder") panic("findnode called on pingRecorder")
} }
func (t pingC) close() { func (t *pingRecorder) close() {
panic("close called on pingRecorder") panic("close called on pingRecorder")
} }
func (t pingC) ping(n *Node) error { func (t *pingRecorder) waitping(from NodeID) error {
if t == nil { return nil // remote always pings
return errTimeout
}
t <- n.ID
return nil
} }
func (t *pingRecorder) ping(toid NodeID, toaddr *net.UDPAddr) error {
func TestTable_bump(t *testing.T) { t.pinged[toid] = true
tab := newTable(nil, NodeID{}, &net.UDPAddr{}) if t.responding[toid] {
return nil
// add an old entry and two recent ones } else {
oldactive := time.Now().Add(-2 * time.Minute) return errTimeout
old := &Node{ID: randomID(tab.self.ID, 200), active: oldactive}
others := []*Node{
&Node{ID: randomID(tab.self.ID, 200), active: time.Now()},
&Node{ID: randomID(tab.self.ID, 200), active: time.Now()},
}
tab.add(append(others, old))
if tab.buckets[200].entries[0] == old {
t.Fatal("old entry is at front of bucket")
}
// bumping the old entry should move it to the front
tab.bump(old.ID)
if old.active == oldactive {
t.Error("activity timestamp not updated")
}
if tab.buckets[200].entries[0] != old {
t.Errorf("bumped entry did not move to the front of bucket")
} }
} }
@ -210,7 +224,7 @@ func TestTable_Lookup(t *testing.T) {
t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results) t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results)
} }
// seed table with initial node (otherwise lookup will terminate immediately) // seed table with initial node (otherwise lookup will terminate immediately)
tab.bumpOrAdd(randomID(target, 200), &net.UDPAddr{Port: 200}) tab.add([]*Node{newNode(randomID(target, 200), &net.UDPAddr{Port: 200})})
results := tab.Lookup(target) results := tab.Lookup(target)
t.Logf("results:") t.Logf("results:")
@ -238,16 +252,16 @@ type findnodeOracle struct {
target NodeID target NodeID
} }
func (t findnodeOracle) findnode(n *Node, target NodeID) ([]*Node, error) { func (t findnodeOracle) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) {
t.t.Logf("findnode query at dist %d", n.DiscPort) t.t.Logf("findnode query at dist %d", toaddr.Port)
// current log distance is encoded in port number // current log distance is encoded in port number
var result []*Node var result []*Node
switch n.DiscPort { switch toaddr.Port {
case 0: case 0:
panic("query to node at distance 0") panic("query to node at distance 0")
default: default:
// TODO: add more randomness to distances // TODO: add more randomness to distances
next := n.DiscPort - 1 next := toaddr.Port - 1
for i := 0; i < bucketSize; i++ { for i := 0; i < bucketSize; i++ {
result = append(result, &Node{ID: randomID(t.target, next), DiscPort: next}) result = append(result, &Node{ID: randomID(t.target, next), DiscPort: next})
} }
@ -256,10 +270,8 @@ func (t findnodeOracle) findnode(n *Node, target NodeID) ([]*Node, error) {
} }
func (t findnodeOracle) close() {} func (t findnodeOracle) close() {}
func (t findnodeOracle) waitping(from NodeID) error { return nil }
func (t findnodeOracle) ping(n *Node) error { func (t findnodeOracle) ping(toid NodeID, toaddr *net.UDPAddr) error { return nil }
return errors.New("ping is not supported by this transport")
}
func hasDuplicates(slice []*Node) bool { func hasDuplicates(slice []*Node) bool {
seen := make(map[NodeID]bool) seen := make(map[NodeID]bool)

View file

@ -16,11 +16,16 @@ import (
var log = logger.NewLogger("P2P Discovery") var log = logger.NewLogger("P2P Discovery")
const Version = 3
// Errors // Errors
var ( var (
errPacketTooSmall = errors.New("too small") errPacketTooSmall = errors.New("too small")
errBadHash = errors.New("bad hash") errBadHash = errors.New("bad hash")
errExpired = errors.New("expired") errExpired = errors.New("expired")
errBadVersion = errors.New("version mismatch")
errUnsolicitedReply = errors.New("unsolicited reply")
errUnknownNode = errors.New("unknown node")
errTimeout = errors.New("RPC timeout") errTimeout = errors.New("RPC timeout")
errClosed = errors.New("socket closed") errClosed = errors.New("socket closed")
) )
@ -45,6 +50,7 @@ const (
// RPC request structures // RPC request structures
type ( type (
ping struct { ping struct {
Version uint // must match Version
IP string // our IP IP string // our IP
Port uint16 // our port Port uint16 // our port
Expiration uint64 Expiration uint64
@ -76,12 +82,25 @@ type rpcNode struct {
ID NodeID ID NodeID
} }
type packet interface {
handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error
}
type conn interface {
ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error)
WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error)
Close() error
LocalAddr() net.Addr
}
// udp implements the RPC protocol. // udp implements the RPC protocol.
type udp struct { type udp struct {
conn *net.UDPConn conn conn
priv *ecdsa.PrivateKey priv *ecdsa.PrivateKey
addpending chan *pending addpending chan *pending
replies chan reply gotreply chan reply
closing chan struct{} closing chan struct{}
nat nat.Interface nat nat.Interface
@ -120,6 +139,9 @@ type reply struct {
from NodeID from NodeID
ptype byte ptype byte
data interface{} data interface{}
// loop indicates whether there was
// a matching request by sending on this channel.
matched chan<- bool
} }
// ListenUDP returns a new table that listens for UDP packets on laddr. // ListenUDP returns a new table that listens for UDP packets on laddr.
@ -132,15 +154,20 @@ func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface) (*Table
if err != nil { if err != nil {
return nil, err return nil, err
} }
tab, _ := newUDP(priv, conn, natm)
log.Infoln("Listening,", tab.self)
return tab, nil
}
func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface) (*Table, *udp) {
udp := &udp{ udp := &udp{
conn: conn, conn: c,
priv: priv, priv: priv,
closing: make(chan struct{}), closing: make(chan struct{}),
gotreply: make(chan reply),
addpending: make(chan *pending), addpending: make(chan *pending),
replies: make(chan reply),
} }
realaddr := c.LocalAddr().(*net.UDPAddr)
realaddr := conn.LocalAddr().(*net.UDPAddr)
if natm != nil { if natm != nil {
if !realaddr.IP.IsLoopback() { if !realaddr.IP.IsLoopback() {
go nat.Map(natm, udp.closing, "udp", realaddr.Port, realaddr.Port, "ethereum discovery") go nat.Map(natm, udp.closing, "udp", realaddr.Port, realaddr.Port, "ethereum discovery")
@ -151,11 +178,9 @@ func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface) (*Table
} }
} }
udp.Table = newTable(udp, PubkeyID(&priv.PublicKey), realaddr) udp.Table = newTable(udp, PubkeyID(&priv.PublicKey), realaddr)
go udp.loop() go udp.loop()
go udp.readLoop() go udp.readLoop()
log.Infoln("Listening, ", udp.self) return udp.Table, udp
return udp.Table, nil
} }
func (t *udp) close() { func (t *udp) close() {
@ -165,10 +190,11 @@ func (t *udp) close() {
} }
// ping sends a ping message to the given node and waits for a reply. // ping sends a ping message to the given node and waits for a reply.
func (t *udp) ping(e *Node) error { func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error {
// TODO: maybe check for ReplyTo field in callback to measure RTT // TODO: maybe check for ReplyTo field in callback to measure RTT
errc := t.pending(e.ID, pongPacket, func(interface{}) bool { return true }) errc := t.pending(toid, pongPacket, func(interface{}) bool { return true })
t.send(e, pingPacket, ping{ t.send(toaddr, pingPacket, ping{
Version: Version,
IP: t.self.IP.String(), IP: t.self.IP.String(),
Port: uint16(t.self.TCPPort), Port: uint16(t.self.TCPPort),
Expiration: uint64(time.Now().Add(expiration).Unix()), Expiration: uint64(time.Now().Add(expiration).Unix()),
@ -176,12 +202,16 @@ func (t *udp) ping(e *Node) error {
return <-errc return <-errc
} }
func (t *udp) waitping(from NodeID) error {
return <-t.pending(from, pingPacket, func(interface{}) bool { return true })
}
// findnode sends a findnode request to the given node and waits until // findnode sends a findnode request to the given node and waits until
// the node has sent up to k neighbors. // the node has sent up to k neighbors.
func (t *udp) findnode(to *Node, target NodeID) ([]*Node, error) { func (t *udp) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) {
nodes := make([]*Node, 0, bucketSize) nodes := make([]*Node, 0, bucketSize)
nreceived := 0 nreceived := 0
errc := t.pending(to.ID, neighborsPacket, func(r interface{}) bool { errc := t.pending(toid, neighborsPacket, func(r interface{}) bool {
reply := r.(*neighbors) reply := r.(*neighbors)
for _, n := range reply.Nodes { for _, n := range reply.Nodes {
nreceived++ nreceived++
@ -191,8 +221,7 @@ func (t *udp) findnode(to *Node, target NodeID) ([]*Node, error) {
} }
return nreceived >= bucketSize return nreceived >= bucketSize
}) })
t.send(toaddr, findnodePacket, findnode{
t.send(to, findnodePacket, findnode{
Target: target, Target: target,
Expiration: uint64(time.Now().Add(expiration).Unix()), Expiration: uint64(time.Now().Add(expiration).Unix()),
}) })
@ -214,6 +243,17 @@ func (t *udp) pending(id NodeID, ptype byte, callback func(interface{}) bool) <-
return ch return ch
} }
func (t *udp) handleReply(from NodeID, ptype byte, req packet) bool {
matched := make(chan bool)
select {
case t.gotreply <- reply{from, ptype, req, matched}:
// loop will handle it
return <-matched
case <-t.closing:
return false
}
}
// loop runs in its own goroutin. it keeps track of // loop runs in its own goroutin. it keeps track of
// the refresh timer and the pending reply queue. // the refresh timer and the pending reply queue.
func (t *udp) loop() { func (t *udp) loop() {
@ -244,6 +284,7 @@ func (t *udp) loop() {
for _, p := range pending { for _, p := range pending {
p.errc <- errClosed p.errc <- errClosed
} }
pending = nil
return return
case p := <-t.addpending: case p := <-t.addpending:
@ -251,18 +292,21 @@ func (t *udp) loop() {
pending = append(pending, p) pending = append(pending, p)
rearmTimeout() rearmTimeout()
case reply := <-t.replies: case r := <-t.gotreply:
// run matching callbacks, remove if they return false. var matched bool
for i := 0; i < len(pending); i++ { for i := 0; i < len(pending); i++ {
p := pending[i] if p := pending[i]; p.from == r.from && p.ptype == r.ptype {
if reply.from == p.from && reply.ptype == p.ptype && p.callback(reply.data) { matched = true
if p.callback(r.data) {
// callback indicates the request is done, remove it.
p.errc <- nil p.errc <- nil
copy(pending[i:], pending[i+1:]) copy(pending[i:], pending[i+1:])
pending = pending[:len(pending)-1] pending = pending[:len(pending)-1]
i-- i--
} }
} }
rearmTimeout() }
r.matched <- matched
case now := <-timeout.C: case now := <-timeout.C:
// notify and remove callbacks whose deadline is in the past. // notify and remove callbacks whose deadline is in the past.
@ -287,28 +331,11 @@ const (
var headSpace = make([]byte, headSize) var headSpace = make([]byte, headSize)
func (t *udp) send(to *Node, ptype byte, req interface{}) error { func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req interface{}) error {
b := new(bytes.Buffer) packet, err := encodePacket(t.priv, ptype, req)
b.Write(headSpace)
b.WriteByte(ptype)
if err := rlp.Encode(b, req); err != nil {
log.Errorln("error encoding packet:", err)
return err
}
packet := b.Bytes()
sig, err := crypto.Sign(crypto.Sha3(packet[headSize:]), t.priv)
if err != nil { if err != nil {
log.Errorln("could not sign packet:", err)
return err return err
} }
copy(packet[macSize:], sig)
// add the hash to the front. Note: this doesn't protect the
// packet in any way. Our public key will be part of this hash in
// the future.
copy(packet, crypto.Sha3(packet[macSize:]))
toaddr := &net.UDPAddr{IP: to.IP, Port: to.DiscPort}
log.DebugDetailf(">>> %v %T %v\n", toaddr, req, req) log.DebugDetailf(">>> %v %T %v\n", toaddr, req, req)
if _, err = t.conn.WriteToUDP(packet, toaddr); err != nil { if _, err = t.conn.WriteToUDP(packet, toaddr); err != nil {
log.DebugDetailln("UDP send failed:", err) log.DebugDetailln("UDP send failed:", err)
@ -316,6 +343,28 @@ func (t *udp) send(to *Node, ptype byte, req interface{}) error {
return err return err
} }
func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) ([]byte, error) {
b := new(bytes.Buffer)
b.Write(headSpace)
b.WriteByte(ptype)
if err := rlp.Encode(b, req); err != nil {
log.Errorln("error encoding packet:", err)
return nil, err
}
packet := b.Bytes()
sig, err := crypto.Sign(crypto.Sha3(packet[headSize:]), priv)
if err != nil {
log.Errorln("could not sign packet:", err)
return nil, err
}
copy(packet[macSize:], sig)
// add the hash to the front. Note: this doesn't protect the
// packet in any way. Our public key will be part of this hash in
// The future.
copy(packet, crypto.Sha3(packet[macSize:]))
return packet, nil
}
// readLoop runs in its own goroutine. it handles incoming UDP packets. // readLoop runs in its own goroutine. it handles incoming UDP packets.
func (t *udp) readLoop() { func (t *udp) readLoop() {
defer t.conn.Close() defer t.conn.Close()
@ -325,29 +374,34 @@ func (t *udp) readLoop() {
if err != nil { if err != nil {
return return
} }
if err := t.packetIn(from, buf[:nbytes]); err != nil { packet, fromID, hash, err := decodePacket(buf[:nbytes])
if err != nil {
log.Debugf("Bad packet from %v: %v\n", from, err) log.Debugf("Bad packet from %v: %v\n", from, err)
continue
} }
log.DebugDetailf("<<< %v %T %v\n", from, packet, packet)
go func() {
if err := packet.handle(t, from, fromID, hash); err != nil {
log.Debugf("error handling %T from %v: %v", packet, from, err)
}
}()
} }
} }
func (t *udp) packetIn(from *net.UDPAddr, buf []byte) error { func decodePacket(buf []byte) (packet, NodeID, []byte, error) {
if len(buf) < headSize+1 { if len(buf) < headSize+1 {
return errPacketTooSmall return nil, NodeID{}, nil, errPacketTooSmall
} }
hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:] hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:]
shouldhash := crypto.Sha3(buf[macSize:]) shouldhash := crypto.Sha3(buf[macSize:])
if !bytes.Equal(hash, shouldhash) { if !bytes.Equal(hash, shouldhash) {
return errBadHash return nil, NodeID{}, nil, errBadHash
} }
fromID, err := recoverNodeID(crypto.Sha3(buf[headSize:]), sig) fromID, err := recoverNodeID(crypto.Sha3(buf[headSize:]), sig)
if err != nil { if err != nil {
return err return nil, NodeID{}, hash, err
}
var req interface {
handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error
} }
var req packet
switch ptype := sigdata[0]; ptype { switch ptype := sigdata[0]; ptype {
case pingPacket: case pingPacket:
req = new(ping) req = new(ping)
@ -358,31 +412,27 @@ func (t *udp) packetIn(from *net.UDPAddr, buf []byte) error {
case neighborsPacket: case neighborsPacket:
req = new(neighbors) req = new(neighbors)
default: default:
return fmt.Errorf("unknown type: %d", ptype) return nil, fromID, hash, fmt.Errorf("unknown type: %d", ptype)
} }
if err := rlp.Decode(bytes.NewReader(sigdata[1:]), req); err != nil { err = rlp.Decode(bytes.NewReader(sigdata[1:]), req)
return err return req, fromID, hash, err
}
log.DebugDetailf("<<< %v %T %v\n", from, req, req)
return req.handle(t, from, fromID, hash)
} }
func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
if expired(req.Expiration) { if expired(req.Expiration) {
return errExpired return errExpired
} }
t.mutex.Lock() if req.Version != Version {
// Note: we're ignoring the provided IP address right now return errBadVersion
n := t.bumpOrAdd(fromID, from)
if req.Port != 0 {
n.TCPPort = int(req.Port)
} }
t.mutex.Unlock() t.send(from, pongPacket, pong{
t.send(n, pongPacket, pong{
ReplyTok: mac, ReplyTok: mac,
Expiration: uint64(time.Now().Add(expiration).Unix()), Expiration: uint64(time.Now().Add(expiration).Unix()),
}) })
if !t.handleReply(fromID, pingPacket, req) {
// Note: we're ignoring the provided IP address right now
t.bond(true, fromID, from, req.Port)
}
return nil return nil
} }
@ -390,11 +440,9 @@ func (req *pong) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) er
if expired(req.Expiration) { if expired(req.Expiration) {
return errExpired return errExpired
} }
t.mutex.Lock() if !t.handleReply(fromID, pongPacket, req) {
t.bump(fromID) return errUnsolicitedReply
t.mutex.Unlock() }
t.replies <- reply{fromID, pongPacket, req}
return nil return nil
} }
@ -402,12 +450,21 @@ func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte
if expired(req.Expiration) { if expired(req.Expiration) {
return errExpired return errExpired
} }
if t.db.get(fromID) == nil {
// No bond exists, we don't process the packet. This prevents
// an attack vector where the discovery protocol could be used
// to amplify traffic in a DDOS attack. A malicious actor
// would send a findnode request with the IP address and UDP
// port of the target as the source address. The recipient of
// the findnode packet would then send a neighbors packet
// (which is a much bigger packet than findnode) to the victim.
return errUnknownNode
}
t.mutex.Lock() t.mutex.Lock()
e := t.bumpOrAdd(fromID, from)
closest := t.closest(req.Target, bucketSize).entries closest := t.closest(req.Target, bucketSize).entries
t.mutex.Unlock() t.mutex.Unlock()
t.send(e, neighborsPacket, neighbors{ t.send(from, neighborsPacket, neighbors{
Nodes: closest, Nodes: closest,
Expiration: uint64(time.Now().Add(expiration).Unix()), Expiration: uint64(time.Now().Add(expiration).Unix()),
}) })
@ -418,12 +475,9 @@ func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byt
if expired(req.Expiration) { if expired(req.Expiration) {
return errExpired return errExpired
} }
t.mutex.Lock() if !t.handleReply(fromID, neighborsPacket, req) {
t.bump(fromID) return errUnsolicitedReply
t.add(req.Nodes) }
t.mutex.Unlock()
t.replies <- reply{fromID, neighborsPacket, req}
return nil return nil
} }

View file

@ -1,10 +1,18 @@
package discover package discover
import ( import (
"bytes"
"crypto/ecdsa"
"errors"
"fmt" "fmt"
"io"
logpkg "log" logpkg "log"
"net" "net"
"os" "os"
"path"
"reflect"
"runtime"
"sync"
"testing" "testing"
"time" "time"
@ -15,22 +23,243 @@ func init() {
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, logpkg.LstdFlags, logger.ErrorLevel)) logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, logpkg.LstdFlags, logger.ErrorLevel))
} }
func TestUDP_ping(t *testing.T) { type udpTest struct {
t *testing.T
pipe *dgramPipe
table *Table
udp *udp
sent [][]byte
localkey, remotekey *ecdsa.PrivateKey
remoteaddr *net.UDPAddr
}
func newUDPTest(t *testing.T) *udpTest {
test := &udpTest{
t: t,
pipe: newpipe(),
localkey: newkey(),
remotekey: newkey(),
remoteaddr: &net.UDPAddr{IP: net.IP{1, 2, 3, 4}, Port: 30303},
}
test.table, test.udp = newUDP(test.localkey, test.pipe, nil)
return test
}
// handles a packet as if it had been sent to the transport.
func (test *udpTest) packetIn(wantError error, ptype byte, data packet) error {
enc, err := encodePacket(test.remotekey, ptype, data)
if err != nil {
return test.errorf("packet (%d) encode error: %v", err)
}
test.sent = append(test.sent, enc)
err = data.handle(test.udp, test.remoteaddr, PubkeyID(&test.remotekey.PublicKey), enc[:macSize])
if err != wantError {
return test.errorf("error mismatch: got %q, want %q", err, wantError)
}
return nil
}
// waits for a packet to be sent by the transport.
// validate should have type func(*udpTest, X) error, where X is a packet type.
func (test *udpTest) waitPacketOut(validate interface{}) error {
dgram := test.pipe.waitPacketOut()
p, _, _, err := decodePacket(dgram)
if err != nil {
return test.errorf("sent packet decode error: %v", err)
}
fn := reflect.ValueOf(validate)
exptype := fn.Type().In(0)
if reflect.TypeOf(p) != exptype {
return test.errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype)
}
fn.Call([]reflect.Value{reflect.ValueOf(p)})
return nil
}
func (test *udpTest) errorf(format string, args ...interface{}) error {
_, file, line, ok := runtime.Caller(2) // errorf + waitPacketOut
if ok {
file = path.Base(file)
} else {
file = "???"
line = 1
}
err := fmt.Errorf(format, args...)
fmt.Printf("\t%s:%d: %v\n", file, line, err)
test.t.Fail()
return err
}
// shared test variables
var (
futureExp = uint64(time.Now().Add(10 * time.Hour).Unix())
testTarget = MustHexID("01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101")
)
func TestUDP_packetErrors(t *testing.T) {
test := newUDPTest(t)
defer test.table.Close()
test.packetIn(errExpired, pingPacket, &ping{IP: "foo", Port: 99, Version: Version})
test.packetIn(errBadVersion, pingPacket, &ping{IP: "foo", Port: 99, Version: 99, Expiration: futureExp})
test.packetIn(errUnsolicitedReply, pongPacket, &pong{ReplyTok: []byte{}, Expiration: futureExp})
test.packetIn(errUnknownNode, findnodePacket, &findnode{Expiration: futureExp})
test.packetIn(errUnsolicitedReply, neighborsPacket, &neighbors{Expiration: futureExp})
}
func TestUDP_pingTimeout(t *testing.T) {
t.Parallel() t.Parallel()
test := newUDPTest(t)
defer test.table.Close()
n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222}
n2, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) toid := NodeID{1, 2, 3, 4}
defer n1.Close() if err := test.udp.ping(toid, toaddr); err != errTimeout {
defer n2.Close() t.Error("expected timeout error, got", err)
}
}
if err := n1.net.ping(n2.self); err != nil { func TestUDP_findnodeTimeout(t *testing.T) {
t.Fatalf("ping error: %v", err) t.Parallel()
test := newUDPTest(t)
defer test.table.Close()
toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222}
toid := NodeID{1, 2, 3, 4}
target := NodeID{4, 5, 6, 7}
result, err := test.udp.findnode(toid, toaddr, target)
if err != errTimeout {
t.Error("expected timeout error, got", err)
} }
if find(n2, n1.self.ID) == nil { if len(result) > 0 {
t.Errorf("node 2 does not contain id of node 1") t.Error("expected empty result, got", result)
} }
if e := find(n1, n2.self.ID); e != nil { }
t.Errorf("node 1 does contains id of node 2: %v", e)
func TestUDP_findnode(t *testing.T) {
test := newUDPTest(t)
defer test.table.Close()
// put a few nodes into the table. their exact
// distribution shouldn't matter much, altough we need to
// take care not to overflow any bucket.
target := testTarget
nodes := &nodesByDistance{target: target}
for i := 0; i < bucketSize; i++ {
nodes.push(&Node{
IP: net.IP{1, 2, 3, byte(i)},
DiscPort: i + 2,
TCPPort: i + 2,
ID: randomID(test.table.self.ID, i+2),
}, bucketSize)
}
test.table.add(nodes.entries)
// ensure there's a bond with the test node,
// findnode won't be accepted otherwise.
test.table.db.add(PubkeyID(&test.remotekey.PublicKey), test.remoteaddr, 99)
// check that closest neighbors are returned.
test.packetIn(nil, findnodePacket, &findnode{Target: testTarget, Expiration: futureExp})
test.waitPacketOut(func(p *neighbors) {
expected := test.table.closest(testTarget, bucketSize)
if len(p.Nodes) != bucketSize {
t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), bucketSize)
}
for i := range p.Nodes {
if p.Nodes[i].ID != expected.entries[i].ID {
t.Errorf("result mismatch at %d:\n got: %v\n want: %v", i, p.Nodes[i], expected.entries[i])
}
}
})
}
func TestUDP_findnodeMultiReply(t *testing.T) {
test := newUDPTest(t)
defer test.table.Close()
// queue a pending findnode request
resultc, errc := make(chan []*Node), make(chan error)
go func() {
rid := PubkeyID(&test.remotekey.PublicKey)
ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget)
if err != nil && len(ns) == 0 {
errc <- err
} else {
resultc <- ns
}
}()
// wait for the findnode to be sent.
// after it is sent, the transport is waiting for a reply
test.waitPacketOut(func(p *findnode) {
if p.Target != testTarget {
t.Errorf("wrong target: got %v, want %v", p.Target, testTarget)
}
})
// send the reply as two packets.
list := []*Node{
MustParseNode("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303"),
MustParseNode("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303"),
MustParseNode("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301"),
MustParseNode("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303"),
}
test.packetIn(nil, neighborsPacket, &neighbors{Expiration: futureExp, Nodes: list[:2]})
test.packetIn(nil, neighborsPacket, &neighbors{Expiration: futureExp, Nodes: list[2:]})
// check that the sent neighbors are all returned by findnode
select {
case result := <-resultc:
if !reflect.DeepEqual(result, list) {
t.Errorf("neighbors mismatch:\n got: %v\n want: %v", result, list)
}
case err := <-errc:
t.Errorf("findnode error: %v", err)
case <-time.After(5 * time.Second):
t.Error("findnode did not return within 5 seconds")
}
}
func TestUDP_successfulPing(t *testing.T) {
test := newUDPTest(t)
defer test.table.Close()
done := make(chan struct{})
go func() {
test.packetIn(nil, pingPacket, &ping{IP: "foo", Port: 99, Version: Version, Expiration: futureExp})
close(done)
}()
// the ping is replied to.
test.waitPacketOut(func(p *pong) {
pinghash := test.sent[0][:macSize]
if !bytes.Equal(p.ReplyTok, pinghash) {
t.Errorf("got ReplyTok %x, want %x", p.ReplyTok, pinghash)
}
})
// remote is unknown, the table pings back.
test.waitPacketOut(func(p *ping) error { return nil })
test.packetIn(nil, pongPacket, &pong{Expiration: futureExp})
// ping should return shortly after getting the pong packet.
<-done
// check that the node was added.
rid := PubkeyID(&test.remotekey.PublicKey)
rnode := find(test.table, rid)
if rnode == nil {
t.Fatalf("node %v not found in table", rid)
}
if !bytes.Equal(rnode.IP, test.remoteaddr.IP) {
t.Errorf("node has wrong IP: got %v, want: %v", rnode.IP, test.remoteaddr.IP)
}
if rnode.DiscPort != test.remoteaddr.Port {
t.Errorf("node has wrong Port: got %v, want: %v", rnode.DiscPort, test.remoteaddr.Port)
}
if rnode.TCPPort != 99 {
t.Errorf("node has wrong Port: got %v, want: %v", rnode.TCPPort, 99)
} }
} }
@ -45,167 +274,66 @@ func find(tab *Table, id NodeID) *Node {
return nil return nil
} }
func TestUDP_findnode(t *testing.T) { // dgramPipe is a fake UDP socket. It queues all sent datagrams.
t.Parallel() type dgramPipe struct {
mu *sync.Mutex
cond *sync.Cond
closing chan struct{}
closed bool
queue [][]byte
}
n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) func newpipe() *dgramPipe {
n2, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) mu := new(sync.Mutex)
defer n1.Close() return &dgramPipe{
defer n2.Close() closing: make(chan struct{}),
cond: &sync.Cond{L: mu},
// put a few nodes into n2. the exact distribution shouldn't mu: mu,
// matter much, altough we need to take care not to overflow
// any bucket.
target := randomID(n1.self.ID, 100)
nodes := &nodesByDistance{target: target}
for i := 0; i < bucketSize; i++ {
n2.add([]*Node{&Node{
IP: net.IP{1, 2, 3, byte(i)},
DiscPort: i + 2,
TCPPort: i + 2,
ID: randomID(n2.self.ID, i+2),
}})
}
n2.add(nodes.entries)
n2.bumpOrAdd(n1.self.ID, &net.UDPAddr{IP: n1.self.IP, Port: n1.self.DiscPort})
expected := n2.closest(target, bucketSize)
err := runUDP(10, func() error {
result, _ := n1.net.findnode(n2.self, target)
if len(result) != bucketSize {
return fmt.Errorf("wrong number of results: got %d, want %d", len(result), bucketSize)
}
for i := range result {
if result[i].ID != expected.entries[i].ID {
return fmt.Errorf("result mismatch at %d:\n got: %v\n want: %v", i, result[i], expected.entries[i])
}
}
return nil
})
if err != nil {
t.Error(err)
} }
} }
func TestUDP_replytimeout(t *testing.T) { // WriteToUDP queues a datagram.
t.Parallel() func (c *dgramPipe) WriteToUDP(b []byte, to *net.UDPAddr) (n int, err error) {
msg := make([]byte, len(b))
// reserve a port so we don't talk to an existing service by accident copy(msg, b)
addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:0") c.mu.Lock()
fd, err := net.ListenUDP("udp", addr) defer c.mu.Unlock()
if err != nil { if c.closed {
t.Fatal(err) return 0, errors.New("closed")
}
defer fd.Close()
n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil)
defer n1.Close()
n2 := n1.bumpOrAdd(randomID(n1.self.ID, 10), fd.LocalAddr().(*net.UDPAddr))
if err := n1.net.ping(n2); err != errTimeout {
t.Error("expected timeout error, got", err)
}
if result, err := n1.net.findnode(n2, n1.self.ID); err != errTimeout {
t.Error("expected timeout error, got", err)
} else if len(result) > 0 {
t.Error("expected empty result, got", result)
} }
c.queue = append(c.queue, msg)
c.cond.Signal()
return len(b), nil
} }
func TestUDP_findnodeMultiReply(t *testing.T) { // ReadFromUDP just hangs until the pipe is closed.
t.Parallel() func (c *dgramPipe) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
<-c.closing
n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) return 0, nil, io.EOF
n2, _ := ListenUDP(newkey(), "127.0.0.1:0", nil)
udp2 := n2.net.(*udp)
defer n1.Close()
defer n2.Close()
err := runUDP(10, func() error {
nodes := make([]*Node, bucketSize)
for i := range nodes {
nodes[i] = &Node{
IP: net.IP{1, 2, 3, 4},
DiscPort: i + 1,
TCPPort: i + 1,
ID: randomID(n2.self.ID, i+1),
}
}
// ask N2 for neighbors. it will send an empty reply back.
// the request will wait for up to bucketSize replies.
resultc := make(chan []*Node)
errc := make(chan error)
go func() {
ns, err := n1.net.findnode(n2.self, n1.self.ID)
if err != nil {
errc <- err
} else {
resultc <- ns
}
}()
// send a few more neighbors packets to N1.
// it should collect those.
for end := 0; end < len(nodes); {
off := end
if end = end + 5; end > len(nodes) {
end = len(nodes)
}
udp2.send(n1.self, neighborsPacket, neighbors{
Nodes: nodes[off:end],
Expiration: uint64(time.Now().Add(10 * time.Second).Unix()),
})
}
// check that they are all returned. we cannot just check for
// equality because they might not be returned in the order they
// were sent.
var result []*Node
select {
case result = <-resultc:
case err := <-errc:
return err
}
if hasDuplicates(result) {
return fmt.Errorf("result slice contains duplicates")
}
if len(result) != len(nodes) {
return fmt.Errorf("wrong number of nodes returned: got %d, want %d", len(result), len(nodes))
}
matched := make(map[NodeID]bool)
for _, n := range result {
for _, expn := range nodes {
if n.ID == expn.ID { // && bytes.Equal(n.Addr.IP, expn.Addr.IP) && n.Addr.Port == expn.Addr.Port {
matched[n.ID] = true
}
}
}
if len(matched) != len(nodes) {
return fmt.Errorf("wrong number of matching nodes: got %d, want %d", len(matched), len(nodes))
}
return nil
})
if err != nil {
t.Error(err)
}
} }
// runUDP runs a test n times and returns an error if the test failed func (c *dgramPipe) Close() error {
// in all n runs. This is necessary because UDP is unreliable even for c.mu.Lock()
// connections on the local machine, causing test failures. defer c.mu.Unlock()
func runUDP(n int, test func() error) error { if !c.closed {
errcount := 0 close(c.closing)
errors := "" c.closed = true
for i := 0; i < n; i++ {
if err := test(); err != nil {
errors += fmt.Sprintf("\n#%d: %v", i, err)
errcount++
}
}
if errcount == n {
return fmt.Errorf("failed on all %d iterations:%s", n, errors)
} }
return nil return nil
} }
func (c *dgramPipe) LocalAddr() net.Addr {
return &net.UDPAddr{}
}
func (c *dgramPipe) waitPacketOut() []byte {
c.mu.Lock()
defer c.mu.Unlock()
for len(c.queue) == 0 {
c.cond.Wait()
}
p := c.queue[0]
copy(c.queue, c.queue[1:])
c.queue = c.queue[:len(c.queue)-1]
return p
}

54
params/protocol_params.go Executable file
View file

@ -0,0 +1,54 @@
// DO NOT EDIT!!!
// AUTOGENERATED FROM generators/defaults.go
package params
import "math/big"
var (
MaximumExtraDataSize = big.NewInt(1024) // Maximum size extra data may be after Genesis.
ExpByteGas = big.NewInt(10) // Times ceil(log256(exponent)) for the EXP instruction.
SloadGas = big.NewInt(50) // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
CallValueTransferGas = big.NewInt(9000) // Paid for CALL when the value transfor is non-zero.
CallNewAccountGas = big.NewInt(25000) // Paid for CALL when the destination address didn't exist prior.
TxGas = big.NewInt(21000) // Per transaction. NOTE: Not payable on data of calls between transactions.
TxDataZeroGas = big.NewInt(4) // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations.
QuadCoeffDiv = big.NewInt(512) // Divisor for the quadratic particle of the memory cost equation.
GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
DurationLimit = big.NewInt(8) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
SstoreSetGas = big.NewInt(20000) // Once per SLOAD operation.
LogDataGas = big.NewInt(8) // Per byte in a LOG* operation's data.
CallStipend = big.NewInt(2300) // Free gas given at beginning of call.
EcrecoverGas = big.NewInt(3000) //
Sha256WordGas = big.NewInt(12) //
MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be.
Sha3Gas = big.NewInt(30) // Once per SHA3 operation.
Sha256Gas = big.NewInt(60) //
IdentityWordGas = big.NewInt(3) //
Sha3WordGas = big.NewInt(6) // Once per word of the SHA3 operation's data.
SstoreResetGas = big.NewInt(5000) // Once per SSTORE operation if the zeroness changes from zero.
SstoreClearGas = big.NewInt(5000) // Once per SSTORE operation if the zeroness doesn't change.
SstoreRefundGas = big.NewInt(15000) // Once per SSTORE operation if the zeroness changes to zero.
JumpdestGas = big.NewInt(1) // Refunded gas, once per SSTORE operation if the zeroness changes to zero.
IdentityGas = big.NewInt(15) //
GasLimitBoundDivisor = big.NewInt(1024) // The bound divisor of the gas limit, used in update calculations.
EpochDuration = big.NewInt(30000) // Duration between proof-of-work epochs.
CallGas = big.NewInt(40) // Once per CALL operation & message call transaction.
CreateDataGas = big.NewInt(200) //
Ripemd160Gas = big.NewInt(600) //
Ripemd160WordGas = big.NewInt(120) //
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
CallCreateDepth = big.NewInt(1024) // Maximum depth of call/create stack.
ExpGas = big.NewInt(10) // Once per EXP instuction.
LogGas = big.NewInt(375) // Per LOG* operation.
CopyGas = big.NewInt(3) //
StackLimit = big.NewInt(1024) // Maximum size of VM stack allowed.
TierStepGas = big.NewInt(0) // Once per operation, for a selection of them.
LogTopicGas = big.NewInt(375) // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
CreateGas = big.NewInt(32000) // Once per CREATE operation & contract-creation transaction.
SuicideRefundGas = big.NewInt(24000) // Refunded following a suicide operation.
MemoryGas = big.NewInt(3) // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
TxDataNonZeroGas = big.NewInt(68) // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
)

View file

@ -54,7 +54,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
case "net_peerCount": case "net_peerCount":
v := api.xeth().PeerCount() v := api.xeth().PeerCount()
*reply = common.ToHex(big.NewInt(int64(v)).Bytes()) *reply = common.ToHex(big.NewInt(int64(v)).Bytes())
case "eth_version": case "eth_protocolVersion":
*reply = api.xeth().EthVersion() *reply = api.xeth().EthVersion()
case "eth_coinbase": case "eth_coinbase":
// TODO handling of empty coinbase due to lack of accounts // TODO handling of empty coinbase due to lack of accounts
@ -95,10 +95,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
return err return err
} }
state := api.xethAtStateNum(args.BlockNumber).State().SafeGet(args.Address) *reply = api.xethAtStateNum(args.BlockNumber).StorageAt(args.Address, args.Key)
value := state.StorageString(args.Key)
*reply = common.ToHex(value.Bytes())
case "eth_getTransactionCount": case "eth_getTransactionCount":
args := new(GetTxCountArgs) args := new(GetTxCountArgs)
if err := json.Unmarshal(req.Params, &args); err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
@ -113,7 +110,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
return err return err
} }
block := NewBlockRes(api.xeth().EthBlockByHash(args.BlockHash)) block := NewBlockRes(api.xeth().EthBlockByHash(args.BlockHash), false)
*reply = common.ToHex(big.NewInt(int64(len(block.Transactions))).Bytes()) *reply = common.ToHex(big.NewInt(int64(len(block.Transactions))).Bytes())
case "eth_getBlockTransactionCountByNumber": case "eth_getBlockTransactionCountByNumber":
args := new(GetBlockByNumberArgs) args := new(GetBlockByNumberArgs)
@ -121,7 +118,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
return err return err
} }
block := NewBlockRes(api.xeth().EthBlockByNumber(args.BlockNumber)) block := NewBlockRes(api.xeth().EthBlockByNumber(args.BlockNumber), false)
*reply = common.ToHex(big.NewInt(int64(len(block.Transactions))).Bytes()) *reply = common.ToHex(big.NewInt(int64(len(block.Transactions))).Bytes())
case "eth_getUncleCountByBlockHash": case "eth_getUncleCountByBlockHash":
args := new(GetBlockByHashArgs) args := new(GetBlockByHashArgs)
@ -130,7 +127,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
} }
block := api.xeth().EthBlockByHash(args.BlockHash) block := api.xeth().EthBlockByHash(args.BlockHash)
br := NewBlockRes(block) br := NewBlockRes(block, false)
*reply = common.ToHex(big.NewInt(int64(len(br.Uncles))).Bytes()) *reply = common.ToHex(big.NewInt(int64(len(br.Uncles))).Bytes())
case "eth_getUncleCountByBlockNumber": case "eth_getUncleCountByBlockNumber":
args := new(GetBlockByNumberArgs) args := new(GetBlockByNumberArgs)
@ -139,7 +136,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
} }
block := api.xeth().EthBlockByNumber(args.BlockNumber) block := api.xeth().EthBlockByNumber(args.BlockNumber)
br := NewBlockRes(block) br := NewBlockRes(block, false)
*reply = common.ToHex(big.NewInt(int64(len(br.Uncles))).Bytes()) *reply = common.ToHex(big.NewInt(int64(len(br.Uncles))).Bytes())
case "eth_getData", "eth_getCode": case "eth_getData", "eth_getCode":
args := new(GetDataArgs) args := new(GetDataArgs)
@ -159,7 +156,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
} }
*reply = v *reply = v
case "eth_call": case "eth_call":
args := new(NewTxArgs) args := new(CallArgs)
if err := json.Unmarshal(req.Params, &args); err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
@ -179,8 +176,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
} }
block := api.xeth().EthBlockByHash(args.BlockHash) block := api.xeth().EthBlockByHash(args.BlockHash)
br := NewBlockRes(block) br := NewBlockRes(block, true)
br.fullTx = args.IncludeTxs
*reply = br *reply = br
case "eth_getBlockByNumber": case "eth_getBlockByNumber":
@ -190,8 +186,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
} }
block := api.xeth().EthBlockByNumber(args.BlockNumber) block := api.xeth().EthBlockByNumber(args.BlockNumber)
br := NewBlockRes(block) br := NewBlockRes(block, true)
br.fullTx = args.IncludeTxs
*reply = br *reply = br
case "eth_getTransactionByHash": case "eth_getTransactionByHash":
@ -199,9 +194,13 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
args := new(HashIndexArgs) args := new(HashIndexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
} }
tx := api.xeth().EthTransactionByHash(args.Hash) tx, bhash, bnum, txi := api.xeth().EthTransactionByHash(args.Hash)
if tx != nil { if tx != nil {
*reply = NewTransactionRes(tx) v := NewTransactionRes(tx)
v.BlockHash = newHexData(bhash)
v.BlockNumber = newHexNum(bnum)
v.TxIndex = newHexNum(txi)
*reply = v
} }
case "eth_getTransactionByBlockHashAndIndex": case "eth_getTransactionByBlockHashAndIndex":
args := new(HashIndexArgs) args := new(HashIndexArgs)
@ -210,10 +209,9 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
} }
block := api.xeth().EthBlockByHash(args.Hash) block := api.xeth().EthBlockByHash(args.Hash)
br := NewBlockRes(block) br := NewBlockRes(block, true)
br.fullTx = true
if args.Index > int64(len(br.Transactions)) || args.Index < 0 { if args.Index >= int64(len(br.Transactions)) || args.Index < 0 {
return NewValidationError("Index", "does not exist") return NewValidationError("Index", "does not exist")
} }
*reply = br.Transactions[args.Index] *reply = br.Transactions[args.Index]
@ -224,10 +222,9 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
} }
block := api.xeth().EthBlockByNumber(args.BlockNumber) block := api.xeth().EthBlockByNumber(args.BlockNumber)
v := NewBlockRes(block) v := NewBlockRes(block, true)
v.fullTx = true
if args.Index > int64(len(v.Transactions)) || args.Index < 0 { if args.Index >= int64(len(v.Transactions)) || args.Index < 0 {
return NewValidationError("Index", "does not exist") return NewValidationError("Index", "does not exist")
} }
*reply = v.Transactions[args.Index] *reply = v.Transactions[args.Index]
@ -237,14 +234,14 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
return err return err
} }
br := NewBlockRes(api.xeth().EthBlockByHash(args.Hash)) br := NewBlockRes(api.xeth().EthBlockByHash(args.Hash), false)
if args.Index > int64(len(br.Uncles)) || args.Index < 0 { if args.Index >= int64(len(br.Uncles)) || args.Index < 0 {
return NewValidationError("Index", "does not exist") return NewValidationError("Index", "does not exist")
} }
uhash := br.Uncles[args.Index] uhash := br.Uncles[args.Index]
uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.Hex())) uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String()), false)
*reply = uncle *reply = uncle
case "eth_getUncleByBlockNumberAndIndex": case "eth_getUncleByBlockNumberAndIndex":
@ -254,15 +251,14 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
} }
block := api.xeth().EthBlockByNumber(args.BlockNumber) block := api.xeth().EthBlockByNumber(args.BlockNumber)
v := NewBlockRes(block) v := NewBlockRes(block, true)
v.fullTx = true
if args.Index > int64(len(v.Uncles)) || args.Index < 0 { if args.Index >= int64(len(v.Uncles)) || args.Index < 0 {
return NewValidationError("Index", "does not exist") return NewValidationError("Index", "does not exist")
} }
uhash := v.Uncles[args.Index] uhash := v.Uncles[args.Index]
uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.Hex())) uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String()), false)
*reply = uncle *reply = uncle
case "eth_getCompilers": case "eth_getCompilers":

View file

@ -238,6 +238,93 @@ func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
return nil return nil
} }
type CallArgs struct {
From string
To string
Value *big.Int
Gas *big.Int
GasPrice *big.Int
Data string
BlockNumber int64
}
func (args *CallArgs) UnmarshalJSON(b []byte) (err error) {
var obj []json.RawMessage
var ext struct {
From string
To string
Value interface{}
Gas interface{}
GasPrice interface{}
Data string
}
// Decode byte slice to array of RawMessages
if err := json.Unmarshal(b, &obj); err != nil {
return NewDecodeParamError(err.Error())
}
// Check for sufficient params
if len(obj) < 1 {
return NewInsufficientParamsError(len(obj), 1)
}
// Decode 0th RawMessage to temporary struct
if err := json.Unmarshal(obj[0], &ext); err != nil {
return NewDecodeParamError(err.Error())
}
if len(ext.From) == 0 {
return NewValidationError("from", "is required")
}
args.From = ext.From
if len(ext.To) == 0 {
return NewValidationError("to", "is required")
}
args.To = ext.To
var num int64
if ext.Value == nil {
num = int64(0)
} else {
if err := numString(ext.Value, &num); err != nil {
return err
}
}
args.Value = big.NewInt(num)
if ext.Gas == nil {
num = int64(0)
} else {
if err := numString(ext.Gas, &num); err != nil {
return err
}
}
args.Gas = big.NewInt(num)
if ext.GasPrice == nil {
num = int64(0)
} else {
if err := numString(ext.GasPrice, &num); err != nil {
return err
}
}
args.GasPrice = big.NewInt(num)
args.Data = ext.Data
// Check for optional BlockNumber param
if len(obj) > 1 {
if err := blockHeightFromJson(obj[1], &args.BlockNumber); err != nil {
return err
}
}
return nil
}
type GetStorageArgs struct { type GetStorageArgs struct {
Address string Address string
BlockNumber int64 BlockNumber int64

View file

@ -531,14 +531,275 @@ func TestNewTxArgsFromEmpty(t *testing.T) {
input := `[{"to": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]` input := `[{"to": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]`
args := new(NewTxArgs) args := new(NewTxArgs)
err := json.Unmarshal([]byte(input), &args) str := ExpectValidationError(json.Unmarshal([]byte(input), &args))
switch err.(type) { if len(str) > 0 {
case nil: t.Error(str)
t.Error("Expected error but didn't get one") }
case *ValidationError: }
break
default: func TestCallArgs(t *testing.T) {
t.Errorf("Expected *rpc.ValidationError, but got %T with message `%s`", err, err.Error()) input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gas": "0x76c0",
"gasPrice": "0x9184e72a000",
"value": "0x9184e72a000",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"},
"0x10"]`
expected := new(CallArgs)
expected.From = "0xb60e8dd61c5d32be8058bb8eb970870f07233155"
expected.To = "0xd46e8dd67c5d32be8058bb8eb970870f072445675"
expected.Gas = big.NewInt(30400)
expected.GasPrice = big.NewInt(10000000000000)
expected.Value = big.NewInt(10000000000000)
expected.Data = "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
expected.BlockNumber = big.NewInt(16).Int64()
args := new(CallArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if expected.From != args.From {
t.Errorf("From shoud be %#v but is %#v", expected.From, args.From)
}
if expected.To != args.To {
t.Errorf("To shoud be %#v but is %#v", expected.To, args.To)
}
if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 {
t.Errorf("Gas shoud be %#v but is %#v", expected.Gas.Bytes(), args.Gas.Bytes())
}
if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 {
t.Errorf("GasPrice shoud be %#v but is %#v", expected.GasPrice, args.GasPrice)
}
if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 {
t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value)
}
if expected.Data != args.Data {
t.Errorf("Data shoud be %#v but is %#v", expected.Data, args.Data)
}
if expected.BlockNumber != args.BlockNumber {
t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber)
}
}
func TestCallArgsInt(t *testing.T) {
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gas": 100,
"gasPrice": 50,
"value": 8765456789,
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"},
5]`
expected := new(CallArgs)
expected.Gas = big.NewInt(100)
expected.GasPrice = big.NewInt(50)
expected.Value = big.NewInt(8765456789)
expected.BlockNumber = int64(5)
args := new(CallArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 {
t.Errorf("Gas shoud be %v but is %v", expected.Gas, args.Gas)
}
if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 {
t.Errorf("GasPrice shoud be %v but is %v", expected.GasPrice, args.GasPrice)
}
if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 {
t.Errorf("Value shoud be %v but is %v", expected.Value, args.Value)
}
if expected.BlockNumber != args.BlockNumber {
t.Errorf("BlockNumber shoud be %v but is %v", expected.BlockNumber, args.BlockNumber)
}
}
func TestCallArgsBlockBool(t *testing.T) {
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gas": "0x76c0",
"gasPrice": "0x9184e72a000",
"value": "0x9184e72a000",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"},
false]`
args := new(CallArgs)
str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
if len(str) > 0 {
t.Error(str)
}
}
func TestCallArgsGasInvalid(t *testing.T) {
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gas": false,
"gasPrice": "0x9184e72a000",
"value": "0x9184e72a000",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]`
args := new(CallArgs)
str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
if len(str) > 0 {
t.Error(str)
}
}
func TestCallArgsGaspriceInvalid(t *testing.T) {
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gas": "0x76c0",
"gasPrice": false,
"value": "0x9184e72a000",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]`
args := new(CallArgs)
str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
if len(str) > 0 {
t.Error(str)
}
}
func TestCallArgsValueInvalid(t *testing.T) {
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gas": "0x76c0",
"gasPrice": "0x9184e72a000",
"value": false,
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]`
args := new(CallArgs)
str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
if len(str) > 0 {
t.Error(str)
}
}
func TestCallArgsGasMissing(t *testing.T) {
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gasPrice": "0x9184e72a000",
"value": "0x9184e72a000",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]`
args := new(CallArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
expected := new(CallArgs)
expected.Gas = big.NewInt(0)
if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 {
t.Errorf("Gas shoud be %v but is %v", expected.Gas, args.Gas)
}
}
func TestCallArgsBlockGaspriceMissing(t *testing.T) {
input := `[{
"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gas": "0x76c0",
"value": "0x9184e72a000",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]`
args := new(CallArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
expected := new(CallArgs)
expected.GasPrice = big.NewInt(0)
if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 {
t.Errorf("GasPrice shoud be %v but is %v", expected.GasPrice, args.GasPrice)
}
}
func TestCallArgsValueMissing(t *testing.T) {
input := `[{
"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gas": "0x76c0",
"gasPrice": "0x9184e72a000",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]`
args := new(CallArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
expected := new(CallArgs)
expected.Value = big.NewInt(int64(0))
if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 {
t.Errorf("GasPrice shoud be %v but is %v", expected.Value, args.Value)
}
}
func TestCallArgsEmpty(t *testing.T) {
input := `[]`
args := new(CallArgs)
str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args))
if len(str) > 0 {
t.Error(str)
}
}
func TestCallArgsInvalid(t *testing.T) {
input := `{}`
args := new(CallArgs)
str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args))
if len(str) > 0 {
t.Error(str)
}
}
func TestCallArgsNotStrings(t *testing.T) {
input := `[{"from":6}]`
args := new(CallArgs)
str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args))
if len(str) > 0 {
t.Error(str)
}
}
func TestCallArgsFromEmpty(t *testing.T) {
input := `[{"to": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]`
args := new(CallArgs)
str := ExpectValidationError(json.Unmarshal([]byte(input), &args))
if len(str) > 0 {
t.Error(str)
}
}
func TestCallArgsToEmpty(t *testing.T) {
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]`
args := new(CallArgs)
str := ExpectValidationError(json.Unmarshal([]byte(input), &args))
if len(str) > 0 {
t.Error(str)
} }
} }

View file

@ -2,12 +2,15 @@ package rpc
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/xeth" "github.com/ethereum/go-ethereum/xeth"
"github.com/rs/cors"
) )
var rpclogger = logger.NewLogger("RPC") var rpclogger = logger.NewLogger("RPC")
@ -17,13 +20,36 @@ const (
maxSizeReqLength = 1024 * 1024 // 1MB maxSizeReqLength = 1024 * 1024 // 1MB
) )
func Start(pipe *xeth.XEth, config RpcConfig) error {
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.ListenAddress, config.ListenPort))
if err != nil {
rpclogger.Errorf("Can't listen on %s:%d: %v", config.ListenAddress, config.ListenPort, err)
return err
}
var handler http.Handler
if len(config.CorsDomain) > 0 {
var opts cors.Options
opts.AllowedMethods = []string{"POST"}
opts.AllowedOrigins = []string{config.CorsDomain}
c := cors.New(opts)
handler = c.Handler(JSONRPC(pipe))
} else {
handler = JSONRPC(pipe)
}
go http.Serve(l, handler)
return nil
}
// JSONRPC returns a handler that implements the Ethereum JSON-RPC API. // JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
func JSONRPC(pipe *xeth.XEth) http.Handler { func JSONRPC(pipe *xeth.XEth) http.Handler {
api := NewEthereumApi(pipe) api := NewEthereumApi(pipe)
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
// TODO this needs to be configurable w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*")
// Limit request size to resist DoS // Limit request size to resist DoS
if req.ContentLength > maxSizeReqLength { if req.ContentLength > maxSizeReqLength {

View file

@ -19,8 +19,101 @@ package rpc
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/common"
) )
type hexdata struct {
data []byte
}
func (d *hexdata) String() string {
return "0x" + common.Bytes2Hex(d.data)
}
func (d *hexdata) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String())
}
func (d *hexdata) UnmarshalJSON(b []byte) (err error) {
d.data = common.FromHex(string(b))
return nil
}
func newHexData(input interface{}) *hexdata {
d := new(hexdata)
switch input := input.(type) {
case []byte:
d.data = input
case common.Hash:
d.data = input.Bytes()
case *common.Hash:
d.data = input.Bytes()
case common.Address:
d.data = input.Bytes()
case *common.Address:
d.data = input.Bytes()
case *big.Int:
d.data = input.Bytes()
case int64:
d.data = big.NewInt(input).Bytes()
case uint64:
d.data = big.NewInt(int64(input)).Bytes()
case int:
d.data = big.NewInt(int64(input)).Bytes()
case uint:
d.data = big.NewInt(int64(input)).Bytes()
case string: // hexstring
d.data = common.Big(input).Bytes()
default:
d.data = nil
}
return d
}
type hexnum struct {
data []byte
}
func (d *hexnum) String() string {
// Get hex string from bytes
out := common.Bytes2Hex(d.data)
// Trim leading 0s
out = strings.Trim(out, "0")
// Output "0x0" when value is 0
if len(out) == 0 {
out = "0"
}
return "0x" + out
}
func (d *hexnum) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String())
}
func (d *hexnum) UnmarshalJSON(b []byte) (err error) {
d.data = common.FromHex(string(b))
return nil
}
func newHexNum(input interface{}) *hexnum {
d := new(hexnum)
d.data = newHexData(input).data
return d
}
type RpcConfig struct {
ListenAddress string
ListenPort uint
CorsDomain string
}
type InvalidTypeError struct { type InvalidTypeError struct {
method string method string
msg string msg string

View file

@ -1,11 +1,6 @@
package rpc package rpc
import ( import (
"encoding/json"
// "fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
@ -13,246 +8,149 @@ import (
type BlockRes struct { type BlockRes struct {
fullTx bool fullTx bool
BlockNumber *big.Int `json:"number"` BlockNumber *hexnum `json:"number"`
BlockHash common.Hash `json:"hash"` BlockHash *hexdata `json:"hash"`
ParentHash common.Hash `json:"parentHash"` ParentHash *hexdata `json:"parentHash"`
Nonce [8]byte `json:"nonce"` Nonce *hexnum `json:"nonce"`
Sha3Uncles common.Hash `json:"sha3Uncles"` Sha3Uncles *hexdata `json:"sha3Uncles"`
LogsBloom types.Bloom `json:"logsBloom"` LogsBloom *hexdata `json:"logsBloom"`
TransactionRoot common.Hash `json:"transactionRoot"` TransactionRoot *hexdata `json:"transactionRoot"`
StateRoot common.Hash `json:"stateRoot"` StateRoot *hexdata `json:"stateRoot"`
Miner common.Address `json:"miner"` Miner *hexdata `json:"miner"`
Difficulty *big.Int `json:"difficulty"` Difficulty *hexnum `json:"difficulty"`
TotalDifficulty *big.Int `json:"totalDifficulty"` TotalDifficulty *hexnum `json:"totalDifficulty"`
Size *big.Int `json:"size"` Size *hexnum `json:"size"`
ExtraData []byte `json:"extraData"` ExtraData *hexdata `json:"extraData"`
GasLimit *big.Int `json:"gasLimit"` GasLimit *hexnum `json:"gasLimit"`
MinGasPrice int64 `json:"minGasPrice"` MinGasPrice *hexnum `json:"minGasPrice"`
GasUsed *big.Int `json:"gasUsed"` GasUsed *hexnum `json:"gasUsed"`
UnixTimestamp int64 `json:"timestamp"` UnixTimestamp *hexnum `json:"timestamp"`
Transactions []*TransactionRes `json:"transactions"` Transactions []*TransactionRes `json:"transactions"`
Uncles []common.Hash `json:"uncles"` Uncles []*hexdata `json:"uncles"`
} }
func (b *BlockRes) MarshalJSON() ([]byte, error) { func NewBlockRes(block *types.Block, fullTx bool) *BlockRes {
var ext struct { // TODO respect fullTx flag
BlockNumber string `json:"number"`
BlockHash string `json:"hash"`
ParentHash string `json:"parentHash"`
Nonce string `json:"nonce"`
Sha3Uncles string `json:"sha3Uncles"`
LogsBloom string `json:"logsBloom"`
TransactionRoot string `json:"transactionRoot"`
StateRoot string `json:"stateRoot"`
Miner string `json:"miner"`
Difficulty string `json:"difficulty"`
TotalDifficulty string `json:"totalDifficulty"`
Size string `json:"size"`
ExtraData string `json:"extraData"`
GasLimit string `json:"gasLimit"`
MinGasPrice string `json:"minGasPrice"`
GasUsed string `json:"gasUsed"`
UnixTimestamp string `json:"timestamp"`
Transactions []interface{} `json:"transactions"`
Uncles []string `json:"uncles"`
}
// convert strict types to hexified strings
ext.BlockNumber = common.ToHex(b.BlockNumber.Bytes())
ext.BlockHash = b.BlockHash.Hex()
ext.ParentHash = b.ParentHash.Hex()
ext.Nonce = common.ToHex(b.Nonce[:])
ext.Sha3Uncles = b.Sha3Uncles.Hex()
ext.LogsBloom = common.ToHex(b.LogsBloom[:])
ext.TransactionRoot = b.TransactionRoot.Hex()
ext.StateRoot = b.StateRoot.Hex()
ext.Miner = b.Miner.Hex()
ext.Difficulty = common.ToHex(b.Difficulty.Bytes())
ext.TotalDifficulty = common.ToHex(b.TotalDifficulty.Bytes())
ext.Size = common.ToHex(b.Size.Bytes())
ext.ExtraData = common.ToHex(b.ExtraData)
ext.GasLimit = common.ToHex(b.GasLimit.Bytes())
// ext.MinGasPrice = common.ToHex(big.NewInt(b.MinGasPrice).Bytes())
ext.GasUsed = common.ToHex(b.GasUsed.Bytes())
ext.UnixTimestamp = common.ToHex(big.NewInt(b.UnixTimestamp).Bytes())
ext.Transactions = make([]interface{}, len(b.Transactions))
if b.fullTx {
for i, tx := range b.Transactions {
ext.Transactions[i] = tx
}
} else {
for i, tx := range b.Transactions {
ext.Transactions[i] = tx.Hash.Hex()
}
}
ext.Uncles = make([]string, len(b.Uncles))
for i, v := range b.Uncles {
ext.Uncles[i] = v.Hex()
}
return json.Marshal(ext)
}
func NewBlockRes(block *types.Block) *BlockRes {
if block == nil { if block == nil {
return &BlockRes{} return &BlockRes{}
} }
res := new(BlockRes) res := new(BlockRes)
res.BlockNumber = block.Number() res.fullTx = fullTx
res.BlockHash = block.Hash() res.BlockNumber = newHexNum(block.Number())
res.ParentHash = block.ParentHash() res.BlockHash = newHexData(block.Hash())
res.Nonce = block.Header().Nonce res.ParentHash = newHexData(block.ParentHash())
res.Sha3Uncles = block.Header().UncleHash res.Nonce = newHexNum(block.Header().Nonce)
res.LogsBloom = block.Bloom() res.Sha3Uncles = newHexData(block.Header().UncleHash)
res.TransactionRoot = block.Header().TxHash res.LogsBloom = newHexData(block.Bloom())
res.StateRoot = block.Root() res.TransactionRoot = newHexData(block.Header().TxHash)
res.Miner = block.Header().Coinbase res.StateRoot = newHexData(block.Root())
res.Difficulty = block.Difficulty() res.Miner = newHexData(block.Header().Coinbase)
res.TotalDifficulty = block.Td res.Difficulty = newHexNum(block.Difficulty())
res.Size = big.NewInt(int64(block.Size())) res.TotalDifficulty = newHexNum(block.Td)
res.ExtraData = []byte(block.Header().Extra) res.Size = newHexNum(block.Size())
res.GasLimit = block.GasLimit() res.ExtraData = newHexData(block.Header().Extra)
res.GasLimit = newHexNum(block.GasLimit())
// res.MinGasPrice = // res.MinGasPrice =
res.GasUsed = block.GasUsed() res.GasUsed = newHexNum(block.GasUsed())
res.UnixTimestamp = block.Time() res.UnixTimestamp = newHexNum(block.Time())
res.Transactions = make([]*TransactionRes, len(block.Transactions())) res.Transactions = make([]*TransactionRes, len(block.Transactions()))
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
v := NewTransactionRes(tx) res.Transactions[i] = NewTransactionRes(tx)
v.BlockHash = block.Hash() res.Transactions[i].BlockHash = res.BlockHash
v.BlockNumber = block.Number().Int64() res.Transactions[i].BlockNumber = res.BlockNumber
v.TxIndex = int64(i) res.Transactions[i].TxIndex = newHexNum(i)
res.Transactions[i] = v
} }
res.Uncles = make([]common.Hash, len(block.Uncles()))
res.Uncles = make([]*hexdata, len(block.Uncles()))
for i, uncle := range block.Uncles() { for i, uncle := range block.Uncles() {
res.Uncles[i] = uncle.Hash() res.Uncles[i] = newHexData(uncle.Hash())
} }
return res return res
} }
type TransactionRes struct { type TransactionRes struct {
Hash common.Hash `json:"hash"` Hash *hexdata `json:"hash"`
Nonce uint64 `json:"nonce"` Nonce *hexnum `json:"nonce"`
BlockHash common.Hash `json:"blockHash,omitempty"` BlockHash *hexdata `json:"blockHash"`
BlockNumber int64 `json:"blockNumber,omitempty"` BlockNumber *hexnum `json:"blockNumber"`
TxIndex int64 `json:"transactionIndex,omitempty"` TxIndex *hexnum `json:"transactionIndex"`
From common.Address `json:"from"` From *hexdata `json:"from"`
To *common.Address `json:"to"` To *hexdata `json:"to"`
Value *big.Int `json:"value"` Value *hexnum `json:"value"`
Gas *big.Int `json:"gas"` Gas *hexnum `json:"gas"`
GasPrice *big.Int `json:"gasPrice"` GasPrice *hexnum `json:"gasPrice"`
Input []byte `json:"input"` Input *hexdata `json:"input"`
}
func (t *TransactionRes) MarshalJSON() ([]byte, error) {
var ext struct {
Hash string `json:"hash"`
Nonce string `json:"nonce"`
BlockHash string `json:"blockHash,omitempty"`
BlockNumber string `json:"blockNumber,omitempty"`
TxIndex string `json:"transactionIndex,omitempty"`
From string `json:"from"`
To interface{} `json:"to"`
Value string `json:"value"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice"`
Input string `json:"input"`
}
ext.Hash = t.Hash.Hex()
ext.Nonce = common.ToHex(big.NewInt(int64(t.Nonce)).Bytes())
ext.BlockHash = t.BlockHash.Hex()
ext.BlockNumber = common.ToHex(big.NewInt(t.BlockNumber).Bytes())
ext.TxIndex = common.ToHex(big.NewInt(t.TxIndex).Bytes())
ext.From = t.From.Hex()
if t.To == nil {
ext.To = nil
} else {
ext.To = t.To.Hex()
}
ext.Value = common.ToHex(t.Value.Bytes())
ext.Gas = common.ToHex(t.Gas.Bytes())
ext.GasPrice = common.ToHex(t.GasPrice.Bytes())
ext.Input = common.ToHex(t.Input)
return json.Marshal(ext)
} }
func NewTransactionRes(tx *types.Transaction) *TransactionRes { func NewTransactionRes(tx *types.Transaction) *TransactionRes {
var v = new(TransactionRes) var v = new(TransactionRes)
v.Hash = tx.Hash() v.Hash = newHexData(tx.Hash())
v.Nonce = tx.Nonce() v.Nonce = newHexNum(tx.Nonce())
v.From, _ = tx.From() // v.BlockHash =
v.To = tx.To() // v.BlockNumber =
v.Value = tx.Value() // v.TxIndex =
v.Gas = tx.Gas() from, _ := tx.From()
v.GasPrice = tx.GasPrice() v.From = newHexData(from)
v.Input = tx.Data() v.To = newHexData(tx.To())
v.Value = newHexNum(tx.Value())
v.Gas = newHexNum(tx.Gas())
v.GasPrice = newHexNum(tx.GasPrice())
v.Input = newHexData(tx.Data())
return v return v
} }
type FilterLogRes struct { // type FilterLogRes struct {
Hash string `json:"hash"` // Hash string `json:"hash"`
Address string `json:"address"` // Address string `json:"address"`
Data string `json:"data"` // Data string `json:"data"`
BlockNumber string `json:"blockNumber"` // BlockNumber string `json:"blockNumber"`
TransactionHash string `json:"transactionHash"` // TransactionHash string `json:"transactionHash"`
BlockHash string `json:"blockHash"` // BlockHash string `json:"blockHash"`
TransactionIndex string `json:"transactionIndex"` // TransactionIndex string `json:"transactionIndex"`
LogIndex string `json:"logIndex"` // LogIndex string `json:"logIndex"`
} // }
type FilterWhisperRes struct { // type FilterWhisperRes struct {
Hash string `json:"hash"` // Hash string `json:"hash"`
From string `json:"from"` // From string `json:"from"`
To string `json:"to"` // To string `json:"to"`
Expiry string `json:"expiry"` // Expiry string `json:"expiry"`
Sent string `json:"sent"` // Sent string `json:"sent"`
Ttl string `json:"ttl"` // Ttl string `json:"ttl"`
Topics string `json:"topics"` // Topics string `json:"topics"`
Payload string `json:"payload"` // Payload string `json:"payload"`
WorkProved string `json:"workProved"` // WorkProved string `json:"workProved"`
} // }
type LogRes struct { type LogRes struct {
Address common.Address `json:"address"` Address *hexdata `json:"address"`
Topics []common.Hash `json:"topics"` Topics []*hexdata `json:"topics"`
Data []byte `json:"data"` Data *hexdata `json:"data"`
Number uint64 `json:"number"` BlockNumber *hexnum `json:"blockNumber"`
Hash *hexdata `json:"hash"`
LogIndex *hexnum `json:"logIndex"`
BlockHash *hexdata `json:"blockHash"`
TransactionHash *hexdata `json:"transactionHash"`
TransactionIndex *hexnum `json:"transactionIndex"`
} }
func NewLogRes(log state.Log) LogRes { func NewLogRes(log state.Log) LogRes {
var l LogRes var l LogRes
l.Topics = make([]common.Hash, len(log.Topics())) l.Topics = make([]*hexdata, len(log.Topics()))
l.Address = log.Address()
l.Data = log.Data()
l.Number = log.Number()
for j, topic := range log.Topics() { for j, topic := range log.Topics() {
l.Topics[j] = topic l.Topics[j] = newHexData(topic)
} }
l.Address = newHexData(log.Address())
l.Data = newHexData(log.Data())
l.BlockNumber = newHexNum(log.Number())
return l return l
} }
func (l *LogRes) MarshalJSON() ([]byte, error) {
var ext struct {
Address string `json:"address"`
Topics []string `json:"topics"`
Data string `json:"data"`
Number string `json:"number"`
}
ext.Address = l.Address.Hex()
ext.Data = common.ToHex(l.Data)
ext.Number = common.ToHex(big.NewInt(int64(l.Number)).Bytes())
ext.Topics = make([]string, len(l.Topics))
for i, v := range l.Topics {
ext.Topics[i] = v.Hex()
}
return json.Marshal(ext)
}
func NewLogsRes(logs state.Logs) (ls []LogRes) { func NewLogsRes(logs state.Logs) (ls []LogRes) {
ls = make([]LogRes, len(logs)) ls = make([]LogRes, len(logs))

View file

@ -2,7 +2,9 @@ package rpc
import ( import (
"encoding/json" "encoding/json"
"fmt"
"math/big" "math/big"
"regexp"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -10,6 +12,15 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
const (
reHash = `"0x[0-9a-f]{64}"` // 32 bytes
reHashOpt = `"(0x[0-9a-f]{64})"|null` // 32 bytes or null
reAddress = `"0x[0-9a-f]{40}"` // 20 bytes
reAddressOpt = `"0x[0-9a-f]{40}"|null` // 20 bytes or null
reNum = `"0x([1-9a-f][0-9a-f]{1,15})|0"` // must not have left-padded zeros
reData = `"0x[0-9a-f]*"` // can be "empty"
)
func TestNewBlockRes(t *testing.T) { func TestNewBlockRes(t *testing.T) {
parentHash := common.HexToHash("0x01") parentHash := common.HexToHash("0x01")
coinbase := common.HexToAddress("0x01") coinbase := common.HexToAddress("0x01")
@ -18,56 +29,35 @@ func TestNewBlockRes(t *testing.T) {
nonce := uint64(1) nonce := uint64(1)
extra := "" extra := ""
block := types.NewBlock(parentHash, coinbase, root, difficulty, nonce, extra) block := types.NewBlock(parentHash, coinbase, root, difficulty, nonce, extra)
tests := map[string]string{
_ = NewBlockRes(block) "number": reNum,
} "hash": reHash,
"parentHash": reHash,
func TestBlockRes(t *testing.T) { "nonce": reNum,
v := &BlockRes{ "sha3Uncles": reHash,
BlockNumber: big.NewInt(0), "logsBloom": reData,
BlockHash: common.HexToHash("0x0"), "transactionRoot": reHash,
ParentHash: common.HexToHash("0x0"), "stateRoot": reHash,
Nonce: [8]byte{0, 0, 0, 0, 0, 0, 0, 0}, "miner": reAddress,
Sha3Uncles: common.HexToHash("0x0"), "difficulty": `"0x1"`,
LogsBloom: types.BytesToBloom([]byte{0}), "totalDifficulty": reNum,
TransactionRoot: common.HexToHash("0x0"), "size": reNum,
StateRoot: common.HexToHash("0x0"), "extraData": reData,
Miner: common.HexToAddress("0x0"), "gasLimit": reNum,
Difficulty: big.NewInt(0), // "minGasPrice": "0x",
TotalDifficulty: big.NewInt(0), "gasUsed": reNum,
Size: big.NewInt(0), "timestamp": reNum,
ExtraData: []byte{},
GasLimit: big.NewInt(0),
MinGasPrice: int64(0),
GasUsed: big.NewInt(0),
UnixTimestamp: int64(0),
// Transactions []*TransactionRes `json:"transactions"`
// Uncles []common.Hash `json:"uncles"`
} }
_, _ = json.Marshal(v) v := NewBlockRes(block, false)
j, _ := json.Marshal(v)
// fmt.Println(string(j)) for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j))
} if !match {
t.Error(fmt.Sprintf("%s output json does not match format %s. Got %s", k, re, j))
func TestTransactionRes(t *testing.T) { }
a := common.HexToAddress("0x0")
v := &TransactionRes{
Hash: common.HexToHash("0x0"),
Nonce: uint64(0),
BlockHash: common.HexToHash("0x0"),
BlockNumber: int64(0),
TxIndex: int64(0),
From: common.HexToAddress("0x0"),
To: &a,
Value: big.NewInt(0),
Gas: big.NewInt(0),
GasPrice: big.NewInt(0),
Input: []byte{0},
} }
_, _ = json.Marshal(v)
} }
func TestNewTransactionRes(t *testing.T) { func TestNewTransactionRes(t *testing.T) {
@ -78,26 +68,80 @@ func TestNewTransactionRes(t *testing.T) {
data := []byte{1, 2, 3} data := []byte{1, 2, 3}
tx := types.NewTransactionMessage(to, amount, gasAmount, gasPrice, data) tx := types.NewTransactionMessage(to, amount, gasAmount, gasPrice, data)
_ = NewTransactionRes(tx) tests := map[string]string{
} "hash": reHash,
"nonce": reNum,
func TestLogRes(t *testing.T) { "blockHash": reHash,
topics := make([]common.Hash, 3) "blockNum": reNum,
topics = append(topics, common.HexToHash("0x00")) "transactionIndex": reNum,
topics = append(topics, common.HexToHash("0x10")) "from": reAddress,
topics = append(topics, common.HexToHash("0x20")) "to": reAddressOpt,
"value": reNum,
v := &LogRes{ "gas": reNum,
Topics: topics, "gasPrice": reNum,
Address: common.HexToAddress("0x0"), "input": reData,
Data: []byte{1, 2, 3}, }
Number: uint64(5),
v := NewTransactionRes(tx)
v.BlockHash = newHexData(common.HexToHash("0x030201"))
v.BlockNumber = newHexNum(5)
v.TxIndex = newHexNum(0)
j, _ := json.Marshal(v)
for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j))
if !match {
t.Error(fmt.Sprintf("`%s` output json does not match format %s. Source %s", k, re, j))
}
} }
_, _ = json.Marshal(v)
} }
func MakeStateLog(num int) state.Log { func TestNewLogRes(t *testing.T) {
log := makeStateLog(0)
tests := map[string]string{
"address": reAddress,
// "topics": "[.*]"
"data": reData,
"blockNumber": reNum,
// "hash": reHash,
// "logIndex": reNum,
// "blockHash": reHash,
// "transactionHash": reHash,
"transactionIndex": reNum,
}
v := NewLogRes(log)
j, _ := json.Marshal(v)
for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j))
if !match {
t.Error(fmt.Sprintf("`%s` output json does not match format %s. Got %s", k, re, j))
}
}
}
func TestNewLogsRes(t *testing.T) {
logs := make([]state.Log, 3)
logs[0] = makeStateLog(1)
logs[1] = makeStateLog(2)
logs[2] = makeStateLog(3)
tests := map[string]string{}
v := NewLogsRes(logs)
j, _ := json.Marshal(v)
for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`[{.*"%s":%s.*}]`, k, re), string(j))
if !match {
t.Error(fmt.Sprintf("%s output json does not match format %s. Got %s", k, re, j))
}
}
}
func makeStateLog(num int) state.Log {
address := common.HexToAddress("0x0") address := common.HexToAddress("0x0")
data := []byte{1, 2, 3} data := []byte{1, 2, 3}
number := uint64(num) number := uint64(num)
@ -108,16 +152,3 @@ func MakeStateLog(num int) state.Log {
log := state.NewLog(address, topics, data, number) log := state.NewLog(address, topics, data, number)
return log return log
} }
func TestNewLogRes(t *testing.T) {
log := MakeStateLog(0)
_ = NewLogRes(log)
}
func TestNewLogsRes(t *testing.T) {
logs := make([]state.Log, 3)
logs[0] = MakeStateLog(1)
logs[1] = MakeStateLog(2)
logs[2] = MakeStateLog(3)
_ = NewLogsRes(logs)
}

View file

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
@ -69,7 +68,7 @@ type btBlock struct {
BlockHeader *btHeader BlockHeader *btHeader
Rlp string Rlp string
Transactions []btTransaction Transactions []btTransaction
UncleHeaders []string UncleHeaders []*btHeader
} }
type BlockTest struct { type BlockTest struct {
@ -106,21 +105,21 @@ func (t *BlockTest) InsertPreState(db common.Database) (*state.StateDB, error) {
balance, _ := new(big.Int).SetString(acct.Balance, 0) balance, _ := new(big.Int).SetString(acct.Balance, 0)
nonce, _ := strconv.ParseUint(acct.Nonce, 16, 64) nonce, _ := strconv.ParseUint(acct.Nonce, 16, 64)
obj := statedb.NewStateObject(common.HexToAddress(addrString)) obj := statedb.CreateAccount(common.HexToAddress(addrString))
obj.SetCode(code) obj.SetCode(code)
obj.SetBalance(balance) obj.SetBalance(balance)
obj.SetNonce(nonce) obj.SetNonce(nonce)
// for k, v := range acct.Storage { for k, v := range acct.Storage {
// obj.SetState(k, v) statedb.SetState(common.HexToAddress(addrString), common.HexToHash(k), common.FromHex(v))
// } }
} }
// sync objects to trie // sync objects to trie
statedb.Update(nil) statedb.Update()
// sync trie to disk // sync trie to disk
statedb.Sync() statedb.Sync()
if !bytes.Equal(t.Genesis.Root().Bytes(), statedb.Root().Bytes()) { if !bytes.Equal(t.Genesis.Root().Bytes(), statedb.Root().Bytes()) {
return nil, errors.New("computed state root does not match genesis block") return nil, fmt.Errorf("computed state root does not match genesis block %x %x", t.Genesis.Root().Bytes()[:4], statedb.Root().Bytes()[:4])
} }
return statedb, nil return statedb, nil
} }

View file

@ -1,5 +1,5 @@
{ {
"genesis_rlp_hex": "f90219f90214a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a09178d0f23c965d81f0834a4c72c6253ce6830f4022b1359aaebfc1ecba442d4ea056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080830f4240808080a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000088000000000000002ac0c0", "genesis_rlp_hex": "f901f8f901f3a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a09178d0f23c965d81f0834a4c72c6253ce6830f4022b1359aaebfc1ecba442d4ea056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808080a0000000000000000000000000000000000000000000000000000000000000000088000000000000002ac0c0",
"genesis_state_root": "9178d0f23c965d81f0834a4c72c6253ce6830f4022b1359aaebfc1ecba442d4e", "genesis_state_root": "9178d0f23c965d81f0834a4c72c6253ce6830f4022b1359aaebfc1ecba442d4e",
"genesis_hash": "b5d6d8402156c5c1dfadaa4b87c676b5bcadb17ef9bc8e939606daaa0d35f55d" "genesis_hash": "fd4af92a79c7fc2fd8bf0d342f2e832e1d4f485c85b9152d2039e03bc604fdca"
} }

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "972201916",
"code" : "0x7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000019e7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000c35036017f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b51916f2620a6e7d187a5560005155",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "912450255",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999998115347875",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "24e7dcfb7ff0269a9000bedfeafad33c3ccc3610e3031c88bace245f3cbe64d2",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000019e7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000c35036017f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b51916f2620a6e7d187a5560005155",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000019e7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000c35036017f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b51916f2620a6e7d187a",
"gasLimit" : "0x3662e2a1",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "972201916"
}
}
}

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000c350377f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000100000000000000000000000000000000000000000b3a09785b1084418866100af0868a3455",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "1556088597",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999998443911449",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "886793cb795aad67bef8747046a71428c332fac253236d4002e142f08f31602b",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000c350377f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000100000000000000000000000000000000000000000b3a09785b1084418866100af0868a3455",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000c350377f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000100000000000000000000000000000000000000000b3a09785b1084418866100af0868a34",
"gasLimit" : "0x5cc006e7",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "2056709657"
}
}
}

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000100000000000000000000000000000000000000004340427f000000000000000000000000000000000000000000000000000000000000c3507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff52835a546b6685923465",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "1241595343",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999998758404703",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "adebc5b15e70b5b8ad3eb5d2d0bc7880149d6f86d96cbc861494f810c3d325c1",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000100000000000000000000000000000000000000004340427f000000000000000000000000000000000000000000000000000000000000c3507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff52835a546b6685923465",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000100000000000000000000000000000000000000004340427f000000000000000000000000000000000000000000000000000000000000c3507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff52835a546b6685923465",
"gasLimit" : "0x4a013da1",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "1959890283"
}
}
}

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f000000000000000000000000000000000000000000000000000000000000c3507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f00000000000000000000000100000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe527f00000000000000000000000000000000000000000000000000000000000000017f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "1944132934",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999998055867112",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "16d58f4edca99e12b53543966af5ef6159af7dbf93ef4f085bce2972ecb413ad",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f000000000000000000000000000000000000000000000000000000000000c3507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f00000000000000000000000100000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe527f00000000000000000000000000000000000000000000000000000000000000017f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x7f000000000000000000000000000000000000000000000000000000000000c3507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f00000000000000000000000100000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe527f00000000000000000000000000000000000000000000000000000000000000017f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5",
"gasLimit" : "0x73e11d18",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "1285310456"
}
}
}

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000027ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe307f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000100000000000000000000000000000000000000005255",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "1380924181",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999998619075865",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "224160a19d11a6252067a26ecfc2963fd1aff5c2b484a2f12c12ec7d5bbc547d",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000027ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe307f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000100000000000000000000000000000000000000005255",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000027ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe307f00000000000000000000000100000000000000000000000000000000000000007f000000000000000000000001000000000000000000000000000000000000000052",
"gasLimit" : "0x524f3ae7",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "936808044"
}
}
}

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f00000000000000000000000000000000000000000000000000000000000000017f00000000000000000000000100000000000000000000000000000000000000007f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001155933704",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "1932635520",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999998067364526",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "3c9d47fb3ada07b78c2e6470ed8b4107db21e513979a71c270d97da5a20186bc",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f00000000000000000000000000000000000000000000000000000000000000017f00000000000000000000000100000000000000000000000000000000000000007f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001155933704",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f00000000000000000000000000000000000000000000000000000000000000017f00000000000000000000000100000000000000000000000000000000000000007f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001155933704",
"gasLimit" : "0x7331ad52",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "1499936335"
}
}
}

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f000000000000000000000001000000000000000000000000000000000000000044457f0000000000000000000000000000000000000000000000000000000000000001187f00000000000000000000000000000000000000000000000000000000000000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff52155955",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "1283993444",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999998716006602",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "af423ed22996f4161da21729d08e3d9138d94234b778a043313bb6dcbc55d93d",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f000000000000000000000001000000000000000000000000000000000000000044457f0000000000000000000000000000000000000000000000000000000000000001187f00000000000000000000000000000000000000000000000000000000000000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff52155955",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f000000000000000000000001000000000000000000000000000000000000000044457f0000000000000000000000000000000000000000000000000000000000000001187f00000000000000000000000000000000000000000000000000000000000000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff521559",
"gasLimit" : "0x4c882f36",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "679746513"
}
}
}

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x31417f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000c3507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0315208a675944747f7430661519049a55",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "704316238",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999999295683808",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "ddb8f27abb51685caa793be133df9db3912648c02498b74a0ae874294acce6f0",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x31417f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000c3507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0315208a675944747f7430661519049a55",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x31417f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000c3507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0315208a675944747f7430661519049a",
"gasLimit" : "0x29fb0320",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "1758540724"
}
}
}

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x44207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000001145344846604627f5560005155",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "620442430",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999999379557616",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "da70f5af0d1545ec9f0f0e28a55d3f2896bb3d64c71b4908f72ed26c345aafe4",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x44207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000001145344846604627f5560005155",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x44207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000001145344846604627f",
"gasLimit" : "0x24fb3310",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "1561176030"
}
}
}

View file

@ -0,0 +1,71 @@
{
"randomStatetest" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f0000000000000000000000000000000000000000000000000000000000000001207f000000000000000000000000000000000000000000000000000000000000c3507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000c3507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe406f",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "1258533548",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999998741466498",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "e1881131f80068947922f01c78464f93c46e6e11314d0deceb55809e594aec0a",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x7f0000000000000000000000000000000000000000000000000000000000000001207f000000000000000000000000000000000000000000000000000000000000c3507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000c3507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe406f",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x7f0000000000000000000000000000000000000000000000000000000000000001207f000000000000000000000000000000000000000000000000000000000000c3507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000c3507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe406f",
"gasLimit" : "0x4b03b27e",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "781711523"
}
}
}

View file

@ -847,6 +847,78 @@
"value" : "100000" "value" : "100000"
} }
}, },
"createJS_ExampleContract" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x60003560e060020a9004806343d726d61461004257806391b7f5ed14610050578063d686f9ee14610061578063f5bade661461006f578063fcfff16f1461008057005b61004a6101de565b60006000f35b61005b6004356100bf565b60006000f35b610069610304565b60006000f35b61007a60043561008e565b60006000f35b6100886100f0565b60006000f35b600054600160a060020a031633600160a060020a031614156100af576100b4565b6100bc565b806001819055505b50565b600054600160a060020a031633600160a060020a031614156100e0576100e5565b6100ed565b806002819055505b50565b600054600160a060020a031633600160a060020a031614806101255750600354600160a060020a031633600160a060020a0316145b61012e57610161565b60016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a16101dc565b60045460011480610173575060015434105b6101b85760016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a142600581905550336003819055506101db565b33600160a060020a03166000346000600060006000848787f16101d757005b5050505b5b565b60006004546000146101ef576101f4565b610301565b600054600160a060020a031633600160a060020a031614801561022c5750600054600160a060020a0316600354600160a060020a0316145b61023557610242565b6000600481905550610301565b600354600160a060020a031633600160a060020a03161461026257610300565b600554420360025402905060015481116102c757600354600160a060020a0316600082600154036000600060006000848787f161029b57005b505050600054600160a060020a03166000826000600060006000848787f16102bf57005b5050506102ee565b600054600160a060020a031660006001546000600060006000848787f16102ea57005b5050505b60006004819055506000546003819055505b5b50565b6000600054600160a060020a031633600160a060020a031614156103275761032c565b61037e565b600554420360025402905060015481116103455761037d565b600054600160a060020a031660006001546000600060006000848787f161036857005b50505060006004819055506000546003819055505b5b5056",
"post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "366356",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
},
"6295ee1b4f6dd65047762f924ecd367c17eabf8f" : {
"balance" : "200000",
"code" : "0x60003560e060020a9004806343d726d61461004257806391b7f5ed14610050578063d686f9ee14610061578063f5bade661461006f578063fcfff16f1461008057005b61004a6101de565b60006000f35b61005b6004356100bf565b60006000f35b610069610304565b60006000f35b61007a60043561008e565b60006000f35b6100886100f0565b60006000f35b600054600160a060020a031633600160a060020a031614156100af576100b4565b6100bc565b806001819055505b50565b600054600160a060020a031633600160a060020a031614156100e0576100e5565b6100ed565b806002819055505b50565b600054600160a060020a031633600160a060020a031614806101255750600354600160a060020a031633600160a060020a0316145b61012e57610161565b60016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a16101dc565b60045460011480610173575060015434105b6101b85760016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a142600581905550336003819055506101db565b33600160a060020a03166000346000600060006000848787f16101d757005b5050505b5b565b60006004546000146101ef576101f4565b610301565b600054600160a060020a031633600160a060020a031614801561022c5750600054600160a060020a0316600354600160a060020a0316145b61023557610242565b6000600481905550610301565b600354600160a060020a031633600160a060020a03161461026257610300565b600554420360025402905060015481116102c757600354600160a060020a0316600082600154036000600060006000848787f161029b57005b505050600054600160a060020a03166000826000600060006000848787f16102bf57005b5050506102ee565b600054600160a060020a031660006001546000600060006000848787f16102ea57005b5050505b60006004819055506000546003819055505b5b50565b6000600054600160a060020a031633600160a060020a031614156103275761032c565b61037e565b600554420360025402905060015481116103455761037d565b600054600160a060020a031660006001546000600060006000848787f161036857005b50505060006004819055506000546003819055505b5b5056",
"nonce" : "0",
"storage" : {
"0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"0x01" : "0x42",
"0x02" : "0x23",
"0x03" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"0x05" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "9999999533644",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "5500215cdbf8165ca47720ad088ae49c2441560cdf267f1c946ae7b9807cb1d4",
"pre" : {
"6295ee1b4f6dd65047762f924ecd367c17eabf8f" : {
"balance" : "100000",
"code" : "0x60003560e060020a9004806343d726d61461004257806391b7f5ed14610050578063d686f9ee14610061578063f5bade661461006f578063fcfff16f1461008057005b61004a6101de565b60006000f35b61005b6004356100bf565b60006000f35b610069610304565b60006000f35b61007a60043561008e565b60006000f35b6100886100f0565b60006000f35b600054600160a060020a031633600160a060020a031614156100af576100b4565b6100bc565b806001819055505b50565b600054600160a060020a031633600160a060020a031614156100e0576100e5565b6100ed565b806002819055505b50565b600054600160a060020a031633600160a060020a031614806101255750600354600160a060020a031633600160a060020a0316145b61012e57610161565b60016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a16101dc565b60045460011480610173575060015434105b6101b85760016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a142600581905550336003819055506101db565b33600160a060020a03166000346000600060006000848787f16101d757005b5050505b5b565b60006004546000146101ef576101f4565b610301565b600054600160a060020a031633600160a060020a031614801561022c5750600054600160a060020a0316600354600160a060020a0316145b61023557610242565b6000600481905550610301565b600354600160a060020a031633600160a060020a03161461026257610300565b600554420360025402905060015481116102c757600354600160a060020a0316600082600154036000600060006000848787f161029b57005b505050600054600160a060020a03166000826000600060006000848787f16102bf57005b5050506102ee565b600054600160a060020a031660006001546000600060006000848787f16102ea57005b5050505b60006004819055506000546003819055505b5b50565b6000600054600160a060020a031633600160a060020a031614156103275761032c565b61037e565b600554420360025402905060015481116103455761037d565b600054600160a060020a031660006001546000600060006000848787f161036857005b50505060006004819055506000546003819055505b5b5056",
"nonce" : "0",
"storage" : {
"0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"0x01" : "0x42",
"0x02" : "0x23",
"0x03" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"0x05" : "0x54c98c81"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x60406103ca600439600451602451336000819055506000600481905550816001819055508060028190555042600581905550336003819055505050610381806100496000396000f30060003560e060020a9004806343d726d61461004257806391b7f5ed14610050578063d686f9ee14610061578063f5bade661461006f578063fcfff16f1461008057005b61004a6101de565b60006000f35b61005b6004356100bf565b60006000f35b610069610304565b60006000f35b61007a60043561008e565b60006000f35b6100886100f0565b60006000f35b600054600160a060020a031633600160a060020a031614156100af576100b4565b6100bc565b806001819055505b50565b600054600160a060020a031633600160a060020a031614156100e0576100e5565b6100ed565b806002819055505b50565b600054600160a060020a031633600160a060020a031614806101255750600354600160a060020a031633600160a060020a0316145b61012e57610161565b60016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a16101dc565b60045460011480610173575060015434105b6101b85760016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a142600581905550336003819055506101db565b33600160a060020a03166000346000600060006000848787f16101d757005b5050505b5b565b60006004546000146101ef576101f4565b610301565b600054600160a060020a031633600160a060020a031614801561022c5750600054600160a060020a0316600354600160a060020a0316145b61023557610242565b6000600481905550610301565b600354600160a060020a031633600160a060020a03161461026257610300565b600554420360025402905060015481116102c757600354600160a060020a0316600082600154036000600060006000848787f161029b57005b505050600054600160a060020a03166000826000600060006000848787f16102bf57005b5050506102ee565b600054600160a060020a031660006001546000600060006000848787f16102ea57005b5050505b60006004819055506000546003819055505b5b50565b6000600054600160a060020a031633600160a060020a031614156103275761032c565b61037e565b600554420360025402905060015481116103455761037d565b600054600160a060020a031660006001546000600060006000848787f161036857005b50505060006004819055506000546003819055505b5b505600000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000023",
"gasLimit" : "600000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "",
"value" : "100000"
}
},
"createNameRegistratorendowmentTooHigh" : { "createNameRegistratorendowmentTooHigh" : {
"env" : { "env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",

View file

@ -1,4 +1,73 @@
{ {
"FillStack" : {
"env" : {
"currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5",
"currentDifficulty" : "5623894562375",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe457f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000017f000000000000000000000000000000000000000000000000000000000000c3504357155320803a975560005155",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "3141638",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "999999999996858408",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "fce3d23dbb978bf49908221f831b52381c8a13cc354cf20130f659c481515e83",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0",
"code" : "0x5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe457f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000017f000000000000000000000000000000000000000000000000000000000000c3504357155320803a975560005155",
"nonce" : "0",
"storage" : {
}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "46",
"code" : "0x6000355415600957005b60203560003555",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe457f00000000000000000000000100000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000017f000000000000000000000000000000000000000000000000000000000000c3504357155320803a97",
"gasLimit" : "3141592",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "264050067"
}
},
"mload32bitBound" : { "mload32bitBound" : {
"env" : { "env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
@ -13,7 +82,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000010", "balance" : "1000000000000000000",
"code" : "0x64010000000051600155", "code" : "0x64010000000051600155",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
@ -27,14 +96,14 @@
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "158330884724018", "balance" : "158330884724028",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "090f17dba3bdd58cf107c8155b9066e54f53a9d75bd0ec5524c364f361e32d14", "postStateRoot" : "8a47d8a8689889820bd4273dd667ece01f288b091ce244c671a6394dc4109f1f",
"pre" : { "pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",
@ -75,7 +144,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000010", "balance" : "1000000000000000000",
"code" : "0x64017735940051600155", "code" : "0x64017735940051600155",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
@ -89,14 +158,14 @@
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340119723807253", "balance" : "340119723807263",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "bc10fc8e26a51bad7dad35ee2a218076947efd3010ef12d869c3eae434a41b6d", "postStateRoot" : "6965350d67785b430326cd01f5c523976fa9361740a6f09f2f8b1f1f7940b6ec",
"pre" : { "pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",
@ -141,7 +210,7 @@
"code" : "0x600163ffffffff5259600055", "code" : "0x600163ffffffff5259600055",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
"0x" : "0x0100000020" "0x" : "0x20"
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
@ -159,7 +228,7 @@
} }
} }
}, },
"postStateRoot" : "f5cba7b1b92529ff627b7c99277dce9461d3b4cf23b030d82a3c67411d22315d", "postStateRoot" : "2959cb7d4801e19f2f83560db82253c45d0f3ebe6fd24b683e3fb61cbf36d8c3",
"pre" : { "pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",

View file

@ -13,7 +13,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374606549268211445", "balance" : "340282366920938463463374606549268211455",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -34,14 +34,14 @@
} }
}, },
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "4503599627370505", "balance" : "4503599627370495",
"code" : "0x60016000540160005561040060005410601b5760016002556047565b60006000620f42406000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620f55c85a03f16001555b", "code" : "0x60016000540160005561040060005410601b5760016002556047565b60006000620f42406000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620f55c85a03f16001555b",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "663dc49e9b7325b42dada44e8783314a91be746a73a86e834f9592ba7c69fd3e", "postStateRoot" : "41ae7b9b5d5a40a8cf673e75e87da34ee60e054579798da9de4b91add7119fc6",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211455", "balance" : "340282366920938463463374607431768211455",
@ -89,7 +89,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431683211445", "balance" : "340282366920938463463374607431683211455",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -110,14 +110,14 @@
} }
}, },
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "4503599627370505", "balance" : "4503599627370495",
"code" : "0x5b61c3506080511015603f576000600061c3506000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b610640f16000556001608051016080526000565b608051600155", "code" : "0x5b61c3506080511015603f576000600061c3506000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b610640f16000556001608051016080526000565b608051600155",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "fa335ba0e63752360fc9eaf701cdcf4315e0f9038b898c008ba975fd66028ed4", "postStateRoot" : "03b85800376c94106b746ac1714af750c6bccc95263fe92bfd673b623c2a9f58",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211455", "balance" : "340282366920938463463374607431768211455",
@ -165,7 +165,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431673711445", "balance" : "340282366920938463463374607431673711455",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -179,14 +179,14 @@
} }
}, },
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211465", "balance" : "340282366920938463463374607431768211455",
"code" : "0x5b61c3506080511015602c576000600061c3506000600160016101f4f16000556001608051016080526000565b608051600155", "code" : "0x5b61c3506080511015602c576000600061c3506000600160016101f4f16000556001608051016080526000565b608051600155",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "d036f16280564019d2bfab66b8e37fa41cfcad04025c949f897f511e321e5cb3", "postStateRoot" : "1c10ca4d661261f2041a209c80878a85e70c568fcaca0d2672207bfbc8e5262c",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211455", "balance" : "340282366920938463463374607431768211455",
@ -227,7 +227,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431679961445", "balance" : "340282366920938463463374607431679961455",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -241,14 +241,14 @@
} }
}, },
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "4503599627370505", "balance" : "4503599627370495",
"code" : "0x5b61c3506080511015602c576000600061c35060006001600461061cf16000556001608051016080526000565b608051600155", "code" : "0x5b61c3506080511015602c576000600061c35060006001600461061cf16000556001608051016080526000565b608051600155",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "5b62734d0f07edf448659b47743c07b3e255d22b7fd982f94afffe40cad36257", "postStateRoot" : "5b598dad661bdec03972e39b4f8a81c4a5e660761ad43dce42f270963759d7eb",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211455", "balance" : "340282366920938463463374607431768211455",
@ -289,7 +289,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431679961445", "balance" : "340282366920938463463374607431679961455",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -303,14 +303,14 @@
} }
}, },
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "4503599627370505", "balance" : "4503599627370495",
"code" : "0x602a6001525b61c350608051101560325761c350600161c35060006001600461061cf16000556001608051016080526005565b608051600155600151600255", "code" : "0x602a6001525b61c350608051101560325761c350600161c35060006001600461061cf16000556001608051016080526005565b608051600155600151600255",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "5216c8ba51b38440ac008c5667e3042a89135b89a9489d2e0f710d1b17f4046e", "postStateRoot" : "0c99be86d6bc6d54547baa21ad24a66e033b1d2f66faa45f8a698dfefc89b58b",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211455", "balance" : "340282366920938463463374607431768211455",
@ -351,7 +351,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607427843211445", "balance" : "340282366920938463463374607427843211455",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -365,14 +365,14 @@
} }
}, },
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "4503599627370505", "balance" : "4503599627370495",
"code" : "0x5b61c3506080511015602d576000600061c35060006001600362013178f16000556001608051016080526000565b608051600155", "code" : "0x5b61c3506080511015602d576000600061c35060006001600362013178f16000556001608051016080526000565b608051600155",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "13aaa7fe67364082aca2dea3277354b8fd6c67833900fc255dd8c11d560af5cc", "postStateRoot" : "ee56d166321770f333bc9706cd878884698f94afeb9fdfdaba14b19488a3395a",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211455", "balance" : "340282366920938463463374607431768211455",
@ -721,7 +721,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431683211445", "balance" : "340282366920938463463374607431683211455",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -742,14 +742,14 @@
} }
}, },
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "4503599627370505", "balance" : "4503599627370495",
"code" : "0x5b61c3506080511015603f576000600061c3506000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b610640f26000556001608051016080526000565b608051600155", "code" : "0x5b61c3506080511015603f576000600061c3506000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b610640f26000556001608051016080526000565b608051600155",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "e006bf33ef8b4299670ee9eeb3ccc19c783fd73677088bb76e056e07df70197d", "postStateRoot" : "414b9e24bee6c3d77fe338f9830cbd0653b6ddbe64177dfdc16a3dd20f234697",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211455", "balance" : "340282366920938463463374607431768211455",
@ -7924,7 +7924,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431679961445", "balance" : "340282366920938463463374607431679961455",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -7945,14 +7945,14 @@
} }
}, },
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "4503599627370505", "balance" : "4503599627370495",
"code" : "0x5b61c3506080511015603f576000600061c3506000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61061cf16000556001608051016080526000565b608051600155", "code" : "0x5b61c3506080511015603f576000600061c3506000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61061cf16000556001608051016080526000565b608051600155",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "31d45315e75daa1099c6dec7a6ab85d39fdd6c5bb5d7f7d1b19a5cd85de7bce7", "postStateRoot" : "722399a622a8b9b74621e7523708158e65293d659fee58c0a056d2f48b44a189",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211455", "balance" : "340282366920938463463374607431768211455",
@ -8000,7 +8000,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431679961445", "balance" : "340282366920938463463374607431679961455",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -8021,14 +8021,14 @@
} }
}, },
"bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : { "bbbf5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "4503599627370505", "balance" : "4503599627370495",
"code" : "0x5b61c3506080511015603f576000600061c3506000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61061cf16000556001608051016080526000565b608051600155", "code" : "0x5b61c3506080511015603f576000600061c3506000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61061cf16000556001608051016080526000565b608051600155",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "4d4f0332a3f18f34b3d4777ac84c7c99e91c0da4005834dc819dfa69f7cbd156", "postStateRoot" : "a3d7da9aa50be0201d42a2d00f968aa675ba436172ff793a3bc174ad7ffee206",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "340282366920938463463374607431768211455", "balance" : "340282366920938463463374607431768211455",

View file

@ -53,7 +53,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run()",
"data" : "0xc0406226", "data" : "0xc0406226",
"gasLimit" : "300000", "gasLimit" : "300000",
"gasPrice" : "1", "gasPrice" : "1",
@ -116,7 +115,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "testInfiniteLoop()",
"data" : "0x296df0df", "data" : "0x296df0df",
"gasLimit" : "300000", "gasLimit" : "300000",
"gasPrice" : "1", "gasPrice" : "1",
@ -188,7 +186,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run()",
"data" : "0xc0406226", "data" : "0xc0406226",
"gasLimit" : "350000", "gasLimit" : "350000",
"gasPrice" : "1", "gasPrice" : "1",
@ -213,31 +210,31 @@
"post" : { "post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000", "balance" : "100000",
"code" : "0x60003560e060020a90048063296df0df1460295780634893d88a146035578063981a316514604157005b602f604d565b60006000f35b603b6062565b60006000f35b6047605a565b60006000f35b5b600115605857604e565b565b60606062565b565b6068605a565b56", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463296df0df811460415780634893d88a14604d578063981a316514605957005b60476065565b60006000f35b6053607a565b60006000f35b605f6072565b60006000f35b5b6001156070576066565b565b6078607a565b565b60806072565b56",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "30000", "balance" : "60000",
"code" : "0x", "code" : "0x",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "470000", "balance" : "440000",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "34c16a291d6bdb8a48cabda1af07fc654e147e715705b1fde0e4f86d021ca627", "postStateRoot" : "28775a9bfb2082afcf55670f0cec3345867d51cf068580a38bb823d375e44f1a",
"pre" : { "pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000", "balance" : "100000",
"code" : "0x60003560e060020a90048063296df0df1460295780634893d88a146035578063981a316514604157005b602f604d565b60006000f35b603b6062565b60006000f35b6047605a565b60006000f35b5b600115605857604e565b565b60606062565b565b6068605a565b56", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463296df0df811460415780634893d88a14604d578063981a316514605957005b60476065565b60006000f35b6053607a565b60006000f35b605f6072565b60006000f35b5b6001156070576066565b565b6078607a565b565b60806072565b56",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
@ -251,9 +248,8 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "testRecursiveMethods()",
"data" : "0x981a3165", "data" : "0x981a3165",
"gasLimit" : "30000", "gasLimit" : "60000",
"gasPrice" : "1", "gasPrice" : "1",
"nonce" : "0", "nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
@ -321,7 +317,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run()",
"data" : "0xc0406226", "data" : "0xc0406226",
"gasLimit" : "350000", "gasLimit" : "350000",
"gasPrice" : "1", "gasPrice" : "1",
@ -384,7 +379,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run(uint256)",
"data" : "0xa444f5e90000000000000000000000000000000000000000000000000000000000000204", "data" : "0xa444f5e90000000000000000000000000000000000000000000000000000000000000204",
"gasLimit" : "300000", "gasLimit" : "300000",
"gasPrice" : "1", "gasPrice" : "1",
@ -480,7 +474,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run(uint256)",
"data" : "0xa444f5e90000000000000000000000000000000000000000000000000000000000000004", "data" : "0xa444f5e90000000000000000000000000000000000000000000000000000000000000004",
"gasLimit" : "300000", "gasLimit" : "300000",
"gasPrice" : "1", "gasPrice" : "1",
@ -505,31 +498,32 @@
"post" : { "post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100100", "balance" : "100100",
"code" : "0x60003560e060020a90048063c040622614610021578063e97384dc1461003357005b610029610045565b8060005260206000f35b61003b610054565b8060005260206000f35b600061004f610054565b905090565b60006001905041600160a060020a0316732adc25665018aa1fe0e6bc666dac8fc2697ff9ba14156100845761008d565b60009050610172565b446302b8feb0141561009e576100a7565b60009050610172565b45683635c9adc5dea0000014156100bd576100c6565b60009050610172565b43607814156100d4576100dd565b60009050610172565b33600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561010757610110565b60009050610172565b346064141561011e57610127565b60009050610172565b3a600114156101355761013e565b60009050610172565b32600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561016857610171565b60009050610172565b5b9056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463c04062268114610039578063e97384dc1461004b57005b61004161005d565b8060005260206000f35b61005361008c565b8060005260206000f35b600061006761008c565b600060006101000a81548160ff0219169083021790555060ff60016000540416905090565b6001732adc25665018aa1fe0e6bc666dac8fc2697ff9ba73ffffffffffffffffffffffffffffffffffffffff411614156100c5576100cd565b5060006101c7565b446302b8feb014156100de576100e6565b5060006101c7565b45683635c9adc5dea0000014156100fc57610104565b5060006101c7565b43607814156101125761011a565b5060006101c7565b5a503373ffffffffffffffffffffffffffffffffffffffff1673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156101535761015b565b5060006101c7565b346064141561016957610171565b5060006101c7565b3a6001141561017f57610187565b5060006101c7565b3273ffffffffffffffffffffffffffffffffffffffff1673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156101be576101c6565b5060006101c7565b5b9056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
"0x" : "0x01"
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "21820", "balance" : "41878",
"code" : "0x", "code" : "0x",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "978080", "balance" : "958022",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "989a1a0c1eb8ea72f8bccba220d7aaacc7aa51171a0a1e753bbb03893367cbb1", "postStateRoot" : "7cd344479a3d29c91dd9d9492f35811b5671e6a756a6c6dc223961fd34a1038e",
"pre" : { "pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000", "balance" : "100000",
"code" : "0x60003560e060020a90048063c040622614610021578063e97384dc1461003357005b610029610045565b8060005260206000f35b61003b610054565b8060005260206000f35b600061004f610054565b905090565b60006001905041600160a060020a0316732adc25665018aa1fe0e6bc666dac8fc2697ff9ba14156100845761008d565b60009050610172565b446302b8feb0141561009e576100a7565b60009050610172565b45683635c9adc5dea0000014156100bd576100c6565b60009050610172565b43607814156100d4576100dd565b60009050610172565b33600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561010757610110565b60009050610172565b346064141561011e57610127565b60009050610172565b3a600114156101355761013e565b60009050610172565b32600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561016857610171565b60009050610172565b5b9056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463c04062268114610039578063e97384dc1461004b57005b61004161005d565b8060005260206000f35b61005361008c565b8060005260206000f35b600061006761008c565b600060006101000a81548160ff0219169083021790555060ff60016000540416905090565b6001732adc25665018aa1fe0e6bc666dac8fc2697ff9ba73ffffffffffffffffffffffffffffffffffffffff411614156100c5576100cd565b5060006101c7565b446302b8feb014156100de576100e6565b5060006101c7565b45683635c9adc5dea0000014156100fc57610104565b5060006101c7565b43607814156101125761011a565b5060006101c7565b5a503373ffffffffffffffffffffffffffffffffffffffff1673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156101535761015b565b5060006101c7565b346064141561016957610171565b5060006101c7565b3a6001141561017f57610187565b5060006101c7565b3273ffffffffffffffffffffffffffffffffffffffff1673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156101be576101c6565b5060006101c7565b5b9056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
@ -543,7 +537,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run()",
"data" : "0xc0406226", "data" : "0xc0406226",
"gasLimit" : "350000", "gasLimit" : "350000",
"gasPrice" : "1", "gasPrice" : "1",
@ -568,20 +561,21 @@
"post" : { "post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100001", "balance" : "100001",
"code" : "0x60003560e060020a90048063c040622614610021578063ed973fe91461003357005b6100296100ac565b8060005260206000f35b61003b610045565b8060005260206000f35b6000600060606100bc600039606060006000f0905080600160a060020a031663b9c3d0a5602060008260e060020a026000526004600060008660325a03f161008957005b505060005160e11461009a576100a3565b600191506100a8565b600091505b5090565b60006100b6610045565b9050905600605480600c6000396000f30060003560e060020a90048062f55d9d14601e578063b9c3d0a514602d57005b6027600435603d565b60006000f35b6033604b565b8060005260206000f35b80600160a060020a0316ff50565b600060e190509056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463c04062268114610039578063ed973fe91461004b57005b6100416100ea565b8060005260206000f35b61005361005d565b8060005260206000f35b60006000608161011a600039608160006000f0905073ffffffffffffffffffffffffffffffffffffffff811663b9c3d0a5602060007fb9c3d0a50000000000000000000000000000000000000000000000000000000081526004600060008660325a03f16100c757005b505060005160e1146100d8576100e1565b600191506100e6565b600091505b5090565b60006100f461005d565b600060006101000a81548160ff0219169083021790555060ff600160005404169050905600607580600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350462f55d9d81146036578063b9c3d0a514604557005b603f6004356055565b60006000f35b604b6070565b8060005260206000f35b8073ffffffffffffffffffffffffffffffffffffffff16ff50565b60e19056",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
"0x" : "0x01"
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "70652", "balance" : "97325",
"code" : "0x", "code" : "0x",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "929347", "balance" : "902674",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
@ -589,17 +583,17 @@
}, },
"d2571607e241ecf590ed94b12d87c94babe36db6" : { "d2571607e241ecf590ed94b12d87c94babe36db6" : {
"balance" : "0", "balance" : "0",
"code" : "0x60003560e060020a90048062f55d9d14601e578063b9c3d0a514602d57005b6027600435603d565b60006000f35b6033604b565b8060005260206000f35b80600160a060020a0316ff50565b600060e190509056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350462f55d9d81146036578063b9c3d0a514604557005b603f6004356055565b60006000f35b604b6070565b8060005260206000f35b8073ffffffffffffffffffffffffffffffffffffffff16ff50565b60e19056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "4443b958061e0151621819e559aba5e36640e0a46aba770d2f4431faa9f484f9", "postStateRoot" : "8af7e668bc981aaa612683f34062e73fbcbb262d9394b199bdb08663d93c53c0",
"pre" : { "pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000", "balance" : "100000",
"code" : "0x60003560e060020a90048063c040622614610021578063ed973fe91461003357005b6100296100ac565b8060005260206000f35b61003b610045565b8060005260206000f35b6000600060606100bc600039606060006000f0905080600160a060020a031663b9c3d0a5602060008260e060020a026000526004600060008660325a03f161008957005b505060005160e11461009a576100a3565b600191506100a8565b600091505b5090565b60006100b6610045565b9050905600605480600c6000396000f30060003560e060020a90048062f55d9d14601e578063b9c3d0a514602d57005b6027600435603d565b60006000f35b6033604b565b8060005260206000f35b80600160a060020a0316ff50565b600060e190509056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463c04062268114610039578063ed973fe91461004b57005b6100416100ea565b8060005260206000f35b61005361005d565b8060005260206000f35b60006000608161011a600039608160006000f0905073ffffffffffffffffffffffffffffffffffffffff811663b9c3d0a5602060007fb9c3d0a50000000000000000000000000000000000000000000000000000000081526004600060008660325a03f16100c757005b505060005160e1146100d8576100e1565b600191506100e6565b600091505b5090565b60006100f461005d565b600060006101000a81548160ff0219169083021790555060ff600160005404169050905600607580600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350462f55d9d81146036578063b9c3d0a514604557005b603f6004356055565b60006000f35b604b6070565b8060005260206000f35b8073ffffffffffffffffffffffffffffffffffffffff16ff50565b60e19056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
@ -613,7 +607,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run()",
"data" : "0xc0406226", "data" : "0xc0406226",
"gasLimit" : "350000", "gasLimit" : "350000",
"gasPrice" : "1", "gasPrice" : "1",
@ -638,31 +631,32 @@
"post" : { "post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100001", "balance" : "100001",
"code" : "0x60003560e060020a90048063a60eedda14610021578063c04062261461003357005b610029610045565b8060005260206000f35b61003b6100eb565b8060005260206000f35b6000600060606100fb600039606060006000f0905080600160a060020a031662f55d9d600060008260e060020a02600052600441600160a060020a03168152602001600060008660325a03f161009757005b505080600160a060020a031663b9c3d0a5602060008260e060020a026000526004600060008660325a03f16100c857005b505060005160e1146100d9576100e2565b600191506100e7565b600091505b5090565b60006100f5610045565b9050905600605480600c6000396000f30060003560e060020a90048062f55d9d14601e578063b9c3d0a514602d57005b60276004356046565b60006000f35b6033603d565b8060005260206000f35b600060e1905090565b80600160a060020a0316ff5056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463a60eedda8114610039578063c04062261461004b57005b61004161005d565b8060005260206000f35b61005361015a565b8060005260206000f35b60006000608161018a600039608160006000f0905073ffffffffffffffffffffffffffffffffffffffff811662f55d9d6000807ef55d9d00000000000000000000000000000000000000000000000000000000825260044173ffffffffffffffffffffffffffffffffffffffff168152602001600060008660325a03f16100e057005b505073ffffffffffffffffffffffffffffffffffffffff811663b9c3d0a5602060007fb9c3d0a50000000000000000000000000000000000000000000000000000000081526004600060008660325a03f161013757005b505060005160e11461014857610151565b60019150610156565b600091505b5090565b600061016461005d565b600060006101000a81548160ff0219169083021790555060ff600160005404169050905600607580600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350462f55d9d81146036578063b9c3d0a514604557005b603f600435605a565b60006000f35b604b6055565b8060005260206000f35b60e190565b8073ffffffffffffffffffffffffffffffffffffffff16ff5056",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
"0x" : "0x01"
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "47010", "balance" : "73539",
"code" : "0x", "code" : "0x",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "952989", "balance" : "926460",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "2d0ec35a9c5c2ccba2bb561164abb54e54f7d83954f0f75284d9b8633fe00e37", "postStateRoot" : "367a4e05a146eef4824adcbb8c7e445dc01852707762a005b01b97ce1eb8622f",
"pre" : { "pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000", "balance" : "100000",
"code" : "0x60003560e060020a90048063a60eedda14610021578063c04062261461003357005b610029610045565b8060005260206000f35b61003b6100eb565b8060005260206000f35b6000600060606100fb600039606060006000f0905080600160a060020a031662f55d9d600060008260e060020a02600052600441600160a060020a03168152602001600060008660325a03f161009757005b505080600160a060020a031663b9c3d0a5602060008260e060020a026000526004600060008660325a03f16100c857005b505060005160e1146100d9576100e2565b600191506100e7565b600091505b5090565b60006100f5610045565b9050905600605480600c6000396000f30060003560e060020a90048062f55d9d14601e578063b9c3d0a514602d57005b60276004356046565b60006000f35b6033603d565b8060005260206000f35b600060e1905090565b80600160a060020a0316ff5056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463a60eedda8114610039578063c04062261461004b57005b61004161005d565b8060005260206000f35b61005361015a565b8060005260206000f35b60006000608161018a600039608160006000f0905073ffffffffffffffffffffffffffffffffffffffff811662f55d9d6000807ef55d9d00000000000000000000000000000000000000000000000000000000825260044173ffffffffffffffffffffffffffffffffffffffff168152602001600060008660325a03f16100e057005b505073ffffffffffffffffffffffffffffffffffffffff811663b9c3d0a5602060007fb9c3d0a50000000000000000000000000000000000000000000000000000000081526004600060008660325a03f161013757005b505060005160e11461014857610151565b60019150610156565b600091505b5090565b600061016461005d565b600060006101000a81548160ff0219169083021790555060ff600160005404169050905600607580600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350462f55d9d81146036578063b9c3d0a514604557005b603f600435605a565b60006000f35b604b6055565b8060005260206000f35b60e190565b8073ffffffffffffffffffffffffffffffffffffffff16ff5056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
@ -676,7 +670,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run()",
"data" : "0xc0406226", "data" : "0xc0406226",
"gasLimit" : "350000", "gasLimit" : "350000",
"gasPrice" : "1", "gasPrice" : "1",
@ -697,35 +690,98 @@
}, },
"logs" : [ "logs" : [
], ],
"out" : "0x0000000000000000000000000000000000000000000000000000000000000000", "out" : "0x",
"post" : { "post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100100", "balance" : "100000",
"code" : "0x60003560e060020a90048063c040622614610021578063e0a9fd281461003357005b610029610045565b8060005260206000f35b61003b610054565b8060005260206000f35b600061004f610054565b905090565b60006001905060007f74657374737472696e67000000000000000000000000000000000000000000008152600a017f030d40000000000000000000000000000000000000000000000000000000000081526003016000207f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d14156100d7576100e0565b60009050610218565b60026020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a017f030d4000000000000000000000000000000000000000000000000000000000008152600301600060008560325a03f161014457005b506000517f3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d11114156101745761017d565b60009050610218565b60036020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a017f030d4000000000000000000000000000000000000000000000000000000000008152600301600060008560325a03f16101e157005b50600051600160a060020a031673cd566972b5e50104011a92b59fa8e0b1234851ae141561020e57610217565b60009050610218565b5b9056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463c04062268114610039578063e0a9fd281461004b57005b61004161005d565b8060005260206000f35b61005361008c565b8060005260206000f35b600061006761008c565b600060006101000a81548160ff0219169083021790555060ff60016000540416905090565b600160007f74657374737472696e67000000000000000000000000000000000000000000008152600a016000207f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d14156100e5576100ed565b5060006101da565b60026020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560325a03f161012b57005b507f3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d111600051141561015b57610163565b5060006101da565b60036020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560325a03f16101a157005b507fcd566972b5e50104011a92b59fa8e0b1234851ae00000000000000000000000060005114156101d1576101d9565b5060006101da565b5b9056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "21544", "balance" : "35000000",
"code" : "0x", "code" : "0x",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "49978356", "balance" : "15000000",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "940c34c6de77d43cccaf37a27032388bc2725da017a49427d7992c315edd70c4", "postStateRoot" : "278ae629f0005a2579ea98acd0189bcbf0a57969b0116c4db92eff9515f5f5fb",
"pre" : { "pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000", "balance" : "100000",
"code" : "0x60003560e060020a90048063c040622614610021578063e0a9fd281461003357005b610029610045565b8060005260206000f35b61003b610054565b8060005260206000f35b600061004f610054565b905090565b60006001905060007f74657374737472696e67000000000000000000000000000000000000000000008152600a017f030d40000000000000000000000000000000000000000000000000000000000081526003016000207f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d14156100d7576100e0565b60009050610218565b60026020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a017f030d4000000000000000000000000000000000000000000000000000000000008152600301600060008560325a03f161014457005b506000517f3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d11114156101745761017d565b60009050610218565b60036020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a017f030d4000000000000000000000000000000000000000000000000000000000008152600301600060008560325a03f16101e157005b50600051600160a060020a031673cd566972b5e50104011a92b59fa8e0b1234851ae141561020e57610217565b60009050610218565b5b9056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463c04062268114610039578063e0a9fd281461004b57005b61004161005d565b8060005260206000f35b61005361008c565b8060005260206000f35b600061006761008c565b600060006101000a81548160ff0219169083021790555060ff60016000540416905090565b600160007f74657374737472696e67000000000000000000000000000000000000000000008152600a016000207f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d14156100e5576100ed565b5060006101da565b60026020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560325a03f161012b57005b507f3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d111600051141561015b57610163565b5060006101da565b60036020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560325a03f16101a157005b507fcd566972b5e50104011a92b59fa8e0b1234851ae00000000000000000000000060005114156101d1576101d9565b5060006101da565b5b9056",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "50000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "0xc0406226",
"gasLimit" : "35000000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100"
}
},
"TestCryptographicFunctionsREM" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1000000000000000000000",
"currentNumber" : "120",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x0000000000000000000000000000000000000000000000000000000000000001",
"post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100100",
"code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463c040622681146037578063e0a9fd2814604757005b603d60bc565b8060005260206000f35b604d6057565b8060005260206000f35b600160007f74657374737472696e67000000000000000000000000000000000000000000008152600a016000207f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d600102141560b15760b8565b50600060b9565b5b90565b600060c46057565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016821790555060ff6000541690509056",
"nonce" : "0",
"storage" : {
"0x" : "0x01"
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "41624",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "49958276",
"code" : "0x",
"nonce" : "1",
"storage" : {
}
}
},
"postStateRoot" : "f8bddcc3fceb378c6b63f774547e8e60375ba8477dbbe000fc83988151198028",
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000",
"code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463c040622681146037578063e0a9fd2814604757005b603d60bc565b8060005260206000f35b604d6057565b8060005260206000f35b600160007f74657374737472696e67000000000000000000000000000000000000000000008152600a016000207f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d600102141560b15760b8565b50600060b9565b5b90565b600060c46057565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016821790555060ff6000541690509056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
@ -739,7 +795,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run()",
"data" : "0xc0406226", "data" : "0xc0406226",
"gasLimit" : "35000000", "gasLimit" : "35000000",
"gasPrice" : "1", "gasPrice" : "1",
@ -764,31 +819,32 @@
"post" : { "post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100001", "balance" : "100001",
"code" : "0x60003560e060020a90048063380e439614601f578063c040622614602f57005b6025603f565b8060005260206000f35b603560f0565b8060005260206000f35b60006000600060009150600092508160001460585760d3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe782131560ca575b600a82121560945781806001019250506080565b81600a14609f5760c6565b600a90505b60008160ff16111560c55781806001900392505080806001900391505060a4565b5b60d2565b6000925060eb565b5b8160001460de5760e6565b6001925060eb565b600092505b505090565b600060f8603f565b90509056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463380e439681146037578063c040622614604757005b603d6084565b8060005260206000f35b604d6057565b8060005260206000f35b6000605f6084565b600060006101000a81548160ff0219169083021790555060ff60016000540416905090565b6000808160011560cd575b600a82121560a157600190910190608f565b81600a1460ac5760c9565b50600a5b60008160ff16111560c85760019182900391900360b0565b5b60d5565b6000925060ed565b8160001460e05760e8565b6001925060ed565b600092505b50509056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
"0x" : "0x01"
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "23092", "balance" : "42952",
"code" : "0x", "code" : "0x",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "976907", "balance" : "957047",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "9f6ebe6ef8a7b6bbf49e7bd85f60b5755d27454b887d000be929c6bcbe3775cc", "postStateRoot" : "5d9414ffd30ec040a59e0a99b7a54097306ee5d426bd8adf8e5a99490ad083c5",
"pre" : { "pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000", "balance" : "100000",
"code" : "0x60003560e060020a90048063380e439614601f578063c040622614602f57005b6025603f565b8060005260206000f35b603560f0565b8060005260206000f35b60006000600060009150600092508160001460585760d3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe782131560ca575b600a82121560945781806001019250506080565b81600a14609f5760c6565b600a90505b60008160ff16111560c55781806001900392505080806001900391505060a4565b5b60d2565b6000925060eb565b5b8160001460de5760e6565b6001925060eb565b600092505b505090565b600060f8603f565b90509056", "code" : "0x7c01000000000000000000000000000000000000000000000000000000006000350463380e439681146037578063c040622614604757005b603d6084565b8060005260206000f35b604d6057565b8060005260206000f35b6000605f6084565b600060006101000a81548160ff0219169083021790555060ff60016000540416905090565b6000808160011560cd575b600a82121560a157600190910190608f565b81600a1460ac5760c9565b50600a5b60008160ff16111560c85760019182900391900360b0565b5b60d5565b6000925060ed565b8160001460e05760e8565b6001925060ed565b600092505b50509056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
@ -802,7 +858,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run()",
"data" : "0xc0406226", "data" : "0xc0406226",
"gasLimit" : "350000", "gasLimit" : "350000",
"gasPrice" : "1", "gasPrice" : "1",
@ -827,36 +882,37 @@
"post" : { "post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100100", "balance" : "100100",
"code" : "0x60003560e060020a900480632a9afb8314610021578063c04062261461003357005b610029610045565b8060005260206000f35b61003b610136565b8060005260206000f35b60006001905060005460ff141561005b57610064565b60009050610133565b60025460005414156100755761007e565b60009050610133565b600154600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156100aa576100b3565b60009050610133565b6003547f676c6f62616c2064617461203332206c656e67746820737472696e670000000014156100e2576100eb565b60009050610133565b600460006000815260200190815260200160002054600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561012957610132565b60009050610133565b5b90565b600060ff60008190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b60018190555060ff6002819055507f676c6f62616c2064617461203332206c656e67746820737472696e670000000060038190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b6004600060008152602001908152602001600020819055506101bf610045565b90509056", "code" : "0x7c010000000000000000000000000000000000000000000000000000000060003504632a9afb838114610039578063c04062261461004b57005b61004161005d565b8060005260206000f35b61005361016c565b8060005260206000f35b600160ff8154141561006e57610076565b506000610169565b60015460035414156100875761008f565b506000610169565b73a94f5374fce5edbc8e2a8697c15331677e6ebf0b73ffffffffffffffffffffffffffffffffffffffff60016002540481161614156100cd576100d5565b506000610169565b7f676c6f62616c2064617461203332206c656e67746820737472696e670000000060045414156101045761010c565b506000610169565b6005600080815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561016057610168565b506000610169565b5b90565b600060ff806001555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b6002805473ffffffffffffffffffffffffffffffffffffffff1916821790555060ff80600355507f676c6f62616c2064617461203332206c656e67746820737472696e6700000000806004555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b6005600080815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff0219169083021790555061022f61005d565b600060006101000a81548160ff0219169083021790555060ff6001600054041690509056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
"0x" : "0xff", "0x" : "0x01",
"0x01" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x01" : "0xff",
"0x02" : "0xff", "0x02" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"0x03" : "0x676c6f62616c2064617461203332206c656e67746820737472696e6700000000", "0x03" : "0xff",
"0x17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" "0x04" : "0x676c6f62616c2064617461203332206c656e67746820737472696e6700000000",
"0x05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "122233", "balance" : "142513",
"code" : "0x", "code" : "0x",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "877667", "balance" : "857387",
"code" : "0x", "code" : "0x",
"nonce" : "1", "nonce" : "1",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "cd199efc068169fa69288eea1531f3eee70c842750f58d1b873fc493ab4e8a80", "postStateRoot" : "fabbcefefcd34f324da40464c4bd8df7a21d379e0a897796d290a2b49e974e88",
"pre" : { "pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100000", "balance" : "100000",
"code" : "0x60003560e060020a900480632a9afb8314610021578063c04062261461003357005b610029610045565b8060005260206000f35b61003b610136565b8060005260206000f35b60006001905060005460ff141561005b57610064565b60009050610133565b60025460005414156100755761007e565b60009050610133565b600154600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156100aa576100b3565b60009050610133565b6003547f676c6f62616c2064617461203332206c656e67746820737472696e670000000014156100e2576100eb565b60009050610133565b600460006000815260200190815260200160002054600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561012957610132565b60009050610133565b5b90565b600060ff60008190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b60018190555060ff6002819055507f676c6f62616c2064617461203332206c656e67746820737472696e670000000060038190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b6004600060008152602001908152602001600020819055506101bf610045565b90509056", "code" : "0x7c010000000000000000000000000000000000000000000000000000000060003504632a9afb838114610039578063c04062261461004b57005b61004161005d565b8060005260206000f35b61005361016c565b8060005260206000f35b600160ff8154141561006e57610076565b506000610169565b60015460035414156100875761008f565b506000610169565b73a94f5374fce5edbc8e2a8697c15331677e6ebf0b73ffffffffffffffffffffffffffffffffffffffff60016002540481161614156100cd576100d5565b506000610169565b7f676c6f62616c2064617461203332206c656e67746820737472696e670000000060045414156101045761010c565b506000610169565b6005600080815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561016057610168565b506000610169565b5b90565b600060ff806001555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b6002805473ffffffffffffffffffffffffffffffffffffffff1916821790555060ff80600355507f676c6f62616c2064617461203332206c656e67746820737472696e6700000000806004555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b6005600080815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff0219169083021790555061022f61005d565b600060006101000a81548160ff0219169083021790555060ff6001600054041690509056",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
@ -870,7 +926,6 @@
} }
}, },
"transaction" : { "transaction" : {
"//" : "run()",
"data" : "0xc0406226", "data" : "0xc0406226",
"gasLimit" : "350000", "gasLimit" : "350000",
"gasPrice" : "1", "gasPrice" : "1",

View file

@ -185,7 +185,7 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state.
if core.IsNonceErr(err) || core.IsInvalidTxErr(err) { if core.IsNonceErr(err) || core.IsInvalidTxErr(err) {
statedb.Set(snapshot) statedb.Set(snapshot)
} }
statedb.Update(vmenv.Gas) statedb.Update()
return ret, vmenv.logs, vmenv.Gas, err return ret, vmenv.logs, vmenv.Gas, err
} }

View file

@ -19,6 +19,7 @@ import (
"github.com/ethereum/go-ethereum/event/filter" "github.com/ethereum/go-ethereum/event/filter"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/rlp"
) )
var ( var (
@ -121,6 +122,7 @@ func cAddress(a []string) []common.Address {
func cTopics(t [][]string) [][]common.Hash { func cTopics(t [][]string) [][]common.Hash {
topics := make([][]common.Hash, len(t)) topics := make([][]common.Hash, len(t))
for i, iv := range t { for i, iv := range t {
topics[i] = make([]common.Hash, len(iv))
for j, jv := range iv { for j, jv := range iv {
topics[i][j] = common.HexToHash(jv) topics[i][j] = common.HexToHash(jv)
} }
@ -128,8 +130,8 @@ func cTopics(t [][]string) [][]common.Hash {
return topics return topics
} }
func (self *XEth) DefaultGas() *big.Int { return defaultGas } func (self *XEth) DefaultGas() *big.Int { return new(big.Int).Set(defaultGas) }
func (self *XEth) DefaultGasPrice() *big.Int { return defaultGasPrice } func (self *XEth) DefaultGasPrice() *big.Int { return new(big.Int).Set(defaultGasPrice) }
func (self *XEth) RemoteMining() *miner.RemoteAgent { return self.agent } func (self *XEth) RemoteMining() *miner.RemoteAgent { return self.agent }
@ -185,12 +187,29 @@ func (self *XEth) EthBlockByHash(strHash string) *types.Block {
return block return block
} }
func (self *XEth) EthTransactionByHash(hash string) *types.Transaction { func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blhash common.Hash, blnum *big.Int, txi uint64) {
data, _ := self.backend.ExtraDb().Get(common.FromHex(hash)) data, _ := self.backend.ExtraDb().Get(common.FromHex(hash))
if len(data) != 0 { if len(data) != 0 {
return types.NewTransactionFromBytes(data) tx = types.NewTransactionFromBytes(data)
} }
return nil
// meta
var txExtra struct {
BlockHash common.Hash
BlockIndex int64
Index uint64
}
v, _ := self.backend.ExtraDb().Get(append(common.FromHex(hash), 0x0001))
r := bytes.NewReader(v)
err := rlp.Decode(r, &txExtra)
if err == nil {
blhash = txExtra.BlockHash
blnum = big.NewInt(txExtra.BlockIndex)
txi = txExtra.Index
}
return
} }
func (self *XEth) BlockByNumber(num int64) *Block { func (self *XEth) BlockByNumber(num int64) *Block {
@ -289,21 +308,19 @@ func (self *XEth) NumberToHuman(balance string) string {
} }
func (self *XEth) StorageAt(addr, storageAddr string) string { func (self *XEth) StorageAt(addr, storageAddr string) string {
storage := self.State().SafeGet(addr).StorageString(storageAddr) return common.ToHex(self.State().state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)))
return common.ToHex(storage.Bytes())
} }
func (self *XEth) BalanceAt(addr string) string { func (self *XEth) BalanceAt(addr string) string {
return self.State().SafeGet(addr).Balance().String() return self.State().state.GetBalance(common.HexToAddress(addr)).String()
} }
func (self *XEth) TxCountAt(address string) int { func (self *XEth) TxCountAt(address string) int {
return int(self.State().SafeGet(address).Nonce()) return int(self.State().state.GetNonce(common.HexToAddress(address)))
} }
func (self *XEth) CodeAt(address string) string { func (self *XEth) CodeAt(address string) string {
return common.ToHex(self.State().SafeGet(address).Code()) return common.ToHex(self.State().state.GetCode(common.HexToAddress(address)))
} }
func (self *XEth) IsContract(address string) bool { func (self *XEth) IsContract(address string) bool {
@ -547,12 +564,13 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
value: common.Big(valueStr), value: common.Big(valueStr),
data: common.FromHex(dataStr), data: common.FromHex(dataStr),
} }
if msg.gas.Cmp(big.NewInt(0)) == 0 { if msg.gas.Cmp(big.NewInt(0)) == 0 {
msg.gas = defaultGas msg.gas = self.DefaultGas()
} }
if msg.gasPrice.Cmp(big.NewInt(0)) == 0 { if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
msg.gasPrice = defaultGasPrice msg.gasPrice = self.DefaultGasPrice()
} }
block := self.CurrentBlock() block := self.CurrentBlock()
@ -598,11 +616,11 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
// TODO: align default values to have the same type, e.g. not depend on // TODO: align default values to have the same type, e.g. not depend on
// common.Value conversions later on // common.Value conversions later on
if gas.Cmp(big.NewInt(0)) == 0 { if gas.Cmp(big.NewInt(0)) == 0 {
gas = defaultGas gas = self.DefaultGas()
} }
if price.Cmp(big.NewInt(0)) == 0 { if price.Cmp(big.NewInt(0)) == 0 {
price = defaultGasPrice price = self.DefaultGasPrice()
} }
data = common.FromHex(codeStr) data = common.FromHex(codeStr)