mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 09:53:48 +00:00
all: resolve merge conflicts with master
This commit is contained in:
commit
aa46e840bf
55 changed files with 9424 additions and 10271 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -42,3 +42,6 @@ profile.cov
|
||||||
/dashboard/assets/node_modules
|
/dashboard/assets/node_modules
|
||||||
/dashboard/assets/stats.json
|
/dashboard/assets/stats.json
|
||||||
/dashboard/assets/bundle.js
|
/dashboard/assets/bundle.js
|
||||||
|
/dashboard/assets/package-lock.json
|
||||||
|
|
||||||
|
**/yarn-error.log
|
||||||
|
|
|
||||||
25
.travis.yml
25
.travis.yml
|
|
@ -14,13 +14,14 @@ matrix:
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
- go run build/ci.go test -coverage
|
- go run build/ci.go test -coverage
|
||||||
|
|
||||||
- os: osx
|
- os: linux
|
||||||
go: 1.9.x
|
dist: trusty
|
||||||
|
sudo: required
|
||||||
|
go: "1.10"
|
||||||
script:
|
script:
|
||||||
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
|
- sudo modprobe fuse
|
||||||
- brew update
|
- sudo chmod 666 /dev/fuse
|
||||||
- brew install caskroom/cask/brew-cask
|
- sudo chown root:$USER /etc/fuse.conf
|
||||||
- brew cask install osxfuse
|
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
- go run build/ci.go test -coverage
|
- go run build/ci.go test -coverage
|
||||||
|
|
||||||
|
|
@ -49,7 +50,7 @@ matrix:
|
||||||
# This builder only tests code linters on latest version of Go
|
# This builder only tests code linters on latest version of Go
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
go: 1.9.x
|
go: "1.10"
|
||||||
env:
|
env:
|
||||||
- lint
|
- lint
|
||||||
git:
|
git:
|
||||||
|
|
@ -61,7 +62,7 @@ matrix:
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.9.x
|
go: "1.10"
|
||||||
env:
|
env:
|
||||||
- ubuntu-ppa
|
- ubuntu-ppa
|
||||||
- azure-linux
|
- azure-linux
|
||||||
|
|
@ -101,7 +102,7 @@ matrix:
|
||||||
dist: trusty
|
dist: trusty
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
go: 1.9.x
|
go: "1.10"
|
||||||
env:
|
env:
|
||||||
- azure-linux-mips
|
- azure-linux-mips
|
||||||
git:
|
git:
|
||||||
|
|
@ -145,7 +146,7 @@ matrix:
|
||||||
git:
|
git:
|
||||||
submodules: false # avoid cloning ethereum/tests
|
submodules: false # avoid cloning ethereum/tests
|
||||||
before_install:
|
before_install:
|
||||||
- curl https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz | tar -xz
|
- curl https://storage.googleapis.com/golang/go1.10.linux-amd64.tar.gz | tar -xz
|
||||||
- export PATH=`pwd`/go/bin:$PATH
|
- export PATH=`pwd`/go/bin:$PATH
|
||||||
- export GOROOT=`pwd`/go
|
- export GOROOT=`pwd`/go
|
||||||
- export GOPATH=$HOME/go
|
- export GOPATH=$HOME/go
|
||||||
|
|
@ -162,7 +163,7 @@ matrix:
|
||||||
|
|
||||||
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.9.x
|
go: "1.10"
|
||||||
env:
|
env:
|
||||||
- azure-osx
|
- azure-osx
|
||||||
- azure-ios
|
- azure-ios
|
||||||
|
|
@ -192,7 +193,7 @@ matrix:
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.9.x
|
go: "1.10"
|
||||||
env:
|
env:
|
||||||
- azure-purge
|
- azure-purge
|
||||||
git:
|
git:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.9-alpine as builder
|
FROM golang:1.10-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache make gcc musl-dev linux-headers
|
RUN apk add --no-cache make gcc musl-dev linux-headers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.9-alpine as builder
|
FROM golang:1.10-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache make gcc musl-dev linux-headers
|
RUN apk add --no-cache make gcc musl-dev linux-headers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -385,8 +385,7 @@ var methodNormalizer = map[Lang]func(string) string{
|
||||||
LangJava: decapitalise,
|
LangJava: decapitalise,
|
||||||
}
|
}
|
||||||
|
|
||||||
// capitalise makes the first character of a string upper case, also removing any
|
// capitalise makes a camel-case string which starts with an upper case character.
|
||||||
// prefixing underscores from the variable names.
|
|
||||||
func capitalise(input string) string {
|
func capitalise(input string) string {
|
||||||
for len(input) > 0 && input[0] == '_' {
|
for len(input) > 0 && input[0] == '_' {
|
||||||
input = input[1:]
|
input = input[1:]
|
||||||
|
|
@ -394,12 +393,42 @@ func capitalise(input string) string {
|
||||||
if len(input) == 0 {
|
if len(input) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return strings.ToUpper(input[:1]) + input[1:]
|
return toCamelCase(strings.ToUpper(input[:1]) + input[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// decapitalise makes the first character of a string lower case.
|
// decapitalise makes a camel-case string which starts with a lower case character.
|
||||||
func decapitalise(input string) string {
|
func decapitalise(input string) string {
|
||||||
return strings.ToLower(input[:1]) + input[1:]
|
for len(input) > 0 && input[0] == '_' {
|
||||||
|
input = input[1:]
|
||||||
|
}
|
||||||
|
if len(input) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return toCamelCase(strings.ToLower(input[:1]) + input[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// toCamelCase converts an under-score string to a camel-case string
|
||||||
|
func toCamelCase(input string) string {
|
||||||
|
toupper := false
|
||||||
|
|
||||||
|
result := ""
|
||||||
|
for k, v := range input {
|
||||||
|
switch {
|
||||||
|
case k == 0:
|
||||||
|
result = strings.ToUpper(string(input[0]))
|
||||||
|
|
||||||
|
case toupper:
|
||||||
|
result += strings.ToUpper(string(v))
|
||||||
|
toupper = false
|
||||||
|
|
||||||
|
case v == '_':
|
||||||
|
toupper = true
|
||||||
|
|
||||||
|
default:
|
||||||
|
result += string(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// structured checks whether a list of ABI data types has enough information to
|
// structured checks whether a list of ABI data types has enough information to
|
||||||
|
|
|
||||||
|
|
@ -506,6 +506,7 @@ var bindTests = []struct {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
// Tests that methods and returns with underscores inside work correctly.
|
||||||
{
|
{
|
||||||
`Underscorer`,
|
`Underscorer`,
|
||||||
`
|
`
|
||||||
|
|
@ -531,9 +532,12 @@ var bindTests = []struct {
|
||||||
function AllPurelyUnderscoredOutput() constant returns (int _, int __) {
|
function AllPurelyUnderscoredOutput() constant returns (int _, int __) {
|
||||||
return (1, 2);
|
return (1, 2);
|
||||||
}
|
}
|
||||||
|
function _under_scored_func() constant returns (int _int) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
`, `6060604052341561000f57600080fd5b6103498061001e6000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461008857806367e6633d146100b85780639df484851461014d578063af7486ab1461017d578063b564b34d146101ad578063e02ab24d146101dd578063e409ca451461020d575b600080fd5b341561009357600080fd5b61009b61023d565b604051808381526020018281526020019250505060405180910390f35b34156100c357600080fd5b6100cb610252565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156101115780820151818401526020810190506100f6565b50505050905090810190601f16801561013e5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561015857600080fd5b6101606102a0565b604051808381526020018281526020019250505060405180910390f35b341561018857600080fd5b6101906102b5565b604051808381526020018281526020019250505060405180910390f35b34156101b857600080fd5b6101c06102ca565b604051808381526020018281526020019250505060405180910390f35b34156101e857600080fd5b6101f06102df565b604051808381526020018281526020019250505060405180910390f35b341561021857600080fd5b6102206102f4565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600061025c610309565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820c11dcfa136fc7d182ee4d34f0b12d988496228f7e2d02d2b5376d996ca1743d00029`,
|
}
|
||||||
`[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`,
|
`, `6060604052341561000f57600080fd5b6103858061001e6000396000f30060606040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461009357806346546dbe146100c357806367e6633d146100ec5780639df4848514610181578063af7486ab146101b1578063b564b34d146101e1578063e02ab24d14610211578063e409ca4514610241575b600080fd5b341561009e57600080fd5b6100a6610271565b604051808381526020018281526020019250505060405180910390f35b34156100ce57600080fd5b6100d6610286565b6040518082815260200191505060405180910390f35b34156100f757600080fd5b6100ff61028e565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561014557808201518184015260208101905061012a565b50505050905090810190601f1680156101725780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561018c57600080fd5b6101946102dc565b604051808381526020018281526020019250505060405180910390f35b34156101bc57600080fd5b6101c46102f1565b604051808381526020018281526020019250505060405180910390f35b34156101ec57600080fd5b6101f4610306565b604051808381526020018281526020019250505060405180910390f35b341561021c57600080fd5b61022461031b565b604051808381526020018281526020019250505060405180910390f35b341561024c57600080fd5b610254610330565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600080905090565b6000610298610345565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820d1a53d9de9d1e3d55cb3dc591900b63c4f1ded79114f7b79b332684840e186a40029`,
|
||||||
|
`[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_under_scored_func","outputs":[{"name":"_int","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`,
|
||||||
`
|
`
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
|
|
@ -562,6 +566,7 @@ var bindTests = []struct {
|
||||||
a, b, _ = underscorer.UpperUpperCollision(nil)
|
a, b, _ = underscorer.UpperUpperCollision(nil)
|
||||||
a, b, _ = underscorer.PurelyUnderscoredOutput(nil)
|
a, b, _ = underscorer.PurelyUnderscoredOutput(nil)
|
||||||
a, b, _ = underscorer.AllPurelyUnderscoredOutput(nil)
|
a, b, _ = underscorer.AllPurelyUnderscoredOutput(nil)
|
||||||
|
a, _ = underscorer.UnderScoredFunc(nil)
|
||||||
|
|
||||||
fmt.Println(a, b, err)
|
fmt.Println(a, b, err)
|
||||||
`,
|
`,
|
||||||
|
|
@ -801,7 +806,8 @@ var bindTests = []struct {
|
||||||
// (See accounts/abi/unpack_test.go for more extensive testing)
|
// (See accounts/abi/unpack_test.go for more extensive testing)
|
||||||
if retrievedArr[4][3][2] != testArr[4][3][2] {
|
if retrievedArr[4][3][2] != testArr[4][3][2] {
|
||||||
t.Fatalf("Retrieved value does not match expected value! got: %d, expected: %d. %v", retrievedArr[4][3][2], testArr[4][3][2], err)
|
t.Fatalf("Retrieved value does not match expected value! got: %d, expected: %d. %v", retrievedArr[4][3][2], testArr[4][3][2], err)
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ environment:
|
||||||
install:
|
install:
|
||||||
- git submodule update --init
|
- git submodule update --init
|
||||||
- rmdir C:\go /s /q
|
- rmdir C:\go /s /q
|
||||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.9.2.windows-%GETH_ARCH%.zip
|
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.windows-%GETH_ARCH%.zip
|
||||||
- 7z x go1.9.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
- 7z x go1.10.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||||
- go version
|
- go version
|
||||||
- gcc --version
|
- gcc --version
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,7 @@
|
||||||
|
|
||||||
Tagged releases and develop branch commits are available as installable Debian packages
|
Tagged releases and develop branch commits are available as installable Debian packages
|
||||||
for Ubuntu. Packages are built for the all Ubuntu versions which are supported by
|
for Ubuntu. Packages are built for the all Ubuntu versions which are supported by
|
||||||
Canonical:
|
Canonical.
|
||||||
|
|
||||||
- Trusty Tahr (14.04 LTS)
|
|
||||||
- Xenial Xerus (16.04 LTS)
|
|
||||||
- Yakkety Yak (16.10)
|
|
||||||
- Zesty Zapus (17.04)
|
|
||||||
|
|
||||||
Packages of develop branch commits have suffix -unstable and cannot be installed alongside
|
Packages of develop branch commits have suffix -unstable and cannot be installed alongside
|
||||||
the stable version. Switching between release streams requires user intervention.
|
the stable version. Switching between release streams requires user intervention.
|
||||||
|
|
@ -21,18 +16,18 @@ variable which Travis CI makes available to certain builds.
|
||||||
We want to build go-ethereum with the most recent version of Go, irrespective of the Go
|
We want to build go-ethereum with the most recent version of Go, irrespective of the Go
|
||||||
version that is available in the main Ubuntu repository. In order to make this possible,
|
version that is available in the main Ubuntu repository. In order to make this possible,
|
||||||
our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on
|
our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on
|
||||||
golang-1.9, which is co-installable alongside the regular golang package. PPA dependencies
|
golang-1.10, which is co-installable alongside the regular golang package. PPA dependencies
|
||||||
can be edited at https://launchpad.net/%7Eethereum/+archive/ubuntu/ethereum/+edit-dependencies
|
can be edited at https://launchpad.net/%7Eethereum/+archive/ubuntu/ethereum/+edit-dependencies
|
||||||
|
|
||||||
## Building Packages Locally (for testing)
|
## Building Packages Locally (for testing)
|
||||||
|
|
||||||
You need to run Ubuntu to do test packaging.
|
You need to run Ubuntu to do test packaging.
|
||||||
|
|
||||||
Add the gophers PPA and install Go 1.9 and Debian packaging tools:
|
Add the gophers PPA and install Go 1.10 and Debian packaging tools:
|
||||||
|
|
||||||
$ sudo apt-add-repository ppa:gophers/ubuntu/archive
|
$ sudo apt-add-repository ppa:gophers/ubuntu/archive
|
||||||
$ sudo apt-get update
|
$ sudo apt-get update
|
||||||
$ sudo apt-get install build-essential golang-1.9 devscripts debhelper
|
$ sudo apt-get install build-essential golang-1.10 devscripts debhelper
|
||||||
|
|
||||||
Create the source packages:
|
Create the source packages:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ Source: {{.Name}}
|
||||||
Section: science
|
Section: science
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: {{.Author}}
|
Maintainer: {{.Author}}
|
||||||
Build-Depends: debhelper (>= 8.0.0), golang-1.9
|
Build-Depends: debhelper (>= 8.0.0), golang-1.10
|
||||||
Standards-Version: 3.9.5
|
Standards-Version: 3.9.5
|
||||||
Homepage: https://ethereum.org
|
Homepage: https://ethereum.org
|
||||||
Vcs-Git: git://github.com/ethereum/go-ethereum.git
|
Vcs-Git: git://github.com/ethereum/go-ethereum.git
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#export DH_VERBOSE=1
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
override_dh_auto_build:
|
override_dh_auto_build:
|
||||||
build/env.sh /usr/lib/go-1.9/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
build/env.sh /usr/lib/go-1.10/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,13 @@ func importChain(ctx *cli.Context) error {
|
||||||
utils.Fatalf("Failed to read database stats: %v", err)
|
utils.Fatalf("Failed to read database stats: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Println(stats)
|
fmt.Println(stats)
|
||||||
|
|
||||||
|
ioStats, err := db.LDB().GetProperty("leveldb.iostats")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read database iostats: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(ioStats)
|
||||||
|
|
||||||
fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses())
|
fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses())
|
||||||
fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads())
|
fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads())
|
||||||
|
|
||||||
|
|
@ -255,6 +262,12 @@ func importChain(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
fmt.Println(stats)
|
fmt.Println(stats)
|
||||||
|
|
||||||
|
ioStats, err = db.LDB().GetProperty("leveldb.iostats")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read database iostats: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(ioStats)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ var (
|
||||||
utils.DashboardAddrFlag,
|
utils.DashboardAddrFlag,
|
||||||
utils.DashboardPortFlag,
|
utils.DashboardPortFlag,
|
||||||
utils.DashboardRefreshFlag,
|
utils.DashboardRefreshFlag,
|
||||||
utils.DashboardAssetsFlag,
|
|
||||||
utils.EthashCacheDirFlag,
|
utils.EthashCacheDirFlag,
|
||||||
utils.EthashCachesInMemoryFlag,
|
utils.EthashCachesInMemoryFlag,
|
||||||
utils.EthashCachesOnDiskFlag,
|
utils.EthashCachesOnDiskFlag,
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ ADD genesis.json /genesis.json
|
||||||
RUN \
|
RUN \
|
||||||
echo 'node server.js &' > wallet.sh && \
|
echo 'node server.js &' > wallet.sh && \
|
||||||
echo 'geth --cache 512 init /genesis.json' >> wallet.sh && \
|
echo 'geth --cache 512 init /genesis.json' >> wallet.sh && \
|
||||||
echo $'geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*"' >> wallet.sh
|
echo $'geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*"' >> wallet.sh
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \
|
sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \
|
||||||
|
|
|
||||||
|
|
@ -209,11 +209,6 @@ var (
|
||||||
Usage: "Dashboard metrics collection refresh rate",
|
Usage: "Dashboard metrics collection refresh rate",
|
||||||
Value: dashboard.DefaultConfig.Refresh,
|
Value: dashboard.DefaultConfig.Refresh,
|
||||||
}
|
}
|
||||||
DashboardAssetsFlag = cli.StringFlag{
|
|
||||||
Name: "dashboard.assets",
|
|
||||||
Usage: "Developer flag to serve the dashboard from the local file system",
|
|
||||||
Value: dashboard.DefaultConfig.Assets,
|
|
||||||
}
|
|
||||||
// Ethash settings
|
// Ethash settings
|
||||||
EthashCacheDirFlag = DirectoryFlag{
|
EthashCacheDirFlag = DirectoryFlag{
|
||||||
Name: "ethash.cachedir",
|
Name: "ethash.cachedir",
|
||||||
|
|
@ -819,6 +814,9 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
||||||
|
|
||||||
if ctx.GlobalIsSet(MaxPeersFlag.Name) {
|
if ctx.GlobalIsSet(MaxPeersFlag.Name) {
|
||||||
cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
|
cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
|
||||||
|
if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) {
|
||||||
|
cfg.MaxPeers += lightPeers
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if lightServer {
|
if lightServer {
|
||||||
cfg.MaxPeers += lightPeers
|
cfg.MaxPeers += lightPeers
|
||||||
|
|
@ -1120,7 +1118,6 @@ func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
|
||||||
cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
|
cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
|
||||||
cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
|
cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
|
||||||
cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
|
cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
|
||||||
cfg.Assets = ctx.GlobalString(DashboardAssetsFlag.Name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterEthService adds an Ethereum client to the stack.
|
// RegisterEthService adds an Ethereum client to the stack.
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,8 @@ func initialize() {
|
||||||
if len(*argIP) == 0 {
|
if len(*argIP) == 0 {
|
||||||
argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ")
|
argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ")
|
||||||
}
|
}
|
||||||
|
} else if *fileReader {
|
||||||
|
*bootstrapMode = true
|
||||||
} else {
|
} else {
|
||||||
if len(*argEnode) == 0 {
|
if len(*argEnode) == 0 {
|
||||||
argEnode = scanLineA("Please enter the peer's enode: ")
|
argEnode = scanLineA("Please enter the peer's enode: ")
|
||||||
|
|
@ -205,11 +207,22 @@ func initialize() {
|
||||||
peers = append(peers, peer)
|
peers = append(peers, peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *mailServerMode {
|
||||||
|
if len(msPassword) == 0 {
|
||||||
|
msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read Mail Server password: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cfg := &whisper.Config{
|
cfg := &whisper.Config{
|
||||||
MaxMessageSize: uint32(*argMaxSize),
|
MaxMessageSize: uint32(*argMaxSize),
|
||||||
MinimumAcceptedPOW: *argPoW,
|
MinimumAcceptedPOW: *argPoW,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shh = whisper.New(cfg)
|
||||||
|
|
||||||
if *argPoW != whisper.DefaultMinimumPoW {
|
if *argPoW != whisper.DefaultMinimumPoW {
|
||||||
err := shh.SetMinimumPoW(*argPoW)
|
err := shh.SetMinimumPoW(*argPoW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -257,18 +270,8 @@ func initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *mailServerMode {
|
if *mailServerMode {
|
||||||
if len(msPassword) == 0 {
|
|
||||||
msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ")
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("Failed to read Mail Server password: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shh = whisper.New(cfg)
|
|
||||||
shh.RegisterServer(&mailServer)
|
shh.RegisterServer(&mailServer)
|
||||||
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW)
|
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW)
|
||||||
} else {
|
|
||||||
shh = whisper.New(cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
server = &p2p.Server{
|
server = &p2p.Server{
|
||||||
|
|
@ -306,7 +309,11 @@ func startServer() error {
|
||||||
configureNode()
|
configureNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !*forwarderMode {
|
if *fileExMode {
|
||||||
|
fmt.Printf("Please type the file name to be send. To quit type: '%s'\n", quitCommand)
|
||||||
|
} else if *fileReader {
|
||||||
|
fmt.Printf("Please type the file name to be decrypted. To quit type: '%s'\n", quitCommand)
|
||||||
|
} else if !*forwarderMode {
|
||||||
fmt.Printf("Please type the message. To quit type: '%s'\n", quitCommand)
|
fmt.Printf("Please type the message. To quit type: '%s'\n", quitCommand)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -566,6 +573,7 @@ func sendMsg(payload []byte) common.Hash {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("failed to create new message: %s", err)
|
utils.Fatalf("failed to create new message: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
envelope, err := msg.Wrap(¶ms)
|
envelope, err := msg.Wrap(¶ms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to seal message: %v \n", err)
|
fmt.Printf("failed to seal message: %v \n", err)
|
||||||
|
|
@ -601,15 +609,17 @@ func messageLoop() {
|
||||||
m2 := af.Retrieve()
|
m2 := af.Retrieve()
|
||||||
messages := append(m1, m2...)
|
messages := append(m1, m2...)
|
||||||
for _, msg := range messages {
|
for _, msg := range messages {
|
||||||
|
reportedOnce := false
|
||||||
|
if !*fileExMode && len(msg.Payload) <= 2048 {
|
||||||
|
printMessageInfo(msg)
|
||||||
|
reportedOnce = true
|
||||||
|
}
|
||||||
|
|
||||||
// All messages are saved upon specifying argSaveDir.
|
// All messages are saved upon specifying argSaveDir.
|
||||||
// fileExMode only specifies how messages are displayed on the console after they are saved.
|
// fileExMode only specifies how messages are displayed on the console after they are saved.
|
||||||
// if fileExMode == true, only the hashes are displayed, since messages might be too big.
|
// if fileExMode == true, only the hashes are displayed, since messages might be too big.
|
||||||
if len(*argSaveDir) > 0 {
|
if len(*argSaveDir) > 0 {
|
||||||
writeMessageToFile(*argSaveDir, msg)
|
writeMessageToFile(*argSaveDir, msg, !reportedOnce)
|
||||||
}
|
|
||||||
|
|
||||||
if !*fileExMode && len(msg.Payload) <= 2048 {
|
|
||||||
printMessageInfo(msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case <-done:
|
case <-done:
|
||||||
|
|
@ -634,7 +644,11 @@ func printMessageInfo(msg *whisper.ReceivedMessage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage, show bool) {
|
||||||
|
if len(dir) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
timestamp := fmt.Sprintf("%d", msg.Sent)
|
timestamp := fmt.Sprintf("%d", msg.Sent)
|
||||||
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
||||||
|
|
||||||
|
|
@ -643,22 +657,24 @@ func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
||||||
address = crypto.PubkeyToAddress(*msg.Src)
|
address = crypto.PubkeyToAddress(*msg.Src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env := shh.GetEnvelope(msg.EnvelopeHash)
|
||||||
|
if env == nil {
|
||||||
|
fmt.Printf("\nUnexpected error: envelope not found: %x\n", msg.EnvelopeHash)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// this is a sample code; uncomment if you don't want to save your own messages.
|
// this is a sample code; uncomment if you don't want to save your own messages.
|
||||||
//if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
//if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
||||||
// fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name)
|
// fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name)
|
||||||
// return
|
// return
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if len(dir) > 0 {
|
|
||||||
fullpath := filepath.Join(dir, name)
|
fullpath := filepath.Join(dir, name)
|
||||||
err := ioutil.WriteFile(fullpath, msg.Raw, 0644)
|
err := ioutil.WriteFile(fullpath, env.Data, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
||||||
} else {
|
} else if show {
|
||||||
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(msg.Raw))
|
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(env.Data))
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Printf("\n%s {%x}: message received (%d bytes), but not saved: %s\n", timestamp, address, len(msg.Raw), name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -682,18 +698,23 @@ func requestExpiredMessagesLoop() {
|
||||||
for {
|
for {
|
||||||
timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ")
|
timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ")
|
||||||
timeUpp = scanUint("Please enter the upper limit of the time range (unix timestamp): ")
|
timeUpp = scanUint("Please enter the upper limit of the time range (unix timestamp): ")
|
||||||
t = scanLine("Please enter the topic (hexadecimal): ")
|
t = scanLine("Enter the topic (hex). Press enter to request all messages, regardless of the topic: ")
|
||||||
if len(t) >= whisper.TopicLength*2 {
|
if len(t) == whisper.TopicLength*2 {
|
||||||
x, err := hex.DecodeString(t)
|
x, err := hex.DecodeString(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to parse the topic: %s", err)
|
fmt.Printf("Failed to parse the topic: %s \n", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
xt = whisper.BytesToTopic(x)
|
xt = whisper.BytesToTopic(x)
|
||||||
bloom = whisper.TopicToBloom(xt)
|
bloom = whisper.TopicToBloom(xt)
|
||||||
obfuscateBloom(bloom)
|
obfuscateBloom(bloom)
|
||||||
} else {
|
} else if len(t) == 0 {
|
||||||
bloom = whisper.MakeFullNodeBloom()
|
bloom = whisper.MakeFullNodeBloom()
|
||||||
|
} else {
|
||||||
|
fmt.Println("Error: topic is invalid, request aborted")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if timeUpp == 0 {
|
if timeUpp == 0 {
|
||||||
timeUpp = 0xFFFFFFFF
|
timeUpp = 0xFFFFFFFF
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ type solcOutput struct {
|
||||||
func (s *Solidity) makeArgs() []string {
|
func (s *Solidity) makeArgs() []string {
|
||||||
p := []string{
|
p := []string{
|
||||||
"--combined-json", "bin,abi,userdoc,devdoc",
|
"--combined-json", "bin,abi,userdoc,devdoc",
|
||||||
"--add-std", // include standard lib contracts
|
|
||||||
"--optimize", // code optimizer switched on
|
"--optimize", // code optimizer switched on
|
||||||
}
|
}
|
||||||
if s.Major > 0 || s.Minor > 4 || s.Patch > 6 {
|
if s.Major > 0 || s.Minor > 4 || s.Patch > 6 {
|
||||||
|
|
|
||||||
|
|
@ -723,10 +723,13 @@ func (bc *BlockChain) Rollback(chain []common.Hash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetReceiptsData computes all the non-consensus fields of the receipts
|
// SetReceiptsData computes all the non-consensus fields of the receipts
|
||||||
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) {
|
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) error {
|
||||||
signer := types.MakeSigner(config, block.Number())
|
signer := types.MakeSigner(config, block.Number())
|
||||||
|
|
||||||
transactions, logIndex := block.Transactions(), uint(0)
|
transactions, logIndex := block.Transactions(), uint(0)
|
||||||
|
if len(transactions) != len(receipts) {
|
||||||
|
return errors.New("transaction and receipt count mismatch")
|
||||||
|
}
|
||||||
|
|
||||||
for j := 0; j < len(receipts); j++ {
|
for j := 0; j < len(receipts); j++ {
|
||||||
// The transaction hash can be retrieved from the transaction itself
|
// The transaction hash can be retrieved from the transaction itself
|
||||||
|
|
@ -754,6 +757,7 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty
|
||||||
logIndex++
|
logIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertReceiptChain attempts to complete an already existing header chain with
|
// InsertReceiptChain attempts to complete an already existing header chain with
|
||||||
|
|
@ -794,7 +798,9 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Compute all the non-consensus fields of the receipts
|
// Compute all the non-consensus fields of the receipts
|
||||||
SetReceiptsData(bc.chainConfig, block, receipts)
|
if err := SetReceiptsData(bc.chainConfig, block, receipts); err != nil {
|
||||||
|
return i, fmt.Errorf("failed to set receipts data: %v", err)
|
||||||
|
}
|
||||||
// Write all the data out into the database
|
// Write all the data out into the database
|
||||||
if err := WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
if err := WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
||||||
return i, fmt.Errorf("failed to write block body: %v", err)
|
return i, fmt.Errorf("failed to write block body: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -877,16 +877,15 @@ func (pool *TxPool) removeTx(hash common.Hash) {
|
||||||
// Remove the transaction from the pending lists and reset the account nonce
|
// Remove the transaction from the pending lists and reset the account nonce
|
||||||
if pending := pool.pending[addr]; pending != nil {
|
if pending := pool.pending[addr]; pending != nil {
|
||||||
if removed, invalids := pending.Remove(tx); removed {
|
if removed, invalids := pending.Remove(tx); removed {
|
||||||
// If no more transactions are left, remove the list
|
// If no more pending transactions are left, remove the list
|
||||||
if pending.Empty() {
|
if pending.Empty() {
|
||||||
delete(pool.pending, addr)
|
delete(pool.pending, addr)
|
||||||
delete(pool.beats, addr)
|
delete(pool.beats, addr)
|
||||||
} else {
|
}
|
||||||
// Otherwise postpone any invalidated transactions
|
// Postpone any invalidated transactions
|
||||||
for _, tx := range invalids {
|
for _, tx := range invalids {
|
||||||
pool.enqueueTx(tx.Hash(), tx)
|
pool.enqueueTx(tx.Hash(), tx)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Update the account nonce if needed
|
// Update the account nonce if needed
|
||||||
if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce {
|
if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce {
|
||||||
pool.pendingState.SetNonce(addr, nonce)
|
pool.pendingState.SetNonce(addr, nonce)
|
||||||
|
|
|
||||||
|
|
@ -557,74 +557,112 @@ func TestTransactionDropping(t *testing.T) {
|
||||||
func TestTransactionPostponing(t *testing.T) {
|
func TestTransactionPostponing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create a test account and fund it
|
// Create the pool to test the postponing with
|
||||||
pool, key := setupTxPool()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
|
||||||
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
|
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account, _ := deriveSender(transaction(0, 0, key))
|
// Create two test accounts to produce different gap profiles with
|
||||||
pool.currentState.AddBalance(account, big.NewInt(1000))
|
keys := make([]*ecdsa.PrivateKey, 2)
|
||||||
|
accs := make([]common.Address, len(keys))
|
||||||
|
|
||||||
// Add a batch consecutive pending transactions for validation
|
for i := 0; i < len(keys); i++ {
|
||||||
txns := []*types.Transaction{}
|
keys[i], _ = crypto.GenerateKey()
|
||||||
for i := 0; i < 100; i++ {
|
accs[i] = crypto.PubkeyToAddress(keys[i].PublicKey)
|
||||||
var tx *types.Transaction
|
|
||||||
if i%2 == 0 {
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100))
|
||||||
tx = transaction(uint64(i), 100, key)
|
}
|
||||||
} else {
|
// Add a batch consecutive pending transactions for validation
|
||||||
tx = transaction(uint64(i), 500, key)
|
txs := []*types.Transaction{}
|
||||||
|
for i, key := range keys {
|
||||||
|
|
||||||
|
for j := 0; j < 100; j++ {
|
||||||
|
var tx *types.Transaction
|
||||||
|
if (i+j)%2 == 0 {
|
||||||
|
tx = transaction(uint64(j), 25000, key)
|
||||||
|
} else {
|
||||||
|
tx = transaction(uint64(j), 50000, key)
|
||||||
|
}
|
||||||
|
txs = append(txs, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, err := range pool.AddRemotes(txs) {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("tx %d: failed to add transactions: %v", i, err)
|
||||||
}
|
}
|
||||||
pool.promoteTx(account, tx.Hash(), tx)
|
|
||||||
txns = append(txns, tx)
|
|
||||||
}
|
}
|
||||||
// Check that pre and post validations leave the pool as is
|
// Check that pre and post validations leave the pool as is
|
||||||
if pool.pending[account].Len() != len(txns) {
|
if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) {
|
||||||
t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns))
|
t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs))
|
||||||
}
|
}
|
||||||
if len(pool.queue) != 0 {
|
if len(pool.queue) != 0 {
|
||||||
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0)
|
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
||||||
}
|
}
|
||||||
if len(pool.all) != len(txns) {
|
if len(pool.all) != len(txs) {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns))
|
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs))
|
||||||
}
|
}
|
||||||
pool.lockedReset(nil, nil)
|
pool.lockedReset(nil, nil)
|
||||||
if pool.pending[account].Len() != len(txns) {
|
if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) {
|
||||||
t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns))
|
t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs))
|
||||||
}
|
}
|
||||||
if len(pool.queue) != 0 {
|
if len(pool.queue) != 0 {
|
||||||
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0)
|
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
||||||
}
|
}
|
||||||
if len(pool.all) != len(txns) {
|
if len(pool.all) != len(txs) {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns))
|
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs))
|
||||||
}
|
}
|
||||||
// Reduce the balance of the account, and check that transactions are reorganised
|
// Reduce the balance of the account, and check that transactions are reorganised
|
||||||
pool.currentState.AddBalance(account, big.NewInt(-750))
|
for _, addr := range accs {
|
||||||
|
pool.currentState.AddBalance(addr, big.NewInt(-1))
|
||||||
|
}
|
||||||
pool.lockedReset(nil, nil)
|
pool.lockedReset(nil, nil)
|
||||||
|
|
||||||
if _, ok := pool.pending[account].txs.items[txns[0].Nonce()]; !ok {
|
// The first account's first transaction remains valid, check that subsequent
|
||||||
t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txns[0])
|
// ones are either filtered out, or queued up for later.
|
||||||
|
if _, ok := pool.pending[accs[0]].txs.items[txs[0].Nonce()]; !ok {
|
||||||
|
t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txs[0])
|
||||||
}
|
}
|
||||||
if _, ok := pool.queue[account].txs.items[txns[0].Nonce()]; ok {
|
if _, ok := pool.queue[accs[0]].txs.items[txs[0].Nonce()]; ok {
|
||||||
t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txns[0])
|
t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txs[0])
|
||||||
}
|
}
|
||||||
for i, tx := range txns[1:] {
|
for i, tx := range txs[1:100] {
|
||||||
if i%2 == 1 {
|
if i%2 == 1 {
|
||||||
if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok {
|
if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok {
|
||||||
t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx)
|
t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx)
|
||||||
}
|
}
|
||||||
if _, ok := pool.queue[account].txs.items[tx.Nonce()]; !ok {
|
if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; !ok {
|
||||||
t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx)
|
t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok {
|
if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok {
|
||||||
t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx)
|
t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx)
|
||||||
}
|
}
|
||||||
if _, ok := pool.queue[account].txs.items[tx.Nonce()]; ok {
|
if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; ok {
|
||||||
t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx)
|
t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(pool.all) != len(txns)/2 {
|
// The second account's first transaction got invalid, check that all transactions
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)/2)
|
// are either filtered out, or queued up for later.
|
||||||
|
if pool.pending[accs[1]] != nil {
|
||||||
|
t.Errorf("invalidated account still has pending transactions")
|
||||||
|
}
|
||||||
|
for i, tx := range txs[100:] {
|
||||||
|
if i%2 == 1 {
|
||||||
|
if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; !ok {
|
||||||
|
t.Errorf("tx %d: valid but future transaction missing from future queue: %v", 100+i, tx)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; ok {
|
||||||
|
t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", 100+i, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(pool.all) != len(txs)/2 {
|
||||||
|
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)/2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -949,11 +987,11 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
|
||||||
account2, _ := deriveSender(transaction(0, 0, key2))
|
account2, _ := deriveSender(transaction(0, 0, key2))
|
||||||
pool2.currentState.AddBalance(account2, big.NewInt(1000000))
|
pool2.currentState.AddBalance(account2, big.NewInt(1000000))
|
||||||
|
|
||||||
txns := []*types.Transaction{}
|
txs := []*types.Transaction{}
|
||||||
for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ {
|
for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ {
|
||||||
txns = append(txns, transaction(origin+i, 100000, key2))
|
txs = append(txs, transaction(origin+i, 100000, key2))
|
||||||
}
|
}
|
||||||
pool2.AddRemotes(txns)
|
pool2.AddRemotes(txs)
|
||||||
|
|
||||||
// Ensure the batch optimization honors the same pool mechanics
|
// Ensure the batch optimization honors the same pool mechanics
|
||||||
if len(pool1.pending) != len(pool2.pending) {
|
if len(pool1.pending) != len(pool2.pending) {
|
||||||
|
|
@ -1124,7 +1162,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
defer sub.Unsubscribe()
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
// Create a number of test accounts and fund them
|
// Create a number of test accounts and fund them
|
||||||
keys := make([]*ecdsa.PrivateKey, 3)
|
keys := make([]*ecdsa.PrivateKey, 4)
|
||||||
for i := 0; i < len(keys); i++ {
|
for i := 0; i < len(keys); i++ {
|
||||||
keys[i], _ = crypto.GenerateKey()
|
keys[i], _ = crypto.GenerateKey()
|
||||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||||
|
|
@ -1136,24 +1174,28 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0]))
|
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0]))
|
||||||
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0]))
|
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0]))
|
||||||
|
|
||||||
|
txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[1]))
|
||||||
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[1]))
|
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[1]))
|
||||||
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[1]))
|
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[1]))
|
||||||
txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[1]))
|
|
||||||
|
|
||||||
ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[2])
|
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[2]))
|
||||||
|
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2]))
|
||||||
|
txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[2]))
|
||||||
|
|
||||||
|
ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[3])
|
||||||
|
|
||||||
// Import the batch and that both pending and queued transactions match up
|
// Import the batch and that both pending and queued transactions match up
|
||||||
pool.AddRemotes(txs)
|
pool.AddRemotes(txs)
|
||||||
pool.AddLocal(ltx)
|
pool.AddLocal(ltx)
|
||||||
|
|
||||||
pending, queued := pool.Stats()
|
pending, queued := pool.Stats()
|
||||||
if pending != 4 {
|
if pending != 7 {
|
||||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4)
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7)
|
||||||
}
|
}
|
||||||
if queued != 3 {
|
if queued != 3 {
|
||||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 4); err != nil {
|
if err := validateEvents(events, 7); err != nil {
|
||||||
t.Fatalf("original event firing failed: %v", err)
|
t.Fatalf("original event firing failed: %v", err)
|
||||||
}
|
}
|
||||||
if err := validateTxPoolInternals(pool); err != nil {
|
if err := validateTxPoolInternals(pool); err != nil {
|
||||||
|
|
@ -1166,8 +1208,8 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
if pending != 2 {
|
if pending != 2 {
|
||||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||||
}
|
}
|
||||||
if queued != 3 {
|
if queued != 5 {
|
||||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 0); err != nil {
|
if err := validateEvents(events, 0); err != nil {
|
||||||
t.Fatalf("reprice event firing failed: %v", err)
|
t.Fatalf("reprice event firing failed: %v", err)
|
||||||
|
|
@ -1179,7 +1221,10 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); err != ErrUnderpriced {
|
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); err != ErrUnderpriced {
|
||||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||||
}
|
}
|
||||||
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced {
|
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced {
|
||||||
|
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||||
|
}
|
||||||
|
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); err != ErrUnderpriced {
|
||||||
t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 0); err != nil {
|
if err := validateEvents(events, 0); err != nil {
|
||||||
|
|
@ -1189,7 +1234,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
t.Fatalf("pool internal state corrupted: %v", err)
|
t.Fatalf("pool internal state corrupted: %v", err)
|
||||||
}
|
}
|
||||||
// However we can add local underpriced transactions
|
// However we can add local underpriced transactions
|
||||||
tx := pricedTransaction(1, 100000, big.NewInt(1), keys[2])
|
tx := pricedTransaction(1, 100000, big.NewInt(1), keys[3])
|
||||||
if err := pool.AddLocal(tx); err != nil {
|
if err := pool.AddLocal(tx); err != nil {
|
||||||
t.Fatalf("failed to add underpriced local transaction: %v", err)
|
t.Fatalf("failed to add underpriced local transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1202,6 +1247,22 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
if err := validateTxPoolInternals(pool); err != nil {
|
if err := validateTxPoolInternals(pool); err != nil {
|
||||||
t.Fatalf("pool internal state corrupted: %v", err)
|
t.Fatalf("pool internal state corrupted: %v", err)
|
||||||
}
|
}
|
||||||
|
// And we can fill gaps with properly priced transactions
|
||||||
|
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil {
|
||||||
|
t.Fatalf("failed to add pending transaction: %v", err)
|
||||||
|
}
|
||||||
|
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(2), keys[1])); err != nil {
|
||||||
|
t.Fatalf("failed to add pending transaction: %v", err)
|
||||||
|
}
|
||||||
|
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(2), keys[2])); err != nil {
|
||||||
|
t.Fatalf("failed to add queued transaction: %v", err)
|
||||||
|
}
|
||||||
|
if err := validateEvents(events, 5); err != nil {
|
||||||
|
t.Fatalf("post-reprice event firing failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := validateTxPoolInternals(pool); err != nil {
|
||||||
|
t.Fatalf("pool internal state corrupted: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that setting the transaction pool gas price to a higher value does not
|
// Tests that setting the transaction pool gas price to a higher value does not
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bigZero = new(big.Int)
|
bigZero = new(big.Int)
|
||||||
|
tt255 = math.BigPow(2, 255)
|
||||||
|
tt256 = math.BigPow(2, 256)
|
||||||
errWriteProtection = errors.New("evm: write protection")
|
errWriteProtection = errors.New("evm: write protection")
|
||||||
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
||||||
errExecutionReverted = errors.New("evm: execution reverted")
|
errExecutionReverted = errors.New("evm: execution reverted")
|
||||||
|
|
@ -191,50 +193,71 @@ func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(math.S256(y)) < 0 {
|
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
|
||||||
} else {
|
|
||||||
stack.push(new(big.Int))
|
|
||||||
}
|
|
||||||
|
|
||||||
evm.interpreter.intPool.put(x, y)
|
xSign := x.Cmp(tt255)
|
||||||
|
ySign := y.Cmp(tt255)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case xSign >= 0 && ySign < 0:
|
||||||
|
y.SetUint64(1)
|
||||||
|
|
||||||
|
case xSign < 0 && ySign >= 0:
|
||||||
|
y.SetUint64(0)
|
||||||
|
|
||||||
|
default:
|
||||||
|
if x.Cmp(y) < 0 {
|
||||||
|
y.SetUint64(1)
|
||||||
|
} else {
|
||||||
|
y.SetUint64(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(y) > 0 {
|
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
|
||||||
} else {
|
|
||||||
stack.push(new(big.Int))
|
|
||||||
}
|
|
||||||
|
|
||||||
evm.interpreter.intPool.put(x, y)
|
xSign := x.Cmp(tt255)
|
||||||
|
ySign := y.Cmp(tt255)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case xSign >= 0 && ySign < 0:
|
||||||
|
y.SetUint64(0)
|
||||||
|
|
||||||
|
case xSign < 0 && ySign >= 0:
|
||||||
|
y.SetUint64(1)
|
||||||
|
|
||||||
|
default:
|
||||||
|
if x.Cmp(y) > 0 {
|
||||||
|
y.SetUint64(1)
|
||||||
|
} else {
|
||||||
|
y.SetUint64(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(y) == 0 {
|
if x.Cmp(y) == 0 {
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
y.SetUint64(1)
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
y.SetUint64(0)
|
||||||
}
|
}
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
evm.interpreter.intPool.put(x, y)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x := stack.pop()
|
x := stack.peek()
|
||||||
if x.Sign() > 0 {
|
if x.Sign() > 0 {
|
||||||
stack.push(new(big.Int))
|
x.SetUint64(0)
|
||||||
} else {
|
} else {
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
x.SetUint64(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
evm.interpreter.intPool.put(x)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ func TestSAR(t *testing.T) {
|
||||||
|
|
||||||
func TestSGT(t *testing.T) {
|
func TestSGT(t *testing.T) {
|
||||||
tests := []twoOperandTest{
|
tests := []twoOperandTest{
|
||||||
|
|
||||||
{"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
|
|
@ -171,6 +172,8 @@ func TestSGT(t *testing.T) {
|
||||||
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
|
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||||
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
|
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||||
|
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
}
|
}
|
||||||
testTwoOperandOp(t, tests, opSgt)
|
testTwoOperandOp(t, tests, opSgt)
|
||||||
}
|
}
|
||||||
|
|
@ -187,6 +190,8 @@ func TestSLT(t *testing.T) {
|
||||||
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||||
|
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
|
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||||
}
|
}
|
||||||
testTwoOperandOp(t, tests, opSlt)
|
testTwoOperandOp(t, tests, opSlt)
|
||||||
}
|
}
|
||||||
|
|
@ -349,7 +354,11 @@ func BenchmarkOpEq(b *testing.B) {
|
||||||
|
|
||||||
opBenchmark(b, opEq, x, y)
|
opBenchmark(b, opEq, x, y)
|
||||||
}
|
}
|
||||||
|
func BenchmarkOpEq2(b *testing.B) {
|
||||||
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
||||||
|
y := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201fffffffe"
|
||||||
|
opBenchmark(b, opEq, x, y)
|
||||||
|
}
|
||||||
func BenchmarkOpAnd(b *testing.B) {
|
func BenchmarkOpAnd(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||||
|
|
@ -412,3 +421,7 @@ func BenchmarkOpSAR(b *testing.B) {
|
||||||
|
|
||||||
opBenchmark(b, opSAR, x, y)
|
opBenchmark(b, opSAR, x, y)
|
||||||
}
|
}
|
||||||
|
func BenchmarkOpIsZero(b *testing.B) {
|
||||||
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
||||||
|
opBenchmark(b, opIszero, x)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,28 +12,27 @@ The client's UI uses [React][React] with JSX syntax, which is validated by the [
|
||||||
As the dashboard depends on certain NPM packages (which are not included in the `go-ethereum` repo), these need to be installed first:
|
As the dashboard depends on certain NPM packages (which are not included in the `go-ethereum` repo), these need to be installed first:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ (cd dashboard/assets && npm install)
|
$ (cd dashboard/assets && yarn install && yarn flow)
|
||||||
$ (cd dashboard/assets && ./node_modules/.bin/flow-typed install)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Normally the dashboard assets are bundled into Geth via `go-bindata` to avoid external dependencies. Rebuilding Geth after each UI modification however is not feasible from a developer perspective. Instead, we can run `webpack` in watch mode to automatically rebundle the UI, and ask `geth` to use external assets to not rely on compiled resources:
|
Normally the dashboard assets are bundled into Geth via `go-bindata` to avoid external dependencies. Rebuilding Geth after each UI modification however is not feasible from a developer perspective. Instead, we can run `yarn dev` to watch for file system changes and refresh the browser automatically.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ (cd dashboard/assets && ./node_modules/.bin/webpack --watch)
|
$ geth --dashboard --vmodule=dashboard=5
|
||||||
$ geth --dashboard --dashboard.assets=dashboard/assets --vmodule=dashboard=5
|
$ (cd dashboard/assets && yarn dev)
|
||||||
```
|
```
|
||||||
|
|
||||||
To bundle up the final UI into Geth, run `go generate`:
|
To bundle up the final UI into Geth, run `go generate`:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ go generate ./dashboard
|
$ (cd dashboard && go generate)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Static type checking
|
### Static type checking
|
||||||
|
|
||||||
Since JavaScript doesn't provide type safety, [Flow][Flow] is used to check types. These are only useful during development, so at the end of the process Babel will strip them.
|
Since JavaScript doesn't provide type safety, [Flow][Flow] is used to check types. These are only useful during development, so at the end of the process Babel will strip them.
|
||||||
|
|
||||||
To take advantage of static type checking, your IDE needs to be prepared for it. In case of [Atom][Atom] a configuration guide can be found [here][Atom config]: Install the [Nuclide][Nuclide] package for Flow support, making sure it installs all of its support packages by enabling `Install Recommended Packages on Startup`, and set the path of the `flow-bin` which were installed previously by `npm`.
|
To take advantage of static type checking, your IDE needs to be prepared for it. In case of [Atom][Atom] a configuration guide can be found [here][Atom config]: Install the [Nuclide][Nuclide] package for Flow support, making sure it installs all of its support packages by enabling `Install Recommended Packages on Startup`, and set the path of the `flow-bin` which were installed previously by `yarn`.
|
||||||
|
|
||||||
For more IDE support install the `linter-eslint` package too, which finds the `.eslintrc` file, and provides real-time linting. Atom warns, that these two packages are incompatible, but they seem to work well together. For third-party library errors and auto-completion [flow-typed][flow-typed] is used.
|
For more IDE support install the `linter-eslint` package too, which finds the `.eslintrc` file, and provides real-time linting. Atom warns, that these two packages are incompatible, but they seem to work well together. For third-party library errors and auto-completion [flow-typed][flow-typed] is used.
|
||||||
|
|
||||||
|
|
@ -41,7 +40,7 @@ For more IDE support install the `linter-eslint` package too, which finds the `.
|
||||||
|
|
||||||
[Webpack][Webpack] offers handy tools for visualizing the bundle's dependency tree and space usage.
|
[Webpack][Webpack] offers handy tools for visualizing the bundle's dependency tree and space usage.
|
||||||
|
|
||||||
* Generate the bundle's profile running `webpack --profile --json > stats.json`
|
* Generate the bundle's profile running `yarn stats`
|
||||||
* For the _dependency tree_ go to [Webpack Analyze][WA], and import `stats.json`
|
* For the _dependency tree_ go to [Webpack Analyze][WA], and import `stats.json`
|
||||||
* For the _space usage_ go to [Webpack Visualizer][WV], and import `stats.json`
|
* For the _space usage_ go to [Webpack Visualizer][WV], and import `stats.json`
|
||||||
|
|
||||||
|
|
|
||||||
3737
dashboard/assets.go
3737
dashboard/assets.go
File diff suppressed because one or more lines are too long
|
|
@ -38,15 +38,15 @@ export const percentPlotter = <T>(text: string, mapper: (T => T) = multiplier(1)
|
||||||
};
|
};
|
||||||
|
|
||||||
// unit contains the units for the bytePlotter.
|
// unit contains the units for the bytePlotter.
|
||||||
const unit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
const unit = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
|
||||||
|
|
||||||
// simplifyBytes returns the simplified version of the given value followed by the unit.
|
// simplifyBytes returns the simplified version of the given value followed by the unit.
|
||||||
const simplifyBytes = (x: number) => {
|
const simplifyBytes = (x: number) => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (; x > 1024 && i < 5; i++) {
|
for (; x > 1024 && i < 8; i++) {
|
||||||
x /= 1024;
|
x /= 1024;
|
||||||
}
|
}
|
||||||
return x.toFixed(2).toString().concat(' ', unit[i]);
|
return x.toFixed(2).toString().concat(' ', unit[i], 'B');
|
||||||
};
|
};
|
||||||
|
|
||||||
// bytePlotter renders a tooltip, which displays the payload as a byte value.
|
// bytePlotter renders a tooltip, which displays the payload as a byte value.
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,11 @@ const defaultContent: Content = {
|
||||||
version: null,
|
version: null,
|
||||||
commit: null,
|
commit: null,
|
||||||
},
|
},
|
||||||
home: {
|
home: {},
|
||||||
|
chain: {},
|
||||||
|
txpool: {},
|
||||||
|
network: {},
|
||||||
|
system: {
|
||||||
activeMemory: [],
|
activeMemory: [],
|
||||||
virtualMemory: [],
|
virtualMemory: [],
|
||||||
networkIngress: [],
|
networkIngress: [],
|
||||||
|
|
@ -91,10 +95,6 @@ const defaultContent: Content = {
|
||||||
diskRead: [],
|
diskRead: [],
|
||||||
diskWrite: [],
|
diskWrite: [],
|
||||||
},
|
},
|
||||||
chain: {},
|
|
||||||
txpool: {},
|
|
||||||
network: {},
|
|
||||||
system: {},
|
|
||||||
logs: {
|
logs: {
|
||||||
log: [],
|
log: [],
|
||||||
},
|
},
|
||||||
|
|
@ -108,7 +108,11 @@ const updaters = {
|
||||||
version: replacer,
|
version: replacer,
|
||||||
commit: replacer,
|
commit: replacer,
|
||||||
},
|
},
|
||||||
home: {
|
home: null,
|
||||||
|
chain: null,
|
||||||
|
txpool: null,
|
||||||
|
network: null,
|
||||||
|
system: {
|
||||||
activeMemory: appender(200),
|
activeMemory: appender(200),
|
||||||
virtualMemory: appender(200),
|
virtualMemory: appender(200),
|
||||||
networkIngress: appender(200),
|
networkIngress: appender(200),
|
||||||
|
|
@ -118,10 +122,6 @@ const updaters = {
|
||||||
diskRead: appender(200),
|
diskRead: appender(200),
|
||||||
diskWrite: appender(200),
|
diskWrite: appender(200),
|
||||||
},
|
},
|
||||||
chain: null,
|
|
||||||
txpool: null,
|
|
||||||
network: null,
|
|
||||||
system: null,
|
|
||||||
logs: {
|
logs: {
|
||||||
log: appender(200),
|
log: appender(200),
|
||||||
},
|
},
|
||||||
|
|
@ -136,7 +136,7 @@ const styles = {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// themeStyles returns the styles generated from the theme for the component.
|
// themeStyles returns the styles generated from the theme for the component.
|
||||||
|
|
@ -178,7 +178,8 @@ class Dashboard extends Component<Props, State> {
|
||||||
// reconnect establishes a websocket connection with the server, listens for incoming messages
|
// reconnect establishes a websocket connection with the server, listens for incoming messages
|
||||||
// and tries to reconnect on connection loss.
|
// and tries to reconnect on connection loss.
|
||||||
reconnect = () => {
|
reconnect = () => {
|
||||||
const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://') + window.location.host}/api`);
|
// PROD is defined by webpack.
|
||||||
|
const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://')}${PROD ? window.location.host : 'localhost:8080'}/api`);
|
||||||
server.onopen = () => {
|
server.onopen = () => {
|
||||||
this.setState({content: defaultContent, shouldUpdate: {}});
|
this.setState({content: defaultContent, shouldUpdate: {}});
|
||||||
};
|
};
|
||||||
|
|
@ -217,7 +218,6 @@ class Dashboard extends Component<Props, State> {
|
||||||
return (
|
return (
|
||||||
<div className={this.props.classes.dashboard} style={styles.dashboard}>
|
<div className={this.props.classes.dashboard} style={styles.dashboard}>
|
||||||
<Header
|
<Header
|
||||||
opened={this.state.sideBar}
|
|
||||||
switchSideBar={this.switchSideBar}
|
switchSideBar={this.switchSideBar}
|
||||||
/>
|
/>
|
||||||
<Body
|
<Body
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,17 @@ import {ResponsiveContainer, AreaChart, Area, Tooltip} from 'recharts';
|
||||||
import ChartRow from './ChartRow';
|
import ChartRow from './ChartRow';
|
||||||
import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from './CustomTooltip';
|
import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from './CustomTooltip';
|
||||||
import {styles as commonStyles} from '../common';
|
import {styles as commonStyles} from '../common';
|
||||||
import type {Content} from '../types/content';
|
import type {General, System} from '../types/content';
|
||||||
|
|
||||||
|
const FOOTER_SYNC_ID = 'footerSyncId';
|
||||||
|
|
||||||
|
const CPU = 'cpu';
|
||||||
|
const MEMORY = 'memory';
|
||||||
|
const DISK = 'disk';
|
||||||
|
const TRAFFIC = 'traffic';
|
||||||
|
|
||||||
|
const TOP = 'Top';
|
||||||
|
const BOTTOM = 'Bottom';
|
||||||
|
|
||||||
// styles contains the constant styles of the component.
|
// styles contains the constant styles of the component.
|
||||||
const styles = {
|
const styles = {
|
||||||
|
|
@ -42,15 +52,14 @@ const styles = {
|
||||||
doubleChartWrapper: {
|
doubleChartWrapper: {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
width: '99%',
|
width: '99%',
|
||||||
paddingTop: 5,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// themeStyles returns the styles generated from the theme for the component.
|
// themeStyles returns the styles generated from the theme for the component.
|
||||||
const themeStyles: Object = (theme: Object) => ({
|
const themeStyles: Object = (theme: Object) => ({
|
||||||
footer: {
|
footer: {
|
||||||
backgroundColor: theme.palette.background.appBar,
|
backgroundColor: theme.palette.grey[900],
|
||||||
color: theme.palette.getContrastText(theme.palette.background.appBar),
|
color: theme.palette.getContrastText(theme.palette.grey[900]),
|
||||||
zIndex: theme.zIndex.appBar,
|
zIndex: theme.zIndex.appBar,
|
||||||
height: theme.spacing.unit * 10,
|
height: theme.spacing.unit * 10,
|
||||||
},
|
},
|
||||||
|
|
@ -59,111 +68,108 @@ const themeStyles: Object = (theme: Object) => ({
|
||||||
export type Props = {
|
export type Props = {
|
||||||
classes: Object, // injected by withStyles()
|
classes: Object, // injected by withStyles()
|
||||||
theme: Object,
|
theme: Object,
|
||||||
content: Content,
|
general: General,
|
||||||
|
system: System,
|
||||||
shouldUpdate: Object,
|
shouldUpdate: Object,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Footer renders the footer of the dashboard.
|
// Footer renders the footer of the dashboard.
|
||||||
class Footer extends Component<Props> {
|
class Footer extends Component<Props> {
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
return typeof nextProps.shouldUpdate.home !== 'undefined';
|
return typeof nextProps.shouldUpdate.general !== 'undefined' || typeof nextProps.shouldUpdate.system !== 'undefined';
|
||||||
}
|
}
|
||||||
|
|
||||||
// info renders a label with the given values.
|
// halfHeightChart renders an area chart with half of the height of its parent.
|
||||||
info = (about: string, value: ?string) => (value ? (
|
halfHeightChart = (chartProps, tooltip, areaProps) => (
|
||||||
<Typography type='caption' color='inherit'>
|
<ResponsiveContainer width='100%' height='50%'>
|
||||||
<span style={commonStyles.light}>{about}</span> {value}
|
<AreaChart {...chartProps} >
|
||||||
</Typography>
|
{!tooltip || (<Tooltip cursor={false} content={<CustomTooltip tooltip={tooltip} />} />)}
|
||||||
) : null);
|
<Area isAnimationActive={false} type='monotone' {...areaProps} />
|
||||||
|
</AreaChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
);
|
||||||
|
|
||||||
// doubleChart renders a pair of charts separated by the baseline.
|
// doubleChart renders a pair of charts separated by the baseline.
|
||||||
doubleChart = (syncId, topChart, bottomChart) => {
|
doubleChart = (syncId, chartKey, topChart, bottomChart) => {
|
||||||
const topKey = 'topKey';
|
if (!Array.isArray(topChart.data) || !Array.isArray(bottomChart.data)) {
|
||||||
const bottomKey = 'bottomKey';
|
return null;
|
||||||
const topDefault = topChart.default ? topChart.default : 0;
|
}
|
||||||
const bottomDefault = bottomChart.default ? bottomChart.default : 0;
|
const topDefault = topChart.default || 0;
|
||||||
const topTooltip = topChart.tooltip ? (
|
const bottomDefault = bottomChart.default || 0;
|
||||||
<Tooltip cursor={false} content={<CustomTooltip tooltip={topChart.tooltip} />} />
|
const topKey = `${chartKey}${TOP}`;
|
||||||
) : null;
|
const bottomKey = `${chartKey}${BOTTOM}`;
|
||||||
const bottomTooltip = bottomChart.tooltip ? (
|
|
||||||
<Tooltip cursor={false} content={<CustomTooltip tooltip={bottomChart.tooltip} />} />
|
|
||||||
) : null;
|
|
||||||
const topColor = '#8884d8';
|
const topColor = '#8884d8';
|
||||||
const bottomColor = '#82ca9d';
|
const bottomColor = '#82ca9d';
|
||||||
|
|
||||||
// Put the samples of the two charts into the same array in order to avoid problems
|
|
||||||
// at the synchronized area charts. If one of the two arrays doesn't have value at
|
|
||||||
// a given position, give it a 0 default value.
|
|
||||||
let data = [...topChart.data.map(({value}) => {
|
|
||||||
const d = {};
|
|
||||||
d[topKey] = value || topDefault;
|
|
||||||
return d;
|
|
||||||
})];
|
|
||||||
for (let i = 0; i < data.length && i < bottomChart.data.length; i++) {
|
|
||||||
// The value needs to be negative in order to plot it upside down.
|
|
||||||
const d = bottomChart.data[i];
|
|
||||||
data[i][bottomKey] = d && d.value ? -d.value : bottomDefault;
|
|
||||||
}
|
|
||||||
data = [...data, ...bottomChart.data.slice(data.length).map(({value}) => {
|
|
||||||
const d = {};
|
|
||||||
d[topKey] = topDefault;
|
|
||||||
d[bottomKey] = -value || bottomDefault;
|
|
||||||
return d;
|
|
||||||
})];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={styles.doubleChartWrapper}>
|
<div style={styles.doubleChartWrapper}>
|
||||||
<ResponsiveContainer width='100%' height='50%'>
|
{this.halfHeightChart(
|
||||||
<AreaChart data={data} syncId={syncId} >
|
{
|
||||||
{topTooltip}
|
syncId,
|
||||||
<Area type='monotone' dataKey={topKey} stroke={topColor} fill={topColor} />
|
data: topChart.data.map(({value}) => ({[topKey]: value || topDefault})),
|
||||||
</AreaChart>
|
margin: {top: 5, right: 5, bottom: 0, left: 5},
|
||||||
</ResponsiveContainer>
|
},
|
||||||
<div style={{marginTop: -10, width: '100%', height: '50%'}}>
|
topChart.tooltip,
|
||||||
<ResponsiveContainer width='100%' height='100%'>
|
{dataKey: topKey, stroke: topColor, fill: topColor},
|
||||||
<AreaChart data={data} syncId={syncId} >
|
)}
|
||||||
{bottomTooltip}
|
{this.halfHeightChart(
|
||||||
<Area type='monotone' dataKey={bottomKey} stroke={bottomColor} fill={bottomColor} />
|
{
|
||||||
</AreaChart>
|
syncId,
|
||||||
</ResponsiveContainer>
|
data: bottomChart.data.map(({value}) => ({[bottomKey]: -value || -bottomDefault})),
|
||||||
</div>
|
margin: {top: 0, right: 5, bottom: 5, left: 5},
|
||||||
|
},
|
||||||
|
bottomChart.tooltip,
|
||||||
|
{dataKey: bottomKey, stroke: bottomColor, fill: bottomColor},
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {content} = this.props;
|
const {general, system} = this.props;
|
||||||
const {general, home} = content;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}>
|
<Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}>
|
||||||
<Grid item xs style={styles.chartRowWrapper}>
|
<Grid item xs style={styles.chartRowWrapper}>
|
||||||
<ChartRow>
|
<ChartRow>
|
||||||
{this.doubleChart(
|
{this.doubleChart(
|
||||||
'all',
|
FOOTER_SYNC_ID,
|
||||||
{data: home.processCPU, tooltip: percentPlotter('Process')},
|
CPU,
|
||||||
{data: home.systemCPU, tooltip: percentPlotter('System', multiplier(-1))},
|
{data: system.processCPU, tooltip: percentPlotter('Process load')},
|
||||||
|
{data: system.systemCPU, tooltip: percentPlotter('System load', multiplier(-1))},
|
||||||
)}
|
)}
|
||||||
{this.doubleChart(
|
{this.doubleChart(
|
||||||
'all',
|
FOOTER_SYNC_ID,
|
||||||
{data: home.activeMemory, tooltip: bytePlotter('Active')},
|
MEMORY,
|
||||||
{data: home.virtualMemory, tooltip: bytePlotter('Virtual', multiplier(-1))},
|
{data: system.activeMemory, tooltip: bytePlotter('Active memory')},
|
||||||
|
{data: system.virtualMemory, tooltip: bytePlotter('Virtual memory', multiplier(-1))},
|
||||||
)}
|
)}
|
||||||
{this.doubleChart(
|
{this.doubleChart(
|
||||||
'all',
|
FOOTER_SYNC_ID,
|
||||||
{data: home.diskRead, tooltip: bytePerSecPlotter('Disk Read')},
|
DISK,
|
||||||
{data: home.diskWrite, tooltip: bytePerSecPlotter('Disk Write', multiplier(-1))},
|
{data: system.diskRead, tooltip: bytePerSecPlotter('Disk read')},
|
||||||
|
{data: system.diskWrite, tooltip: bytePerSecPlotter('Disk write', multiplier(-1))},
|
||||||
)}
|
)}
|
||||||
{this.doubleChart(
|
{this.doubleChart(
|
||||||
'all',
|
FOOTER_SYNC_ID,
|
||||||
{data: home.networkIngress, tooltip: bytePerSecPlotter('Download')},
|
TRAFFIC,
|
||||||
{data: home.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))},
|
{data: system.networkIngress, tooltip: bytePerSecPlotter('Download')},
|
||||||
|
{data: system.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))},
|
||||||
)}
|
)}
|
||||||
</ChartRow>
|
</ChartRow>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item >
|
<Grid item >
|
||||||
{this.info('Geth', general.version)}
|
<Typography type='caption' color='inherit'>
|
||||||
{this.info('Commit', general.commit ? general.commit.substring(0, 7) : null)}
|
<span style={commonStyles.light}>Geth</span> {general.version}
|
||||||
|
</Typography>
|
||||||
|
{general.commit && (
|
||||||
|
<Typography type='caption' color='inherit'>
|
||||||
|
<span style={commonStyles.light}>{'Commit '}</span>
|
||||||
|
<a href={`https://github.com/ethereum/go-ethereum/commit/${general.commit}`} target='_blank' style={{color: 'inherit', textDecoration: 'none'}} >
|
||||||
|
{general.commit.substring(0, 8)}
|
||||||
|
</a>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -21,30 +21,16 @@ import React, {Component} from 'react';
|
||||||
import withStyles from 'material-ui/styles/withStyles';
|
import withStyles from 'material-ui/styles/withStyles';
|
||||||
import AppBar from 'material-ui/AppBar';
|
import AppBar from 'material-ui/AppBar';
|
||||||
import Toolbar from 'material-ui/Toolbar';
|
import Toolbar from 'material-ui/Toolbar';
|
||||||
import Transition from 'react-transition-group/Transition';
|
|
||||||
import IconButton from 'material-ui/IconButton';
|
import IconButton from 'material-ui/IconButton';
|
||||||
|
import Icon from 'material-ui/Icon';
|
||||||
|
import MenuIcon from 'material-ui-icons/Menu';
|
||||||
import Typography from 'material-ui/Typography';
|
import Typography from 'material-ui/Typography';
|
||||||
import ChevronLeftIcon from 'material-ui-icons/ChevronLeft';
|
|
||||||
|
|
||||||
import {DURATION} from '../common';
|
|
||||||
|
|
||||||
// styles contains the constant styles of the component.
|
|
||||||
const styles = {
|
|
||||||
arrow: {
|
|
||||||
default: {
|
|
||||||
transition: `transform ${DURATION}ms`,
|
|
||||||
},
|
|
||||||
transition: {
|
|
||||||
entered: {transform: 'rotate(180deg)'},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// themeStyles returns the styles generated from the theme for the component.
|
// themeStyles returns the styles generated from the theme for the component.
|
||||||
const themeStyles = (theme: Object) => ({
|
const themeStyles = (theme: Object) => ({
|
||||||
header: {
|
header: {
|
||||||
backgroundColor: theme.palette.background.appBar,
|
backgroundColor: theme.palette.grey[900],
|
||||||
color: theme.palette.getContrastText(theme.palette.background.appBar),
|
color: theme.palette.getContrastText(theme.palette.grey[900]),
|
||||||
zIndex: theme.zIndex.appBar,
|
zIndex: theme.zIndex.appBar,
|
||||||
},
|
},
|
||||||
toolbar: {
|
toolbar: {
|
||||||
|
|
@ -53,42 +39,28 @@ const themeStyles = (theme: Object) => ({
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
paddingLeft: theme.spacing.unit,
|
paddingLeft: theme.spacing.unit,
|
||||||
|
fontSize: 3 * theme.spacing.unit,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
classes: Object, // injected by withStyles()
|
classes: Object, // injected by withStyles()
|
||||||
opened: boolean,
|
|
||||||
switchSideBar: () => void,
|
switchSideBar: () => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Header renders the header of the dashboard.
|
// Header renders the header of the dashboard.
|
||||||
class Header extends Component<Props> {
|
class Header extends Component<Props> {
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
return nextProps.opened !== this.props.opened;
|
|
||||||
}
|
|
||||||
|
|
||||||
// arrow renders a button, which changes the sidebar's state.
|
|
||||||
arrow = (transitionState: string) => (
|
|
||||||
<IconButton onClick={this.props.switchSideBar}>
|
|
||||||
<ChevronLeftIcon
|
|
||||||
style={{
|
|
||||||
...styles.arrow.default,
|
|
||||||
...styles.arrow.transition[transitionState],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
);
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {classes, opened} = this.props;
|
const {classes} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar position='static' className={classes.header}>
|
<AppBar position='static' className={classes.header}>
|
||||||
<Toolbar className={classes.toolbar}>
|
<Toolbar className={classes.toolbar}>
|
||||||
<Transition mountOnEnter in={opened} timeout={{enter: DURATION}}>
|
<IconButton onClick={this.props.switchSideBar}>
|
||||||
{this.arrow}
|
<Icon>
|
||||||
</Transition>
|
<MenuIcon />
|
||||||
|
</Icon>
|
||||||
|
</IconButton>
|
||||||
<Typography type='title' color='inherit' noWrap className={classes.title}>
|
<Typography type='title' color='inherit' noWrap className={classes.title}>
|
||||||
Go Ethereum Dashboard
|
Go Ethereum Dashboard
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,8 @@ class Main extends Component<Props> {
|
||||||
<div style={styles.wrapper}>
|
<div style={styles.wrapper}>
|
||||||
<div className={classes.content} style={styles.content}>{children}</div>
|
<div className={classes.content} style={styles.content}>{children}</div>
|
||||||
<Footer
|
<Footer
|
||||||
content={content}
|
general={content.general}
|
||||||
|
system={content.system}
|
||||||
shouldUpdate={shouldUpdate}
|
shouldUpdate={shouldUpdate}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ const styles = {
|
||||||
// themeStyles returns the styles generated from the theme for the component.
|
// themeStyles returns the styles generated from the theme for the component.
|
||||||
const themeStyles = theme => ({
|
const themeStyles = theme => ({
|
||||||
list: {
|
list: {
|
||||||
background: theme.palette.background.appBar,
|
background: theme.palette.grey[900],
|
||||||
},
|
},
|
||||||
listItem: {
|
listItem: {
|
||||||
minWidth: theme.spacing.unit * 3,
|
minWidth: theme.spacing.unit * 7,
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
fontSize: theme.spacing.unit * 3,
|
fontSize: theme.spacing.unit * 3,
|
||||||
|
|
|
||||||
7678
dashboard/assets/package-lock.json
generated
7678
dashboard/assets/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -15,11 +15,11 @@
|
||||||
"css-loader": "^0.28.9",
|
"css-loader": "^0.28.9",
|
||||||
"eslint": "^4.16.0",
|
"eslint": "^4.16.0",
|
||||||
"eslint-config-airbnb": "^16.1.0",
|
"eslint-config-airbnb": "^16.1.0",
|
||||||
"eslint-loader": "^1.9.0",
|
"eslint-loader": "^2.0.0",
|
||||||
|
"eslint-plugin-flowtype": "^2.41.0",
|
||||||
"eslint-plugin-import": "^2.8.0",
|
"eslint-plugin-import": "^2.8.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||||
"eslint-plugin-react": "^7.5.1",
|
"eslint-plugin-react": "^7.5.1",
|
||||||
"eslint-plugin-flowtype": "^2.41.0",
|
|
||||||
"file-loader": "^1.1.6",
|
"file-loader": "^1.1.6",
|
||||||
"flow-bin": "^0.63.1",
|
"flow-bin": "^0.63.1",
|
||||||
"flow-bin-loader": "^1.0.2",
|
"flow-bin-loader": "^1.0.2",
|
||||||
|
|
@ -35,6 +35,13 @@
|
||||||
"style-loader": "^0.19.1",
|
"style-loader": "^0.19.1",
|
||||||
"url": "^0.11.0",
|
"url": "^0.11.0",
|
||||||
"url-loader": "^0.6.2",
|
"url-loader": "^0.6.2",
|
||||||
"webpack": "^3.10.0"
|
"webpack": "^3.10.0",
|
||||||
|
"webpack-dev-server": "^2.11.1"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "NODE_ENV=production webpack",
|
||||||
|
"stats": "webpack --profile --json > stats.json",
|
||||||
|
"dev": "webpack-dev-server --port 8081",
|
||||||
|
"flow": "flow-typed install"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,27 +26,20 @@ export type Content = {
|
||||||
logs: Logs,
|
logs: Logs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ChartEntries = Array<ChartEntry>;
|
||||||
|
|
||||||
|
export type ChartEntry = {
|
||||||
|
time: Date,
|
||||||
|
value: number,
|
||||||
|
};
|
||||||
|
|
||||||
export type General = {
|
export type General = {
|
||||||
version: ?string,
|
version: ?string,
|
||||||
commit: ?string,
|
commit: ?string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Home = {
|
export type Home = {
|
||||||
activeMemory: ChartEntries,
|
/* TODO (kurkomisi) */
|
||||||
virtualMemory: ChartEntries,
|
|
||||||
networkIngress: ChartEntries,
|
|
||||||
networkEgress: ChartEntries,
|
|
||||||
processCPU: ChartEntries,
|
|
||||||
systemCPU: ChartEntries,
|
|
||||||
diskRead: ChartEntries,
|
|
||||||
diskWrite: ChartEntries,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ChartEntries = Array<ChartEntry>;
|
|
||||||
|
|
||||||
export type ChartEntry = {
|
|
||||||
time: Date,
|
|
||||||
value: number,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Chain = {
|
export type Chain = {
|
||||||
|
|
@ -62,7 +55,14 @@ export type Network = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type System = {
|
export type System = {
|
||||||
/* TODO (kurkomisi) */
|
activeMemory: ChartEntries,
|
||||||
|
virtualMemory: ChartEntries,
|
||||||
|
networkIngress: ChartEntries,
|
||||||
|
networkEgress: ChartEntries,
|
||||||
|
processCPU: ChartEntries,
|
||||||
|
systemCPU: ChartEntries,
|
||||||
|
diskRead: ChartEntries,
|
||||||
|
diskWrite: ChartEntries,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Logs = {
|
export type Logs = {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ module.exports = {
|
||||||
mangle: false,
|
mangle: false,
|
||||||
beautify: true,
|
beautify: true,
|
||||||
}),
|
}),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
PROD: process.env.NODE_ENV === 'production',
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
|
|
||||||
6551
dashboard/assets/yarn.lock
Normal file
6551
dashboard/assets/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -38,8 +38,4 @@ type Config struct {
|
||||||
|
|
||||||
// Refresh is the refresh rate of the data updates, the chartEntry will be collected this often.
|
// Refresh is the refresh rate of the data updates, the chartEntry will be collected this often.
|
||||||
Refresh time.Duration `toml:",omitempty"`
|
Refresh time.Duration `toml:",omitempty"`
|
||||||
|
|
||||||
// Assets offers a possibility to manually set the dashboard website's location on the server side.
|
|
||||||
// It is useful for debugging, avoids the repeated generation of the binary.
|
|
||||||
Assets string `toml:",omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,21 +16,17 @@
|
||||||
|
|
||||||
package dashboard
|
package dashboard
|
||||||
|
|
||||||
//go:generate npm --prefix ./assets install
|
//go:generate yarn --cwd ./assets install
|
||||||
//go:generate ./assets/node_modules/.bin/webpack --config ./assets/webpack.config.js --context ./assets
|
//go:generate yarn --cwd ./assets build
|
||||||
//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/dashboard.html assets/bundle.js
|
//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/index.html assets/bundle.js
|
||||||
//go:generate sh -c "sed 's#var _bundleJs#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
//go:generate sh -c "sed 's#var _bundleJs#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
||||||
//go:generate sh -c "sed 's#var _dashboardHtml#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
//go:generate sh -c "sed 's#var _indexHtml#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
||||||
//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/public/...
|
|
||||||
//go:generate sh -c "sed 's#var _public#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
|
||||||
//go:generate gofmt -w -s assets.go
|
//go:generate gofmt -w -s assets.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
@ -64,7 +60,7 @@ type Dashboard struct {
|
||||||
|
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
conns map[uint32]*client // Currently live websocket connections
|
conns map[uint32]*client // Currently live websocket connections
|
||||||
charts *HomeMessage
|
charts *SystemMessage
|
||||||
commit string
|
commit string
|
||||||
lock sync.RWMutex // Lock protecting the dashboard's internals
|
lock sync.RWMutex // Lock protecting the dashboard's internals
|
||||||
|
|
||||||
|
|
@ -86,7 +82,7 @@ func New(config *Config, commit string) (*Dashboard, error) {
|
||||||
conns: make(map[uint32]*client),
|
conns: make(map[uint32]*client),
|
||||||
config: config,
|
config: config,
|
||||||
quit: make(chan chan error),
|
quit: make(chan chan error),
|
||||||
charts: &HomeMessage{
|
charts: &SystemMessage{
|
||||||
ActiveMemory: emptyChartEntries(now, activeMemorySampleLimit, config.Refresh),
|
ActiveMemory: emptyChartEntries(now, activeMemorySampleLimit, config.Refresh),
|
||||||
VirtualMemory: emptyChartEntries(now, virtualMemorySampleLimit, config.Refresh),
|
VirtualMemory: emptyChartEntries(now, virtualMemorySampleLimit, config.Refresh),
|
||||||
NetworkIngress: emptyChartEntries(now, networkIngressSampleLimit, config.Refresh),
|
NetworkIngress: emptyChartEntries(now, networkIngressSampleLimit, config.Refresh),
|
||||||
|
|
@ -182,18 +178,7 @@ func (db *Dashboard) webHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
path := r.URL.String()
|
path := r.URL.String()
|
||||||
if path == "/" {
|
if path == "/" {
|
||||||
path = "/dashboard.html"
|
path = "/index.html"
|
||||||
}
|
|
||||||
// If the path of the assets is manually set
|
|
||||||
if db.config.Assets != "" {
|
|
||||||
blob, err := ioutil.ReadFile(filepath.Join(db.config.Assets, path))
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("Failed to read file", "path", path, "err", err)
|
|
||||||
http.Error(w, "not found", http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Write(blob)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
blob, err := Asset(path[1:])
|
blob, err := Asset(path[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -243,7 +228,7 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) {
|
||||||
Version: fmt.Sprintf("v%d.%d.%d%s", params.VersionMajor, params.VersionMinor, params.VersionPatch, versionMeta),
|
Version: fmt.Sprintf("v%d.%d.%d%s", params.VersionMajor, params.VersionMinor, params.VersionPatch, versionMeta),
|
||||||
Commit: db.commit,
|
Commit: db.commit,
|
||||||
},
|
},
|
||||||
Home: &HomeMessage{
|
System: &SystemMessage{
|
||||||
ActiveMemory: db.charts.ActiveMemory,
|
ActiveMemory: db.charts.ActiveMemory,
|
||||||
VirtualMemory: db.charts.VirtualMemory,
|
VirtualMemory: db.charts.VirtualMemory,
|
||||||
NetworkIngress: db.charts.NetworkIngress,
|
NetworkIngress: db.charts.NetworkIngress,
|
||||||
|
|
@ -279,12 +264,14 @@ func (db *Dashboard) collectData() {
|
||||||
systemCPUUsage := gosigar.Cpu{}
|
systemCPUUsage := gosigar.Cpu{}
|
||||||
systemCPUUsage.Get()
|
systemCPUUsage.Get()
|
||||||
var (
|
var (
|
||||||
|
mem runtime.MemStats
|
||||||
|
|
||||||
prevNetworkIngress = metrics.DefaultRegistry.Get("p2p/InboundTraffic").(metrics.Meter).Count()
|
prevNetworkIngress = metrics.DefaultRegistry.Get("p2p/InboundTraffic").(metrics.Meter).Count()
|
||||||
prevNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
prevNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
||||||
prevProcessCPUTime = getProcessCPUTime()
|
prevProcessCPUTime = getProcessCPUTime()
|
||||||
prevSystemCPUUsage = systemCPUUsage
|
prevSystemCPUUsage = systemCPUUsage
|
||||||
prevDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/input").(metrics.Meter).Count()
|
prevDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/read").(metrics.Meter).Count()
|
||||||
prevDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/output").(metrics.Meter).Count()
|
prevDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/write").(metrics.Meter).Count()
|
||||||
|
|
||||||
frequency = float64(db.config.Refresh / time.Second)
|
frequency = float64(db.config.Refresh / time.Second)
|
||||||
numCPU = float64(runtime.NumCPU())
|
numCPU = float64(runtime.NumCPU())
|
||||||
|
|
@ -302,13 +289,13 @@ func (db *Dashboard) collectData() {
|
||||||
curNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
curNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
||||||
curProcessCPUTime = getProcessCPUTime()
|
curProcessCPUTime = getProcessCPUTime()
|
||||||
curSystemCPUUsage = systemCPUUsage
|
curSystemCPUUsage = systemCPUUsage
|
||||||
curDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/input").(metrics.Meter).Count()
|
curDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/read").(metrics.Meter).Count()
|
||||||
curDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/output").(metrics.Meter).Count()
|
curDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/write").(metrics.Meter).Count()
|
||||||
|
|
||||||
deltaNetworkIngress = float64(curNetworkIngress - prevNetworkIngress)
|
deltaNetworkIngress = float64(curNetworkIngress - prevNetworkIngress)
|
||||||
deltaNetworkEgress = float64(curNetworkEgress - prevNetworkEgress)
|
deltaNetworkEgress = float64(curNetworkEgress - prevNetworkEgress)
|
||||||
deltaProcessCPUTime = curProcessCPUTime - prevProcessCPUTime
|
deltaProcessCPUTime = curProcessCPUTime - prevProcessCPUTime
|
||||||
deltaSystemCPUUsage = systemCPUUsage.Delta(prevSystemCPUUsage)
|
deltaSystemCPUUsage = curSystemCPUUsage.Delta(prevSystemCPUUsage)
|
||||||
deltaDiskRead = curDiskRead - prevDiskRead
|
deltaDiskRead = curDiskRead - prevDiskRead
|
||||||
deltaDiskWrite = curDiskWrite - prevDiskWrite
|
deltaDiskWrite = curDiskWrite - prevDiskWrite
|
||||||
)
|
)
|
||||||
|
|
@ -321,7 +308,6 @@ func (db *Dashboard) collectData() {
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
var mem runtime.MemStats
|
|
||||||
runtime.ReadMemStats(&mem)
|
runtime.ReadMemStats(&mem)
|
||||||
activeMemory := &ChartEntry{
|
activeMemory := &ChartEntry{
|
||||||
Time: now,
|
Time: now,
|
||||||
|
|
@ -365,7 +351,7 @@ func (db *Dashboard) collectData() {
|
||||||
db.charts.DiskWrite = append(db.charts.DiskRead[1:], diskWrite)
|
db.charts.DiskWrite = append(db.charts.DiskRead[1:], diskWrite)
|
||||||
|
|
||||||
db.sendToAll(&Message{
|
db.sendToAll(&Message{
|
||||||
Home: &HomeMessage{
|
System: &SystemMessage{
|
||||||
ActiveMemory: ChartEntries{activeMemory},
|
ActiveMemory: ChartEntries{activeMemory},
|
||||||
VirtualMemory: ChartEntries{virtualMemory},
|
VirtualMemory: ChartEntries{virtualMemory},
|
||||||
NetworkIngress: ChartEntries{networkIngress},
|
NetworkIngress: ChartEntries{networkIngress},
|
||||||
|
|
|
||||||
|
|
@ -28,27 +28,20 @@ type Message struct {
|
||||||
Logs *LogsMessage `json:"logs,omitempty"`
|
Logs *LogsMessage `json:"logs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChartEntries []*ChartEntry
|
||||||
|
|
||||||
|
type ChartEntry struct {
|
||||||
|
Time time.Time `json:"time,omitempty"`
|
||||||
|
Value float64 `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type GeneralMessage struct {
|
type GeneralMessage struct {
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version,omitempty"`
|
||||||
Commit string `json:"commit,omitempty"`
|
Commit string `json:"commit,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HomeMessage struct {
|
type HomeMessage struct {
|
||||||
ActiveMemory ChartEntries `json:"activeMemory,omitempty"`
|
/* TODO (kurkomisi) */
|
||||||
VirtualMemory ChartEntries `json:"virtualMemory,omitempty"`
|
|
||||||
NetworkIngress ChartEntries `json:"networkIngress,omitempty"`
|
|
||||||
NetworkEgress ChartEntries `json:"networkEgress,omitempty"`
|
|
||||||
ProcessCPU ChartEntries `json:"processCPU,omitempty"`
|
|
||||||
SystemCPU ChartEntries `json:"systemCPU,omitempty"`
|
|
||||||
DiskRead ChartEntries `json:"diskRead,omitempty"`
|
|
||||||
DiskWrite ChartEntries `json:"diskWrite,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChartEntries []*ChartEntry
|
|
||||||
|
|
||||||
type ChartEntry struct {
|
|
||||||
Time time.Time `json:"time,omitempty"`
|
|
||||||
Value float64 `json:"value,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainMessage struct {
|
type ChainMessage struct {
|
||||||
|
|
@ -64,7 +57,14 @@ type NetworkMessage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SystemMessage struct {
|
type SystemMessage struct {
|
||||||
/* TODO (kurkomisi) */
|
ActiveMemory ChartEntries `json:"activeMemory,omitempty"`
|
||||||
|
VirtualMemory ChartEntries `json:"virtualMemory,omitempty"`
|
||||||
|
NetworkIngress ChartEntries `json:"networkIngress,omitempty"`
|
||||||
|
NetworkEgress ChartEntries `json:"networkEgress,omitempty"`
|
||||||
|
ProcessCPU ChartEntries `json:"processCPU,omitempty"`
|
||||||
|
SystemCPU ChartEntries `json:"systemCPU,omitempty"`
|
||||||
|
DiskRead ChartEntries `json:"diskRead,omitempty"`
|
||||||
|
DiskWrite ChartEntries `json:"diskWrite,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogsMessage struct {
|
type LogsMessage struct {
|
||||||
|
|
|
||||||
|
|
@ -1296,6 +1296,14 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er
|
||||||
headers = headers[limit:]
|
headers = headers[limit:]
|
||||||
origin += uint64(limit)
|
origin += uint64(limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the highest block number we know if a higher one is found.
|
||||||
|
d.syncStatsLock.Lock()
|
||||||
|
if d.syncStatsChainHeight < origin {
|
||||||
|
d.syncStatsChainHeight = origin - 1
|
||||||
|
}
|
||||||
|
d.syncStatsLock.Unlock()
|
||||||
|
|
||||||
// Signal the content downloaders of the availablility of new tasks
|
// Signal the content downloaders of the availablility of new tasks
|
||||||
for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} {
|
for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} {
|
||||||
select {
|
select {
|
||||||
|
|
|
||||||
|
|
@ -633,7 +633,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert spawns a new goroutine to run a block insertion into the chain. If the
|
// insert spawns a new goroutine to run a block insertion into the chain. If the
|
||||||
// block's number is at the same height as the current import phase, if updates
|
// block's number is at the same height as the current import phase, it updates
|
||||||
// the phase states accordingly.
|
// the phase states accordingly.
|
||||||
func (f *Fetcher) insert(peer string, block *types.Block) {
|
func (f *Fetcher) insert(peer string, block *types.Block) {
|
||||||
hash := block.Hash()
|
hash := block.Hash()
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,14 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
|
||||||
atomic.StoreUint32(&pm.fastSync, 1)
|
atomic.StoreUint32(&pm.fastSync, 1)
|
||||||
mode = downloader.FastSync
|
mode = downloader.FastSync
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mode == downloader.FastSync {
|
||||||
|
// Make sure the peer's total difficulty we are synchronizing is higher.
|
||||||
|
if pm.blockchain.GetTdByHash(pm.blockchain.CurrentFastBlock().Hash()).Cmp(pTd) >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Run the sync cycle, and disable fast sync if we've went past the pivot block
|
// Run the sync cycle, and disable fast sync if we've went past the pivot block
|
||||||
if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
|
if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -37,15 +37,11 @@ type LDBDatabase struct {
|
||||||
fn string // filename for reporting
|
fn string // filename for reporting
|
||||||
db *leveldb.DB // LevelDB instance
|
db *leveldb.DB // LevelDB instance
|
||||||
|
|
||||||
getTimer metrics.Timer // Timer for measuring the database get request counts and latencies
|
|
||||||
putTimer metrics.Timer // Timer for measuring the database put request counts and latencies
|
|
||||||
delTimer metrics.Timer // Timer for measuring the database delete request counts and latencies
|
|
||||||
missMeter metrics.Meter // Meter for measuring the missed database get requests
|
|
||||||
readMeter metrics.Meter // Meter for measuring the database get request data usage
|
|
||||||
writeMeter metrics.Meter // Meter for measuring the database put request data usage
|
|
||||||
compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction
|
compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction
|
||||||
compReadMeter metrics.Meter // Meter for measuring the data read during compaction
|
compReadMeter metrics.Meter // Meter for measuring the data read during compaction
|
||||||
compWriteMeter metrics.Meter // Meter for measuring the data written during compaction
|
compWriteMeter metrics.Meter // Meter for measuring the data written during compaction
|
||||||
|
diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read
|
||||||
|
diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written
|
||||||
|
|
||||||
quitLock sync.Mutex // Mutex protecting the quit channel access
|
quitLock sync.Mutex // Mutex protecting the quit channel access
|
||||||
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
|
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
|
||||||
|
|
@ -94,16 +90,9 @@ func (db *LDBDatabase) Path() string {
|
||||||
|
|
||||||
// Put puts the given key / value to the queue
|
// Put puts the given key / value to the queue
|
||||||
func (db *LDBDatabase) Put(key []byte, value []byte) error {
|
func (db *LDBDatabase) Put(key []byte, value []byte) error {
|
||||||
// Measure the database put latency, if requested
|
|
||||||
if db.putTimer != nil {
|
|
||||||
defer db.putTimer.UpdateSince(time.Now())
|
|
||||||
}
|
|
||||||
// Generate the data to write to disk, update the meter and write
|
// Generate the data to write to disk, update the meter and write
|
||||||
//value = rle.Compress(value)
|
//value = rle.Compress(value)
|
||||||
|
|
||||||
if db.writeMeter != nil {
|
|
||||||
db.writeMeter.Mark(int64(len(value)))
|
|
||||||
}
|
|
||||||
return db.db.Put(key, value, nil)
|
return db.db.Put(key, value, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,32 +102,17 @@ func (db *LDBDatabase) Has(key []byte) (bool, error) {
|
||||||
|
|
||||||
// Get returns the given key if it's present.
|
// Get returns the given key if it's present.
|
||||||
func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
|
func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
|
||||||
// Measure the database get latency, if requested
|
|
||||||
if db.getTimer != nil {
|
|
||||||
defer db.getTimer.UpdateSince(time.Now())
|
|
||||||
}
|
|
||||||
// Retrieve the key and increment the miss counter if not found
|
// Retrieve the key and increment the miss counter if not found
|
||||||
dat, err := db.db.Get(key, nil)
|
dat, err := db.db.Get(key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if db.missMeter != nil {
|
|
||||||
db.missMeter.Mark(1)
|
|
||||||
}
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Otherwise update the actually retrieved amount of data
|
|
||||||
if db.readMeter != nil {
|
|
||||||
db.readMeter.Mark(int64(len(dat)))
|
|
||||||
}
|
|
||||||
return dat, nil
|
return dat, nil
|
||||||
//return rle.Decompress(dat)
|
//return rle.Decompress(dat)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete deletes the key from the queue and database
|
// Delete deletes the key from the queue and database
|
||||||
func (db *LDBDatabase) Delete(key []byte) error {
|
func (db *LDBDatabase) Delete(key []byte) error {
|
||||||
// Measure the database delete latency, if requested
|
|
||||||
if db.delTimer != nil {
|
|
||||||
defer db.delTimer.UpdateSince(time.Now())
|
|
||||||
}
|
|
||||||
// Execute the actual operation
|
// Execute the actual operation
|
||||||
return db.db.Delete(key, nil)
|
return db.db.Delete(key, nil)
|
||||||
}
|
}
|
||||||
|
|
@ -178,15 +152,11 @@ func (db *LDBDatabase) Meter(prefix string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Initialize all the metrics collector at the requested prefix
|
// Initialize all the metrics collector at the requested prefix
|
||||||
db.getTimer = metrics.NewRegisteredTimer(prefix+"user/gets", nil)
|
|
||||||
db.putTimer = metrics.NewRegisteredTimer(prefix+"user/puts", nil)
|
|
||||||
db.delTimer = metrics.NewRegisteredTimer(prefix+"user/dels", nil)
|
|
||||||
db.missMeter = metrics.NewRegisteredMeter(prefix+"user/misses", nil)
|
|
||||||
db.readMeter = metrics.NewRegisteredMeter(prefix+"user/reads", nil)
|
|
||||||
db.writeMeter = metrics.NewRegisteredMeter(prefix+"user/writes", nil)
|
|
||||||
db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
|
db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
|
||||||
db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
|
db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
|
||||||
db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
|
db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
|
||||||
|
db.diskReadMeter = metrics.NewRegisteredMeter(prefix+"disk/read", nil)
|
||||||
|
db.diskWriteMeter = metrics.NewRegisteredMeter(prefix+"disk/write", nil)
|
||||||
|
|
||||||
// Create a quit channel for the periodic collector and run it
|
// Create a quit channel for the periodic collector and run it
|
||||||
db.quitLock.Lock()
|
db.quitLock.Lock()
|
||||||
|
|
@ -207,12 +177,17 @@ func (db *LDBDatabase) Meter(prefix string) {
|
||||||
// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294
|
// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294
|
||||||
// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884
|
// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884
|
||||||
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
|
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
|
||||||
|
//
|
||||||
|
// This is how the iostats look like (currently):
|
||||||
|
// Read(MB):3895.04860 Write(MB):3654.64712
|
||||||
func (db *LDBDatabase) meter(refresh time.Duration) {
|
func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
// Create the counters to store current and previous values
|
// Create the counters to store current and previous compaction values
|
||||||
counters := make([][]float64, 2)
|
compactions := make([][]float64, 2)
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
counters[i] = make([]float64, 3)
|
compactions[i] = make([]float64, 3)
|
||||||
}
|
}
|
||||||
|
// Create storage for iostats.
|
||||||
|
var iostats [2]float64
|
||||||
// Iterate ad infinitum and collect the stats
|
// Iterate ad infinitum and collect the stats
|
||||||
for i := 1; ; i++ {
|
for i := 1; ; i++ {
|
||||||
// Retrieve the database stats
|
// Retrieve the database stats
|
||||||
|
|
@ -233,8 +208,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
lines = lines[3:]
|
lines = lines[3:]
|
||||||
|
|
||||||
// Iterate over all the table rows, and accumulate the entries
|
// Iterate over all the table rows, and accumulate the entries
|
||||||
for j := 0; j < len(counters[i%2]); j++ {
|
for j := 0; j < len(compactions[i%2]); j++ {
|
||||||
counters[i%2][j] = 0
|
compactions[i%2][j] = 0
|
||||||
}
|
}
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
parts := strings.Split(line, "|")
|
parts := strings.Split(line, "|")
|
||||||
|
|
@ -247,19 +222,60 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
db.log.Error("Compaction entry parsing failed", "err", err)
|
db.log.Error("Compaction entry parsing failed", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
counters[i%2][idx] += value
|
compactions[i%2][idx] += value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update all the requested meters
|
// Update all the requested meters
|
||||||
if db.compTimeMeter != nil {
|
if db.compTimeMeter != nil {
|
||||||
db.compTimeMeter.Mark(int64((counters[i%2][0] - counters[(i-1)%2][0]) * 1000 * 1000 * 1000))
|
db.compTimeMeter.Mark(int64((compactions[i%2][0] - compactions[(i-1)%2][0]) * 1000 * 1000 * 1000))
|
||||||
}
|
}
|
||||||
if db.compReadMeter != nil {
|
if db.compReadMeter != nil {
|
||||||
db.compReadMeter.Mark(int64((counters[i%2][1] - counters[(i-1)%2][1]) * 1024 * 1024))
|
db.compReadMeter.Mark(int64((compactions[i%2][1] - compactions[(i-1)%2][1]) * 1024 * 1024))
|
||||||
}
|
}
|
||||||
if db.compWriteMeter != nil {
|
if db.compWriteMeter != nil {
|
||||||
db.compWriteMeter.Mark(int64((counters[i%2][2] - counters[(i-1)%2][2]) * 1024 * 1024))
|
db.compWriteMeter.Mark(int64((compactions[i%2][2] - compactions[(i-1)%2][2]) * 1024 * 1024))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve the database iostats.
|
||||||
|
ioStats, err := db.db.GetProperty("leveldb.iostats")
|
||||||
|
if err != nil {
|
||||||
|
db.log.Error("Failed to read database iostats", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parts := strings.Split(ioStats, " ")
|
||||||
|
if len(parts) < 2 {
|
||||||
|
db.log.Error("Bad syntax of ioStats", "ioStats", ioStats)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r := strings.Split(parts[0], ":")
|
||||||
|
if len(r) < 2 {
|
||||||
|
db.log.Error("Bad syntax of read entry", "entry", parts[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
read, err := strconv.ParseFloat(r[1], 64)
|
||||||
|
if err != nil {
|
||||||
|
db.log.Error("Read entry parsing failed", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w := strings.Split(parts[1], ":")
|
||||||
|
if len(w) < 2 {
|
||||||
|
db.log.Error("Bad syntax of write entry", "entry", parts[1])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
write, err := strconv.ParseFloat(w[1], 64)
|
||||||
|
if err != nil {
|
||||||
|
db.log.Error("Write entry parsing failed", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if db.diskReadMeter != nil {
|
||||||
|
db.diskReadMeter.Mark(int64((read - iostats[0]) * 1024 * 1024))
|
||||||
|
}
|
||||||
|
if db.diskWriteMeter != nil {
|
||||||
|
db.diskWriteMeter.Mark(int64((write - iostats[1]) * 1024 * 1024))
|
||||||
|
}
|
||||||
|
iostats[0] = read
|
||||||
|
iostats[1] = write
|
||||||
|
|
||||||
// Sleep a bit, then repeat the stats collection
|
// Sleep a bit, then repeat the stats collection
|
||||||
select {
|
select {
|
||||||
case errc := <-db.quitChan:
|
case errc := <-db.quitChan:
|
||||||
|
|
|
||||||
|
|
@ -1337,10 +1337,10 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
|
||||||
|
|
||||||
if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.From && signer.Hash(p) == wantSigHash {
|
if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.From && signer.Hash(p) == wantSigHash {
|
||||||
// Match. Re-sign and send the transaction.
|
// Match. Re-sign and send the transaction.
|
||||||
if gasPrice != nil {
|
if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 {
|
||||||
sendArgs.GasPrice = gasPrice
|
sendArgs.GasPrice = gasPrice
|
||||||
}
|
}
|
||||||
if gasLimit != nil {
|
if gasLimit != nil && *gasLimit != 0 {
|
||||||
sendArgs.Gas = gasLimit
|
sendArgs.Gas = gasLimit
|
||||||
}
|
}
|
||||||
signedTx, err := s.sign(sendArgs.From, sendArgs.toTransaction())
|
signedTx, err := s.sign(sendArgs.From, sendArgs.toTransaction())
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,9 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num
|
||||||
genesis := core.GetCanonicalHash(odr.Database(), 0)
|
genesis := core.GetCanonicalHash(odr.Database(), 0)
|
||||||
config, _ := core.GetChainConfig(odr.Database(), genesis)
|
config, _ := core.GetChainConfig(odr.Database(), genesis)
|
||||||
|
|
||||||
core.SetReceiptsData(config, block, receipts)
|
if err := core.SetReceiptsData(config, block, receipts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
core.WriteBlockReceipts(odr.Database(), hash, number, receipts)
|
core.WriteBlockReceipts(odr.Database(), hash, number, receipts)
|
||||||
}
|
}
|
||||||
return receipts, nil
|
return receipts, nil
|
||||||
|
|
|
||||||
6
vendor/github.com/syndtr/goleveldb/leveldb/db.go
generated
vendored
6
vendor/github.com/syndtr/goleveldb/leveldb/db.go
generated
vendored
|
|
@ -906,6 +906,8 @@ func (db *DB) GetSnapshot() (*Snapshot, error) {
|
||||||
// Returns the number of files at level 'n'.
|
// Returns the number of files at level 'n'.
|
||||||
// leveldb.stats
|
// leveldb.stats
|
||||||
// Returns statistics of the underlying DB.
|
// Returns statistics of the underlying DB.
|
||||||
|
// leveldb.iostats
|
||||||
|
// Returns statistics of effective disk read and write.
|
||||||
// leveldb.writedelay
|
// leveldb.writedelay
|
||||||
// Returns cumulative write delay caused by compaction.
|
// Returns cumulative write delay caused by compaction.
|
||||||
// leveldb.sstables
|
// leveldb.sstables
|
||||||
|
|
@ -959,6 +961,10 @@ func (db *DB) GetProperty(name string) (value string, err error) {
|
||||||
level, len(tables), float64(tables.size())/1048576.0, duration.Seconds(),
|
level, len(tables), float64(tables.size())/1048576.0, duration.Seconds(),
|
||||||
float64(read)/1048576.0, float64(write)/1048576.0)
|
float64(read)/1048576.0, float64(write)/1048576.0)
|
||||||
}
|
}
|
||||||
|
case p == "iostats":
|
||||||
|
value = fmt.Sprintf("Read(MB):%.5f Write(MB):%.5f",
|
||||||
|
float64(db.s.stor.reads())/1048576.0,
|
||||||
|
float64(db.s.stor.writes())/1048576.0)
|
||||||
case p == "writedelay":
|
case p == "writedelay":
|
||||||
writeDelayN, writeDelay := atomic.LoadInt32(&db.cWriteDelayN), time.Duration(atomic.LoadInt64(&db.cWriteDelay))
|
writeDelayN, writeDelay := atomic.LoadInt32(&db.cWriteDelayN), time.Duration(atomic.LoadInt64(&db.cWriteDelay))
|
||||||
value = fmt.Sprintf("DelayN:%d Delay:%s", writeDelayN, writeDelay)
|
value = fmt.Sprintf("DelayN:%d Delay:%s", writeDelayN, writeDelay)
|
||||||
|
|
|
||||||
2
vendor/github.com/syndtr/goleveldb/leveldb/iterator/iter.go
generated
vendored
2
vendor/github.com/syndtr/goleveldb/leveldb/iterator/iter.go
generated
vendored
|
|
@ -88,7 +88,7 @@ type Iterator interface {
|
||||||
// its contents may change on the next call to any 'seeks method'.
|
// its contents may change on the next call to any 'seeks method'.
|
||||||
Key() []byte
|
Key() []byte
|
||||||
|
|
||||||
// Value returns the key of the current key/value pair, or nil if done.
|
// Value returns the value of the current key/value pair, or nil if done.
|
||||||
// The caller should not modify the contents of the returned slice, and
|
// The caller should not modify the contents of the returned slice, and
|
||||||
// its contents may change on the next call to any 'seeks method'.
|
// its contents may change on the next call to any 'seeks method'.
|
||||||
Value() []byte
|
Value() []byte
|
||||||
|
|
|
||||||
2
vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go
generated
vendored
2
vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go
generated
vendored
|
|
@ -329,7 +329,7 @@ func (p *DB) Delete(key []byte) error {
|
||||||
|
|
||||||
h := p.nodeData[node+nHeight]
|
h := p.nodeData[node+nHeight]
|
||||||
for i, n := range p.prevNode[:h] {
|
for i, n := range p.prevNode[:h] {
|
||||||
m := n + 4 + i
|
m := n + nNext + i
|
||||||
p.nodeData[m] = p.nodeData[p.nodeData[m]+nNext+i]
|
p.nodeData[m] = p.nodeData[p.nodeData[m]+nNext+i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
4
vendor/github.com/syndtr/goleveldb/leveldb/session.go
generated
vendored
4
vendor/github.com/syndtr/goleveldb/leveldb/session.go
generated
vendored
|
|
@ -42,7 +42,7 @@ type session struct {
|
||||||
stTempFileNum int64
|
stTempFileNum int64
|
||||||
stSeqNum uint64 // last mem compacted seq; need external synchronization
|
stSeqNum uint64 // last mem compacted seq; need external synchronization
|
||||||
|
|
||||||
stor storage.Storage
|
stor *iStorage
|
||||||
storLock storage.Locker
|
storLock storage.Locker
|
||||||
o *cachedOptions
|
o *cachedOptions
|
||||||
icmp *iComparer
|
icmp *iComparer
|
||||||
|
|
@ -68,7 +68,7 @@ func newSession(stor storage.Storage, o *opt.Options) (s *session, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s = &session{
|
s = &session{
|
||||||
stor: stor,
|
stor: newIStorage(stor),
|
||||||
storLock: storLock,
|
storLock: storLock,
|
||||||
fileRef: make(map[int64]int),
|
fileRef: make(map[int64]int),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
63
vendor/github.com/syndtr/goleveldb/leveldb/storage.go
generated
vendored
Normal file
63
vendor/github.com/syndtr/goleveldb/leveldb/storage.go
generated
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package leveldb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/storage"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
type iStorage struct {
|
||||||
|
storage.Storage
|
||||||
|
read uint64
|
||||||
|
write uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iStorage) Open(fd storage.FileDesc) (storage.Reader, error) {
|
||||||
|
r, err := c.Storage.Open(fd)
|
||||||
|
return &iStorageReader{r, c}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iStorage) Create(fd storage.FileDesc) (storage.Writer, error) {
|
||||||
|
w, err := c.Storage.Create(fd)
|
||||||
|
return &iStorageWriter{w, c}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iStorage) reads() uint64 {
|
||||||
|
return atomic.LoadUint64(&c.read)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iStorage) writes() uint64 {
|
||||||
|
return atomic.LoadUint64(&c.write)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newIStorage returns the given storage wrapped by iStorage.
|
||||||
|
func newIStorage(s storage.Storage) *iStorage {
|
||||||
|
return &iStorage{s, 0, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
type iStorageReader struct {
|
||||||
|
storage.Reader
|
||||||
|
c *iStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *iStorageReader) Read(p []byte) (n int, err error) {
|
||||||
|
n, err = r.Reader.Read(p)
|
||||||
|
atomic.AddUint64(&r.c.read, uint64(n))
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *iStorageReader) ReadAt(p []byte, off int64) (n int, err error) {
|
||||||
|
n, err = r.Reader.ReadAt(p, off)
|
||||||
|
atomic.AddUint64(&r.c.read, uint64(n))
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type iStorageWriter struct {
|
||||||
|
storage.Writer
|
||||||
|
c *iStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *iStorageWriter) Write(p []byte) (n int, err error) {
|
||||||
|
n, err = w.Writer.Write(p)
|
||||||
|
atomic.AddUint64(&w.c.write, uint64(n))
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
4
vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go
generated
vendored
4
vendor/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go
generated
vendored
|
|
@ -8,7 +8,6 @@ package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type plan9FileLock struct {
|
type plan9FileLock struct {
|
||||||
|
|
@ -48,8 +47,7 @@ func rename(oldpath, newpath string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, fname := filepath.Split(newpath)
|
return os.Rename(oldpath, newpath)
|
||||||
return os.Rename(oldpath, fname)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncDir(name string) error {
|
func syncDir(name string) error {
|
||||||
|
|
|
||||||
2
vendor/github.com/syndtr/goleveldb/leveldb/util/util.go
generated
vendored
2
vendor/github.com/syndtr/goleveldb/leveldb/util/util.go
generated
vendored
|
|
@ -19,7 +19,7 @@ var (
|
||||||
// Releaser is the interface that wraps the basic Release method.
|
// Releaser is the interface that wraps the basic Release method.
|
||||||
type Releaser interface {
|
type Releaser interface {
|
||||||
// Release releases associated resources. Release should always success
|
// Release releases associated resources. Release should always success
|
||||||
// and can be called multipe times without causing error.
|
// and can be called multiple times without causing error.
|
||||||
Release()
|
Release()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
4
vendor/gopkg.in/olebedev/go-duktape.v3/api.go
generated
vendored
4
vendor/gopkg.in/olebedev/go-duktape.v3/api.go
generated
vendored
|
|
@ -1,8 +1,8 @@
|
||||||
package duktape
|
package duktape
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo !windows CFLAGS: -std=c99 -O3 -Wall -fomit-frame-pointer -fstrict-aliasing
|
#cgo !windows CFLAGS: -std=c99 -O3 -Wall -Wno-unused-value -fomit-frame-pointer -fstrict-aliasing
|
||||||
#cgo windows CFLAGS: -O3 -Wall -fomit-frame-pointer -fstrict-aliasing
|
#cgo windows CFLAGS: -O3 -Wall -Wno-unused-value -fomit-frame-pointer -fstrict-aliasing
|
||||||
|
|
||||||
#include "duktape.h"
|
#include "duktape.h"
|
||||||
#include "duk_logging.h"
|
#include "duk_logging.h"
|
||||||
|
|
|
||||||
1
vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go
generated
vendored
1
vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go
generated
vendored
|
|
@ -5,6 +5,7 @@ package duktape
|
||||||
#cgo windows CFLAGS: -O3 -Wall -fomit-frame-pointer -fstrict-aliasing
|
#cgo windows CFLAGS: -O3 -Wall -fomit-frame-pointer -fstrict-aliasing
|
||||||
#cgo linux LDFLAGS: -lm
|
#cgo linux LDFLAGS: -lm
|
||||||
#cgo freebsd LDFLAGS: -lm
|
#cgo freebsd LDFLAGS: -lm
|
||||||
|
#cgo openbsd LDFLAGS: -lm
|
||||||
|
|
||||||
#include "duktape.h"
|
#include "duktape.h"
|
||||||
#include "duk_logging.h"
|
#include "duk_logging.h"
|
||||||
|
|
|
||||||
64
vendor/vendor.json
vendored
64
vendor/vendor.json
vendored
|
|
@ -424,76 +424,76 @@
|
||||||
"revisionTime": "2017-07-05T02:17:15Z"
|
"revisionTime": "2017-07-05T02:17:15Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "rpu5ZHjXlV13UKA7L1d5MTOyQwA=",
|
"checksumSHA1": "3QsnhPTXGytTbW3uDvQLgSo9s9M=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb",
|
"path": "github.com/syndtr/goleveldb/leveldb",
|
||||||
"revision": "211f780988068502fe874c44dae530528ebd840f",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2018-01-28T14:04:16Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "EKIow7XkgNdWvR/982ffIZxKG8Y=",
|
"checksumSHA1": "EKIow7XkgNdWvR/982ffIZxKG8Y=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/cache",
|
"path": "github.com/syndtr/goleveldb/leveldb/cache",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "5KPgnvCPlR0ysDAqo6jApzRQ3tw=",
|
"checksumSHA1": "5KPgnvCPlR0ysDAqo6jApzRQ3tw=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/comparer",
|
"path": "github.com/syndtr/goleveldb/leveldb/comparer",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "1DRAxdlWzS4U0xKN/yQ/fdNN7f0=",
|
"checksumSHA1": "1DRAxdlWzS4U0xKN/yQ/fdNN7f0=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/errors",
|
"path": "github.com/syndtr/goleveldb/leveldb/errors",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "eqKeD6DS7eNCtxVYZEHHRKkyZrw=",
|
"checksumSHA1": "eqKeD6DS7eNCtxVYZEHHRKkyZrw=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/filter",
|
"path": "github.com/syndtr/goleveldb/leveldb/filter",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "8dXuAVIsbtaMiGGuHjzGR6Ny/5c=",
|
"checksumSHA1": "weSsccMav4BCerDpSLzh3mMxAYo=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/iterator",
|
"path": "github.com/syndtr/goleveldb/leveldb/iterator",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "gJY7bRpELtO0PJpZXgPQ2BYFJ88=",
|
"checksumSHA1": "gJY7bRpELtO0PJpZXgPQ2BYFJ88=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/journal",
|
"path": "github.com/syndtr/goleveldb/leveldb/journal",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "j+uaQ6DwJ50dkIdfMQu1TXdlQcY=",
|
"checksumSHA1": "MtYY1b2234y/MlS+djL8tXVAcQs=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/memdb",
|
"path": "github.com/syndtr/goleveldb/leveldb/memdb",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "UmQeotV+m8/FduKEfLOhjdp18rs=",
|
"checksumSHA1": "UmQeotV+m8/FduKEfLOhjdp18rs=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/opt",
|
"path": "github.com/syndtr/goleveldb/leveldb/opt",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "tQ2AqXXAEy9icbZI9dLVdZGvWMw=",
|
"checksumSHA1": "QCSae2ub87f8awH+PKMpd8ZYOtg=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/storage",
|
"path": "github.com/syndtr/goleveldb/leveldb/storage",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "gWFPMz8OQeul0t54RM66yMTX49g=",
|
"checksumSHA1": "gWFPMz8OQeul0t54RM66yMTX49g=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/table",
|
"path": "github.com/syndtr/goleveldb/leveldb/table",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "4zil8Gwg8VPkDn1YzlgCvtukJFU=",
|
"checksumSHA1": "V/Dh7NV0/fy/5jX1KaAjmGcNbzI=",
|
||||||
"path": "github.com/syndtr/goleveldb/leveldb/util",
|
"path": "github.com/syndtr/goleveldb/leveldb/util",
|
||||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||||
"revisionTime": "2017-07-25T06:48:36Z"
|
"revisionTime": "2018-03-07T11:33:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "pClJgcy1COeHxz/qRDFWnWgXTEI=",
|
"checksumSHA1": "pClJgcy1COeHxz/qRDFWnWgXTEI=",
|
||||||
|
|
@ -802,10 +802,10 @@
|
||||||
"revisionTime": "2016-06-21T03:49:01Z"
|
"revisionTime": "2016-06-21T03:49:01Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "YvuEbc0a032zr+BTp/YbBQojiuY=",
|
"checksumSHA1": "vndxs5Tv09/8S+Dr2PBAiM557lI=",
|
||||||
"path": "gopkg.in/olebedev/go-duktape.v3",
|
"path": "gopkg.in/olebedev/go-duktape.v3",
|
||||||
"revision": "9af39127cb024b355a6a0221769f6ddfe3f542e7",
|
"revision": "abf0ba0be5d5d36b1f9266463cc320b9a5ab224e",
|
||||||
"revisionTime": "2017-12-20T12:19:14Z"
|
"revisionTime": "2018-03-02T12:15:09Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "4BwmmgQUhWtizsR2soXND0nqZ1I=",
|
"checksumSHA1": "4BwmmgQUhWtizsR2soXND0nqZ1I=",
|
||||||
|
|
|
||||||
|
|
@ -269,3 +269,11 @@ func TopicToBloom(topic TopicType) []byte {
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetEnvelope retrieves an envelope from the message queue by its hash.
|
||||||
|
// It returns nil if the envelope can not be found.
|
||||||
|
func (w *Whisper) GetEnvelope(hash common.Hash) *Envelope {
|
||||||
|
w.poolMu.RLock()
|
||||||
|
defer w.poolMu.RUnlock()
|
||||||
|
return w.envelopes[hash]
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue