Compare commits
150 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
46891c12ab | ||
|
c0010f0220 | ||
|
9f98628dc2 | ||
|
a6a14f6b71 | ||
|
f9eb307216 | ||
|
03c7d8fb31 | ||
|
2becb99583 | ||
|
ad380cd57f | ||
|
7b32d2a470 | ||
|
f40ff23b7b | ||
|
0ac9bbba6c | ||
|
d4dce43bff | ||
|
056183c056 | ||
|
8d41e885e6 | ||
|
8bd64f4a1c | ||
|
b1c3010bf2 | ||
|
aff986958d | ||
|
f49d6e5ec0 | ||
|
223b950944 | ||
|
16f0fb70f1 | ||
|
96fb839133 | ||
|
3b6c9902f3 | ||
|
efe123759a | ||
|
8eb646a96d | ||
|
c02d5bc5a9 | ||
|
71251c7296 | ||
|
2469c4ecd4 | ||
|
39b0b1a1a6 | ||
|
91b7349509 | ||
|
52a967cfab | ||
|
305ed955db | ||
|
72045dff4f | ||
|
46b437f39c | ||
|
72d5a27a39 | ||
|
4f6bf2f1c5 | ||
|
49b86a2859 | ||
|
cea2c80445 | ||
|
67bfc93053 | ||
|
ce2da832ac | ||
|
b4a4a4db71 | ||
|
cfbb969da8 | ||
|
1611815b8d | ||
|
b8a9457139 | ||
|
af16ca177f | ||
|
cedf8be435 | ||
|
d5bd38384c | ||
|
292cf7c649 | ||
|
396f1dd87b | ||
|
68502595f6 | ||
|
a978adfd7c | ||
|
cc9eb91d30 | ||
|
e39b2a2bde | ||
|
c8a1c0a115 | ||
|
4aeeddc658 | ||
|
e126b0836a | ||
|
961aa0533f | ||
|
54b271a86d | ||
|
b90cdbaa79 | ||
|
4d358b9fc0 | ||
|
1eaf66ae60 | ||
|
4ef5e9746b | ||
|
060e33fb4c | ||
|
46ec63b849 | ||
|
1cd5bf080e | ||
|
7c229941ac | ||
|
ac23073619 | ||
|
8e391cec43 | ||
|
5b2c47a575 | ||
|
8517dd463d | ||
|
22fdbee8ed | ||
|
1bccafe5ef | ||
|
2890f060b7 | ||
|
2ed729d38e | ||
|
4aee0d1994 | ||
|
039a9c3622 | ||
|
3bb9b49afb | ||
|
9dfca5df4b | ||
|
273b3741b6 | ||
|
85d2b0d654 | ||
|
7d3b26018b | ||
|
dbb03fe989 | ||
|
2c50b2c904 | ||
|
9bad7fa717 | ||
|
26f538b0e5 | ||
|
260b177fe3 | ||
|
c2c4c9f1e5 | ||
|
44c8b9ad37 | ||
|
eea66ddbbd | ||
|
aaf29095bb | ||
|
e76047e9f5 | ||
|
34d7503d95 | ||
|
9b8d727655 | ||
|
df6c08a485 | ||
|
423fd5877d | ||
|
8657a0d6b5 | ||
|
36994e4e0b | ||
|
c9cdf144d5 | ||
|
081642ed25 | ||
|
17589aa75f | ||
|
3e993ff64a | ||
|
f3478f2899 | ||
|
c55e1b495c | ||
|
f891fd9875 | ||
|
beff5fa578 | ||
|
aa6005b469 | ||
|
a7de796840 | ||
|
947f5f2b15 | ||
|
e46a01d56c | ||
|
7f3362595a | ||
|
140a7e9177 | ||
|
96ab8e1575 | ||
|
f34a3a6805 | ||
|
8812c4d3f9 | ||
|
e4232c153b | ||
|
389bd75142 | ||
|
08e5cd94a9 | ||
|
b7b2f60f86 | ||
|
530f78e22d | ||
|
57d9c93dcd | ||
|
4f56790efc | ||
|
78ab411aac | ||
|
f08eb04896 | ||
|
3b96c17fc1 | ||
|
4ac941a9fc | ||
|
b80c840af3 | ||
|
a32a2b933a | ||
|
04e175b8ec | ||
|
e8141e1685 | ||
|
82985075f7 | ||
|
b973eddd28 | ||
|
1a83114c74 | ||
|
364e485e51 | ||
|
28fea9c5af | ||
|
57fc1d21e1 | ||
|
cc3ef1e4f4 | ||
|
5183483c53 | ||
|
a1f8549262 | ||
|
e8c9579fb7 | ||
|
433cb564e9 | ||
|
8485f7cc7b | ||
|
61a20cb56d | ||
|
f088c650a5 | ||
|
9466b9eec5 | ||
|
4ac04ae0fe | ||
|
8f80cafa10 | ||
|
31a1f164d9 | ||
|
6bd896a97f | ||
|
49a7ee460e | ||
|
252150918c | ||
|
72029f0f88 |
77
.travis.yml
77
.travis.yml
@@ -1,32 +1,48 @@
|
||||
language: go
|
||||
go_import_path: github.com/ethereum/go-ethereum
|
||||
sudo: false
|
||||
matrix:
|
||||
jobs:
|
||||
include:
|
||||
- os: linux
|
||||
# This builder only tests code linters on latest version of Go
|
||||
- stage: lint
|
||||
os: linux
|
||||
dist: xenial
|
||||
go: 1.10.x
|
||||
go: 1.12.x
|
||||
env:
|
||||
- lint
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
script:
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
- go run build/ci.go lint
|
||||
|
||||
- os: linux
|
||||
- stage: build
|
||||
os: linux
|
||||
dist: xenial
|
||||
go: 1.11.x
|
||||
script:
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
|
||||
# These are the latest Go versions.
|
||||
- os: linux
|
||||
- stage: build
|
||||
os: linux
|
||||
dist: xenial
|
||||
go: 1.12.x
|
||||
script:
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
|
||||
- os: osx
|
||||
go: 1.12.x
|
||||
# These are the latest Go versions.
|
||||
- stage: build
|
||||
os: linux
|
||||
dist: xenial
|
||||
go: 1.13.x
|
||||
script:
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
|
||||
- stage: build
|
||||
os: osx
|
||||
go: 1.13.x
|
||||
script:
|
||||
- echo "Increase the maximum number of open file descriptors on macOS"
|
||||
- NOFILE=20480
|
||||
@@ -40,22 +56,12 @@ matrix:
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
|
||||
# This builder only tests code linters on latest version of Go
|
||||
- os: linux
|
||||
dist: xenial
|
||||
go: 1.12.x
|
||||
env:
|
||||
- lint
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
script:
|
||||
- go run build/ci.go lint
|
||||
|
||||
# This builder does the Ubuntu PPA upload
|
||||
- if: type = push
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
dist: xenial
|
||||
go: 1.12.x
|
||||
go: 1.13.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
git:
|
||||
@@ -74,11 +80,12 @@ matrix:
|
||||
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
|
||||
|
||||
# This builder does the Linux Azure uploads
|
||||
- if: type = push
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
dist: xenial
|
||||
sudo: required
|
||||
go: 1.12.x
|
||||
go: 1.13.x
|
||||
env:
|
||||
- azure-linux
|
||||
git:
|
||||
@@ -108,12 +115,13 @@ matrix:
|
||||
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||
|
||||
# This builder does the Linux Azure MIPS xgo uploads
|
||||
- if: type = push
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
dist: xenial
|
||||
services:
|
||||
- docker
|
||||
go: 1.12.x
|
||||
go: 1.13.x
|
||||
env:
|
||||
- azure-linux-mips
|
||||
git:
|
||||
@@ -136,7 +144,8 @@ matrix:
|
||||
- go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||
|
||||
# This builder does the Android Maven and Azure uploads
|
||||
- if: type = push
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
dist: xenial
|
||||
addons:
|
||||
@@ -158,7 +167,7 @@ matrix:
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
before_install:
|
||||
- curl https://dl.google.com/go/go1.12.linux-amd64.tar.gz | tar -xz
|
||||
- curl https://dl.google.com/go/go1.13.linux-amd64.tar.gz | tar -xz
|
||||
- export PATH=`pwd`/go/bin:$PATH
|
||||
- export GOROOT=`pwd`/go
|
||||
- export GOPATH=$HOME/go
|
||||
@@ -173,9 +182,10 @@ matrix:
|
||||
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
|
||||
|
||||
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
||||
- if: type = push
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: osx
|
||||
go: 1.12.x
|
||||
go: 1.13.x
|
||||
env:
|
||||
- azure-osx
|
||||
- azure-ios
|
||||
@@ -202,10 +212,11 @@ matrix:
|
||||
- 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
|
||||
- if: type = cron
|
||||
- stage: build
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: xenial
|
||||
go: 1.12.x
|
||||
go: 1.13.x
|
||||
env:
|
||||
- azure-purge
|
||||
git:
|
||||
|
247
AUTHORS
247
AUTHORS
@@ -1,5 +1,11 @@
|
||||
# This is the official list of go-ethereum authors for copyright purposes.
|
||||
|
||||
a e r t h <aerth@users.noreply.github.com>
|
||||
Abel Nieto <abel.nieto90@gmail.com>
|
||||
Abel Nieto <anietoro@uwaterloo.ca>
|
||||
Adam Babik <a.babik@designfortress.com>
|
||||
Aditya <adityasripal@gmail.com>
|
||||
Adrià Cidre <adria.cidre@gmail.com>
|
||||
Afri Schoedon <5chdn@users.noreply.github.com>
|
||||
Agustin Armellini Fischer <armellini13@gmail.com>
|
||||
Airead <fgh1987168@gmail.com>
|
||||
@@ -10,165 +16,354 @@ Alex Leverington <alex@ethdev.com>
|
||||
Alex Wu <wuyiding@gmail.com>
|
||||
Alexandre Van de Sande <alex.vandesande@ethdev.com>
|
||||
Ali Hajimirza <Ali92hm@users.noreply.github.com>
|
||||
am2rican5 <am2rican5@gmail.com>
|
||||
Andrea Franz <andrea@gravityblast.com>
|
||||
Andrey Petrov <andrey.petrov@shazow.net>
|
||||
Andrey Petrov <shazow@gmail.com>
|
||||
ANOTHEL <anothel1@naver.com>
|
||||
Antoine Rondelet <rondelet.antoine@gmail.com>
|
||||
Anton Evangelatov <anton.evangelatov@gmail.com>
|
||||
Antonio Salazar Cardozo <savedfastcool@gmail.com>
|
||||
Arba Sasmoyo <arba.sasmoyo@gmail.com>
|
||||
Armani Ferrante <armaniferrante@berkeley.edu>
|
||||
Armin Braun <me@obrown.io>
|
||||
Aron Fischer <github@aron.guru>
|
||||
atsushi-ishibashi <atsushi.ishibashi@finatext.com>
|
||||
ayeowch <ayeowch@gmail.com>
|
||||
b00ris <b00ris@mail.ru>
|
||||
bailantaotao <Edwin@maicoin.com>
|
||||
baizhenxuan <nkbai@163.com>
|
||||
Balint Gabor <balint.g@gmail.com>
|
||||
Bas van Kervel <bas@ethdev.com>
|
||||
Benjamin Brent <benjamin@benjaminbrent.com>
|
||||
benma <mbencun@gmail.com>
|
||||
Benoit Verkindt <benoit.verkindt@gmail.com>
|
||||
bloonfield <bloonfield@163.com>
|
||||
Bo <bohende@gmail.com>
|
||||
Bo Ye <boy.e.computer.1982@outlook.com>
|
||||
Bob Glickstein <bobg@users.noreply.github.com>
|
||||
Brent <bmperrea@gmail.com>
|
||||
Brian Schroeder <bts@gmail.com>
|
||||
Bruno Škvorc <bruno@skvorc.me>
|
||||
C. Brown <hackdom@majoolr.io>
|
||||
Caesar Chad <BLUE.WEB.GEEK@gmail.com>
|
||||
Casey Detrio <cdetrio@gmail.com>
|
||||
CDsigma <cdsigma271@gmail.com>
|
||||
changhong <changhong.yu@shanbay.com>
|
||||
Chase Wright <mysticryuujin@gmail.com>
|
||||
Chen Quan <terasum@163.com>
|
||||
chenyufeng <yufengcode@gmail.com>
|
||||
Christian Muehlhaeuser <muesli@gmail.com>
|
||||
Christoph Jentzsch <jentzsch.software@gmail.com>
|
||||
cong <ackratos@users.noreply.github.com>
|
||||
Corey Lin <514971757@qq.com>
|
||||
cpusoft <cpusoft@live.com>
|
||||
Crispin Flowerday <crispin@bitso.com>
|
||||
croath <croathliu@gmail.com>
|
||||
cui <523516579@qq.com>
|
||||
Dan Kinsley <dan@joincivil.com>
|
||||
Daniel A. Nagy <nagy.da@gmail.com>
|
||||
Daniel Sloof <goapsychadelic@gmail.com>
|
||||
Darrel Herbst <dherbst@gmail.com>
|
||||
Dave Appleton <calistralabs@gmail.com>
|
||||
Dave McGregor <dave.s.mcgregor@gmail.com>
|
||||
David Huie <dahuie@gmail.com>
|
||||
Derek Gottfrid <derek@codecubed.com>
|
||||
Diego Siqueira <DiSiqueira@users.noreply.github.com>
|
||||
Diep Pham <mrfavadi@gmail.com>
|
||||
dipingxian2 <39109351+dipingxian2@users.noreply.github.com>
|
||||
dm4 <sunrisedm4@gmail.com>
|
||||
Dmitrij Koniajev <dimchansky@gmail.com>
|
||||
Dmitry Shulyak <yashulyak@gmail.com>
|
||||
Domino Valdano <dominoplural@gmail.com>
|
||||
Domino Valdano <jeff@okcupid.com>
|
||||
Dragan Milic <dragan@netice9.com>
|
||||
dragonvslinux <35779158+dragononcrypto@users.noreply.github.com>
|
||||
Egon Elbre <egonelbre@gmail.com>
|
||||
Elad <theman@elad.im>
|
||||
Eli <elihanover@yahoo.com>
|
||||
Elias Naur <elias.naur@gmail.com>
|
||||
Elliot Shepherd <elliot@identitii.com>
|
||||
Emil <mursalimovemeel@gmail.com>
|
||||
emile <emile@users.noreply.github.com>
|
||||
Enrique Fynn <enriquefynn@gmail.com>
|
||||
Enrique Fynn <me@enriquefynn.com>
|
||||
EOS Classic <info@eos-classic.io>
|
||||
Erichin <erichinbato@gmail.com>
|
||||
Ernesto del Toro <ernesto.deltoro@gmail.com>
|
||||
Ethan Buchman <ethan@coinculture.info>
|
||||
ethersphere <thesw@rm.eth>
|
||||
Eugene Valeyev <evgen.povt@gmail.com>
|
||||
Evangelos Pappas <epappas@evalonlabs.com>
|
||||
Evgeny <awesome.observer@yandex.com>
|
||||
Evgeny Danilenko <6655321@bk.ru>
|
||||
evgk <evgeniy.kamyshev@gmail.com>
|
||||
Fabian Vogelsteller <fabian@frozeman.de>
|
||||
Fabio Barone <fabio.barone.co@gmail.com>
|
||||
Fabio Berger <fabioberger1991@gmail.com>
|
||||
FaceHo <facehoshi@gmail.com>
|
||||
Felix Lange <fjl@twurst.com>
|
||||
Ferenc Szabo <frncmx@gmail.com>
|
||||
ferhat elmas <elmas.ferhat@gmail.com>
|
||||
Fiisio <liangcszzu@163.com>
|
||||
Frank Szendzielarz <33515470+FrankSzendzielarz@users.noreply.github.com>
|
||||
Frank Wang <eternnoir@gmail.com>
|
||||
Franklin <mr_franklin@126.com>
|
||||
Furkan KAMACI <furkankamaci@gmail.com>
|
||||
GagziW <leon.stanko@rwth-aachen.de>
|
||||
Gary Rong <garyrong0905@gmail.com>
|
||||
George Ornbo <george@shapeshed.com>
|
||||
Gregg Dourgarian <greggd@tempworks.com>
|
||||
Guilherme Salgado <gsalgado@gmail.com>
|
||||
Guillaume Ballet <gballet@gmail.com>
|
||||
Guillaume Nicolas <guin56@gmail.com>
|
||||
GuiltyMorishita <morilliantblue@gmail.com>
|
||||
Gus <yo@soygus.com>
|
||||
Gustav Simonsson <gustav.simonsson@gmail.com>
|
||||
Gísli Kristjánsson <gislik@hamstur.is>
|
||||
Ha ĐANG <dvietha@gmail.com>
|
||||
HackyMiner <hackyminer@gmail.com>
|
||||
hadv <dvietha@gmail.com>
|
||||
Hao Bryan Cheng <haobcheng@gmail.com>
|
||||
HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
|
||||
Henning Diedrich <hd@eonblast.com>
|
||||
holisticode <holistic.computing@gmail.com>
|
||||
Hongbin Mao <hello2mao@gmail.com>
|
||||
Hsien-Tang Kao <htkao@pm.me>
|
||||
Husam Ibrahim <39692071+HusamIbrahim@users.noreply.github.com>
|
||||
hydai <z54981220@gmail.com>
|
||||
Hyung-Kyu Hqueue Choi <hyungkyu.choi@gmail.com>
|
||||
Ian Macalinao <me@ian.pw>
|
||||
Ian Norden <iannordenn@gmail.com>
|
||||
Isidoro Ghezzi <isidoro.ghezzi@icloud.com>
|
||||
Iskander (Alex) Sharipov <quasilyte@gmail.com>
|
||||
Ivan Daniluk <ivan.daniluk@gmail.com>
|
||||
Ivo Georgiev <ivo@strem.io>
|
||||
Jae Kwon <jkwon.work@gmail.com>
|
||||
Jamie Pitts <james.pitts@gmail.com>
|
||||
Janos Guljas <janos@resenje.org>
|
||||
Janoš Guljaš <janos@users.noreply.github.com>
|
||||
Jason Carver <jacarver@linkedin.com>
|
||||
Javier Peletier <jm@epiclabs.io>
|
||||
Javier Peletier <jpeletier@users.noreply.github.com>
|
||||
Javier Sagredo <jasataco@gmail.com>
|
||||
Jay <codeholic.arena@gmail.com>
|
||||
Jay Guo <guojiannan1101@gmail.com>
|
||||
Jaynti Kanani <jdkanani@gmail.com>
|
||||
Jeff Prestes <jeffprestes@gmail.com>
|
||||
Jeff R. Allen <jra@nella.org>
|
||||
Jeffery Robert Walsh <rlxrlps@gmail.com>
|
||||
Jeffrey Wilcke <jeffrey@ethereum.org>
|
||||
Jens Agerberg <github@agerberg.me>
|
||||
Jeremy McNevin <jeremy.mcnevin@optum.com>
|
||||
Jeremy Schlatter <jeremy.schlatter@gmail.com>
|
||||
Jerzy Lasyk <jerzylasyk@gmail.com>
|
||||
Jia Chenhui <jiachenhui1989@gmail.com>
|
||||
Jim McDonald <Jim@mcdee.net>
|
||||
jkcomment <jkcomment@gmail.com>
|
||||
Joel Burget <joelburget@gmail.com>
|
||||
John C. Vernaleo <john@netpurgatory.com>
|
||||
Johns Beharry <johns@peakshift.com>
|
||||
Jonas <felberj@users.noreply.github.com>
|
||||
Jonathan Brown <jbrown@bluedroplet.com>
|
||||
JoranHonig <JoranHonig@users.noreply.github.com>
|
||||
Jordan Krage <jmank88@gmail.com>
|
||||
Joseph Chow <ethereum@outlook.com>
|
||||
jtakalai <juuso.takalainen@streamr.com>
|
||||
JU HYEONG PARK <dkdkajej@gmail.com>
|
||||
Justin Clark-Casey <justincc@justincc.org>
|
||||
Justin Drake <drakefjustin@gmail.com>
|
||||
jwasinger <j-wasinger@hotmail.com>
|
||||
ken10100147 <sunhongping@kanjian.com>
|
||||
Kenji Siu <kenji@isuntv.com>
|
||||
Kenso Trabing <kenso.trabing@bloomwebsite.com>
|
||||
Kenso Trabing <ktrabing@acm.org>
|
||||
Kevin <denk.kevin@web.de>
|
||||
kevin.xu <cming.xu@gmail.com>
|
||||
kiel barry <kiel.j.barry@gmail.com>
|
||||
kimmylin <30611210+kimmylin@users.noreply.github.com>
|
||||
Kitten King <53072918+kittenking@users.noreply.github.com>
|
||||
knarfeh <hejun1874@gmail.com>
|
||||
Kobi Gurkan <kobigurk@gmail.com>
|
||||
Konrad Feldmeier <konrad@brainbot.com>
|
||||
Kris Shinn <raggamuffin.music@gmail.com>
|
||||
Kurkó Mihály <kurkomisi@users.noreply.github.com>
|
||||
Kushagra Sharma <ksharm01@gmail.com>
|
||||
Kwuaint <34888408+kwuaint@users.noreply.github.com>
|
||||
Kyuntae Ethan Kim <ethan.kyuntae.kim@gmail.com>
|
||||
ledgerwatch <akhounov@gmail.com>
|
||||
Lefteris Karapetsas <lefteris@refu.co>
|
||||
Leif Jurvetson <leijurv@gmail.com>
|
||||
Leo Shklovskii <leo@thermopylae.net>
|
||||
LeoLiao <leofantast@gmail.com>
|
||||
Lewis Marshall <lewis@lmars.net>
|
||||
lhendre <lhendre2@gmail.com>
|
||||
Liang Ma <liangma.ul@gmail.com>
|
||||
Liang Ma <liangma@liangbit.com>
|
||||
Liang ZOU <liang.d.zou@gmail.com>
|
||||
libotony <liboliqi@gmail.com>
|
||||
ligi <ligi@ligi.de>
|
||||
Lio李欧 <lionello@users.noreply.github.com>
|
||||
Lorenzo Manacorda <lorenzo@kinvolk.io>
|
||||
Louis Holbrook <dev@holbrook.no>
|
||||
Luca Zeug <luclu@users.noreply.github.com>
|
||||
Magicking <s@6120.eu>
|
||||
manlio <manlio.poltronieri@gmail.com>
|
||||
Maran Hidskes <maran.hidskes@gmail.com>
|
||||
Marek Kotewicz <marek.kotewicz@gmail.com>
|
||||
Marius van der Wijden <m.vanderwijden@live.de>
|
||||
Mark <markya0616@gmail.com>
|
||||
Mark Rushakoff <mark.rushakoff@gmail.com>
|
||||
mark.lin <mark@maicoin.com>
|
||||
Martin Alex Philip Dawson <u1356770@gmail.com>
|
||||
Martin Holst Swende <martin@swende.se>
|
||||
Martin Klepsch <martinklepsch@googlemail.com>
|
||||
Mats Julian Olsen <mats@plysjbyen.net>
|
||||
Matt K <1036969+mkrump@users.noreply.github.com>
|
||||
Matthew Di Ferrante <mattdf@users.noreply.github.com>
|
||||
Matthew Halpern <matthalp@gmail.com>
|
||||
Matthew Halpern <matthalp@google.com>
|
||||
Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
|
||||
Max Sistemich <mafrasi2@googlemail.com>
|
||||
Maximilian Meister <mmeister@suse.de>
|
||||
Micah Zoltu <micah@zoltu.net>
|
||||
Michael Ruminer <michael.ruminer+github@gmail.com>
|
||||
Miguel Mota <miguelmota2@gmail.com>
|
||||
Miya Chen <miyatlchen@gmail.com>
|
||||
Mohanson <mohanson@outlook.com>
|
||||
mr_franklin <mr_franklin@126.com>
|
||||
Mymskmkt <1847234666@qq.com>
|
||||
Nalin Bhardwaj <nalinbhardwaj@nibnalin.me>
|
||||
Nchinda Nchinda <nchinda2@gmail.com>
|
||||
necaremus <necaremus@gmail.com>
|
||||
needkane <604476380@qq.com>
|
||||
Nguyen Kien Trung <trung.n.k@gmail.com>
|
||||
Nguyen Sy Thanh Son <thanhson1085@gmail.com>
|
||||
Nick Dodson <silentcicero@outlook.com>
|
||||
Nick Johnson <arachnid@notdot.net>
|
||||
Nicolas Guillaume <gunicolas@sqli.com>
|
||||
Nilesh Trivedi <nilesh@hypertrack.io>
|
||||
Nimrod Gutman <nimrod.gutman@gmail.com>
|
||||
njupt-moon <1015041018@njupt.edu.cn>
|
||||
nkbai <nkbai@163.com>
|
||||
nobody <ddean2009@163.com>
|
||||
Noman <noman@noman.land>
|
||||
Oleg Kovalov <iamolegkovalov@gmail.com>
|
||||
Oli Bye <olibye@users.noreply.github.com>
|
||||
Osuke <arget-fee.free.dgm@hotmail.co.jp>
|
||||
Paul Berg <hello@paulrberg.com>
|
||||
Paul Litvak <litvakpol@012.net.il>
|
||||
Paulo L F Casaretto <pcasaretto@gmail.com>
|
||||
Paweł Bylica <chfast@gmail.com>
|
||||
Pedro Pombeiro <PombeirP@users.noreply.github.com>
|
||||
Peter Broadhurst <peter@themumbles.net>
|
||||
Peter Pratscher <pratscher@gmail.com>
|
||||
Petr Mikusek <petr@mikusek.info>
|
||||
Philip Schlump <pschlump@gmail.com>
|
||||
Pierre Neter <pierreneter@gmail.com>
|
||||
PilkyuJung <anothel1@naver.com>
|
||||
protolambda <proto@protolambda.com>
|
||||
Péter Szilágyi <peterke@gmail.com>
|
||||
RJ Catalano <catalanor0220@gmail.com>
|
||||
qd-ethan <31876119+qdgogogo@users.noreply.github.com>
|
||||
Raghav Sood <raghavsood@gmail.com>
|
||||
Ralph Caraveo <deckarep@gmail.com>
|
||||
Ralph Caraveo III <deckarep@gmail.com>
|
||||
Ramesh Nair <ram@hiddentao.com>
|
||||
reinerRubin <tolstov.georgij@gmail.com>
|
||||
rhaps107 <dod-source@yandex.ru>
|
||||
Ricardo Catalinas Jiménez <r@untroubled.be>
|
||||
Ricardo Domingos <ricardohsd@gmail.com>
|
||||
Richard Hart <richardhart92@gmail.com>
|
||||
RJ Catalano <catalanor0220@gmail.com>
|
||||
Rob <robert@rojotek.com>
|
||||
Rob Mulholand <rmulholand@8thlight.com>
|
||||
Robert Zaremba <robert.zaremba@scale-it.pl>
|
||||
Roc Yu <rociiu0112@gmail.com>
|
||||
Runchao Han <elvisage941102@gmail.com>
|
||||
Russ Cox <rsc@golang.org>
|
||||
Ryan Schneider <ryanleeschneider@gmail.com>
|
||||
Rémy Roy <remyroy@remyroy.com>
|
||||
S. Matthew English <s-matthew-english@users.noreply.github.com>
|
||||
salanfe <salanfe@users.noreply.github.com>
|
||||
Samuel Marks <samuelmarks@gmail.com>
|
||||
Sarlor <kinsleer@outlook.com>
|
||||
Sasuke1964 <neilperry1964@gmail.com>
|
||||
Saulius Grigaitis <saulius@necolt.com>
|
||||
Sean <darcys22@gmail.com>
|
||||
Sheldon <11510383@mail.sustc.edu.cn>
|
||||
Sheldon <374662347@qq.com>
|
||||
Shintaro Kaneko <kaneshin0120@gmail.com>
|
||||
Shuai Qi <qishuai231@gmail.com>
|
||||
Shunsuke Watanabe <ww.shunsuke@gmail.com>
|
||||
silence <wangsai.silence@qq.com>
|
||||
Simon Jentzsch <simon@slock.it>
|
||||
slumber1122 <slumber1122@gmail.com>
|
||||
Smilenator <yurivanenko@yandex.ru>
|
||||
Sorin Neacsu <sorin.neacsu@gmail.com>
|
||||
Stein Dekker <dekker.stein@gmail.com>
|
||||
Steve Gattuso <steve@stevegattuso.me>
|
||||
Steve Ruckdashel <steve.ruckdashel@gmail.com>
|
||||
Steve Waldman <swaldman@mchange.com>
|
||||
Steven Roose <stevenroose@gmail.com>
|
||||
stompesi <stompesi@gmail.com>
|
||||
stormpang <jialinpeng@vip.qq.com>
|
||||
sunxiaojun2014 <sunxiaojun-xy@360.cn>
|
||||
tamirms <tamir@trello.com>
|
||||
Taylor Gerring <taylor.gerring@gmail.com>
|
||||
TColl <38299499+TColl@users.noreply.github.com>
|
||||
terasum <terasum@163.com>
|
||||
Thomas Bocek <tom@tomp2p.net>
|
||||
thomasmodeneis <thomas.modeneis@gmail.com>
|
||||
thumb8432 <thumb8432@gmail.com>
|
||||
Ti Zhou <tizhou1986@gmail.com>
|
||||
Tosh Camille <tochecamille@gmail.com>
|
||||
tsarpaul <Litvakpol@012.net.il>
|
||||
tzapu <alex@tzapu.com>
|
||||
ult-bobonovski <alex@ultiledger.io>
|
||||
Valentin Wüstholz <wuestholz@gmail.com>
|
||||
Vedhavyas Singareddi <vedhavyas.singareddi@gmail.com>
|
||||
Victor Farazdagi <simple.square@gmail.com>
|
||||
Victor Tran <vu.tran54@gmail.com>
|
||||
Vie <yangchenzhong@gmail.com>
|
||||
Viktor Trón <viktor.tron@gmail.com>
|
||||
Ville Sundell <github@solarius.fi>
|
||||
vim88 <vim88vim88@gmail.com>
|
||||
Vincent G <caktux@gmail.com>
|
||||
Vincent Serpoul <vincent@serpoul.com>
|
||||
Vitalik Buterin <v@buterin.com>
|
||||
Vitaly Bogdanov <vsbogd@gmail.com>
|
||||
Vitaly V <vvelikodny@gmail.com>
|
||||
Vivek Anand <vivekanand1101@users.noreply.github.com>
|
||||
Vlad <gluk256@gmail.com>
|
||||
Vlad Bokov <razum2um@mail.ru>
|
||||
Vlad Gluhovsky <gluk256@users.noreply.github.com>
|
||||
weimumu <934657014@qq.com>
|
||||
Wenbiao Zheng <delweng@gmail.com>
|
||||
William Setzer <bootstrapsetzer@gmail.com>
|
||||
williambannas <wrschwartz@wpi.edu>
|
||||
Wuxiang <wuxiangzhou2010@gmail.com>
|
||||
xiekeyang <xiekeyang@users.noreply.github.com>
|
||||
xincaosu <xincaosu@126.com>
|
||||
yahtoo <yahtoo.ma@gmail.com>
|
||||
YaoZengzeng <yaozengzeng@zju.edu.cn>
|
||||
YH-Zhou <yanhong.zhou05@gmail.com>
|
||||
Yohann Léon <sybiload@gmail.com>
|
||||
Yoichi Hirai <i@yoichihirai.com>
|
||||
Yondon Fu <yondon.fu@gmail.com>
|
||||
YOSHIDA Masanori <masanori.yoshida@gmail.com>
|
||||
yoza <yoza.is12s@gmail.com>
|
||||
Yusup <awklsgrep@gmail.com>
|
||||
Zach <zach.ramsay@gmail.com>
|
||||
zah <zahary@gmail.com>
|
||||
Zahoor Mohamed <zahoor@zahoor.in>
|
||||
Zak Cole <zak@beattiecole.com>
|
||||
zer0to0ne <36526113+zer0to0ne@users.noreply.github.com>
|
||||
Zhenguo Niu <Niu.ZGlinux@gmail.com>
|
||||
Zoe Nolan <github@zoenolan.org>
|
||||
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>
|
||||
jtakalai <juuso.takalainen@streamr.com>
|
||||
ken10100147 <sunhongping@kanjian.com>
|
||||
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>
|
||||
yoza <yoza.is12s@gmail.com>
|
||||
Łukasz Kurowski <crackcomm@users.noreply.github.com>
|
||||
ΞTHΞЯSPHΞЯΞ <{viktor.tron,nagydani,zsfelfoldi}@gmail.com>
|
||||
Максим Чусовлянов <mchusovlianov@gmail.com>
|
||||
Ralph Caraveo <deckarep@gmail.com>
|
||||
大彬 <hz_stb@163.com>
|
||||
贺鹏飞 <hpf@hackerful.cn>
|
||||
유용환 <33824408+eric-yoo@users.noreply.github.com>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.12-alpine as builder
|
||||
FROM golang:1.13-alpine as builder
|
||||
|
||||
RUN apk add --no-cache make gcc musl-dev linux-headers git
|
||||
|
||||
@@ -12,5 +12,5 @@ FROM alpine:latest
|
||||
RUN apk add --no-cache ca-certificates
|
||||
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
|
||||
|
||||
EXPOSE 8545 8546 30303 30303/udp
|
||||
EXPOSE 8545 8546 8547 30303 30303/udp
|
||||
ENTRYPOINT ["geth"]
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.12-alpine as builder
|
||||
FROM golang:1.13-alpine as builder
|
||||
|
||||
RUN apk add --no-cache make gcc musl-dev linux-headers git
|
||||
|
||||
@@ -12,4 +12,4 @@ FROM alpine:latest
|
||||
RUN apk add --no-cache ca-certificates
|
||||
COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/
|
||||
|
||||
EXPOSE 8545 8546 30303 30303/udp
|
||||
EXPOSE 8545 8546 8547 30303 30303/udp
|
||||
|
2
Makefile
2
Makefile
@@ -8,7 +8,7 @@
|
||||
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
|
||||
.PHONY: geth-windows geth-windows-386 geth-windows-amd64
|
||||
|
||||
GOBIN = $(shell pwd)/build/bin
|
||||
GOBIN = ./build/bin
|
||||
GO ?= latest
|
||||
|
||||
geth:
|
||||
|
14
README.md
14
README.md
@@ -98,7 +98,7 @@ Specifying the `--testnet` flag, however, will reconfigure your `geth` instance
|
||||
this.
|
||||
* Instead of connecting the main Ethereum network, the client will connect to the test
|
||||
network, which uses different P2P bootnodes, different network IDs and genesis states.
|
||||
|
||||
|
||||
*Note: Although there are some internal protective measures to prevent transactions from
|
||||
crossing over between the main network and test network, you should make sure to always
|
||||
use separate accounts for play-money and real-money. Unless you manually move
|
||||
@@ -210,10 +210,14 @@ aware of and agree upon. This consists of a small JSON file (e.g. call it `genes
|
||||
```json
|
||||
{
|
||||
"config": {
|
||||
"chainId": 0,
|
||||
"chainId": <arbitrary positive integer>,
|
||||
"homesteadBlock": 0,
|
||||
"eip150Block": 0,
|
||||
"eip155Block": 0,
|
||||
"eip158Block": 0
|
||||
"eip158Block": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"constantinopleBlock": 0,
|
||||
"petersburgBlock": 0
|
||||
},
|
||||
"alloc": {},
|
||||
"coinbase": "0x0000000000000000000000000000000000000000",
|
||||
@@ -229,8 +233,8 @@ aware of and agree upon. This consists of a small JSON file (e.g. call it `genes
|
||||
|
||||
The above fields should be fine for most purposes, although we'd recommend changing
|
||||
the `nonce` to some random value so you prevent unknown remote nodes from being able
|
||||
to connect to you. If you'd like to pre-fund some accounts for easier testing, you can
|
||||
populate the `alloc` field with account configs:
|
||||
to connect to you. If you'd like to pre-fund some accounts for easier testing, create
|
||||
the accounts and populate the `alloc` field with their addresses.
|
||||
|
||||
```json
|
||||
"alloc": {
|
||||
|
@@ -70,7 +70,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
// Pack up the method ID too if not a constructor and return
|
||||
return append(method.Id(), arguments...), nil
|
||||
return append(method.ID(), arguments...), nil
|
||||
}
|
||||
|
||||
// Unpack output in v according to the abi specification
|
||||
@@ -121,11 +121,9 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||
Inputs []Argument
|
||||
Outputs []Argument
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &fields); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
abi.Methods = make(map[string]Method)
|
||||
abi.Events = make(map[string]Event)
|
||||
for _, field := range fields {
|
||||
@@ -144,6 +142,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||
}
|
||||
abi.Methods[name] = Method{
|
||||
Name: name,
|
||||
RawName: field.Name,
|
||||
Const: field.Constant,
|
||||
Inputs: field.Inputs,
|
||||
Outputs: field.Outputs,
|
||||
@@ -157,6 +156,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||
}
|
||||
abi.Events[name] = Event{
|
||||
Name: name,
|
||||
RawName: field.Name,
|
||||
Anonymous: field.Anonymous,
|
||||
Inputs: field.Inputs,
|
||||
}
|
||||
@@ -173,7 +173,7 @@ func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
|
||||
return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata))
|
||||
}
|
||||
for _, method := range abi.Methods {
|
||||
if bytes.Equal(method.Id(), sigdata[:4]) {
|
||||
if bytes.Equal(method.ID(), sigdata[:4]) {
|
||||
return &method, nil
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
|
||||
// ABI and returns nil if none found.
|
||||
func (abi *ABI) EventByID(topic common.Hash) (*Event, error) {
|
||||
for _, event := range abi.Events {
|
||||
if bytes.Equal(event.Id().Bytes(), topic.Bytes()) {
|
||||
if bytes.Equal(event.ID().Bytes(), topic.Bytes()) {
|
||||
return &event, nil
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -62,10 +61,10 @@ func TestReader(t *testing.T) {
|
||||
exp := ABI{
|
||||
Methods: map[string]Method{
|
||||
"balance": {
|
||||
"balance", true, nil, nil,
|
||||
"balance", "balance", true, nil, nil,
|
||||
},
|
||||
"send": {
|
||||
"send", false, []Argument{
|
||||
"send", "send", false, []Argument{
|
||||
{"amount", Uint256, false},
|
||||
}, nil,
|
||||
},
|
||||
@@ -102,8 +101,7 @@ func TestReader(t *testing.T) {
|
||||
func TestTestNumbers(t *testing.T) {
|
||||
abi, err := JSON(strings.NewReader(jsondata2))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := abi.Pack("balance"); err != nil {
|
||||
@@ -140,8 +138,7 @@ func TestTestNumbers(t *testing.T) {
|
||||
func TestTestString(t *testing.T) {
|
||||
abi, err := JSON(strings.NewReader(jsondata2))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := abi.Pack("string", "hello world"); err != nil {
|
||||
@@ -152,8 +149,7 @@ func TestTestString(t *testing.T) {
|
||||
func TestTestBool(t *testing.T) {
|
||||
abi, err := JSON(strings.NewReader(jsondata2))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := abi.Pack("bool", true); err != nil {
|
||||
@@ -164,15 +160,12 @@ func TestTestBool(t *testing.T) {
|
||||
func TestTestSlice(t *testing.T) {
|
||||
abi, err := JSON(strings.NewReader(jsondata2))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
slice := make([]uint64, 2)
|
||||
if _, err := abi.Pack("uint64[2]", slice); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if _, err := abi.Pack("uint64[]", slice); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -180,19 +173,19 @@ func TestTestSlice(t *testing.T) {
|
||||
|
||||
func TestMethodSignature(t *testing.T) {
|
||||
String, _ := NewType("string", nil)
|
||||
m := Method{"foo", false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil}
|
||||
m := Method{"foo", "foo", false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil}
|
||||
exp := "foo(string,string)"
|
||||
if m.Sig() != exp {
|
||||
t.Error("signature mismatch", exp, "!=", m.Sig())
|
||||
}
|
||||
|
||||
idexp := crypto.Keccak256([]byte(exp))[:4]
|
||||
if !bytes.Equal(m.Id(), idexp) {
|
||||
t.Errorf("expected ids to match %x != %x", m.Id(), idexp)
|
||||
if !bytes.Equal(m.ID(), idexp) {
|
||||
t.Errorf("expected ids to match %x != %x", m.ID(), idexp)
|
||||
}
|
||||
|
||||
uintt, _ := NewType("uint256", nil)
|
||||
m = Method{"foo", false, []Argument{{"bar", uintt, false}}, nil}
|
||||
m = Method{"foo", "foo", false, []Argument{{"bar", uintt, false}}, nil}
|
||||
exp = "foo(uint256)"
|
||||
if m.Sig() != exp {
|
||||
t.Error("signature mismatch", exp, "!=", m.Sig())
|
||||
@@ -211,18 +204,40 @@ func TestMethodSignature(t *testing.T) {
|
||||
{Name: "y", Type: "int256"},
|
||||
}},
|
||||
})
|
||||
m = Method{"foo", false, []Argument{{"s", s, false}, {"bar", String, false}}, nil}
|
||||
m = Method{"foo", "foo", false, []Argument{{"s", s, false}, {"bar", String, false}}, nil}
|
||||
exp = "foo((int256,int256[],(int256,int256)[],(int256,int256)[2]),string)"
|
||||
if m.Sig() != exp {
|
||||
t.Error("signature mismatch", exp, "!=", m.Sig())
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverloadedMethodSignature(t *testing.T) {
|
||||
json := `[{"constant":true,"inputs":[{"name":"i","type":"uint256"},{"name":"j","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"}],"name":"bar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"},{"indexed":false,"name":"j","type":"uint256"}],"name":"bar","type":"event"}]`
|
||||
abi, err := JSON(strings.NewReader(json))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
check := func(name string, expect string, method bool) {
|
||||
if method {
|
||||
if abi.Methods[name].Sig() != expect {
|
||||
t.Fatalf("The signature of overloaded method mismatch, want %s, have %s", expect, abi.Methods[name].Sig())
|
||||
}
|
||||
} else {
|
||||
if abi.Events[name].Sig() != expect {
|
||||
t.Fatalf("The signature of overloaded event mismatch, want %s, have %s", expect, abi.Events[name].Sig())
|
||||
}
|
||||
}
|
||||
}
|
||||
check("foo", "foo(uint256,uint256)", true)
|
||||
check("foo0", "foo(uint256)", true)
|
||||
check("bar", "bar(uint256)", false)
|
||||
check("bar0", "bar(uint256,uint256)", false)
|
||||
}
|
||||
|
||||
func TestMultiPack(t *testing.T) {
|
||||
abi, err := JSON(strings.NewReader(jsondata2))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sig := crypto.Keccak256([]byte("bar(uint32,uint16)"))[:4]
|
||||
@@ -232,10 +247,8 @@ func TestMultiPack(t *testing.T) {
|
||||
|
||||
packed, err := abi.Pack("bar", uint32(10), uint16(11))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(packed, sig) {
|
||||
t.Errorf("expected %x got %x", sig, packed)
|
||||
}
|
||||
@@ -246,11 +259,11 @@ func ExampleJSON() {
|
||||
|
||||
abi, err := JSON(strings.NewReader(definition))
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
panic(err)
|
||||
}
|
||||
out, err := abi.Pack("isBar", common.HexToAddress("01"))
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%x\n", out)
|
||||
@@ -908,13 +921,13 @@ func TestABI_MethodById(t *testing.T) {
|
||||
}
|
||||
for name, m := range abi.Methods {
|
||||
a := fmt.Sprintf("%v", m)
|
||||
m2, err := 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 {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
// Also test empty
|
||||
@@ -982,8 +995,8 @@ func TestABI_EventById(t *testing.T) {
|
||||
t.Errorf("We should find a event for topic %s, test #%d", topicID.Hex(), testnum)
|
||||
}
|
||||
|
||||
if event.Id() != topicID {
|
||||
t.Errorf("Event id %s does not match topic %s, test #%d", event.Id().Hex(), topicID.Hex(), testnum)
|
||||
if event.ID() != topicID {
|
||||
t.Errorf("Event id %s does not match topic %s, test #%d", event.ID().Hex(), topicID.Hex(), testnum)
|
||||
}
|
||||
|
||||
unknowntopicID := crypto.Keccak256Hash([]byte("unknownEvent"))
|
||||
|
@@ -88,6 +88,12 @@ func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBac
|
||||
return NewSimulatedBackendWithDatabase(rawdb.NewMemoryDatabase(), alloc, gasLimit)
|
||||
}
|
||||
|
||||
// Close terminates the underlying blockchain's update loop.
|
||||
func (b *SimulatedBackend) Close() error {
|
||||
b.blockchain.Stop()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Commit imports all the pending transactions as a single block and starts a
|
||||
// fresh new state.
|
||||
func (b *SimulatedBackend) Commit() {
|
||||
|
@@ -38,6 +38,7 @@ func TestSimulatedBackend(t *testing.T) {
|
||||
genAlloc[auth.From] = core.GenesisAccount{Balance: big.NewInt(9223372036854775807)}
|
||||
|
||||
sim := backends.NewSimulatedBackend(genAlloc, gasLimit)
|
||||
defer sim.Close()
|
||||
|
||||
// should return an error if the tx is not found
|
||||
txHash := common.HexToHash("2")
|
||||
|
@@ -252,7 +252,7 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int
|
||||
opts = new(FilterOpts)
|
||||
}
|
||||
// Append the event selector to the query parameters and construct the topic set
|
||||
query = append([][]interface{}{{c.abi.Events[name].Id()}}, query...)
|
||||
query = append([][]interface{}{{c.abi.Events[name].ID()}}, query...)
|
||||
|
||||
topics, err := makeTopics(query...)
|
||||
if err != nil {
|
||||
@@ -301,7 +301,7 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter
|
||||
opts = new(WatchOpts)
|
||||
}
|
||||
// Append the event selector to the query parameters and construct the topic set
|
||||
query = append([][]interface{}{{c.abi.Events[name].Id()}}, query...)
|
||||
query = append([][]interface{}{{c.abi.Events[name].ID()}}, query...)
|
||||
|
||||
topics, err := makeTopics(query...)
|
||||
if err != nil {
|
||||
|
@@ -541,7 +541,7 @@ func formatMethod(method abi.Method, structs map[string]*tmplStruct) string {
|
||||
if method.Const {
|
||||
constant = "constant "
|
||||
}
|
||||
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
|
||||
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.RawName, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
|
||||
}
|
||||
|
||||
// formatEvent transforms raw event representation into a user friendly one.
|
||||
@@ -554,5 +554,5 @@ func formatEvent(event abi.Event, structs map[string]*tmplStruct) string {
|
||||
inputs[i] = fmt.Sprintf("%v %v", resolveArgName(input, structs), input.Name)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("event %v(%v)", event.Name, strings.Join(inputs, ", "))
|
||||
return fmt.Sprintf("event %v(%v)", event.RawName, strings.Join(inputs, ", "))
|
||||
}
|
||||
|
@@ -282,7 +282,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy an interaction tester contract and call a transaction on it
|
||||
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
|
||||
@@ -334,7 +336,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a tuple tester contract and execute a structured call on it
|
||||
_, _, getter, err := DeployGetter(auth, sim)
|
||||
@@ -377,7 +381,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a tuple tester contract and execute a structured call on it
|
||||
_, _, tupler, err := DeployTupler(auth, sim)
|
||||
@@ -432,7 +438,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a slice tester contract and execute a n array call on it
|
||||
_, _, slicer, err := DeploySlicer(auth, sim)
|
||||
@@ -477,7 +485,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a default method invoker contract and execute its default method
|
||||
_, _, defaulter, err := DeployDefaulter(auth, sim)
|
||||
@@ -519,7 +529,9 @@ var bindTests = []struct {
|
||||
`,
|
||||
`
|
||||
// Create a simulator and wrap a non-deployed contract
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{}, uint64(10000000000))
|
||||
defer sim.Close()
|
||||
|
||||
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
||||
if err != nil {
|
||||
@@ -566,7 +578,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a funky gas pattern contract
|
||||
_, _, limiter, err := DeployFunkyGasPattern(auth, sim)
|
||||
@@ -613,7 +627,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a sender tester contract and execute a structured call on it
|
||||
_, _, callfrom, err := DeployCallFrom(auth, sim)
|
||||
@@ -685,7 +701,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a underscorer tester contract and execute a structured call on it
|
||||
_, _, underscorer, err := DeployUnderscorer(auth, sim)
|
||||
@@ -776,7 +794,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy an eventer contract
|
||||
_, _, eventer, err := DeployEventer(auth, sim)
|
||||
@@ -963,7 +983,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
//deploy the test contract
|
||||
_, _, testContract, err := DeployDeeplyNestedArray(auth, sim)
|
||||
@@ -1059,12 +1081,12 @@ var bindTests = []struct {
|
||||
`
|
||||
pragma solidity >=0.4.19 <0.6.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
contract Tuple {
|
||||
struct S { uint a; uint[] b; T[] c; }
|
||||
struct T { uint x; uint y; }
|
||||
event TupleEvent(S a, T[2][] b, T[][2] c, S[] d, uint[] e);
|
||||
|
||||
|
||||
function func1(S memory a, T[2][] memory b, T[][2] memory c, S[] memory d, uint[] memory e) public pure returns (S memory, T[2][] memory, T[][2] memory, S[] memory, uint[] memory) {
|
||||
return (a, b, c, d, e);
|
||||
}
|
||||
@@ -1081,7 +1103,7 @@ var bindTests = []struct {
|
||||
`
|
||||
"math/big"
|
||||
"reflect"
|
||||
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
@@ -1091,13 +1113,15 @@ var bindTests = []struct {
|
||||
`
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
backend := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
|
||||
_, _, contract, err := DeployTuple(auth, backend)
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
_, _, contract, err := DeployTuple(auth, sim)
|
||||
if err != nil {
|
||||
t.Fatalf("deploy contract failed %v", err)
|
||||
}
|
||||
backend.Commit()
|
||||
sim.Commit()
|
||||
|
||||
check := func(a, b interface{}, errMsg string) {
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
@@ -1169,7 +1193,7 @@ var bindTests = []struct {
|
||||
if err != nil {
|
||||
t.Fatalf("invoke contract failed, err %v", err)
|
||||
}
|
||||
backend.Commit()
|
||||
sim.Commit()
|
||||
|
||||
iter, err := contract.FilterTupleEvent(nil)
|
||||
if err != nil {
|
||||
@@ -1225,7 +1249,9 @@ var bindTests = []struct {
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
//deploy the test contract
|
||||
_, _, testContract, err := DeployUseLibrary(auth, sim)
|
||||
@@ -1254,6 +1280,99 @@ var bindTests = []struct {
|
||||
"b98c933f0a6ececcd167bd4f9d3299b1a0": "Math",
|
||||
},
|
||||
[]string{"UseLibrary", "Math"},
|
||||
}, {
|
||||
"Overload",
|
||||
`
|
||||
pragma solidity ^0.5.10;
|
||||
|
||||
contract overload {
|
||||
mapping(address => uint256) balances;
|
||||
|
||||
event bar(uint256 i);
|
||||
event bar(uint256 i, uint256 j);
|
||||
|
||||
function foo(uint256 i) public {
|
||||
emit bar(i);
|
||||
}
|
||||
function foo(uint256 i, uint256 j) public {
|
||||
emit bar(i, j);
|
||||
}
|
||||
}
|
||||
`,
|
||||
[]string{`608060405234801561001057600080fd5b50610153806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806304bc52f81461003b5780632fbebd3814610073575b600080fd5b6100716004803603604081101561005157600080fd5b8101908080359060200190929190803590602001909291905050506100a1565b005b61009f6004803603602081101561008957600080fd5b81019080803590602001909291905050506100e4565b005b7fae42e9514233792a47a1e4554624e83fe852228e1503f63cd383e8a431f4f46d8282604051808381526020018281526020019250505060405180910390a15050565b7f0423a1321222a0a8716c22b92fac42d85a45a612b696a461784d9fa537c81e5c816040518082815260200191505060405180910390a15056fea265627a7a72305820e22b049858b33291cbe67eeaece0c5f64333e439d27032ea8337d08b1de18fe864736f6c634300050a0032`},
|
||||
[]string{`[{"constant":false,"inputs":[{"name":"i","type":"uint256"},{"name":"j","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"}],"name":"bar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"},{"indexed":false,"name":"j","type":"uint256"}],"name":"bar","type":"event"}]`},
|
||||
`
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
// Initialize test accounts
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// deploy the test contract
|
||||
_, _, contract, err := DeployOverload(auth, sim)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to deploy contract: %v", err)
|
||||
}
|
||||
// Finish deploy.
|
||||
sim.Commit()
|
||||
|
||||
resCh, stopCh := make(chan uint64), make(chan struct{})
|
||||
|
||||
go func() {
|
||||
barSink := make(chan *OverloadBar)
|
||||
sub, _ := contract.WatchBar(nil, barSink)
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
bar0Sink := make(chan *OverloadBar0)
|
||||
sub0, _ := contract.WatchBar0(nil, bar0Sink)
|
||||
defer sub0.Unsubscribe()
|
||||
|
||||
for {
|
||||
select {
|
||||
case ev := <-barSink:
|
||||
resCh <- ev.I.Uint64()
|
||||
case ev := <-bar0Sink:
|
||||
resCh <- ev.I.Uint64() + ev.J.Uint64()
|
||||
case <-stopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
contract.Foo(auth, big.NewInt(1), big.NewInt(2))
|
||||
sim.Commit()
|
||||
select {
|
||||
case n := <-resCh:
|
||||
if n != 3 {
|
||||
t.Fatalf("Invalid bar0 event")
|
||||
}
|
||||
case <-time.NewTimer(100 * time.Millisecond).C:
|
||||
t.Fatalf("Wait bar0 event timeout")
|
||||
}
|
||||
|
||||
contract.Foo0(auth, big.NewInt(1))
|
||||
sim.Commit()
|
||||
select {
|
||||
case n := <-resCh:
|
||||
if n != 1 {
|
||||
t.Fatalf("Invalid bar event")
|
||||
}
|
||||
case <-time.NewTimer(100 * time.Millisecond).C:
|
||||
t.Fatalf("Wait bar event timeout")
|
||||
}
|
||||
close(stopCh)
|
||||
`,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -294,7 +294,7 @@ var (
|
||||
{{end}}
|
||||
|
||||
{{range .Calls}}
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{formatmethod .Original $structs}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) {
|
||||
@@ -313,14 +313,14 @@ var (
|
||||
return {{if .Structured}}*ret,{{else}}{{range $i, $_ := .Normalized.Outputs}}*ret{{$i}},{{end}}{{end}} err
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{formatmethod .Original $structs}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{formatmethod .Original $structs}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
@@ -329,21 +329,21 @@ var (
|
||||
{{end}}
|
||||
|
||||
{{range .Transacts}}
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{formatmethod .Original $structs}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{formatmethod .Original $structs}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{formatmethod .Original $structs}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
@@ -422,7 +422,7 @@ var (
|
||||
Raw types.Log // Blockchain specific contextual infos
|
||||
}
|
||||
|
||||
// Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.Id}}.
|
||||
// Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{formatevent .Original $structs}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) {
|
||||
@@ -439,7 +439,7 @@ var (
|
||||
return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil
|
||||
}
|
||||
|
||||
// Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.Id}}.
|
||||
// Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{formatevent .Original $structs}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) {
|
||||
@@ -481,7 +481,7 @@ var (
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.Id}}.
|
||||
// Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) {
|
||||
@@ -574,7 +574,7 @@ import java.util.*;
|
||||
}
|
||||
{{end}}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
public {{if gt (len .Normalized.Outputs) 1}}{{capitalise .Normalized.Name}}Results{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}}{{end}}{{end}} {{.Normalized.Name}}(CallOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception {
|
||||
@@ -601,7 +601,7 @@ import java.util.*;
|
||||
{{end}}
|
||||
|
||||
{{range .Transacts}}
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
public Transaction {{.Normalized.Name}}(TransactOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// Copyright 2019 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
|
||||
|
@@ -59,6 +59,7 @@ func TestWaitDeployed(t *testing.T) {
|
||||
},
|
||||
10000000,
|
||||
)
|
||||
defer backend.Close()
|
||||
|
||||
// Create the transaction.
|
||||
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
|
||||
|
@@ -28,7 +28,18 @@ import (
|
||||
// holds type information (inputs) about the yielded output. Anonymous events
|
||||
// don't get the signature canonical representation as the first LOG topic.
|
||||
type Event struct {
|
||||
Name string
|
||||
// Name is the event name used for internal representation. It's derived from
|
||||
// the raw name and a suffix will be added in the case of a event overload.
|
||||
//
|
||||
// e.g.
|
||||
// There are two events have same name:
|
||||
// * foo(int,int)
|
||||
// * foo(uint,uint)
|
||||
// The event name of the first one wll be resolved as foo while the second one
|
||||
// will be resolved as foo0.
|
||||
Name string
|
||||
// RawName is the raw event name parsed from ABI.
|
||||
RawName string
|
||||
Anonymous bool
|
||||
Inputs Arguments
|
||||
}
|
||||
@@ -41,17 +52,26 @@ func (e Event) String() string {
|
||||
inputs[i] = fmt.Sprintf("%v indexed %v", input.Type, input.Name)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("event %v(%v)", e.Name, strings.Join(inputs, ", "))
|
||||
return fmt.Sprintf("event %v(%v)", e.RawName, strings.Join(inputs, ", "))
|
||||
}
|
||||
|
||||
// Id returns the canonical representation of the event's signature used by the
|
||||
// abi definition to identify event names and types.
|
||||
func (e Event) Id() common.Hash {
|
||||
// Sig returns the event string signature according to the ABI spec.
|
||||
//
|
||||
// Example
|
||||
//
|
||||
// event foo(uint32 a, int b) = "foo(uint32,int256)"
|
||||
//
|
||||
// Please note that "int" is substitute for its canonical representation "int256"
|
||||
func (e Event) Sig() string {
|
||||
types := make([]string, len(e.Inputs))
|
||||
i := 0
|
||||
for _, input := range e.Inputs {
|
||||
for i, input := range e.Inputs {
|
||||
types[i] = input.Type.String()
|
||||
i++
|
||||
}
|
||||
return common.BytesToHash(crypto.Keccak256([]byte(fmt.Sprintf("%v(%v)", e.Name, strings.Join(types, ",")))))
|
||||
return fmt.Sprintf("%v(%v)", e.RawName, strings.Join(types, ","))
|
||||
}
|
||||
|
||||
// ID returns the canonical representation of the event's signature used by the
|
||||
// abi definition to identify event names and types.
|
||||
func (e Event) ID() common.Hash {
|
||||
return common.BytesToHash(crypto.Keccak256([]byte(e.Sig())))
|
||||
}
|
||||
|
@@ -104,8 +104,8 @@ func TestEventId(t *testing.T) {
|
||||
}
|
||||
|
||||
for name, event := range abi.Events {
|
||||
if event.Id() != test.expectations[name] {
|
||||
t.Errorf("expected id to be %x, got %x", test.expectations[name], event.Id())
|
||||
if event.ID() != test.expectations[name] {
|
||||
t.Errorf("expected id to be %x, got %x", test.expectations[name], event.ID())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -32,7 +32,18 @@ import (
|
||||
// be flagged `false`.
|
||||
// Input specifies the required input parameters for this gives method.
|
||||
type Method struct {
|
||||
Name string
|
||||
// Name is the method name used for internal representation. It's derived from
|
||||
// the raw name and a suffix will be added in the case of a function overload.
|
||||
//
|
||||
// e.g.
|
||||
// There are two functions have same name:
|
||||
// * foo(int,int)
|
||||
// * foo(uint,uint)
|
||||
// The method name of the first one will be resolved as foo while the second one
|
||||
// will be resolved as foo0.
|
||||
Name string
|
||||
// RawName is the raw method name parsed from ABI.
|
||||
RawName string
|
||||
Const bool
|
||||
Inputs Arguments
|
||||
Outputs Arguments
|
||||
@@ -42,7 +53,7 @@ type Method struct {
|
||||
//
|
||||
// Example
|
||||
//
|
||||
// function foo(uint32 a, int b) = "foo(uint32,int256)"
|
||||
// function foo(uint32 a, int b) = "foo(uint32,int256)"
|
||||
//
|
||||
// Please note that "int" is substitute for its canonical representation "int256"
|
||||
func (method Method) Sig() string {
|
||||
@@ -50,7 +61,7 @@ func (method Method) Sig() string {
|
||||
for i, input := range method.Inputs {
|
||||
types[i] = input.Type.String()
|
||||
}
|
||||
return fmt.Sprintf("%v(%v)", method.Name, strings.Join(types, ","))
|
||||
return fmt.Sprintf("%v(%v)", method.RawName, strings.Join(types, ","))
|
||||
}
|
||||
|
||||
func (method Method) String() string {
|
||||
@@ -69,9 +80,11 @@ func (method Method) String() string {
|
||||
if method.Const {
|
||||
constant = "constant "
|
||||
}
|
||||
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
|
||||
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.RawName, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
|
||||
}
|
||||
|
||||
func (method Method) Id() []byte {
|
||||
// ID returns the canonical representation of the method's signature used by the
|
||||
// abi definition to identify method names and types.
|
||||
func (method Method) ID() []byte {
|
||||
return crypto.Keccak256([]byte(method.Sig()))[:4]
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// Copyright 2018 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
|
||||
|
@@ -634,7 +634,7 @@ func TestMethodPack(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sig := abi.Methods["slice"].Id()
|
||||
sig := abi.Methods["slice"].ID()
|
||||
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
||||
|
||||
@@ -648,7 +648,7 @@ func TestMethodPack(t *testing.T) {
|
||||
}
|
||||
|
||||
var addrA, addrB = common.Address{1}, common.Address{2}
|
||||
sig = abi.Methods["sliceAddress"].Id()
|
||||
sig = abi.Methods["sliceAddress"].ID()
|
||||
sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes(addrA[:], 32)...)
|
||||
@@ -663,7 +663,7 @@ func TestMethodPack(t *testing.T) {
|
||||
}
|
||||
|
||||
var addrC, addrD = common.Address{3}, common.Address{4}
|
||||
sig = abi.Methods["sliceMultiAddress"].Id()
|
||||
sig = abi.Methods["sliceMultiAddress"].ID()
|
||||
sig = append(sig, common.LeftPadBytes([]byte{64}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{160}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
||||
@@ -681,7 +681,7 @@ func TestMethodPack(t *testing.T) {
|
||||
t.Errorf("expected %x got %x", sig, packed)
|
||||
}
|
||||
|
||||
sig = abi.Methods["slice256"].Id()
|
||||
sig = abi.Methods["slice256"].ID()
|
||||
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
||||
|
||||
@@ -695,7 +695,7 @@ func TestMethodPack(t *testing.T) {
|
||||
}
|
||||
|
||||
a := [2][2]*big.Int{{big.NewInt(1), big.NewInt(1)}, {big.NewInt(2), big.NewInt(0)}}
|
||||
sig = abi.Methods["nestedArray"].Id()
|
||||
sig = abi.Methods["nestedArray"].ID()
|
||||
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
|
||||
@@ -712,7 +712,7 @@ func TestMethodPack(t *testing.T) {
|
||||
t.Errorf("expected %x got %x", sig, packed)
|
||||
}
|
||||
|
||||
sig = abi.Methods["nestedArray2"].Id()
|
||||
sig = abi.Methods["nestedArray2"].ID()
|
||||
sig = append(sig, common.LeftPadBytes([]byte{0x20}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{0x40}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{0x80}, 32)...)
|
||||
@@ -728,7 +728,7 @@ func TestMethodPack(t *testing.T) {
|
||||
t.Errorf("expected %x got %x", sig, packed)
|
||||
}
|
||||
|
||||
sig = abi.Methods["nestedSlice"].Id()
|
||||
sig = abi.Methods["nestedSlice"].ID()
|
||||
sig = append(sig, common.LeftPadBytes([]byte{0x20}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{0x02}, 32)...)
|
||||
sig = append(sig, common.LeftPadBytes([]byte{0x40}, 32)...)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// Copyright 2015 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
|
||||
|
@@ -35,7 +35,7 @@ var ErrNotSupported = errors.New("not supported")
|
||||
|
||||
// ErrInvalidPassphrase is returned when a decryption operation receives a bad
|
||||
// passphrase.
|
||||
var ErrInvalidPassphrase = errors.New("invalid passphrase")
|
||||
var ErrInvalidPassphrase = errors.New("invalid password")
|
||||
|
||||
// ErrWalletAlreadyOpen is returned if a wallet is attempted to be opened the
|
||||
// second time.
|
||||
|
22
accounts/external/backend.go
vendored
22
accounts/external/backend.go
vendored
@@ -1,18 +1,18 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// 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 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.
|
||||
//
|
||||
// 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
|
||||
// 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
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
// 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 external
|
||||
|
||||
@@ -204,14 +204,14 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
|
||||
}
|
||||
|
||||
func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
|
||||
return []byte{}, fmt.Errorf("passphrase-operations not supported on external signers")
|
||||
return []byte{}, fmt.Errorf("password-operations not supported on external signers")
|
||||
}
|
||||
|
||||
func (api *ExternalSigner) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
|
||||
return nil, fmt.Errorf("passphrase-operations not supported on external signers")
|
||||
return nil, fmt.Errorf("password-operations not supported on external signers")
|
||||
}
|
||||
func (api *ExternalSigner) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) {
|
||||
return nil, fmt.Errorf("passphrase-operations not supported on external signers")
|
||||
return nil, fmt.Errorf("password-operations not supported on external signers")
|
||||
}
|
||||
|
||||
func (api *ExternalSigner) listAccounts() ([]common.Address, error) {
|
||||
|
@@ -43,7 +43,7 @@ import (
|
||||
var (
|
||||
ErrLocked = accounts.NewAuthNeededError("password or unlock")
|
||||
ErrNoMatch = errors.New("no key for given address or file")
|
||||
ErrDecrypt = errors.New("could not decrypt key with given passphrase")
|
||||
ErrDecrypt = errors.New("could not decrypt key with given password")
|
||||
)
|
||||
|
||||
// KeyStoreType is the reflect type of a keystore backend.
|
||||
|
@@ -96,7 +96,7 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = ks.GetKey(k1.Address, account.URL.Path, "bar"); err != ErrDecrypt {
|
||||
t.Fatalf("wrong error for invalid passphrase\ngot %q\nwant %q", err, ErrDecrypt)
|
||||
t.Fatalf("wrong error for invalid password\ngot %q\nwant %q", err, ErrDecrypt)
|
||||
}
|
||||
}
|
||||
|
||||
|
2
accounts/keystore/testdata/keystore/README
vendored
2
accounts/keystore/testdata/keystore/README
vendored
@@ -1,5 +1,5 @@
|
||||
This directory contains accounts for testing.
|
||||
The passphrase that unlocks them is "foobar".
|
||||
The password that unlocks them is "foobar".
|
||||
|
||||
The "good" key files which are supposed to be loadable are:
|
||||
|
||||
|
@@ -21,6 +21,7 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
@@ -162,6 +163,20 @@ func (am *Manager) Wallet(url string) (Wallet, error) {
|
||||
return nil, ErrUnknownWallet
|
||||
}
|
||||
|
||||
// Accounts returns all account addresses of all wallets within the account manager
|
||||
func (am *Manager) Accounts() []common.Address {
|
||||
am.lock.RLock()
|
||||
defer am.lock.RUnlock()
|
||||
|
||||
addresses := make([]common.Address, 0) // return [] instead of nil if empty
|
||||
for _, wallet := range am.wallets {
|
||||
for _, account := range wallet.Accounts() {
|
||||
addresses = append(addresses, account.Address)
|
||||
}
|
||||
}
|
||||
return addresses
|
||||
}
|
||||
|
||||
// Find attempts to locate the wallet corresponding to a specific account. Since
|
||||
// accounts can be dynamically added to and removed from wallets, this method has
|
||||
// a linear runtime in the number of wallets.
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017 The go-ethereum Authors
|
||||
// Copyright 2018 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
|
||||
|
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
@@ -341,7 +342,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
|
||||
op = ledgerP1ContTransactionData
|
||||
}
|
||||
// Extract the Ethereum signature and do a sanity validation
|
||||
if len(reply) != 65 {
|
||||
if len(reply) != crypto.SignatureLength {
|
||||
return common.Address{}, nil, errors.New("reply lacks signature")
|
||||
}
|
||||
signature := append(reply[1:], reply[0])
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// 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
|
||||
|
@@ -479,7 +479,8 @@ func (w *wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Accoun
|
||||
|
||||
if _, ok := w.paths[address]; !ok {
|
||||
w.accounts = append(w.accounts, account)
|
||||
w.paths[address] = path
|
||||
w.paths[address] = make(accounts.DerivationPath, len(path))
|
||||
copy(w.paths[address], path)
|
||||
}
|
||||
return account, nil
|
||||
}
|
||||
|
@@ -23,8 +23,8 @@ environment:
|
||||
install:
|
||||
- git submodule update --init
|
||||
- rmdir C:\go /s /q
|
||||
- appveyor DownloadFile https://dl.google.com/go/go1.12.7.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.12.7.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- appveyor DownloadFile https://dl.google.com/go/go1.13.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.13.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- go version
|
||||
- gcc --version
|
||||
|
||||
|
@@ -137,7 +137,8 @@ var (
|
||||
// Note: yakkety is unsupported because it was officially deprecated on Launchpad.
|
||||
// Note: zesty is unsupported because it was officially deprecated on Launchpad.
|
||||
// Note: artful is unsupported because it was officially deprecated on Launchpad.
|
||||
debDistros = []string{"trusty", "xenial", "bionic", "cosmic", "disco"}
|
||||
// Note: cosmic is unsupported because it was officially deprecated on Launchpad.
|
||||
debDistros = []string{"trusty", "xenial", "bionic", "disco", "eoan"}
|
||||
)
|
||||
|
||||
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
|
||||
@@ -213,7 +214,6 @@ func doInstall(cmdline []string) {
|
||||
if flag.NArg() > 0 {
|
||||
packages = flag.Args()
|
||||
}
|
||||
packages = build.ExpandPackagesNoVendor(packages)
|
||||
|
||||
if *arch == "" || *arch == runtime.GOARCH {
|
||||
goinstall := goTool("install", buildFlags(env)...)
|
||||
@@ -310,7 +310,6 @@ func doTest(cmdline []string) {
|
||||
if len(flag.CommandLine.Args()) > 0 {
|
||||
packages = flag.CommandLine.Args()
|
||||
}
|
||||
packages = build.ExpandPackagesNoVendor(packages)
|
||||
|
||||
// Run the actual tests.
|
||||
// Test a single package at a time. CI builders are slow
|
||||
@@ -899,7 +898,7 @@ func doXCodeFramework(cmdline []string) {
|
||||
// Build the iOS XCode framework
|
||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
|
||||
build.MustRun(gomobileTool("init"))
|
||||
bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||
bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||
|
||||
if *local {
|
||||
// If we're building locally, use the build folder and stop afterwards
|
||||
|
@@ -62,16 +62,22 @@ var (
|
||||
skipPrefixes = []string{
|
||||
// boring stuff
|
||||
"vendor/", "tests/testdata/", "build/",
|
||||
|
||||
// don't relicense vendored sources
|
||||
"cmd/internal/browser",
|
||||
"common/bitutil/bitutil",
|
||||
"common/prque/",
|
||||
"consensus/ethash/xor.go",
|
||||
"crypto/bn256/",
|
||||
"crypto/ecies/",
|
||||
"crypto/secp256k1/curve.go",
|
||||
"crypto/sha3/",
|
||||
"graphql/graphiql.go",
|
||||
"internal/jsre/deps",
|
||||
"log/",
|
||||
"common/bitutil/bitutil",
|
||||
"metrics/",
|
||||
"signer/rules/deps",
|
||||
|
||||
// skip special licenses
|
||||
"crypto/secp256k1", // Relicensed to BSD-3 via https://github.com/ethereum/go-ethereum/pull/17225
|
||||
}
|
||||
|
||||
// paths with this prefix are licensed as GPL. all other files are LGPL.
|
||||
@@ -144,6 +150,13 @@ func (i info) gpl() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// authors implements the sort.Interface for strings in case-insensitive mode.
|
||||
type authors []string
|
||||
|
||||
func (as authors) Len() int { return len(as) }
|
||||
func (as authors) Less(i, j int) bool { return strings.ToLower(as[i]) < strings.ToLower(as[j]) }
|
||||
func (as authors) Swap(i, j int) { as[i], as[j] = as[j], as[i] }
|
||||
|
||||
func main() {
|
||||
var (
|
||||
files = getFiles()
|
||||
@@ -262,27 +275,32 @@ func mailmapLookup(authors []string) []string {
|
||||
}
|
||||
|
||||
func writeAuthors(files []string) {
|
||||
merge := make(map[string]bool)
|
||||
// Add authors that Git reports as contributorxs.
|
||||
var (
|
||||
dedup = make(map[string]bool)
|
||||
list []string
|
||||
)
|
||||
// Add authors that Git reports as contributors.
|
||||
// This is the primary source of author information.
|
||||
for _, a := range gitAuthors(files) {
|
||||
merge[a] = true
|
||||
if la := strings.ToLower(a); !dedup[la] {
|
||||
list = append(list, a)
|
||||
dedup[la] = true
|
||||
}
|
||||
}
|
||||
// Add existing authors from the file. This should ensure that we
|
||||
// never lose authors, even if Git stops listing them. We can also
|
||||
// add authors manually this way.
|
||||
for _, a := range readAuthors() {
|
||||
merge[a] = true
|
||||
if la := strings.ToLower(a); !dedup[la] {
|
||||
list = append(list, a)
|
||||
dedup[la] = true
|
||||
}
|
||||
}
|
||||
// Write sorted list of authors back to the file.
|
||||
var result []string
|
||||
for a := range merge {
|
||||
result = append(result, a)
|
||||
}
|
||||
sort.Strings(result)
|
||||
sort.Sort(authors(list))
|
||||
content := new(bytes.Buffer)
|
||||
content.WriteString(authorsFileHeader)
|
||||
for _, a := range result {
|
||||
for _, a := range list {
|
||||
content.WriteString(a)
|
||||
content.WriteString("\n")
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
|
@@ -566,8 +566,8 @@ Response
|
||||
### account_export
|
||||
|
||||
#### Export account from keystore
|
||||
Export a private key from the keystore. The exported private key is encrypted with the original passphrase. When the
|
||||
key is imported later this passphrase is required.
|
||||
Export a private key from the keystore. The exported private key is encrypted with the original password. When the
|
||||
key is imported later this password is required.
|
||||
|
||||
#### Arguments
|
||||
- account [address]: export private key that is associated with this account
|
||||
@@ -914,7 +914,7 @@ A UI should conform to the following rules.
|
||||
* For example, not load icons, stylesheets from the internet
|
||||
* Not load files from the filesystem, unless they reside in the same local directory (e.g. config files)
|
||||
* A Graphical UI MUST show the blocky-identicon for ethereum addresses.
|
||||
* A UI MUST warn display approproate warning if the destination-account is formatted with invalid checksum.
|
||||
* A UI MUST warn display appropriate warning if the destination-account is formatted with invalid checksum.
|
||||
* A UI MUST NOT open any ports or services
|
||||
* The signer opens the public port
|
||||
* A UI SHOULD verify the permissions on the signer binary, and refuse to execute or warn if permissions allow non-user write.
|
||||
|
@@ -53,6 +53,8 @@ import (
|
||||
"github.com/ethereum/go-ethereum/signer/fourbyte"
|
||||
"github.com/ethereum/go-ethereum/signer/rules"
|
||||
"github.com/ethereum/go-ethereum/signer/storage"
|
||||
colorable "github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
@@ -333,7 +335,7 @@ func setCredential(ctx *cli.Context) error {
|
||||
utils.Fatalf("Invalid address specified: %s", addr)
|
||||
}
|
||||
address := common.HexToAddress(addr)
|
||||
password := getPassPhrase("Please enter a passphrase to store for this address:", true)
|
||||
password := getPassPhrase("Please enter a password to store for this address:", true)
|
||||
fmt.Println()
|
||||
|
||||
stretchedKey, err := readMasterKey(ctx, nil)
|
||||
@@ -392,7 +394,13 @@ func initialize(c *cli.Context) error {
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int(logLevelFlag.Name)), log.StreamHandler(logOutput, log.TerminalFormat(true))))
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(logOutput)
|
||||
if usecolor {
|
||||
output = colorable.NewColorable(logOutput)
|
||||
}
|
||||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int(logLevelFlag.Name)), log.StreamHandler(output, log.TerminalFormat(usecolor))))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -767,8 +775,8 @@ func testExternalUI(api *core.SignerAPI) {
|
||||
data := `{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Person":[{"name":"name","type":"string"},{"name":"test","type":"uint8"},{"name":"wallet","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person"},{"name":"contents","type":"string"}]},"primaryType":"Mail","domain":{"name":"Ether Mail","version":"1","chainId":"1","verifyingContract":"0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","test":"3","wallet":"0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","test":"2"},"contents":"Hello, Bob!"}}`
|
||||
//_, err := api.SignData(ctx, accounts.MimetypeTypedData, *addr, hexutil.Encode([]byte(data)))
|
||||
var typedData core.TypedData
|
||||
err := json.Unmarshal([]byte(data), &typedData)
|
||||
_, err = api.SignTypedData(ctx, *addr, typedData)
|
||||
json.Unmarshal([]byte(data), &typedData)
|
||||
_, err := api.SignTypedData(ctx, *addr, typedData)
|
||||
expectApprove("sign 712 typed data", err)
|
||||
}
|
||||
{ // Sign data test - plain text
|
||||
@@ -837,17 +845,17 @@ func testExternalUI(api *core.SignerAPI) {
|
||||
// TODO: there are many `getPassPhrase` functions, it will be better to abstract them into one.
|
||||
func getPassPhrase(prompt string, confirmation bool) string {
|
||||
fmt.Println(prompt)
|
||||
password, err := console.Stdin.PromptPassword("Passphrase: ")
|
||||
password, err := console.Stdin.PromptPassword("Password: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase: %v", err)
|
||||
utils.Fatalf("Failed to read password: %v", err)
|
||||
}
|
||||
if confirmation {
|
||||
confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
|
||||
confirm, err := console.Stdin.PromptPassword("Repeat password: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase confirmation: %v", err)
|
||||
utils.Fatalf("Failed to read password confirmation: %v", err)
|
||||
}
|
||||
if password != confirm {
|
||||
utils.Fatalf("Passphrases do not match")
|
||||
utils.Fatalf("Passwords do not match")
|
||||
}
|
||||
}
|
||||
return password
|
||||
|
@@ -70,7 +70,7 @@ The Otto vm has a few [caveats](https://github.com/robertkrimen/otto):
|
||||
Additionally, a few more have been added
|
||||
|
||||
* The rule execution cannot load external javascript files.
|
||||
* The only preloaded libary is [`bignumber.js`](https://github.com/MikeMcl/bignumber.js) version `2.0.3`. This one is fairly old, and is not aligned with the documentation at the github repository.
|
||||
* The only preloaded library is [`bignumber.js`](https://github.com/MikeMcl/bignumber.js) version `2.0.3`. This one is fairly old, and is not aligned with the documentation at the github repository.
|
||||
* Each invocation is made in a fresh virtual machine. This means that you cannot store data in global variables between invocations. This is a deliberate choice -- if you want to store data, use the disk-backed `storage`, since rules should not rely on ephemeral data.
|
||||
* Javascript API parameters are _always_ an object. This is also a design choice, to ensure that parameters are accessed by _key_ and not by order. This is to prevent mistakes due to missing parameters or parameter changes.
|
||||
* The JS engine has access to `storage` and `console`.
|
||||
|
@@ -1,3 +1,19 @@
|
||||
// Copyright 2019 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/>.
|
||||
|
||||
// This file is a test-utility for testing clef-functionality
|
||||
//
|
||||
// Start clef with
|
||||
|
@@ -22,8 +22,8 @@ Enter 'ok' to proceed:
|
||||
|
||||
The master seed of clef will be locked with a password.
|
||||
Please specify a password. Do not forget this password!
|
||||
Passphrase:
|
||||
Repeat passphrase:
|
||||
Password:
|
||||
Repeat password:
|
||||
|
||||
A master seed has been generated into /home/martin/.clef/masterseed.json
|
||||
|
||||
@@ -124,7 +124,7 @@ $ sha256sum rules.js
|
||||
|
||||
$ clef attest 645b58e4f945e24d0221714ff29f6aa8e860382ced43490529db1695f5fcc71c
|
||||
Decrypt master seed of clef
|
||||
Passphrase:
|
||||
Password:
|
||||
INFO [07-01|13:25:03.290] Ruleset attestation updated sha256=645b58e4f945e24d0221714ff29f6aa8e860382ced43490529db1695f5fcc71c
|
||||
```
|
||||
|
||||
@@ -193,12 +193,12 @@ In order to make more useful rules - like signing transactions - the signer need
|
||||
```text
|
||||
$ clef setpw 0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3
|
||||
|
||||
Please enter a passphrase to store for this address:
|
||||
Passphrase:
|
||||
Repeat passphrase:
|
||||
Please enter a password to store for this address:
|
||||
Password:
|
||||
Repeat password:
|
||||
|
||||
Decrypt master seed of clef
|
||||
Passphrase:
|
||||
Password:
|
||||
INFO [07-01|14:05:56.031] Credential store updated key=0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3
|
||||
```
|
||||
|
||||
@@ -227,7 +227,7 @@ In this example:
|
||||
- Auto-rejected if the message does not contain `bazonk`,
|
||||
- Any other requests will be passed along for manual confirmation.
|
||||
|
||||
*Note, to make this example work, please use you own accounts. You can create a new account either via Clef or the traditional account CLI tools. If the latter was chosen, make sure both Clef and Geth use the same keystore by specifing `--keystore path/to/your/keystore` when running Clef.*
|
||||
*Note, to make this example work, please use you own accounts. You can create a new account either via Clef or the traditional account CLI tools. If the latter was chosen, make sure both Clef and Geth use the same keystore by specifying `--keystore path/to/your/keystore` when running Clef.*
|
||||
|
||||
Attest the new rule file so that Clef will accept loading it:
|
||||
|
||||
@@ -237,7 +237,7 @@ f163a1738b649259bb9b369c593fdc4c6b6f86cc87e343c3ba58faee03c2a178 rules.js
|
||||
|
||||
$ clef attest f163a1738b649259bb9b369c593fdc4c6b6f86cc87e343c3ba58faee03c2a178
|
||||
Decrypt master seed of clef
|
||||
Passphrase:
|
||||
Password:
|
||||
INFO [07-01|14:11:28.509] Ruleset attestation updated sha256=f163a1738b649259bb9b369c593fdc4c6b6f86cc87e343c3ba58faee03c2a178
|
||||
```
|
||||
|
||||
|
@@ -35,18 +35,18 @@ It is possible to refer to a file containing the message.
|
||||
To sign a message contained in a file, use the --msgfile flag.
|
||||
|
||||
|
||||
### `ethkey changepassphrase <keyfile>`
|
||||
### `ethkey changepassword <keyfile>`
|
||||
|
||||
Change the passphrase of a keyfile.
|
||||
Change the password of a keyfile.
|
||||
use the `--newpasswordfile` to point to the new password file.
|
||||
|
||||
|
||||
## Passphrases
|
||||
## Passwords
|
||||
|
||||
For every command that uses a keyfile, you will be prompted to provide the
|
||||
passphrase for decrypting the keyfile. To avoid this message, it is possible
|
||||
to pass the passphrase by using the `--passwordfile` flag pointing to a file that
|
||||
contains the passphrase.
|
||||
password for decrypting the keyfile. To avoid this message, it is possible
|
||||
to pass the password by using the `--passwordfile` flag pointing to a file that
|
||||
contains the password.
|
||||
|
||||
## JSON
|
||||
|
||||
|
@@ -1,3 +1,19 @@
|
||||
// Copyright 2018 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
|
||||
|
||||
import (
|
||||
@@ -12,15 +28,15 @@ import (
|
||||
|
||||
var newPassphraseFlag = cli.StringFlag{
|
||||
Name: "newpasswordfile",
|
||||
Usage: "the file that contains the new passphrase for the keyfile",
|
||||
Usage: "the file that contains the new password for the keyfile",
|
||||
}
|
||||
|
||||
var commandChangePassphrase = cli.Command{
|
||||
Name: "changepassphrase",
|
||||
Usage: "change the passphrase on a keyfile",
|
||||
Name: "changepassword",
|
||||
Usage: "change the password on a keyfile",
|
||||
ArgsUsage: "<keyfile>",
|
||||
Description: `
|
||||
Change the passphrase of a keyfile.`,
|
||||
Change the password of a keyfile.`,
|
||||
Flags: []cli.Flag{
|
||||
passphraseFlag,
|
||||
newPassphraseFlag,
|
||||
@@ -42,12 +58,12 @@ Change the passphrase of a keyfile.`,
|
||||
}
|
||||
|
||||
// Get a new passphrase.
|
||||
fmt.Println("Please provide a new passphrase")
|
||||
fmt.Println("Please provide a new password")
|
||||
var newPhrase string
|
||||
if passFile := ctx.String(newPassphraseFlag.Name); passFile != "" {
|
||||
content, err := ioutil.ReadFile(passFile)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read new passphrase file '%s': %v", passFile, err)
|
||||
utils.Fatalf("Failed to read new password file '%s': %v", passFile, err)
|
||||
}
|
||||
newPhrase = strings.TrimRight(string(content), "\r\n")
|
||||
} else {
|
||||
@@ -57,7 +73,7 @@ Change the passphrase of a keyfile.`,
|
||||
// Encrypt the key with the new passphrase.
|
||||
newJson, err := keystore.EncryptKey(key, newPhrase, keystore.StandardScryptN, keystore.StandardScryptP)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error encrypting with new passphrase: %v", err)
|
||||
utils.Fatalf("Error encrypting with new password: %v", err)
|
||||
}
|
||||
|
||||
// Then write the new keyfile in place of the old one.
|
@@ -49,7 +49,7 @@ func init() {
|
||||
var (
|
||||
passphraseFlag = cli.StringFlag{
|
||||
Name: "passwordfile",
|
||||
Usage: "the file that contains the passphrase for the keyfile",
|
||||
Usage: "the file that contains the password for the keyfile",
|
||||
}
|
||||
jsonFlag = cli.BoolFlag{
|
||||
Name: "json",
|
||||
|
@@ -37,8 +37,8 @@ func TestMessageSignVerify(t *testing.T) {
|
||||
generate := runEthkey(t, "generate", keyfile)
|
||||
generate.Expect(`
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "foobar"}}
|
||||
Repeat passphrase: {{.InputLine "foobar"}}
|
||||
Password: {{.InputLine "foobar"}}
|
||||
Repeat password: {{.InputLine "foobar"}}
|
||||
`)
|
||||
_, matches := generate.ExpectRegexp(`Address: (0x[0-9a-fA-F]{40})\n`)
|
||||
address := matches[1]
|
||||
@@ -48,7 +48,7 @@ Repeat passphrase: {{.InputLine "foobar"}}
|
||||
sign := runEthkey(t, "signmessage", keyfile, message)
|
||||
sign.Expect(`
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "foobar"}}
|
||||
Password: {{.InputLine "foobar"}}
|
||||
`)
|
||||
_, matches = sign.ExpectRegexp(`Signature: ([0-9a-f]+)\n`)
|
||||
signature := matches[1]
|
||||
|
@@ -31,18 +31,18 @@ import (
|
||||
// promptPassphrase prompts the user for a passphrase. Set confirmation to true
|
||||
// to require the user to confirm the passphrase.
|
||||
func promptPassphrase(confirmation bool) string {
|
||||
passphrase, err := console.Stdin.PromptPassword("Passphrase: ")
|
||||
passphrase, err := console.Stdin.PromptPassword("Password: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase: %v", err)
|
||||
utils.Fatalf("Failed to read password: %v", err)
|
||||
}
|
||||
|
||||
if confirmation {
|
||||
confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
|
||||
confirm, err := console.Stdin.PromptPassword("Repeat password: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase confirmation: %v", err)
|
||||
utils.Fatalf("Failed to read password confirmation: %v", err)
|
||||
}
|
||||
if passphrase != confirm {
|
||||
utils.Fatalf("Passphrases do not match")
|
||||
utils.Fatalf("Passwords do not match")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func getPassphrase(ctx *cli.Context) string {
|
||||
if passphraseFile != "" {
|
||||
content, err := ioutil.ReadFile(passphraseFile)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase file '%s': %v",
|
||||
utils.Fatalf("Failed to read password file '%s': %v",
|
||||
passphraseFile, err)
|
||||
}
|
||||
return strings.TrimRight(string(content), "\r\n")
|
||||
|
@@ -198,6 +198,8 @@ func runCmd(ctx *cli.Context) error {
|
||||
|
||||
if chainConfig != nil {
|
||||
runtimeConfig.ChainConfig = chainConfig
|
||||
} else {
|
||||
runtimeConfig.ChainConfig = params.AllEthashProtocolChanges
|
||||
}
|
||||
tstart := time.Now()
|
||||
var leftOverGas uint64
|
||||
|
@@ -506,7 +506,10 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
|
||||
Time: time.Now(),
|
||||
Tx: signed,
|
||||
})
|
||||
f.timeouts[username] = time.Now().Add(time.Duration(*minutesFlag*int(math.Pow(3, float64(msg.Tier)))) * time.Minute)
|
||||
timeout := time.Duration(*minutesFlag*int(math.Pow(3, float64(msg.Tier)))) * time.Minute
|
||||
grace := timeout / 288 // 24h timeout => 5m grace
|
||||
|
||||
f.timeouts[username] = time.Now().Add(timeout - grace)
|
||||
fund = true
|
||||
}
|
||||
f.lock.Unlock()
|
||||
|
@@ -116,11 +116,11 @@ Print a short summary of all accounts`,
|
||||
|
||||
Creates a new account and prints the address.
|
||||
|
||||
The account is saved in encrypted format, you are prompted for a passphrase.
|
||||
The account is saved in encrypted format, you are prompted for a password.
|
||||
|
||||
You must remember this passphrase to unlock your account in the future.
|
||||
You must remember this password to unlock your account in the future.
|
||||
|
||||
For non-interactive use the passphrase can be specified with the --password flag:
|
||||
For non-interactive use the password can be specified with the --password flag:
|
||||
|
||||
Note, this is meant to be used for testing only, it is a bad idea to save your
|
||||
password to file or expose in any other way.
|
||||
@@ -142,12 +142,12 @@ password to file or expose in any other way.
|
||||
Update an existing account.
|
||||
|
||||
The account is saved in the newest version in encrypted format, you are prompted
|
||||
for a passphrase to unlock the account and another to save the updated file.
|
||||
for a password to unlock the account and another to save the updated file.
|
||||
|
||||
This same command can therefore be used to migrate an account of a deprecated
|
||||
format to the newest format or change the password for an account.
|
||||
|
||||
For non-interactive use the passphrase can be specified with the --password flag:
|
||||
For non-interactive use the password can be specified with the --password flag:
|
||||
|
||||
geth account update [options] <address>
|
||||
|
||||
@@ -174,11 +174,11 @@ Prints the address.
|
||||
|
||||
The keyfile is assumed to contain an unencrypted private key in hexadecimal format.
|
||||
|
||||
The account is saved in encrypted format, you are prompted for a passphrase.
|
||||
The account is saved in encrypted format, you are prompted for a password.
|
||||
|
||||
You must remember this passphrase to unlock your account in the future.
|
||||
You must remember this password to unlock your account in the future.
|
||||
|
||||
For non-interactive use the passphrase can be specified with the -password flag:
|
||||
For non-interactive use the password can be specified with the -password flag:
|
||||
|
||||
geth account import [options] <keyfile>
|
||||
|
||||
@@ -247,17 +247,17 @@ func getPassPhrase(prompt string, confirmation bool, i int, passwords []string)
|
||||
if prompt != "" {
|
||||
fmt.Println(prompt)
|
||||
}
|
||||
password, err := console.Stdin.PromptPassword("Passphrase: ")
|
||||
password, err := console.Stdin.PromptPassword("Password: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase: %v", err)
|
||||
utils.Fatalf("Failed to read password: %v", err)
|
||||
}
|
||||
if confirmation {
|
||||
confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
|
||||
confirm, err := console.Stdin.PromptPassword("Repeat password: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase confirmation: %v", err)
|
||||
utils.Fatalf("Failed to read password confirmation: %v", err)
|
||||
}
|
||||
if password != confirm {
|
||||
utils.Fatalf("Passphrases do not match")
|
||||
utils.Fatalf("Passwords do not match")
|
||||
}
|
||||
}
|
||||
return password
|
||||
@@ -268,7 +268,7 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr
|
||||
for _, a := range err.Matches {
|
||||
fmt.Println(" ", a.URL)
|
||||
}
|
||||
fmt.Println("Testing your passphrase against all of them...")
|
||||
fmt.Println("Testing your password against all of them...")
|
||||
var match *accounts.Account
|
||||
for _, a := range err.Matches {
|
||||
if err := ks.Unlock(a, auth); err == nil {
|
||||
@@ -279,7 +279,7 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr
|
||||
if match == nil {
|
||||
utils.Fatalf("None of the listed files could be unlocked.")
|
||||
}
|
||||
fmt.Printf("Your passphrase unlocked %s\n", match.URL)
|
||||
fmt.Printf("Your password unlocked %s\n", match.URL)
|
||||
fmt.Println("In order to avoid this warning, you need to remove the following duplicate key files:")
|
||||
for _, a := range err.Matches {
|
||||
if a != *match {
|
||||
|
@@ -72,8 +72,8 @@ func TestAccountNew(t *testing.T) {
|
||||
geth.Expect(`
|
||||
Your new account is locked with a password. Please give a password. Do not forget this password.
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "foobar"}}
|
||||
Repeat passphrase: {{.InputLine "foobar"}}
|
||||
Password: {{.InputLine "foobar"}}
|
||||
Repeat password: {{.InputLine "foobar"}}
|
||||
|
||||
Your new key was generated
|
||||
`)
|
||||
@@ -94,9 +94,9 @@ func TestAccountNewBadRepeat(t *testing.T) {
|
||||
geth.Expect(`
|
||||
Your new account is locked with a password. Please give a password. Do not forget this password.
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "something"}}
|
||||
Repeat passphrase: {{.InputLine "something else"}}
|
||||
Fatal: Passphrases do not match
|
||||
Password: {{.InputLine "something"}}
|
||||
Repeat password: {{.InputLine "something else"}}
|
||||
Fatal: Passwords do not match
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -109,10 +109,10 @@ func TestAccountUpdate(t *testing.T) {
|
||||
geth.Expect(`
|
||||
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "foobar"}}
|
||||
Password: {{.InputLine "foobar"}}
|
||||
Please give a new password. Do not forget this password.
|
||||
Passphrase: {{.InputLine "foobar2"}}
|
||||
Repeat passphrase: {{.InputLine "foobar2"}}
|
||||
Password: {{.InputLine "foobar2"}}
|
||||
Repeat password: {{.InputLine "foobar2"}}
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ func TestWalletImport(t *testing.T) {
|
||||
defer geth.ExpectExit()
|
||||
geth.Expect(`
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "foo"}}
|
||||
Password: {{.InputLine "foo"}}
|
||||
Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f}
|
||||
`)
|
||||
|
||||
@@ -136,8 +136,8 @@ func TestWalletImportBadPassword(t *testing.T) {
|
||||
defer geth.ExpectExit()
|
||||
geth.Expect(`
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "wrong"}}
|
||||
Fatal: could not decrypt key with given passphrase
|
||||
Password: {{.InputLine "wrong"}}
|
||||
Fatal: could not decrypt key with given password
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ func TestUnlockFlag(t *testing.T) {
|
||||
geth.Expect(`
|
||||
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "foobar"}}
|
||||
Password: {{.InputLine "foobar"}}
|
||||
`)
|
||||
geth.ExpectExit()
|
||||
|
||||
@@ -174,12 +174,12 @@ func TestUnlockFlagWrongPassword(t *testing.T) {
|
||||
geth.Expect(`
|
||||
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "wrong1"}}
|
||||
Password: {{.InputLine "wrong1"}}
|
||||
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 2/3
|
||||
Passphrase: {{.InputLine "wrong2"}}
|
||||
Password: {{.InputLine "wrong2"}}
|
||||
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 3/3
|
||||
Passphrase: {{.InputLine "wrong3"}}
|
||||
Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could not decrypt key with given passphrase)
|
||||
Password: {{.InputLine "wrong3"}}
|
||||
Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could not decrypt key with given password)
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -193,9 +193,9 @@ func TestUnlockFlagMultiIndex(t *testing.T) {
|
||||
geth.Expect(`
|
||||
Unlocking account 0 | Attempt 1/3
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "foobar"}}
|
||||
Password: {{.InputLine "foobar"}}
|
||||
Unlocking account 2 | Attempt 1/3
|
||||
Passphrase: {{.InputLine "foobar"}}
|
||||
Password: {{.InputLine "foobar"}}
|
||||
`)
|
||||
geth.ExpectExit()
|
||||
|
||||
@@ -238,7 +238,7 @@ func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) {
|
||||
"--password", "testdata/wrong-passwords.txt", "--unlock", "0,2")
|
||||
defer geth.ExpectExit()
|
||||
geth.Expect(`
|
||||
Fatal: Failed to unlock account 0 (could not decrypt key with given passphrase)
|
||||
Fatal: Failed to unlock account 0 (could not decrypt key with given password)
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -258,12 +258,12 @@ func TestUnlockFlagAmbiguous(t *testing.T) {
|
||||
geth.Expect(`
|
||||
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "foobar"}}
|
||||
Password: {{.InputLine "foobar"}}
|
||||
Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a:
|
||||
keystore://{{keypath "1"}}
|
||||
keystore://{{keypath "2"}}
|
||||
Testing your passphrase against all of them...
|
||||
Your passphrase unlocked keystore://{{keypath "1"}}
|
||||
Testing your password against all of them...
|
||||
Your password unlocked keystore://{{keypath "1"}}
|
||||
In order to avoid this warning, you need to remove the following duplicate key files:
|
||||
keystore://{{keypath "2"}}
|
||||
`)
|
||||
@@ -295,11 +295,11 @@ func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) {
|
||||
geth.Expect(`
|
||||
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
|
||||
!! Unsupported terminal, password will be echoed.
|
||||
Passphrase: {{.InputLine "wrong"}}
|
||||
Password: {{.InputLine "wrong"}}
|
||||
Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a:
|
||||
keystore://{{keypath "1"}}
|
||||
keystore://{{keypath "2"}}
|
||||
Testing your passphrase against all of them...
|
||||
Testing your password against all of them...
|
||||
Fatal: None of the listed files could be unlocked.
|
||||
`)
|
||||
geth.ExpectExit()
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"reflect"
|
||||
"unicode"
|
||||
@@ -150,6 +151,9 @@ func enableWhisper(ctx *cli.Context) bool {
|
||||
|
||||
func makeFullNode(ctx *cli.Context) *node.Node {
|
||||
stack, cfg := makeConfigNode(ctx)
|
||||
if ctx.GlobalIsSet(utils.OverrideIstanbulFlag.Name) {
|
||||
cfg.Eth.OverrideIstanbul = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideIstanbulFlag.Name))
|
||||
}
|
||||
utils.RegisterEthService(stack, &cfg.Eth)
|
||||
|
||||
if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) {
|
||||
|
@@ -77,6 +77,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Cons
|
||||
// same time.
|
||||
func localConsole(ctx *cli.Context) error {
|
||||
// Create and start the node based on the CLI flags
|
||||
prepare(ctx)
|
||||
node := makeFullNode(ctx)
|
||||
startNode(ctx, node)
|
||||
defer node.Close()
|
||||
|
@@ -87,7 +87,7 @@ func TestIPCAttachWelcome(t *testing.T) {
|
||||
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
||||
"--etherbase", coinbase, "--shh", "--ipcpath", ipc)
|
||||
|
||||
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
||||
waitForEndpoint(t, ipc, 3*time.Second)
|
||||
testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs)
|
||||
|
||||
geth.Interrupt()
|
||||
@@ -101,8 +101,9 @@ func TestHTTPAttachWelcome(t *testing.T) {
|
||||
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
||||
"--etherbase", coinbase, "--rpc", "--rpcport", port)
|
||||
|
||||
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
||||
testAttachWelcome(t, geth, "http://localhost:"+port, httpAPIs)
|
||||
endpoint := "http://127.0.0.1:" + port
|
||||
waitForEndpoint(t, endpoint, 3*time.Second)
|
||||
testAttachWelcome(t, geth, endpoint, httpAPIs)
|
||||
|
||||
geth.Interrupt()
|
||||
geth.ExpectExit()
|
||||
@@ -116,8 +117,9 @@ func TestWSAttachWelcome(t *testing.T) {
|
||||
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
||||
"--etherbase", coinbase, "--ws", "--wsport", port)
|
||||
|
||||
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
||||
testAttachWelcome(t, geth, "ws://localhost:"+port, httpAPIs)
|
||||
endpoint := "ws://127.0.0.1:" + port
|
||||
waitForEndpoint(t, endpoint, 3*time.Second)
|
||||
testAttachWelcome(t, geth, endpoint, httpAPIs)
|
||||
|
||||
geth.Interrupt()
|
||||
geth.ExpectExit()
|
||||
|
@@ -69,6 +69,7 @@ var (
|
||||
utils.ExternalSignerFlag,
|
||||
utils.NoUSBFlag,
|
||||
utils.SmartCardDaemonPathFlag,
|
||||
utils.OverrideIstanbulFlag,
|
||||
utils.DashboardEnabledFlag,
|
||||
utils.DashboardAddrFlag,
|
||||
utils.DashboardPortFlag,
|
||||
@@ -242,46 +243,6 @@ func init() {
|
||||
if err := debug.Setup(ctx, logdir); err != nil {
|
||||
return err
|
||||
}
|
||||
// If we're a full node on mainnet without --cache specified, bump default cache allowance
|
||||
if ctx.GlobalString(utils.SyncModeFlag.Name) != "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) && !ctx.GlobalIsSet(utils.NetworkIdFlag.Name) {
|
||||
// Make sure we're not on any supported preconfigured testnet either
|
||||
if !ctx.GlobalIsSet(utils.TestnetFlag.Name) && !ctx.GlobalIsSet(utils.RinkebyFlag.Name) && !ctx.GlobalIsSet(utils.GoerliFlag.Name) {
|
||||
// Nope, we're really on mainnet. Bump that cache up!
|
||||
log.Info("Bumping default cache on mainnet", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 4096)
|
||||
ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(4096))
|
||||
}
|
||||
}
|
||||
// If we're running a light client on any network, drop the cache to some meaningfully low amount
|
||||
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) {
|
||||
log.Info("Dropping default light client cache", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 128)
|
||||
ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(128))
|
||||
}
|
||||
// Cap the cache allowance and tune the garbage collector
|
||||
var mem gosigar.Mem
|
||||
// Workaround until OpenBSD support lands into gosigar
|
||||
// Check https://github.com/elastic/gosigar#supported-platforms
|
||||
if runtime.GOOS != "openbsd" {
|
||||
if err := mem.Get(); err == nil {
|
||||
allowance := int(mem.Total / 1024 / 1024 / 3)
|
||||
if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance {
|
||||
log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance)
|
||||
ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure Go's GC ignores the database cache for trigger percentage
|
||||
cache := ctx.GlobalInt(utils.CacheFlag.Name)
|
||||
gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024)))
|
||||
|
||||
log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc))
|
||||
godebug.SetGCPercent(int(gogc))
|
||||
|
||||
// Start metrics export if enabled
|
||||
utils.SetupMetrics(ctx)
|
||||
|
||||
// Start system runtime metrics collection
|
||||
go metrics.CollectProcessMetrics(3 * time.Second)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -299,6 +260,50 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// prepare manipulates memory cache allowance and setups metric system.
|
||||
// This function should be called before launching devp2p stack.
|
||||
func prepare(ctx *cli.Context) {
|
||||
// If we're a full node on mainnet without --cache specified, bump default cache allowance
|
||||
if ctx.GlobalString(utils.SyncModeFlag.Name) != "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) && !ctx.GlobalIsSet(utils.NetworkIdFlag.Name) {
|
||||
// Make sure we're not on any supported preconfigured testnet either
|
||||
if !ctx.GlobalIsSet(utils.TestnetFlag.Name) && !ctx.GlobalIsSet(utils.RinkebyFlag.Name) && !ctx.GlobalIsSet(utils.GoerliFlag.Name) && !ctx.GlobalIsSet(utils.DeveloperFlag.Name) {
|
||||
// Nope, we're really on mainnet. Bump that cache up!
|
||||
log.Info("Bumping default cache on mainnet", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 4096)
|
||||
ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(4096))
|
||||
}
|
||||
}
|
||||
// If we're running a light client on any network, drop the cache to some meaningfully low amount
|
||||
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) {
|
||||
log.Info("Dropping default light client cache", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 128)
|
||||
ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(128))
|
||||
}
|
||||
// Cap the cache allowance and tune the garbage collector
|
||||
var mem gosigar.Mem
|
||||
// Workaround until OpenBSD support lands into gosigar
|
||||
// Check https://github.com/elastic/gosigar#supported-platforms
|
||||
if runtime.GOOS != "openbsd" {
|
||||
if err := mem.Get(); err == nil {
|
||||
allowance := int(mem.Total / 1024 / 1024 / 3)
|
||||
if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance {
|
||||
log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance)
|
||||
ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure Go's GC ignores the database cache for trigger percentage
|
||||
cache := ctx.GlobalInt(utils.CacheFlag.Name)
|
||||
gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024)))
|
||||
|
||||
log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc))
|
||||
godebug.SetGCPercent(int(gogc))
|
||||
|
||||
// Start metrics export if enabled
|
||||
utils.SetupMetrics(ctx)
|
||||
|
||||
// Start system runtime metrics collection
|
||||
go metrics.CollectProcessMetrics(3 * time.Second)
|
||||
}
|
||||
|
||||
// geth is the main entry point into the system if no special subcommand is ran.
|
||||
// It creates a default node based on the command line arguments and runs it in
|
||||
// blocking mode, waiting for it to be shut down.
|
||||
@@ -306,6 +311,7 @@ func geth(ctx *cli.Context) error {
|
||||
if args := ctx.Args(); len(args) > 0 {
|
||||
return fmt.Errorf("invalid command: %q", args[0])
|
||||
}
|
||||
prepare(ctx)
|
||||
node := makeFullNode(ctx)
|
||||
defer node.Close()
|
||||
startNode(ctx, node)
|
||||
|
@@ -86,7 +86,7 @@ type RetestethEthAPI interface {
|
||||
}
|
||||
|
||||
type RetestethDebugAPI interface {
|
||||
AccountRangeAt(ctx context.Context,
|
||||
AccountRange(ctx context.Context,
|
||||
blockHashOrNumber *math.HexOrDecimal256, txIndex uint64,
|
||||
addressHash *math.HexOrDecimal256, maxResults uint64,
|
||||
) (AccountRangeResult, error)
|
||||
@@ -132,6 +132,7 @@ type CParamsParams struct {
|
||||
ByzantiumForkBlock *math.HexOrDecimal64 `json:"byzantiumForkBlock"`
|
||||
ConstantinopleForkBlock *math.HexOrDecimal64 `json:"constantinopleForkBlock"`
|
||||
ConstantinopleFixForkBlock *math.HexOrDecimal64 `json:"constantinopleFixForkBlock"`
|
||||
IstanbulBlock *math.HexOrDecimal64 `json:"istanbulForkBlock"`
|
||||
ChainID *math.HexOrDecimal256 `json:"chainID"`
|
||||
MaximumExtraDataSize math.HexOrDecimal64 `json:"maximumExtraDataSize"`
|
||||
TieBreakingGas bool `json:"tieBreakingGas"`
|
||||
@@ -319,6 +320,7 @@ func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainPa
|
||||
byzantiumBlock *big.Int
|
||||
constantinopleBlock *big.Int
|
||||
petersburgBlock *big.Int
|
||||
istanbulBlock *big.Int
|
||||
)
|
||||
if chainParams.Params.HomesteadForkBlock != nil {
|
||||
homesteadBlock = big.NewInt(int64(*chainParams.Params.HomesteadForkBlock))
|
||||
@@ -345,6 +347,10 @@ func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainPa
|
||||
if constantinopleBlock != nil && petersburgBlock == nil {
|
||||
petersburgBlock = big.NewInt(100000000000)
|
||||
}
|
||||
if chainParams.Params.IstanbulBlock != nil {
|
||||
istanbulBlock = big.NewInt(int64(*chainParams.Params.IstanbulBlock))
|
||||
}
|
||||
|
||||
genesis := &core.Genesis{
|
||||
Config: ¶ms.ChainConfig{
|
||||
ChainID: chainId,
|
||||
@@ -357,6 +363,7 @@ func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainPa
|
||||
ByzantiumBlock: byzantiumBlock,
|
||||
ConstantinopleBlock: constantinopleBlock,
|
||||
PetersburgBlock: petersburgBlock,
|
||||
IstanbulBlock: istanbulBlock,
|
||||
},
|
||||
Nonce: uint64(chainParams.Genesis.Nonce),
|
||||
Timestamp: uint64(chainParams.Genesis.Timestamp),
|
||||
@@ -501,7 +508,7 @@ func (api *RetestethAPI) mineBlock() error {
|
||||
statedb.Prepare(tx.Hash(), common.Hash{}, txCount)
|
||||
snap := statedb.Snapshot()
|
||||
|
||||
receipt, _, err := core.ApplyTransaction(
|
||||
receipt, err := core.ApplyTransaction(
|
||||
api.chainConfig,
|
||||
api.blockchain,
|
||||
&api.author,
|
||||
@@ -533,6 +540,9 @@ func (api *RetestethAPI) mineBlock() error {
|
||||
}
|
||||
}
|
||||
block, err := api.engine.FinalizeAndAssemble(api.blockchain, header, statedb, txs, []*types.Header{}, receipts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return api.importBlock(block)
|
||||
}
|
||||
|
||||
@@ -604,7 +614,7 @@ func (api *RetestethAPI) GetBlockByNumber(ctx context.Context, blockNr math.HexO
|
||||
return nil, fmt.Errorf("block %d not found", blockNr)
|
||||
}
|
||||
|
||||
func (api *RetestethAPI) AccountRangeAt(ctx context.Context,
|
||||
func (api *RetestethAPI) AccountRange(ctx context.Context,
|
||||
blockHashOrNumber *math.HexOrDecimal256, txIndex uint64,
|
||||
addressHash *math.HexOrDecimal256, maxResults uint64,
|
||||
) (AccountRangeResult, error) {
|
||||
@@ -669,7 +679,7 @@ func (api *RetestethAPI) AccountRangeAt(ctx context.Context,
|
||||
}
|
||||
it := trie.NewIterator(accountTrie.NodeIterator(common.BigToHash((*big.Int)(addressHash)).Bytes()))
|
||||
result := AccountRangeResult{AddressMap: make(map[common.Hash]common.Address)}
|
||||
for i := 0; /*i < int(maxResults) && */ it.Next(); i++ {
|
||||
for i := 0; i < int(maxResults) && it.Next(); i++ {
|
||||
if preimage := accountTrie.GetKey(it.Key); preimage != nil {
|
||||
result.AddressMap[common.BytesToHash(it.Key)] = common.BytesToAddress(preimage)
|
||||
//fmt.Printf("%x: %x\n", it.Key, preimage)
|
||||
@@ -765,10 +775,10 @@ func (api *RetestethAPI) StorageRangeAt(ctx context.Context,
|
||||
}
|
||||
// Ensure any modifications are committed to the state
|
||||
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
|
||||
root = statedb.IntermediateRoot(vmenv.ChainConfig().IsEIP158(block.Number()))
|
||||
_ = statedb.IntermediateRoot(vmenv.ChainConfig().IsEIP158(block.Number()))
|
||||
if idx == int(txIndex) {
|
||||
// This is to make sure root can be opened by OpenTrie
|
||||
root, err = statedb.Commit(vmenv.ChainConfig().IsEIP158(block.Number()))
|
||||
_, err = statedb.Commit(vmenv.ChainConfig().IsEIP158(block.Number()))
|
||||
if err != nil {
|
||||
return StorageRangeResult{}, err
|
||||
}
|
||||
@@ -829,7 +839,7 @@ func retesteth(ctx *cli.Context) error {
|
||||
log.Info("Welcome to retesteth!")
|
||||
// register signer API with server
|
||||
var (
|
||||
extapiURL = "n/a"
|
||||
extapiURL string
|
||||
)
|
||||
apiImpl := &RetestethAPI{}
|
||||
var testApi RetestethTestAPI = apiImpl
|
||||
|
@@ -17,13 +17,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/ethereum/go-ethereum/internal/cmdtest"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
func tmpdir(t *testing.T) string {
|
||||
@@ -96,3 +99,28 @@ func runGeth(t *testing.T, args ...string) *testgeth {
|
||||
|
||||
return tt
|
||||
}
|
||||
|
||||
// waitForEndpoint attempts to connect to an RPC endpoint until it succeeds.
|
||||
func waitForEndpoint(t *testing.T, endpoint string, timeout time.Duration) {
|
||||
probe := func() bool {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
c, err := rpc.DialContext(ctx, endpoint)
|
||||
if c != nil {
|
||||
_, err = c.SupportedModules()
|
||||
c.Close()
|
||||
}
|
||||
return err == nil
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
for {
|
||||
if probe() {
|
||||
return
|
||||
}
|
||||
if time.Since(start) > timeout {
|
||||
t.Fatal("endpoint", endpoint, "did not open within", timeout)
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -61,7 +60,7 @@ func TestAlethSturebyConverter(t *testing.T) {
|
||||
got := strings.Split(c.Sdump(spec), "\n")
|
||||
for i := 0; i < len(exp) && i < len(got); i++ {
|
||||
if exp[i] != got[i] {
|
||||
fmt.Printf("got: %v\nexp: %v\n", exp[i], got[i])
|
||||
t.Logf("got: %v\nexp: %v\n", exp[i], got[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,7 +101,7 @@ func TestParitySturebyConverter(t *testing.T) {
|
||||
got := strings.Split(c.Sdump(spec), "\n")
|
||||
for i := 0; i < len(exp) && i < len(got); i++ {
|
||||
if exp[i] != got[i] {
|
||||
fmt.Printf("got: %v\nexp: %v\n", exp[i], got[i])
|
||||
t.Logf("got: %v\nexp: %v\n", exp[i], got[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -147,7 +147,7 @@ func (w *wizard) deployFaucet() {
|
||||
infos.node.keyPass = w.readPassword()
|
||||
|
||||
if _, err := keystore.DecryptKey([]byte(infos.node.keyJSON), infos.node.keyPass); err != nil {
|
||||
log.Error("Failed to decrypt key with given passphrase")
|
||||
log.Error("Failed to decrypt key with given password")
|
||||
infos.node.keyJSON = ""
|
||||
infos.node.keyPass = ""
|
||||
}
|
||||
|
@@ -142,7 +142,7 @@ func (w *wizard) deployNode(boot bool) {
|
||||
infos.keyPass = w.readPassword()
|
||||
|
||||
if _, err := keystore.DecryptKey([]byte(infos.keyJSON), infos.keyPass); err != nil {
|
||||
log.Error("Failed to decrypt key with given passphrase")
|
||||
log.Error("Failed to decrypt key with given password")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@ import (
|
||||
"encoding"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/user"
|
||||
@@ -34,33 +33,44 @@ import (
|
||||
// Custom type which is registered in the flags library which cli uses for
|
||||
// argument parsing. This allows us to expand Value to an absolute path when
|
||||
// the argument is parsed
|
||||
type DirectoryString struct {
|
||||
Value string
|
||||
type DirectoryString string
|
||||
|
||||
func (s *DirectoryString) String() string {
|
||||
return string(*s)
|
||||
}
|
||||
|
||||
func (self *DirectoryString) String() string {
|
||||
return self.Value
|
||||
}
|
||||
|
||||
func (self *DirectoryString) Set(value string) error {
|
||||
self.Value = expandPath(value)
|
||||
func (s *DirectoryString) Set(value string) error {
|
||||
*s = DirectoryString(expandPath(value))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Custom cli.Flag type which expand the received string to an absolute path.
|
||||
// e.g. ~/.ethereum -> /home/username/.ethereum
|
||||
type DirectoryFlag struct {
|
||||
Name string
|
||||
Value DirectoryString
|
||||
Usage string
|
||||
Name string
|
||||
Value DirectoryString
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (self DirectoryFlag) String() string {
|
||||
fmtString := "%s %v\t%v"
|
||||
if len(self.Value.Value) > 0 {
|
||||
fmtString = "%s \"%v\"\t%v"
|
||||
}
|
||||
return fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage)
|
||||
func (f DirectoryFlag) String() string {
|
||||
return cli.FlagStringer(f)
|
||||
}
|
||||
|
||||
// called by cli library, grabs variable from environment (if in env)
|
||||
// and adds variable to flag set for parsing.
|
||||
func (f DirectoryFlag) Apply(set *flag.FlagSet) {
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Var(&f.Value, f.Name, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f DirectoryFlag) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
func (f *DirectoryFlag) Set(value string) {
|
||||
f.Value.Set(value)
|
||||
}
|
||||
|
||||
func eachName(longName string, fn func(string)) {
|
||||
@@ -71,14 +81,6 @@ func eachName(longName string, fn func(string)) {
|
||||
}
|
||||
}
|
||||
|
||||
// called by cli library, grabs variable from environment (if in env)
|
||||
// and adds variable to flag set for parsing.
|
||||
func (self DirectoryFlag) Apply(set *flag.FlagSet) {
|
||||
eachName(self.Name, func(name string) {
|
||||
set.Var(&self.Value, self.Name, self.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
type TextMarshaler interface {
|
||||
encoding.TextMarshaler
|
||||
encoding.TextUnmarshaler
|
||||
@@ -103,9 +105,10 @@ func (v textMarshalerVal) Set(s string) error {
|
||||
|
||||
// TextMarshalerFlag wraps a TextMarshaler value.
|
||||
type TextMarshalerFlag struct {
|
||||
Name string
|
||||
Value TextMarshaler
|
||||
Usage string
|
||||
Name string
|
||||
Value TextMarshaler
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (f TextMarshalerFlag) GetName() string {
|
||||
@@ -113,7 +116,7 @@ func (f TextMarshalerFlag) GetName() string {
|
||||
}
|
||||
|
||||
func (f TextMarshalerFlag) String() string {
|
||||
return fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)
|
||||
return cli.FlagStringer(f)
|
||||
}
|
||||
|
||||
func (f TextMarshalerFlag) Apply(set *flag.FlagSet) {
|
||||
@@ -134,9 +137,10 @@ func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler {
|
||||
// BigFlag is a command line flag that accepts 256 bit big integers in decimal or
|
||||
// hexadecimal syntax.
|
||||
type BigFlag struct {
|
||||
Name string
|
||||
Value *big.Int
|
||||
Usage string
|
||||
Name string
|
||||
Value *big.Int
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
// bigValue turns *big.Int into a flag.Value
|
||||
@@ -163,11 +167,7 @@ func (f BigFlag) GetName() string {
|
||||
}
|
||||
|
||||
func (f BigFlag) String() string {
|
||||
fmtString := "%s %v\t%v"
|
||||
if f.Value != nil {
|
||||
fmtString = "%s \"%v\"\t%v"
|
||||
}
|
||||
return fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage)
|
||||
return cli.FlagStringer(f)
|
||||
}
|
||||
|
||||
func (f BigFlag) Apply(set *flag.FlagSet) {
|
||||
@@ -207,14 +207,6 @@ func prefixedNames(fullName string) (prefixed string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (self DirectoryFlag) GetName() string {
|
||||
return self.Name
|
||||
}
|
||||
|
||||
func (self *DirectoryFlag) Set(value string) {
|
||||
self.Value.Value = value
|
||||
}
|
||||
|
||||
// Expands a file path
|
||||
// 1. replace tilde with users home dir
|
||||
// 2. expands embedded environment variables
|
||||
|
@@ -21,12 +21,15 @@ import (
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
@@ -90,8 +93,8 @@ GLOBAL OPTIONS:
|
||||
{{range .Flags}}{{.}}
|
||||
{{end}}{{end}}
|
||||
`
|
||||
|
||||
cli.CommandHelpTemplate = CommandHelpTemplate
|
||||
cli.HelpPrinter = printHelp
|
||||
}
|
||||
|
||||
// NewApp creates an app with sane defaults.
|
||||
@@ -105,6 +108,17 @@ func NewApp(gitCommit, gitDate, usage string) *cli.App {
|
||||
return app
|
||||
}
|
||||
|
||||
func printHelp(out io.Writer, templ string, data interface{}) {
|
||||
funcMap := template.FuncMap{"join": strings.Join}
|
||||
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
||||
w := tabwriter.NewWriter(out, 38, 8, 2, ' ', 0)
|
||||
err := t.Execute(w, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
// These are all the command line flags we support.
|
||||
// If you add to this list, please remember to include the
|
||||
// flag in the appropriate command definition.
|
||||
@@ -117,7 +131,7 @@ var (
|
||||
DataDirFlag = DirectoryFlag{
|
||||
Name: "datadir",
|
||||
Usage: "Data directory for the databases and keystore",
|
||||
Value: DirectoryString{node.DefaultDataDir()},
|
||||
Value: DirectoryString(node.DefaultDataDir()),
|
||||
}
|
||||
AncientFlag = DirectoryFlag{
|
||||
Name: "datadir.ancient",
|
||||
@@ -168,7 +182,7 @@ var (
|
||||
DocRootFlag = DirectoryFlag{
|
||||
Name: "docroot",
|
||||
Usage: "Document Root for HTTPClient file scheme",
|
||||
Value: DirectoryString{homeDir()},
|
||||
Value: DirectoryString(homeDir()),
|
||||
}
|
||||
ExitWhenSyncedFlag = cli.BoolFlag{
|
||||
Name: "exitwhensynced",
|
||||
@@ -209,6 +223,10 @@ var (
|
||||
Name: "whitelist",
|
||||
Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)",
|
||||
}
|
||||
OverrideIstanbulFlag = cli.Uint64Flag{
|
||||
Name: "override.istanbul",
|
||||
Usage: "Manually specify Istanbul fork-block, overriding the bundled setting",
|
||||
}
|
||||
// Light server and client settings
|
||||
LightLegacyServFlag = cli.IntFlag{ // Deprecated in favor of light.serve, remove in 2021
|
||||
Name: "lightserv",
|
||||
@@ -291,8 +309,8 @@ var (
|
||||
}
|
||||
EthashDatasetDirFlag = DirectoryFlag{
|
||||
Name: "ethash.dagdir",
|
||||
Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
|
||||
Value: DirectoryString{eth.DefaultConfig.Ethash.DatasetDir},
|
||||
Usage: "Directory to store the ethash mining DAGs",
|
||||
Value: DirectoryString(eth.DefaultConfig.Ethash.DatasetDir),
|
||||
}
|
||||
EthashDatasetsInMemoryFlag = cli.IntFlag{
|
||||
Name: "ethash.dagsinmem",
|
||||
@@ -1091,6 +1109,11 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
||||
if ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
|
||||
lightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name)
|
||||
}
|
||||
if lightClient && !ctx.GlobalIsSet(LightLegacyPeersFlag.Name) && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
|
||||
// dynamic default - for clients we use 1/10th of the default for servers
|
||||
lightPeers /= 10
|
||||
}
|
||||
|
||||
if ctx.GlobalIsSet(MaxPeersFlag.Name) {
|
||||
cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
|
||||
if lightServer && !ctx.GlobalIsSet(LightLegacyPeersFlag.Name) && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
|
||||
@@ -1202,11 +1225,11 @@ func setDataDir(ctx *cli.Context, cfg *node.Config) {
|
||||
cfg.DataDir = ctx.GlobalString(DataDirFlag.Name)
|
||||
case ctx.GlobalBool(DeveloperFlag.Name):
|
||||
cfg.DataDir = "" // unless explicitly requested, use memory databases
|
||||
case ctx.GlobalBool(TestnetFlag.Name):
|
||||
case ctx.GlobalBool(TestnetFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet")
|
||||
case ctx.GlobalBool(RinkebyFlag.Name):
|
||||
case ctx.GlobalBool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
|
||||
case ctx.GlobalBool(GoerliFlag.Name):
|
||||
case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
|
||||
}
|
||||
}
|
||||
|
@@ -356,7 +356,7 @@ func configureNode() {
|
||||
if len(symPass) == 0 {
|
||||
symPass, err = console.Stdin.PromptPassword("Please enter the password for symmetric encryption: ")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read passphrase: %v", err)
|
||||
utils.Fatalf("Failed to read password: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -190,6 +190,8 @@ func benchmarkBaseOR(b *testing.B, size int) {
|
||||
}
|
||||
}
|
||||
|
||||
var GloBool bool // Exported global will not be dead-code eliminated, at least not yet.
|
||||
|
||||
// Benchmarks the potentially optimized bit testing performance.
|
||||
func BenchmarkFastTest1KB(b *testing.B) { benchmarkFastTest(b, 1024) }
|
||||
func BenchmarkFastTest2KB(b *testing.B) { benchmarkFastTest(b, 2048) }
|
||||
@@ -197,9 +199,11 @@ func BenchmarkFastTest4KB(b *testing.B) { benchmarkFastTest(b, 4096) }
|
||||
|
||||
func benchmarkFastTest(b *testing.B, size int) {
|
||||
p := make([]byte, size)
|
||||
a := false
|
||||
for i := 0; i < b.N; i++ {
|
||||
TestBytes(p)
|
||||
a = a != TestBytes(p)
|
||||
}
|
||||
GloBool = a // Use of benchmark "result" to prevent total dead code elimination.
|
||||
}
|
||||
|
||||
// Benchmarks the baseline bit testing performance.
|
||||
@@ -209,7 +213,9 @@ func BenchmarkBaseTest4KB(b *testing.B) { benchmarkBaseTest(b, 4096) }
|
||||
|
||||
func benchmarkBaseTest(b *testing.B, size int) {
|
||||
p := make([]byte, size)
|
||||
a := false
|
||||
for i := 0; i < b.N; i++ {
|
||||
safeTestBytes(p)
|
||||
a = a != safeTestBytes(p)
|
||||
}
|
||||
GloBool = a // Use of benchmark "result" to prevent total dead code elimination.
|
||||
}
|
||||
|
@@ -43,10 +43,8 @@ func ToHexArray(b [][]byte) []string {
|
||||
// FromHex returns the bytes represented by the hexadecimal string s.
|
||||
// s may be prefixed with "0x".
|
||||
func FromHex(s string) []byte {
|
||||
if len(s) > 1 {
|
||||
if s[0:2] == "0x" || s[0:2] == "0X" {
|
||||
s = s[2:]
|
||||
}
|
||||
if has0xPrefix(s) {
|
||||
s = s[2:]
|
||||
}
|
||||
if len(s)%2 == 1 {
|
||||
s = "0" + s
|
||||
@@ -65,8 +63,8 @@ func CopyBytes(b []byte) (copiedBytes []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
// hasHexPrefix validates str begins with '0x' or '0X'.
|
||||
func hasHexPrefix(str string) bool {
|
||||
// has0xPrefix validates str begins with '0x' or '0X'.
|
||||
func has0xPrefix(str string) bool {
|
||||
return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
|
||||
}
|
||||
|
||||
@@ -136,3 +134,14 @@ func LeftPadBytes(slice []byte, l int) []byte {
|
||||
|
||||
return padded
|
||||
}
|
||||
|
||||
// TrimLeftZeroes returns a subslice of s without leading zeroes
|
||||
func TrimLeftZeroes(s []byte) []byte {
|
||||
idx := 0
|
||||
for ; idx < len(s); idx++ {
|
||||
if s[idx] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return s[idx:]
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// Copyright 2015 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
|
||||
@@ -47,7 +47,8 @@ type solcOutput struct {
|
||||
func (s *Solidity) makeArgs() []string {
|
||||
p := []string{
|
||||
"--combined-json", "bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc",
|
||||
"--optimize", // code optimizer switched on
|
||||
"--optimize", // code optimizer switched on
|
||||
"--allow-paths", "., ./, ../", // default to support relative paths
|
||||
}
|
||||
if s.Major > 0 || s.Minor > 4 || s.Patch > 6 {
|
||||
p[1] += ",metadata,hashes"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// Copyright 2015 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
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// Copyright 2016 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
|
||||
|
@@ -36,28 +36,39 @@ func (t AbsTime) Add(d time.Duration) AbsTime {
|
||||
return t + AbsTime(d)
|
||||
}
|
||||
|
||||
// Clock interface makes it possible to replace the monotonic system clock with
|
||||
// The Clock interface makes it possible to replace the monotonic system clock with
|
||||
// a simulated clock.
|
||||
type Clock interface {
|
||||
Now() AbsTime
|
||||
Sleep(time.Duration)
|
||||
After(time.Duration) <-chan time.Time
|
||||
AfterFunc(d time.Duration, f func()) Timer
|
||||
}
|
||||
|
||||
// Timer represents a cancellable event returned by AfterFunc
|
||||
type Timer interface {
|
||||
Stop() bool
|
||||
}
|
||||
|
||||
// System implements Clock using the system clock.
|
||||
type System struct{}
|
||||
|
||||
// Now implements Clock.
|
||||
// Now returns the current monotonic time.
|
||||
func (System) Now() AbsTime {
|
||||
return AbsTime(monotime.Now())
|
||||
}
|
||||
|
||||
// Sleep implements Clock.
|
||||
// Sleep blocks for the given duration.
|
||||
func (System) Sleep(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
||||
|
||||
// After implements Clock.
|
||||
// After returns a channel which receives the current time after d has elapsed.
|
||||
func (System) After(d time.Duration) <-chan time.Time {
|
||||
return time.After(d)
|
||||
}
|
||||
|
||||
// AfterFunc runs f on a new goroutine after the duration has elapsed.
|
||||
func (System) AfterFunc(d time.Duration, f func()) Timer {
|
||||
return time.AfterFunc(d, f)
|
||||
}
|
||||
|
@@ -32,35 +32,45 @@ import (
|
||||
// the timeout using a channel or semaphore.
|
||||
type Simulated struct {
|
||||
now AbsTime
|
||||
scheduled []event
|
||||
scheduled []*simTimer
|
||||
mu sync.RWMutex
|
||||
cond *sync.Cond
|
||||
lastId uint64
|
||||
}
|
||||
|
||||
type event struct {
|
||||
// simTimer implements Timer on the virtual clock.
|
||||
type simTimer struct {
|
||||
do func()
|
||||
at AbsTime
|
||||
id uint64
|
||||
s *Simulated
|
||||
}
|
||||
|
||||
// Run moves the clock by the given duration, executing all timers before that duration.
|
||||
func (s *Simulated) Run(d time.Duration) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.init()
|
||||
|
||||
end := s.now + AbsTime(d)
|
||||
var do []func()
|
||||
for len(s.scheduled) > 0 {
|
||||
ev := s.scheduled[0]
|
||||
if ev.at > end {
|
||||
break
|
||||
}
|
||||
s.now = ev.at
|
||||
ev.do()
|
||||
do = append(do, ev.do)
|
||||
s.scheduled = s.scheduled[1:]
|
||||
}
|
||||
s.now = end
|
||||
s.mu.Unlock()
|
||||
|
||||
for _, fn := range do {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
|
||||
// ActiveTimers returns the number of timers that haven't fired.
|
||||
func (s *Simulated) ActiveTimers() int {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
@@ -68,6 +78,7 @@ func (s *Simulated) ActiveTimers() int {
|
||||
return len(s.scheduled)
|
||||
}
|
||||
|
||||
// WaitForTimers waits until the clock has at least n scheduled timers.
|
||||
func (s *Simulated) WaitForTimers(n int) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
@@ -78,7 +89,7 @@ func (s *Simulated) WaitForTimers(n int) {
|
||||
}
|
||||
}
|
||||
|
||||
// Now implements Clock.
|
||||
// Now returns the current virtual time.
|
||||
func (s *Simulated) Now() AbsTime {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
@@ -86,40 +97,62 @@ func (s *Simulated) Now() AbsTime {
|
||||
return s.now
|
||||
}
|
||||
|
||||
// Sleep implements Clock.
|
||||
// Sleep blocks until the clock has advanced by d.
|
||||
func (s *Simulated) Sleep(d time.Duration) {
|
||||
<-s.After(d)
|
||||
}
|
||||
|
||||
// After implements Clock.
|
||||
// After returns a channel which receives the current time after the clock
|
||||
// has advanced by d.
|
||||
func (s *Simulated) After(d time.Duration) <-chan time.Time {
|
||||
after := make(chan time.Time, 1)
|
||||
s.insert(d, func() {
|
||||
s.AfterFunc(d, func() {
|
||||
after <- (time.Time{}).Add(time.Duration(s.now))
|
||||
})
|
||||
return after
|
||||
}
|
||||
|
||||
func (s *Simulated) insert(d time.Duration, do func()) {
|
||||
// AfterFunc runs fn after the clock has advanced by d. Unlike with the system
|
||||
// clock, fn runs on the goroutine that calls Run.
|
||||
func (s *Simulated) AfterFunc(d time.Duration, fn func()) Timer {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.init()
|
||||
|
||||
at := s.now + AbsTime(d)
|
||||
s.lastId++
|
||||
id := s.lastId
|
||||
l, h := 0, len(s.scheduled)
|
||||
ll := h
|
||||
for l != h {
|
||||
m := (l + h) / 2
|
||||
if at < s.scheduled[m].at {
|
||||
if (at < s.scheduled[m].at) || ((at == s.scheduled[m].at) && (id < s.scheduled[m].id)) {
|
||||
h = m
|
||||
} else {
|
||||
l = m + 1
|
||||
}
|
||||
}
|
||||
s.scheduled = append(s.scheduled, event{})
|
||||
ev := &simTimer{do: fn, at: at, s: s}
|
||||
s.scheduled = append(s.scheduled, nil)
|
||||
copy(s.scheduled[l+1:], s.scheduled[l:ll])
|
||||
s.scheduled[l] = event{do: do, at: at}
|
||||
s.scheduled[l] = ev
|
||||
s.cond.Broadcast()
|
||||
return ev
|
||||
}
|
||||
|
||||
func (ev *simTimer) Stop() bool {
|
||||
s := ev.s
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
for i := 0; i < len(s.scheduled); i++ {
|
||||
if s.scheduled[i] == ev {
|
||||
s.scheduled = append(s.scheduled[:i], s.scheduled[i+1:]...)
|
||||
s.cond.Broadcast()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Simulated) init() {
|
||||
|
115
common/mclock/simclock_test.go
Normal file
115
common/mclock/simclock_test.go
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2018 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 mclock
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ Clock = System{}
|
||||
var _ Clock = new(Simulated)
|
||||
|
||||
func TestSimulatedAfter(t *testing.T) {
|
||||
const timeout = 30 * time.Minute
|
||||
const adv = time.Minute
|
||||
|
||||
var (
|
||||
c Simulated
|
||||
end = c.Now().Add(timeout)
|
||||
ch = c.After(timeout)
|
||||
)
|
||||
for c.Now() < end.Add(-adv) {
|
||||
c.Run(adv)
|
||||
select {
|
||||
case <-ch:
|
||||
t.Fatal("Timer fired early")
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
c.Run(adv)
|
||||
select {
|
||||
case stamp := <-ch:
|
||||
want := time.Time{}.Add(timeout)
|
||||
if !stamp.Equal(want) {
|
||||
t.Errorf("Wrong time sent on timer channel: got %v, want %v", stamp, want)
|
||||
}
|
||||
default:
|
||||
t.Fatal("Timer didn't fire")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimulatedAfterFunc(t *testing.T) {
|
||||
var c Simulated
|
||||
|
||||
called1 := false
|
||||
timer1 := c.AfterFunc(100*time.Millisecond, func() { called1 = true })
|
||||
if c.ActiveTimers() != 1 {
|
||||
t.Fatalf("%d active timers, want one", c.ActiveTimers())
|
||||
}
|
||||
if fired := timer1.Stop(); !fired {
|
||||
t.Fatal("Stop returned false even though timer didn't fire")
|
||||
}
|
||||
if c.ActiveTimers() != 0 {
|
||||
t.Fatalf("%d active timers, want zero", c.ActiveTimers())
|
||||
}
|
||||
if called1 {
|
||||
t.Fatal("timer 1 called")
|
||||
}
|
||||
if fired := timer1.Stop(); fired {
|
||||
t.Fatal("Stop returned true after timer was already stopped")
|
||||
}
|
||||
|
||||
called2 := false
|
||||
timer2 := c.AfterFunc(100*time.Millisecond, func() { called2 = true })
|
||||
c.Run(50 * time.Millisecond)
|
||||
if called2 {
|
||||
t.Fatal("timer 2 called")
|
||||
}
|
||||
c.Run(51 * time.Millisecond)
|
||||
if !called2 {
|
||||
t.Fatal("timer 2 not called")
|
||||
}
|
||||
if fired := timer2.Stop(); fired {
|
||||
t.Fatal("Stop returned true after timer has fired")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimulatedSleep(t *testing.T) {
|
||||
var (
|
||||
c Simulated
|
||||
timeout = 1 * time.Hour
|
||||
done = make(chan AbsTime)
|
||||
)
|
||||
go func() {
|
||||
c.Sleep(timeout)
|
||||
done <- c.Now()
|
||||
}()
|
||||
|
||||
c.WaitForTimers(1)
|
||||
c.Run(2 * timeout)
|
||||
select {
|
||||
case stamp := <-done:
|
||||
want := AbsTime(2 * timeout)
|
||||
if stamp != want {
|
||||
t.Errorf("Wrong time after sleep: got %v, want %v", stamp, want)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("Sleep didn't return in time")
|
||||
}
|
||||
}
|
182
common/prque/lazyqueue.go
Normal file
182
common/prque/lazyqueue.go
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright 2019 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 prque
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
)
|
||||
|
||||
// LazyQueue is a priority queue data structure where priorities can change over
|
||||
// time and are only evaluated on demand.
|
||||
// Two callbacks are required:
|
||||
// - priority evaluates the actual priority of an item
|
||||
// - maxPriority gives an upper estimate for the priority in any moment between
|
||||
// now and the given absolute time
|
||||
// If the upper estimate is exceeded then Update should be called for that item.
|
||||
// A global Refresh function should also be called periodically.
|
||||
type LazyQueue struct {
|
||||
clock mclock.Clock
|
||||
// Items are stored in one of two internal queues ordered by estimated max
|
||||
// priority until the next and the next-after-next refresh. Update and Refresh
|
||||
// always places items in queue[1].
|
||||
queue [2]*sstack
|
||||
popQueue *sstack
|
||||
period time.Duration
|
||||
maxUntil mclock.AbsTime
|
||||
indexOffset int
|
||||
setIndex SetIndexCallback
|
||||
priority PriorityCallback
|
||||
maxPriority MaxPriorityCallback
|
||||
}
|
||||
|
||||
type (
|
||||
PriorityCallback func(data interface{}, now mclock.AbsTime) int64 // actual priority callback
|
||||
MaxPriorityCallback func(data interface{}, until mclock.AbsTime) int64 // estimated maximum priority callback
|
||||
)
|
||||
|
||||
// NewLazyQueue creates a new lazy queue
|
||||
func NewLazyQueue(setIndex SetIndexCallback, priority PriorityCallback, maxPriority MaxPriorityCallback, clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue {
|
||||
q := &LazyQueue{
|
||||
popQueue: newSstack(nil),
|
||||
setIndex: setIndex,
|
||||
priority: priority,
|
||||
maxPriority: maxPriority,
|
||||
clock: clock,
|
||||
period: refreshPeriod}
|
||||
q.Reset()
|
||||
q.Refresh()
|
||||
return q
|
||||
}
|
||||
|
||||
// Reset clears the contents of the queue
|
||||
func (q *LazyQueue) Reset() {
|
||||
q.queue[0] = newSstack(q.setIndex0)
|
||||
q.queue[1] = newSstack(q.setIndex1)
|
||||
}
|
||||
|
||||
// Refresh should be called at least with the frequency specified by the refreshPeriod parameter
|
||||
func (q *LazyQueue) Refresh() {
|
||||
q.maxUntil = q.clock.Now() + mclock.AbsTime(q.period)
|
||||
for q.queue[0].Len() != 0 {
|
||||
q.Push(heap.Pop(q.queue[0]).(*item).value)
|
||||
}
|
||||
q.queue[0], q.queue[1] = q.queue[1], q.queue[0]
|
||||
q.indexOffset = 1 - q.indexOffset
|
||||
q.maxUntil += mclock.AbsTime(q.period)
|
||||
}
|
||||
|
||||
// Push adds an item to the queue
|
||||
func (q *LazyQueue) Push(data interface{}) {
|
||||
heap.Push(q.queue[1], &item{data, q.maxPriority(data, q.maxUntil)})
|
||||
}
|
||||
|
||||
// Update updates the upper priority estimate for the item with the given queue index
|
||||
func (q *LazyQueue) Update(index int) {
|
||||
q.Push(q.Remove(index))
|
||||
}
|
||||
|
||||
// Pop removes and returns the item with the greatest actual priority
|
||||
func (q *LazyQueue) Pop() (interface{}, int64) {
|
||||
var (
|
||||
resData interface{}
|
||||
resPri int64
|
||||
)
|
||||
q.MultiPop(func(data interface{}, priority int64) bool {
|
||||
resData = data
|
||||
resPri = priority
|
||||
return false
|
||||
})
|
||||
return resData, resPri
|
||||
}
|
||||
|
||||
// peekIndex returns the index of the internal queue where the item with the
|
||||
// highest estimated priority is or -1 if both are empty
|
||||
func (q *LazyQueue) peekIndex() int {
|
||||
if q.queue[0].Len() != 0 {
|
||||
if q.queue[1].Len() != 0 && q.queue[1].blocks[0][0].priority > q.queue[0].blocks[0][0].priority {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
if q.queue[1].Len() != 0 {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// MultiPop pops multiple items from the queue and is more efficient than calling
|
||||
// Pop multiple times. Popped items are passed to the callback. MultiPop returns
|
||||
// when the callback returns false or there are no more items to pop.
|
||||
func (q *LazyQueue) MultiPop(callback func(data interface{}, priority int64) bool) {
|
||||
now := q.clock.Now()
|
||||
nextIndex := q.peekIndex()
|
||||
for nextIndex != -1 {
|
||||
data := heap.Pop(q.queue[nextIndex]).(*item).value
|
||||
heap.Push(q.popQueue, &item{data, q.priority(data, now)})
|
||||
nextIndex = q.peekIndex()
|
||||
for q.popQueue.Len() != 0 && (nextIndex == -1 || q.queue[nextIndex].blocks[0][0].priority < q.popQueue.blocks[0][0].priority) {
|
||||
i := heap.Pop(q.popQueue).(*item)
|
||||
if !callback(i.value, i.priority) {
|
||||
for q.popQueue.Len() != 0 {
|
||||
q.Push(heap.Pop(q.popQueue).(*item).value)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PopItem pops the item from the queue only, dropping the associated priority value.
|
||||
func (q *LazyQueue) PopItem() interface{} {
|
||||
i, _ := q.Pop()
|
||||
return i
|
||||
}
|
||||
|
||||
// Remove removes removes the item with the given index.
|
||||
func (q *LazyQueue) Remove(index int) interface{} {
|
||||
if index < 0 {
|
||||
return nil
|
||||
}
|
||||
return heap.Remove(q.queue[index&1^q.indexOffset], index>>1).(*item).value
|
||||
}
|
||||
|
||||
// Empty checks whether the priority queue is empty.
|
||||
func (q *LazyQueue) Empty() bool {
|
||||
return q.queue[0].Len() == 0 && q.queue[1].Len() == 0
|
||||
}
|
||||
|
||||
// Size returns the number of items in the priority queue.
|
||||
func (q *LazyQueue) Size() int {
|
||||
return q.queue[0].Len() + q.queue[1].Len()
|
||||
}
|
||||
|
||||
// setIndex0 translates internal queue item index to the virtual index space of LazyQueue
|
||||
func (q *LazyQueue) setIndex0(data interface{}, index int) {
|
||||
if index == -1 {
|
||||
q.setIndex(data, -1)
|
||||
} else {
|
||||
q.setIndex(data, index+index)
|
||||
}
|
||||
}
|
||||
|
||||
// setIndex1 translates internal queue item index to the virtual index space of LazyQueue
|
||||
func (q *LazyQueue) setIndex1(data interface{}, index int) {
|
||||
q.setIndex(data, index+index+1)
|
||||
}
|
119
common/prque/lazyqueue_test.go
Normal file
119
common/prque/lazyqueue_test.go
Normal file
@@ -0,0 +1,119 @@
|
||||
// Copyright 2019 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 prque
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
)
|
||||
|
||||
const (
|
||||
testItems = 1000
|
||||
testPriorityStep = 100
|
||||
testSteps = 1000000
|
||||
testStepPeriod = time.Millisecond
|
||||
testQueueRefresh = time.Second
|
||||
testAvgRate = float64(testPriorityStep) / float64(testItems) / float64(testStepPeriod)
|
||||
)
|
||||
|
||||
type lazyItem struct {
|
||||
p, maxp int64
|
||||
last mclock.AbsTime
|
||||
index int
|
||||
}
|
||||
|
||||
func testPriority(a interface{}, now mclock.AbsTime) int64 {
|
||||
return a.(*lazyItem).p
|
||||
}
|
||||
|
||||
func testMaxPriority(a interface{}, until mclock.AbsTime) int64 {
|
||||
i := a.(*lazyItem)
|
||||
dt := until - i.last
|
||||
i.maxp = i.p + int64(float64(dt)*testAvgRate)
|
||||
return i.maxp
|
||||
}
|
||||
|
||||
func testSetIndex(a interface{}, i int) {
|
||||
a.(*lazyItem).index = i
|
||||
}
|
||||
|
||||
func TestLazyQueue(t *testing.T) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
clock := &mclock.Simulated{}
|
||||
q := NewLazyQueue(testSetIndex, testPriority, testMaxPriority, clock, testQueueRefresh)
|
||||
|
||||
var (
|
||||
items [testItems]lazyItem
|
||||
maxPri int64
|
||||
)
|
||||
|
||||
for i := range items[:] {
|
||||
items[i].p = rand.Int63n(testPriorityStep * 10)
|
||||
if items[i].p > maxPri {
|
||||
maxPri = items[i].p
|
||||
}
|
||||
items[i].index = -1
|
||||
q.Push(&items[i])
|
||||
}
|
||||
|
||||
var lock sync.Mutex
|
||||
stopCh := make(chan chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-clock.After(testQueueRefresh):
|
||||
lock.Lock()
|
||||
q.Refresh()
|
||||
lock.Unlock()
|
||||
case stop := <-stopCh:
|
||||
close(stop)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for c := 0; c < testSteps; c++ {
|
||||
i := rand.Intn(testItems)
|
||||
lock.Lock()
|
||||
items[i].p += rand.Int63n(testPriorityStep*2-1) + 1
|
||||
if items[i].p > maxPri {
|
||||
maxPri = items[i].p
|
||||
}
|
||||
items[i].last = clock.Now()
|
||||
if items[i].p > items[i].maxp {
|
||||
q.Update(items[i].index)
|
||||
}
|
||||
if rand.Intn(100) == 0 {
|
||||
p := q.PopItem().(*lazyItem)
|
||||
if p.p != maxPri {
|
||||
t.Fatalf("incorrect item (best known priority %d, popped %d)", maxPri, p.p)
|
||||
}
|
||||
q.Push(p)
|
||||
}
|
||||
lock.Unlock()
|
||||
clock.Run(testStepPeriod)
|
||||
clock.WaitForTimers(1)
|
||||
}
|
||||
|
||||
stop := make(chan struct{})
|
||||
stopCh <- stop
|
||||
<-stop
|
||||
}
|
@@ -149,7 +149,7 @@ func (h *Hash) UnmarshalGraphQL(input interface{}) error {
|
||||
var err error
|
||||
switch input := input.(type) {
|
||||
case string:
|
||||
*h = HexToHash(input)
|
||||
err = h.UnmarshalText([]byte(input))
|
||||
default:
|
||||
err = fmt.Errorf("Unexpected type for Bytes32: %v", input)
|
||||
}
|
||||
@@ -193,7 +193,7 @@ func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
|
||||
// IsHexAddress verifies whether a string can represent a valid hex-encoded
|
||||
// Ethereum address or not.
|
||||
func IsHexAddress(s string) bool {
|
||||
if hasHexPrefix(s) {
|
||||
if has0xPrefix(s) {
|
||||
s = s[2:]
|
||||
}
|
||||
return len(s) == 2*AddressLength && isHex(s)
|
||||
@@ -288,7 +288,7 @@ func (a *Address) UnmarshalGraphQL(input interface{}) error {
|
||||
var err error
|
||||
switch input := input.(type) {
|
||||
case string:
|
||||
*a = HexToAddress(input)
|
||||
err = a.UnmarshalText([]byte(input))
|
||||
default:
|
||||
err = fmt.Errorf("Unexpected type for Address: %v", input)
|
||||
}
|
||||
|
@@ -55,8 +55,8 @@ const (
|
||||
var (
|
||||
epochLength = uint64(30000) // Default number of blocks after which to checkpoint and reset the pending votes
|
||||
|
||||
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
|
||||
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
|
||||
extraSeal = crypto.SignatureLength // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
|
||||
nonceAuthVote = hexutil.MustDecode("0xffffffffffffffff") // Magic nonce number to vote on adding a new signer
|
||||
nonceDropVote = hexutil.MustDecode("0x0000000000000000") // Magic nonce number to vote on removing a signer.
|
||||
@@ -728,7 +728,7 @@ func encodeSigHeader(w io.Writer, header *types.Header) {
|
||||
header.GasLimit,
|
||||
header.GasUsed,
|
||||
header.Time,
|
||||
header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
|
||||
header.Extra[:len(header.Extra)-crypto.SignatureLength], // Yes, this will panic if extra is too short
|
||||
header.MixDigest,
|
||||
header.Nonce,
|
||||
})
|
||||
|
@@ -1,3 +1,19 @@
|
||||
// Copyright 2018 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 ethash
|
||||
|
||||
import (
|
||||
|
@@ -59,14 +59,14 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
|
||||
switch {
|
||||
// No password was specified, prompt the user for it
|
||||
case len(call.ArgumentList) == 0:
|
||||
if password, err = b.prompter.PromptPassword("Passphrase: "); err != nil {
|
||||
if password, err = b.prompter.PromptPassword("Password: "); err != nil {
|
||||
throwJSException(err.Error())
|
||||
}
|
||||
if confirm, err = b.prompter.PromptPassword("Repeat passphrase: "); err != nil {
|
||||
if confirm, err = b.prompter.PromptPassword("Repeat password: "); err != nil {
|
||||
throwJSException(err.Error())
|
||||
}
|
||||
if password != confirm {
|
||||
throwJSException("passphrases don't match!")
|
||||
throwJSException("passwords don't match!")
|
||||
}
|
||||
|
||||
// A single string password was specified, use that
|
||||
@@ -180,7 +180,7 @@ func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) {
|
||||
func (b *bridge) readPassphraseAndReopenWallet(call otto.FunctionCall) (otto.Value, error) {
|
||||
var passwd otto.Value
|
||||
wallet := call.Argument(0)
|
||||
if input, err := b.prompter.PromptPassword("Please enter your passphrase: "); err != nil {
|
||||
if input, err := b.prompter.PromptPassword("Please enter your password: "); err != nil {
|
||||
throwJSException(err.Error())
|
||||
} else {
|
||||
passwd, _ = otto.ToValue(input)
|
||||
@@ -223,7 +223,7 @@ func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) {
|
||||
|
||||
if call.Argument(1).IsUndefined() || call.Argument(1).IsNull() {
|
||||
fmt.Fprintf(b.printer, "Unlock account %s\n", account)
|
||||
if input, err := b.prompter.PromptPassword("Passphrase: "); err != nil {
|
||||
if input, err := b.prompter.PromptPassword("Password: "); err != nil {
|
||||
throwJSException(err.Error())
|
||||
} else {
|
||||
passwd, _ = otto.ToValue(input)
|
||||
@@ -270,7 +270,7 @@ func (b *bridge) Sign(call otto.FunctionCall) (response otto.Value) {
|
||||
// if the password is not given or null ask the user and ensure password is a string
|
||||
if passwd.IsUndefined() || passwd.IsNull() {
|
||||
fmt.Fprintf(b.printer, "Give password for account %s\n", account)
|
||||
if input, err := b.prompter.PromptPassword("Passphrase: "); err != nil {
|
||||
if input, err := b.prompter.PromptPassword("Password: "); err != nil {
|
||||
throwJSException(err.Error())
|
||||
} else {
|
||||
passwd, _ = otto.ToValue(input)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// Copyright 2019 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
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// Copyright 2019 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
|
||||
@@ -175,8 +175,11 @@ func TestCheckpointRegister(t *testing.T) {
|
||||
sort.Sort(accounts)
|
||||
|
||||
// Deploy registrar contract
|
||||
transactOpts := bind.NewKeyedTransactor(accounts[0].key)
|
||||
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{accounts[0].addr: {Balance: big.NewInt(1000000000)}, accounts[1].addr: {Balance: big.NewInt(1000000000)}, accounts[2].addr: {Balance: big.NewInt(1000000000)}}, 10000000)
|
||||
defer contractBackend.Close()
|
||||
|
||||
transactOpts := bind.NewKeyedTransactor(accounts[0].key)
|
||||
|
||||
// 3 trusted signers, threshold 2
|
||||
contractAddr, _, c, err := contract.DeployCheckpointOracle(transactOpts, contractBackend, []common.Address{accounts[0].addr, accounts[1].addr, accounts[2].addr}, sectionSize, processConfirms, big.NewInt(2))
|
||||
if err != nil {
|
||||
@@ -241,9 +244,9 @@ func TestCheckpointRegister(t *testing.T) {
|
||||
|
||||
// Test transaction replay protection
|
||||
validateOperation(t, c, contractBackend, func() {
|
||||
number, hash := getRecent()
|
||||
number, _ := getRecent()
|
||||
v, r, s := collectSig(0, checkpoint0.Hash(), 2, nil)
|
||||
hash = common.HexToHash("deadbeef")
|
||||
hash := common.HexToHash("deadbeef")
|
||||
c.SetCheckpoint(transactOpts, number, hash, checkpoint0.Hash(), 0, v, r, s)
|
||||
}, func(events <-chan *contract.CheckpointOracleNewCheckpointVote) error {
|
||||
return assert(0, emptyHash, big.NewInt(0))
|
||||
|
@@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
|
||||
return func(i int, gen *BlockGen) {
|
||||
toaddr := common.Address{}
|
||||
data := make([]byte, nbytes)
|
||||
gas, _ := IntrinsicGas(data, false, false)
|
||||
gas, _ := IntrinsicGas(data, false, false, false)
|
||||
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
|
||||
gen.AddTx(tx)
|
||||
}
|
||||
|
@@ -64,6 +64,8 @@ var (
|
||||
blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil)
|
||||
blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil)
|
||||
blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil)
|
||||
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil)
|
||||
blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
|
||||
|
||||
blockPrefetchExecuteTimer = metrics.NewRegisteredTimer("chain/prefetch/executes", nil)
|
||||
blockPrefetchInterruptMeter = metrics.NewRegisteredMeter("chain/prefetch/interrupts", nil)
|
||||
@@ -75,6 +77,7 @@ const (
|
||||
bodyCacheLimit = 256
|
||||
blockCacheLimit = 256
|
||||
receiptsCacheLimit = 32
|
||||
txLookupCacheLimit = 1024
|
||||
maxFutureBlocks = 256
|
||||
maxTimeFutureBlocks = 30
|
||||
badBlockLimit = 10
|
||||
@@ -155,6 +158,7 @@ type BlockChain struct {
|
||||
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
|
||||
receiptsCache *lru.Cache // Cache for the most recent receipts per block
|
||||
blockCache *lru.Cache // Cache for the most recent entire blocks
|
||||
txLookupCache *lru.Cache // Cache for the most recent transaction lookup data.
|
||||
futureBlocks *lru.Cache // future blocks are blocks added for later processing
|
||||
|
||||
quit chan struct{} // blockchain quit channel
|
||||
@@ -189,6 +193,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
||||
receiptsCache, _ := lru.New(receiptsCacheLimit)
|
||||
blockCache, _ := lru.New(blockCacheLimit)
|
||||
txLookupCache, _ := lru.New(txLookupCacheLimit)
|
||||
futureBlocks, _ := lru.New(maxFutureBlocks)
|
||||
badBlocks, _ := lru.New(badBlockLimit)
|
||||
|
||||
@@ -204,6 +209,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||
bodyRLPCache: bodyRLPCache,
|
||||
receiptsCache: receiptsCache,
|
||||
blockCache: blockCache,
|
||||
txLookupCache: txLookupCache,
|
||||
futureBlocks: futureBlocks,
|
||||
engine: engine,
|
||||
vmConfig: vmConfig,
|
||||
@@ -440,6 +446,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
|
||||
bc.bodyRLPCache.Purge()
|
||||
bc.receiptsCache.Purge()
|
||||
bc.blockCache.Purge()
|
||||
bc.txLookupCache.Purge()
|
||||
bc.futureBlocks.Purge()
|
||||
|
||||
return bc.loadLastState()
|
||||
@@ -921,6 +928,7 @@ func (bc *BlockChain) truncateAncient(head uint64) error {
|
||||
bc.bodyRLPCache.Purge()
|
||||
bc.receiptsCache.Purge()
|
||||
bc.blockCache.Purge()
|
||||
bc.txLookupCache.Purge()
|
||||
bc.futureBlocks.Purge()
|
||||
|
||||
log.Info("Rewind ancient data", "number", head)
|
||||
@@ -1742,6 +1750,11 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
||||
canonical := bc.GetBlockByNumber(number)
|
||||
if canonical != nil && canonical.Hash() == block.Hash() {
|
||||
// Not a sidechain block, this is a re-import of a canon block which has it's state pruned
|
||||
|
||||
// Collect the TD of the block. Since we know it's a canon one,
|
||||
// we can get it directly, and not (like further below) use
|
||||
// the parent and then add the block on top
|
||||
externTd = bc.GetTd(block.Hash(), block.NumberU64())
|
||||
continue
|
||||
}
|
||||
if canonical != nil && canonical.Root() == block.Root() {
|
||||
@@ -1922,12 +1935,16 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||
}
|
||||
// Ensure the user sees large reorgs
|
||||
if len(oldChain) > 0 && len(newChain) > 0 {
|
||||
logFn := log.Debug
|
||||
logFn := log.Info
|
||||
msg := "Chain reorg detected"
|
||||
if len(oldChain) > 63 {
|
||||
msg = "Large chain reorg detected"
|
||||
logFn = log.Warn
|
||||
}
|
||||
logFn("Chain split detected", "number", commonBlock.Number(), "hash", commonBlock.Hash(),
|
||||
logFn(msg, "number", commonBlock.Number(), "hash", commonBlock.Hash(),
|
||||
"drop", len(oldChain), "dropfrom", oldChain[0].Hash(), "add", len(newChain), "addfrom", newChain[0].Hash())
|
||||
blockReorgAddMeter.Mark(int64(len(newChain)))
|
||||
blockReorgDropMeter.Mark(int64(len(oldChain)))
|
||||
} else {
|
||||
log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "newnum", newBlock.Number(), "newhash", newBlock.Hash())
|
||||
}
|
||||
@@ -2134,9 +2151,6 @@ func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []com
|
||||
//
|
||||
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
|
||||
func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) {
|
||||
bc.chainmu.RLock()
|
||||
defer bc.chainmu.RUnlock()
|
||||
|
||||
return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical)
|
||||
}
|
||||
|
||||
@@ -2146,6 +2160,22 @@ func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
|
||||
return bc.hc.GetHeaderByNumber(number)
|
||||
}
|
||||
|
||||
// GetTransactionLookup retrieves the lookup associate with the given transaction
|
||||
// hash from the cache or database.
|
||||
func (bc *BlockChain) GetTransactionLookup(hash common.Hash) *rawdb.LegacyTxLookupEntry {
|
||||
// Short circuit if the txlookup already in the cache, retrieve otherwise
|
||||
if lookup, exist := bc.txLookupCache.Get(hash); exist {
|
||||
return lookup.(*rawdb.LegacyTxLookupEntry)
|
||||
}
|
||||
tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(bc.db, hash)
|
||||
if tx == nil {
|
||||
return nil
|
||||
}
|
||||
lookup := &rawdb.LegacyTxLookupEntry{BlockHash: blockHash, BlockIndex: blockNumber, Index: txIndex}
|
||||
bc.txLookupCache.Add(hash, lookup)
|
||||
return lookup
|
||||
}
|
||||
|
||||
// Config retrieves the chain's fork configuration.
|
||||
func (bc *BlockChain) Config() *params.ChainConfig { return bc.chainConfig }
|
||||
|
||||
|
@@ -2241,3 +2241,124 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
|
||||
}
|
||||
benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn)
|
||||
}
|
||||
|
||||
// Tests that importing a some old blocks, where all blocks are before the
|
||||
// pruning point.
|
||||
// This internally leads to a sidechain import, since the blocks trigger an
|
||||
// ErrPrunedAncestor error.
|
||||
// This may e.g. happen if
|
||||
// 1. Downloader rollbacks a batch of inserted blocks and exits
|
||||
// 2. Downloader starts to sync again
|
||||
// 3. The blocks fetched are all known and canonical blocks
|
||||
func TestSideImportPrunedBlocks(t *testing.T) {
|
||||
// Generate a canonical chain to act as the main dataset
|
||||
engine := ethash.NewFaker()
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
genesis := new(Genesis).MustCommit(db)
|
||||
|
||||
// Generate and import the canonical chain
|
||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil)
|
||||
diskdb := rawdb.NewMemoryDatabase()
|
||||
new(Genesis).MustCommit(diskdb)
|
||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
if n, err := chain.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
|
||||
lastPrunedIndex := len(blocks) - TriesInMemory - 1
|
||||
lastPrunedBlock := blocks[lastPrunedIndex]
|
||||
|
||||
// Verify pruning of lastPrunedBlock
|
||||
if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) {
|
||||
t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64())
|
||||
}
|
||||
firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory]
|
||||
// Verify firstNonPrunedBlock is not pruned
|
||||
if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) {
|
||||
t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64())
|
||||
}
|
||||
// Now re-import some old blocks
|
||||
blockToReimport := blocks[5:8]
|
||||
_, err = chain.InsertChain(blockToReimport)
|
||||
if err != nil {
|
||||
t.Errorf("Got error, %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDeleteCreateRevert tests a weird state transition corner case that we hit
|
||||
// while changing the internals of statedb. The workflow is that a contract is
|
||||
// self destructed, then in a followup transaction (but same block) it's created
|
||||
// again and the transaction reverted.
|
||||
//
|
||||
// The original statedb implementation flushed dirty objects to the tries after
|
||||
// each transaction, so this works ok. The rework accumulated writes in memory
|
||||
// first, but the journal wiped the entire state object on create-revert.
|
||||
func TestDeleteCreateRevert(t *testing.T) {
|
||||
var (
|
||||
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||
bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
|
||||
// Generate a canonical chain to act as the main dataset
|
||||
engine = ethash.NewFaker()
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
|
||||
// A sender who makes transactions, has some funds
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||
funds = big.NewInt(1000000000)
|
||||
gspec = &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: GenesisAlloc{
|
||||
address: {Balance: funds},
|
||||
// The address 0xAAAAA selfdestructs if called
|
||||
aa: {
|
||||
// Code needs to just selfdestruct
|
||||
Code: []byte{byte(vm.PC), 0xFF},
|
||||
Nonce: 1,
|
||||
Balance: big.NewInt(0),
|
||||
},
|
||||
// The address 0xBBBB send 1 wei to 0xAAAA, then reverts
|
||||
bb: {
|
||||
Code: []byte{
|
||||
byte(vm.PC), // [0]
|
||||
byte(vm.DUP1), // [0,0]
|
||||
byte(vm.DUP1), // [0,0,0]
|
||||
byte(vm.DUP1), // [0,0,0,0]
|
||||
byte(vm.PUSH1), 0x01, // [0,0,0,0,1] (value)
|
||||
byte(vm.PUSH2), 0xaa, 0xaa, // [0,0,0,0,1, 0xaaaa]
|
||||
byte(vm.GAS),
|
||||
byte(vm.CALL),
|
||||
byte(vm.REVERT),
|
||||
},
|
||||
Balance: big.NewInt(1),
|
||||
},
|
||||
},
|
||||
}
|
||||
genesis = gspec.MustCommit(db)
|
||||
)
|
||||
|
||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{1})
|
||||
// One transaction to AAAA
|
||||
tx, _ := types.SignTx(types.NewTransaction(0, aa,
|
||||
big.NewInt(0), 50000, big.NewInt(1), nil), types.HomesteadSigner{}, key)
|
||||
b.AddTx(tx)
|
||||
// One transaction to BBBB
|
||||
tx, _ = types.SignTx(types.NewTransaction(1, bb,
|
||||
big.NewInt(0), 100000, big.NewInt(1), nil), types.HomesteadSigner{}, key)
|
||||
b.AddTx(tx)
|
||||
})
|
||||
// Import the canonical chain
|
||||
diskdb := rawdb.NewMemoryDatabase()
|
||||
gspec.MustCommit(diskdb)
|
||||
|
||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
if n, err := chain.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
}
|
||||
|
@@ -103,7 +103,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
|
||||
b.SetCoinbase(common.Address{})
|
||||
}
|
||||
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
|
||||
receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
|
||||
receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@@ -72,8 +72,10 @@ func TestCreation(t *testing.T) {
|
||||
{4229999, ID{Hash: checksumToBytes(0x3ea159c7), Next: 4230000}}, // Last Byzantium block
|
||||
{4230000, ID{Hash: checksumToBytes(0x97b544f3), Next: 4939394}}, // First Constantinople block
|
||||
{4939393, ID{Hash: checksumToBytes(0x97b544f3), Next: 4939394}}, // Last Constantinople block
|
||||
{4939394, ID{Hash: checksumToBytes(0xd6e2149b), Next: 0}}, // First Petersburg block
|
||||
{5822692, ID{Hash: checksumToBytes(0xd6e2149b), Next: 0}}, // Today Petersburg block
|
||||
{4939394, ID{Hash: checksumToBytes(0xd6e2149b), Next: 6485846}}, // First Petersburg block
|
||||
{6485845, ID{Hash: checksumToBytes(0xd6e2149b), Next: 6485846}}, // Last Petersburg block
|
||||
{6485846, ID{Hash: checksumToBytes(0x4bc66396), Next: 0}}, // First Istanbul block
|
||||
{7500000, ID{Hash: checksumToBytes(0x4bc66396), Next: 0}}, // Future Istanbul block
|
||||
},
|
||||
},
|
||||
// Rinkeby test cases
|
||||
@@ -90,8 +92,10 @@ func TestCreation(t *testing.T) {
|
||||
{3660662, ID{Hash: checksumToBytes(0x8d748b57), Next: 3660663}}, // Last Byzantium block
|
||||
{3660663, ID{Hash: checksumToBytes(0xe49cab14), Next: 4321234}}, // First Constantinople block
|
||||
{4321233, ID{Hash: checksumToBytes(0xe49cab14), Next: 4321234}}, // Last Constantinople block
|
||||
{4321234, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}}, // First Petersburg block
|
||||
{4586649, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}}, // Today Petersburg block
|
||||
{4321234, ID{Hash: checksumToBytes(0xafec6b27), Next: 5435345}}, // First Petersburg block
|
||||
{5435344, ID{Hash: checksumToBytes(0xafec6b27), Next: 5435345}}, // Last Petersburg block
|
||||
{5435345, ID{Hash: checksumToBytes(0xcbdb8838), Next: 0}}, // First Istanbul block
|
||||
{6000000, ID{Hash: checksumToBytes(0xcbdb8838), Next: 0}}, // Future Istanbul block
|
||||
},
|
||||
},
|
||||
// Goerli test cases
|
||||
@@ -99,8 +103,10 @@ func TestCreation(t *testing.T) {
|
||||
params.GoerliChainConfig,
|
||||
params.GoerliGenesisHash,
|
||||
[]testcase{
|
||||
{0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 0}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
|
||||
{795329, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 0}}, // Today Petersburg block
|
||||
{0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
|
||||
{1561650, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block
|
||||
{1561651, ID{Hash: checksumToBytes(0xc25efa5c), Next: 0}}, // First Istanbul block
|
||||
{2000000, ID{Hash: checksumToBytes(0xc25efa5c), Next: 0}}, // Future Istanbul block
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
@@ -151,6 +152,10 @@ func (e *GenesisMismatchError) Error() string {
|
||||
//
|
||||
// The returned chain configuration is never nil.
|
||||
func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
|
||||
return SetupGenesisBlockWithOverride(db, genesis, nil)
|
||||
}
|
||||
|
||||
func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrideIstanbul *big.Int) (*params.ChainConfig, common.Hash, error) {
|
||||
if genesis != nil && genesis.Config == nil {
|
||||
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
|
||||
}
|
||||
@@ -164,7 +169,10 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
|
||||
log.Info("Writing custom genesis block")
|
||||
}
|
||||
block, err := genesis.Commit(db)
|
||||
return genesis.Config, block.Hash(), err
|
||||
if err != nil {
|
||||
return genesis.Config, common.Hash{}, err
|
||||
}
|
||||
return genesis.Config, block.Hash(), nil
|
||||
}
|
||||
|
||||
// We have the genesis block in database(perhaps in ancient database)
|
||||
@@ -180,7 +188,10 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
|
||||
return genesis.Config, hash, &GenesisMismatchError{stored, hash}
|
||||
}
|
||||
block, err := genesis.Commit(db)
|
||||
return genesis.Config, block.Hash(), err
|
||||
if err != nil {
|
||||
return genesis.Config, hash, err
|
||||
}
|
||||
return genesis.Config, block.Hash(), nil
|
||||
}
|
||||
|
||||
// Check whether the genesis block is already written.
|
||||
@@ -193,6 +204,9 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
|
||||
|
||||
// Get the existing chain configuration.
|
||||
newcfg := genesis.configOrDefault(stored)
|
||||
if overrideIstanbul != nil {
|
||||
newcfg.IstanbulBlock = overrideIstanbul
|
||||
}
|
||||
storedcfg := rawdb.ReadChainConfig(db, stored)
|
||||
if storedcfg == nil {
|
||||
log.Warn("Found genesis block without chain config")
|
||||
@@ -371,7 +385,7 @@ func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
|
||||
// Assemble and return the genesis with the precompiles and faucet pre-funded
|
||||
return &Genesis{
|
||||
Config: &config,
|
||||
ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, 65)...),
|
||||
ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, crypto.SignatureLength)...),
|
||||
GasLimit: 6283185,
|
||||
Difficulty: big.NewInt(1),
|
||||
Alloc: map[common.Address]GenesisAccount{
|
||||
|
@@ -349,8 +349,11 @@ func (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, ma
|
||||
}
|
||||
for ancestor != 0 {
|
||||
if rawdb.ReadCanonicalHash(hc.chainDb, number) == hash {
|
||||
number -= ancestor
|
||||
return rawdb.ReadCanonicalHash(hc.chainDb, number), number
|
||||
ancestorHash := rawdb.ReadCanonicalHash(hc.chainDb, number-ancestor)
|
||||
if rawdb.ReadCanonicalHash(hc.chainDb, number) == hash {
|
||||
number -= ancestor
|
||||
return ancestorHash, number
|
||||
}
|
||||
}
|
||||
if *maxNonCanonical == 0 {
|
||||
return common.Hash{}, 0
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// Copyright 2019 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
|
||||
@@ -80,9 +80,9 @@ type freezer struct {
|
||||
func newFreezer(datadir string, namespace string) (*freezer, error) {
|
||||
// Create the initial freezer object
|
||||
var (
|
||||
readMeter = metrics.NewRegisteredMeter(namespace+"ancient/read", nil)
|
||||
writeMeter = metrics.NewRegisteredMeter(namespace+"ancient/write", nil)
|
||||
sizeCounter = metrics.NewRegisteredCounter(namespace+"ancient/size", nil)
|
||||
readMeter = metrics.NewRegisteredMeter(namespace+"ancient/read", nil)
|
||||
writeMeter = metrics.NewRegisteredMeter(namespace+"ancient/write", nil)
|
||||
sizeGauge = metrics.NewRegisteredGauge(namespace+"ancient/size", nil)
|
||||
)
|
||||
// Ensure the datadir is not a symbolic link if it exists.
|
||||
if info, err := os.Lstat(datadir); !os.IsNotExist(err) {
|
||||
@@ -103,7 +103,7 @@ func newFreezer(datadir string, namespace string) (*freezer, error) {
|
||||
instanceLock: lock,
|
||||
}
|
||||
for name, disableSnappy := range freezerNoSnappy {
|
||||
table, err := newTable(datadir, name, readMeter, writeMeter, sizeCounter, disableSnappy)
|
||||
table, err := newTable(datadir, name, readMeter, writeMeter, sizeGauge, disableSnappy)
|
||||
if err != nil {
|
||||
for _, table := range freezer.tables {
|
||||
table.Close()
|
||||
|
@@ -94,18 +94,18 @@ type freezerTable struct {
|
||||
// to count how many historic items have gone missing.
|
||||
itemOffset uint32 // Offset (number of discarded items)
|
||||
|
||||
headBytes uint32 // Number of bytes written to the head file
|
||||
readMeter metrics.Meter // Meter for measuring the effective amount of data read
|
||||
writeMeter metrics.Meter // Meter for measuring the effective amount of data written
|
||||
sizeCounter metrics.Counter // Counter for tracking the combined size of all freezer tables
|
||||
headBytes uint32 // Number of bytes written to the head file
|
||||
readMeter metrics.Meter // Meter for measuring the effective amount of data read
|
||||
writeMeter metrics.Meter // Meter for measuring the effective amount of data written
|
||||
sizeGauge metrics.Gauge // Gauge for tracking the combined size of all freezer tables
|
||||
|
||||
logger log.Logger // Logger with database path and table name ambedded
|
||||
lock sync.RWMutex // Mutex protecting the data file descriptors
|
||||
}
|
||||
|
||||
// newTable opens a freezer table with default settings - 2G files
|
||||
func newTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter, sizeCounter metrics.Counter, disableSnappy bool) (*freezerTable, error) {
|
||||
return newCustomTable(path, name, readMeter, writeMeter, sizeCounter, 2*1000*1000*1000, disableSnappy)
|
||||
func newTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter, sizeGauge metrics.Gauge, disableSnappy bool) (*freezerTable, error) {
|
||||
return newCustomTable(path, name, readMeter, writeMeter, sizeGauge, 2*1000*1000*1000, disableSnappy)
|
||||
}
|
||||
|
||||
// openFreezerFileForAppend opens a freezer table file and seeks to the end
|
||||
@@ -149,7 +149,7 @@ func truncateFreezerFile(file *os.File, size int64) error {
|
||||
// newCustomTable opens a freezer table, creating the data and index files if they are
|
||||
// non existent. Both files are truncated to the shortest common length to ensure
|
||||
// they don't go out of sync.
|
||||
func newCustomTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter, sizeCounter metrics.Counter, maxFilesize uint32, noCompression bool) (*freezerTable, error) {
|
||||
func newCustomTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter, sizeGauge metrics.Gauge, maxFilesize uint32, noCompression bool) (*freezerTable, error) {
|
||||
// Ensure the containing directory exists and open the indexEntry file
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return nil, err
|
||||
@@ -172,7 +172,7 @@ func newCustomTable(path string, name string, readMeter metrics.Meter, writeMete
|
||||
files: make(map[uint32]*os.File),
|
||||
readMeter: readMeter,
|
||||
writeMeter: writeMeter,
|
||||
sizeCounter: sizeCounter,
|
||||
sizeGauge: sizeGauge,
|
||||
name: name,
|
||||
path: path,
|
||||
logger: log.New("database", path, "table", name),
|
||||
@@ -189,7 +189,7 @@ func newCustomTable(path string, name string, readMeter metrics.Meter, writeMete
|
||||
tab.Close()
|
||||
return nil, err
|
||||
}
|
||||
tab.sizeCounter.Inc(int64(size))
|
||||
tab.sizeGauge.Inc(int64(size))
|
||||
|
||||
return tab, nil
|
||||
}
|
||||
@@ -272,7 +272,9 @@ func (t *freezerTable) repair() error {
|
||||
if newLastIndex.filenum != lastIndex.filenum {
|
||||
// Release earlier opened file
|
||||
t.releaseFile(lastIndex.filenum)
|
||||
t.head, err = t.openFile(newLastIndex.filenum, openFreezerFileForAppend)
|
||||
if t.head, err = t.openFile(newLastIndex.filenum, openFreezerFileForAppend); err != nil {
|
||||
return err
|
||||
}
|
||||
if stat, err = t.head.Stat(); err != nil {
|
||||
// TODO, anything more we can do here?
|
||||
// A data file has gone missing...
|
||||
@@ -376,7 +378,7 @@ func (t *freezerTable) truncate(items uint64) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.sizeCounter.Dec(int64(oldSize - newSize))
|
||||
t.sizeGauge.Dec(int64(oldSize - newSize))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -508,7 +510,7 @@ func (t *freezerTable) Append(item uint64, blob []byte) error {
|
||||
t.index.Write(idx.marshallBinary())
|
||||
|
||||
t.writeMeter.Mark(int64(bLen + indexEntrySize))
|
||||
t.sizeCounter.Inc(int64(bLen + indexEntrySize))
|
||||
t.sizeGauge.Inc(int64(bLen + indexEntrySize))
|
||||
|
||||
atomic.AddUint64(&t.items, 1)
|
||||
return nil
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// Copyright 2019 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
|
||||
@@ -46,7 +46,7 @@ func print(t *testing.T, f *freezerTable, item uint64) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("db[%d] = %x\n", item, a)
|
||||
t.Logf("db[%d] = %x\n", item, a)
|
||||
}
|
||||
|
||||
// TestFreezerBasics test initializing a freezertable from scratch, writing to the table,
|
||||
@@ -56,7 +56,7 @@ func TestFreezerBasics(t *testing.T) {
|
||||
// set cutoff at 50 bytes
|
||||
f, err := newCustomTable(os.TempDir(),
|
||||
fmt.Sprintf("unittest-%d", rand.Uint64()),
|
||||
metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter(), 50, true)
|
||||
metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -99,11 +99,11 @@ func TestFreezerBasicsClosing(t *testing.T) {
|
||||
// set cutoff at 50 bytes
|
||||
var (
|
||||
fname = fmt.Sprintf("basics-close-%d", rand.Uint64())
|
||||
rm, wm, sc = metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter()
|
||||
rm, wm, sg = metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
|
||||
f *freezerTable
|
||||
err error
|
||||
)
|
||||
f, err = newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err = newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -112,7 +112,10 @@ func TestFreezerBasicsClosing(t *testing.T) {
|
||||
data := getChunk(15, x)
|
||||
f.Append(uint64(x), data)
|
||||
f.Close()
|
||||
f, err = newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err = newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
@@ -126,7 +129,7 @@ func TestFreezerBasicsClosing(t *testing.T) {
|
||||
t.Fatalf("test %d, got \n%x != \n%x", y, got, exp)
|
||||
}
|
||||
f.Close()
|
||||
f, err = newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err = newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -136,11 +139,11 @@ func TestFreezerBasicsClosing(t *testing.T) {
|
||||
// TestFreezerRepairDanglingHead tests that we can recover if index entries are removed
|
||||
func TestFreezerRepairDanglingHead(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm, wm, sc := metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter()
|
||||
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
|
||||
fname := fmt.Sprintf("dangling_headtest-%d", rand.Uint64())
|
||||
|
||||
{ // Fill table
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -169,7 +172,10 @@ func TestFreezerRepairDanglingHead(t *testing.T) {
|
||||
idxFile.Close()
|
||||
// Now open it again
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The last item should be missing
|
||||
if _, err = f.Retrieve(0xff); err == nil {
|
||||
t.Errorf("Expected error for missing index entry")
|
||||
@@ -184,11 +190,11 @@ func TestFreezerRepairDanglingHead(t *testing.T) {
|
||||
// TestFreezerRepairDanglingHeadLarge tests that we can recover if very many index entries are removed
|
||||
func TestFreezerRepairDanglingHeadLarge(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm, wm, sc := metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter()
|
||||
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
|
||||
fname := fmt.Sprintf("dangling_headtest-%d", rand.Uint64())
|
||||
|
||||
{ // Fill a table and close it
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -216,7 +222,10 @@ func TestFreezerRepairDanglingHeadLarge(t *testing.T) {
|
||||
idxFile.Close()
|
||||
// Now open it again
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The first item should be there
|
||||
if _, err = f.Retrieve(0); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -234,7 +243,7 @@ func TestFreezerRepairDanglingHeadLarge(t *testing.T) {
|
||||
}
|
||||
// And if we open it, we should now be able to read all of them (new values)
|
||||
{
|
||||
f, _ := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, _ := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
for y := 1; y < 255; y++ {
|
||||
exp := getChunk(15, ^y)
|
||||
got, err := f.Retrieve(uint64(y))
|
||||
@@ -251,11 +260,11 @@ func TestFreezerRepairDanglingHeadLarge(t *testing.T) {
|
||||
// TestSnappyDetection tests that we fail to open a snappy database and vice versa
|
||||
func TestSnappyDetection(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm, wm, sc := metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter()
|
||||
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
|
||||
fname := fmt.Sprintf("snappytest-%d", rand.Uint64())
|
||||
// Open with snappy
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -268,7 +277,10 @@ func TestSnappyDetection(t *testing.T) {
|
||||
}
|
||||
// Open without snappy
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, false)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = f.Retrieve(0); err == nil {
|
||||
f.Close()
|
||||
t.Fatalf("expected empty table")
|
||||
@@ -277,7 +289,10 @@ func TestSnappyDetection(t *testing.T) {
|
||||
|
||||
// Open with snappy
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// There should be 255 items
|
||||
if _, err = f.Retrieve(0xfe); err != nil {
|
||||
f.Close()
|
||||
@@ -302,11 +317,11 @@ func assertFileSize(f string, size int64) error {
|
||||
// the index is repaired
|
||||
func TestFreezerRepairDanglingIndex(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm, wm, sc := metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter()
|
||||
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
|
||||
fname := fmt.Sprintf("dangling_indextest-%d", rand.Uint64())
|
||||
|
||||
{ // Fill a table and close it
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -342,7 +357,7 @@ func TestFreezerRepairDanglingIndex(t *testing.T) {
|
||||
// 45, 45, 15
|
||||
// with 3+3+1 items
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -359,11 +374,11 @@ func TestFreezerRepairDanglingIndex(t *testing.T) {
|
||||
func TestFreezerTruncate(t *testing.T) {
|
||||
|
||||
t.Parallel()
|
||||
rm, wm, sc := metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter()
|
||||
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
|
||||
fname := fmt.Sprintf("truncation-%d", rand.Uint64())
|
||||
|
||||
{ // Fill table
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -380,7 +395,7 @@ func TestFreezerTruncate(t *testing.T) {
|
||||
}
|
||||
// Reopen, truncate
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -402,10 +417,10 @@ func TestFreezerTruncate(t *testing.T) {
|
||||
// That will rewind the index, and _should_ truncate the head file
|
||||
func TestFreezerRepairFirstFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm, wm, sc := metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter()
|
||||
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
|
||||
fname := fmt.Sprintf("truncationfirst-%d", rand.Uint64())
|
||||
{ // Fill table
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -433,7 +448,7 @@ func TestFreezerRepairFirstFile(t *testing.T) {
|
||||
}
|
||||
// Reopen
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -458,10 +473,10 @@ func TestFreezerRepairFirstFile(t *testing.T) {
|
||||
// - check that we did not keep the rdonly file descriptors
|
||||
func TestFreezerReadAndTruncate(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm, wm, sc := metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter()
|
||||
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
|
||||
fname := fmt.Sprintf("read_truncate-%d", rand.Uint64())
|
||||
{ // Fill table
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -478,7 +493,7 @@ func TestFreezerReadAndTruncate(t *testing.T) {
|
||||
}
|
||||
// Reopen and read all files
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 50, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -504,10 +519,10 @@ func TestFreezerReadAndTruncate(t *testing.T) {
|
||||
|
||||
func TestOffset(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm, wm, sc := metrics.NewMeter(), metrics.NewMeter(), metrics.NewCounter()
|
||||
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
|
||||
fname := fmt.Sprintf("offset-%d", rand.Uint64())
|
||||
{ // Fill table
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 40, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 40, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -563,7 +578,7 @@ func TestOffset(t *testing.T) {
|
||||
}
|
||||
// Now open again
|
||||
{
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sc, 40, true)
|
||||
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 40, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@@ -118,7 +118,12 @@ func (self *StateDB) dump(c collector, excludeCode, excludeStorage, excludeMissi
|
||||
account.Storage = make(map[common.Hash]string)
|
||||
storageIt := trie.NewIterator(obj.getTrie(self.db).NodeIterator(nil))
|
||||
for storageIt.Next() {
|
||||
account.Storage[common.BytesToHash(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
|
||||
_, content, _, err := rlp.Split(storageIt.Value)
|
||||
if err != nil {
|
||||
log.Error("Failed to decode the value returned by iterator", "error", err)
|
||||
continue
|
||||
}
|
||||
account.Storage[common.BytesToHash(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content)
|
||||
}
|
||||
}
|
||||
c.onAccount(addr, account)
|
||||
|
@@ -79,8 +79,10 @@ type stateObject struct {
|
||||
trie Trie // storage trie, which becomes non-nil on first access
|
||||
code Code // contract bytecode, which gets set when code is loaded
|
||||
|
||||
originStorage Storage // Storage cache of original entries to dedup rewrites
|
||||
dirtyStorage Storage // Storage entries that need to be flushed to disk
|
||||
originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction
|
||||
pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block
|
||||
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution
|
||||
fakeStorage Storage // Fake storage which constructed by caller for debugging purpose.
|
||||
|
||||
// Cache flags.
|
||||
// When an object is marked suicided it will be delete from the trie
|
||||
@@ -112,13 +114,17 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject {
|
||||
if data.CodeHash == nil {
|
||||
data.CodeHash = emptyCodeHash
|
||||
}
|
||||
if data.Root == (common.Hash{}) {
|
||||
data.Root = emptyRoot
|
||||
}
|
||||
return &stateObject{
|
||||
db: db,
|
||||
address: address,
|
||||
addrHash: crypto.Keccak256Hash(address[:]),
|
||||
data: data,
|
||||
originStorage: make(Storage),
|
||||
dirtyStorage: make(Storage),
|
||||
db: db,
|
||||
address: address,
|
||||
addrHash: crypto.Keccak256Hash(address[:]),
|
||||
data: data,
|
||||
originStorage: make(Storage),
|
||||
pendingStorage: make(Storage),
|
||||
dirtyStorage: make(Storage),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,6 +169,10 @@ func (s *stateObject) getTrie(db Database) Trie {
|
||||
|
||||
// GetState retrieves a value from the account storage trie.
|
||||
func (s *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
||||
// If the fake storage is set, only lookup the state here(in the debugging mode)
|
||||
if s.fakeStorage != nil {
|
||||
return s.fakeStorage[key]
|
||||
}
|
||||
// If we have a dirty value for this state entry, return it
|
||||
value, dirty := s.dirtyStorage[key]
|
||||
if dirty {
|
||||
@@ -174,12 +184,18 @@ func (s *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
||||
|
||||
// GetCommittedState retrieves a value from the committed account storage trie.
|
||||
func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash {
|
||||
// If we have the original value cached, return that
|
||||
value, cached := s.originStorage[key]
|
||||
if cached {
|
||||
// If the fake storage is set, only lookup the state here(in the debugging mode)
|
||||
if s.fakeStorage != nil {
|
||||
return s.fakeStorage[key]
|
||||
}
|
||||
// If we have a pending write or clean cached, return that
|
||||
if value, pending := s.pendingStorage[key]; pending {
|
||||
return value
|
||||
}
|
||||
// Track the amount of time wasted on reading the storge trie
|
||||
if value, cached := s.originStorage[key]; cached {
|
||||
return value
|
||||
}
|
||||
// Track the amount of time wasted on reading the storage trie
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.db.StorageReads += time.Since(start) }(time.Now())
|
||||
}
|
||||
@@ -189,6 +205,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
|
||||
s.setError(err)
|
||||
return common.Hash{}
|
||||
}
|
||||
var value common.Hash
|
||||
if len(enc) > 0 {
|
||||
_, content, _, err := rlp.Split(enc)
|
||||
if err != nil {
|
||||
@@ -202,6 +219,11 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
|
||||
|
||||
// SetState updates a value in account storage.
|
||||
func (s *stateObject) SetState(db Database, key, value common.Hash) {
|
||||
// If the fake storage is set, put the temporary state update here.
|
||||
if s.fakeStorage != nil {
|
||||
s.fakeStorage[key] = value
|
||||
return
|
||||
}
|
||||
// If the new value is the same as old, don't set
|
||||
prev := s.GetState(db, key)
|
||||
if prev == value {
|
||||
@@ -216,21 +238,51 @@ func (s *stateObject) SetState(db Database, key, value common.Hash) {
|
||||
s.setState(key, value)
|
||||
}
|
||||
|
||||
// SetStorage replaces the entire state storage with the given one.
|
||||
//
|
||||
// After this function is called, all original state will be ignored and state
|
||||
// lookup only happens in the fake state storage.
|
||||
//
|
||||
// Note this function should only be used for debugging purpose.
|
||||
func (s *stateObject) SetStorage(storage map[common.Hash]common.Hash) {
|
||||
// Allocate fake storage if it's nil.
|
||||
if s.fakeStorage == nil {
|
||||
s.fakeStorage = make(Storage)
|
||||
}
|
||||
for key, value := range storage {
|
||||
s.fakeStorage[key] = value
|
||||
}
|
||||
// Don't bother journal since this function should only be used for
|
||||
// debugging and the `fake` storage won't be committed to database.
|
||||
}
|
||||
|
||||
func (s *stateObject) setState(key, value common.Hash) {
|
||||
s.dirtyStorage[key] = value
|
||||
}
|
||||
|
||||
// finalise moves all dirty storage slots into the pending area to be hashed or
|
||||
// committed later. It is invoked at the end of every transaction.
|
||||
func (s *stateObject) finalise() {
|
||||
for key, value := range s.dirtyStorage {
|
||||
s.pendingStorage[key] = value
|
||||
}
|
||||
if len(s.dirtyStorage) > 0 {
|
||||
s.dirtyStorage = make(Storage)
|
||||
}
|
||||
}
|
||||
|
||||
// updateTrie writes cached storage modifications into the object's storage trie.
|
||||
func (s *stateObject) updateTrie(db Database) Trie {
|
||||
// Make sure all dirty slots are finalized into the pending storage area
|
||||
s.finalise()
|
||||
|
||||
// Track the amount of time wasted on updating the storge trie
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now())
|
||||
}
|
||||
// Update all the dirty slots in the trie
|
||||
// Insert all the pending updates into the trie
|
||||
tr := s.getTrie(db)
|
||||
for key, value := range s.dirtyStorage {
|
||||
delete(s.dirtyStorage, key)
|
||||
|
||||
for key, value := range s.pendingStorage {
|
||||
// Skip noop changes, persist actual changes
|
||||
if value == s.originStorage[key] {
|
||||
continue
|
||||
@@ -242,9 +294,12 @@ func (s *stateObject) updateTrie(db Database) Trie {
|
||||
continue
|
||||
}
|
||||
// Encoding []byte cannot fail, ok to ignore the error.
|
||||
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
|
||||
v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
|
||||
s.setError(tr.TryUpdate(key[:], v))
|
||||
}
|
||||
if len(s.pendingStorage) > 0 {
|
||||
s.pendingStorage = make(Storage)
|
||||
}
|
||||
return tr
|
||||
}
|
||||
|
||||
|
70
core/state/state_object_test.go
Normal file
70
core/state/state_object_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2019 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 state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
func BenchmarkCutOriginal(b *testing.B) {
|
||||
value := common.HexToHash("0x01")
|
||||
for i := 0; i < b.N; i++ {
|
||||
bytes.TrimLeft(value[:], "\x00")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCutsetterFn(b *testing.B) {
|
||||
value := common.HexToHash("0x01")
|
||||
cutSetFn := func(r rune) bool {
|
||||
return int32(r) == int32(0)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
bytes.TrimLeftFunc(value[:], cutSetFn)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCutCustomTrim(b *testing.B) {
|
||||
value := common.HexToHash("0x01")
|
||||
for i := 0; i < b.N; i++ {
|
||||
common.TrimLeftZeroes(value[:])
|
||||
}
|
||||
}
|
||||
|
||||
func xTestFuzzCutter(t *testing.T) {
|
||||
rand.Seed(time.Now().Unix())
|
||||
for {
|
||||
v := make([]byte, 20)
|
||||
zeroes := rand.Intn(21)
|
||||
rand.Read(v[zeroes:])
|
||||
exp := bytes.TrimLeft(v[:], "\x00")
|
||||
got := common.TrimLeftZeroes(v)
|
||||
if !bytes.Equal(exp, got) {
|
||||
|
||||
fmt.Printf("Input %x\n", v)
|
||||
fmt.Printf("Exp %x\n", exp)
|
||||
fmt.Printf("Got %x\n", got)
|
||||
t.Fatalf("Error")
|
||||
}
|
||||
//break
|
||||
}
|
||||
}
|
@@ -67,8 +67,9 @@ type StateDB struct {
|
||||
trie Trie
|
||||
|
||||
// This map holds 'live' objects, which will get modified while processing a state transition.
|
||||
stateObjects map[common.Address]*stateObject
|
||||
stateObjectsDirty map[common.Address]struct{}
|
||||
stateObjects map[common.Address]*stateObject
|
||||
stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie
|
||||
stateObjectsDirty map[common.Address]struct{} // State objects modified in the current execution
|
||||
|
||||
// DB error.
|
||||
// State objects are used by the consensus core and VM which are
|
||||
@@ -111,13 +112,14 @@ func New(root common.Hash, db Database) (*StateDB, error) {
|
||||
return nil, err
|
||||
}
|
||||
return &StateDB{
|
||||
db: db,
|
||||
trie: tr,
|
||||
stateObjects: make(map[common.Address]*stateObject),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||
logs: make(map[common.Hash][]*types.Log),
|
||||
preimages: make(map[common.Hash][]byte),
|
||||
journal: newJournal(),
|
||||
db: db,
|
||||
trie: tr,
|
||||
stateObjects: make(map[common.Address]*stateObject),
|
||||
stateObjectsPending: make(map[common.Address]struct{}),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||
logs: make(map[common.Hash][]*types.Log),
|
||||
preimages: make(map[common.Hash][]byte),
|
||||
journal: newJournal(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -141,6 +143,7 @@ func (self *StateDB) Reset(root common.Hash) error {
|
||||
}
|
||||
self.trie = tr
|
||||
self.stateObjects = make(map[common.Address]*stateObject)
|
||||
self.stateObjectsPending = make(map[common.Address]struct{})
|
||||
self.stateObjectsDirty = make(map[common.Address]struct{})
|
||||
self.thash = common.Hash{}
|
||||
self.bhash = common.Hash{}
|
||||
@@ -386,6 +389,15 @@ func (self *StateDB) SetState(addr common.Address, key, value common.Hash) {
|
||||
}
|
||||
}
|
||||
|
||||
// SetStorage replaces the entire storage for the specified account with given
|
||||
// storage. This function should only be used for debugging.
|
||||
func (self *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) {
|
||||
stateObject := self.GetOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.SetStorage(storage)
|
||||
}
|
||||
}
|
||||
|
||||
// Suicide marks the given account as suicided.
|
||||
// This clears the account balance.
|
||||
//
|
||||
@@ -412,15 +424,15 @@ func (self *StateDB) Suicide(addr common.Address) bool {
|
||||
//
|
||||
|
||||
// updateStateObject writes the given object to the trie.
|
||||
func (s *StateDB) updateStateObject(stateObject *stateObject) {
|
||||
func (s *StateDB) updateStateObject(obj *stateObject) {
|
||||
// Track the amount of time wasted on updating the account from the trie
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
|
||||
}
|
||||
// Encode the account and update the account trie
|
||||
addr := stateObject.Address()
|
||||
addr := obj.Address()
|
||||
|
||||
data, err := rlp.EncodeToBytes(stateObject)
|
||||
data, err := rlp.EncodeToBytes(obj)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err))
|
||||
}
|
||||
@@ -428,25 +440,33 @@ func (s *StateDB) updateStateObject(stateObject *stateObject) {
|
||||
}
|
||||
|
||||
// deleteStateObject removes the given object from the state trie.
|
||||
func (s *StateDB) deleteStateObject(stateObject *stateObject) {
|
||||
func (s *StateDB) deleteStateObject(obj *stateObject) {
|
||||
// Track the amount of time wasted on deleting the account from the trie
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
|
||||
}
|
||||
// Delete the account from the trie
|
||||
stateObject.deleted = true
|
||||
|
||||
addr := stateObject.Address()
|
||||
addr := obj.Address()
|
||||
s.setError(s.trie.TryDelete(addr[:]))
|
||||
}
|
||||
|
||||
// Retrieve a state object given by the address. Returns nil if not found.
|
||||
func (s *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) {
|
||||
// Prefer live objects
|
||||
// getStateObject retrieves a state object given by the address, returning nil if
|
||||
// the object is not found or was deleted in this execution context. If you need
|
||||
// to differentiate between non-existent/just-deleted, use getDeletedStateObject.
|
||||
func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
||||
if obj := s.getDeletedStateObject(addr); obj != nil && !obj.deleted {
|
||||
return obj
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getDeletedStateObject is similar to getStateObject, but instead of returning
|
||||
// nil for a deleted state object, it returns the actual object with the deleted
|
||||
// flag set. This is needed by the state journal to revert to the correct self-
|
||||
// destructed object instead of wiping all knowledge about the state object.
|
||||
func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
||||
// Prefer live objects if any is available
|
||||
if obj := s.stateObjects[addr]; obj != nil {
|
||||
if obj.deleted {
|
||||
return nil
|
||||
}
|
||||
return obj
|
||||
}
|
||||
// Track the amount of time wasted on loading the object from the database
|
||||
@@ -477,7 +497,7 @@ func (self *StateDB) setStateObject(object *stateObject) {
|
||||
// Retrieve a state object or create a new state object if nil.
|
||||
func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
|
||||
stateObject := self.getStateObject(addr)
|
||||
if stateObject == nil || stateObject.deleted {
|
||||
if stateObject == nil {
|
||||
stateObject, _ = self.createObject(addr)
|
||||
}
|
||||
return stateObject
|
||||
@@ -486,7 +506,8 @@ func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
|
||||
// createObject creates a new state object. If there is an existing account with
|
||||
// the given address, it is overwritten and returned as the second return value.
|
||||
func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
|
||||
prev = self.getStateObject(addr)
|
||||
prev = self.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
|
||||
|
||||
newobj = newObject(self, addr, Account{})
|
||||
newobj.setNonce(0) // sets the object to dirty
|
||||
if prev == nil {
|
||||
@@ -549,15 +570,16 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common
|
||||
func (self *StateDB) Copy() *StateDB {
|
||||
// Copy all the basic fields, initialize the memory ones
|
||||
state := &StateDB{
|
||||
db: self.db,
|
||||
trie: self.db.CopyTrie(self.trie),
|
||||
stateObjects: make(map[common.Address]*stateObject, len(self.journal.dirties)),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}, len(self.journal.dirties)),
|
||||
refund: self.refund,
|
||||
logs: make(map[common.Hash][]*types.Log, len(self.logs)),
|
||||
logSize: self.logSize,
|
||||
preimages: make(map[common.Hash][]byte, len(self.preimages)),
|
||||
journal: newJournal(),
|
||||
db: self.db,
|
||||
trie: self.db.CopyTrie(self.trie),
|
||||
stateObjects: make(map[common.Address]*stateObject, len(self.journal.dirties)),
|
||||
stateObjectsPending: make(map[common.Address]struct{}, len(self.stateObjectsPending)),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}, len(self.journal.dirties)),
|
||||
refund: self.refund,
|
||||
logs: make(map[common.Hash][]*types.Log, len(self.logs)),
|
||||
logSize: self.logSize,
|
||||
preimages: make(map[common.Hash][]byte, len(self.preimages)),
|
||||
journal: newJournal(),
|
||||
}
|
||||
// Copy the dirty states, logs, and preimages
|
||||
for addr := range self.journal.dirties {
|
||||
@@ -573,11 +595,17 @@ func (self *StateDB) Copy() *StateDB {
|
||||
// Above, we don't copy the actual journal. This means that if the copy is copied, the
|
||||
// loop above will be a no-op, since the copy's journal is empty.
|
||||
// Thus, here we iterate over stateObjects, to enable copies of copies
|
||||
for addr := range self.stateObjectsPending {
|
||||
if _, exist := state.stateObjects[addr]; !exist {
|
||||
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state)
|
||||
}
|
||||
state.stateObjectsPending[addr] = struct{}{}
|
||||
}
|
||||
for addr := range self.stateObjectsDirty {
|
||||
if _, exist := state.stateObjects[addr]; !exist {
|
||||
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state)
|
||||
state.stateObjectsDirty[addr] = struct{}{}
|
||||
}
|
||||
state.stateObjectsDirty[addr] = struct{}{}
|
||||
}
|
||||
for hash, logs := range self.logs {
|
||||
cpy := make([]*types.Log, len(logs))
|
||||
@@ -622,11 +650,12 @@ func (self *StateDB) GetRefund() uint64 {
|
||||
return self.refund
|
||||
}
|
||||
|
||||
// Finalise finalises the state by removing the self destructed objects
|
||||
// and clears the journal as well as the refunds.
|
||||
// Finalise finalises the state by removing the self destructed objects and clears
|
||||
// the journal as well as the refunds. Finalise, however, will not push any updates
|
||||
// into the tries just yet. Only IntermediateRoot or Commit will do that.
|
||||
func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
||||
for addr := range s.journal.dirties {
|
||||
stateObject, exist := s.stateObjects[addr]
|
||||
obj, exist := s.stateObjects[addr]
|
||||
if !exist {
|
||||
// ripeMD is 'touched' at block 1714175, in tx 0x1237f737031e40bcde4a8b7e717b2d15e3ecadfe49bb1bbc71ee9deb09c6fcf2
|
||||
// That tx goes out of gas, and although the notion of 'touched' does not exist there, the
|
||||
@@ -636,13 +665,12 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
||||
// Thus, we can safely ignore it here
|
||||
continue
|
||||
}
|
||||
|
||||
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
|
||||
s.deleteStateObject(stateObject)
|
||||
if obj.suicided || (deleteEmptyObjects && obj.empty()) {
|
||||
obj.deleted = true
|
||||
} else {
|
||||
stateObject.updateRoot(s.db)
|
||||
s.updateStateObject(stateObject)
|
||||
obj.finalise()
|
||||
}
|
||||
s.stateObjectsPending[addr] = struct{}{}
|
||||
s.stateObjectsDirty[addr] = struct{}{}
|
||||
}
|
||||
// Invalidate journal because reverting across transactions is not allowed.
|
||||
@@ -653,8 +681,21 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
||||
// It is called in between transactions to get the root hash that
|
||||
// goes into transaction receipts.
|
||||
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||
// Finalise all the dirty storage states and write them into the tries
|
||||
s.Finalise(deleteEmptyObjects)
|
||||
|
||||
for addr := range s.stateObjectsPending {
|
||||
obj := s.stateObjects[addr]
|
||||
if obj.deleted {
|
||||
s.deleteStateObject(obj)
|
||||
} else {
|
||||
obj.updateRoot(s.db)
|
||||
s.updateStateObject(obj)
|
||||
}
|
||||
}
|
||||
if len(s.stateObjectsPending) > 0 {
|
||||
s.stateObjectsPending = make(map[common.Address]struct{})
|
||||
}
|
||||
// Track the amount of time wasted on hashing the account trie
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now())
|
||||
@@ -671,46 +712,40 @@ func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) {
|
||||
}
|
||||
|
||||
func (s *StateDB) clearJournalAndRefund() {
|
||||
s.journal = newJournal()
|
||||
s.validRevisions = s.validRevisions[:0]
|
||||
s.refund = 0
|
||||
if len(s.journal.entries) > 0 {
|
||||
s.journal = newJournal()
|
||||
s.refund = 0
|
||||
}
|
||||
s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entires
|
||||
}
|
||||
|
||||
// Commit writes the state to the underlying in-memory trie database.
|
||||
func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) {
|
||||
defer s.clearJournalAndRefund()
|
||||
func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
|
||||
// Finalize any pending changes and merge everything into the tries
|
||||
s.IntermediateRoot(deleteEmptyObjects)
|
||||
|
||||
for addr := range s.journal.dirties {
|
||||
s.stateObjectsDirty[addr] = struct{}{}
|
||||
}
|
||||
// Commit objects to the trie, measuring the elapsed time
|
||||
for addr, stateObject := range s.stateObjects {
|
||||
_, isDirty := s.stateObjectsDirty[addr]
|
||||
switch {
|
||||
case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()):
|
||||
// If the object has been removed, don't bother syncing it
|
||||
// and just mark it for deletion in the trie.
|
||||
s.deleteStateObject(stateObject)
|
||||
case isDirty:
|
||||
for addr := range s.stateObjectsDirty {
|
||||
if obj := s.stateObjects[addr]; !obj.deleted {
|
||||
// Write any contract code associated with the state object
|
||||
if stateObject.code != nil && stateObject.dirtyCode {
|
||||
s.db.TrieDB().InsertBlob(common.BytesToHash(stateObject.CodeHash()), stateObject.code)
|
||||
stateObject.dirtyCode = false
|
||||
if obj.code != nil && obj.dirtyCode {
|
||||
s.db.TrieDB().InsertBlob(common.BytesToHash(obj.CodeHash()), obj.code)
|
||||
obj.dirtyCode = false
|
||||
}
|
||||
// Write any storage changes in the state object to its storage trie.
|
||||
if err := stateObject.CommitTrie(s.db); err != nil {
|
||||
// Write any storage changes in the state object to its storage trie
|
||||
if err := obj.CommitTrie(s.db); err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
// Update the object in the main account trie.
|
||||
s.updateStateObject(stateObject)
|
||||
}
|
||||
delete(s.stateObjectsDirty, addr)
|
||||
}
|
||||
if len(s.stateObjectsDirty) > 0 {
|
||||
s.stateObjectsDirty = make(map[common.Address]struct{})
|
||||
}
|
||||
// Write the account trie changes, measuing the amount of wasted time
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.AccountCommits += time.Since(start) }(time.Now())
|
||||
}
|
||||
root, err = s.trie.Commit(func(leaf []byte, parent common.Hash) error {
|
||||
return s.trie.Commit(func(leaf []byte, parent common.Hash) error {
|
||||
var account Account
|
||||
if err := rlp.DecodeBytes(leaf, &account); err != nil {
|
||||
return nil
|
||||
@@ -724,5 +759,4 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return root, err
|
||||
}
|
||||
|
@@ -86,15 +86,15 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||
|
||||
// Modify the transient state.
|
||||
for i := byte(0); i < 255; i++ {
|
||||
modify(transState, common.Address{byte(i)}, i, 0)
|
||||
modify(transState, common.Address{i}, i, 0)
|
||||
}
|
||||
// Write modifications to trie.
|
||||
transState.IntermediateRoot(false)
|
||||
|
||||
// Overwrite all the data with new values in the transient database.
|
||||
for i := byte(0); i < 255; i++ {
|
||||
modify(transState, common.Address{byte(i)}, i, 99)
|
||||
modify(finalState, common.Address{byte(i)}, i, 99)
|
||||
modify(transState, common.Address{i}, i, 99)
|
||||
modify(finalState, common.Address{i}, i, 99)
|
||||
}
|
||||
|
||||
// Commit and cross check the databases.
|
||||
@@ -449,3 +449,38 @@ func TestCopyOfCopy(t *testing.T) {
|
||||
t.Fatalf("2nd copy fail, expected 42, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDeleteCreateRevert tests a weird state transition corner case that we hit
|
||||
// while changing the internals of statedb. The workflow is that a contract is
|
||||
// self destructed, then in a followup transaction (but same block) it's created
|
||||
// again and the transaction reverted.
|
||||
//
|
||||
// The original statedb implementation flushed dirty objects to the tries after
|
||||
// each transaction, so this works ok. The rework accumulated writes in memory
|
||||
// first, but the journal wiped the entire state object on create-revert.
|
||||
func TestDeleteCreateRevert(t *testing.T) {
|
||||
// Create an initial state with a single contract
|
||||
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
||||
|
||||
addr := toAddr([]byte("so"))
|
||||
state.SetBalance(addr, big.NewInt(1))
|
||||
|
||||
root, _ := state.Commit(false)
|
||||
state.Reset(root)
|
||||
|
||||
// Simulate self-destructing in one transaction, then create-reverting in another
|
||||
state.Suicide(addr)
|
||||
state.Finalise(true)
|
||||
|
||||
id := state.Snapshot()
|
||||
state.SetBalance(addr, big.NewInt(2))
|
||||
state.RevertToSnapshot(id)
|
||||
|
||||
// Commit the entire state and make sure we don't crash and have the correct state
|
||||
root, _ = state.Commit(true)
|
||||
state.Reset(root)
|
||||
|
||||
if state.getStateObject(addr) != nil {
|
||||
t.Fatalf("self-destructed contract came alive")
|
||||
}
|
||||
}
|
||||
|
@@ -68,7 +68,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
// Iterate over and process the individual transactions
|
||||
for i, tx := range block.Transactions() {
|
||||
statedb.Prepare(tx.Hash(), block.Hash(), i)
|
||||
receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
|
||||
receipt, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
@@ -85,10 +85,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
// and uses the input parameters for its environment. It returns the receipt
|
||||
// for the transaction, gas used and an error if the transaction failed,
|
||||
// indicating the block was invalid.
|
||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) {
|
||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
||||
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, err
|
||||
}
|
||||
// Create a new context to be used in the EVM environment
|
||||
context := NewEVMContext(msg, header, bc, author)
|
||||
@@ -98,7 +98,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
||||
// Apply the transaction to the current state (included in the env)
|
||||
_, gas, failed, err := ApplyMessage(vmenv, msg, gp)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, err
|
||||
}
|
||||
// Update the state with pending changes
|
||||
var root []byte
|
||||
@@ -125,5 +125,5 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
||||
receipt.BlockNumber = header.Number
|
||||
receipt.TransactionIndex = uint(statedb.TxIndex())
|
||||
|
||||
return receipt, gas, err
|
||||
return receipt, err
|
||||
}
|
||||
|
@@ -76,10 +76,10 @@ type Message interface {
|
||||
}
|
||||
|
||||
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
|
||||
func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) {
|
||||
func IntrinsicGas(data []byte, contractCreation, isEIP155 bool, isEIP2028 bool) (uint64, error) {
|
||||
// Set the starting gas for the raw transaction
|
||||
var gas uint64
|
||||
if contractCreation && homestead {
|
||||
if contractCreation && isEIP155 {
|
||||
gas = params.TxGasContractCreation
|
||||
} else {
|
||||
gas = params.TxGas
|
||||
@@ -94,10 +94,14 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error)
|
||||
}
|
||||
}
|
||||
// Make sure we don't exceed uint64 for all data combinations
|
||||
if (math.MaxUint64-gas)/params.TxDataNonZeroGas < nz {
|
||||
nonZeroGas := params.TxDataNonZeroGasFrontier
|
||||
if isEIP2028 {
|
||||
nonZeroGas = params.TxDataNonZeroGasEIP2028
|
||||
}
|
||||
if (math.MaxUint64-gas)/nonZeroGas < nz {
|
||||
return 0, vm.ErrOutOfGas
|
||||
}
|
||||
gas += nz * params.TxDataNonZeroGas
|
||||
gas += nz * nonZeroGas
|
||||
|
||||
z := uint64(len(data)) - nz
|
||||
if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
|
||||
@@ -187,10 +191,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
|
||||
msg := st.msg
|
||||
sender := vm.AccountRef(msg.From())
|
||||
homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)
|
||||
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber)
|
||||
contractCreation := msg.To() == nil
|
||||
|
||||
// Pay intrinsic gas
|
||||
gas, err := IntrinsicGas(st.data, contractCreation, homestead)
|
||||
gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul)
|
||||
if err != nil {
|
||||
return nil, 0, false, err
|
||||
}
|
||||
|
@@ -17,6 +17,8 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
)
|
||||
@@ -27,6 +29,7 @@ import (
|
||||
type txNoncer struct {
|
||||
fallback *state.StateDB
|
||||
nonces map[common.Address]uint64
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// newTxNoncer creates a new virtual state database to track the pool nonces.
|
||||
@@ -40,6 +43,11 @@ func newTxNoncer(statedb *state.StateDB) *txNoncer {
|
||||
// get returns the current nonce of an account, falling back to a real state
|
||||
// database if the account is unknown.
|
||||
func (txn *txNoncer) get(addr common.Address) uint64 {
|
||||
// We use mutex for get operation is the underlying
|
||||
// state will mutate db even for read access.
|
||||
txn.lock.Lock()
|
||||
defer txn.lock.Unlock()
|
||||
|
||||
if _, ok := txn.nonces[addr]; !ok {
|
||||
txn.nonces[addr] = txn.fallback.GetNonce(addr)
|
||||
}
|
||||
@@ -49,5 +57,23 @@ func (txn *txNoncer) get(addr common.Address) uint64 {
|
||||
// set inserts a new virtual nonce into the virtual state database to be returned
|
||||
// whenever the pool requests it instead of reaching into the real state database.
|
||||
func (txn *txNoncer) set(addr common.Address, nonce uint64) {
|
||||
txn.lock.Lock()
|
||||
defer txn.lock.Unlock()
|
||||
|
||||
txn.nonces[addr] = nonce
|
||||
}
|
||||
|
||||
// setIfLower updates a new virtual nonce into the virtual state database if the
|
||||
// the new one is lower.
|
||||
func (txn *txNoncer) setIfLower(addr common.Address, nonce uint64) {
|
||||
txn.lock.Lock()
|
||||
defer txn.lock.Unlock()
|
||||
|
||||
if _, ok := txn.nonces[addr]; !ok {
|
||||
txn.nonces[addr] = txn.fallback.GetNonce(addr)
|
||||
}
|
||||
if txn.nonces[addr] <= nonce {
|
||||
return
|
||||
}
|
||||
txn.nonces[addr] = nonce
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user