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/stats.json
|
||||
/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 test -coverage
|
||||
|
||||
- os: osx
|
||||
go: 1.9.x
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: "1.10"
|
||||
script:
|
||||
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
|
||||
- brew update
|
||||
- brew install caskroom/cask/brew-cask
|
||||
- brew cask install osxfuse
|
||||
- sudo modprobe fuse
|
||||
- sudo chmod 666 /dev/fuse
|
||||
- sudo chown root:$USER /etc/fuse.conf
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ matrix:
|
|||
# This builder only tests code linters on latest version of Go
|
||||
- os: linux
|
||||
dist: trusty
|
||||
go: 1.9.x
|
||||
go: "1.10"
|
||||
env:
|
||||
- lint
|
||||
git:
|
||||
|
|
@ -61,7 +62,7 @@ matrix:
|
|||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.9.x
|
||||
go: "1.10"
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
- azure-linux
|
||||
|
|
@ -101,7 +102,7 @@ matrix:
|
|||
dist: trusty
|
||||
services:
|
||||
- docker
|
||||
go: 1.9.x
|
||||
go: "1.10"
|
||||
env:
|
||||
- azure-linux-mips
|
||||
git:
|
||||
|
|
@ -145,7 +146,7 @@ matrix:
|
|||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
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 GOROOT=`pwd`/go
|
||||
- export GOPATH=$HOME/go
|
||||
|
|
@ -162,7 +163,7 @@ matrix:
|
|||
|
||||
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
||||
- os: osx
|
||||
go: 1.9.x
|
||||
go: "1.10"
|
||||
env:
|
||||
- azure-osx
|
||||
- azure-ios
|
||||
|
|
@ -192,7 +193,7 @@ matrix:
|
|||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.9.x
|
||||
go: "1.10"
|
||||
env:
|
||||
- azure-purge
|
||||
git:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# 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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# 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
|
||||
|
||||
|
|
|
|||
|
|
@ -385,8 +385,7 @@ var methodNormalizer = map[Lang]func(string) string{
|
|||
LangJava: decapitalise,
|
||||
}
|
||||
|
||||
// capitalise makes the first character of a string upper case, also removing any
|
||||
// prefixing underscores from the variable names.
|
||||
// capitalise makes a camel-case string which starts with an upper case character.
|
||||
func capitalise(input string) string {
|
||||
for len(input) > 0 && input[0] == '_' {
|
||||
input = input[1:]
|
||||
|
|
@ -394,12 +393,42 @@ func capitalise(input string) string {
|
|||
if len(input) == 0 {
|
||||
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 {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ var bindTests = []struct {
|
|||
}
|
||||
`,
|
||||
},
|
||||
// Tests that gas estimation works for contracts with weird gas mechanics too.
|
||||
// Tests that gas estimation works for contracts with weird gas mechanics too.
|
||||
{
|
||||
`FunkyGasPattern`,
|
||||
`
|
||||
|
|
@ -506,6 +506,7 @@ var bindTests = []struct {
|
|||
}
|
||||
`,
|
||||
},
|
||||
// Tests that methods and returns with underscores inside work correctly.
|
||||
{
|
||||
`Underscorer`,
|
||||
`
|
||||
|
|
@ -518,7 +519,7 @@ var bindTests = []struct {
|
|||
}
|
||||
function LowerUpperCollision() constant returns (int _res, int Res) {
|
||||
return (1, 2);
|
||||
}
|
||||
}
|
||||
function UpperLowerCollision() constant returns (int _Res, int res) {
|
||||
return (1, 2);
|
||||
}
|
||||
|
|
@ -531,9 +532,12 @@ var bindTests = []struct {
|
|||
function AllPurelyUnderscoredOutput() constant returns (int _, int __) {
|
||||
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
|
||||
key, _ := crypto.GenerateKey()
|
||||
|
|
@ -562,6 +566,7 @@ var bindTests = []struct {
|
|||
a, b, _ = underscorer.UpperUpperCollision(nil)
|
||||
a, b, _ = underscorer.PurelyUnderscoredOutput(nil)
|
||||
a, b, _ = underscorer.AllPurelyUnderscoredOutput(nil)
|
||||
a, _ = underscorer.UnderScoredFunc(nil)
|
||||
|
||||
fmt.Println(a, b, err)
|
||||
`,
|
||||
|
|
@ -801,7 +806,8 @@ var bindTests = []struct {
|
|||
// (See accounts/abi/unpack_test.go for more extensive testing)
|
||||
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)
|
||||
}`,
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ environment:
|
|||
install:
|
||||
- git submodule update --init
|
||||
- rmdir C:\go /s /q
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.9.2.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.9.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.10.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- go version
|
||||
- gcc --version
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,7 @@
|
|||
|
||||
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
|
||||
Canonical:
|
||||
|
||||
- Trusty Tahr (14.04 LTS)
|
||||
- Xenial Xerus (16.04 LTS)
|
||||
- Yakkety Yak (16.10)
|
||||
- Zesty Zapus (17.04)
|
||||
Canonical.
|
||||
|
||||
Packages of develop branch commits have suffix -unstable and cannot be installed alongside
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
## Building Packages Locally (for testing)
|
||||
|
||||
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-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:
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ Source: {{.Name}}
|
|||
Section: science
|
||||
Priority: extra
|
||||
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
|
||||
Homepage: https://ethereum.org
|
||||
Vcs-Git: git://github.com/ethereum/go-ethereum.git
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#export DH_VERBOSE=1
|
||||
|
||||
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:
|
||||
|
||||
|
|
|
|||
|
|
@ -225,6 +225,13 @@ func importChain(ctx *cli.Context) error {
|
|||
utils.Fatalf("Failed to read database stats: %v", err)
|
||||
}
|
||||
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 unloads: %d\n\n", trie.CacheUnloads())
|
||||
|
||||
|
|
@ -255,6 +262,12 @@ func importChain(ctx *cli.Context) error {
|
|||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ var (
|
|||
utils.DashboardAddrFlag,
|
||||
utils.DashboardPortFlag,
|
||||
utils.DashboardRefreshFlag,
|
||||
utils.DashboardAssetsFlag,
|
||||
utils.EthashCacheDirFlag,
|
||||
utils.EthashCachesInMemoryFlag,
|
||||
utils.EthashCachesOnDiskFlag,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ ADD genesis.json /genesis.json
|
|||
RUN \
|
||||
echo 'node server.js &' > 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 \
|
||||
sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \
|
||||
|
|
|
|||
|
|
@ -209,11 +209,6 @@ var (
|
|||
Usage: "Dashboard metrics collection refresh rate",
|
||||
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
|
||||
EthashCacheDirFlag = DirectoryFlag{
|
||||
Name: "ethash.cachedir",
|
||||
|
|
@ -819,6 +814,9 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
|||
|
||||
if ctx.GlobalIsSet(MaxPeersFlag.Name) {
|
||||
cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
|
||||
if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) {
|
||||
cfg.MaxPeers += lightPeers
|
||||
}
|
||||
} else {
|
||||
if lightServer {
|
||||
cfg.MaxPeers += lightPeers
|
||||
|
|
@ -1120,7 +1118,6 @@ func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
|
|||
cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
|
||||
cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
|
||||
cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
|
||||
cfg.Assets = ctx.GlobalString(DashboardAssetsFlag.Name)
|
||||
}
|
||||
|
||||
// RegisterEthService adds an Ethereum client to the stack.
|
||||
|
|
|
|||
|
|
@ -197,6 +197,8 @@ func initialize() {
|
|||
if len(*argIP) == 0 {
|
||||
argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ")
|
||||
}
|
||||
} else if *fileReader {
|
||||
*bootstrapMode = true
|
||||
} else {
|
||||
if len(*argEnode) == 0 {
|
||||
argEnode = scanLineA("Please enter the peer's enode: ")
|
||||
|
|
@ -205,11 +207,22 @@ func initialize() {
|
|||
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{
|
||||
MaxMessageSize: uint32(*argMaxSize),
|
||||
MinimumAcceptedPOW: *argPoW,
|
||||
}
|
||||
|
||||
shh = whisper.New(cfg)
|
||||
|
||||
if *argPoW != whisper.DefaultMinimumPoW {
|
||||
err := shh.SetMinimumPoW(*argPoW)
|
||||
if err != nil {
|
||||
|
|
@ -257,18 +270,8 @@ func initialize() {
|
|||
}
|
||||
|
||||
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)
|
||||
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW)
|
||||
} else {
|
||||
shh = whisper.New(cfg)
|
||||
}
|
||||
|
||||
server = &p2p.Server{
|
||||
|
|
@ -306,7 +309,11 @@ func startServer() error {
|
|||
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)
|
||||
}
|
||||
return nil
|
||||
|
|
@ -566,6 +573,7 @@ func sendMsg(payload []byte) common.Hash {
|
|||
if err != nil {
|
||||
utils.Fatalf("failed to create new message: %s", err)
|
||||
}
|
||||
|
||||
envelope, err := msg.Wrap(¶ms)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to seal message: %v \n", err)
|
||||
|
|
@ -601,15 +609,17 @@ func messageLoop() {
|
|||
m2 := af.Retrieve()
|
||||
messages := append(m1, m2...)
|
||||
for _, msg := range messages {
|
||||
reportedOnce := false
|
||||
if !*fileExMode && len(msg.Payload) <= 2048 {
|
||||
printMessageInfo(msg)
|
||||
reportedOnce = true
|
||||
}
|
||||
|
||||
// All messages are saved upon specifying argSaveDir.
|
||||
// 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 len(*argSaveDir) > 0 {
|
||||
writeMessageToFile(*argSaveDir, msg)
|
||||
}
|
||||
|
||||
if !*fileExMode && len(msg.Payload) <= 2048 {
|
||||
printMessageInfo(msg)
|
||||
writeMessageToFile(*argSaveDir, msg, !reportedOnce)
|
||||
}
|
||||
}
|
||||
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)
|
||||
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
||||
|
||||
|
|
@ -643,22 +657,24 @@ func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
|||
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.
|
||||
//if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
||||
// fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name)
|
||||
// return
|
||||
//}
|
||||
|
||||
if len(dir) > 0 {
|
||||
fullpath := filepath.Join(dir, name)
|
||||
err := ioutil.WriteFile(fullpath, msg.Raw, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
||||
} else {
|
||||
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(msg.Raw))
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("\n%s {%x}: message received (%d bytes), but not saved: %s\n", timestamp, address, len(msg.Raw), name)
|
||||
fullpath := filepath.Join(dir, name)
|
||||
err := ioutil.WriteFile(fullpath, env.Data, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
||||
} else if show {
|
||||
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(env.Data))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -682,18 +698,23 @@ func requestExpiredMessagesLoop() {
|
|||
for {
|
||||
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): ")
|
||||
t = scanLine("Please enter the topic (hexadecimal): ")
|
||||
if len(t) >= whisper.TopicLength*2 {
|
||||
t = scanLine("Enter the topic (hex). Press enter to request all messages, regardless of the topic: ")
|
||||
if len(t) == whisper.TopicLength*2 {
|
||||
x, err := hex.DecodeString(t)
|
||||
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)
|
||||
bloom = whisper.TopicToBloom(xt)
|
||||
obfuscateBloom(bloom)
|
||||
} else {
|
||||
} else if len(t) == 0 {
|
||||
bloom = whisper.MakeFullNodeBloom()
|
||||
} else {
|
||||
fmt.Println("Error: topic is invalid, request aborted")
|
||||
continue
|
||||
}
|
||||
|
||||
if timeUpp == 0 {
|
||||
timeUpp = 0xFFFFFFFF
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ type solcOutput struct {
|
|||
func (s *Solidity) makeArgs() []string {
|
||||
p := []string{
|
||||
"--combined-json", "bin,abi,userdoc,devdoc",
|
||||
"--add-std", // include standard lib contracts
|
||||
"--optimize", // code optimizer switched on
|
||||
}
|
||||
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
|
||||
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())
|
||||
|
||||
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++ {
|
||||
// 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++
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertReceiptChain attempts to complete an already existing header chain with
|
||||
|
|
@ -794,7 +798,9 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
|||
continue
|
||||
}
|
||||
// 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
|
||||
if err := WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
||||
return i, fmt.Errorf("failed to write block body: %v", err)
|
||||
|
|
|
|||
|
|
@ -877,15 +877,14 @@ func (pool *TxPool) removeTx(hash common.Hash) {
|
|||
// Remove the transaction from the pending lists and reset the account nonce
|
||||
if pending := pool.pending[addr]; pending != nil {
|
||||
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() {
|
||||
delete(pool.pending, addr)
|
||||
delete(pool.beats, addr)
|
||||
} else {
|
||||
// Otherwise postpone any invalidated transactions
|
||||
for _, tx := range invalids {
|
||||
pool.enqueueTx(tx.Hash(), tx)
|
||||
}
|
||||
}
|
||||
// Postpone any invalidated transactions
|
||||
for _, tx := range invalids {
|
||||
pool.enqueueTx(tx.Hash(), tx)
|
||||
}
|
||||
// Update the account nonce if needed
|
||||
if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce {
|
||||
|
|
|
|||
|
|
@ -557,74 +557,112 @@ func TestTransactionDropping(t *testing.T) {
|
|||
func TestTransactionPostponing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a test account and fund it
|
||||
pool, key := setupTxPool()
|
||||
// Create the pool to test the postponing with
|
||||
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()
|
||||
|
||||
account, _ := deriveSender(transaction(0, 0, key))
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000))
|
||||
// Create two test accounts to produce different gap profiles with
|
||||
keys := make([]*ecdsa.PrivateKey, 2)
|
||||
accs := make([]common.Address, len(keys))
|
||||
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
accs[i] = crypto.PubkeyToAddress(keys[i].PublicKey)
|
||||
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100))
|
||||
}
|
||||
// Add a batch consecutive pending transactions for validation
|
||||
txns := []*types.Transaction{}
|
||||
for i := 0; i < 100; i++ {
|
||||
var tx *types.Transaction
|
||||
if i%2 == 0 {
|
||||
tx = transaction(uint64(i), 100, key)
|
||||
} else {
|
||||
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
|
||||
if pool.pending[account].Len() != len(txns) {
|
||||
t.Errorf("pending transaction mismatch: have %d, want %d", 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", pending, len(txs))
|
||||
}
|
||||
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) {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns))
|
||||
if len(pool.all) != len(txs) {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs))
|
||||
}
|
||||
pool.lockedReset(nil, nil)
|
||||
if pool.pending[account].Len() != len(txns) {
|
||||
t.Errorf("pending transaction mismatch: have %d, want %d", 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", pending, len(txs))
|
||||
}
|
||||
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) {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns))
|
||||
if len(pool.all) != len(txs) {
|
||||
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
|
||||
pool.currentState.AddBalance(account, big.NewInt(-750))
|
||||
for _, addr := range accs {
|
||||
pool.currentState.AddBalance(addr, big.NewInt(-1))
|
||||
}
|
||||
pool.lockedReset(nil, nil)
|
||||
|
||||
if _, ok := pool.pending[account].txs.items[txns[0].Nonce()]; !ok {
|
||||
t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txns[0])
|
||||
// The first account's first transaction remains valid, check that subsequent
|
||||
// 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 {
|
||||
t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txns[0])
|
||||
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, txs[0])
|
||||
}
|
||||
for i, tx := range txns[1:] {
|
||||
for i, tx := range txs[1:100] {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
} 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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(pool.all) != len(txns)/2 {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)/2)
|
||||
// The second account's first transaction got invalid, check that all transactions
|
||||
// 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))
|
||||
pool2.currentState.AddBalance(account2, big.NewInt(1000000))
|
||||
|
||||
txns := []*types.Transaction{}
|
||||
txs := []*types.Transaction{}
|
||||
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
|
||||
if len(pool1.pending) != len(pool2.pending) {
|
||||
|
|
@ -1124,7 +1162,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
|||
defer sub.Unsubscribe()
|
||||
|
||||
// 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++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
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(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(2, 100000, big.NewInt(1), keys[1]))
|
||||
txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[1]))
|
||||
txs = append(txs, pricedTransaction(2, 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
|
||||
pool.AddRemotes(txs)
|
||||
pool.AddLocal(ltx)
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
if pending != 4 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4)
|
||||
if pending != 7 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7)
|
||||
}
|
||||
if 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)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
|
|
@ -1166,8 +1208,8 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
|||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
if queued != 3 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
||||
if queued != 5 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5)
|
||||
}
|
||||
if err := validateEvents(events, 0); err != nil {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
if err := validateEvents(events, 0); err != nil {
|
||||
|
|
@ -1189,7 +1234,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
|||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
// 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 {
|
||||
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 {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import (
|
|||
|
||||
var (
|
||||
bigZero = new(big.Int)
|
||||
tt255 = math.BigPow(2, 255)
|
||||
tt256 = math.BigPow(2, 256)
|
||||
errWriteProtection = errors.New("evm: write protection")
|
||||
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
||||
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) {
|
||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
||||
if x.Cmp(math.S256(y)) < 0 {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
x, y := stack.pop(), stack.peek()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
||||
if x.Cmp(y) > 0 {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
}
|
||||
x, y := stack.pop(), stack.peek()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
y.SetUint64(1)
|
||||
} else {
|
||||
stack.push(new(big.Int))
|
||||
y.SetUint64(0)
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(x, y)
|
||||
evm.interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x := stack.pop()
|
||||
x := stack.peek()
|
||||
if x.Sign() > 0 {
|
||||
stack.push(new(big.Int))
|
||||
x.SetUint64(0)
|
||||
} else {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
x.SetUint64(1)
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ func TestSAR(t *testing.T) {
|
|||
|
||||
func TestSGT(t *testing.T) {
|
||||
tests := []twoOperandTest{
|
||||
|
||||
{"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
|
|
@ -171,6 +172,8 @@ func TestSGT(t *testing.T) {
|
|||
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
}
|
||||
testTwoOperandOp(t, tests, opSgt)
|
||||
}
|
||||
|
|
@ -187,6 +190,8 @@ func TestSLT(t *testing.T) {
|
|||
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||
}
|
||||
testTwoOperandOp(t, tests, opSlt)
|
||||
}
|
||||
|
|
@ -349,7 +354,11 @@ func BenchmarkOpEq(b *testing.B) {
|
|||
|
||||
opBenchmark(b, opEq, x, y)
|
||||
}
|
||||
|
||||
func BenchmarkOpEq2(b *testing.B) {
|
||||
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
||||
y := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201fffffffe"
|
||||
opBenchmark(b, opEq, x, y)
|
||||
}
|
||||
func BenchmarkOpAnd(b *testing.B) {
|
||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||
|
|
@ -412,3 +421,7 @@ func BenchmarkOpSAR(b *testing.B) {
|
|||
|
||||
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:
|
||||
|
||||
```
|
||||
$ (cd dashboard/assets && npm install)
|
||||
$ (cd dashboard/assets && ./node_modules/.bin/flow-typed install)
|
||||
$ (cd dashboard/assets && yarn install && yarn flow)
|
||||
```
|
||||
|
||||
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 --dashboard.assets=dashboard/assets --vmodule=dashboard=5
|
||||
$ geth --dashboard --vmodule=dashboard=5
|
||||
$ (cd dashboard/assets && yarn dev)
|
||||
```
|
||||
|
||||
To bundle up the final UI into Geth, run `go generate`:
|
||||
|
||||
```
|
||||
$ go generate ./dashboard
|
||||
$ (cd dashboard && go generate)
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -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.
|
||||
|
||||
* 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 _space usage_ go to [Webpack Visualizer][WV], and import `stats.json`
|
||||
|
||||
|
|
|
|||
4299
dashboard/assets.go
4299
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.
|
||||
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.
|
||||
const simplifyBytes = (x: number) => {
|
||||
let i = 0;
|
||||
for (; x > 1024 && i < 5; i++) {
|
||||
for (; x > 1024 && i < 8; i++) {
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -81,7 +81,11 @@ const defaultContent: Content = {
|
|||
version: null,
|
||||
commit: null,
|
||||
},
|
||||
home: {
|
||||
home: {},
|
||||
chain: {},
|
||||
txpool: {},
|
||||
network: {},
|
||||
system: {
|
||||
activeMemory: [],
|
||||
virtualMemory: [],
|
||||
networkIngress: [],
|
||||
|
|
@ -91,10 +95,6 @@ const defaultContent: Content = {
|
|||
diskRead: [],
|
||||
diskWrite: [],
|
||||
},
|
||||
chain: {},
|
||||
txpool: {},
|
||||
network: {},
|
||||
system: {},
|
||||
logs: {
|
||||
log: [],
|
||||
},
|
||||
|
|
@ -108,7 +108,11 @@ const updaters = {
|
|||
version: replacer,
|
||||
commit: replacer,
|
||||
},
|
||||
home: {
|
||||
home: null,
|
||||
chain: null,
|
||||
txpool: null,
|
||||
network: null,
|
||||
system: {
|
||||
activeMemory: appender(200),
|
||||
virtualMemory: appender(200),
|
||||
networkIngress: appender(200),
|
||||
|
|
@ -118,11 +122,7 @@ const updaters = {
|
|||
diskRead: appender(200),
|
||||
diskWrite: appender(200),
|
||||
},
|
||||
chain: null,
|
||||
txpool: null,
|
||||
network: null,
|
||||
system: null,
|
||||
logs: {
|
||||
logs: {
|
||||
log: appender(200),
|
||||
},
|
||||
};
|
||||
|
|
@ -136,7 +136,7 @@ const styles = {
|
|||
height: '100%',
|
||||
zIndex: 1,
|
||||
overflow: 'hidden',
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// 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
|
||||
// and tries to reconnect on connection loss.
|
||||
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 = () => {
|
||||
this.setState({content: defaultContent, shouldUpdate: {}});
|
||||
};
|
||||
|
|
@ -217,7 +218,6 @@ class Dashboard extends Component<Props, State> {
|
|||
return (
|
||||
<div className={this.props.classes.dashboard} style={styles.dashboard}>
|
||||
<Header
|
||||
opened={this.state.sideBar}
|
||||
switchSideBar={this.switchSideBar}
|
||||
/>
|
||||
<Body
|
||||
|
|
|
|||
|
|
@ -26,7 +26,17 @@ import {ResponsiveContainer, AreaChart, Area, Tooltip} from 'recharts';
|
|||
import ChartRow from './ChartRow';
|
||||
import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from './CustomTooltip';
|
||||
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.
|
||||
const styles = {
|
||||
|
|
@ -40,17 +50,16 @@ const styles = {
|
|||
padding: 0,
|
||||
},
|
||||
doubleChartWrapper: {
|
||||
height: '100%',
|
||||
width: '99%',
|
||||
paddingTop: 5,
|
||||
height: '100%',
|
||||
width: '99%',
|
||||
},
|
||||
};
|
||||
|
||||
// themeStyles returns the styles generated from the theme for the component.
|
||||
const themeStyles: Object = (theme: Object) => ({
|
||||
footer: {
|
||||
backgroundColor: theme.palette.background.appBar,
|
||||
color: theme.palette.getContrastText(theme.palette.background.appBar),
|
||||
backgroundColor: theme.palette.grey[900],
|
||||
color: theme.palette.getContrastText(theme.palette.grey[900]),
|
||||
zIndex: theme.zIndex.appBar,
|
||||
height: theme.spacing.unit * 10,
|
||||
},
|
||||
|
|
@ -59,111 +68,108 @@ const themeStyles: Object = (theme: Object) => ({
|
|||
export type Props = {
|
||||
classes: Object, // injected by withStyles()
|
||||
theme: Object,
|
||||
content: Content,
|
||||
general: General,
|
||||
system: System,
|
||||
shouldUpdate: Object,
|
||||
};
|
||||
|
||||
// Footer renders the footer of the dashboard.
|
||||
class Footer extends Component<Props> {
|
||||
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.
|
||||
info = (about: string, value: ?string) => (value ? (
|
||||
<Typography type='caption' color='inherit'>
|
||||
<span style={commonStyles.light}>{about}</span> {value}
|
||||
</Typography>
|
||||
) : null);
|
||||
// halfHeightChart renders an area chart with half of the height of its parent.
|
||||
halfHeightChart = (chartProps, tooltip, areaProps) => (
|
||||
<ResponsiveContainer width='100%' height='50%'>
|
||||
<AreaChart {...chartProps} >
|
||||
{!tooltip || (<Tooltip cursor={false} content={<CustomTooltip tooltip={tooltip} />} />)}
|
||||
<Area isAnimationActive={false} type='monotone' {...areaProps} />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
|
||||
// doubleChart renders a pair of charts separated by the baseline.
|
||||
doubleChart = (syncId, topChart, bottomChart) => {
|
||||
const topKey = 'topKey';
|
||||
const bottomKey = 'bottomKey';
|
||||
const topDefault = topChart.default ? topChart.default : 0;
|
||||
const bottomDefault = bottomChart.default ? bottomChart.default : 0;
|
||||
const topTooltip = topChart.tooltip ? (
|
||||
<Tooltip cursor={false} content={<CustomTooltip tooltip={topChart.tooltip} />} />
|
||||
) : null;
|
||||
const bottomTooltip = bottomChart.tooltip ? (
|
||||
<Tooltip cursor={false} content={<CustomTooltip tooltip={bottomChart.tooltip} />} />
|
||||
) : null;
|
||||
doubleChart = (syncId, chartKey, topChart, bottomChart) => {
|
||||
if (!Array.isArray(topChart.data) || !Array.isArray(bottomChart.data)) {
|
||||
return null;
|
||||
}
|
||||
const topDefault = topChart.default || 0;
|
||||
const bottomDefault = bottomChart.default || 0;
|
||||
const topKey = `${chartKey}${TOP}`;
|
||||
const bottomKey = `${chartKey}${BOTTOM}`;
|
||||
const topColor = '#8884d8';
|
||||
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 (
|
||||
<div style={styles.doubleChartWrapper}>
|
||||
<ResponsiveContainer width='100%' height='50%'>
|
||||
<AreaChart data={data} syncId={syncId} >
|
||||
{topTooltip}
|
||||
<Area type='monotone' dataKey={topKey} stroke={topColor} fill={topColor} />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
<div style={{marginTop: -10, width: '100%', height: '50%'}}>
|
||||
<ResponsiveContainer width='100%' height='100%'>
|
||||
<AreaChart data={data} syncId={syncId} >
|
||||
{bottomTooltip}
|
||||
<Area type='monotone' dataKey={bottomKey} stroke={bottomColor} fill={bottomColor} />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
{this.halfHeightChart(
|
||||
{
|
||||
syncId,
|
||||
data: topChart.data.map(({value}) => ({[topKey]: value || topDefault})),
|
||||
margin: {top: 5, right: 5, bottom: 0, left: 5},
|
||||
},
|
||||
topChart.tooltip,
|
||||
{dataKey: topKey, stroke: topColor, fill: topColor},
|
||||
)}
|
||||
{this.halfHeightChart(
|
||||
{
|
||||
syncId,
|
||||
data: bottomChart.data.map(({value}) => ({[bottomKey]: -value || -bottomDefault})),
|
||||
margin: {top: 0, right: 5, bottom: 5, left: 5},
|
||||
},
|
||||
bottomChart.tooltip,
|
||||
{dataKey: bottomKey, stroke: bottomColor, fill: bottomColor},
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {content} = this.props;
|
||||
const {general, home} = content;
|
||||
const {general, system} = this.props;
|
||||
|
||||
return (
|
||||
<Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}>
|
||||
<Grid item xs style={styles.chartRowWrapper}>
|
||||
<ChartRow>
|
||||
{this.doubleChart(
|
||||
'all',
|
||||
{data: home.processCPU, tooltip: percentPlotter('Process')},
|
||||
{data: home.systemCPU, tooltip: percentPlotter('System', multiplier(-1))},
|
||||
FOOTER_SYNC_ID,
|
||||
CPU,
|
||||
{data: system.processCPU, tooltip: percentPlotter('Process load')},
|
||||
{data: system.systemCPU, tooltip: percentPlotter('System load', multiplier(-1))},
|
||||
)}
|
||||
{this.doubleChart(
|
||||
'all',
|
||||
{data: home.activeMemory, tooltip: bytePlotter('Active')},
|
||||
{data: home.virtualMemory, tooltip: bytePlotter('Virtual', multiplier(-1))},
|
||||
FOOTER_SYNC_ID,
|
||||
MEMORY,
|
||||
{data: system.activeMemory, tooltip: bytePlotter('Active memory')},
|
||||
{data: system.virtualMemory, tooltip: bytePlotter('Virtual memory', multiplier(-1))},
|
||||
)}
|
||||
{this.doubleChart(
|
||||
'all',
|
||||
{data: home.diskRead, tooltip: bytePerSecPlotter('Disk Read')},
|
||||
{data: home.diskWrite, tooltip: bytePerSecPlotter('Disk Write', multiplier(-1))},
|
||||
FOOTER_SYNC_ID,
|
||||
DISK,
|
||||
{data: system.diskRead, tooltip: bytePerSecPlotter('Disk read')},
|
||||
{data: system.diskWrite, tooltip: bytePerSecPlotter('Disk write', multiplier(-1))},
|
||||
)}
|
||||
{this.doubleChart(
|
||||
'all',
|
||||
{data: home.networkIngress, tooltip: bytePerSecPlotter('Download')},
|
||||
{data: home.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))},
|
||||
FOOTER_SYNC_ID,
|
||||
TRAFFIC,
|
||||
{data: system.networkIngress, tooltip: bytePerSecPlotter('Download')},
|
||||
{data: system.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))},
|
||||
)}
|
||||
</ChartRow>
|
||||
</Grid>
|
||||
<Grid item >
|
||||
{this.info('Geth', general.version)}
|
||||
{this.info('Commit', general.commit ? general.commit.substring(0, 7) : null)}
|
||||
<Typography type='caption' color='inherit'>
|
||||
<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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -21,30 +21,16 @@ import React, {Component} from 'react';
|
|||
import withStyles from 'material-ui/styles/withStyles';
|
||||
import AppBar from 'material-ui/AppBar';
|
||||
import Toolbar from 'material-ui/Toolbar';
|
||||
import Transition from 'react-transition-group/Transition';
|
||||
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 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.
|
||||
const themeStyles = (theme: Object) => ({
|
||||
header: {
|
||||
backgroundColor: theme.palette.background.appBar,
|
||||
color: theme.palette.getContrastText(theme.palette.background.appBar),
|
||||
backgroundColor: theme.palette.grey[900],
|
||||
color: theme.palette.getContrastText(theme.palette.grey[900]),
|
||||
zIndex: theme.zIndex.appBar,
|
||||
},
|
||||
toolbar: {
|
||||
|
|
@ -53,42 +39,28 @@ const themeStyles = (theme: Object) => ({
|
|||
},
|
||||
title: {
|
||||
paddingLeft: theme.spacing.unit,
|
||||
fontSize: 3 * theme.spacing.unit,
|
||||
},
|
||||
});
|
||||
|
||||
export type Props = {
|
||||
classes: Object, // injected by withStyles()
|
||||
opened: boolean,
|
||||
switchSideBar: () => void,
|
||||
};
|
||||
|
||||
// Header renders the header of the dashboard.
|
||||
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() {
|
||||
const {classes, opened} = this.props;
|
||||
const {classes} = this.props;
|
||||
|
||||
return (
|
||||
<AppBar position='static' className={classes.header}>
|
||||
<Toolbar className={classes.toolbar}>
|
||||
<Transition mountOnEnter in={opened} timeout={{enter: DURATION}}>
|
||||
{this.arrow}
|
||||
</Transition>
|
||||
<IconButton onClick={this.props.switchSideBar}>
|
||||
<Icon>
|
||||
<MenuIcon />
|
||||
</Icon>
|
||||
</IconButton>
|
||||
<Typography type='title' color='inherit' noWrap className={classes.title}>
|
||||
Go Ethereum Dashboard
|
||||
</Typography>
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@ class Main extends Component<Props> {
|
|||
<div style={styles.wrapper}>
|
||||
<div className={classes.content} style={styles.content}>{children}</div>
|
||||
<Footer
|
||||
content={content}
|
||||
general={content.general}
|
||||
system={content.system}
|
||||
shouldUpdate={shouldUpdate}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -41,10 +41,10 @@ const styles = {
|
|||
// themeStyles returns the styles generated from the theme for the component.
|
||||
const themeStyles = theme => ({
|
||||
list: {
|
||||
background: theme.palette.background.appBar,
|
||||
background: theme.palette.grey[900],
|
||||
},
|
||||
listItem: {
|
||||
minWidth: theme.spacing.unit * 3,
|
||||
minWidth: theme.spacing.unit * 7,
|
||||
},
|
||||
icon: {
|
||||
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",
|
||||
"eslint": "^4.16.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-jsx-a11y": "^6.0.3",
|
||||
"eslint-plugin-react": "^7.5.1",
|
||||
"eslint-plugin-flowtype": "^2.41.0",
|
||||
"file-loader": "^1.1.6",
|
||||
"flow-bin": "^0.63.1",
|
||||
"flow-bin-loader": "^1.0.2",
|
||||
|
|
@ -35,6 +35,13 @@
|
|||
"style-loader": "^0.19.1",
|
||||
"url": "^0.11.0",
|
||||
"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,22 +26,6 @@ export type Content = {
|
|||
logs: Logs,
|
||||
};
|
||||
|
||||
export type General = {
|
||||
version: ?string,
|
||||
commit: ?string,
|
||||
};
|
||||
|
||||
export type Home = {
|
||||
activeMemory: ChartEntries,
|
||||
virtualMemory: ChartEntries,
|
||||
networkIngress: ChartEntries,
|
||||
networkEgress: ChartEntries,
|
||||
processCPU: ChartEntries,
|
||||
systemCPU: ChartEntries,
|
||||
diskRead: ChartEntries,
|
||||
diskWrite: ChartEntries,
|
||||
};
|
||||
|
||||
export type ChartEntries = Array<ChartEntry>;
|
||||
|
||||
export type ChartEntry = {
|
||||
|
|
@ -49,6 +33,15 @@ export type ChartEntry = {
|
|||
value: number,
|
||||
};
|
||||
|
||||
export type General = {
|
||||
version: ?string,
|
||||
commit: ?string,
|
||||
};
|
||||
|
||||
export type Home = {
|
||||
/* TODO (kurkomisi) */
|
||||
};
|
||||
|
||||
export type Chain = {
|
||||
/* TODO (kurkomisi) */
|
||||
};
|
||||
|
|
@ -62,7 +55,14 @@ export type Network = {
|
|||
};
|
||||
|
||||
export type System = {
|
||||
/* TODO (kurkomisi) */
|
||||
activeMemory: ChartEntries,
|
||||
virtualMemory: ChartEntries,
|
||||
networkIngress: ChartEntries,
|
||||
networkEgress: ChartEntries,
|
||||
processCPU: ChartEntries,
|
||||
systemCPU: ChartEntries,
|
||||
diskRead: ChartEntries,
|
||||
diskWrite: ChartEntries,
|
||||
};
|
||||
|
||||
export type Logs = {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ module.exports = {
|
|||
mangle: false,
|
||||
beautify: true,
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
PROD: process.env.NODE_ENV === 'production',
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
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 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
|
||||
|
||||
//go:generate npm --prefix ./assets install
|
||||
//go:generate ./assets/node_modules/.bin/webpack --config ./assets/webpack.config.js --context ./assets
|
||||
//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/dashboard.html assets/bundle.js
|
||||
//go:generate yarn --cwd ./assets install
|
||||
//go:generate yarn --cwd ./assets build
|
||||
//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 _dashboardHtml#//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 sh -c "sed 's#var _indexHtml#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
||||
//go:generate gofmt -w -s assets.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
|
@ -64,7 +60,7 @@ type Dashboard struct {
|
|||
|
||||
listener net.Listener
|
||||
conns map[uint32]*client // Currently live websocket connections
|
||||
charts *HomeMessage
|
||||
charts *SystemMessage
|
||||
commit string
|
||||
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),
|
||||
config: config,
|
||||
quit: make(chan chan error),
|
||||
charts: &HomeMessage{
|
||||
charts: &SystemMessage{
|
||||
ActiveMemory: emptyChartEntries(now, activeMemorySampleLimit, config.Refresh),
|
||||
VirtualMemory: emptyChartEntries(now, virtualMemorySampleLimit, 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()
|
||||
if path == "/" {
|
||||
path = "/dashboard.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
|
||||
path = "/index.html"
|
||||
}
|
||||
blob, err := Asset(path[1:])
|
||||
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),
|
||||
Commit: db.commit,
|
||||
},
|
||||
Home: &HomeMessage{
|
||||
System: &SystemMessage{
|
||||
ActiveMemory: db.charts.ActiveMemory,
|
||||
VirtualMemory: db.charts.VirtualMemory,
|
||||
NetworkIngress: db.charts.NetworkIngress,
|
||||
|
|
@ -279,12 +264,14 @@ func (db *Dashboard) collectData() {
|
|||
systemCPUUsage := gosigar.Cpu{}
|
||||
systemCPUUsage.Get()
|
||||
var (
|
||||
mem runtime.MemStats
|
||||
|
||||
prevNetworkIngress = metrics.DefaultRegistry.Get("p2p/InboundTraffic").(metrics.Meter).Count()
|
||||
prevNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
||||
prevProcessCPUTime = getProcessCPUTime()
|
||||
prevSystemCPUUsage = systemCPUUsage
|
||||
prevDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/input").(metrics.Meter).Count()
|
||||
prevDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/output").(metrics.Meter).Count()
|
||||
prevDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/read").(metrics.Meter).Count()
|
||||
prevDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/write").(metrics.Meter).Count()
|
||||
|
||||
frequency = float64(db.config.Refresh / time.Second)
|
||||
numCPU = float64(runtime.NumCPU())
|
||||
|
|
@ -302,13 +289,13 @@ func (db *Dashboard) collectData() {
|
|||
curNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
||||
curProcessCPUTime = getProcessCPUTime()
|
||||
curSystemCPUUsage = systemCPUUsage
|
||||
curDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/input").(metrics.Meter).Count()
|
||||
curDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/output").(metrics.Meter).Count()
|
||||
curDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/read").(metrics.Meter).Count()
|
||||
curDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/write").(metrics.Meter).Count()
|
||||
|
||||
deltaNetworkIngress = float64(curNetworkIngress - prevNetworkIngress)
|
||||
deltaNetworkEgress = float64(curNetworkEgress - prevNetworkEgress)
|
||||
deltaProcessCPUTime = curProcessCPUTime - prevProcessCPUTime
|
||||
deltaSystemCPUUsage = systemCPUUsage.Delta(prevSystemCPUUsage)
|
||||
deltaSystemCPUUsage = curSystemCPUUsage.Delta(prevSystemCPUUsage)
|
||||
deltaDiskRead = curDiskRead - prevDiskRead
|
||||
deltaDiskWrite = curDiskWrite - prevDiskWrite
|
||||
)
|
||||
|
|
@ -321,7 +308,6 @@ func (db *Dashboard) collectData() {
|
|||
|
||||
now := time.Now()
|
||||
|
||||
var mem runtime.MemStats
|
||||
runtime.ReadMemStats(&mem)
|
||||
activeMemory := &ChartEntry{
|
||||
Time: now,
|
||||
|
|
@ -365,7 +351,7 @@ func (db *Dashboard) collectData() {
|
|||
db.charts.DiskWrite = append(db.charts.DiskRead[1:], diskWrite)
|
||||
|
||||
db.sendToAll(&Message{
|
||||
Home: &HomeMessage{
|
||||
System: &SystemMessage{
|
||||
ActiveMemory: ChartEntries{activeMemory},
|
||||
VirtualMemory: ChartEntries{virtualMemory},
|
||||
NetworkIngress: ChartEntries{networkIngress},
|
||||
|
|
|
|||
|
|
@ -28,27 +28,20 @@ type Message struct {
|
|||
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 {
|
||||
Version string `json:"version,omitempty"`
|
||||
Commit string `json:"commit,omitempty"`
|
||||
}
|
||||
|
||||
type HomeMessage struct {
|
||||
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 ChartEntries []*ChartEntry
|
||||
|
||||
type ChartEntry struct {
|
||||
Time time.Time `json:"time,omitempty"`
|
||||
Value float64 `json:"value,omitempty"`
|
||||
/* TODO (kurkomisi) */
|
||||
}
|
||||
|
||||
type ChainMessage struct {
|
||||
|
|
@ -64,7 +57,14 @@ type NetworkMessage 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 {
|
||||
|
|
|
|||
|
|
@ -1296,6 +1296,14 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er
|
|||
headers = headers[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
|
||||
for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} {
|
||||
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
|
||||
// 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.
|
||||
func (f *Fetcher) insert(peer string, block *types.Block) {
|
||||
hash := block.Hash()
|
||||
|
|
|
|||
|
|
@ -188,6 +188,14 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
|
|||
atomic.StoreUint32(&pm.fastSync, 1)
|
||||
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
|
||||
if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -37,15 +37,11 @@ type LDBDatabase struct {
|
|||
fn string // filename for reporting
|
||||
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
|
||||
compReadMeter metrics.Meter // Meter for measuring the data read 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
|
||||
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
|
||||
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
|
||||
//value = rle.Compress(value)
|
||||
|
||||
if db.writeMeter != nil {
|
||||
db.writeMeter.Mark(int64(len(value)))
|
||||
}
|
||||
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.
|
||||
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
|
||||
dat, err := db.db.Get(key, nil)
|
||||
if err != nil {
|
||||
if db.missMeter != nil {
|
||||
db.missMeter.Mark(1)
|
||||
}
|
||||
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 rle.Decompress(dat)
|
||||
}
|
||||
|
||||
// Delete deletes the key from the queue and database
|
||||
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
|
||||
return db.db.Delete(key, nil)
|
||||
}
|
||||
|
|
@ -178,15 +152,11 @@ func (db *LDBDatabase) Meter(prefix string) {
|
|||
return
|
||||
}
|
||||
// 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.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", 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
|
||||
db.quitLock.Lock()
|
||||
|
|
@ -207,12 +177,17 @@ func (db *LDBDatabase) Meter(prefix string) {
|
|||
// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294
|
||||
// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884
|
||||
// 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) {
|
||||
// Create the counters to store current and previous values
|
||||
counters := make([][]float64, 2)
|
||||
// Create the counters to store current and previous compaction values
|
||||
compactions := make([][]float64, 2)
|
||||
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
|
||||
for i := 1; ; i++ {
|
||||
// Retrieve the database stats
|
||||
|
|
@ -233,8 +208,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
|||
lines = lines[3:]
|
||||
|
||||
// Iterate over all the table rows, and accumulate the entries
|
||||
for j := 0; j < len(counters[i%2]); j++ {
|
||||
counters[i%2][j] = 0
|
||||
for j := 0; j < len(compactions[i%2]); j++ {
|
||||
compactions[i%2][j] = 0
|
||||
}
|
||||
for _, line := range lines {
|
||||
parts := strings.Split(line, "|")
|
||||
|
|
@ -247,19 +222,60 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
|||
db.log.Error("Compaction entry parsing failed", "err", err)
|
||||
return
|
||||
}
|
||||
counters[i%2][idx] += value
|
||||
compactions[i%2][idx] += value
|
||||
}
|
||||
}
|
||||
// Update all the requested meters
|
||||
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 {
|
||||
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 {
|
||||
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
|
||||
select {
|
||||
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 {
|
||||
// Match. Re-sign and send the transaction.
|
||||
if gasPrice != nil {
|
||||
if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 {
|
||||
sendArgs.GasPrice = gasPrice
|
||||
}
|
||||
if gasLimit != nil {
|
||||
if gasLimit != nil && *gasLimit != 0 {
|
||||
sendArgs.Gas = gasLimit
|
||||
}
|
||||
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)
|
||||
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)
|
||||
}
|
||||
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'.
|
||||
// leveldb.stats
|
||||
// Returns statistics of the underlying DB.
|
||||
// leveldb.iostats
|
||||
// Returns statistics of effective disk read and write.
|
||||
// leveldb.writedelay
|
||||
// Returns cumulative write delay caused by compaction.
|
||||
// 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(),
|
||||
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":
|
||||
writeDelayN, writeDelay := atomic.LoadInt32(&db.cWriteDelayN), time.Duration(atomic.LoadInt64(&db.cWriteDelay))
|
||||
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'.
|
||||
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
|
||||
// its contents may change on the next call to any 'seeks method'.
|
||||
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]
|
||||
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]
|
||||
}
|
||||
|
||||
|
|
|
|||
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
|
||||
stSeqNum uint64 // last mem compacted seq; need external synchronization
|
||||
|
||||
stor storage.Storage
|
||||
stor *iStorage
|
||||
storLock storage.Locker
|
||||
o *cachedOptions
|
||||
icmp *iComparer
|
||||
|
|
@ -68,7 +68,7 @@ func newSession(stor storage.Storage, o *opt.Options) (s *session, err error) {
|
|||
return
|
||||
}
|
||||
s = &session{
|
||||
stor: stor,
|
||||
stor: newIStorage(stor),
|
||||
storLock: storLock,
|
||||
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 (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type plan9FileLock struct {
|
||||
|
|
@ -48,8 +47,7 @@ func rename(oldpath, newpath string) error {
|
|||
}
|
||||
}
|
||||
|
||||
_, fname := filepath.Split(newpath)
|
||||
return os.Rename(oldpath, fname)
|
||||
return os.Rename(oldpath, newpath)
|
||||
}
|
||||
|
||||
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.
|
||||
type Releaser interface {
|
||||
// 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()
|
||||
}
|
||||
|
||||
|
|
|
|||
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
|
||||
|
||||
/*
|
||||
#cgo !windows CFLAGS: -std=c99 -O3 -Wall -fomit-frame-pointer -fstrict-aliasing
|
||||
#cgo windows CFLAGS: -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 -Wno-unused-value -fomit-frame-pointer -fstrict-aliasing
|
||||
|
||||
#include "duktape.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 linux LDFLAGS: -lm
|
||||
#cgo freebsd LDFLAGS: -lm
|
||||
#cgo openbsd LDFLAGS: -lm
|
||||
|
||||
#include "duktape.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"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "rpu5ZHjXlV13UKA7L1d5MTOyQwA=",
|
||||
"checksumSHA1": "3QsnhPTXGytTbW3uDvQLgSo9s9M=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb",
|
||||
"revision": "211f780988068502fe874c44dae530528ebd840f",
|
||||
"revisionTime": "2018-01-28T14:04:16Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "EKIow7XkgNdWvR/982ffIZxKG8Y=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/cache",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "5KPgnvCPlR0ysDAqo6jApzRQ3tw=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/comparer",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "1DRAxdlWzS4U0xKN/yQ/fdNN7f0=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/errors",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "eqKeD6DS7eNCtxVYZEHHRKkyZrw=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/filter",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "8dXuAVIsbtaMiGGuHjzGR6Ny/5c=",
|
||||
"checksumSHA1": "weSsccMav4BCerDpSLzh3mMxAYo=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/iterator",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "gJY7bRpELtO0PJpZXgPQ2BYFJ88=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/journal",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "j+uaQ6DwJ50dkIdfMQu1TXdlQcY=",
|
||||
"checksumSHA1": "MtYY1b2234y/MlS+djL8tXVAcQs=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/memdb",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "UmQeotV+m8/FduKEfLOhjdp18rs=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/opt",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "tQ2AqXXAEy9icbZI9dLVdZGvWMw=",
|
||||
"checksumSHA1": "QCSae2ub87f8awH+PKMpd8ZYOtg=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/storage",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "gWFPMz8OQeul0t54RM66yMTX49g=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/table",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "4zil8Gwg8VPkDn1YzlgCvtukJFU=",
|
||||
"checksumSHA1": "V/Dh7NV0/fy/5jX1KaAjmGcNbzI=",
|
||||
"path": "github.com/syndtr/goleveldb/leveldb/util",
|
||||
"revision": "b89cc31ef7977104127d34c1bd31ebd1a9db2199",
|
||||
"revisionTime": "2017-07-25T06:48:36Z"
|
||||
"revision": "169b1b37be738edb2813dab48c97a549bcf99bb5",
|
||||
"revisionTime": "2018-03-07T11:33:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "pClJgcy1COeHxz/qRDFWnWgXTEI=",
|
||||
|
|
@ -802,10 +802,10 @@
|
|||
"revisionTime": "2016-06-21T03:49:01Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "YvuEbc0a032zr+BTp/YbBQojiuY=",
|
||||
"checksumSHA1": "vndxs5Tv09/8S+Dr2PBAiM557lI=",
|
||||
"path": "gopkg.in/olebedev/go-duktape.v3",
|
||||
"revision": "9af39127cb024b355a6a0221769f6ddfe3f542e7",
|
||||
"revisionTime": "2017-12-20T12:19:14Z"
|
||||
"revision": "abf0ba0be5d5d36b1f9266463cc320b9a5ab224e",
|
||||
"revisionTime": "2018-03-02T12:15:09Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "4BwmmgQUhWtizsR2soXND0nqZ1I=",
|
||||
|
|
|
|||
|
|
@ -269,3 +269,11 @@ func TopicToBloom(topic TopicType) []byte {
|
|||
}
|
||||
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