Merge pull request #9 from ethereum/master

Pull latest changes from geth
This commit is contained in:
ledgerwatch 2018-03-01 13:22:13 +00:00 committed by GitHub
commit fc3d2eb02c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
282 changed files with 13356 additions and 4999 deletions

3
.gitignore vendored
View file

@ -34,6 +34,9 @@ profile.cov
# IdeaIDE # IdeaIDE
.idea .idea
# VS Code
.vscode
# dashboard # dashboard
/dashboard/assets/flow-typed /dashboard/assets/flow-typed
/dashboard/assets/node_modules /dashboard/assets/node_modules

View file

@ -65,7 +65,8 @@ Enrique Fynn <enriquefynn@gmail.com>
Vincent G <caktux@gmail.com> Vincent G <caktux@gmail.com>
RJ Catalano <rj@erisindustries.com> RJ Catalano <catalanor0220@gmail.com>
RJ Catalano <catalanor0220@gmail.com> <rj@erisindustries.com>
Nchinda Nchinda <nchinda2@gmail.com> Nchinda Nchinda <nchinda2@gmail.com>
@ -109,3 +110,14 @@ Frank Wang <eternnoir@gmail.com>
Gary Rong <garyrong0905@gmail.com> Gary Rong <garyrong0905@gmail.com>
Guillaume Nicolas <guin56@gmail.com> Guillaume Nicolas <guin56@gmail.com>
Sorin Neacsu <sorin.neacsu@gmail.com>
Sorin Neacsu <sorin.neacsu@gmail.com> <sorin@users.noreply.github.com>
Valentin Wüstholz <wuestholz@gmail.com>
Valentin Wüstholz <wuestholz@gmail.com> <wuestholz@users.noreply.github.com>
Armin Braun <me@obrown.io>
Ernesto del Toro <ernesto.deltoro@gmail.com>
Ernesto del Toro <ernesto.deltoro@gmail.com> <ernestodeltoro@users.noreply.github.com>

View file

@ -3,17 +3,6 @@ go_import_path: github.com/ethereum/go-ethereum
sudo: false sudo: false
matrix: matrix:
include: include:
- os: linux
dist: trusty
sudo: required
go: 1.7.x
script:
- 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
- os: linux - os: linux
dist: trusty dist: trusty
sudo: required sudo: required
@ -185,6 +174,8 @@ matrix:
- xctool -version - xctool -version
- xcrun simctl list - xcrun simctl list
# Workaround for https://github.com/golang/go/issues/23749
- export CGO_CFLAGS_ALLOW='-fmodules|-fblocks|-fobjc-arc'
- go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds - go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
# This builder does the Azure archive purges to avoid accumulating junk # This builder does the Azure archive purges to avoid accumulating junk

92
AUTHORS
View file

@ -1,85 +1,173 @@
# This is the official list of go-ethereum authors for copyright purposes. # This is the official list of go-ethereum authors for copyright purposes.
Afri Schoedon <5chdn@users.noreply.github.com>
Agustin Armellini Fischer <armellini13@gmail.com>
Airead <fgh1987168@gmail.com>
Alan Chen <alanchchen@users.noreply.github.com>
Alejandro Isaza <alejandro.isaza@gmail.com>
Ales Katona <ales@coinbase.com> Ales Katona <ales@coinbase.com>
Alex Leverington <alex@ethdev.com> Alex Leverington <alex@ethdev.com>
Alex Wu <wuyiding@gmail.com>
Alexandre Van de Sande <alex.vandesande@ethdev.com> Alexandre Van de Sande <alex.vandesande@ethdev.com>
Ali Hajimirza <Ali92hm@users.noreply.github.com>
Anton Evangelatov <anton.evangelatov@gmail.com>
Arba Sasmoyo <arba.sasmoyo@gmail.com>
Armani Ferrante <armaniferrante@berkeley.edu>
Armin Braun <me@obrown.io>
Aron Fischer <github@aron.guru> Aron Fischer <github@aron.guru>
Bas van Kervel <bas@ethdev.com> Bas van Kervel <bas@ethdev.com>
Benjamin Brent <benjamin@benjaminbrent.com> Benjamin Brent <benjamin@benjaminbrent.com>
Benoit Verkindt <benoit.verkindt@gmail.com>
Bo <bohende@gmail.com>
Bo Ye <boy.e.computer.1982@outlook.com>
Bob Glickstein <bobg@users.noreply.github.com>
Brian Schroeder <bts@gmail.com> Brian Schroeder <bts@gmail.com>
Casey Detrio <cdetrio@gmail.com> Casey Detrio <cdetrio@gmail.com>
Chase Wright <mysticryuujin@gmail.com>
Christoph Jentzsch <jentzsch.software@gmail.com> Christoph Jentzsch <jentzsch.software@gmail.com>
Daniel A. Nagy <nagy.da@gmail.com> Daniel A. Nagy <nagy.da@gmail.com>
Daniel Sloof <goapsychadelic@gmail.com>
Darrel Herbst <dherbst@gmail.com>
Dave Appleton <calistralabs@gmail.com>
Diego Siqueira <DiSiqueira@users.noreply.github.com> Diego Siqueira <DiSiqueira@users.noreply.github.com>
Dmitry Shulyak <yashulyak@gmail.com>
Egon Elbre <egonelbre@gmail.com>
Elias Naur <elias.naur@gmail.com>
Elliot Shepherd <elliot@identitii.com> Elliot Shepherd <elliot@identitii.com>
Enrique Fynn <enriquefynn@gmail.com> Enrique Fynn <enriquefynn@gmail.com>
Ernesto del Toro <ernesto.deltoro@gmail.com>
Ethan Buchman <ethan@coinculture.info> Ethan Buchman <ethan@coinculture.info>
Eugene Valeyev <evgen.povt@gmail.com>
Evangelos Pappas <epappas@evalonlabs.com>
Evgeny Danilenko <6655321@bk.ru>
Fabian Vogelsteller <fabian@frozeman.de> Fabian Vogelsteller <fabian@frozeman.de>
Fabio Barone <fabio.barone.co@gmail.com>
Fabio Berger <fabioberger1991@gmail.com> Fabio Berger <fabioberger1991@gmail.com>
FaceHo <facehoshi@gmail.com>
Felix Lange <fjl@twurst.com> Felix Lange <fjl@twurst.com>
Fiisio <liangcszzu@163.com>
Frank Wang <eternnoir@gmail.com> Frank Wang <eternnoir@gmail.com>
Furkan KAMACI <furkankamaci@gmail.com>
Gary Rong <garyrong0905@gmail.com> Gary Rong <garyrong0905@gmail.com>
George Ornbo <george@shapeshed.com>
Gregg Dourgarian <greggd@tempworks.com> Gregg Dourgarian <greggd@tempworks.com>
Guillaume Ballet <gballet@gmail.com>
Guillaume Nicolas <guin56@gmail.com> Guillaume Nicolas <guin56@gmail.com>
Gustav Simonsson <gustav.simonsson@gmail.com> Gustav Simonsson <gustav.simonsson@gmail.com>
Hao Bryan Cheng <haobcheng@gmail.com> Hao Bryan Cheng <haobcheng@gmail.com>
Henning Diedrich <hd@eonblast.com> Henning Diedrich <hd@eonblast.com>
Isidoro Ghezzi <isidoro.ghezzi@icloud.com> Isidoro Ghezzi <isidoro.ghezzi@icloud.com>
Ivan Daniluk <ivan.daniluk@gmail.com>
Jae Kwon <jkwon.work@gmail.com> Jae Kwon <jkwon.work@gmail.com>
Jamie Pitts <james.pitts@gmail.com> Jamie Pitts <james.pitts@gmail.com>
Janoš Guljaš <janos@users.noreply.github.com>
Jason Carver <jacarver@linkedin.com> Jason Carver <jacarver@linkedin.com>
Jay Guo <guojiannan1101@gmail.com>
Jeff R. Allen <jra@nella.org> Jeff R. Allen <jra@nella.org>
Jeffrey Wilcke <jeffrey@ethereum.org> Jeffrey Wilcke <jeffrey@ethereum.org>
Jens Agerberg <github@agerberg.me> Jens Agerberg <github@agerberg.me>
Jia Chenhui <jiachenhui1989@gmail.com>
Jim McDonald <Jim@mcdee.net>
Joel Burget <joelburget@gmail.com>
Jonathan Brown <jbrown@bluedroplet.com> Jonathan Brown <jbrown@bluedroplet.com>
Joseph Chow <ethereum@outlook.com> Joseph Chow <ethereum@outlook.com>
Justin Clark-Casey <justincc@justincc.org> Justin Clark-Casey <justincc@justincc.org>
Justin Drake <drakefjustin@gmail.com> Justin Drake <drakefjustin@gmail.com>
Kenji Siu <kenji@isuntv.com> Kenji Siu <kenji@isuntv.com>
Kobi Gurkan <kobigurk@gmail.com> Kobi Gurkan <kobigurk@gmail.com>
Konrad Feldmeier <konrad@brainbot.com>
Kurkó Mihály <kurkomisi@users.noreply.github.com>
Kyuntae Ethan Kim <ethan.kyuntae.kim@gmail.com>
Lefteris Karapetsas <lefteris@refu.co> Lefteris Karapetsas <lefteris@refu.co>
Leif Jurvetson <leijurv@gmail.com> Leif Jurvetson <leijurv@gmail.com>
Leo Shklovskii <leo@thermopylae.net>
Lewis Marshall <lewis@lmars.net> Lewis Marshall <lewis@lmars.net>
Lio李欧 <lionello@users.noreply.github.com>
Louis Holbrook <dev@holbrook.no> Louis Holbrook <dev@holbrook.no>
Luca Zeug <luclu@users.noreply.github.com> Luca Zeug <luclu@users.noreply.github.com>
Magicking <s@6120.eu>
Maran Hidskes <maran.hidskes@gmail.com> Maran Hidskes <maran.hidskes@gmail.com>
Marek Kotewicz <marek.kotewicz@gmail.com> Marek Kotewicz <marek.kotewicz@gmail.com>
Mark <markya0616@gmail.com>
Martin Holst Swende <martin@swende.se> Martin Holst Swende <martin@swende.se>
Matthew Di Ferrante <mattdf@users.noreply.github.com> Matthew Di Ferrante <mattdf@users.noreply.github.com>
Matthew Wampler-Doty <matthew.wampler.doty@gmail.com> Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
Maximilian Meister <mmeister@suse.de>
Micah Zoltu <micah@zoltu.net> Micah Zoltu <micah@zoltu.net>
Michael Ruminer <michael.ruminer+github@gmail.com>
Miguel Mota <miguelmota2@gmail.com>
Miya Chen <miyatlchen@gmail.com>
Nchinda Nchinda <nchinda2@gmail.com> Nchinda Nchinda <nchinda2@gmail.com>
Nick Dodson <silentcicero@outlook.com> Nick Dodson <silentcicero@outlook.com>
Nick Johnson <arachnid@notdot.net> Nick Johnson <arachnid@notdot.net>
Nicolas Guillaume <gunicolas@sqli.com>
Noman <noman@noman.land>
Oli Bye <olibye@users.noreply.github.com>
Paul Litvak <litvakpol@012.net.il>
Paulo L F Casaretto <pcasaretto@gmail.com> Paulo L F Casaretto <pcasaretto@gmail.com>
Paweł Bylica <chfast@gmail.com>
Peter Pratscher <pratscher@gmail.com> Peter Pratscher <pratscher@gmail.com>
Petr Mikusek <petr@mikusek.info>
Péter Szilágyi <peterke@gmail.com> Péter Szilágyi <peterke@gmail.com>
RJ Catalano <rj@erisindustries.com> RJ Catalano <catalanor0220@gmail.com>
Ramesh Nair <ram@hiddentao.com> Ramesh Nair <ram@hiddentao.com>
Ricardo Catalinas Jiménez <r@untroubled.be> Ricardo Catalinas Jiménez <r@untroubled.be>
Ricardo Domingos <ricardohsd@gmail.com>
Richard Hart <richardhart92@gmail.com>
Rob <robert@rojotek.com>
Robert Zaremba <robert.zaremba@scale-it.pl>
Russ Cox <rsc@golang.org>
Rémy Roy <remyroy@remyroy.com> Rémy Roy <remyroy@remyroy.com>
S. Matthew English <s-matthew-english@users.noreply.github.com>
Shintaro Kaneko <kaneshin0120@gmail.com> Shintaro Kaneko <kaneshin0120@gmail.com>
Sorin Neacsu <sorin.neacsu@gmail.com>
Stein Dekker <dekker.stein@gmail.com> Stein Dekker <dekker.stein@gmail.com>
Steve Waldman <swaldman@mchange.com>
Steven Roose <stevenroose@gmail.com> Steven Roose <stevenroose@gmail.com>
Taylor Gerring <taylor.gerring@gmail.com> Taylor Gerring <taylor.gerring@gmail.com>
Thomas Bocek <tom@tomp2p.net> Thomas Bocek <tom@tomp2p.net>
Ti Zhou <tizhou1986@gmail.com>
Tosh Camille <tochecamille@gmail.com> Tosh Camille <tochecamille@gmail.com>
Valentin Wüstholz <wuestholz@users.noreply.github.com> Valentin Wüstholz <wuestholz@gmail.com>
Victor Farazdagi <simple.square@gmail.com> Victor Farazdagi <simple.square@gmail.com>
Victor Tran <vu.tran54@gmail.com> Victor Tran <vu.tran54@gmail.com>
Viktor Trón <viktor.tron@gmail.com> Viktor Trón <viktor.tron@gmail.com>
Ville Sundell <github@solarius.fi> Ville Sundell <github@solarius.fi>
Vincent G <caktux@gmail.com> Vincent G <caktux@gmail.com>
Vitalik Buterin <v@buterin.com> Vitalik Buterin <v@buterin.com>
Vitaly V <vvelikodny@gmail.com>
Vivek Anand <vivekanand1101@users.noreply.github.com> Vivek Anand <vivekanand1101@users.noreply.github.com>
Vlad Gluhovsky <gluk256@users.noreply.github.com> Vlad Gluhovsky <gluk256@users.noreply.github.com>
Yohann Léon <sybiload@gmail.com> Yohann Léon <sybiload@gmail.com>
Yoichi Hirai <i@yoichihirai.com> Yoichi Hirai <i@yoichihirai.com>
Yondon Fu <yondon.fu@gmail.com>
Zach <zach.ramsay@gmail.com>
Zahoor Mohamed <zahoor@zahoor.in> Zahoor Mohamed <zahoor@zahoor.in>
Zoe Nolan <github@zoenolan.org>
Zsolt Felföldi <zsfelfoldi@gmail.com> Zsolt Felföldi <zsfelfoldi@gmail.com>
am2rican5 <am2rican5@gmail.com>
ayeowch <ayeowch@gmail.com>
b00ris <b00ris@mail.ru>
bailantaotao <Edwin@maicoin.com>
baizhenxuan <nkbai@163.com>
bloonfield <bloonfield@163.com>
changhong <changhong.yu@shanbay.com>
evgk <evgeniy.kamyshev@gmail.com>
ferhat elmas <elmas.ferhat@gmail.com>
holisticode <holistic.computing@gmail.com> holisticode <holistic.computing@gmail.com>
jtakalai <juuso.takalainen@streamr.com>
ken10100147 <sunhongping@kanjian.com> ken10100147 <sunhongping@kanjian.com>
ligi <ligi@ligi.de> ligi <ligi@ligi.de>
mark.lin <mark@maicoin.com>
necaremus <necaremus@gmail.com>
njupt-moon <1015041018@njupt.edu.cn>
nkbai <nkbai@163.com>
rhaps107 <dod-source@yandex.ru>
slumber1122 <slumber1122@gmail.com>
sunxiaojun2014 <sunxiaojun-xy@360.cn>
terasum <terasum@163.com>
tsarpaul <Litvakpol@012.net.il>
xiekeyang <xiekeyang@users.noreply.github.com> xiekeyang <xiekeyang@users.noreply.github.com>
yoza <yoza.is12s@gmail.com>
ΞTHΞЯSPHΞЯΞ <{viktor.tron,nagydani,zsfelfoldi}@gmail.com> ΞTHΞЯSPHΞЯΞ <{viktor.tron,nagydani,zsfelfoldi}@gmail.com>
Максим Чусовлянов <mchusovlianov@gmail.com> Максим Чусовлянов <mchusovlianov@gmail.com>

View file

@ -5,6 +5,8 @@ Official golang implementation of the Ethereum protocol.
[![API Reference]( [![API Reference](
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667 https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
)](https://godoc.org/github.com/ethereum/go-ethereum) )](https://godoc.org/github.com/ethereum/go-ethereum)
[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
[![Travis](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Automated builds are available for stable releases and the unstable master branch. Automated builds are available for stable releases and the unstable master branch.
@ -56,16 +58,14 @@ the user doesn't care about years-old historical data, so we can fast-sync quick
state of the network. To do so: state of the network. To do so:
``` ```
$ geth --fast --cache=512 console $ geth console
``` ```
This command will: This command will:
* Start geth in fast sync mode (`--fast`), causing it to download more data in exchange for avoiding * Start geth in fast sync mode (default, can be changed with the `--syncmode` flag), causing it to
processing the entire history of the Ethereum network, which is very CPU intensive. download more data in exchange for avoiding processing the entire history of the Ethereum network,
* Bump the memory allowance of the database to 512MB (`--cache=512`), which can help significantly in which is very CPU intensive.
sync times especially for HDD users. This flag is optional and you can set it as high or as low as
you'd like, though we'd recommend the 512MB - 2GB range.
* Start up Geth's built-in interactive [JavaScript console](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console), * Start up Geth's built-in interactive [JavaScript console](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console),
(via the trailing `console` subcommand) through which you can invoke all official [`web3` methods](https://github.com/ethereum/wiki/wiki/JavaScript-API) (via the trailing `console` subcommand) through which you can invoke all official [`web3` methods](https://github.com/ethereum/wiki/wiki/JavaScript-API)
as well as Geth's own [management APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs). as well as Geth's own [management APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs).
@ -80,12 +80,11 @@ entire system. In other words, instead of attaching to the main network, you wan
network with your node, which is fully equivalent to the main network, but with play-Ether only. network with your node, which is fully equivalent to the main network, but with play-Ether only.
``` ```
$ geth --testnet --fast --cache=512 console $ geth --testnet console
``` ```
The `--fast`, `--cache` flags and `console` subcommand have the exact same meaning as above and they The `console` subcommand have the exact same meaning as above and they are equally useful on the
are equally useful on the testnet too. Please see above for their explanations if you've skipped to testnet too. Please see above for their explanations if you've skipped to here.
here.
Specifying the `--testnet` flag however will reconfigure your Geth instance a bit: Specifying the `--testnet` flag however will reconfigure your Geth instance a bit:
@ -102,6 +101,14 @@ over between the main network and test network, you should make sure to always u
for play-money and real-money. Unless you manually move accounts, Geth will by default correctly for play-money and real-money. Unless you manually move accounts, Geth will by default correctly
separate the two networks and will not make any accounts available between them.* separate the two networks and will not make any accounts available between them.*
### Full node on the Rinkeby test network
The above test network is a cross client one based on the ethash proof-of-work consensus algorithm. As such, it has certain extra overhead and is more susceptible to reorganization attacks due to the network's low difficulty / security. Go Ethereum also supports connecting to a proof-of-authority based test network called [*Rinkeby*](https://www.rinkeby.io) (operated by members of the community). This network is lighter, more secure, but is only supported by go-ethereum.
```
$ geth --rinkeby console
```
### Configuration ### Configuration
As an alternative to passing the numerous flags to the `geth` binary, you can also pass a configuration file via: As an alternative to passing the numerous flags to the `geth` binary, you can also pass a configuration file via:
@ -125,10 +132,10 @@ One of the quickest ways to get Ethereum up and running on your machine is by us
``` ```
docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \ docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \
-p 8545:8545 -p 30303:30303 \ -p 8545:8545 -p 30303:30303 \
ethereum/client-go --fast --cache=512 ethereum/client-go
``` ```
This will start geth in fast sync mode with a DB memory allowance of 512MB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image. This will start geth in fast-sync mode with a DB memory allowance of 1GB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image.
Do not forget `--rpcaddr 0.0.0.0`, if you want to access RPC from other containers and/or hosts. By default, `geth` binds to the local interface and RPC endpoints is not accessible from the outside. Do not forget `--rpcaddr 0.0.0.0`, if you want to access RPC from other containers and/or hosts. By default, `geth` binds to the local interface and RPC endpoints is not accessible from the outside.

View file

@ -1 +1 @@
1.8.0 1.8.2

View file

@ -136,11 +136,11 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
// MethodById looks up a method by the 4-byte id // MethodById looks up a method by the 4-byte id
// returns nil if none found // returns nil if none found
func (abi *ABI) MethodById(sigdata []byte) *Method { func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
for _, method := range abi.Methods { for _, method := range abi.Methods {
if bytes.Equal(method.Id(), sigdata[:4]) { if bytes.Equal(method.Id(), sigdata[:4]) {
return &method return &method, nil
} }
} }
return nil return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
} }

View file

@ -689,7 +689,11 @@ func TestABI_MethodById(t *testing.T) {
} }
for name, m := range abi.Methods { for name, m := range abi.Methods {
a := fmt.Sprintf("%v", m) a := fmt.Sprintf("%v", m)
b := fmt.Sprintf("%v", abi.MethodById(m.Id())) m2, err := abi.MethodById(m.Id())
if err != nil {
t.Fatalf("Failed to look up ABI method: %v", err)
}
b := fmt.Sprintf("%v", m2)
if a != b { if a != b {
t.Errorf("Method %v (id %v) not 'findable' by id in ABI", name, common.ToHex(m.Id())) t.Errorf("Method %v (id %v) not 'findable' by id in ABI", name, common.ToHex(m.Id()))
} }

View file

@ -67,6 +67,17 @@ func (arguments Arguments) LengthNonIndexed() int {
return out return out
} }
// NonIndexed returns the arguments with indexed arguments filtered out
func (arguments Arguments) NonIndexed() Arguments {
var ret []Argument
for _, arg := range arguments {
if !arg.Indexed {
ret = append(ret, arg)
}
}
return ret
}
// isTuple returns true for non-atomic constructs, like (uint,uint) or uint[] // isTuple returns true for non-atomic constructs, like (uint,uint) or uint[]
func (arguments Arguments) isTuple() bool { func (arguments Arguments) isTuple() bool {
return len(arguments) > 1 return len(arguments) > 1
@ -74,21 +85,25 @@ func (arguments Arguments) isTuple() bool {
// Unpack performs the operation hexdata -> Go format // Unpack performs the operation hexdata -> Go format
func (arguments Arguments) Unpack(v interface{}, data []byte) error { func (arguments Arguments) Unpack(v interface{}, data []byte) error {
if arguments.isTuple() {
return arguments.unpackTuple(v, data)
}
return arguments.unpackAtomic(v, data)
}
func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
// make sure the passed value is arguments pointer // make sure the passed value is arguments pointer
valueOf := reflect.ValueOf(v) if reflect.Ptr != reflect.ValueOf(v).Kind() {
if reflect.Ptr != valueOf.Kind() {
return fmt.Errorf("abi: Unpack(non-pointer %T)", v) return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
} }
marshalledValues, err := arguments.UnpackValues(data)
if err != nil {
return err
}
if arguments.isTuple() {
return arguments.unpackTuple(v, marshalledValues)
}
return arguments.unpackAtomic(v, marshalledValues)
}
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
var ( var (
value = valueOf.Elem() value = reflect.ValueOf(v).Elem()
typ = value.Type() typ = value.Type()
kind = value.Kind() kind = value.Kind()
) )
@ -110,30 +125,9 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
exists[field] = true exists[field] = true
} }
} }
// `i` counts the nonindexed arguments. for i, arg := range arguments.NonIndexed() {
// `j` counts the number of complex types.
// both `i` and `j` are used to to correctly compute `data` offset.
i, j := -1, 0 reflectValue := reflect.ValueOf(marshalledValues[i])
for _, arg := range arguments {
if arg.Indexed {
// can't read, continue
continue
}
i++
marshalledValue, err := toGoType((i+j)*32, arg.Type, output)
if err != nil {
return err
}
if arg.Type.T == ArrayTy {
// combined index ('i' + 'j') need to be adjusted only by size of array, thus
// we need to decrement 'j' because 'i' was incremented
j += arg.Type.Size - 1
}
reflectValue := reflect.ValueOf(marshalledValue)
switch kind { switch kind {
case reflect.Struct: case reflect.Struct:
@ -166,34 +160,52 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
} }
// unpackAtomic unpacks ( hexdata -> go ) a single value // unpackAtomic unpacks ( hexdata -> go ) a single value
func (arguments Arguments) unpackAtomic(v interface{}, output []byte) error { func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error {
// make sure the passed value is arguments pointer if len(marshalledValues) != 1 {
valueOf := reflect.ValueOf(v) return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
if reflect.Ptr != valueOf.Kind() {
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
} }
arg := arguments[0] elem := reflect.ValueOf(v).Elem()
if arg.Indexed { reflectValue := reflect.ValueOf(marshalledValues[0])
return fmt.Errorf("abi: attempting to unpack indexed variable into element.") return set(elem, reflectValue, arguments.NonIndexed()[0])
}
value := valueOf.Elem()
marshalledValue, err := toGoType(0, arg.Type, output)
if err != nil {
return err
}
return set(value, reflect.ValueOf(marshalledValue), arg)
} }
// Unpack performs the operation Go format -> Hexdata // UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
// without supplying a struct to unpack into. Instead, this method returns a list containing the
// values. An atomic argument will be a list with one element.
func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
retval := make([]interface{}, 0, arguments.LengthNonIndexed())
virtualArgs := 0
for index, arg := range arguments.NonIndexed() {
marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data)
if arg.Type.T == ArrayTy {
// If we have a static array, like [3]uint256, these are coded as
// just like uint256,uint256,uint256.
// This means that we need to add two 'virtual' arguments when
// we count the index from now on
virtualArgs += arg.Type.Size - 1
}
if err != nil {
return nil, err
}
retval = append(retval, marshalledValue)
}
return retval, nil
}
// PackValues performs the operation Go format -> Hexdata
// It is the semantic opposite of UnpackValues
func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) {
return arguments.Pack(args...)
}
// Pack performs the operation Go format -> Hexdata
func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
// Make sure arguments match up and pack them // Make sure arguments match up and pack them
abiArgs := arguments abiArgs := arguments
if len(args) != len(abiArgs) { if len(args) != len(abiArgs) {
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs)) return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs))
} }
// variable input is the output appended at the end of packed // variable input is the output appended at the end of packed
// output. This is used for strings and bytes types input. // output. This is used for strings and bytes types input.
var variableInput []byte var variableInput []byte
@ -207,7 +219,6 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
inputOffset += 32 inputOffset += 32
} }
} }
var ret []byte var ret []byte
for i, a := range args { for i, a := range args {
input := abiArgs[i] input := abiArgs[i]
@ -216,7 +227,6 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// check for a slice type (string, bytes, slice) // check for a slice type (string, bytes, slice)
if input.Type.requiresLengthPrefix() { if input.Type.requiresLengthPrefix() {
// calculate the offset // calculate the offset

View file

@ -428,10 +428,23 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumb
} }
return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
} }
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil
} }
func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
receipts := core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash))
if receipts == nil {
return nil, nil
}
logs := make([][]*types.Log, len(receipts))
for i, receipt := range receipts {
logs[i] = receipt.Logs
}
return logs, nil
}
func (fb *filterBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { func (fb *filterBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {
return event.NewSubscription(func(quit <-chan struct{}) error { return event.NewSubscription(func(quit <-chan struct{}) error {
<-quit <-quit

View file

@ -1,4 +1,4 @@
// Copyright 2015 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
// Copyright 2015 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
@ -95,6 +95,9 @@ func readFixedBytes(t Type, word []byte) (interface{}, error) {
// iteratively unpack elements // iteratively unpack elements
func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) { func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
if size < 0 {
return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size)
}
if start+32*size > len(output) { if start+32*size > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size) return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size)
} }
@ -181,16 +184,32 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
// interprets a 32 byte slice as an offset and then determines which indice to look to decode the type. // interprets a 32 byte slice as an offset and then determines which indice to look to decode the type.
func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) { func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) {
offset := int(binary.BigEndian.Uint64(output[index+24 : index+32])) bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32])
if offset+32 > len(output) { bigOffsetEnd.Add(bigOffsetEnd, common.Big32)
return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32) outputLength := big.NewInt(int64(len(output)))
}
length = int(binary.BigEndian.Uint64(output[offset+24 : offset+32]))
if offset+32+length > len(output) {
return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+length)
}
start = offset + 32
//fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start) if bigOffsetEnd.Cmp(outputLength) > 0 {
return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", bigOffsetEnd, outputLength)
}
if bigOffsetEnd.BitLen() > 63 {
return 0, 0, fmt.Errorf("abi offset larger than int64: %v", bigOffsetEnd)
}
offsetEnd := int(bigOffsetEnd.Uint64())
lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd])
totalSize := big.NewInt(0)
totalSize.Add(totalSize, bigOffsetEnd)
totalSize.Add(totalSize, lengthBig)
if totalSize.BitLen() > 63 {
return 0, 0, fmt.Errorf("abi length larger than int64: %v", totalSize)
}
if totalSize.Cmp(outputLength) > 0 {
return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %v require %v", outputLength, totalSize)
}
start = int(bigOffsetEnd.Uint64())
length = int(lengthBig.Uint64())
return return
} }

View file

@ -1,4 +1,4 @@
// Copyright 2015 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
@ -130,7 +130,7 @@ var unpackTests = []unpackTest{
{ {
def: `[{"type": "bytes32"}]`, def: `[{"type": "bytes32"}]`,
enc: "0100000000000000000000000000000000000000000000000000000000000000", enc: "0100000000000000000000000000000000000000000000000000000000000000",
want: common.HexToHash("0100000000000000000000000000000000000000000000000000000000000000"), want: [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}, },
{ {
def: `[{"type": "function"}]`, def: `[{"type": "function"}]`,
@ -683,3 +683,73 @@ func TestUnmarshal(t *testing.T) {
t.Fatal("expected error:", err) t.Fatal("expected error:", err)
} }
} }
func TestOOMMaliciousInput(t *testing.T) {
oomTests := []unpackTest{
{
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
"0000000000000000000000000000000000000000000000000000000000000003" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Length larger than 64 bits
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
"00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Offset very large (over 64 bits)
def: `[{"type": "uint8[]"}]`,
enc: "00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000020" + // offset
"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Offset very large (below 64 bits)
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000007ffffffffff00020" + // offset
"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Offset negative (as 64 bit)
def: `[{"type": "uint8[]"}]`,
enc: "000000000000000000000000000000000000000000000000f000000000000020" + // offset
"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Negative length
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
"000000000000000000000000000000000000000000000000f000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Very large length
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
"0000000000000000000000000000000000000000000000007fffffffff000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
}
for i, test := range oomTests {
def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
abi, err := JSON(strings.NewReader(def))
if err != nil {
t.Fatalf("invalid ABI definition %s: %v", def, err)
}
encb, err := hex.DecodeString(test.enc)
if err != nil {
t.Fatalf("invalid hex: %s" + test.enc)
}
_, err = abi.Methods["method"].Outputs.UnpackValues(encb)
if err == nil {
t.Fatalf("Expected error on malicious input, test %d", i)
}
}
}

View file

@ -121,7 +121,8 @@ var (
// Note: vivid is unsupported because there is no golang-1.6 package for it. // Note: vivid is unsupported because there is no golang-1.6 package for it.
// Note: wily is unsupported because it was officially deprecated on lanchpad. // Note: wily is unsupported because it was officially deprecated on lanchpad.
// Note: yakkety is unsupported because it was officially deprecated on lanchpad. // Note: yakkety is unsupported because it was officially deprecated on lanchpad.
debDistros = []string{"trusty", "xenial", "zesty", "artful"} // Note: zesty is unsupported because it was officially deprecated on lanchpad.
debDistros = []string{"trusty", "xenial", "artful", "bionic"}
) )
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
@ -181,13 +182,13 @@ func doInstall(cmdline []string) {
// Check Go version. People regularly open issues about compilation // Check Go version. People regularly open issues about compilation
// failure with outdated Go. This should save them the trouble. // failure with outdated Go. This should save them the trouble.
if !strings.Contains(runtime.Version(), "devel") { if !strings.Contains(runtime.Version(), "devel") {
// Figure out the minor version number since we can't textually compare (1.10 < 1.7) // Figure out the minor version number since we can't textually compare (1.10 < 1.8)
var minor int var minor int
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor) fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
if minor < 7 { if minor < 8 {
log.Println("You have Go version", runtime.Version()) log.Println("You have Go version", runtime.Version())
log.Println("go-ethereum requires at least Go version 1.7 and cannot") log.Println("go-ethereum requires at least Go version 1.8 and cannot")
log.Println("be compiled with an earlier version. Please upgrade your Go installation.") log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
os.Exit(1) os.Exit(1)
} }

View file

@ -55,10 +55,9 @@ var (
"crypto/sha3/", "crypto/sha3/",
"internal/jsre/deps", "internal/jsre/deps",
"log/", "log/",
"common/bitutil/bitutil",
// don't license generated files // don't license generated files
"contracts/chequebook/contract/", "contracts/chequebook/contract/code.go",
"contracts/ens/contract/",
"contracts/release/contract.go",
} }
// paths with this prefix are licensed as GPL. all other files are LGPL. // paths with this prefix are licensed as GPL. all other files are LGPL.

View file

@ -122,7 +122,12 @@ func main() {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
} }
} else { } else {
if _, err := discover.ListenUDP(nodeKey, conn, realaddr, nil, "", restrictList); err != nil { cfg := discover.Config{
PrivateKey: nodeKey,
AnnounceAddr: realaddr,
NetRestrict: restrictList,
}
if _, err := discover.ListenUDP(conn, cfg); err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
} }
} }

View file

@ -1,3 +1,19 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main package main
import ( import (

View file

@ -1,4 +1,4 @@
// Copyright 2017 The go-ethereum Authors // Copyright 2018 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of go-ethereum.
// //
// go-ethereum is free software: you can redistribute it and/or modify // go-ethereum is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
// Copyright 2017 The go-ethereum Authors // Copyright 2018 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of go-ethereum.
// //
// go-ethereum is free software: you can redistribute it and/or modify // go-ethereum is free software: you can redistribute it and/or modify

View file

@ -1,18 +1,18 @@
// Copyright 2017 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of go-ethereum.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// The go-ethereum library is distributed in the hope that it will be useful, // go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main package main

View file

@ -686,8 +686,6 @@ func authTwitter(url string) (string, string, common.Address, error) {
if len(parts) < 4 || parts[len(parts)-2] != "status" { if len(parts) < 4 || parts[len(parts)-2] != "status" {
return "", "", common.Address{}, errors.New("Invalid Twitter status URL") return "", "", common.Address{}, errors.New("Invalid Twitter status URL")
} }
username := parts[len(parts)-3]
// Twitter's API isn't really friendly with direct links. Still, we don't // Twitter's API isn't really friendly with direct links. Still, we don't
// want to do ask read permissions from users, so just load the public posts and // want to do ask read permissions from users, so just load the public posts and
// scrape it for the Ethereum address and profile URL. // scrape it for the Ethereum address and profile URL.
@ -697,6 +695,13 @@ func authTwitter(url string) (string, string, common.Address, error) {
} }
defer res.Body.Close() defer res.Body.Close()
// Resolve the username from the final redirect, no intermediate junk
parts = strings.Split(res.Request.URL.String(), "/")
if len(parts) < 4 || parts[len(parts)-2] != "status" {
return "", "", common.Address{}, errors.New("Invalid Twitter status URL")
}
username := parts[len(parts)-3]
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
return "", "", common.Address{}, err return "", "", common.Address{}, err

View file

@ -67,6 +67,9 @@ It expects the genesis file as argument.`,
utils.DataDirFlag, utils.DataDirFlag,
utils.CacheFlag, utils.CacheFlag,
utils.LightModeFlag, utils.LightModeFlag,
utils.GCModeFlag,
utils.CacheDatabaseFlag,
utils.CacheGCFlag,
}, },
Category: "BLOCKCHAIN COMMANDS", Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `

View file

@ -22,6 +22,7 @@ import (
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"strings" "strings"
"syscall"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/console"
@ -42,7 +43,7 @@ var (
Description: ` Description: `
The Geth console is an interactive shell for the JavaScript runtime environment The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.`, See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.`,
} }
attachCommand = cli.Command{ attachCommand = cli.Command{
@ -55,7 +56,7 @@ See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.`,
Description: ` Description: `
The Geth console is an interactive shell for the JavaScript runtime environment The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.
This command allows to open a console on a running geth node.`, This command allows to open a console on a running geth node.`,
} }
@ -68,7 +69,7 @@ This command allows to open a console on a running geth node.`,
Category: "CONSOLE COMMANDS", Category: "CONSOLE COMMANDS",
Description: ` Description: `
The JavaScript VM exposes a node admin interface as well as the Ðapp The JavaScript VM exposes a node admin interface as well as the Ðapp
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console`, JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console`,
} }
) )
@ -207,7 +208,7 @@ func ephemeralConsole(ctx *cli.Context) error {
} }
// Wait for pending callbacks, but stop for Ctrl-C. // Wait for pending callbacks, but stop for Ctrl-C.
abort := make(chan os.Signal, 1) abort := make(chan os.Signal, 1)
signal.Notify(abort, os.Interrupt) signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM)
go func() { go func() {
<-abort <-abort

View file

@ -114,6 +114,7 @@ var (
utils.VMEnableDebugFlag, utils.VMEnableDebugFlag,
utils.NetworkIdFlag, utils.NetworkIdFlag,
utils.RPCCORSDomainFlag, utils.RPCCORSDomainFlag,
utils.RPCVirtualHostsFlag,
utils.EthStatsURLFlag, utils.EthStatsURLFlag,
utils.MetricsEnabledFlag, utils.MetricsEnabledFlag,
utils.FakePoWFlag, utils.FakePoWFlag,

View file

@ -156,6 +156,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.IPCDisabledFlag, utils.IPCDisabledFlag,
utils.IPCPathFlag, utils.IPCPathFlag,
utils.RPCCORSDomainFlag, utils.RPCCORSDomainFlag,
utils.RPCVirtualHostsFlag,
utils.JSpathFlag, utils.JSpathFlag,
utils.ExecFlag, utils.ExecFlag,
utils.PreloadJSFlag, utils.PreloadJSFlag,

View file

@ -1,3 +1,19 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// p2psim provides a command-line client for a simulation HTTP API. // p2psim provides a command-line client for a simulation HTTP API.
// //
// Here is an example of creating a 2 node network with the first node // Here is an example of creating a 2 node network with the first node

View file

@ -168,19 +168,18 @@ type parityChainSpec struct {
Engine struct { Engine struct {
Ethash struct { Ethash struct {
Params struct { Params struct {
MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"`
DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"` DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"`
GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"` DurationLimit *hexutil.Big `json:"durationLimit"`
DurationLimit *hexutil.Big `json:"durationLimit"` BlockReward *hexutil.Big `json:"blockReward"`
BlockReward *hexutil.Big `json:"blockReward"` HomesteadTransition uint64 `json:"homesteadTransition"`
HomesteadTransition uint64 `json:"homesteadTransition"` EIP150Transition uint64 `json:"eip150Transition"`
EIP150Transition uint64 `json:"eip150Transition"` EIP160Transition uint64 `json:"eip160Transition"`
EIP160Transition uint64 `json:"eip160Transition"` EIP161abcTransition uint64 `json:"eip161abcTransition"`
EIP161abcTransition uint64 `json:"eip161abcTransition"` EIP161dTransition uint64 `json:"eip161dTransition"`
EIP161dTransition uint64 `json:"eip161dTransition"` EIP649Reward *hexutil.Big `json:"eip649Reward"`
EIP649Reward *hexutil.Big `json:"eip649Reward"` EIP100bTransition uint64 `json:"eip100bTransition"`
EIP100bTransition uint64 `json:"eip100bTransition"` EIP649Transition uint64 `json:"eip649Transition"`
EIP649Transition uint64 `json:"eip649Transition"`
} `json:"params"` } `json:"params"`
} `json:"Ethash"` } `json:"Ethash"`
} `json:"engine"` } `json:"engine"`
@ -188,6 +187,7 @@ type parityChainSpec struct {
Params struct { Params struct {
MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"` MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"`
MinGasLimit hexutil.Uint64 `json:"minGasLimit"` MinGasLimit hexutil.Uint64 `json:"minGasLimit"`
GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"`
NetworkID hexutil.Uint64 `json:"networkID"` NetworkID hexutil.Uint64 `json:"networkID"`
MaxCodeSize uint64 `json:"maxCodeSize"` MaxCodeSize uint64 `json:"maxCodeSize"`
EIP155Transition uint64 `json:"eip155Transition"` EIP155Transition uint64 `json:"eip155Transition"`
@ -270,7 +270,6 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
} }
spec.Engine.Ethash.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty) spec.Engine.Ethash.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty)
spec.Engine.Ethash.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor) spec.Engine.Ethash.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor)
spec.Engine.Ethash.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
spec.Engine.Ethash.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit) spec.Engine.Ethash.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit)
spec.Engine.Ethash.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward) spec.Engine.Ethash.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward)
spec.Engine.Ethash.Params.HomesteadTransition = genesis.Config.HomesteadBlock.Uint64() spec.Engine.Ethash.Params.HomesteadTransition = genesis.Config.HomesteadBlock.Uint64()
@ -284,6 +283,7 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize) spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit) spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64()) spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64())
spec.Params.MaxCodeSize = params.MaxCodeSize spec.Params.MaxCodeSize = params.MaxCodeSize
spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64() spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64()

View file

@ -117,7 +117,7 @@ var dashboardContent = `
<br/> <br/>
<p>To run an archive node, download <a href="/{{.GethGenesis}}"><code>{{.GethGenesis}}</code></a> and start Geth with: <p>To run an archive node, download <a href="/{{.GethGenesis}}"><code>{{.GethGenesis}}</code></a> and start Geth with:
<pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre> <pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre>
<pre>geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=1024 --syncmode=full{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFullFlat}}</pre> <pre>geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=1024 --syncmode=full{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFlat}}</pre>
</p> </p>
<br/> <br/>
<p>You can download Geth from <a href="https://geth.ethereum.org/downloads/" target="about:blank">https://geth.ethereum.org/downloads/</a>.</p> <p>You can download Geth from <a href="https://geth.ethereum.org/downloads/" target="about:blank">https://geth.ethereum.org/downloads/</a>.</p>
@ -136,7 +136,7 @@ var dashboardContent = `
<br/> <br/>
<p>To run a full node, download <a href="/{{.GethGenesis}}"><code>{{.GethGenesis}}</code></a> and start Geth with: <p>To run a full node, download <a href="/{{.GethGenesis}}"><code>{{.GethGenesis}}</code></a> and start Geth with:
<pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre> <pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre>
<pre>geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=512{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFullFlat}}</pre> <pre>geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=512{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFlat}}</pre>
</p> </p>
<br/> <br/>
<p>You can download Geth from <a href="https://geth.ethereum.org/downloads/" target="about:blank">https://geth.ethereum.org/downloads/</a>.</p> <p>You can download Geth from <a href="https://geth.ethereum.org/downloads/" target="about:blank">https://geth.ethereum.org/downloads/</a>.</p>
@ -158,7 +158,7 @@ var dashboardContent = `
<br/> <br/>
<p>To run a light node, download <a href="/{{.GethGenesis}}"><code>{{.GethGenesis}}</code></a> and start Geth with: <p>To run a light node, download <a href="/{{.GethGenesis}}"><code>{{.GethGenesis}}</code></a> and start Geth with:
<pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre> <pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre>
<pre>geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --syncmode=light{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesLightFlat}}</pre> <pre>geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --syncmode=light{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFlat}}</pre>
</p> </p>
<br/> <br/>
<p>You can download Geth from <a href="https://geth.ethereum.org/downloads/" target="about:blank">https://geth.ethereum.org/downloads/</a>.</p> <p>You can download Geth from <a href="https://geth.ethereum.org/downloads/" target="about:blank">https://geth.ethereum.org/downloads/</a>.</p>
@ -177,7 +177,7 @@ var dashboardContent = `
<br/> <br/>
<p>To run an embedded node, download <a href="/{{.GethGenesis}}"><code>{{.GethGenesis}}</code></a> and start Geth with: <p>To run an embedded node, download <a href="/{{.GethGenesis}}"><code>{{.GethGenesis}}</code></a> and start Geth with:
<pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre> <pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre>
<pre>geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=16 --ethash.cachesinmem=1 --syncmode=light{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesLightFlat}}</pre> <pre>geth --networkid={{.NetworkID}} --datadir=$HOME/.{{.Network}} --cache=16 --ethash.cachesinmem=1 --syncmode=light{{if .Ethstats}} --ethstats='{{.Ethstats}}'{{end}} --bootnodes={{.BootnodesFlat}}</pre>
</p> </p>
<br/> <br/>
<p>You can download Geth from <a href="https://geth.ethereum.org/downloads/" target="about:blank">https://geth.ethereum.org/downloads/</a>.</p> <p>You can download Geth from <a href="https://geth.ethereum.org/downloads/" target="about:blank">https://geth.ethereum.org/downloads/</a>.</p>
@ -208,7 +208,7 @@ var dashboardContent = `
<pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre> <pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre>
</p> </p>
<p>With your local chain initialized, you can start the Ethereum Wallet: <p>With your local chain initialized, you can start the Ethereum Wallet:
<pre>ethereumwallet --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFullFlat}}</pre> <pre>ethereumwallet --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFlat}}</pre>
<p> <p>
<br/> <br/>
<p>You can download the Ethereum Wallet from <a href="https://github.com/ethereum/mist/releases" target="about:blank">https://github.com/ethereum/mist/releases</a>.</p> <p>You can download the Ethereum Wallet from <a href="https://github.com/ethereum/mist/releases" target="about:blank">https://github.com/ethereum/mist/releases</a>.</p>
@ -229,7 +229,7 @@ var dashboardContent = `
<pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre> <pre>geth --datadir=$HOME/.{{.Network}} init {{.GethGenesis}}</pre>
</p> </p>
<p>With your local chain initialized, you can start Mist: <p>With your local chain initialized, you can start Mist:
<pre>mist --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFullFlat}}</pre> <pre>mist --rpc $HOME/.{{.Network}}/geth.ipc --node-networkid={{.NetworkID}} --node-datadir=$HOME/.{{.Network}}{{if .Ethstats}} --node-ethstats='{{.Ethstats}}'{{end}} --node-bootnodes={{.BootnodesFlat}}</pre>
<p> <p>
<br/> <br/>
<p>You can download the Mist browser from <a href="https://github.com/ethereum/mist/releases" target="about:blank">https://github.com/ethereum/mist/releases</a>.</p> <p>You can download the Mist browser from <a href="https://github.com/ethereum/mist/releases" target="about:blank">https://github.com/ethereum/mist/releases</a>.</p>
@ -261,7 +261,7 @@ var dashboardContent = `
<p>Inside your Java code you can now import the geth archive and connect to Ethereum: <p>Inside your Java code you can now import the geth archive and connect to Ethereum:
<pre>import org.ethereum.geth.*;</pre> <pre>import org.ethereum.geth.*;</pre>
<pre> <pre>
Enodes bootnodes = new Enodes();{{range .BootnodesLight}} Enodes bootnodes = new Enodes();{{range .Bootnodes}}
bootnodes.append(new Enode("{{.}}"));{{end}} bootnodes.append(new Enode("{{.}}"));{{end}}
NodeConfig config = new NodeConfig(); NodeConfig config = new NodeConfig();
@ -294,7 +294,7 @@ node.start();
<pre> <pre>
var error: NSError? var error: NSError?
let bootnodes = GethNewEnodesEmpty(){{range .BootnodesLight}} let bootnodes = GethNewEnodesEmpty(){{range .Bootnodes}}
bootnodes?.append(GethNewEnode("{{.}}", &error)){{end}} bootnodes?.append(GethNewEnode("{{.}}", &error)){{end}}
let config = GethNewNodeConfig() let config = GethNewNodeConfig()
@ -595,44 +595,43 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da
statsLogin = "" statsLogin = ""
} }
indexfile := new(bytes.Buffer) indexfile := new(bytes.Buffer)
bootCpp := make([]string, len(conf.bootFull)) bootCpp := make([]string, len(conf.bootnodes))
for i, boot := range conf.bootFull { for i, boot := range conf.bootnodes {
bootCpp[i] = "required:" + strings.TrimPrefix(boot, "enode://") bootCpp[i] = "required:" + strings.TrimPrefix(boot, "enode://")
} }
bootHarmony := make([]string, len(conf.bootFull)) bootHarmony := make([]string, len(conf.bootnodes))
for i, boot := range conf.bootFull { for i, boot := range conf.bootnodes {
bootHarmony[i] = fmt.Sprintf("-Dpeer.active.%d.url=%s", i, boot) bootHarmony[i] = fmt.Sprintf("-Dpeer.active.%d.url=%s", i, boot)
} }
bootPython := make([]string, len(conf.bootFull)) bootPython := make([]string, len(conf.bootnodes))
for i, boot := range conf.bootFull { for i, boot := range conf.bootnodes {
bootPython[i] = "'" + boot + "'" bootPython[i] = "'" + boot + "'"
} }
template.Must(template.New("").Parse(dashboardContent)).Execute(indexfile, map[string]interface{}{ template.Must(template.New("").Parse(dashboardContent)).Execute(indexfile, map[string]interface{}{
"Network": network, "Network": network,
"NetworkID": conf.Genesis.Config.ChainId, "NetworkID": conf.Genesis.Config.ChainId,
"NetworkTitle": strings.Title(network), "NetworkTitle": strings.Title(network),
"EthstatsPage": config.ethstats, "EthstatsPage": config.ethstats,
"ExplorerPage": config.explorer, "ExplorerPage": config.explorer,
"WalletPage": config.wallet, "WalletPage": config.wallet,
"FaucetPage": config.faucet, "FaucetPage": config.faucet,
"GethGenesis": network + ".json", "GethGenesis": network + ".json",
"BootnodesFull": conf.bootFull, "Bootnodes": conf.bootnodes,
"BootnodesLight": conf.bootLight, "BootnodesFlat": strings.Join(conf.bootnodes, ","),
"BootnodesFullFlat": strings.Join(conf.bootFull, ","), "Ethstats": statsLogin,
"BootnodesLightFlat": strings.Join(conf.bootLight, ","), "Ethash": conf.Genesis.Config.Ethash != nil,
"Ethstats": statsLogin, "CppGenesis": network + "-cpp.json",
"Ethash": conf.Genesis.Config.Ethash != nil, "CppBootnodes": strings.Join(bootCpp, " "),
"CppGenesis": network + "-cpp.json", "HarmonyGenesis": network + "-harmony.json",
"CppBootnodes": strings.Join(bootCpp, " "), "HarmonyBootnodes": strings.Join(bootHarmony, " "),
"HarmonyGenesis": network + "-harmony.json", "ParityGenesis": network + "-parity.json",
"HarmonyBootnodes": strings.Join(bootHarmony, " "), "PythonGenesis": network + "-python.json",
"ParityGenesis": network + "-parity.json", "PythonBootnodes": strings.Join(bootPython, ","),
"PythonGenesis": network + "-python.json", "Homestead": conf.Genesis.Config.HomesteadBlock,
"PythonBootnodes": strings.Join(bootPython, ","), "Tangerine": conf.Genesis.Config.EIP150Block,
"Homestead": conf.Genesis.Config.HomesteadBlock, "Spurious": conf.Genesis.Config.EIP155Block,
"Tangerine": conf.Genesis.Config.EIP150Block, "Byzantium": conf.Genesis.Config.ByzantiumBlock,
"Spurious": conf.Genesis.Config.EIP155Block, "Constantinople": conf.Genesis.Config.ConstantinopleBlock,
"Byzantium": conf.Genesis.Config.ByzantiumBlock,
}) })
files[filepath.Join(workdir, "index.html")] = indexfile.Bytes() files[filepath.Join(workdir, "index.html")] = indexfile.Bytes()
@ -651,7 +650,7 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da
harmonySpecJSON, _ := conf.Genesis.MarshalJSON() harmonySpecJSON, _ := conf.Genesis.MarshalJSON()
files[filepath.Join(workdir, network+"-harmony.json")] = harmonySpecJSON files[filepath.Join(workdir, network+"-harmony.json")] = harmonySpecJSON
paritySpec, err := newParityChainSpec(network, conf.Genesis, conf.bootFull) paritySpec, err := newParityChainSpec(network, conf.Genesis, conf.bootnodes)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -93,7 +93,7 @@ func deployFaucet(client *sshClient, network string, bootnodes []string, config
"NetworkID": config.node.network, "NetworkID": config.node.network,
"Bootnodes": strings.Join(bootnodes, ","), "Bootnodes": strings.Join(bootnodes, ","),
"Ethstats": config.node.ethstats, "Ethstats": config.node.ethstats,
"EthPort": config.node.portFull, "EthPort": config.node.port,
"CaptchaToken": config.captchaToken, "CaptchaToken": config.captchaToken,
"CaptchaSecret": config.captchaSecret, "CaptchaSecret": config.captchaSecret,
"FaucetName": strings.Title(network), "FaucetName": strings.Title(network),
@ -110,7 +110,7 @@ func deployFaucet(client *sshClient, network string, bootnodes []string, config
"Datadir": config.node.datadir, "Datadir": config.node.datadir,
"VHost": config.host, "VHost": config.host,
"ApiPort": config.port, "ApiPort": config.port,
"EthPort": config.node.portFull, "EthPort": config.node.port,
"EthName": config.node.ethstats[:strings.Index(config.node.ethstats, ":")], "EthName": config.node.ethstats[:strings.Index(config.node.ethstats, ":")],
"CaptchaToken": config.captchaToken, "CaptchaToken": config.captchaToken,
"CaptchaSecret": config.captchaSecret, "CaptchaSecret": config.captchaSecret,
@ -158,7 +158,7 @@ func (info *faucetInfos) Report() map[string]string {
report := map[string]string{ report := map[string]string{
"Website address": info.host, "Website address": info.host,
"Website listener port": strconv.Itoa(info.port), "Website listener port": strconv.Itoa(info.port),
"Ethereum listener port": strconv.Itoa(info.node.portFull), "Ethereum listener port": strconv.Itoa(info.node.port),
"Funding amount (base tier)": fmt.Sprintf("%d Ethers", info.amount), "Funding amount (base tier)": fmt.Sprintf("%d Ethers", info.amount),
"Funding cooldown (base tier)": fmt.Sprintf("%d mins", info.minutes), "Funding cooldown (base tier)": fmt.Sprintf("%d mins", info.minutes),
"Funding tiers": strconv.Itoa(info.tiers), "Funding tiers": strconv.Itoa(info.tiers),
@ -228,7 +228,7 @@ func checkFaucet(client *sshClient, network string) (*faucetInfos, error) {
return &faucetInfos{ return &faucetInfos{
node: &nodeInfos{ node: &nodeInfos{
datadir: infos.volumes["/root/.faucet"], datadir: infos.volumes["/root/.faucet"],
portFull: infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"], port: infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"],
ethstats: infos.envvars["ETH_NAME"], ethstats: infos.envvars["ETH_NAME"],
keyJSON: keyJSON, keyJSON: keyJSON,
keyPass: keyPass, keyPass: keyPass,

View file

@ -42,7 +42,7 @@ ADD genesis.json /genesis.json
RUN \ RUN \
echo 'geth --cache 512 init /genesis.json' > geth.sh && \{{if .Unlock}} echo 'geth --cache 512 init /genesis.json' > geth.sh && \{{if .Unlock}}
echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}} echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}}
echo $'geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .BootV4}}--bootnodesv4 {{.BootV4}}{{end}} {{if .BootV5}}--bootnodesv5 {{.BootV5}}{{end}} {{if .Etherbase}}--etherbase {{.Etherbase}} --mine --minerthreads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --targetgaslimit {{.GasTarget}} --gasprice {{.GasPrice}}' >> geth.sh echo $'geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--etherbase {{.Etherbase}} --mine --minerthreads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --targetgaslimit {{.GasTarget}} --gasprice {{.GasPrice}}' >> geth.sh
ENTRYPOINT ["/bin/sh", "geth.sh"] ENTRYPOINT ["/bin/sh", "geth.sh"]
` `
@ -56,15 +56,13 @@ services:
build: . build: .
image: {{.Network}}/{{.Type}} image: {{.Network}}/{{.Type}}
ports: ports:
- "{{.FullPort}}:{{.FullPort}}" - "{{.Port}}:{{.Port}}"
- "{{.FullPort}}:{{.FullPort}}/udp"{{if .Light}} - "{{.Port}}:{{.Port}}/udp"
- "{{.LightPort}}:{{.LightPort}}/udp"{{end}}
volumes: volumes:
- {{.Datadir}}:/root/.ethereum{{if .Ethashdir}} - {{.Datadir}}:/root/.ethereum{{if .Ethashdir}}
- {{.Ethashdir}}:/root/.ethash{{end}} - {{.Ethashdir}}:/root/.ethash{{end}}
environment: environment:
- FULL_PORT={{.FullPort}}/tcp - PORT={{.Port}}/tcp
- LIGHT_PORT={{.LightPort}}/udp
- TOTAL_PEERS={{.TotalPeers}} - TOTAL_PEERS={{.TotalPeers}}
- LIGHT_PEERS={{.LightPeers}} - LIGHT_PEERS={{.LightPeers}}
- STATS_NAME={{.Ethstats}} - STATS_NAME={{.Ethstats}}
@ -82,12 +80,11 @@ services:
// deployNode deploys a new Ethereum node container to a remote machine via SSH, // deployNode deploys a new Ethereum node container to a remote machine via SSH,
// docker and docker-compose. If an instance with the specified network name // docker and docker-compose. If an instance with the specified network name
// already exists there, it will be overwritten! // already exists there, it will be overwritten!
func deployNode(client *sshClient, network string, bootv4, bootv5 []string, config *nodeInfos, nocache bool) ([]byte, error) { func deployNode(client *sshClient, network string, bootnodes []string, config *nodeInfos, nocache bool) ([]byte, error) {
kind := "sealnode" kind := "sealnode"
if config.keyJSON == "" && config.etherbase == "" { if config.keyJSON == "" && config.etherbase == "" {
kind = "bootnode" kind = "bootnode"
bootv4 = make([]string, 0) bootnodes = make([]string, 0)
bootv5 = make([]string, 0)
} }
// Generate the content to upload to the server // Generate the content to upload to the server
workdir := fmt.Sprintf("%d", rand.Int63()) workdir := fmt.Sprintf("%d", rand.Int63())
@ -100,11 +97,10 @@ func deployNode(client *sshClient, network string, bootv4, bootv5 []string, conf
dockerfile := new(bytes.Buffer) dockerfile := new(bytes.Buffer)
template.Must(template.New("").Parse(nodeDockerfile)).Execute(dockerfile, map[string]interface{}{ template.Must(template.New("").Parse(nodeDockerfile)).Execute(dockerfile, map[string]interface{}{
"NetworkID": config.network, "NetworkID": config.network,
"Port": config.portFull, "Port": config.port,
"Peers": config.peersTotal, "Peers": config.peersTotal,
"LightFlag": lightFlag, "LightFlag": lightFlag,
"BootV4": strings.Join(bootv4, ","), "Bootnodes": strings.Join(bootnodes, ","),
"BootV5": strings.Join(bootv5, ","),
"Ethstats": config.ethstats, "Ethstats": config.ethstats,
"Etherbase": config.etherbase, "Etherbase": config.etherbase,
"GasTarget": uint64(1000000 * config.gasTarget), "GasTarget": uint64(1000000 * config.gasTarget),
@ -119,10 +115,9 @@ func deployNode(client *sshClient, network string, bootv4, bootv5 []string, conf
"Datadir": config.datadir, "Datadir": config.datadir,
"Ethashdir": config.ethashdir, "Ethashdir": config.ethashdir,
"Network": network, "Network": network,
"FullPort": config.portFull, "Port": config.port,
"TotalPeers": config.peersTotal, "TotalPeers": config.peersTotal,
"Light": config.peersLight > 0, "Light": config.peersLight > 0,
"LightPort": config.portFull + 1,
"LightPeers": config.peersLight, "LightPeers": config.peersLight,
"Ethstats": config.ethstats[:strings.Index(config.ethstats, ":")], "Ethstats": config.ethstats[:strings.Index(config.ethstats, ":")],
"Etherbase": config.etherbase, "Etherbase": config.etherbase,
@ -157,10 +152,8 @@ type nodeInfos struct {
datadir string datadir string
ethashdir string ethashdir string
ethstats string ethstats string
portFull int port int
portLight int enode string
enodeFull string
enodeLight string
peersTotal int peersTotal int
peersLight int peersLight int
etherbase string etherbase string
@ -174,15 +167,11 @@ type nodeInfos struct {
// most - but not all - fields for reporting to the user. // most - but not all - fields for reporting to the user.
func (info *nodeInfos) Report() map[string]string { func (info *nodeInfos) Report() map[string]string {
report := map[string]string{ report := map[string]string{
"Data directory": info.datadir, "Data directory": info.datadir,
"Listener port (full nodes)": strconv.Itoa(info.portFull), "Listener port": strconv.Itoa(info.port),
"Peer count (all total)": strconv.Itoa(info.peersTotal), "Peer count (all total)": strconv.Itoa(info.peersTotal),
"Peer count (light nodes)": strconv.Itoa(info.peersLight), "Peer count (light nodes)": strconv.Itoa(info.peersLight),
"Ethstats username": info.ethstats, "Ethstats username": info.ethstats,
}
if info.peersLight > 0 {
// Light server enabled
report["Listener port (light nodes)"] = strconv.Itoa(info.portLight)
} }
if info.gasTarget > 0 { if info.gasTarget > 0 {
// Miner or signer node // Miner or signer node
@ -250,7 +239,7 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
keyPass = string(bytes.TrimSpace(out)) keyPass = string(bytes.TrimSpace(out))
} }
// Run a sanity check to see if the devp2p is reachable // Run a sanity check to see if the devp2p is reachable
port := infos.portmap[infos.envvars["FULL_PORT"]] port := infos.portmap[infos.envvars["PORT"]]
if err = checkPort(client.server, port); err != nil { if err = checkPort(client.server, port); err != nil {
log.Warn(fmt.Sprintf("%s devp2p port seems unreachable", strings.Title(kind)), "server", client.server, "port", port, "err", err) log.Warn(fmt.Sprintf("%s devp2p port seems unreachable", strings.Title(kind)), "server", client.server, "port", port, "err", err)
} }
@ -259,8 +248,7 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
genesis: genesis, genesis: genesis,
datadir: infos.volumes["/root/.ethereum"], datadir: infos.volumes["/root/.ethereum"],
ethashdir: infos.volumes["/root/.ethash"], ethashdir: infos.volumes["/root/.ethash"],
portFull: infos.portmap[infos.envvars["FULL_PORT"]], port: port,
portLight: infos.portmap[infos.envvars["LIGHT_PORT"]],
peersTotal: totalPeers, peersTotal: totalPeers,
peersLight: lightPeers, peersLight: lightPeers,
ethstats: infos.envvars["STATS_NAME"], ethstats: infos.envvars["STATS_NAME"],
@ -270,9 +258,7 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
gasTarget: gasTarget, gasTarget: gasTarget,
gasPrice: gasPrice, gasPrice: gasPrice,
} }
stats.enodeFull = fmt.Sprintf("enode://%s@%s:%d", id, client.address, stats.portFull) stats.enode = fmt.Sprintf("enode://%s@%s:%d", id, client.address, stats.port)
if stats.portLight != 0 {
stats.enodeLight = fmt.Sprintf("enode://%s@%s:%d?discport=%d", id, client.address, stats.portFull, stats.portLight)
}
return stats, nil return stats, nil
} }

View file

@ -40,8 +40,7 @@ import (
// between sessions. // between sessions.
type config struct { type config struct {
path string // File containing the configuration values path string // File containing the configuration values
bootFull []string // Bootnodes to always connect to by full nodes bootnodes []string // Bootnodes to always connect to by all nodes
bootLight []string // Bootnodes to always connect to by light nodes
ethstats string // Ethstats settings to cache for node deploys ethstats string // Ethstats settings to cache for node deploys
Genesis *core.Genesis `json:"genesis,omitempty"` // Genesis block to cache for node deploys Genesis *core.Genesis `json:"genesis,omitempty"` // Genesis block to cache for node deploys

View file

@ -55,7 +55,7 @@ func (w *wizard) deployExplorer() {
} }
existed := err == nil existed := err == nil
chainspec, err := newParityChainSpec(w.network, w.conf.Genesis, w.conf.bootFull) chainspec, err := newParityChainSpec(w.network, w.conf.Genesis, w.conf.bootnodes)
if err != nil { if err != nil {
log.Error("Failed to create chain spec for explorer", "err", err) log.Error("Failed to create chain spec for explorer", "err", err)
return return

View file

@ -38,7 +38,7 @@ func (w *wizard) deployFaucet() {
infos, err := checkFaucet(client, w.network) infos, err := checkFaucet(client, w.network)
if err != nil { if err != nil {
infos = &faucetInfos{ infos = &faucetInfos{
node: &nodeInfos{portFull: 30303, peersTotal: 25}, node: &nodeInfos{port: 30303, peersTotal: 25},
port: 80, port: 80,
host: client.server, host: client.server,
amount: 1, amount: 1,
@ -113,8 +113,8 @@ func (w *wizard) deployFaucet() {
} }
// Figure out which port to listen on // Figure out which port to listen on
fmt.Println() fmt.Println()
fmt.Printf("Which TCP/UDP port should the light client listen on? (default = %d)\n", infos.node.portFull) fmt.Printf("Which TCP/UDP port should the light client listen on? (default = %d)\n", infos.node.port)
infos.node.portFull = w.readDefaultInt(infos.node.portFull) infos.node.port = w.readDefaultInt(infos.node.port)
// Set a proper name to report on the stats page // Set a proper name to report on the stats page
fmt.Println() fmt.Println()
@ -168,7 +168,7 @@ func (w *wizard) deployFaucet() {
fmt.Printf("Should the faucet be built from scratch (y/n)? (default = no)\n") fmt.Printf("Should the faucet be built from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n" nocache = w.readDefaultString("n") != "n"
} }
if out, err := deployFaucet(client, w.network, w.conf.bootLight, infos, nocache); err != nil { if out, err := deployFaucet(client, w.network, w.conf.bootnodes, infos, nocache); err != nil {
log.Error("Failed to deploy faucet container", "err", err) log.Error("Failed to deploy faucet container", "err", err)
if len(out) > 0 { if len(out) > 0 {
fmt.Printf("%s\n", out) fmt.Printf("%s\n", out)

View file

@ -59,15 +59,16 @@ func (w *wizard) run() {
fmt.Println() fmt.Println()
// Make sure we have a good network name to work with fmt.Println() // Make sure we have a good network name to work with fmt.Println()
// Docker accepts hyphens in image names, but doesn't like it for container names
if w.network == "" { if w.network == "" {
fmt.Println("Please specify a network name to administer (no spaces, please)") fmt.Println("Please specify a network name to administer (no spaces or hyphens, please)")
for { for {
w.network = w.readString() w.network = w.readString()
if !strings.Contains(w.network, " ") { if !strings.Contains(w.network, " ") && !strings.Contains(w.network, "-") {
fmt.Printf("\nSweet, you can set this via --network=%s next time!\n\n", w.network) fmt.Printf("\nSweet, you can set this via --network=%s next time!\n\n", w.network)
break break
} }
log.Error("I also like to live dangerously, still no spaces") log.Error("I also like to live dangerously, still no spaces or hyphens")
} }
} }
log.Info("Administering Ethereum network", "name", w.network) log.Info("Administering Ethereum network", "name", w.network)

View file

@ -37,8 +37,7 @@ func (w *wizard) networkStats() {
} }
// Clear out some previous configs to refill from current scan // Clear out some previous configs to refill from current scan
w.conf.ethstats = "" w.conf.ethstats = ""
w.conf.bootFull = w.conf.bootFull[:0] w.conf.bootnodes = w.conf.bootnodes[:0]
w.conf.bootLight = w.conf.bootLight[:0]
// Iterate over all the specified hosts and check their status // Iterate over all the specified hosts and check their status
var pend sync.WaitGroup var pend sync.WaitGroup
@ -76,8 +75,7 @@ func (w *wizard) gatherStats(server string, pubkey []byte, client *sshClient) *s
var ( var (
genesis string genesis string
ethstats string ethstats string
bootFull []string bootnodes []string
bootLight []string
) )
// Ensure a valid SSH connection to the remote server // Ensure a valid SSH connection to the remote server
logger := log.New("server", server) logger := log.New("server", server)
@ -123,10 +121,7 @@ func (w *wizard) gatherStats(server string, pubkey []byte, client *sshClient) *s
stat.services["bootnode"] = infos.Report() stat.services["bootnode"] = infos.Report()
genesis = string(infos.genesis) genesis = string(infos.genesis)
bootFull = append(bootFull, infos.enodeFull) bootnodes = append(bootnodes, infos.enode)
if infos.enodeLight != "" {
bootLight = append(bootLight, infos.enodeLight)
}
} }
logger.Debug("Checking for sealnode availability") logger.Debug("Checking for sealnode availability")
if infos, err := checkNode(client, w.network, false); err != nil { if infos, err := checkNode(client, w.network, false); err != nil {
@ -184,8 +179,7 @@ func (w *wizard) gatherStats(server string, pubkey []byte, client *sshClient) *s
if ethstats != "" { if ethstats != "" {
w.conf.ethstats = ethstats w.conf.ethstats = ethstats
} }
w.conf.bootFull = append(w.conf.bootFull, bootFull...) w.conf.bootnodes = append(w.conf.bootnodes, bootnodes...)
w.conf.bootLight = append(w.conf.bootLight, bootLight...)
return stat return stat
} }

View file

@ -48,9 +48,9 @@ func (w *wizard) deployNode(boot bool) {
infos, err := checkNode(client, w.network, boot) infos, err := checkNode(client, w.network, boot)
if err != nil { if err != nil {
if boot { if boot {
infos = &nodeInfos{portFull: 30303, peersTotal: 512, peersLight: 256} infos = &nodeInfos{port: 30303, peersTotal: 512, peersLight: 256}
} else { } else {
infos = &nodeInfos{portFull: 30303, peersTotal: 50, peersLight: 0, gasTarget: 4.7, gasPrice: 18} infos = &nodeInfos{port: 30303, peersTotal: 50, peersLight: 0, gasTarget: 4.7, gasPrice: 18}
} }
} }
existed := err == nil existed := err == nil
@ -79,8 +79,8 @@ func (w *wizard) deployNode(boot bool) {
} }
// Figure out which port to listen on // Figure out which port to listen on
fmt.Println() fmt.Println()
fmt.Printf("Which TCP/UDP port to listen on? (default = %d)\n", infos.portFull) fmt.Printf("Which TCP/UDP port to listen on? (default = %d)\n", infos.port)
infos.portFull = w.readDefaultInt(infos.portFull) infos.port = w.readDefaultInt(infos.port)
// Figure out how many peers to allow (different based on node type) // Figure out how many peers to allow (different based on node type)
fmt.Println() fmt.Println()
@ -163,7 +163,7 @@ func (w *wizard) deployNode(boot bool) {
fmt.Printf("Should the node be built from scratch (y/n)? (default = no)\n") fmt.Printf("Should the node be built from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n" nocache = w.readDefaultString("n") != "n"
} }
if out, err := deployNode(client, w.network, w.conf.bootFull, w.conf.bootLight, infos, nocache); err != nil { if out, err := deployNode(client, w.network, w.conf.bootnodes, infos, nocache); err != nil {
log.Error("Failed to deploy Ethereum node container", "err", err) log.Error("Failed to deploy Ethereum node container", "err", err)
if len(out) > 0 { if len(out) > 0 {
fmt.Printf("%s\n", out) fmt.Printf("%s\n", out)

View file

@ -98,7 +98,7 @@ func (w *wizard) deployWallet() {
fmt.Printf("Should the wallet be built from scratch (y/n)? (default = no)\n") fmt.Printf("Should the wallet be built from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n" nocache = w.readDefaultString("n") != "n"
} }
if out, err := deployWallet(client, w.network, w.conf.bootFull, infos, nocache); err != nil { if out, err := deployWallet(client, w.network, w.conf.bootnodes, infos, nocache); err != nil {
log.Error("Failed to deploy wallet container", "err", err) log.Error("Failed to deploy wallet container", "err", err)
if len(out) > 0 { if len(out) > 0 {
fmt.Printf("%s\n", out) fmt.Printf("%s\n", out)

View file

@ -23,6 +23,7 @@ import (
"os" "os"
"reflect" "reflect"
"strconv" "strconv"
"strings"
"unicode" "unicode"
cli "gopkg.in/urfave/cli.v1" cli "gopkg.in/urfave/cli.v1"
@ -97,10 +98,15 @@ func buildConfig(ctx *cli.Context) (config *bzzapi.Config, err error) {
config = bzzapi.NewDefaultConfig() config = bzzapi.NewDefaultConfig()
//first load settings from config file (if provided) //first load settings from config file (if provided)
config, err = configFileOverride(config, ctx) config, err = configFileOverride(config, ctx)
if err != nil {
return nil, err
}
//override settings provided by environment variables //override settings provided by environment variables
config = envVarsOverride(config) config = envVarsOverride(config)
//override settings provided by command line //override settings provided by command line
config = cmdLineOverride(config, ctx) config = cmdLineOverride(config, ctx)
//validate configuration parameters
err = validateConfig(config)
return return
} }
@ -194,12 +200,16 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con
utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API) utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API)
} }
//EnsApi can be set to "", so can't check for empty string, as it is allowed!
if ctx.GlobalIsSet(EnsAPIFlag.Name) { if ctx.GlobalIsSet(EnsAPIFlag.Name) {
currentConfig.EnsApi = ctx.GlobalString(EnsAPIFlag.Name) ensAPIs := ctx.GlobalStringSlice(EnsAPIFlag.Name)
// preserve backward compatibility to disable ENS with --ens-api=""
if len(ensAPIs) == 1 && ensAPIs[0] == "" {
ensAPIs = nil
}
currentConfig.EnsAPIs = ensAPIs
} }
if ensaddr := ctx.GlobalString(EnsAddrFlag.Name); ensaddr != "" { if ensaddr := ctx.GlobalString(DeprecatedEnsAddrFlag.Name); ensaddr != "" {
currentConfig.EnsRoot = common.HexToAddress(ensaddr) currentConfig.EnsRoot = common.HexToAddress(ensaddr)
} }
@ -266,9 +276,8 @@ func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) {
utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API) utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API)
} }
//EnsApi can be set to "", so can't check for empty string, as it is allowed if ensapi := os.Getenv(SWARM_ENV_ENS_API); ensapi != "" {
if ensapi, exists := os.LookupEnv(SWARM_ENV_ENS_API); exists { currentConfig.EnsAPIs = strings.Split(ensapi, ",")
currentConfig.EnsApi = ensapi
} }
if ensaddr := os.Getenv(SWARM_ENV_ENS_ADDR); ensaddr != "" { if ensaddr := os.Getenv(SWARM_ENV_ENS_ADDR); ensaddr != "" {
@ -309,6 +318,43 @@ func checkDeprecated(ctx *cli.Context) {
if ctx.GlobalString(DeprecatedEthAPIFlag.Name) != "" { if ctx.GlobalString(DeprecatedEthAPIFlag.Name) != "" {
utils.Fatalf("--ethapi is no longer a valid command line flag, please use --ens-api and/or --swap-api.") utils.Fatalf("--ethapi is no longer a valid command line flag, please use --ens-api and/or --swap-api.")
} }
// warn if --ens-api flag is set
if ctx.GlobalString(DeprecatedEnsAddrFlag.Name) != "" {
log.Warn("--ens-addr is no longer a valid command line flag, please use --ens-api to specify contract address.")
}
}
//validate configuration parameters
func validateConfig(cfg *bzzapi.Config) (err error) {
for _, ensAPI := range cfg.EnsAPIs {
if ensAPI != "" {
if err := validateEnsAPIs(ensAPI); err != nil {
return fmt.Errorf("invalid format [tld:][contract-addr@]url for ENS API endpoint configuration %q: %v", ensAPI, err)
}
}
}
return nil
}
//validate EnsAPIs configuration parameter
func validateEnsAPIs(s string) (err error) {
// missing contract address
if strings.HasPrefix(s, "@") {
return errors.New("missing contract address")
}
// missing url
if strings.HasSuffix(s, "@") {
return errors.New("missing url")
}
// missing tld
if strings.HasPrefix(s, ":") {
return errors.New("missing tld")
}
// missing url
if strings.HasSuffix(s, ":") {
return errors.New("missing url")
}
return nil
} }
//print a Config as string //print a Config as string

View file

@ -457,3 +457,98 @@ func TestCmdLineOverridesFile(t *testing.T) {
node.Shutdown() node.Shutdown()
} }
func TestValidateConfig(t *testing.T) {
for _, c := range []struct {
cfg *api.Config
err string
}{
{
cfg: &api.Config{EnsAPIs: []string{
"/data/testnet/geth.ipc",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"http://127.0.0.1:1234",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"ws://127.0.0.1:1234",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"test:/data/testnet/geth.ipc",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"test:ws://127.0.0.1:1234",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"eth:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"eth:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:12344",
}},
},
{
cfg: &api.Config{EnsAPIs: []string{
"eth:",
}},
err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"eth:\": missing url",
},
{
cfg: &api.Config{EnsAPIs: []string{
"314159265dD8dbb310642f98f50C066173C1259b@",
}},
err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"314159265dD8dbb310642f98f50C066173C1259b@\": missing url",
},
{
cfg: &api.Config{EnsAPIs: []string{
":314159265dD8dbb310642f98f50C066173C1259",
}},
err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \":314159265dD8dbb310642f98f50C066173C1259\": missing tld",
},
{
cfg: &api.Config{EnsAPIs: []string{
"@/data/testnet/geth.ipc",
}},
err: "invalid format [tld:][contract-addr@]url for ENS API endpoint configuration \"@/data/testnet/geth.ipc\": missing contract address",
},
} {
err := validateConfig(c.cfg)
if c.err != "" && err.Error() != c.err {
t.Errorf("expected error %q, got %q", c.err, err)
}
if c.err == "" && err != nil {
t.Errorf("unexpected error %q", err)
}
}
}

View file

@ -17,11 +17,9 @@
package main package main
import ( import (
"context"
"crypto/ecdsa" "crypto/ecdsa"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big"
"os" "os"
"os/signal" "os/signal"
"runtime" "runtime"
@ -29,14 +27,12 @@ import (
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
"time"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/console"
"github.com/ethereum/go-ethereum/contracts/ens"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/debug"
@ -45,9 +41,9 @@ import (
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/swarm" "github.com/ethereum/go-ethereum/swarm"
bzzapi "github.com/ethereum/go-ethereum/swarm/api" bzzapi "github.com/ethereum/go-ethereum/swarm/api"
swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics"
"gopkg.in/urfave/cli.v1" "gopkg.in/urfave/cli.v1"
) )
@ -110,16 +106,11 @@ var (
Usage: "Swarm Syncing enabled (default true)", Usage: "Swarm Syncing enabled (default true)",
EnvVar: SWARM_ENV_SYNC_ENABLE, EnvVar: SWARM_ENV_SYNC_ENABLE,
} }
EnsAPIFlag = cli.StringFlag{ EnsAPIFlag = cli.StringSliceFlag{
Name: "ens-api", Name: "ens-api",
Usage: "URL of the Ethereum API provider to use for ENS record lookups", Usage: "ENS API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url",
EnvVar: SWARM_ENV_ENS_API, EnvVar: SWARM_ENV_ENS_API,
} }
EnsAddrFlag = cli.StringFlag{
Name: "ens-addr",
Usage: "ENS contract address (default is detected as testnet or mainnet using --ens-api)",
EnvVar: SWARM_ENV_ENS_ADDR,
}
SwarmApiFlag = cli.StringFlag{ SwarmApiFlag = cli.StringFlag{
Name: "bzzapi", Name: "bzzapi",
Usage: "Swarm HTTP endpoint", Usage: "Swarm HTTP endpoint",
@ -156,6 +147,10 @@ var (
Name: "ethapi", Name: "ethapi",
Usage: "DEPRECATED: please use --ens-api and --swap-api", Usage: "DEPRECATED: please use --ens-api and --swap-api",
} }
DeprecatedEnsAddrFlag = cli.StringFlag{
Name: "ens-addr",
Usage: "DEPRECATED: ENS contract address, please use --ens-api with contract address according to its format",
}
) )
//declare a few constant error messages, useful for later error check comparisons in test //declare a few constant error messages, useful for later error check comparisons in test
@ -343,7 +338,6 @@ DEPRECATED: use 'swarm db clean'.
// bzzd-specific flags // bzzd-specific flags
CorsStringFlag, CorsStringFlag,
EnsAPIFlag, EnsAPIFlag,
EnsAddrFlag,
SwarmTomlConfigPathFlag, SwarmTomlConfigPathFlag,
SwarmConfigPathFlag, SwarmConfigPathFlag,
SwarmSwapEnabledFlag, SwarmSwapEnabledFlag,
@ -363,11 +357,17 @@ DEPRECATED: use 'swarm db clean'.
SwarmUploadMimeType, SwarmUploadMimeType,
//deprecated flags //deprecated flags
DeprecatedEthAPIFlag, DeprecatedEthAPIFlag,
DeprecatedEnsAddrFlag,
} }
app.Flags = append(app.Flags, debug.Flags...) app.Flags = append(app.Flags, debug.Flags...)
app.Flags = append(app.Flags, swarmmetrics.Flags...)
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
return debug.Setup(ctx) if err := debug.Setup(ctx); err != nil {
return err
}
swarmmetrics.Setup(ctx)
return nil
} }
app.After = func(ctx *cli.Context) error { app.After = func(ctx *cli.Context) error {
debug.Exit() debug.Exit()
@ -448,38 +448,6 @@ func bzzd(ctx *cli.Context) error {
return nil return nil
} }
// detectEnsAddr determines the ENS contract address by getting both the
// version and genesis hash using the client and matching them to either
// mainnet or testnet addresses
func detectEnsAddr(client *rpc.Client) (common.Address, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var version string
if err := client.CallContext(ctx, &version, "net_version"); err != nil {
return common.Address{}, err
}
block, err := ethclient.NewClient(client).BlockByNumber(ctx, big.NewInt(0))
if err != nil {
return common.Address{}, err
}
switch {
case version == "1" && block.Hash() == params.MainnetGenesisHash:
log.Info("using Mainnet ENS contract address", "addr", ens.MainNetAddress)
return ens.MainNetAddress, nil
case version == "3" && block.Hash() == params.TestnetGenesisHash:
log.Info("using Testnet ENS contract address", "addr", ens.TestNetAddress)
return ens.TestNetAddress, nil
default:
return common.Address{}, fmt.Errorf("unknown version and genesis hash: %s %s", version, block.Hash())
}
}
func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node.Node) { func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node.Node) {
//define the swarm service boot function //define the swarm service boot function
@ -494,27 +462,7 @@ func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node.
} }
} }
var ensClient *ethclient.Client return swarm.NewSwarm(ctx, swapClient, bzzconfig)
if bzzconfig.EnsApi != "" {
log.Info("connecting to ENS API", "url", bzzconfig.EnsApi)
client, err := rpc.Dial(bzzconfig.EnsApi)
if err != nil {
return nil, fmt.Errorf("error connecting to ENS API %s: %s", bzzconfig.EnsApi, err)
}
ensClient = ethclient.NewClient(client)
//no ENS root address set yet
if bzzconfig.EnsRoot == (common.Address{}) {
ensAddr, err := detectEnsAddr(client)
if err == nil {
bzzconfig.EnsRoot = ensAddr
} else {
log.Warn(fmt.Sprintf("could not determine ENS contract address, using default %s", bzzconfig.EnsRoot), "err", err)
}
}
}
return swarm.NewSwarm(ctx, swapClient, ensClient, bzzconfig, bzzconfig.SwapEnabled, bzzconfig.SyncEnabled, bzzconfig.Cors)
} }
//register within the ethereum node //register within the ethereum node
if err := stack.Register(boot); err != nil { if err := stack.Register(boot); err != nil {

View file

@ -1,4 +1,4 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of go-ethereum.
// //
// go-ethereum is free software: you can redistribute it and/or modify // go-ethereum is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of go-ethereum.
// //
// go-ethereum is free software: you can redistribute it and/or modify // go-ethereum is free software: you can redistribute it and/or modify

View file

@ -25,6 +25,7 @@ import (
"os/signal" "os/signal"
"runtime" "runtime"
"strings" "strings"
"syscall"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -64,7 +65,7 @@ func StartNode(stack *node.Node) {
} }
go func() { go func() {
sigc := make(chan os.Signal, 1) sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt) signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(sigc) defer signal.Stop(sigc)
<-sigc <-sigc
log.Info("Got interrupt, shutting down...") log.Info("Got interrupt, shutting down...")
@ -85,7 +86,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
// If a signal is received, the import will stop at the next batch. // If a signal is received, the import will stop at the next batch.
interrupt := make(chan os.Signal, 1) interrupt := make(chan os.Signal, 1)
stop := make(chan struct{}) stop := make(chan struct{})
signal.Notify(interrupt, os.Interrupt) signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(interrupt) defer signal.Stop(interrupt)
defer close(interrupt) defer close(interrupt)
go func() { go func() {

View file

@ -397,6 +397,11 @@ var (
Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
Value: "", Value: "",
} }
RPCVirtualHostsFlag = cli.StringFlag{
Name: "rpcvhosts",
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
Value: "localhost",
}
RPCApiFlag = cli.StringFlag{ RPCApiFlag = cli.StringFlag{
Name: "rpcapi", Name: "rpcapi",
Usage: "API's offered over the HTTP-RPC interface", Usage: "API's offered over the HTTP-RPC interface",
@ -690,6 +695,8 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) {
if ctx.GlobalIsSet(RPCApiFlag.Name) { if ctx.GlobalIsSet(RPCApiFlag.Name) {
cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name)) cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
} }
cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
} }
// setWS creates the WebSocket RPC listener interface string from the set // setWS creates the WebSocket RPC listener interface string from the set

View file

@ -43,7 +43,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/whisper/mailserver" "github.com/ethereum/go-ethereum/whisper/mailserver"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
) )
@ -61,27 +61,29 @@ var (
// encryption // encryption
var ( var (
symKey []byte symKey []byte
pub *ecdsa.PublicKey pub *ecdsa.PublicKey
asymKey *ecdsa.PrivateKey asymKey *ecdsa.PrivateKey
nodeid *ecdsa.PrivateKey nodeid *ecdsa.PrivateKey
topic whisper.TopicType topic whisper.TopicType
asymKeyID string
filterID string asymKeyID string
symPass string asymFilterID string
msPassword string symFilterID string
symPass string
msPassword string
) )
// cmd arguments // cmd arguments
var ( var (
bootstrapMode = flag.Bool("standalone", false, "boostrap node: don't actively connect to peers, wait for incoming connections") bootstrapMode = flag.Bool("standalone", false, "boostrap node: don't initiate connection to peers, just wait for incoming connections")
forwarderMode = flag.Bool("forwarder", false, "forwarder mode: only forward messages, neither send nor decrypt messages") forwarderMode = flag.Bool("forwarder", false, "forwarder mode: only forward messages, neither encrypt nor decrypt messages")
mailServerMode = flag.Bool("mailserver", false, "mail server mode: delivers expired messages on demand") mailServerMode = flag.Bool("mailserver", false, "mail server mode: delivers expired messages on demand")
requestMail = flag.Bool("mailclient", false, "request expired messages from the bootstrap server") requestMail = flag.Bool("mailclient", false, "request expired messages from the bootstrap server")
asymmetricMode = flag.Bool("asym", false, "use asymmetric encryption") asymmetricMode = flag.Bool("asym", false, "use asymmetric encryption")
generateKey = flag.Bool("generatekey", false, "generate and show the private key") generateKey = flag.Bool("generatekey", false, "generate and show the private key")
fileExMode = flag.Bool("fileexchange", false, "file exchange mode") fileExMode = flag.Bool("fileexchange", false, "file exchange mode")
testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics") testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics (password, etc.)")
echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics") echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics")
argVerbosity = flag.Int("verbosity", int(log.LvlError), "log verbosity level") argVerbosity = flag.Int("verbosity", int(log.LvlError), "log verbosity level")
@ -97,7 +99,7 @@ var (
argIDFile = flag.String("idfile", "", "file name with node id (private key)") argIDFile = flag.String("idfile", "", "file name with node id (private key)")
argEnode = flag.String("boot", "", "bootstrap node you want to connect to (e.g. enode://e454......08d50@52.176.211.200:16428)") argEnode = flag.String("boot", "", "bootstrap node you want to connect to (e.g. enode://e454......08d50@52.176.211.200:16428)")
argTopic = flag.String("topic", "", "topic in hexadecimal format (e.g. 70a4beef)") argTopic = flag.String("topic", "", "topic in hexadecimal format (e.g. 70a4beef)")
argSaveDir = flag.String("savedir", "", "directory where incoming messages will be saved as files") argSaveDir = flag.String("savedir", "", "directory where all incoming messages will be saved as files")
) )
func main() { func main() {
@ -263,7 +265,7 @@ func initialize() {
Config: p2p.Config{ Config: p2p.Config{
PrivateKey: nodeid, PrivateKey: nodeid,
MaxPeers: maxPeers, MaxPeers: maxPeers,
Name: common.MakeName("wnode", "5.0"), Name: common.MakeName("wnode", "6.0"),
Protocols: shh.Protocols(), Protocols: shh.Protocols(),
ListenAddr: *argIP, ListenAddr: *argIP,
NAT: nat.Any(), NAT: nat.Any(),
@ -363,13 +365,22 @@ func configureNode() {
} }
} }
filter := whisper.Filter{ symFilter := whisper.Filter{
KeySym: symKey, KeySym: symKey,
Topics: [][]byte{topic[:]},
AllowP2P: p2pAccept,
}
symFilterID, err = shh.Subscribe(&symFilter)
if err != nil {
utils.Fatalf("Failed to install filter: %s", err)
}
asymFilter := whisper.Filter{
KeyAsym: asymKey, KeyAsym: asymKey,
Topics: [][]byte{topic[:]}, Topics: [][]byte{topic[:]},
AllowP2P: p2pAccept, AllowP2P: p2pAccept,
} }
filterID, err = shh.Subscribe(&filter) asymFilterID, err = shh.Subscribe(&asymFilter)
if err != nil { if err != nil {
utils.Fatalf("Failed to install filter: %s", err) utils.Fatalf("Failed to install filter: %s", err)
} }
@ -522,9 +533,14 @@ func sendMsg(payload []byte) common.Hash {
} }
func messageLoop() { func messageLoop() {
f := shh.GetFilter(filterID) sf := shh.GetFilter(symFilterID)
if f == nil { if sf == nil {
utils.Fatalf("filter is not installed") utils.Fatalf("symmetric filter is not installed")
}
af := shh.GetFilter(asymFilterID)
if af == nil {
utils.Fatalf("asymmetric filter is not installed")
} }
ticker := time.NewTicker(time.Millisecond * 50) ticker := time.NewTicker(time.Millisecond * 50)
@ -532,11 +548,18 @@ func messageLoop() {
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
messages := f.Retrieve() m1 := sf.Retrieve()
m2 := af.Retrieve()
messages := append(m1, m2...)
for _, msg := range messages { for _, msg := range messages {
if *fileExMode || len(msg.Payload) > 2048 { // 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) writeMessageToFile(*argSaveDir, msg)
} else { }
if !*fileExMode && len(msg.Payload) <= 2048 {
printMessageInfo(msg) printMessageInfo(msg)
} }
} }
@ -571,19 +594,22 @@ func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
address = crypto.PubkeyToAddress(*msg.Src) address = crypto.PubkeyToAddress(*msg.Src)
} }
if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) { // this is a sample code; uncomment if you don't want to save your own messages.
// message from myself: don't save, only report //if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
fmt.Printf("\n%s <%x>: message received: '%s'\n", timestamp, address, name) // fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name)
} else if len(dir) > 0 { // return
//}
if len(dir) > 0 {
fullpath := filepath.Join(dir, name) fullpath := filepath.Join(dir, name)
err := ioutil.WriteFile(fullpath, msg.Payload, 0644) err := ioutil.WriteFile(fullpath, msg.Raw, 0644)
if err != nil { if err != nil {
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err) fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
} else { } else {
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(msg.Payload)) fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(msg.Raw))
} }
} else { } else {
fmt.Printf("\n%s {%x}: big message received (%d bytes), but not saved: %s\n", timestamp, address, len(msg.Payload), name) fmt.Printf("\n%s {%x}: message received (%d bytes), but not saved: %s\n", timestamp, address, len(msg.Raw), name)
} }
} }
@ -631,7 +657,7 @@ func requestExpiredMessagesLoop() {
params.PoW = *argServerPoW params.PoW = *argServerPoW
params.Payload = data params.Payload = data
params.KeySym = key params.KeySym = key
params.Src = nodeid params.Src = asymKey
params.WorkTime = 5 params.WorkTime = 5
msg, err := whisper.NewSentMessage(&params) msg, err := whisper.NewSentMessage(&params)

View file

@ -25,6 +25,6 @@ var (
Big3 = big.NewInt(3) Big3 = big.NewInt(3)
Big0 = big.NewInt(0) Big0 = big.NewInt(0)
Big32 = big.NewInt(32) Big32 = big.NewInt(32)
Big256 = big.NewInt(0xff) Big256 = big.NewInt(256)
Big257 = big.NewInt(257) Big257 = big.NewInt(257)
) )

View file

@ -1,18 +1,18 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of the go-ethereum library.
// //
// go-ethereum is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// go-ethereum is distributed in the hope that it will be useful, // The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU Lesser General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU Lesser General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build freebsd // +build freebsd

View file

@ -1,18 +1,18 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of the go-ethereum library.
// //
// go-ethereum is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// go-ethereum is distributed in the hope that it will be useful, // The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU Lesser General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU Lesser General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package fdlimit package fdlimit

View file

@ -1,18 +1,18 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of the go-ethereum library.
// //
// go-ethereum is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// go-ethereum is distributed in the hope that it will be useful, // The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU Lesser General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU Lesser General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build linux darwin netbsd openbsd solaris // +build linux darwin netbsd openbsd solaris

View file

@ -1,18 +1,18 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2018 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of the go-ethereum library.
// //
// go-ethereum is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// go-ethereum is distributed in the hope that it will be useful, // The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU Lesser General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU Lesser General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package fdlimit package fdlimit

View file

@ -19,6 +19,7 @@ package ethash
import ( import (
"encoding/binary" "encoding/binary"
"hash" "hash"
"math/big"
"reflect" "reflect"
"runtime" "runtime"
"sync" "sync"
@ -47,6 +48,48 @@ const (
loopAccesses = 64 // Number of accesses in hashimoto loop loopAccesses = 64 // Number of accesses in hashimoto loop
) )
// cacheSize returns the size of the ethash verification cache that belongs to a certain
// block number.
func cacheSize(block uint64) uint64 {
epoch := int(block / epochLength)
if epoch < maxEpoch {
return cacheSizes[epoch]
}
return calcCacheSize(epoch)
}
// calcCacheSize calculates the cache size for epoch. The cache size grows linearly,
// however, we always take the highest prime below the linearly growing threshold in order
// to reduce the risk of accidental regularities leading to cyclic behavior.
func calcCacheSize(epoch int) uint64 {
size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes
for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
size -= 2 * hashBytes
}
return size
}
// datasetSize returns the size of the ethash mining dataset that belongs to a certain
// block number.
func datasetSize(block uint64) uint64 {
epoch := int(block / epochLength)
if epoch < maxEpoch {
return datasetSizes[epoch]
}
return calcDatasetSize(epoch)
}
// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly,
// however, we always take the highest prime below the linearly growing threshold in order
// to reduce the risk of accidental regularities leading to cyclic behavior.
func calcDatasetSize(epoch int) uint64 {
size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes
for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
size -= 2 * mixBytes
}
return size
}
// hasher is a repetitive hasher allowing the same hash data structures to be // hasher is a repetitive hasher allowing the same hash data structures to be
// reused between hash runs instead of requiring new ones to be created. // reused between hash runs instead of requiring new ones to be created.
type hasher func(dest []byte, data []byte) type hasher func(dest []byte, data []byte)

View file

@ -1,47 +0,0 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build !go1.8
package ethash
// cacheSize calculates and returns the size of the ethash verification cache that
// belongs to a certain block number. The cache size grows linearly, however, we
// always take the highest prime below the linearly growing threshold in order to
// reduce the risk of accidental regularities leading to cyclic behavior.
func cacheSize(block uint64) uint64 {
// If we have a pre-generated value, use that
epoch := int(block / epochLength)
if epoch < maxEpoch {
return cacheSizes[epoch]
}
// We don't have a way to verify primes fast before Go 1.8
panic("fast prime testing unsupported in Go < 1.8")
}
// datasetSize calculates and returns the size of the ethash mining dataset that
// belongs to a certain block number. The dataset size grows linearly, however, we
// always take the highest prime below the linearly growing threshold in order to
// reduce the risk of accidental regularities leading to cyclic behavior.
func datasetSize(block uint64) uint64 {
// If we have a pre-generated value, use that
epoch := int(block / epochLength)
if epoch < maxEpoch {
return datasetSizes[epoch]
}
// We don't have a way to verify primes fast before Go 1.8
panic("fast prime testing unsupported in Go < 1.8")
}

View file

@ -1,63 +0,0 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build go1.8
package ethash
import "math/big"
// cacheSize returns the size of the ethash verification cache that belongs to a certain
// block number.
func cacheSize(block uint64) uint64 {
epoch := int(block / epochLength)
if epoch < maxEpoch {
return cacheSizes[epoch]
}
return calcCacheSize(epoch)
}
// calcCacheSize calculates the cache size for epoch. The cache size grows linearly,
// however, we always take the highest prime below the linearly growing threshold in order
// to reduce the risk of accidental regularities leading to cyclic behavior.
func calcCacheSize(epoch int) uint64 {
size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes
for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
size -= 2 * hashBytes
}
return size
}
// datasetSize returns the size of the ethash mining dataset that belongs to a certain
// block number.
func datasetSize(block uint64) uint64 {
epoch := int(block / epochLength)
if epoch < maxEpoch {
return datasetSizes[epoch]
}
return calcDatasetSize(epoch)
}
// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly,
// however, we always take the highest prime below the linearly growing threshold in order
// to reduce the risk of accidental regularities leading to cyclic behavior.
func calcDatasetSize(epoch int) uint64 {
size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes
for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
size -= 2 * mixBytes
}
return size
}

View file

@ -1,37 +0,0 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build go1.8
package ethash
import "testing"
// Tests whether the dataset size calculator works correctly by cross checking the
// hard coded lookup table with the value generated by it.
func TestSizeCalculations(t *testing.T) {
// Verify all the cache and dataset sizes from the lookup table.
for epoch, want := range cacheSizes {
if size := calcCacheSize(epoch); size != want {
t.Errorf("cache %d: cache size mismatch: have %d, want %d", epoch, size, want)
}
}
for epoch, want := range datasetSizes {
if size := calcDatasetSize(epoch); size != want {
t.Errorf("dataset %d: dataset size mismatch: have %d, want %d", epoch, size, want)
}
}
}

View file

@ -30,6 +30,22 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
// Tests whether the dataset size calculator works correctly by cross checking the
// hard coded lookup table with the value generated by it.
func TestSizeCalculations(t *testing.T) {
// Verify all the cache and dataset sizes from the lookup table.
for epoch, want := range cacheSizes {
if size := calcCacheSize(epoch); size != want {
t.Errorf("cache %d: cache size mismatch: have %d, want %d", epoch, size, want)
}
}
for epoch, want := range datasetSizes {
if size := calcDatasetSize(epoch); size != want {
t.Errorf("dataset %d: dataset size mismatch: have %d, want %d", epoch, size, want)
}
}
}
// Tests that verification caches can be correctly generated. // Tests that verification caches can be correctly generated.
func TestCacheGeneration(t *testing.T) { func TestCacheGeneration(t *testing.T) {
tests := []struct { tests := []struct {

View file

@ -53,7 +53,6 @@ var (
errDuplicateUncle = errors.New("duplicate uncle") errDuplicateUncle = errors.New("duplicate uncle")
errUncleIsAncestor = errors.New("uncle is ancestor") errUncleIsAncestor = errors.New("uncle is ancestor")
errDanglingUncle = errors.New("uncle's parent is not ancestor") errDanglingUncle = errors.New("uncle's parent is not ancestor")
errNonceOutOfRange = errors.New("nonce out of range")
errInvalidDifficulty = errors.New("non-positive difficulty") errInvalidDifficulty = errors.New("non-positive difficulty")
errInvalidMixDigest = errors.New("invalid mix digest") errInvalidMixDigest = errors.New("invalid mix digest")
errInvalidPoW = errors.New("invalid proof-of-work") errInvalidPoW = errors.New("invalid proof-of-work")
@ -474,18 +473,13 @@ func (ethash *Ethash) VerifySeal(chain consensus.ChainReader, header *types.Head
if ethash.shared != nil { if ethash.shared != nil {
return ethash.shared.VerifySeal(chain, header) return ethash.shared.VerifySeal(chain, header)
} }
// Sanity check that the block number is below the lookup table size (60M blocks)
number := header.Number.Uint64()
if number/epochLength >= maxEpoch {
// Go < 1.7 cannot calculate new cache/dataset sizes (no fast prime check)
return errNonceOutOfRange
}
// Ensure that we have a valid difficulty for the block // Ensure that we have a valid difficulty for the block
if header.Difficulty.Sign() <= 0 { if header.Difficulty.Sign() <= 0 {
return errInvalidDifficulty return errInvalidDifficulty
} }
// Recompute the digest and PoW value and verify against the header // Recompute the digest and PoW value and verify against the header
number := header.Number.Uint64()
cache := ethash.cache(number) cache := ethash.cache(number)
size := datasetSize(number) size := datasetSize(number)
if ethash.config.PowMode == ModeTest { if ethash.config.PowMode == ModeTest {

View file

@ -35,9 +35,9 @@ import (
mmap "github.com/edsrzf/mmap-go" mmap "github.com/edsrzf/mmap-go"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/hashicorp/golang-lru/simplelru" "github.com/hashicorp/golang-lru/simplelru"
metrics "github.com/rcrowley/go-metrics"
) )
var ErrInvalidDumpMagic = errors.New("invalid dump magic") var ErrInvalidDumpMagic = errors.New("invalid dump magic")

View file

@ -26,6 +26,7 @@ import (
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
"syscall"
"github.com/ethereum/go-ethereum/internal/jsre" "github.com/ethereum/go-ethereum/internal/jsre"
"github.com/ethereum/go-ethereum/internal/web3ext" "github.com/ethereum/go-ethereum/internal/web3ext"
@ -332,7 +333,7 @@ func (c *Console) Interactive() {
}() }()
// Monitor Ctrl-C too in case the input is empty and we need to bail // Monitor Ctrl-C too in case the input is empty and we need to bail
abort := make(chan os.Signal, 1) abort := make(chan os.Signal, 1)
signal.Notify(abort, os.Interrupt) signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM)
// Start sending prompts to the user and reading back inputs // Start sending prompts to the user and reading back inputs
for { for {

View file

@ -2,7 +2,7 @@ FROM alpine:3.7
RUN \ RUN \
apk add --update go git make gcc musl-dev linux-headers ca-certificates && \ apk add --update go git make gcc musl-dev linux-headers ca-certificates && \
git clone --depth 1 --branch release/1.7 https://github.com/ethereum/go-ethereum && \ git clone --depth 1 --branch release/1.8 https://github.com/ethereum/go-ethereum && \
(cd go-ethereum && make geth) && \ (cd go-ethereum && make geth) && \
cp go-ethereum/build/bin/geth /geth && \ cp go-ethereum/build/bin/geth /geth && \
apk del go git make gcc musl-dev linux-headers && \ apk del go git make gcc musl-dev linux-headers && \

View file

@ -5,7 +5,7 @@ ENV PATH=/usr/lib/go-1.9/bin:$PATH
RUN \ RUN \
apt-get update && apt-get upgrade -q -y && \ apt-get update && apt-get upgrade -q -y && \
apt-get install -y --no-install-recommends golang-1.9 git make gcc libc-dev ca-certificates && \ apt-get install -y --no-install-recommends golang-1.9 git make gcc libc-dev ca-certificates && \
git clone --depth 1 --branch release/1.7 https://github.com/ethereum/go-ethereum && \ git clone --depth 1 --branch release/1.8 https://github.com/ethereum/go-ethereum && \
(cd go-ethereum && make geth) && \ (cd go-ethereum && make geth) && \
cp go-ethereum/build/bin/geth /geth && \ cp go-ethereum/build/bin/geth /geth && \
apt-get remove -y golang-1.9 git make gcc libc-dev && apt autoremove -y && apt-get clean && \ apt-get remove -y golang-1.9 git make gcc libc-dev && apt autoremove -y && apt-get clean && \

View file

@ -281,8 +281,8 @@ func TestDeposit(t *testing.T) {
t.Fatalf("expected balance %v, got %v", exp, chbook.Balance()) t.Fatalf("expected balance %v, got %v", exp, chbook.Balance())
} }
// autodeposit every 30ms if new cheque issued // autodeposit every 200ms if new cheque issued
interval := 30 * time.Millisecond interval := 200 * time.Millisecond
chbook.AutoDeposit(interval, common.Big1, balance) chbook.AutoDeposit(interval, common.Big1, balance)
_, err = chbook.Issue(addr1, amount) _, err = chbook.Issue(addr1, amount)
if err != nil { if err != nil {

View file

@ -206,7 +206,7 @@ func lexLine(l *lexer) stateFn {
return lexComment return lexComment
case isSpace(r): case isSpace(r):
l.ignore() l.ignore()
case isAlphaNumeric(r) || r == '_': case isLetter(r) || r == '_':
return lexElement return lexElement
case isNumber(r): case isNumber(r):
return lexNumber return lexNumber
@ -278,7 +278,7 @@ func lexElement(l *lexer) stateFn {
return lexLine return lexLine
} }
func isAlphaNumeric(t rune) bool { func isLetter(t rune) bool {
return unicode.IsLetter(t) return unicode.IsLetter(t)
} }

View file

@ -46,7 +46,7 @@ import (
) )
var ( var (
blockInsertTimer = metrics.NewTimer("chain/inserts") blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
ErrNoGenesis = errors.New("Genesis not found in chain") ErrNoGenesis = errors.New("Genesis not found in chain")
) )
@ -107,8 +107,8 @@ type BlockChain struct {
procmu sync.RWMutex // block processor lock procmu sync.RWMutex // block processor lock
checkpoint int // checkpoint counts towards the new checkpoint checkpoint int // checkpoint counts towards the new checkpoint
currentBlock *types.Block // Current head of the block chain currentBlock atomic.Value // Current head of the block chain
currentFastBlock *types.Block // Current head of the fast-sync chain (may be above the block chain!) currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
stateCache state.Database // State database to reuse between imports (contains state cache) stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies bodyCache *lru.Cache // Cache for the most recent block bodies
@ -224,10 +224,10 @@ func (bc *BlockChain) loadLastState() error {
} }
} }
// Everything seems to be fine, set as the head block // Everything seems to be fine, set as the head block
bc.currentBlock = currentBlock bc.currentBlock.Store(currentBlock)
// Restore the last known head header // Restore the last known head header
currentHeader := bc.currentBlock.Header() currentHeader := currentBlock.Header()
if head := GetHeadHeaderHash(bc.db); head != (common.Hash{}) { if head := GetHeadHeaderHash(bc.db); head != (common.Hash{}) {
if header := bc.GetHeaderByHash(head); header != nil { if header := bc.GetHeaderByHash(head); header != nil {
currentHeader = header currentHeader = header
@ -236,21 +236,23 @@ func (bc *BlockChain) loadLastState() error {
bc.hc.SetCurrentHeader(currentHeader) bc.hc.SetCurrentHeader(currentHeader)
// Restore the last known head fast block // Restore the last known head fast block
bc.currentFastBlock = bc.currentBlock bc.currentFastBlock.Store(currentBlock)
if head := GetHeadFastBlockHash(bc.db); head != (common.Hash{}) { if head := GetHeadFastBlockHash(bc.db); head != (common.Hash{}) {
if block := bc.GetBlockByHash(head); block != nil { if block := bc.GetBlockByHash(head); block != nil {
bc.currentFastBlock = block bc.currentFastBlock.Store(block)
} }
} }
// Issue a status log for the user // Issue a status log for the user
currentFastBlock := bc.CurrentFastBlock()
headerTd := bc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()) headerTd := bc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64())
blockTd := bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64()) blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
fastTd := bc.GetTd(bc.currentFastBlock.Hash(), bc.currentFastBlock.NumberU64()) fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64())
log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd) log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd)
log.Info("Loaded most recent local full block", "number", bc.currentBlock.Number(), "hash", bc.currentBlock.Hash(), "td", blockTd) log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd)
log.Info("Loaded most recent local fast block", "number", bc.currentFastBlock.Number(), "hash", bc.currentFastBlock.Hash(), "td", fastTd) log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd)
return nil return nil
} }
@ -279,30 +281,32 @@ func (bc *BlockChain) SetHead(head uint64) error {
bc.futureBlocks.Purge() bc.futureBlocks.Purge()
// Rewind the block chain, ensuring we don't end up with a stateless head block // Rewind the block chain, ensuring we don't end up with a stateless head block
if bc.currentBlock != nil && currentHeader.Number.Uint64() < bc.currentBlock.NumberU64() { if currentBlock := bc.CurrentBlock(); currentBlock != nil && currentHeader.Number.Uint64() < currentBlock.NumberU64() {
bc.currentBlock = bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()) bc.currentBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()))
} }
if bc.currentBlock != nil { if currentBlock := bc.CurrentBlock(); currentBlock != nil {
if _, err := state.New(bc.currentBlock.Root(), bc.stateCache); err != nil { if _, err := state.New(currentBlock.Root(), bc.stateCache); err != nil {
// Rewound state missing, rolled back to before pivot, reset to genesis // Rewound state missing, rolled back to before pivot, reset to genesis
bc.currentBlock = nil bc.currentBlock.Store(bc.genesisBlock)
} }
} }
// Rewind the fast block in a simpleton way to the target head // Rewind the fast block in a simpleton way to the target head
if bc.currentFastBlock != nil && currentHeader.Number.Uint64() < bc.currentFastBlock.NumberU64() { if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock != nil && currentHeader.Number.Uint64() < currentFastBlock.NumberU64() {
bc.currentFastBlock = bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()) bc.currentFastBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()))
} }
// If either blocks reached nil, reset to the genesis state // If either blocks reached nil, reset to the genesis state
if bc.currentBlock == nil { if currentBlock := bc.CurrentBlock(); currentBlock == nil {
bc.currentBlock = bc.genesisBlock bc.currentBlock.Store(bc.genesisBlock)
} }
if bc.currentFastBlock == nil { if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock == nil {
bc.currentFastBlock = bc.genesisBlock bc.currentFastBlock.Store(bc.genesisBlock)
} }
if err := WriteHeadBlockHash(bc.db, bc.currentBlock.Hash()); err != nil { currentBlock := bc.CurrentBlock()
currentFastBlock := bc.CurrentFastBlock()
if err := WriteHeadBlockHash(bc.db, currentBlock.Hash()); err != nil {
log.Crit("Failed to reset head full block", "err", err) log.Crit("Failed to reset head full block", "err", err)
} }
if err := WriteHeadFastBlockHash(bc.db, bc.currentFastBlock.Hash()); err != nil { if err := WriteHeadFastBlockHash(bc.db, currentFastBlock.Hash()); err != nil {
log.Crit("Failed to reset head fast block", "err", err) log.Crit("Failed to reset head fast block", "err", err)
} }
return bc.loadLastState() return bc.loadLastState()
@ -321,7 +325,7 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {
} }
// If all checks out, manually set the head block // If all checks out, manually set the head block
bc.mu.Lock() bc.mu.Lock()
bc.currentBlock = block bc.currentBlock.Store(block)
bc.mu.Unlock() bc.mu.Unlock()
log.Info("Committed new head block", "number", block.Number(), "hash", hash) log.Info("Committed new head block", "number", block.Number(), "hash", hash)
@ -330,28 +334,19 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {
// GasLimit returns the gas limit of the current HEAD block. // GasLimit returns the gas limit of the current HEAD block.
func (bc *BlockChain) GasLimit() uint64 { func (bc *BlockChain) GasLimit() uint64 {
bc.mu.RLock() return bc.CurrentBlock().GasLimit()
defer bc.mu.RUnlock()
return bc.currentBlock.GasLimit()
} }
// CurrentBlock retrieves the current head block of the canonical chain. The // CurrentBlock retrieves the current head block of the canonical chain. The
// block is retrieved from the blockchain's internal cache. // block is retrieved from the blockchain's internal cache.
func (bc *BlockChain) CurrentBlock() *types.Block { func (bc *BlockChain) CurrentBlock() *types.Block {
bc.mu.RLock() return bc.currentBlock.Load().(*types.Block)
defer bc.mu.RUnlock()
return bc.currentBlock
} }
// CurrentFastBlock retrieves the current fast-sync head block of the canonical // CurrentFastBlock retrieves the current fast-sync head block of the canonical
// chain. The block is retrieved from the blockchain's internal cache. // chain. The block is retrieved from the blockchain's internal cache.
func (bc *BlockChain) CurrentFastBlock() *types.Block { func (bc *BlockChain) CurrentFastBlock() *types.Block {
bc.mu.RLock() return bc.currentFastBlock.Load().(*types.Block)
defer bc.mu.RUnlock()
return bc.currentFastBlock
} }
// SetProcessor sets the processor required for making state modifications. // SetProcessor sets the processor required for making state modifications.
@ -416,10 +411,10 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
} }
bc.genesisBlock = genesis bc.genesisBlock = genesis
bc.insert(bc.genesisBlock) bc.insert(bc.genesisBlock)
bc.currentBlock = bc.genesisBlock bc.currentBlock.Store(bc.genesisBlock)
bc.hc.SetGenesis(bc.genesisBlock.Header()) bc.hc.SetGenesis(bc.genesisBlock.Header())
bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) bc.hc.SetCurrentHeader(bc.genesisBlock.Header())
bc.currentFastBlock = bc.genesisBlock bc.currentFastBlock.Store(bc.genesisBlock)
return nil return nil
} }
@ -444,7 +439,7 @@ func (bc *BlockChain) repair(head **types.Block) error {
// Export writes the active chain to the given writer. // Export writes the active chain to the given writer.
func (bc *BlockChain) Export(w io.Writer) error { func (bc *BlockChain) Export(w io.Writer) error {
return bc.ExportN(w, uint64(0), bc.currentBlock.NumberU64()) return bc.ExportN(w, uint64(0), bc.CurrentBlock().NumberU64())
} }
// ExportN writes a subset of the active chain to the given writer. // ExportN writes a subset of the active chain to the given writer.
@ -488,7 +483,7 @@ func (bc *BlockChain) insert(block *types.Block) {
if err := WriteHeadBlockHash(bc.db, block.Hash()); err != nil { if err := WriteHeadBlockHash(bc.db, block.Hash()); err != nil {
log.Crit("Failed to insert head block hash", "err", err) log.Crit("Failed to insert head block hash", "err", err)
} }
bc.currentBlock = block bc.currentBlock.Store(block)
// If the block is better than our head or is on a different chain, force update heads // If the block is better than our head or is on a different chain, force update heads
if updateHeads { if updateHeads {
@ -497,7 +492,7 @@ func (bc *BlockChain) insert(block *types.Block) {
if err := WriteHeadFastBlockHash(bc.db, block.Hash()); err != nil { if err := WriteHeadFastBlockHash(bc.db, block.Hash()); err != nil {
log.Crit("Failed to insert head fast block hash", "err", err) log.Crit("Failed to insert head fast block hash", "err", err)
} }
bc.currentFastBlock = block bc.currentFastBlock.Store(block)
} }
} }
@ -648,22 +643,21 @@ func (bc *BlockChain) Stop() {
bc.wg.Wait() bc.wg.Wait()
// Ensure the state of a recent block is also stored to disk before exiting. // Ensure the state of a recent block is also stored to disk before exiting.
// It is fine if this state does not exist (fast start/stop cycle), but it is // We're writing three different states to catch different restart scenarios:
// advisable to leave an N block gap from the head so 1) a restart loads up // - HEAD: So we don't need to reprocess any blocks in the general case
// the last N blocks as sync assistance to remote nodes; 2) a restart during // - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle
// a (small) reorg doesn't require deep reprocesses; 3) chain "repair" from // - HEAD-127: So we have a hard limit on the number of blocks reexecuted
// missing states are constantly tested.
//
// This may be tuned a bit on mainnet if its too annoying to reprocess the last
// N blocks.
if !bc.cacheConfig.Disabled { if !bc.cacheConfig.Disabled {
triedb := bc.stateCache.TrieDB() triedb := bc.stateCache.TrieDB()
if number := bc.CurrentBlock().NumberU64(); number >= triesInMemory {
recent := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - triesInMemory + 1)
log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) for _, offset := range []uint64{0, 1, triesInMemory - 1} {
if err := triedb.Commit(recent.Root(), true); err != nil { if number := bc.CurrentBlock().NumberU64(); number > offset {
log.Error("Failed to commit recent state trie", "err", err) recent := bc.GetBlockByNumber(number - offset)
log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root())
if err := triedb.Commit(recent.Root(), true); err != nil {
log.Error("Failed to commit recent state trie", "err", err)
}
} }
} }
for !bc.triegc.Empty() { for !bc.triegc.Empty() {
@ -715,13 +709,15 @@ func (bc *BlockChain) Rollback(chain []common.Hash) {
if currentHeader.Hash() == hash { if currentHeader.Hash() == hash {
bc.hc.SetCurrentHeader(bc.GetHeader(currentHeader.ParentHash, currentHeader.Number.Uint64()-1)) bc.hc.SetCurrentHeader(bc.GetHeader(currentHeader.ParentHash, currentHeader.Number.Uint64()-1))
} }
if bc.currentFastBlock.Hash() == hash { if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock.Hash() == hash {
bc.currentFastBlock = bc.GetBlock(bc.currentFastBlock.ParentHash(), bc.currentFastBlock.NumberU64()-1) newFastBlock := bc.GetBlock(currentFastBlock.ParentHash(), currentFastBlock.NumberU64()-1)
WriteHeadFastBlockHash(bc.db, bc.currentFastBlock.Hash()) bc.currentFastBlock.Store(newFastBlock)
WriteHeadFastBlockHash(bc.db, newFastBlock.Hash())
} }
if bc.currentBlock.Hash() == hash { if currentBlock := bc.CurrentBlock(); currentBlock.Hash() == hash {
bc.currentBlock = bc.GetBlock(bc.currentBlock.ParentHash(), bc.currentBlock.NumberU64()-1) newBlock := bc.GetBlock(currentBlock.ParentHash(), currentBlock.NumberU64()-1)
WriteHeadBlockHash(bc.db, bc.currentBlock.Hash()) bc.currentBlock.Store(newBlock)
WriteHeadBlockHash(bc.db, newBlock.Hash())
} }
} }
} }
@ -830,11 +826,12 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
bc.mu.Lock() bc.mu.Lock()
head := blockChain[len(blockChain)-1] head := blockChain[len(blockChain)-1]
if td := bc.GetTd(head.Hash(), head.NumberU64()); td != nil { // Rewind may have occurred, skip in that case if td := bc.GetTd(head.Hash(), head.NumberU64()); td != nil { // Rewind may have occurred, skip in that case
if bc.GetTd(bc.currentFastBlock.Hash(), bc.currentFastBlock.NumberU64()).Cmp(td) < 0 { currentFastBlock := bc.CurrentFastBlock()
if bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()).Cmp(td) < 0 {
if err := WriteHeadFastBlockHash(bc.db, head.Hash()); err != nil { if err := WriteHeadFastBlockHash(bc.db, head.Hash()); err != nil {
log.Crit("Failed to update head fast block hash", "err", err) log.Crit("Failed to update head fast block hash", "err", err)
} }
bc.currentFastBlock = head bc.currentFastBlock.Store(head)
} }
} }
bc.mu.Unlock() bc.mu.Unlock()
@ -881,7 +878,8 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
bc.mu.Lock() bc.mu.Lock()
defer bc.mu.Unlock() defer bc.mu.Unlock()
localTd := bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64()) currentBlock := bc.CurrentBlock()
localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
externTd := new(big.Int).Add(block.Difficulty(), ptd) externTd := new(big.Int).Add(block.Difficulty(), ptd)
// Irrelevant of the canonical status, write the block itself to the database // Irrelevant of the canonical status, write the block itself to the database
@ -926,13 +924,9 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
if chosen < lastWrite+triesInMemory { if chosen < lastWrite+triesInMemory {
switch { switch {
case size >= 2*limit: case size >= 2*limit:
log.Error("Trie memory critical, forcing to disk", "size", size, "limit", limit, "optimum", float64(chosen-lastWrite)/triesInMemory) log.Warn("State memory usage too high, committing", "size", size, "limit", limit, "optimum", float64(chosen-lastWrite)/triesInMemory)
case bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit: case bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit:
log.Error("Trie timing critical, forcing to disk", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory) log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory)
case size > limit:
log.Warn("Trie memory at dangerous levels", "size", size, "limit", limit, "optimum", float64(chosen-lastWrite)/triesInMemory)
case bc.gcproc > bc.cacheConfig.TrieTimeLimit:
log.Warn("Trie timing at dangerous levels", "time", bc.gcproc, "limit", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/triesInMemory)
} }
} }
// If optimum or critical limits reached, write to disk // If optimum or critical limits reached, write to disk
@ -960,14 +954,15 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
// Second clause in the if statement reduces the vulnerability to selfish mining. // Second clause in the if statement reduces the vulnerability to selfish mining.
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
reorg := externTd.Cmp(localTd) > 0 reorg := externTd.Cmp(localTd) > 0
currentBlock = bc.CurrentBlock()
if !reorg && externTd.Cmp(localTd) == 0 { if !reorg && externTd.Cmp(localTd) == 0 {
// Split same-difficulty blocks by number, then at random // Split same-difficulty blocks by number, then at random
reorg = block.NumberU64() < bc.currentBlock.NumberU64() || (block.NumberU64() == bc.currentBlock.NumberU64() && mrand.Float64() < 0.5) reorg = block.NumberU64() < currentBlock.NumberU64() || (block.NumberU64() == currentBlock.NumberU64() && mrand.Float64() < 0.5)
} }
if reorg { if reorg {
// Reorganise the chain if the parent is not the head block // Reorganise the chain if the parent is not the head block
if block.ParentHash() != bc.currentBlock.Hash() { if block.ParentHash() != currentBlock.Hash() {
if err := bc.reorg(bc.currentBlock, block); err != nil { if err := bc.reorg(currentBlock, block); err != nil {
return NonStatTy, err return NonStatTy, err
} }
} }
@ -1070,8 +1065,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
} }
switch { switch {
case err == ErrKnownBlock: case err == ErrKnownBlock:
stats.ignored++ // Block and state both already known. However if the current block is below
continue // this number we did a rollback and we should reimport it nonetheless.
if bc.CurrentBlock().NumberU64() >= block.NumberU64() {
stats.ignored++
continue
}
case err == consensus.ErrFutureBlock: case err == consensus.ErrFutureBlock:
// Allow up to MaxFuture second in the future blocks. If this limit is exceeded // Allow up to MaxFuture second in the future blocks. If this limit is exceeded
@ -1092,7 +1091,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
case err == consensus.ErrPrunedAncestor: case err == consensus.ErrPrunedAncestor:
// Block competing with the canonical chain, store in the db, but don't process // Block competing with the canonical chain, store in the db, but don't process
// until the competitor TD goes above the canonical TD // until the competitor TD goes above the canonical TD
localTd := bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64()) currentBlock := bc.CurrentBlock()
localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
externTd := new(big.Int).Add(bc.GetTd(block.ParentHash(), block.NumberU64()-1), block.Difficulty()) externTd := new(big.Int).Add(bc.GetTd(block.ParentHash(), block.NumberU64()-1), block.Difficulty())
if localTd.Cmp(externTd) > 0 { if localTd.Cmp(externTd) > 0 {
if err = bc.WriteBlockWithoutState(block, externTd); err != nil { if err = bc.WriteBlockWithoutState(block, externTd); err != nil {
@ -1481,9 +1481,6 @@ func (bc *BlockChain) writeHeader(header *types.Header) error {
// CurrentHeader retrieves the current head header of the canonical chain. The // CurrentHeader retrieves the current head header of the canonical chain. The
// header is retrieved from the HeaderChain's internal cache. // header is retrieved from the HeaderChain's internal cache.
func (bc *BlockChain) CurrentHeader() *types.Header { func (bc *BlockChain) CurrentHeader() *types.Header {
bc.mu.RLock()
defer bc.mu.RUnlock()
return bc.hc.CurrentHeader() return bc.hc.CurrentHeader()
} }

View file

@ -34,26 +34,6 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
// newTestBlockChain creates a blockchain without validation.
func newTestBlockChain(fake bool) *BlockChain {
db, _ := ethdb.NewMemDatabase()
gspec := &Genesis{
Config: params.TestChainConfig,
Difficulty: big.NewInt(1),
}
gspec.MustCommit(db)
engine := ethash.NewFullFaker()
if !fake {
engine = ethash.NewTester()
}
blockchain, err := NewBlockChain(db, nil, gspec.Config, engine, vm.Config{})
if err != nil {
panic(err)
}
blockchain.SetValidator(bproc{})
return blockchain
}
// Test fork of length N starting from block i // Test fork of length N starting from block i
func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) { func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) {
// Copy old chain up to #i into a new db // Copy old chain up to #i into a new db
@ -183,13 +163,18 @@ func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *
} }
func TestLastBlock(t *testing.T) { func TestLastBlock(t *testing.T) {
bchain := newTestBlockChain(false) _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true)
defer bchain.Stop() if err != nil {
t.Fatalf("failed to create pristine chain: %v", err)
}
defer blockchain.Stop()
block := makeBlockChain(bchain.CurrentBlock(), 1, ethash.NewFaker(), bchain.db, 0)[0] blocks := makeBlockChain(blockchain.CurrentBlock(), 1, ethash.NewFullFaker(), blockchain.db, 0)
bchain.insert(block) if _, err := blockchain.InsertChain(blocks); err != nil {
if block.Hash() != GetHeadBlockHash(bchain.db) { t.Fatalf("Failed to insert block: %v", err)
t.Errorf("Write/Get HeadBlockHash failed") }
if blocks[len(blocks)-1].Hash() != GetHeadBlockHash(blockchain.db) {
t.Fatalf("Write/Get HeadBlockHash failed")
} }
} }
@ -337,55 +322,13 @@ func testBrokenChain(t *testing.T, full bool) {
} }
} }
type bproc struct{}
func (bproc) ValidateBody(*types.Block) error { return nil }
func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error {
return nil
}
func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) {
return nil, nil, 0, nil
}
func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {
blocks := makeBlockChainWithDiff(genesis, d, seed)
headers := make([]*types.Header, len(blocks))
for i, block := range blocks {
headers[i] = block.Header()
}
return headers
}
func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block {
var chain []*types.Block
for i, difficulty := range d {
header := &types.Header{
Coinbase: common.Address{seed},
Number: big.NewInt(int64(i + 1)),
Difficulty: big.NewInt(int64(difficulty)),
UncleHash: types.EmptyUncleHash,
TxHash: types.EmptyRootHash,
ReceiptHash: types.EmptyRootHash,
Time: big.NewInt(int64(i) + 1),
}
if i == 0 {
header.ParentHash = genesis.Hash()
} else {
header.ParentHash = chain[i-1].Hash()
}
block := types.NewBlockWithHeader(header)
chain = append(chain, block)
}
return chain
}
// Tests that reorganising a long difficult chain after a short easy one // Tests that reorganising a long difficult chain after a short easy one
// overwrites the canonical numbers and links in the database. // overwrites the canonical numbers and links in the database.
func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) } func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) }
func TestReorgLongBlocks(t *testing.T) { testReorgLong(t, true) } func TestReorgLongBlocks(t *testing.T) { testReorgLong(t, true) }
func testReorgLong(t *testing.T, full bool) { func testReorgLong(t *testing.T, full bool) {
testReorg(t, []int{1, 2, 4}, []int{1, 2, 3, 4}, 10, full) testReorg(t, []int64{0, 0, -9}, []int64{0, 0, 0, -9}, 393280, full)
} }
// Tests that reorganising a short difficult chain after a long easy one // Tests that reorganising a short difficult chain after a long easy one
@ -394,45 +337,82 @@ func TestReorgShortHeaders(t *testing.T) { testReorgShort(t, false) }
func TestReorgShortBlocks(t *testing.T) { testReorgShort(t, true) } func TestReorgShortBlocks(t *testing.T) { testReorgShort(t, true) }
func testReorgShort(t *testing.T, full bool) { func testReorgShort(t *testing.T, full bool) {
testReorg(t, []int{1, 2, 3, 4}, []int{1, 10}, 11, full) // Create a long easy chain vs. a short heavy one. Due to difficulty adjustment
// we need a fairly long chain of blocks with different difficulties for a short
// one to become heavyer than a long one. The 96 is an empirical value.
easy := make([]int64, 96)
for i := 0; i < len(easy); i++ {
easy[i] = 60
}
diff := make([]int64, len(easy)-1)
for i := 0; i < len(diff); i++ {
diff[i] = -9
}
testReorg(t, easy, diff, 12615120, full)
} }
func testReorg(t *testing.T, first, second []int, td int64, full bool) { func testReorg(t *testing.T, first, second []int64, td int64, full bool) {
bc := newTestBlockChain(true) // Create a pristine chain and database
defer bc.Stop() db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full)
if err != nil {
t.Fatalf("failed to create pristine chain: %v", err)
}
defer blockchain.Stop()
// Insert an easy and a difficult chain afterwards // Insert an easy and a difficult chain afterwards
easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(first), func(i int, b *BlockGen) {
b.OffsetTime(first[i])
})
diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(second), func(i int, b *BlockGen) {
b.OffsetTime(second[i])
})
if full { if full {
bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, first, 11)) if _, err := blockchain.InsertChain(easyBlocks); err != nil {
bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, second, 22)) t.Fatalf("failed to insert easy chain: %v", err)
}
if _, err := blockchain.InsertChain(diffBlocks); err != nil {
t.Fatalf("failed to insert difficult chain: %v", err)
}
} else { } else {
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1) easyHeaders := make([]*types.Header, len(easyBlocks))
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1) for i, block := range easyBlocks {
easyHeaders[i] = block.Header()
}
diffHeaders := make([]*types.Header, len(diffBlocks))
for i, block := range diffBlocks {
diffHeaders[i] = block.Header()
}
if _, err := blockchain.InsertHeaderChain(easyHeaders, 1); err != nil {
t.Fatalf("failed to insert easy chain: %v", err)
}
if _, err := blockchain.InsertHeaderChain(diffHeaders, 1); err != nil {
t.Fatalf("failed to insert difficult chain: %v", err)
}
} }
// Check that the chain is valid number and link wise // Check that the chain is valid number and link wise
if full { if full {
prev := bc.CurrentBlock() prev := blockchain.CurrentBlock()
for block := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, bc.GetBlockByNumber(block.NumberU64()-1) { for block := blockchain.GetBlockByNumber(blockchain.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, blockchain.GetBlockByNumber(block.NumberU64()-1) {
if prev.ParentHash() != block.Hash() { if prev.ParentHash() != block.Hash() {
t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash(), block.Hash()) t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash(), block.Hash())
} }
} }
} else { } else {
prev := bc.CurrentHeader() prev := blockchain.CurrentHeader()
for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) { for header := blockchain.GetHeaderByNumber(blockchain.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, blockchain.GetHeaderByNumber(header.Number.Uint64()-1) {
if prev.ParentHash != header.Hash() { if prev.ParentHash != header.Hash() {
t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash()) t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash())
} }
} }
} }
// Make sure the chain total difficulty is the correct one // Make sure the chain total difficulty is the correct one
want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td)) want := new(big.Int).Add(blockchain.genesisBlock.Difficulty(), big.NewInt(td))
if full { if full {
if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 { if have := blockchain.GetTdByHash(blockchain.CurrentBlock().Hash()); have.Cmp(want) != 0 {
t.Errorf("total difficulty mismatch: have %v, want %v", have, want) t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
} }
} else { } else {
if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 { if have := blockchain.GetTdByHash(blockchain.CurrentHeader().Hash()); have.Cmp(want) != 0 {
t.Errorf("total difficulty mismatch: have %v, want %v", have, want) t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
} }
} }
@ -443,19 +423,28 @@ func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) }
func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) }
func testBadHashes(t *testing.T, full bool) { func testBadHashes(t *testing.T, full bool) {
bc := newTestBlockChain(true) // Create a pristine chain and database
defer bc.Stop() db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full)
if err != nil {
t.Fatalf("failed to create pristine chain: %v", err)
}
defer blockchain.Stop()
// Create a chain, ban a hash and try to import // Create a chain, ban a hash and try to import
var err error
if full { if full {
blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10) blocks := makeBlockChain(blockchain.CurrentBlock(), 3, ethash.NewFaker(), db, 10)
BadHashes[blocks[2].Header().Hash()] = true BadHashes[blocks[2].Header().Hash()] = true
_, err = bc.InsertChain(blocks) defer func() { delete(BadHashes, blocks[2].Header().Hash()) }()
_, err = blockchain.InsertChain(blocks)
} else { } else {
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10) headers := makeHeaderChain(blockchain.CurrentHeader(), 3, ethash.NewFaker(), db, 10)
BadHashes[headers[2].Hash()] = true BadHashes[headers[2].Hash()] = true
_, err = bc.InsertHeaderChain(headers, 1) defer func() { delete(BadHashes, headers[2].Hash()) }()
_, err = blockchain.InsertHeaderChain(headers, 1)
} }
if err != ErrBlacklistedHash { if err != ErrBlacklistedHash {
t.Errorf("error mismatch: have: %v, want: %v", err, ErrBlacklistedHash) t.Errorf("error mismatch: have: %v, want: %v", err, ErrBlacklistedHash)
@ -468,40 +457,41 @@ func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) }
func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) }
func testReorgBadHashes(t *testing.T, full bool) { func testReorgBadHashes(t *testing.T, full bool) {
bc := newTestBlockChain(true) // Create a pristine chain and database
defer bc.Stop() db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full)
if err != nil {
t.Fatalf("failed to create pristine chain: %v", err)
}
// Create a chain, import and ban afterwards // Create a chain, import and ban afterwards
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) headers := makeHeaderChain(blockchain.CurrentHeader(), 4, ethash.NewFaker(), db, 10)
blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) blocks := makeBlockChain(blockchain.CurrentBlock(), 4, ethash.NewFaker(), db, 10)
if full { if full {
if _, err := bc.InsertChain(blocks); err != nil { if _, err = blockchain.InsertChain(blocks); err != nil {
t.Fatalf("failed to import blocks: %v", err) t.Errorf("failed to import blocks: %v", err)
} }
if bc.CurrentBlock().Hash() != blocks[3].Hash() { if blockchain.CurrentBlock().Hash() != blocks[3].Hash() {
t.Errorf("last block hash mismatch: have: %x, want %x", bc.CurrentBlock().Hash(), blocks[3].Header().Hash()) t.Errorf("last block hash mismatch: have: %x, want %x", blockchain.CurrentBlock().Hash(), blocks[3].Header().Hash())
} }
BadHashes[blocks[3].Header().Hash()] = true BadHashes[blocks[3].Header().Hash()] = true
defer func() { delete(BadHashes, blocks[3].Header().Hash()) }() defer func() { delete(BadHashes, blocks[3].Header().Hash()) }()
} else { } else {
if _, err := bc.InsertHeaderChain(headers, 1); err != nil { if _, err = blockchain.InsertHeaderChain(headers, 1); err != nil {
t.Fatalf("failed to import headers: %v", err) t.Errorf("failed to import headers: %v", err)
} }
if bc.CurrentHeader().Hash() != headers[3].Hash() { if blockchain.CurrentHeader().Hash() != headers[3].Hash() {
t.Errorf("last header hash mismatch: have: %x, want %x", bc.CurrentHeader().Hash(), headers[3].Hash()) t.Errorf("last header hash mismatch: have: %x, want %x", blockchain.CurrentHeader().Hash(), headers[3].Hash())
} }
BadHashes[headers[3].Hash()] = true BadHashes[headers[3].Hash()] = true
defer func() { delete(BadHashes, headers[3].Hash()) }() defer func() { delete(BadHashes, headers[3].Hash()) }()
} }
blockchain.Stop()
// Create a new BlockChain and check that it rolled back the state. // Create a new BlockChain and check that it rolled back the state.
ncm, err := NewBlockChain(bc.db, nil, bc.chainConfig, ethash.NewFaker(), vm.Config{}) ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{})
if err != nil { if err != nil {
t.Fatalf("failed to create new chain manager: %v", err) t.Fatalf("failed to create new chain manager: %v", err)
} }
defer ncm.Stop()
if full { if full {
if ncm.CurrentBlock().Hash() != blocks[2].Header().Hash() { if ncm.CurrentBlock().Hash() != blocks[2].Header().Hash() {
t.Errorf("last block hash mismatch: have: %x, want %x", ncm.CurrentBlock().Hash(), blocks[2].Header().Hash()) t.Errorf("last block hash mismatch: have: %x, want %x", ncm.CurrentBlock().Hash(), blocks[2].Header().Hash())
@ -514,6 +504,7 @@ func testReorgBadHashes(t *testing.T, full bool) {
t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash()) t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash())
} }
} }
ncm.Stop()
} }
// Tests chain insertions in the face of one entity containing an invalid nonce. // Tests chain insertions in the face of one entity containing an invalid nonce.
@ -989,10 +980,13 @@ done:
// Tests if the canonical block can be fetched from the database during chain insertion. // Tests if the canonical block can be fetched from the database during chain insertion.
func TestCanonicalBlockRetrieval(t *testing.T) { func TestCanonicalBlockRetrieval(t *testing.T) {
bc := newTestBlockChain(true) _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true)
defer bc.Stop() if err != nil {
t.Fatalf("failed to create pristine chain: %v", err)
}
defer blockchain.Stop()
chain, _ := GenerateChain(bc.chainConfig, bc.genesisBlock, ethash.NewFaker(), bc.db, 10, func(i int, gen *BlockGen) {}) chain, _ := GenerateChain(blockchain.chainConfig, blockchain.genesisBlock, ethash.NewFaker(), blockchain.db, 10, func(i int, gen *BlockGen) {})
var pend sync.WaitGroup var pend sync.WaitGroup
pend.Add(len(chain)) pend.Add(len(chain))
@ -1003,14 +997,14 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
// try to retrieve a block by its canonical hash and see if the block data can be retrieved. // try to retrieve a block by its canonical hash and see if the block data can be retrieved.
for { for {
ch := GetCanonicalHash(bc.db, block.NumberU64()) ch := GetCanonicalHash(blockchain.db, block.NumberU64())
if ch == (common.Hash{}) { if ch == (common.Hash{}) {
continue // busy wait for canonical hash to be written continue // busy wait for canonical hash to be written
} }
if ch != block.Hash() { if ch != block.Hash() {
t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex()) t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())
} }
fb := GetBlock(bc.db, ch, block.NumberU64()) fb := GetBlock(blockchain.db, ch, block.NumberU64())
if fb == nil { if fb == nil {
t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex()) t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())
} }
@ -1021,7 +1015,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
} }
}(chain[i]) }(chain[i])
if _, err := bc.InsertChain(types.Blocks{chain[i]}); err != nil { if _, err := blockchain.InsertChain(types.Blocks{chain[i]}); err != nil {
t.Fatalf("failed to insert block %d: %v", i, err) t.Fatalf("failed to insert block %d: %v", i, err)
} }
} }

View file

@ -70,8 +70,8 @@ var (
ErrChainConfigNotFound = errors.New("ChainConfig not found") // general config not found error ErrChainConfigNotFound = errors.New("ChainConfig not found") // general config not found error
preimageCounter = metrics.NewCounter("db/preimage/total") preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil)
preimageHitCounter = metrics.NewCounter("db/preimage/hits") preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil)
) )
// TxLookupEntry is a positional metadata to help looking up the data content of // TxLookupEntry is a positional metadata to help looking up the data content of

View file

@ -1,23 +0,0 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"math/big"
)
var BlockReward = big.NewInt(5e+18)

View file

@ -118,10 +118,12 @@ func TestSetupGenesis(t *testing.T) {
// Commit the 'old' genesis block with Homestead transition at #2. // Commit the 'old' genesis block with Homestead transition at #2.
// Advance to block #4, past the homestead transition block of customg. // Advance to block #4, past the homestead transition block of customg.
genesis := oldcustomg.MustCommit(db) genesis := oldcustomg.MustCommit(db)
bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}) bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{})
defer bc.Stop() defer bc.Stop()
bc.SetValidator(bproc{})
bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0)) blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
bc.InsertChain(blocks)
bc.CurrentBlock() bc.CurrentBlock()
// This should return a compatibility error. // This should return a compatibility error.
return SetupGenesisBlock(db, &customg) return SetupGenesisBlock(db, &customg)

View file

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/hashicorp/golang-lru" "github.com/hashicorp/golang-lru"
"sync/atomic"
) )
const ( const (
@ -51,8 +52,8 @@ type HeaderChain struct {
chainDb ethdb.Database chainDb ethdb.Database
genesisHeader *types.Header genesisHeader *types.Header
currentHeader *types.Header // Current head of the header chain (may be above the block chain!) currentHeader atomic.Value // Current head of the header chain (may be above the block chain!)
currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time) currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time)
headerCache *lru.Cache // Cache for the most recent block headers headerCache *lru.Cache // Cache for the most recent block headers
tdCache *lru.Cache // Cache for the most recent block total difficulties tdCache *lru.Cache // Cache for the most recent block total difficulties
@ -95,13 +96,13 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
return nil, ErrNoGenesis return nil, ErrNoGenesis
} }
hc.currentHeader = hc.genesisHeader hc.currentHeader.Store(hc.genesisHeader)
if head := GetHeadBlockHash(chainDb); head != (common.Hash{}) { if head := GetHeadBlockHash(chainDb); head != (common.Hash{}) {
if chead := hc.GetHeaderByHash(head); chead != nil { if chead := hc.GetHeaderByHash(head); chead != nil {
hc.currentHeader = chead hc.currentHeader.Store(chead)
} }
} }
hc.currentHeaderHash = hc.currentHeader.Hash() hc.currentHeaderHash = hc.CurrentHeader().Hash()
return hc, nil return hc, nil
} }
@ -139,7 +140,7 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
if ptd == nil { if ptd == nil {
return NonStatTy, consensus.ErrUnknownAncestor return NonStatTy, consensus.ErrUnknownAncestor
} }
localTd := hc.GetTd(hc.currentHeaderHash, hc.currentHeader.Number.Uint64()) localTd := hc.GetTd(hc.currentHeaderHash, hc.CurrentHeader().Number.Uint64())
externTd := new(big.Int).Add(header.Difficulty, ptd) externTd := new(big.Int).Add(header.Difficulty, ptd)
// Irrelevant of the canonical status, write the td and header to the database // Irrelevant of the canonical status, write the td and header to the database
@ -181,7 +182,8 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil { if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil {
log.Crit("Failed to insert head header hash", "err", err) log.Crit("Failed to insert head header hash", "err", err)
} }
hc.currentHeaderHash, hc.currentHeader = hash, types.CopyHeader(header) hc.currentHeaderHash = hash
hc.currentHeader.Store(types.CopyHeader(header))
status = CanonStatTy status = CanonStatTy
} else { } else {
@ -383,7 +385,7 @@ func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
// CurrentHeader retrieves the current head header of the canonical chain. The // CurrentHeader retrieves the current head header of the canonical chain. The
// header is retrieved from the HeaderChain's internal cache. // header is retrieved from the HeaderChain's internal cache.
func (hc *HeaderChain) CurrentHeader() *types.Header { func (hc *HeaderChain) CurrentHeader() *types.Header {
return hc.currentHeader return hc.currentHeader.Load().(*types.Header)
} }
// SetCurrentHeader sets the current head header of the canonical chain. // SetCurrentHeader sets the current head header of the canonical chain.
@ -391,7 +393,7 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
if err := WriteHeadHeaderHash(hc.chainDb, head.Hash()); err != nil { if err := WriteHeadHeaderHash(hc.chainDb, head.Hash()); err != nil {
log.Crit("Failed to insert head header hash", "err", err) log.Crit("Failed to insert head header hash", "err", err)
} }
hc.currentHeader = head hc.currentHeader.Store(head)
hc.currentHeaderHash = head.Hash() hc.currentHeaderHash = head.Hash()
} }
@ -403,19 +405,20 @@ type DeleteCallback func(common.Hash, uint64)
// will be deleted and the new one set. // will be deleted and the new one set.
func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) { func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
height := uint64(0) height := uint64(0)
if hc.currentHeader != nil {
height = hc.currentHeader.Number.Uint64() if hdr := hc.CurrentHeader(); hdr != nil {
height = hdr.Number.Uint64()
} }
for hc.currentHeader != nil && hc.currentHeader.Number.Uint64() > head { for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number.Uint64() > head; hdr = hc.CurrentHeader() {
hash := hc.currentHeader.Hash() hash := hdr.Hash()
num := hc.currentHeader.Number.Uint64() num := hdr.Number.Uint64()
if delFn != nil { if delFn != nil {
delFn(hash, num) delFn(hash, num)
} }
DeleteHeader(hc.chainDb, hash, num) DeleteHeader(hc.chainDb, hash, num)
DeleteTd(hc.chainDb, hash, num) DeleteTd(hc.chainDb, hash, num)
hc.currentHeader = hc.GetHeader(hc.currentHeader.ParentHash, hc.currentHeader.Number.Uint64()-1) hc.currentHeader.Store(hc.GetHeader(hdr.ParentHash, hdr.Number.Uint64()-1))
} }
// Roll back the canonical chain numbering // Roll back the canonical chain numbering
for i := height; i > head; i-- { for i := height; i > head; i-- {
@ -426,10 +429,10 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
hc.tdCache.Purge() hc.tdCache.Purge()
hc.numberCache.Purge() hc.numberCache.Purge()
if hc.currentHeader == nil { if hc.CurrentHeader() == nil {
hc.currentHeader = hc.genesisHeader hc.currentHeader.Store(hc.genesisHeader)
} }
hc.currentHeaderHash = hc.currentHeader.Hash() hc.currentHeaderHash = hc.CurrentHeader().Hash()
if err := WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash); err != nil { if err := WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash); err != nil {
log.Crit("Failed to reset head header hash", "err", err) log.Crit("Failed to reset head header hash", "err", err)

View file

@ -215,6 +215,9 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
// Pay intrinsic gas // Pay intrinsic gas
gas, err := IntrinsicGas(st.data, contractCreation, homestead) gas, err := IntrinsicGas(st.data, contractCreation, homestead)
if err != nil {
return nil, 0, false, err
}
if err = st.useGas(gas); err != nil { if err = st.useGas(gas); err != nil {
return nil, 0, false, err return nil, 0, false, err
} }

View file

@ -87,20 +87,20 @@ var (
var ( var (
// Metrics for the pending pool // Metrics for the pending pool
pendingDiscardCounter = metrics.NewCounter("txpool/pending/discard") pendingDiscardCounter = metrics.NewRegisteredCounter("txpool/pending/discard", nil)
pendingReplaceCounter = metrics.NewCounter("txpool/pending/replace") pendingReplaceCounter = metrics.NewRegisteredCounter("txpool/pending/replace", nil)
pendingRateLimitCounter = metrics.NewCounter("txpool/pending/ratelimit") // Dropped due to rate limiting pendingRateLimitCounter = metrics.NewRegisteredCounter("txpool/pending/ratelimit", nil) // Dropped due to rate limiting
pendingNofundsCounter = metrics.NewCounter("txpool/pending/nofunds") // Dropped due to out-of-funds pendingNofundsCounter = metrics.NewRegisteredCounter("txpool/pending/nofunds", nil) // Dropped due to out-of-funds
// Metrics for the queued pool // Metrics for the queued pool
queuedDiscardCounter = metrics.NewCounter("txpool/queued/discard") queuedDiscardCounter = metrics.NewRegisteredCounter("txpool/queued/discard", nil)
queuedReplaceCounter = metrics.NewCounter("txpool/queued/replace") queuedReplaceCounter = metrics.NewRegisteredCounter("txpool/queued/replace", nil)
queuedRateLimitCounter = metrics.NewCounter("txpool/queued/ratelimit") // Dropped due to rate limiting queuedRateLimitCounter = metrics.NewRegisteredCounter("txpool/queued/ratelimit", nil) // Dropped due to rate limiting
queuedNofundsCounter = metrics.NewCounter("txpool/queued/nofunds") // Dropped due to out-of-funds queuedNofundsCounter = metrics.NewRegisteredCounter("txpool/queued/nofunds", nil) // Dropped due to out-of-funds
// General tx metrics // General tx metrics
invalidTxCounter = metrics.NewCounter("txpool/invalid") invalidTxCounter = metrics.NewRegisteredCounter("txpool/invalid", nil)
underpricedTxCounter = metrics.NewCounter("txpool/underpriced") underpricedTxCounter = metrics.NewRegisteredCounter("txpool/underpriced", nil)
) )
// TxStatus is the current status of a transaction as seen by the pool. // TxStatus is the current status of a transaction as seen by the pool.

View file

@ -1,3 +1,19 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm package vm
import ( import (

View file

@ -302,6 +302,66 @@ func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
return nil, nil return nil, nil
} }
// opSHL implements Shift Left
// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the left by arg1 number of bits.
func opSHL(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
shift, value := math.U256(stack.pop()), math.U256(stack.peek())
defer evm.interpreter.intPool.put(shift) // First operand back into the pool
if shift.Cmp(common.Big256) >= 0 {
value.SetUint64(0)
return nil, nil
}
n := uint(shift.Uint64())
math.U256(value.Lsh(value, n))
return nil, nil
}
// opSHR implements Logical Shift Right
// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
func opSHR(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
shift, value := math.U256(stack.pop()), math.U256(stack.peek())
defer evm.interpreter.intPool.put(shift) // First operand back into the pool
if shift.Cmp(common.Big256) >= 0 {
value.SetUint64(0)
return nil, nil
}
n := uint(shift.Uint64())
math.U256(value.Rsh(value, n))
return nil, nil
}
// opSAR implements Arithmetic Shift Right
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension.
func opSAR(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one
shift, value := math.U256(stack.pop()), math.S256(stack.pop())
defer evm.interpreter.intPool.put(shift) // First operand back into the pool
if shift.Cmp(common.Big256) >= 0 {
if value.Sign() > 0 {
value.SetUint64(0)
} else {
value.SetInt64(-1)
}
stack.push(math.U256(value))
return nil, nil
}
n := uint(shift.Uint64())
value.Rsh(value, n)
stack.push(math.U256(value))
return nil, nil
}
func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset, size := stack.pop(), stack.pop() offset, size := stack.pop(), stack.pop()
data := memory.Get(offset.Int64(), size.Int64()) data := memory.Get(offset.Int64(), size.Int64())

View file

@ -1,3 +1,19 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm package vm
import ( import (
@ -8,6 +24,48 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
type twoOperandTest struct {
x string
y string
expected string
}
func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
stack = newstack()
pc = uint64(0)
)
for i, test := range tests {
x := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
shift := new(big.Int).SetBytes(common.Hex2Bytes(test.y))
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.expected))
stack.push(x)
stack.push(shift)
opFn(&pc, env, nil, nil, stack)
actual := stack.pop()
if actual.Cmp(expected) != 0 {
t.Errorf("Testcase %d, expected %v, got %v", i, expected, actual)
}
// Check pool usage
// 1.pool is not allowed to contain anything on the stack
// 2.pool is not allowed to contain the same pointers twice
if env.interpreter.intPool.pool.len() > 0 {
poolvals := make(map[*big.Int]struct{})
poolvals[actual] = struct{}{}
for env.interpreter.intPool.pool.len() > 0 {
key := env.interpreter.intPool.get()
if _, exist := poolvals[key]; exist {
t.Errorf("Testcase %d, pool contains double-entry", i)
}
poolvals[key] = struct{}{}
}
}
}
}
func TestByteOp(t *testing.T) { func TestByteOp(t *testing.T) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
@ -41,6 +99,98 @@ func TestByteOp(t *testing.T) {
} }
} }
func TestSHL(t *testing.T) {
// Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shl-shift-left
tests := []twoOperandTest{
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000002"},
{"0000000000000000000000000000000000000000000000000000000000000001", "ff", "8000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "0101", "0000000000000000000000000000000000000000000000000000000000000000"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "8000000000000000000000000000000000000000000000000000000000000000"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"},
}
testTwoOperandOp(t, tests, opSHL)
}
func TestSHR(t *testing.T) {
// Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shr-logical-shift-right
tests := []twoOperandTest{
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000000", "01", "4000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000000", "ff", "0000000000000000000000000000000000000000000000000000000000000001"},
{"8000000000000000000000000000000000000000000000000000000000000000", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000000", "0101", "0000000000000000000000000000000000000000000000000000000000000000"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "0000000000000000000000000000000000000000000000000000000000000001"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
}
testTwoOperandOp(t, tests, opSHR)
}
func TestSAR(t *testing.T) {
// Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#sar-arithmetic-shift-right
tests := []twoOperandTest{
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000000", "01", "c000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000000", "ff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"8000000000000000000000000000000000000000000000000000000000000000", "0100", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"8000000000000000000000000000000000000000000000000000000000000000", "0101", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"4000000000000000000000000000000000000000000000000000000000000000", "fe", "0000000000000000000000000000000000000000000000000000000000000001"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "f8", "000000000000000000000000000000000000000000000000000000000000007f"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "fe", "0000000000000000000000000000000000000000000000000000000000000001"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
}
testTwoOperandOp(t, tests, opSAR)
}
func TestSGT(t *testing.T) {
tests := []twoOperandTest{
{"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
{"0000000000000000000000000000000000000000000000000000000000000001", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
}
testTwoOperandOp(t, tests, opSgt)
}
func TestSLT(t *testing.T) {
tests := []twoOperandTest{
{"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
}
testTwoOperandOp(t, tests, opSlt)
}
func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) { func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
@ -243,3 +393,22 @@ func BenchmarkOpMulmod(b *testing.B) {
opBenchmark(b, opMulmod, x, y, z) opBenchmark(b, opMulmod, x, y, z)
} }
func BenchmarkOpSHL(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
y := "ff"
opBenchmark(b, opSHL, x, y)
}
func BenchmarkOpSHR(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
y := "ff"
opBenchmark(b, opSHR, x, y)
}
func BenchmarkOpSAR(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
y := "ff"
opBenchmark(b, opSAR, x, y)
}

View file

@ -20,9 +20,7 @@ import (
"fmt" "fmt"
"sync/atomic" "sync/atomic"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -70,6 +68,8 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
// we'll set the default jump table. // we'll set the default jump table.
if !cfg.JumpTable[STOP].valid { if !cfg.JumpTable[STOP].valid {
switch { switch {
case evm.ChainConfig().IsConstantinople(evm.BlockNumber):
cfg.JumpTable = constantinopleInstructionSet
case evm.ChainConfig().IsByzantium(evm.BlockNumber): case evm.ChainConfig().IsByzantium(evm.BlockNumber):
cfg.JumpTable = byzantiumInstructionSet cfg.JumpTable = byzantiumInstructionSet
case evm.ChainConfig().IsHomestead(evm.BlockNumber): case evm.ChainConfig().IsHomestead(evm.BlockNumber):
@ -123,11 +123,6 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er
return nil, nil return nil, nil
} }
codehash := contract.CodeHash // codehash is used when doing jump dest caching
if codehash == (common.Hash{}) {
codehash = crypto.Keccak256Hash(contract.Code)
}
var ( var (
op OpCode // current opcode op OpCode // current opcode
mem = NewMemory() // bound memory mem = NewMemory() // bound memory

View file

@ -51,11 +51,38 @@ type operation struct {
} }
var ( var (
frontierInstructionSet = NewFrontierInstructionSet() frontierInstructionSet = NewFrontierInstructionSet()
homesteadInstructionSet = NewHomesteadInstructionSet() homesteadInstructionSet = NewHomesteadInstructionSet()
byzantiumInstructionSet = NewByzantiumInstructionSet() byzantiumInstructionSet = NewByzantiumInstructionSet()
constantinopleInstructionSet = NewConstantinopleInstructionSet()
) )
// NewConstantinopleInstructionSet returns the frontier, homestead
// byzantium and contantinople instructions.
func NewConstantinopleInstructionSet() [256]operation {
// instructions that can be executed during the byzantium phase.
instructionSet := NewByzantiumInstructionSet()
instructionSet[SHL] = operation{
execute: opSHL,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
}
instructionSet[SHR] = operation{
execute: opSHR,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
}
instructionSet[SAR] = operation{
execute: opSAR,
gasCost: constGasFunc(GasFastestStep),
validateStack: makeStackFunc(2, 1),
valid: true,
}
return instructionSet
}
// NewByzantiumInstructionSet returns the frontier, homestead and // NewByzantiumInstructionSet returns the frontier, homestead and
// byzantium instructions. // byzantium instructions.
func NewByzantiumInstructionSet() [256]operation { func NewByzantiumInstructionSet() [256]operation {

View file

@ -63,6 +63,9 @@ const (
XOR XOR
NOT NOT
BYTE BYTE
SHL
SHR
SAR
SHA3 = 0x20 SHA3 = 0x20
) )
@ -234,6 +237,9 @@ var opCodeToString = map[OpCode]string{
OR: "OR", OR: "OR",
XOR: "XOR", XOR: "XOR",
BYTE: "BYTE", BYTE: "BYTE",
SHL: "SHL",
SHR: "SHR",
SAR: "SAR",
ADDMOD: "ADDMOD", ADDMOD: "ADDMOD",
MULMOD: "MULMOD", MULMOD: "MULMOD",
@ -400,6 +406,9 @@ var stringToOp = map[string]OpCode{
"OR": OR, "OR": OR,
"XOR": XOR, "XOR": XOR,
"BYTE": BYTE, "BYTE": BYTE,
"SHL": SHL,
"SHR": SHR,
"SAR": SAR,
"ADDMOD": ADDMOD, "ADDMOD": ADDMOD,
"MULMOD": MULMOD, "MULMOD": MULMOD,
"SHA3": SHA3, "SHA3": SHA3,

View file

@ -36,10 +36,10 @@ import (
"github.com/elastic/gosigar" "github.com/elastic/gosigar"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/rcrowley/go-metrics"
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )

View file

@ -104,6 +104,18 @@ func (b *EthApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash)
return core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)), nil return core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)), nil
} }
func (b *EthApiBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) {
receipts := core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash))
if receipts == nil {
return nil, nil
}
logs := make([][]*types.Log, len(receipts))
for i, receipt := range receipts {
logs[i] = receipt.Logs
}
return logs, nil
}
func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int { func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(blockHash) return b.eth.blockchain.GetTdByHash(blockHash)
} }

View file

@ -1,4 +1,4 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify

View file

@ -31,8 +31,8 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/rcrowley/go-metrics"
) )
var ( var (
@ -173,8 +173,8 @@ type LightChain interface {
type BlockChain interface { type BlockChain interface {
LightChain LightChain
// HasBlockAndState verifies block and associated states' presence in the local chain. // HasBlock verifies a block's presence in the local chain.
HasBlockAndState(common.Hash, uint64) bool HasBlock(common.Hash, uint64) bool
// GetBlockByHash retrieves a block from the local chain. // GetBlockByHash retrieves a block from the local chain.
GetBlockByHash(common.Hash) *types.Block GetBlockByHash(common.Hash) *types.Block
@ -266,7 +266,6 @@ func (d *Downloader) Synchronising() bool {
// RegisterPeer injects a new download peer into the set of block source to be // RegisterPeer injects a new download peer into the set of block source to be
// used for fetching hashes and blocks from. // used for fetching hashes and blocks from.
func (d *Downloader) RegisterPeer(id string, version int, peer Peer) error { func (d *Downloader) RegisterPeer(id string, version int, peer Peer) error {
logger := log.New("peer", id) logger := log.New("peer", id)
logger.Trace("Registering sync peer") logger.Trace("Registering sync peer")
if err := d.peers.Register(newPeerConnection(id, version, peer, logger)); err != nil { if err := d.peers.Register(newPeerConnection(id, version, peer, logger)); err != nil {
@ -583,7 +582,6 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
// Figure out the valid ancestor range to prevent rewrite attacks // Figure out the valid ancestor range to prevent rewrite attacks
floor, ceil := int64(-1), d.lightchain.CurrentHeader().Number.Uint64() floor, ceil := int64(-1), d.lightchain.CurrentHeader().Number.Uint64()
p.log.Debug("Looking for common ancestor", "local", ceil, "remote", height)
if d.mode == FullSync { if d.mode == FullSync {
ceil = d.blockchain.CurrentBlock().NumberU64() ceil = d.blockchain.CurrentBlock().NumberU64()
} else if d.mode == FastSync { } else if d.mode == FastSync {
@ -592,6 +590,8 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
if ceil >= MaxForkAncestry { if ceil >= MaxForkAncestry {
floor = int64(ceil - MaxForkAncestry) floor = int64(ceil - MaxForkAncestry)
} }
p.log.Debug("Looking for common ancestor", "local", ceil, "remote", height)
// Request the topmost blocks to short circuit binary ancestor lookup // Request the topmost blocks to short circuit binary ancestor lookup
head := ceil head := ceil
if head > height { if head > height {
@ -647,7 +647,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
continue continue
} }
// Otherwise check if we already know the header or not // Otherwise check if we already know the header or not
if (d.mode == FullSync && d.blockchain.HasBlockAndState(headers[i].Hash(), headers[i].Number.Uint64())) || (d.mode != FullSync && d.lightchain.HasHeader(headers[i].Hash(), headers[i].Number.Uint64())) { if (d.mode == FullSync && d.blockchain.HasBlock(headers[i].Hash(), headers[i].Number.Uint64())) || (d.mode != FullSync && d.lightchain.HasHeader(headers[i].Hash(), headers[i].Number.Uint64())) {
number, hash = headers[i].Number.Uint64(), headers[i].Hash() number, hash = headers[i].Number.Uint64(), headers[i].Hash()
// If every header is known, even future ones, the peer straight out lied about its head // If every header is known, even future ones, the peer straight out lied about its head
@ -712,7 +712,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
arrived = true arrived = true
// Modify the search interval based on the response // Modify the search interval based on the response
if (d.mode == FullSync && !d.blockchain.HasBlockAndState(headers[0].Hash(), headers[0].Number.Uint64())) || (d.mode != FullSync && !d.lightchain.HasHeader(headers[0].Hash(), headers[0].Number.Uint64())) { if (d.mode == FullSync && !d.blockchain.HasBlock(headers[0].Hash(), headers[0].Number.Uint64())) || (d.mode != FullSync && !d.lightchain.HasHeader(headers[0].Hash(), headers[0].Number.Uint64())) {
end = check end = check
break break
} }

View file

@ -221,14 +221,9 @@ func (dl *downloadTester) HasHeader(hash common.Hash, number uint64) bool {
return dl.GetHeaderByHash(hash) != nil return dl.GetHeaderByHash(hash) != nil
} }
// HasBlockAndState checks if a block and associated state is present in the testers canonical chain. // HasBlock checks if a block is present in the testers canonical chain.
func (dl *downloadTester) HasBlockAndState(hash common.Hash, number uint64) bool { func (dl *downloadTester) HasBlock(hash common.Hash, number uint64) bool {
block := dl.GetBlockByHash(hash) return dl.GetBlockByHash(hash) != nil
if block == nil {
return false
}
_, err := dl.stateDb.Get(block.Root().Bytes())
return err == nil
} }
// GetHeader retrieves a header from the testers canonical chain. // GetHeader retrieves a header from the testers canonical chain.

View file

@ -23,21 +23,21 @@ import (
) )
var ( var (
headerInMeter = metrics.NewMeter("eth/downloader/headers/in") headerInMeter = metrics.NewRegisteredMeter("eth/downloader/headers/in", nil)
headerReqTimer = metrics.NewTimer("eth/downloader/headers/req") headerReqTimer = metrics.NewRegisteredTimer("eth/downloader/headers/req", nil)
headerDropMeter = metrics.NewMeter("eth/downloader/headers/drop") headerDropMeter = metrics.NewRegisteredMeter("eth/downloader/headers/drop", nil)
headerTimeoutMeter = metrics.NewMeter("eth/downloader/headers/timeout") headerTimeoutMeter = metrics.NewRegisteredMeter("eth/downloader/headers/timeout", nil)
bodyInMeter = metrics.NewMeter("eth/downloader/bodies/in") bodyInMeter = metrics.NewRegisteredMeter("eth/downloader/bodies/in", nil)
bodyReqTimer = metrics.NewTimer("eth/downloader/bodies/req") bodyReqTimer = metrics.NewRegisteredTimer("eth/downloader/bodies/req", nil)
bodyDropMeter = metrics.NewMeter("eth/downloader/bodies/drop") bodyDropMeter = metrics.NewRegisteredMeter("eth/downloader/bodies/drop", nil)
bodyTimeoutMeter = metrics.NewMeter("eth/downloader/bodies/timeout") bodyTimeoutMeter = metrics.NewRegisteredMeter("eth/downloader/bodies/timeout", nil)
receiptInMeter = metrics.NewMeter("eth/downloader/receipts/in") receiptInMeter = metrics.NewRegisteredMeter("eth/downloader/receipts/in", nil)
receiptReqTimer = metrics.NewTimer("eth/downloader/receipts/req") receiptReqTimer = metrics.NewRegisteredTimer("eth/downloader/receipts/req", nil)
receiptDropMeter = metrics.NewMeter("eth/downloader/receipts/drop") receiptDropMeter = metrics.NewRegisteredMeter("eth/downloader/receipts/drop", nil)
receiptTimeoutMeter = metrics.NewMeter("eth/downloader/receipts/timeout") receiptTimeoutMeter = metrics.NewRegisteredMeter("eth/downloader/receipts/timeout", nil)
stateInMeter = metrics.NewMeter("eth/downloader/states/in") stateInMeter = metrics.NewRegisteredMeter("eth/downloader/states/in", nil)
stateDropMeter = metrics.NewMeter("eth/downloader/states/drop") stateDropMeter = metrics.NewRegisteredMeter("eth/downloader/states/drop", nil)
) )

View file

@ -28,7 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/rcrowley/go-metrics" "github.com/ethereum/go-ethereum/metrics"
"gopkg.in/karalabe/cookiejar.v2/collections/prque" "gopkg.in/karalabe/cookiejar.v2/collections/prque"
) )

View file

@ -23,21 +23,21 @@ import (
) )
var ( var (
propAnnounceInMeter = metrics.NewMeter("eth/fetcher/prop/announces/in") propAnnounceInMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/announces/in", nil)
propAnnounceOutTimer = metrics.NewTimer("eth/fetcher/prop/announces/out") propAnnounceOutTimer = metrics.NewRegisteredTimer("eth/fetcher/prop/announces/out", nil)
propAnnounceDropMeter = metrics.NewMeter("eth/fetcher/prop/announces/drop") propAnnounceDropMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/announces/drop", nil)
propAnnounceDOSMeter = metrics.NewMeter("eth/fetcher/prop/announces/dos") propAnnounceDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/announces/dos", nil)
propBroadcastInMeter = metrics.NewMeter("eth/fetcher/prop/broadcasts/in") propBroadcastInMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/broadcasts/in", nil)
propBroadcastOutTimer = metrics.NewTimer("eth/fetcher/prop/broadcasts/out") propBroadcastOutTimer = metrics.NewRegisteredTimer("eth/fetcher/prop/broadcasts/out", nil)
propBroadcastDropMeter = metrics.NewMeter("eth/fetcher/prop/broadcasts/drop") propBroadcastDropMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/broadcasts/drop", nil)
propBroadcastDOSMeter = metrics.NewMeter("eth/fetcher/prop/broadcasts/dos") propBroadcastDOSMeter = metrics.NewRegisteredMeter("eth/fetcher/prop/broadcasts/dos", nil)
headerFetchMeter = metrics.NewMeter("eth/fetcher/fetch/headers") headerFetchMeter = metrics.NewRegisteredMeter("eth/fetcher/fetch/headers", nil)
bodyFetchMeter = metrics.NewMeter("eth/fetcher/fetch/bodies") bodyFetchMeter = metrics.NewRegisteredMeter("eth/fetcher/fetch/bodies", nil)
headerFilterInMeter = metrics.NewMeter("eth/fetcher/filter/headers/in") headerFilterInMeter = metrics.NewRegisteredMeter("eth/fetcher/filter/headers/in", nil)
headerFilterOutMeter = metrics.NewMeter("eth/fetcher/filter/headers/out") headerFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/filter/headers/out", nil)
bodyFilterInMeter = metrics.NewMeter("eth/fetcher/filter/bodies/in") bodyFilterInMeter = metrics.NewRegisteredMeter("eth/fetcher/filter/bodies/in", nil)
bodyFilterOutMeter = metrics.NewMeter("eth/fetcher/filter/bodies/out") bodyFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/filter/bodies/out", nil)
) )

View file

@ -34,6 +34,7 @@ type Backend interface {
EventMux() *event.TypeMux EventMux() *event.TypeMux
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
@ -201,16 +202,28 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e
// match the filter criteria. This function is called when the bloom filter signals a potential match. // match the filter criteria. This function is called when the bloom filter signals a potential match.
func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs []*types.Log, err error) { func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs []*types.Log, err error) {
// Get the logs of the block // Get the logs of the block
receipts, err := f.backend.GetReceipts(ctx, header.Hash()) logsList, err := f.backend.GetLogs(ctx, header.Hash())
if err != nil { if err != nil {
return nil, err return nil, err
} }
var unfiltered []*types.Log var unfiltered []*types.Log
for _, receipt := range receipts { for _, logs := range logsList {
unfiltered = append(unfiltered, receipt.Logs...) unfiltered = append(unfiltered, logs...)
} }
logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics) logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics)
if len(logs) > 0 { if len(logs) > 0 {
// We have matching logs, check if we need to resolve full logs via the light client
if logs[0].TxHash == (common.Hash{}) {
receipts, err := f.backend.GetReceipts(ctx, header.Hash())
if err != nil {
return nil, err
}
unfiltered = unfiltered[:0]
for _, receipt := range receipts {
unfiltered = append(unfiltered, receipt.Logs...)
}
logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics)
}
return logs, nil return logs, nil
} }
return nil, nil return nil, nil

View file

@ -375,19 +375,35 @@ func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.
// Get the logs of the block // Get the logs of the block
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel() defer cancel()
receipts, err := es.backend.GetReceipts(ctx, header.Hash()) logsList, err := es.backend.GetLogs(ctx, header.Hash())
if err != nil { if err != nil {
return nil return nil
} }
var unfiltered []*types.Log var unfiltered []*types.Log
for _, receipt := range receipts { for _, logs := range logsList {
for _, log := range receipt.Logs { for _, log := range logs {
logcopy := *log logcopy := *log
logcopy.Removed = remove logcopy.Removed = remove
unfiltered = append(unfiltered, &logcopy) unfiltered = append(unfiltered, &logcopy)
} }
} }
logs := filterLogs(unfiltered, nil, nil, addresses, topics) logs := filterLogs(unfiltered, nil, nil, addresses, topics)
if len(logs) > 0 && logs[0].TxHash == (common.Hash{}) {
// We have matching but non-derived logs
receipts, err := es.backend.GetReceipts(ctx, header.Hash())
if err != nil {
return nil
}
unfiltered = unfiltered[:0]
for _, receipt := range receipts {
for _, log := range receipt.Logs {
logcopy := *log
logcopy.Removed = remove
unfiltered = append(unfiltered, &logcopy)
}
}
logs = filterLogs(unfiltered, nil, nil, addresses, topics)
}
return logs return logs
} }
return nil return nil

View file

@ -69,8 +69,19 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumbe
} }
func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) { func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
num := core.GetBlockNumber(b.db, blockHash) number := core.GetBlockNumber(b.db, blockHash)
return core.GetBlockReceipts(b.db, blockHash, num), nil return core.GetBlockReceipts(b.db, blockHash, number), nil
}
func (b *testBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) {
number := core.GetBlockNumber(b.db, blockHash)
receipts := core.GetBlockReceipts(b.db, blockHash, number)
logs := make([][]*types.Log, len(receipts))
for i, receipt := range receipts {
logs[i] = receipt.Logs
}
return logs, nil
} }
func (b *testBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { func (b *testBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {

View file

@ -249,7 +249,8 @@ func (pm *ProtocolManager) newPeer(pv int, p *p2p.Peer, rw p2p.MsgReadWriter) *p
// handle is the callback invoked to manage the life cycle of an eth peer. When // handle is the callback invoked to manage the life cycle of an eth peer. When
// this function terminates, the peer is disconnected. // this function terminates, the peer is disconnected.
func (pm *ProtocolManager) handle(p *peer) error { func (pm *ProtocolManager) handle(p *peer) error {
if pm.peers.Len() >= pm.maxPeers { // Ignore maxPeers if this is a trusted peer
if pm.peers.Len() >= pm.maxPeers && !p.Peer.Info().Network.Trusted {
return p2p.DiscTooManyPeers return p2p.DiscTooManyPeers
} }
p.Log().Debug("Ethereum peer connected", "name", p.Name()) p.Log().Debug("Ethereum peer connected", "name", p.Name())

View file

@ -22,38 +22,38 @@ import (
) )
var ( var (
propTxnInPacketsMeter = metrics.NewMeter("eth/prop/txns/in/packets") propTxnInPacketsMeter = metrics.NewRegisteredMeter("eth/prop/txns/in/packets", nil)
propTxnInTrafficMeter = metrics.NewMeter("eth/prop/txns/in/traffic") propTxnInTrafficMeter = metrics.NewRegisteredMeter("eth/prop/txns/in/traffic", nil)
propTxnOutPacketsMeter = metrics.NewMeter("eth/prop/txns/out/packets") propTxnOutPacketsMeter = metrics.NewRegisteredMeter("eth/prop/txns/out/packets", nil)
propTxnOutTrafficMeter = metrics.NewMeter("eth/prop/txns/out/traffic") propTxnOutTrafficMeter = metrics.NewRegisteredMeter("eth/prop/txns/out/traffic", nil)
propHashInPacketsMeter = metrics.NewMeter("eth/prop/hashes/in/packets") propHashInPacketsMeter = metrics.NewRegisteredMeter("eth/prop/hashes/in/packets", nil)
propHashInTrafficMeter = metrics.NewMeter("eth/prop/hashes/in/traffic") propHashInTrafficMeter = metrics.NewRegisteredMeter("eth/prop/hashes/in/traffic", nil)
propHashOutPacketsMeter = metrics.NewMeter("eth/prop/hashes/out/packets") propHashOutPacketsMeter = metrics.NewRegisteredMeter("eth/prop/hashes/out/packets", nil)
propHashOutTrafficMeter = metrics.NewMeter("eth/prop/hashes/out/traffic") propHashOutTrafficMeter = metrics.NewRegisteredMeter("eth/prop/hashes/out/traffic", nil)
propBlockInPacketsMeter = metrics.NewMeter("eth/prop/blocks/in/packets") propBlockInPacketsMeter = metrics.NewRegisteredMeter("eth/prop/blocks/in/packets", nil)
propBlockInTrafficMeter = metrics.NewMeter("eth/prop/blocks/in/traffic") propBlockInTrafficMeter = metrics.NewRegisteredMeter("eth/prop/blocks/in/traffic", nil)
propBlockOutPacketsMeter = metrics.NewMeter("eth/prop/blocks/out/packets") propBlockOutPacketsMeter = metrics.NewRegisteredMeter("eth/prop/blocks/out/packets", nil)
propBlockOutTrafficMeter = metrics.NewMeter("eth/prop/blocks/out/traffic") propBlockOutTrafficMeter = metrics.NewRegisteredMeter("eth/prop/blocks/out/traffic", nil)
reqHeaderInPacketsMeter = metrics.NewMeter("eth/req/headers/in/packets") reqHeaderInPacketsMeter = metrics.NewRegisteredMeter("eth/req/headers/in/packets", nil)
reqHeaderInTrafficMeter = metrics.NewMeter("eth/req/headers/in/traffic") reqHeaderInTrafficMeter = metrics.NewRegisteredMeter("eth/req/headers/in/traffic", nil)
reqHeaderOutPacketsMeter = metrics.NewMeter("eth/req/headers/out/packets") reqHeaderOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/headers/out/packets", nil)
reqHeaderOutTrafficMeter = metrics.NewMeter("eth/req/headers/out/traffic") reqHeaderOutTrafficMeter = metrics.NewRegisteredMeter("eth/req/headers/out/traffic", nil)
reqBodyInPacketsMeter = metrics.NewMeter("eth/req/bodies/in/packets") reqBodyInPacketsMeter = metrics.NewRegisteredMeter("eth/req/bodies/in/packets", nil)
reqBodyInTrafficMeter = metrics.NewMeter("eth/req/bodies/in/traffic") reqBodyInTrafficMeter = metrics.NewRegisteredMeter("eth/req/bodies/in/traffic", nil)
reqBodyOutPacketsMeter = metrics.NewMeter("eth/req/bodies/out/packets") reqBodyOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/bodies/out/packets", nil)
reqBodyOutTrafficMeter = metrics.NewMeter("eth/req/bodies/out/traffic") reqBodyOutTrafficMeter = metrics.NewRegisteredMeter("eth/req/bodies/out/traffic", nil)
reqStateInPacketsMeter = metrics.NewMeter("eth/req/states/in/packets") reqStateInPacketsMeter = metrics.NewRegisteredMeter("eth/req/states/in/packets", nil)
reqStateInTrafficMeter = metrics.NewMeter("eth/req/states/in/traffic") reqStateInTrafficMeter = metrics.NewRegisteredMeter("eth/req/states/in/traffic", nil)
reqStateOutPacketsMeter = metrics.NewMeter("eth/req/states/out/packets") reqStateOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/states/out/packets", nil)
reqStateOutTrafficMeter = metrics.NewMeter("eth/req/states/out/traffic") reqStateOutTrafficMeter = metrics.NewRegisteredMeter("eth/req/states/out/traffic", nil)
reqReceiptInPacketsMeter = metrics.NewMeter("eth/req/receipts/in/packets") reqReceiptInPacketsMeter = metrics.NewRegisteredMeter("eth/req/receipts/in/packets", nil)
reqReceiptInTrafficMeter = metrics.NewMeter("eth/req/receipts/in/traffic") reqReceiptInTrafficMeter = metrics.NewRegisteredMeter("eth/req/receipts/in/traffic", nil)
reqReceiptOutPacketsMeter = metrics.NewMeter("eth/req/receipts/out/packets") reqReceiptOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/receipts/out/packets", nil)
reqReceiptOutTrafficMeter = metrics.NewMeter("eth/req/receipts/out/traffic") reqReceiptOutTrafficMeter = metrics.NewRegisteredMeter("eth/req/receipts/out/traffic", nil)
miscInPacketsMeter = metrics.NewMeter("eth/misc/in/packets") miscInPacketsMeter = metrics.NewRegisteredMeter("eth/misc/in/packets", nil)
miscInTrafficMeter = metrics.NewMeter("eth/misc/in/traffic") miscInTrafficMeter = metrics.NewRegisteredMeter("eth/misc/in/traffic", nil)
miscOutPacketsMeter = metrics.NewMeter("eth/misc/out/packets") miscOutPacketsMeter = metrics.NewRegisteredMeter("eth/misc/out/packets", nil)
miscOutTrafficMeter = metrics.NewMeter("eth/misc/out/traffic") miscOutTrafficMeter = metrics.NewRegisteredMeter("eth/misc/out/traffic", nil)
) )
// meteredMsgReadWriter is a wrapper around a p2p.MsgReadWriter, capable of // meteredMsgReadWriter is a wrapper around a p2p.MsgReadWriter, capable of

View file

@ -189,18 +189,13 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
mode = downloader.FastSync mode = downloader.FastSync
} }
// Run the sync cycle, and disable fast sync if we've went past the pivot block // Run the sync cycle, and disable fast sync if we've went past the pivot block
err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode) if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
if atomic.LoadUint32(&pm.fastSync) == 1 {
// Disable fast sync if we indeed have something in our chain
if pm.blockchain.CurrentBlock().NumberU64() > 0 {
log.Info("Fast sync complete, auto disabling")
atomic.StoreUint32(&pm.fastSync, 0)
}
}
if err != nil {
return return
} }
if atomic.LoadUint32(&pm.fastSync) == 1 {
log.Info("Fast sync complete, auto disabling")
atomic.StoreUint32(&pm.fastSync, 0)
}
atomic.StoreUint32(&pm.acceptTxs, 1) // Mark initial sync done atomic.StoreUint32(&pm.acceptTxs, 1) // Mark initial sync done
if head := pm.blockchain.CurrentBlock(); head.NumberU64() > 0 { if head := pm.blockchain.CurrentBlock(); head.NumberU64() > 0 {
// We've completed a sync cycle, notify all peers of new state. This path is // We've completed a sync cycle, notify all peers of new state. This path is

View file

@ -1,4 +1,4 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify

View file

@ -29,8 +29,6 @@ import (
"github.com/syndtr/goleveldb/leveldb/filter" "github.com/syndtr/goleveldb/leveldb/filter"
"github.com/syndtr/goleveldb/leveldb/iterator" "github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/opt" "github.com/syndtr/goleveldb/leveldb/opt"
gometrics "github.com/rcrowley/go-metrics"
) )
var OpenFileLimit = 64 var OpenFileLimit = 64
@ -39,15 +37,15 @@ type LDBDatabase struct {
fn string // filename for reporting fn string // filename for reporting
db *leveldb.DB // LevelDB instance db *leveldb.DB // LevelDB instance
getTimer gometrics.Timer // Timer for measuring the database get request counts and latencies getTimer metrics.Timer // Timer for measuring the database get request counts and latencies
putTimer gometrics.Timer // Timer for measuring the database put request counts and latencies putTimer metrics.Timer // Timer for measuring the database put request counts and latencies
delTimer gometrics.Timer // Timer for measuring the database delete request counts and latencies delTimer metrics.Timer // Timer for measuring the database delete request counts and latencies
missMeter gometrics.Meter // Meter for measuring the missed database get requests missMeter metrics.Meter // Meter for measuring the missed database get requests
readMeter gometrics.Meter // Meter for measuring the database get request data usage readMeter metrics.Meter // Meter for measuring the database get request data usage
writeMeter gometrics.Meter // Meter for measuring the database put request data usage writeMeter metrics.Meter // Meter for measuring the database put request data usage
compTimeMeter gometrics.Meter // Meter for measuring the total time spent in database compaction compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction
compReadMeter gometrics.Meter // Meter for measuring the data read during compaction compReadMeter metrics.Meter // Meter for measuring the data read during compaction
compWriteMeter gometrics.Meter // Meter for measuring the data written during compaction compWriteMeter metrics.Meter // Meter for measuring the data written during compaction
quitLock sync.Mutex // Mutex protecting the quit channel access quitLock sync.Mutex // Mutex protecting the quit channel access
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
@ -180,15 +178,15 @@ func (db *LDBDatabase) Meter(prefix string) {
return return
} }
// Initialize all the metrics collector at the requested prefix // Initialize all the metrics collector at the requested prefix
db.getTimer = metrics.NewTimer(prefix + "user/gets") db.getTimer = metrics.NewRegisteredTimer(prefix+"user/gets", nil)
db.putTimer = metrics.NewTimer(prefix + "user/puts") db.putTimer = metrics.NewRegisteredTimer(prefix+"user/puts", nil)
db.delTimer = metrics.NewTimer(prefix + "user/dels") db.delTimer = metrics.NewRegisteredTimer(prefix+"user/dels", nil)
db.missMeter = metrics.NewMeter(prefix + "user/misses") db.missMeter = metrics.NewRegisteredMeter(prefix+"user/misses", nil)
db.readMeter = metrics.NewMeter(prefix + "user/reads") db.readMeter = metrics.NewRegisteredMeter(prefix+"user/reads", nil)
db.writeMeter = metrics.NewMeter(prefix + "user/writes") db.writeMeter = metrics.NewRegisteredMeter(prefix+"user/writes", nil)
db.compTimeMeter = metrics.NewMeter(prefix + "compact/time") db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
db.compReadMeter = metrics.NewMeter(prefix + "compact/input") db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
db.compWriteMeter = metrics.NewMeter(prefix + "compact/output") db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
// Create a quit channel for the periodic collector and run it // Create a quit channel for the periodic collector and run it
db.quitLock.Lock() db.quitLock.Lock()

View file

@ -94,7 +94,7 @@ func LocalEnv() Environment {
} }
if env.Branch == "" { if env.Branch == "" {
if head != "HEAD" { if head != "HEAD" {
env.Branch = strings.TrimLeft(head, "refs/heads/") env.Branch = strings.TrimPrefix(head, "refs/heads/")
} }
} }
if info, err := os.Stat(".git/objects"); err == nil && info.IsDir() && env.Tag == "" { if info, err := os.Stat(".git/objects"); err == nil && info.IsDir() && env.Tag == "" {

View file

@ -1,18 +1,18 @@
// Copyright 2016 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of the go-ethereum library.
// //
// go-ethereum is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// go-ethereum is distributed in the hope that it will be useful, // The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU Lesser General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU Lesser General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package cmdtest package cmdtest

View file

@ -26,6 +26,8 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log/term" "github.com/ethereum/go-ethereum/log/term"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/metrics/exp"
colorable "github.com/mattn/go-colorable" colorable "github.com/mattn/go-colorable"
"gopkg.in/urfave/cli.v1" "gopkg.in/urfave/cli.v1"
) )
@ -127,6 +129,10 @@ func Setup(ctx *cli.Context) error {
// pprof server // pprof server
if ctx.GlobalBool(pprofFlag.Name) { if ctx.GlobalBool(pprofFlag.Name) {
// Hook go-metrics into expvar on any /debug/metrics request, load all vars
// from the registry into expvar, and execute regular expvar handler.
exp.Exp(metrics.DefaultRegistry)
address := fmt.Sprintf("%s:%d", ctx.GlobalString(pprofAddrFlag.Name), ctx.GlobalInt(pprofPortFlag.Name)) address := fmt.Sprintf("%s:%d", ctx.GlobalString(pprofAddrFlag.Name), ctx.GlobalInt(pprofPortFlag.Name))
go func() { go func() {
log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address))

View file

@ -1,4 +1,4 @@
// Copyright 2015 The go-ethereum Authors // Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify

View file

@ -1032,15 +1032,19 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
} }
// GetTransactionReceipt returns the transaction receipt for the given transaction hash. // GetTransactionReceipt returns the transaction receipt for the given transaction hash.
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) { func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash) tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash)
if tx == nil { if tx == nil {
return nil, errors.New("unknown transaction") return nil, nil
} }
receipt, _, _, _ := core.GetReceipt(s.b.ChainDb(), hash) // Old receipts don't have the lookup data available receipts, err := s.b.GetReceipts(ctx, blockHash)
if receipt == nil { if err != nil {
return nil, errors.New("unknown receipt") return nil, err
} }
if len(receipts) <= int(index) {
return nil, nil
}
receipt := receipts[index]
var signer types.Signer = types.FrontierSigner{} var signer types.Signer = types.FrontierSigner{}
if tx.Protected() { if tx.Protected() {
@ -1135,6 +1139,18 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
return errors.New(`Both "data" and "input" are set and not equal. Please use "input" to pass transaction call data.`) return errors.New(`Both "data" and "input" are set and not equal. Please use "input" to pass transaction call data.`)
} }
if args.To == nil {
// Contract creation
var input []byte
if args.Data != nil {
input = *args.Data
} else if args.Input != nil {
input = *args.Input
}
if len(input) == 0 {
return errors.New(`contract creation without any data provided`)
}
}
return nil return nil
} }

View file

@ -87,6 +87,10 @@ func (b *LesApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash)
return light.GetBlockReceipts(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)) return light.GetBlockReceipts(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash))
} }
func (b *LesApiBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) {
return light.GetBlockLogs(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash))
}
func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int { func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(blockHash) return b.eth.blockchain.GetTdByHash(blockHash)
} }

View file

@ -36,24 +36,26 @@ const (
maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer
) )
// lightFetcher // lightFetcher implements retrieval of newly announced headers. It also provides a peerHasBlock function for the
// ODR system to ensure that we only request data related to a certain block from peers who have already processed
// and announced that block.
type lightFetcher struct { type lightFetcher struct {
pm *ProtocolManager pm *ProtocolManager
odr *LesOdr odr *LesOdr
chain *light.LightChain chain *light.LightChain
lock sync.Mutex // lock protects access to the fetcher's internal state variables except sent requests
maxConfirmedTd *big.Int maxConfirmedTd *big.Int
peers map[*peer]*fetcherPeerInfo peers map[*peer]*fetcherPeerInfo
lastUpdateStats *updateStatsEntry lastUpdateStats *updateStatsEntry
syncing bool
syncDone chan *peer
lock sync.Mutex // qwerqwerqwe reqMu sync.RWMutex // reqMu protects access to sent header fetch requests
deliverChn chan fetchResponse
reqMu sync.RWMutex
requested map[uint64]fetchRequest requested map[uint64]fetchRequest
deliverChn chan fetchResponse
timeoutChn chan uint64 timeoutChn chan uint64
requestChn chan bool // true if initiated from outside requestChn chan bool // true if initiated from outside
syncing bool
syncDone chan *peer
} }
// fetcherPeerInfo holds fetcher-specific information about each active peer // fetcherPeerInfo holds fetcher-specific information about each active peer
@ -425,6 +427,9 @@ func (f *lightFetcher) nextRequest() (*distReq, uint64) {
}, },
canSend: func(dp distPeer) bool { canSend: func(dp distPeer) bool {
p := dp.(*peer) p := dp.(*peer)
f.lock.Lock()
defer f.lock.Unlock()
fp := f.peers[p] fp := f.peers[p]
return fp != nil && fp.nodeByHash[bestHash] != nil return fp != nil && fp.nodeByHash[bestHash] != nil
}, },
@ -557,8 +562,13 @@ func (f *lightFetcher) checkAnnouncedHeaders(fp *fetcherPeerInfo, headers []*typ
return true return true
} }
// we ran out of recently delivered headers but have not reached a node known by this peer yet, continue matching // we ran out of recently delivered headers but have not reached a node known by this peer yet, continue matching
td = f.chain.GetTd(header.ParentHash, header.Number.Uint64()-1) hash, number := header.ParentHash, header.Number.Uint64()-1
header = f.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) td = f.chain.GetTd(hash, number)
header = f.chain.GetHeader(hash, number)
if header == nil || td == nil {
log.Error("Missing parent of validated header", "hash", hash, "number", number)
return false
}
} else { } else {
header = headers[i] header = headers[i]
td = tds[i] td = tds[i]
@ -642,13 +652,18 @@ func (f *lightFetcher) checkKnownNode(p *peer, n *fetcherTreeNode) bool {
if td == nil { if td == nil {
return false return false
} }
header := f.chain.GetHeader(n.hash, n.number)
// check the availability of both header and td because reads are not protected by chain db mutex
// Note: returning false is always safe here
if header == nil {
return false
}
fp := f.peers[p] fp := f.peers[p]
if fp == nil { if fp == nil {
p.Log().Debug("Unknown peer to check known nodes") p.Log().Debug("Unknown peer to check known nodes")
return false return false
} }
header := f.chain.GetHeader(n.hash, n.number)
if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) { if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) {
p.Log().Debug("Inconsistent announcement") p.Log().Debug("Inconsistent announcement")
go f.pm.removePeer(p.id) go f.pm.removePeer(p.id)

Some files were not shown because too many files have changed in this diff Show more