mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
Merge pull request #9 from ethereum/master
Pull latest changes from geth
This commit is contained in:
commit
fc3d2eb02c
282 changed files with 13356 additions and 4999 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
14
.mailmap
14
.mailmap
|
|
@ -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>
|
||||||
|
|
|
||||||
13
.travis.yml
13
.travis.yml
|
|
@ -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
92
AUTHORS
|
|
@ -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>
|
||||||
|
|
|
||||||
31
README.md
31
README.md
|
|
@ -5,6 +5,8 @@ Official golang implementation of the Ethereum protocol.
|
||||||
[](https://godoc.org/github.com/ethereum/go-ethereum)
|
)](https://godoc.org/github.com/ethereum/go-ethereum)
|
||||||
|
[](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
|
||||||
|
[](https://travis-ci.org/ethereum/go-ethereum)
|
||||||
[](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
[](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.
|
||||||
|
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.8.0
|
1.8.2
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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: `
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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(¶ms)
|
msg, err := whisper.NewSentMessage(¶ms)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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")
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 && \
|
||||||
|
|
|
||||||
|
|
@ -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 && \
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
23
core/fees.go
23
core/fees.go
|
|
@ -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)
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
15
eth/sync.go
15
eth/sync.go
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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 == "" {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Reference in a new issue