mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
Update Geth from upstream
This commit is contained in:
commit
8d954047f7
117 changed files with 10944 additions and 10838 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
|
@ -9,3 +9,4 @@ les/ @zsfelfoldi
|
||||||
light/ @zsfelfoldi
|
light/ @zsfelfoldi
|
||||||
mobile/ @karalabe
|
mobile/ @karalabe
|
||||||
p2p/ @fjl @zsfelfoldi
|
p2p/ @fjl @zsfelfoldi
|
||||||
|
whisper/ @gballet @gluk256
|
||||||
|
|
|
||||||
11
.github/no-response.yml
vendored
Normal file
11
.github/no-response.yml
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Number of days of inactivity before an Issue is closed for lack of response
|
||||||
|
daysUntilClose: 30
|
||||||
|
# Label requiring a response
|
||||||
|
responseRequiredLabel: more-information-needed
|
||||||
|
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
|
||||||
|
closeComment: >
|
||||||
|
This issue has been automatically closed because there has been no response
|
||||||
|
to our request for more information from the original author. With only the
|
||||||
|
information that is currently in the issue, we don't have enough information
|
||||||
|
to take action. Please reach out if you have or find the answers we need so
|
||||||
|
that we can investigate further.
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -42,3 +42,6 @@ profile.cov
|
||||||
/dashboard/assets/node_modules
|
/dashboard/assets/node_modules
|
||||||
/dashboard/assets/stats.json
|
/dashboard/assets/stats.json
|
||||||
/dashboard/assets/bundle.js
|
/dashboard/assets/bundle.js
|
||||||
|
/dashboard/assets/package-lock.json
|
||||||
|
|
||||||
|
**/yarn-error.log
|
||||||
|
|
|
||||||
303
.travis.yml
303
.travis.yml
|
|
@ -6,7 +6,7 @@ matrix:
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.8.x
|
go: 1.9.x
|
||||||
script:
|
script:
|
||||||
- sudo modprobe fuse
|
- sudo modprobe fuse
|
||||||
- sudo chmod 666 /dev/fuse
|
- sudo chmod 666 /dev/fuse
|
||||||
|
|
@ -18,7 +18,7 @@ matrix:
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.10.x
|
go: "1.10"
|
||||||
script:
|
script:
|
||||||
- sudo modprobe fuse
|
- sudo modprobe fuse
|
||||||
- sudo chmod 666 /dev/fuse
|
- sudo chmod 666 /dev/fuse
|
||||||
|
|
@ -27,7 +27,7 @@ matrix:
|
||||||
- go run build/ci.go test -coverage
|
- go run build/ci.go test -coverage
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.10.x
|
go: "1.10"
|
||||||
script:
|
script:
|
||||||
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
|
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
|
||||||
- brew update
|
- brew update
|
||||||
|
|
@ -39,7 +39,7 @@ matrix:
|
||||||
# This builder only tests code linters on latest version of Go
|
# This builder only tests code linters on latest version of Go
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
go: 1.9.x
|
go: "1.10"
|
||||||
env:
|
env:
|
||||||
- lint
|
- lint
|
||||||
git:
|
git:
|
||||||
|
|
@ -47,148 +47,159 @@ matrix:
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go lint
|
- go run build/ci.go lint
|
||||||
|
|
||||||
# # This builder does the Ubuntu PPA and Linux Azure uploads
|
# This builder does the Ubuntu PPA upload
|
||||||
# - os: linux
|
- os: linux
|
||||||
# dist: trusty
|
dist: trusty
|
||||||
# sudo: required
|
go: "1.10"
|
||||||
# go: 1.9.x
|
env:
|
||||||
# env:
|
- ubuntu-ppa
|
||||||
# - ubuntu-ppa
|
git:
|
||||||
# - azure-linux
|
submodules: false # avoid cloning ethereum/tests
|
||||||
# git:
|
addons:
|
||||||
# submodules: false # avoid cloning ethereum/tests
|
apt:
|
||||||
# addons:
|
packages:
|
||||||
# apt:
|
- devscripts
|
||||||
# packages:
|
- debhelper
|
||||||
# - devscripts
|
- dput
|
||||||
# - debhelper
|
- fakeroot
|
||||||
# - dput
|
script:
|
||||||
# - gcc-multilib
|
- go run build/ci.go debsrc -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -upload ppa:ethereum/ethereum
|
||||||
# - fakeroot
|
|
||||||
# script:
|
# This builder does the Linux Azure uploads
|
||||||
# # Build for the primary platforms that Trusty can manage
|
- os: linux
|
||||||
# - go run build/ci.go debsrc -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -upload ppa:ethereum/ethereum
|
dist: trusty
|
||||||
# - go run build/ci.go install
|
sudo: required
|
||||||
# - go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
go: "1.10"
|
||||||
# - go run build/ci.go install -arch 386
|
env:
|
||||||
# - go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
- azure-linux
|
||||||
#
|
git:
|
||||||
# # Switch over GCC to cross compilation (breaks 386, hence why do it here only)
|
submodules: false # avoid cloning ethereum/tests
|
||||||
# - sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
addons:
|
||||||
# - sudo ln -s /usr/include/asm-generic /usr/include/asm
|
apt:
|
||||||
#
|
packages:
|
||||||
# - GOARM=5 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
|
- gcc-multilib
|
||||||
# - GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
script:
|
||||||
# - GOARM=6 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
|
# Build for the primary platforms that Trusty can manage
|
||||||
# - GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
- go run build/ci.go install
|
||||||
# - GOARM=7 go run build/ci.go install -arch arm -cc arm-linux-gnueabihf-gcc
|
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
# - GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
- go run build/ci.go install -arch 386
|
||||||
# - go run build/ci.go install -arch arm64 -cc aarch64-linux-gnu-gcc
|
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
# - go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
|
||||||
#
|
# Switch over GCC to cross compilation (breaks 386, hence why do it here only)
|
||||||
# # This builder does the Linux Azure MIPS xgo uploads
|
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||||
# - os: linux
|
- sudo ln -s /usr/include/asm-generic /usr/include/asm
|
||||||
# dist: trusty
|
|
||||||
# services:
|
- GOARM=5 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
|
||||||
# - docker
|
- GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
# go: 1.9.x
|
- GOARM=6 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
|
||||||
# env:
|
- GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
# - azure-linux-mips
|
- GOARM=7 go run build/ci.go install -arch arm -cc arm-linux-gnueabihf-gcc
|
||||||
# git:
|
- GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
# submodules: false # avoid cloning ethereum/tests
|
- go run build/ci.go install -arch arm64 -cc aarch64-linux-gnu-gcc
|
||||||
# script:
|
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
# - go run build/ci.go xgo --alltools -- --targets=linux/mips --ldflags '-extldflags "-static"' -v
|
|
||||||
# - for bin in build/bin/*-linux-mips; do mv -f "${bin}" "${bin/-linux-mips/}"; done
|
# This builder does the Linux Azure MIPS xgo uploads
|
||||||
# - go run build/ci.go archive -arch mips -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
- os: linux
|
||||||
#
|
dist: trusty
|
||||||
# - go run build/ci.go xgo --alltools -- --targets=linux/mipsle --ldflags '-extldflags "-static"' -v
|
services:
|
||||||
# - for bin in build/bin/*-linux-mipsle; do mv -f "${bin}" "${bin/-linux-mipsle/}"; done
|
- docker
|
||||||
# - go run build/ci.go archive -arch mipsle -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
go: "1.10"
|
||||||
#
|
env:
|
||||||
# - go run build/ci.go xgo --alltools -- --targets=linux/mips64 --ldflags '-extldflags "-static"' -v
|
- azure-linux-mips
|
||||||
# - for bin in build/bin/*-linux-mips64; do mv -f "${bin}" "${bin/-linux-mips64/}"; done
|
git:
|
||||||
# - go run build/ci.go archive -arch mips64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
submodules: false # avoid cloning ethereum/tests
|
||||||
#
|
script:
|
||||||
# - go run build/ci.go xgo --alltools -- --targets=linux/mips64le --ldflags '-extldflags "-static"' -v
|
- go run build/ci.go xgo --alltools -- --targets=linux/mips --ldflags '-extldflags "-static"' -v
|
||||||
# - for bin in build/bin/*-linux-mips64le; do mv -f "${bin}" "${bin/-linux-mips64le/}"; done
|
- for bin in build/bin/*-linux-mips; do mv -f "${bin}" "${bin/-linux-mips/}"; done
|
||||||
# - go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
- go run build/ci.go archive -arch mips -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
#
|
|
||||||
# # This builder does the Android Maven and Azure uploads
|
- go run build/ci.go xgo --alltools -- --targets=linux/mipsle --ldflags '-extldflags "-static"' -v
|
||||||
# - os: linux
|
- for bin in build/bin/*-linux-mipsle; do mv -f "${bin}" "${bin/-linux-mipsle/}"; done
|
||||||
# dist: precise # Needed for the android tools
|
- go run build/ci.go archive -arch mipsle -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
# addons:
|
|
||||||
# apt:
|
- go run build/ci.go xgo --alltools -- --targets=linux/mips64 --ldflags '-extldflags "-static"' -v
|
||||||
# packages:
|
- for bin in build/bin/*-linux-mips64; do mv -f "${bin}" "${bin/-linux-mips64/}"; done
|
||||||
# - oracle-java8-installer
|
- go run build/ci.go archive -arch mips64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
# - oracle-java8-set-default
|
|
||||||
# language: android
|
- go run build/ci.go xgo --alltools -- --targets=linux/mips64le --ldflags '-extldflags "-static"' -v
|
||||||
# android:
|
- for bin in build/bin/*-linux-mips64le; do mv -f "${bin}" "${bin/-linux-mips64le/}"; done
|
||||||
# components:
|
- go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
# - platform-tools
|
|
||||||
# - tools
|
# This builder does the Android Maven and Azure uploads
|
||||||
# - android-15
|
- os: linux
|
||||||
# - android-19
|
dist: precise # Needed for the android tools
|
||||||
# - android-24
|
addons:
|
||||||
# env:
|
apt:
|
||||||
# - azure-android
|
packages:
|
||||||
# - maven-android
|
- oracle-java8-installer
|
||||||
# git:
|
- oracle-java8-set-default
|
||||||
# submodules: false # avoid cloning ethereum/tests
|
language: android
|
||||||
# before_install:
|
android:
|
||||||
# - curl https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz | tar -xz
|
components:
|
||||||
# - export PATH=`pwd`/go/bin:$PATH
|
- platform-tools
|
||||||
# - export GOROOT=`pwd`/go
|
- tools
|
||||||
# - export GOPATH=$HOME/go
|
- android-15
|
||||||
# script:
|
- android-19
|
||||||
# # Build the Android archive and upload it to Maven Central and Azure
|
- android-24
|
||||||
# - curl https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip -o android-ndk-r15c.zip
|
env:
|
||||||
# - unzip -q android-ndk-r15c.zip && rm android-ndk-r15c.zip
|
- azure-android
|
||||||
# - mv android-ndk-r15c $HOME
|
- maven-android
|
||||||
# - export ANDROID_NDK=$HOME/android-ndk-r15c
|
git:
|
||||||
#
|
submodules: false # avoid cloning ethereum/tests
|
||||||
# - mkdir -p $GOPATH/src/github.com/ethereum
|
before_install:
|
||||||
# - ln -s `pwd` $GOPATH/src/github.com/ethereum
|
- curl https://storage.googleapis.com/golang/go1.10.linux-amd64.tar.gz | tar -xz
|
||||||
# - go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
|
- export PATH=`pwd`/go/bin:$PATH
|
||||||
#
|
- export GOROOT=`pwd`/go
|
||||||
# # This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
- export GOPATH=$HOME/go
|
||||||
# - os: osx
|
script:
|
||||||
# go: 1.9.x
|
# Build the Android archive and upload it to Maven Central and Azure
|
||||||
# env:
|
- curl https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip -o android-ndk-r15c.zip
|
||||||
# - azure-osx
|
- unzip -q android-ndk-r15c.zip && rm android-ndk-r15c.zip
|
||||||
# - azure-ios
|
- mv android-ndk-r15c $HOME
|
||||||
# - cocoapods-ios
|
- export ANDROID_NDK=$HOME/android-ndk-r15c
|
||||||
# git:
|
|
||||||
# submodules: false # avoid cloning ethereum/tests
|
- mkdir -p $GOPATH/src/github.com/ethereum
|
||||||
# script:
|
- ln -s `pwd` $GOPATH/src/github.com/ethereum
|
||||||
# - go run build/ci.go install
|
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
|
||||||
# - go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
|
|
||||||
#
|
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
||||||
# # Build the iOS framework and upload it to CocoaPods and Azure
|
- os: osx
|
||||||
# - gem uninstall cocoapods -a -x
|
go: "1.10"
|
||||||
# - gem install cocoapods
|
env:
|
||||||
#
|
- azure-osx
|
||||||
# - mv ~/.cocoapods/repos/master ~/.cocoapods/repos/master.bak
|
- azure-ios
|
||||||
# - sed -i '.bak' 's/repo.join/!repo.join/g' $(dirname `gem which cocoapods`)/cocoapods/sources_manager.rb
|
- cocoapods-ios
|
||||||
# - if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git clone --depth=1 https://github.com/CocoaPods/Specs.git ~/.cocoapods/repos/master && pod setup --verbose; fi
|
git:
|
||||||
#
|
submodules: false # avoid cloning ethereum/tests
|
||||||
# - xctool -version
|
script:
|
||||||
# - xcrun simctl list
|
- go run build/ci.go install
|
||||||
#
|
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
|
||||||
# # Workaround for https://github.com/golang/go/issues/23749
|
|
||||||
# - export CGO_CFLAGS_ALLOW='-fmodules|-fblocks|-fobjc-arc'
|
# Build the iOS framework and upload it to CocoaPods and Azure
|
||||||
# - go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
|
- gem uninstall cocoapods -a -x
|
||||||
#
|
- gem install cocoapods
|
||||||
# # This builder does the Azure archive purges to avoid accumulating junk
|
|
||||||
# - os: linux
|
- mv ~/.cocoapods/repos/master ~/.cocoapods/repos/master.bak
|
||||||
# dist: trusty
|
- sed -i '.bak' 's/repo.join/!repo.join/g' $(dirname `gem which cocoapods`)/cocoapods/sources_manager.rb
|
||||||
# sudo: required
|
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git clone --depth=1 https://github.com/CocoaPods/Specs.git ~/.cocoapods/repos/master && pod setup --verbose; fi
|
||||||
# go: 1.9.x
|
|
||||||
# env:
|
- xctool -version
|
||||||
# - azure-purge
|
- xcrun simctl list
|
||||||
# git:
|
|
||||||
# submodules: false # avoid cloning ethereum/tests
|
# Workaround for https://github.com/golang/go/issues/23749
|
||||||
# script:
|
- export CGO_CFLAGS_ALLOW='-fmodules|-fblocks|-fobjc-arc'
|
||||||
# - go run build/ci.go purge -store gethstore/builds -days 14
|
- 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
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
go: "1.10"
|
||||||
|
env:
|
||||||
|
- azure-purge
|
||||||
|
git:
|
||||||
|
submodules: false # avoid cloning ethereum/tests
|
||||||
|
script:
|
||||||
|
- go run build/ci.go purge -store gethstore/builds -days 14
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
webhooks:
|
webhooks:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.9-alpine as builder
|
FROM golang:1.10-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache make gcc musl-dev linux-headers
|
RUN apk add --no-cache make gcc musl-dev linux-headers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.9-alpine as builder
|
FROM golang:1.10-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache make gcc musl-dev linux-headers
|
RUN apk add --no-cache make gcc musl-dev linux-headers
|
||||||
|
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.8.2
|
1.8.4
|
||||||
|
|
|
||||||
|
|
@ -621,14 +621,16 @@ func TestBareEvents(t *testing.T) {
|
||||||
// TestUnpackEvent is based on this contract:
|
// TestUnpackEvent is based on this contract:
|
||||||
// contract T {
|
// contract T {
|
||||||
// event received(address sender, uint amount, bytes memo);
|
// event received(address sender, uint amount, bytes memo);
|
||||||
|
// event receivedAddr(address sender);
|
||||||
// function receive(bytes memo) external payable {
|
// function receive(bytes memo) external payable {
|
||||||
// received(msg.sender, msg.value, memo);
|
// received(msg.sender, msg.value, memo);
|
||||||
|
// receivedAddr(msg.sender);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt:
|
// When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt:
|
||||||
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
|
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
|
||||||
func TestUnpackEvent(t *testing.T) {
|
func TestUnpackEvent(t *testing.T) {
|
||||||
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]`
|
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
|
||||||
abi, err := JSON(strings.NewReader(abiJSON))
|
abi, err := JSON(strings.NewReader(abiJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
@ -656,6 +658,17 @@ func TestUnpackEvent(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
t.Logf("len(data): %d; received event: %+v", len(data), ev)
|
t.Logf("len(data): %d; received event: %+v", len(data), ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReceivedAddrEvent struct {
|
||||||
|
Address common.Address
|
||||||
|
}
|
||||||
|
var receivedAddrEv ReceivedAddrEvent
|
||||||
|
err = abi.Unpack(&receivedAddrEv, "receivedAddr", data)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else {
|
||||||
|
t.Logf("len(data): %d; received event: %+v", len(data), receivedAddrEv)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestABI_MethodById(t *testing.T) {
|
func TestABI_MethodById(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -113,16 +113,8 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
|
||||||
}
|
}
|
||||||
// If the output interface is a struct, make sure names don't collide
|
// If the output interface is a struct, make sure names don't collide
|
||||||
if kind == reflect.Struct {
|
if kind == reflect.Struct {
|
||||||
exists := make(map[string]bool)
|
if err := requireUniqueStructFieldNames(arguments); err != nil {
|
||||||
for _, arg := range arguments {
|
return err
|
||||||
field := capitalise(arg.Name)
|
|
||||||
if field == "" {
|
|
||||||
return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
|
|
||||||
}
|
|
||||||
if exists[field] {
|
|
||||||
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)
|
|
||||||
}
|
|
||||||
exists[field] = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, arg := range arguments.NonIndexed() {
|
for i, arg := range arguments.NonIndexed() {
|
||||||
|
|
@ -131,14 +123,9 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
|
||||||
|
|
||||||
switch kind {
|
switch kind {
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
name := capitalise(arg.Name)
|
err := unpackStruct(value, reflectValue, arg)
|
||||||
for j := 0; j < typ.NumField(); j++ {
|
if err != nil {
|
||||||
// TODO read tags: `abi:"fieldName"`
|
return err
|
||||||
if typ.Field(j).Name == name {
|
|
||||||
if err := set(value.Field(j), reflectValue, arg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case reflect.Slice, reflect.Array:
|
case reflect.Slice, reflect.Array:
|
||||||
if value.Len() < i {
|
if value.Len() < i {
|
||||||
|
|
@ -165,8 +152,20 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interf
|
||||||
return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
|
return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
|
||||||
}
|
}
|
||||||
elem := reflect.ValueOf(v).Elem()
|
elem := reflect.ValueOf(v).Elem()
|
||||||
|
kind := elem.Kind()
|
||||||
reflectValue := reflect.ValueOf(marshalledValues[0])
|
reflectValue := reflect.ValueOf(marshalledValues[0])
|
||||||
|
|
||||||
|
if kind == reflect.Struct {
|
||||||
|
//make sure names don't collide
|
||||||
|
if err := requireUniqueStructFieldNames(arguments); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return unpackStruct(elem, reflectValue, arguments[0])
|
||||||
|
}
|
||||||
|
|
||||||
return set(elem, reflectValue, arguments.NonIndexed()[0])
|
return set(elem, reflectValue, arguments.NonIndexed()[0])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Computes the full size of an array;
|
// Computes the full size of an array;
|
||||||
|
|
@ -278,3 +277,18 @@ func capitalise(input string) string {
|
||||||
}
|
}
|
||||||
return strings.ToUpper(input[:1]) + input[1:]
|
return strings.ToUpper(input[:1]) + input[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//unpackStruct extracts each argument into its corresponding struct field
|
||||||
|
func unpackStruct(value, reflectValue reflect.Value, arg Argument) error {
|
||||||
|
name := capitalise(arg.Name)
|
||||||
|
typ := value.Type()
|
||||||
|
for j := 0; j < typ.NumField(); j++ {
|
||||||
|
// TODO read tags: `abi:"fieldName"`
|
||||||
|
if typ.Field(j).Name == name {
|
||||||
|
if err := set(value.Field(j), reflectValue, arg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -307,9 +307,9 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
||||||
|
|
||||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||||
for _, tx := range b.pendingBlock.Transactions() {
|
for _, tx := range b.pendingBlock.Transactions() {
|
||||||
block.AddTx(tx)
|
block.AddTxWithChain(b.blockchain, tx)
|
||||||
}
|
}
|
||||||
block.AddTx(tx)
|
block.AddTxWithChain(b.blockchain, tx)
|
||||||
})
|
})
|
||||||
statedb, _ := b.blockchain.State()
|
statedb, _ := b.blockchain.State()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -385,8 +385,7 @@ var methodNormalizer = map[Lang]func(string) string{
|
||||||
LangJava: decapitalise,
|
LangJava: decapitalise,
|
||||||
}
|
}
|
||||||
|
|
||||||
// capitalise makes the first character of a string upper case, also removing any
|
// capitalise makes a camel-case string which starts with an upper case character.
|
||||||
// prefixing underscores from the variable names.
|
|
||||||
func capitalise(input string) string {
|
func capitalise(input string) string {
|
||||||
for len(input) > 0 && input[0] == '_' {
|
for len(input) > 0 && input[0] == '_' {
|
||||||
input = input[1:]
|
input = input[1:]
|
||||||
|
|
@ -394,12 +393,42 @@ func capitalise(input string) string {
|
||||||
if len(input) == 0 {
|
if len(input) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return strings.ToUpper(input[:1]) + input[1:]
|
return toCamelCase(strings.ToUpper(input[:1]) + input[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// decapitalise makes the first character of a string lower case.
|
// decapitalise makes a camel-case string which starts with a lower case character.
|
||||||
func decapitalise(input string) string {
|
func decapitalise(input string) string {
|
||||||
return strings.ToLower(input[:1]) + input[1:]
|
for len(input) > 0 && input[0] == '_' {
|
||||||
|
input = input[1:]
|
||||||
|
}
|
||||||
|
if len(input) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return toCamelCase(strings.ToLower(input[:1]) + input[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// toCamelCase converts an under-score string to a camel-case string
|
||||||
|
func toCamelCase(input string) string {
|
||||||
|
toupper := false
|
||||||
|
|
||||||
|
result := ""
|
||||||
|
for k, v := range input {
|
||||||
|
switch {
|
||||||
|
case k == 0:
|
||||||
|
result = strings.ToUpper(string(input[0]))
|
||||||
|
|
||||||
|
case toupper:
|
||||||
|
result += strings.ToUpper(string(v))
|
||||||
|
toupper = false
|
||||||
|
|
||||||
|
case v == '_':
|
||||||
|
toupper = true
|
||||||
|
|
||||||
|
default:
|
||||||
|
result += string(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// structured checks whether a list of ABI data types has enough information to
|
// structured checks whether a list of ABI data types has enough information to
|
||||||
|
|
|
||||||
|
|
@ -425,7 +425,7 @@ var bindTests = []struct {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
// Tests that gas estimation works for contracts with weird gas mechanics too.
|
// Tests that gas estimation works for contracts with weird gas mechanics too.
|
||||||
{
|
{
|
||||||
`FunkyGasPattern`,
|
`FunkyGasPattern`,
|
||||||
`
|
`
|
||||||
|
|
@ -506,6 +506,7 @@ var bindTests = []struct {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
// Tests that methods and returns with underscores inside work correctly.
|
||||||
{
|
{
|
||||||
`Underscorer`,
|
`Underscorer`,
|
||||||
`
|
`
|
||||||
|
|
@ -518,7 +519,7 @@ var bindTests = []struct {
|
||||||
}
|
}
|
||||||
function LowerUpperCollision() constant returns (int _res, int Res) {
|
function LowerUpperCollision() constant returns (int _res, int Res) {
|
||||||
return (1, 2);
|
return (1, 2);
|
||||||
}
|
}
|
||||||
function UpperLowerCollision() constant returns (int _Res, int res) {
|
function UpperLowerCollision() constant returns (int _Res, int res) {
|
||||||
return (1, 2);
|
return (1, 2);
|
||||||
}
|
}
|
||||||
|
|
@ -531,9 +532,12 @@ var bindTests = []struct {
|
||||||
function AllPurelyUnderscoredOutput() constant returns (int _, int __) {
|
function AllPurelyUnderscoredOutput() constant returns (int _, int __) {
|
||||||
return (1, 2);
|
return (1, 2);
|
||||||
}
|
}
|
||||||
|
function _under_scored_func() constant returns (int _int) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`, `6060604052341561000f57600080fd5b6103498061001e6000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461008857806367e6633d146100b85780639df484851461014d578063af7486ab1461017d578063b564b34d146101ad578063e02ab24d146101dd578063e409ca451461020d575b600080fd5b341561009357600080fd5b61009b61023d565b604051808381526020018281526020019250505060405180910390f35b34156100c357600080fd5b6100cb610252565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156101115780820151818401526020810190506100f6565b50505050905090810190601f16801561013e5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561015857600080fd5b6101606102a0565b604051808381526020018281526020019250505060405180910390f35b341561018857600080fd5b6101906102b5565b604051808381526020018281526020019250505060405180910390f35b34156101b857600080fd5b6101c06102ca565b604051808381526020018281526020019250505060405180910390f35b34156101e857600080fd5b6101f06102df565b604051808381526020018281526020019250505060405180910390f35b341561021857600080fd5b6102206102f4565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600061025c610309565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820c11dcfa136fc7d182ee4d34f0b12d988496228f7e2d02d2b5376d996ca1743d00029`,
|
`, `6060604052341561000f57600080fd5b6103858061001e6000396000f30060606040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461009357806346546dbe146100c357806367e6633d146100ec5780639df4848514610181578063af7486ab146101b1578063b564b34d146101e1578063e02ab24d14610211578063e409ca4514610241575b600080fd5b341561009e57600080fd5b6100a6610271565b604051808381526020018281526020019250505060405180910390f35b34156100ce57600080fd5b6100d6610286565b6040518082815260200191505060405180910390f35b34156100f757600080fd5b6100ff61028e565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561014557808201518184015260208101905061012a565b50505050905090810190601f1680156101725780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561018c57600080fd5b6101946102dc565b604051808381526020018281526020019250505060405180910390f35b34156101bc57600080fd5b6101c46102f1565b604051808381526020018281526020019250505060405180910390f35b34156101ec57600080fd5b6101f4610306565b604051808381526020018281526020019250505060405180910390f35b341561021c57600080fd5b61022461031b565b604051808381526020018281526020019250505060405180910390f35b341561024c57600080fd5b610254610330565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600080905090565b6000610298610345565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820d1a53d9de9d1e3d55cb3dc591900b63c4f1ded79114f7b79b332684840e186a40029`,
|
||||||
`[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`,
|
`[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_under_scored_func","outputs":[{"name":"_int","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`,
|
||||||
`
|
`
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
|
|
@ -562,6 +566,7 @@ var bindTests = []struct {
|
||||||
a, b, _ = underscorer.UpperUpperCollision(nil)
|
a, b, _ = underscorer.UpperUpperCollision(nil)
|
||||||
a, b, _ = underscorer.PurelyUnderscoredOutput(nil)
|
a, b, _ = underscorer.PurelyUnderscoredOutput(nil)
|
||||||
a, b, _ = underscorer.AllPurelyUnderscoredOutput(nil)
|
a, b, _ = underscorer.AllPurelyUnderscoredOutput(nil)
|
||||||
|
a, _ = underscorer.UnderScoredFunc(nil)
|
||||||
|
|
||||||
fmt.Println(a, b, err)
|
fmt.Println(a, b, err)
|
||||||
`,
|
`,
|
||||||
|
|
@ -801,7 +806,8 @@ var bindTests = []struct {
|
||||||
// (See accounts/abi/unpack_test.go for more extensive testing)
|
// (See accounts/abi/unpack_test.go for more extensive testing)
|
||||||
if retrievedArr[4][3][2] != testArr[4][3][2] {
|
if retrievedArr[4][3][2] != testArr[4][3][2] {
|
||||||
t.Fatalf("Retrieved value does not match expected value! got: %d, expected: %d. %v", retrievedArr[4][3][2], testArr[4][3][2], err)
|
t.Fatalf("Retrieved value does not match expected value! got: %d, expected: %d. %v", retrievedArr[4][3][2], testArr[4][3][2], err)
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,3 +110,19 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// requireUniqueStructFieldNames makes sure field names don't collide
|
||||||
|
func requireUniqueStructFieldNames(args Arguments) error {
|
||||||
|
exists := make(map[string]bool)
|
||||||
|
for _, arg := range args {
|
||||||
|
field := capitalise(arg.Name)
|
||||||
|
if field == "" {
|
||||||
|
return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
|
||||||
|
}
|
||||||
|
if exists[field] {
|
||||||
|
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)
|
||||||
|
}
|
||||||
|
exists[field] = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ environment:
|
||||||
install:
|
install:
|
||||||
- git submodule update --init
|
- git submodule update --init
|
||||||
- rmdir C:\go /s /q
|
- rmdir C:\go /s /q
|
||||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.9.2.windows-%GETH_ARCH%.zip
|
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.windows-%GETH_ARCH%.zip
|
||||||
- 7z x go1.9.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
- 7z x go1.10.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||||
- go version
|
- go version
|
||||||
- gcc --version
|
- gcc --version
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,7 @@
|
||||||
|
|
||||||
Tagged releases and develop branch commits are available as installable Debian packages
|
Tagged releases and develop branch commits are available as installable Debian packages
|
||||||
for Ubuntu. Packages are built for the all Ubuntu versions which are supported by
|
for Ubuntu. Packages are built for the all Ubuntu versions which are supported by
|
||||||
Canonical:
|
Canonical.
|
||||||
|
|
||||||
- Trusty Tahr (14.04 LTS)
|
|
||||||
- Xenial Xerus (16.04 LTS)
|
|
||||||
- Yakkety Yak (16.10)
|
|
||||||
- Zesty Zapus (17.04)
|
|
||||||
|
|
||||||
Packages of develop branch commits have suffix -unstable and cannot be installed alongside
|
Packages of develop branch commits have suffix -unstable and cannot be installed alongside
|
||||||
the stable version. Switching between release streams requires user intervention.
|
the stable version. Switching between release streams requires user intervention.
|
||||||
|
|
@ -21,18 +16,18 @@ variable which Travis CI makes available to certain builds.
|
||||||
We want to build go-ethereum with the most recent version of Go, irrespective of the Go
|
We want to build go-ethereum with the most recent version of Go, irrespective of the Go
|
||||||
version that is available in the main Ubuntu repository. In order to make this possible,
|
version that is available in the main Ubuntu repository. In order to make this possible,
|
||||||
our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on
|
our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on
|
||||||
golang-1.9, which is co-installable alongside the regular golang package. PPA dependencies
|
golang-1.10, which is co-installable alongside the regular golang package. PPA dependencies
|
||||||
can be edited at https://launchpad.net/%7Eethereum/+archive/ubuntu/ethereum/+edit-dependencies
|
can be edited at https://launchpad.net/%7Eethereum/+archive/ubuntu/ethereum/+edit-dependencies
|
||||||
|
|
||||||
## Building Packages Locally (for testing)
|
## Building Packages Locally (for testing)
|
||||||
|
|
||||||
You need to run Ubuntu to do test packaging.
|
You need to run Ubuntu to do test packaging.
|
||||||
|
|
||||||
Add the gophers PPA and install Go 1.9 and Debian packaging tools:
|
Add the gophers PPA and install Go 1.10 and Debian packaging tools:
|
||||||
|
|
||||||
$ sudo apt-add-repository ppa:gophers/ubuntu/archive
|
$ sudo apt-add-repository ppa:gophers/ubuntu/archive
|
||||||
$ sudo apt-get update
|
$ sudo apt-get update
|
||||||
$ sudo apt-get install build-essential golang-1.9 devscripts debhelper
|
$ sudo apt-get install build-essential golang-1.10 devscripts debhelper
|
||||||
|
|
||||||
Create the source packages:
|
Create the source packages:
|
||||||
|
|
||||||
|
|
|
||||||
23
build/ci.go
23
build/ci.go
|
|
@ -182,13 +182,13 @@ func doInstall(cmdline []string) {
|
||||||
// Check Go version. People regularly open issues about compilation
|
// Check Go version. People regularly open issues about compilation
|
||||||
// failure with outdated Go. This should save them the trouble.
|
// failure with outdated Go. This should save them the trouble.
|
||||||
if !strings.Contains(runtime.Version(), "devel") {
|
if !strings.Contains(runtime.Version(), "devel") {
|
||||||
// Figure out the minor version number since we can't textually compare (1.10 < 1.8)
|
// Figure out the minor version number since we can't textually compare (1.10 < 1.9)
|
||||||
var minor int
|
var minor int
|
||||||
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
|
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
|
||||||
|
|
||||||
if minor < 8 {
|
if minor < 9 {
|
||||||
log.Println("You have Go version", runtime.Version())
|
log.Println("You have Go version", runtime.Version())
|
||||||
log.Println("go-ethereum requires at least Go version 1.8 and cannot")
|
log.Println("go-ethereum requires at least Go version 1.9 and cannot")
|
||||||
log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
|
log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
@ -262,16 +262,6 @@ func goTool(subcmd string, args ...string) *exec.Cmd {
|
||||||
|
|
||||||
func goToolArch(arch string, cc string, subcmd string, args ...string) *exec.Cmd {
|
func goToolArch(arch string, cc string, subcmd string, args ...string) *exec.Cmd {
|
||||||
cmd := build.GoTool(subcmd, args...)
|
cmd := build.GoTool(subcmd, args...)
|
||||||
if subcmd == "build" || subcmd == "install" || subcmd == "test" {
|
|
||||||
// Go CGO has a Windows linker error prior to 1.8 (https://github.com/golang/go/issues/8756).
|
|
||||||
// Work around issue by allowing multiple definitions for <1.8 builds.
|
|
||||||
var minor int
|
|
||||||
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
|
|
||||||
|
|
||||||
if runtime.GOOS == "windows" && minor < 8 {
|
|
||||||
cmd.Args = append(cmd.Args, []string{"-ldflags", "-extldflags -Wl,--allow-multiple-definition"}...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmd.Env = []string{"GOPATH=" + build.GOPATH()}
|
cmd.Env = []string{"GOPATH=" + build.GOPATH()}
|
||||||
if arch == "" || arch == runtime.GOARCH {
|
if arch == "" || arch == runtime.GOARCH {
|
||||||
cmd.Env = append(cmd.Env, "GOBIN="+GOBIN)
|
cmd.Env = append(cmd.Env, "GOBIN="+GOBIN)
|
||||||
|
|
@ -736,7 +726,7 @@ func doAndroidArchive(cmdline []string) {
|
||||||
log.Fatal("Please ensure ANDROID_NDK points to your Android NDK")
|
log.Fatal("Please ensure ANDROID_NDK points to your Android NDK")
|
||||||
}
|
}
|
||||||
// Build the Android archive and Maven resources
|
// Build the Android archive and Maven resources
|
||||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
|
||||||
build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK")))
|
build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK")))
|
||||||
build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/EthereumCommonwealth/go-callisto/mobile"))
|
build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/EthereumCommonwealth/go-callisto/mobile"))
|
||||||
|
|
||||||
|
|
@ -787,9 +777,10 @@ func gomobileTool(subcmd string, args ...string) *exec.Cmd {
|
||||||
cmd.Args = append(cmd.Args, args...)
|
cmd.Args = append(cmd.Args, args...)
|
||||||
cmd.Env = []string{
|
cmd.Env = []string{
|
||||||
"GOPATH=" + build.GOPATH(),
|
"GOPATH=" + build.GOPATH(),
|
||||||
|
"PATH=" + GOBIN + string(os.PathListSeparator) + os.Getenv("PATH"),
|
||||||
}
|
}
|
||||||
for _, e := range os.Environ() {
|
for _, e := range os.Environ() {
|
||||||
if strings.HasPrefix(e, "GOPATH=") {
|
if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "PATH=") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cmd.Env = append(cmd.Env, e)
|
cmd.Env = append(cmd.Env, e)
|
||||||
|
|
@ -856,7 +847,7 @@ func doXCodeFramework(cmdline []string) {
|
||||||
env := build.Env()
|
env := build.Env()
|
||||||
|
|
||||||
// Build the iOS XCode framework
|
// Build the iOS XCode framework
|
||||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
|
||||||
build.MustRun(gomobileTool("init"))
|
build.MustRun(gomobileTool("init"))
|
||||||
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/EthereumCommonwealth/go-callisto/mobile")
|
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/EthereumCommonwealth/go-callisto/mobile")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ Source: {{.Name}}
|
||||||
Section: science
|
Section: science
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: {{.Author}}
|
Maintainer: {{.Author}}
|
||||||
Build-Depends: debhelper (>= 8.0.0), golang-1.9
|
Build-Depends: debhelper (>= 8.0.0), golang-1.10
|
||||||
Standards-Version: 3.9.5
|
Standards-Version: 3.9.5
|
||||||
Homepage: https://ethereum.org
|
Homepage: https://ethereum.org
|
||||||
Vcs-Git: git://github.com/EthereumCommonwealth/go-callisto.git
|
Vcs-Git: git://github.com/EthereumCommonwealth/go-callisto.git
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#export DH_VERBOSE=1
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
override_dh_auto_build:
|
override_dh_auto_build:
|
||||||
build/env.sh /usr/lib/go-1.9/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
build/env.sh /usr/lib/go-1.10/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,34 @@ Requires a first argument of the file to write to.
|
||||||
Optional second and third arguments control the first and
|
Optional second and third arguments control the first and
|
||||||
last block to write. In this mode, the file will be appended
|
last block to write. In this mode, the file will be appended
|
||||||
if already existing.`,
|
if already existing.`,
|
||||||
|
}
|
||||||
|
importPreimagesCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(importPreimages),
|
||||||
|
Name: "import-preimages",
|
||||||
|
Usage: "Import the preimage database from an RLP stream",
|
||||||
|
ArgsUsage: "<datafile>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The import-preimages command imports hash preimages from an RLP encoded stream.`,
|
||||||
|
}
|
||||||
|
exportPreimagesCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(exportPreimages),
|
||||||
|
Name: "export-preimages",
|
||||||
|
Usage: "Export the preimage database into an RLP stream",
|
||||||
|
ArgsUsage: "<dumpfile>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The export-preimages command export hash preimages to an RLP encoded stream`,
|
||||||
}
|
}
|
||||||
copydbCommand = cli.Command{
|
copydbCommand = cli.Command{
|
||||||
Action: utils.MigrateFlags(copyDb),
|
Action: utils.MigrateFlags(copyDb),
|
||||||
|
|
@ -225,6 +253,13 @@ func importChain(ctx *cli.Context) error {
|
||||||
utils.Fatalf("Failed to read database stats: %v", err)
|
utils.Fatalf("Failed to read database stats: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Println(stats)
|
fmt.Println(stats)
|
||||||
|
|
||||||
|
ioStats, err := db.LDB().GetProperty("leveldb.iostats")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read database iostats: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(ioStats)
|
||||||
|
|
||||||
fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses())
|
fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses())
|
||||||
fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads())
|
fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads())
|
||||||
|
|
||||||
|
|
@ -255,6 +290,12 @@ func importChain(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
fmt.Println(stats)
|
fmt.Println(stats)
|
||||||
|
|
||||||
|
ioStats, err = db.LDB().GetProperty("leveldb.iostats")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read database iostats: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(ioStats)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,7 +327,39 @@ func exportChain(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Export error: %v\n", err)
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Export done in %v", time.Since(start))
|
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// importPreimages imports preimage data from the specified file.
|
||||||
|
func importPreimages(ctx *cli.Context) error {
|
||||||
|
if len(ctx.Args()) < 1 {
|
||||||
|
utils.Fatalf("This command requires an argument.")
|
||||||
|
}
|
||||||
|
stack := makeFullNode(ctx)
|
||||||
|
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil {
|
||||||
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// exportPreimages dumps the preimage data to specified json file in streaming way.
|
||||||
|
func exportPreimages(ctx *cli.Context) error {
|
||||||
|
if len(ctx.Args()) < 1 {
|
||||||
|
utils.Fatalf("This command requires an argument.")
|
||||||
|
}
|
||||||
|
stack := makeFullNode(ctx)
|
||||||
|
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
if err := utils.ExportPreimages(diskdb, ctx.Args().First()); err != nil {
|
||||||
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import (
|
||||||
"github.com/EthereumCommonwealth/go-callisto/eth"
|
"github.com/EthereumCommonwealth/go-callisto/eth"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/node"
|
"github.com/EthereumCommonwealth/go-callisto/node"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/params"
|
"github.com/EthereumCommonwealth/go-callisto/params"
|
||||||
whisper "github.com/EthereumCommonwealth/go-callisto/whisper/whisperv5"
|
whisper "github.com/EthereumCommonwealth/go-callisto/whisper/whisperv6"
|
||||||
"github.com/naoina/toml"
|
"github.com/naoina/toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ var (
|
||||||
utils.DashboardAddrFlag,
|
utils.DashboardAddrFlag,
|
||||||
utils.DashboardPortFlag,
|
utils.DashboardPortFlag,
|
||||||
utils.DashboardRefreshFlag,
|
utils.DashboardRefreshFlag,
|
||||||
utils.DashboardAssetsFlag,
|
|
||||||
utils.EthashCacheDirFlag,
|
utils.EthashCacheDirFlag,
|
||||||
utils.EthashCachesInMemoryFlag,
|
utils.EthashCachesInMemoryFlag,
|
||||||
utils.EthashCachesOnDiskFlag,
|
utils.EthashCachesOnDiskFlag,
|
||||||
|
|
@ -156,6 +155,8 @@ func init() {
|
||||||
initCommand,
|
initCommand,
|
||||||
importCommand,
|
importCommand,
|
||||||
exportCommand,
|
exportCommand,
|
||||||
|
importPreimagesCommand,
|
||||||
|
exportPreimagesCommand,
|
||||||
copydbCommand,
|
copydbCommand,
|
||||||
removedbCommand,
|
removedbCommand,
|
||||||
dumpCommand,
|
dumpCommand,
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ ADD genesis.json /genesis.json
|
||||||
RUN \
|
RUN \
|
||||||
echo 'node server.js &' > wallet.sh && \
|
echo 'node server.js &' > wallet.sh && \
|
||||||
echo 'geth --cache 512 init /genesis.json' >> wallet.sh && \
|
echo 'geth --cache 512 init /genesis.json' >> wallet.sh && \
|
||||||
echo $'geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*"' >> wallet.sh
|
echo $'geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*"' >> wallet.sh
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \
|
sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/EthereumCommonwealth/go-callisto/log"
|
"github.com/EthereumCommonwealth/go-callisto/log"
|
||||||
|
|
@ -34,7 +35,7 @@ func main() {
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "network",
|
Name: "network",
|
||||||
Usage: "name of the network to administer",
|
Usage: "name of the network to administer (no spaces or hyphens, please)",
|
||||||
},
|
},
|
||||||
cli.IntFlag{
|
cli.IntFlag{
|
||||||
Name: "loglevel",
|
Name: "loglevel",
|
||||||
|
|
@ -47,6 +48,10 @@ func main() {
|
||||||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
|
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
network := c.String("network")
|
||||||
|
if strings.Contains(network, " ") || strings.Contains(network, "-") {
|
||||||
|
log.Crit("No spaces or hyphens allowed in network name")
|
||||||
|
}
|
||||||
// Start the wizard and relinquish control
|
// Start the wizard and relinquish control
|
||||||
makeWizard(c.String("network")).run()
|
makeWizard(c.String("network")).run()
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/EthereumCommonwealth/go-callisto/common"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/core"
|
"github.com/EthereumCommonwealth/go-callisto/core"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/core/types"
|
"github.com/EthereumCommonwealth/go-callisto/core/types"
|
||||||
|
"github.com/EthereumCommonwealth/go-callisto/crypto"
|
||||||
|
"github.com/EthereumCommonwealth/go-callisto/ethdb"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/internal/debug"
|
"github.com/EthereumCommonwealth/go-callisto/internal/debug"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/log"
|
"github.com/EthereumCommonwealth/go-callisto/log"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/node"
|
"github.com/EthereumCommonwealth/go-callisto/node"
|
||||||
|
|
@ -105,6 +108,8 @@ func ImportChain(chain *core.BlockChain, fn string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Importing blockchain", "file", fn)
|
log.Info("Importing blockchain", "file", fn)
|
||||||
|
|
||||||
|
// Open the file handle and potentially unwrap the gzip stream
|
||||||
fh, err := os.Open(fn)
|
fh, err := os.Open(fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -180,8 +185,12 @@ func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExportChain exports a blockchain into the specified file, truncating any data
|
||||||
|
// already present in the file.
|
||||||
func ExportChain(blockchain *core.BlockChain, fn string) error {
|
func ExportChain(blockchain *core.BlockChain, fn string) error {
|
||||||
log.Info("Exporting blockchain", "file", fn)
|
log.Info("Exporting blockchain", "file", fn)
|
||||||
|
|
||||||
|
// Open the file handle and potentially wrap with a gzip stream
|
||||||
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -193,7 +202,7 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
|
||||||
writer = gzip.NewWriter(writer)
|
writer = gzip.NewWriter(writer)
|
||||||
defer writer.(*gzip.Writer).Close()
|
defer writer.(*gzip.Writer).Close()
|
||||||
}
|
}
|
||||||
|
// Iterate over the blocks and export them
|
||||||
if err := blockchain.Export(writer); err != nil {
|
if err := blockchain.Export(writer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -202,9 +211,12 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExportAppendChain exports a blockchain into the specified file, appending to
|
||||||
|
// the file if data already exists in it.
|
||||||
func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
|
func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
|
||||||
log.Info("Exporting blockchain", "file", fn)
|
log.Info("Exporting blockchain", "file", fn)
|
||||||
// TODO verify mode perms
|
|
||||||
|
// Open the file handle and potentially wrap with a gzip stream
|
||||||
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
|
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -216,10 +228,86 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
|
||||||
writer = gzip.NewWriter(writer)
|
writer = gzip.NewWriter(writer)
|
||||||
defer writer.(*gzip.Writer).Close()
|
defer writer.(*gzip.Writer).Close()
|
||||||
}
|
}
|
||||||
|
// Iterate over the blocks and export them
|
||||||
if err := blockchain.ExportN(writer, first, last); err != nil {
|
if err := blockchain.ExportN(writer, first, last); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Info("Exported blockchain to", "file", fn)
|
log.Info("Exported blockchain to", "file", fn)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImportPreimages imports a batch of exported hash preimages into the database.
|
||||||
|
func ImportPreimages(db *ethdb.LDBDatabase, fn string) error {
|
||||||
|
log.Info("Importing preimages", "file", fn)
|
||||||
|
|
||||||
|
// Open the file handle and potentially unwrap the gzip stream
|
||||||
|
fh, err := os.Open(fn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
var reader io.Reader = fh
|
||||||
|
if strings.HasSuffix(fn, ".gz") {
|
||||||
|
if reader, err = gzip.NewReader(reader); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream := rlp.NewStream(reader, 0)
|
||||||
|
|
||||||
|
// Import the preimages in batches to prevent disk trashing
|
||||||
|
preimages := make(map[common.Hash][]byte)
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Read the next entry and ensure it's not junk
|
||||||
|
var blob []byte
|
||||||
|
|
||||||
|
if err := stream.Decode(&blob); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Accumulate the preimages and flush when enough ws gathered
|
||||||
|
preimages[crypto.Keccak256Hash(blob)] = common.CopyBytes(blob)
|
||||||
|
if len(preimages) > 1024 {
|
||||||
|
if err := core.WritePreimages(db, 0, preimages); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
preimages = make(map[common.Hash][]byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Flush the last batch preimage data
|
||||||
|
if len(preimages) > 0 {
|
||||||
|
return core.WritePreimages(db, 0, preimages)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportPreimages exports all known hash preimages into the specified file,
|
||||||
|
// truncating any data already present in the file.
|
||||||
|
func ExportPreimages(db *ethdb.LDBDatabase, fn string) error {
|
||||||
|
log.Info("Exporting preimages", "file", fn)
|
||||||
|
|
||||||
|
// Open the file handle and potentially wrap with a gzip stream
|
||||||
|
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
var writer io.Writer = fh
|
||||||
|
if strings.HasSuffix(fn, ".gz") {
|
||||||
|
writer = gzip.NewWriter(writer)
|
||||||
|
defer writer.(*gzip.Writer).Close()
|
||||||
|
}
|
||||||
|
// Iterate over the preimages and export them
|
||||||
|
it := db.NewIteratorWithPrefix([]byte("secure-key-"))
|
||||||
|
for it.Next() {
|
||||||
|
if err := rlp.Encode(writer, it.Value()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Info("Exported preimages", "file", fn)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ import (
|
||||||
"github.com/EthereumCommonwealth/go-callisto/p2p/nat"
|
"github.com/EthereumCommonwealth/go-callisto/p2p/nat"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/p2p/netutil"
|
"github.com/EthereumCommonwealth/go-callisto/p2p/netutil"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/params"
|
"github.com/EthereumCommonwealth/go-callisto/params"
|
||||||
whisper "github.com/EthereumCommonwealth/go-callisto/whisper/whisperv5"
|
whisper "github.com/EthereumCommonwealth/go-callisto/whisper/whisperv6"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -209,11 +209,6 @@ var (
|
||||||
Usage: "Dashboard metrics collection refresh rate",
|
Usage: "Dashboard metrics collection refresh rate",
|
||||||
Value: dashboard.DefaultConfig.Refresh,
|
Value: dashboard.DefaultConfig.Refresh,
|
||||||
}
|
}
|
||||||
DashboardAssetsFlag = cli.StringFlag{
|
|
||||||
Name: "dashboard.assets",
|
|
||||||
Usage: "Developer flag to serve the dashboard from the local file system",
|
|
||||||
Value: dashboard.DefaultConfig.Assets,
|
|
||||||
}
|
|
||||||
// Ethash settings
|
// Ethash settings
|
||||||
EthashCacheDirFlag = DirectoryFlag{
|
EthashCacheDirFlag = DirectoryFlag{
|
||||||
Name: "ethash.cachedir",
|
Name: "ethash.cachedir",
|
||||||
|
|
@ -819,6 +814,9 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
||||||
|
|
||||||
if ctx.GlobalIsSet(MaxPeersFlag.Name) {
|
if ctx.GlobalIsSet(MaxPeersFlag.Name) {
|
||||||
cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
|
cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
|
||||||
|
if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) {
|
||||||
|
cfg.MaxPeers += lightPeers
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if lightServer {
|
if lightServer {
|
||||||
cfg.MaxPeers += lightPeers
|
cfg.MaxPeers += lightPeers
|
||||||
|
|
@ -1120,7 +1118,6 @@ func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
|
||||||
cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
|
cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
|
||||||
cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
|
cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
|
||||||
cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
|
cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
|
||||||
cfg.Assets = ctx.GlobalString(DashboardAssetsFlag.Name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterEthService adds an Ethereum client to the stack.
|
// RegisterEthService adds an Ethereum client to the stack.
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,8 @@ func initialize() {
|
||||||
if len(*argIP) == 0 {
|
if len(*argIP) == 0 {
|
||||||
argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ")
|
argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ")
|
||||||
}
|
}
|
||||||
|
} else if *fileReader {
|
||||||
|
*bootstrapMode = true
|
||||||
} else {
|
} else {
|
||||||
if len(*argEnode) == 0 {
|
if len(*argEnode) == 0 {
|
||||||
argEnode = scanLineA("Please enter the peer's enode: ")
|
argEnode = scanLineA("Please enter the peer's enode: ")
|
||||||
|
|
@ -205,11 +207,22 @@ func initialize() {
|
||||||
peers = append(peers, peer)
|
peers = append(peers, peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *mailServerMode {
|
||||||
|
if len(msPassword) == 0 {
|
||||||
|
msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read Mail Server password: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cfg := &whisper.Config{
|
cfg := &whisper.Config{
|
||||||
MaxMessageSize: uint32(*argMaxSize),
|
MaxMessageSize: uint32(*argMaxSize),
|
||||||
MinimumAcceptedPOW: *argPoW,
|
MinimumAcceptedPOW: *argPoW,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shh = whisper.New(cfg)
|
||||||
|
|
||||||
if *argPoW != whisper.DefaultMinimumPoW {
|
if *argPoW != whisper.DefaultMinimumPoW {
|
||||||
err := shh.SetMinimumPoW(*argPoW)
|
err := shh.SetMinimumPoW(*argPoW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -257,18 +270,8 @@ func initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *mailServerMode {
|
if *mailServerMode {
|
||||||
if len(msPassword) == 0 {
|
|
||||||
msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ")
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("Failed to read Mail Server password: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shh = whisper.New(cfg)
|
|
||||||
shh.RegisterServer(&mailServer)
|
shh.RegisterServer(&mailServer)
|
||||||
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW)
|
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW)
|
||||||
} else {
|
|
||||||
shh = whisper.New(cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
server = &p2p.Server{
|
server = &p2p.Server{
|
||||||
|
|
@ -306,7 +309,11 @@ func startServer() error {
|
||||||
configureNode()
|
configureNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !*forwarderMode {
|
if *fileExMode {
|
||||||
|
fmt.Printf("Please type the file name to be send. To quit type: '%s'\n", quitCommand)
|
||||||
|
} else if *fileReader {
|
||||||
|
fmt.Printf("Please type the file name to be decrypted. To quit type: '%s'\n", quitCommand)
|
||||||
|
} else if !*forwarderMode {
|
||||||
fmt.Printf("Please type the message. To quit type: '%s'\n", quitCommand)
|
fmt.Printf("Please type the message. To quit type: '%s'\n", quitCommand)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -566,6 +573,7 @@ func sendMsg(payload []byte) common.Hash {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("failed to create new message: %s", err)
|
utils.Fatalf("failed to create new message: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
envelope, err := msg.Wrap(¶ms)
|
envelope, err := msg.Wrap(¶ms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to seal message: %v \n", err)
|
fmt.Printf("failed to seal message: %v \n", err)
|
||||||
|
|
@ -601,15 +609,17 @@ func messageLoop() {
|
||||||
m2 := af.Retrieve()
|
m2 := af.Retrieve()
|
||||||
messages := append(m1, m2...)
|
messages := append(m1, m2...)
|
||||||
for _, msg := range messages {
|
for _, msg := range messages {
|
||||||
|
reportedOnce := false
|
||||||
|
if !*fileExMode && len(msg.Payload) <= 2048 {
|
||||||
|
printMessageInfo(msg)
|
||||||
|
reportedOnce = true
|
||||||
|
}
|
||||||
|
|
||||||
// All messages are saved upon specifying argSaveDir.
|
// All messages are saved upon specifying argSaveDir.
|
||||||
// fileExMode only specifies how messages are displayed on the console after they are saved.
|
// fileExMode only specifies how messages are displayed on the console after they are saved.
|
||||||
// if fileExMode == true, only the hashes are displayed, since messages might be too big.
|
// if fileExMode == true, only the hashes are displayed, since messages might be too big.
|
||||||
if len(*argSaveDir) > 0 {
|
if len(*argSaveDir) > 0 {
|
||||||
writeMessageToFile(*argSaveDir, msg)
|
writeMessageToFile(*argSaveDir, msg, !reportedOnce)
|
||||||
}
|
|
||||||
|
|
||||||
if !*fileExMode && len(msg.Payload) <= 2048 {
|
|
||||||
printMessageInfo(msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case <-done:
|
case <-done:
|
||||||
|
|
@ -634,7 +644,11 @@ func printMessageInfo(msg *whisper.ReceivedMessage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage, show bool) {
|
||||||
|
if len(dir) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
timestamp := fmt.Sprintf("%d", msg.Sent)
|
timestamp := fmt.Sprintf("%d", msg.Sent)
|
||||||
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
||||||
|
|
||||||
|
|
@ -643,22 +657,24 @@ func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
||||||
address = crypto.PubkeyToAddress(*msg.Src)
|
address = crypto.PubkeyToAddress(*msg.Src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env := shh.GetEnvelope(msg.EnvelopeHash)
|
||||||
|
if env == nil {
|
||||||
|
fmt.Printf("\nUnexpected error: envelope not found: %x\n", msg.EnvelopeHash)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// this is a sample code; uncomment if you don't want to save your own messages.
|
// this is a sample code; uncomment if you don't want to save your own messages.
|
||||||
//if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
//if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
||||||
// fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name)
|
// fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name)
|
||||||
// return
|
// return
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if len(dir) > 0 {
|
fullpath := filepath.Join(dir, name)
|
||||||
fullpath := filepath.Join(dir, name)
|
err := ioutil.WriteFile(fullpath, env.Data, 0644)
|
||||||
err := ioutil.WriteFile(fullpath, msg.Raw, 0644)
|
if err != nil {
|
||||||
if err != nil {
|
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
||||||
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
} else if show {
|
||||||
} else {
|
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(env.Data))
|
||||||
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(msg.Raw))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Printf("\n%s {%x}: message received (%d bytes), but not saved: %s\n", timestamp, address, len(msg.Raw), name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -682,18 +698,23 @@ func requestExpiredMessagesLoop() {
|
||||||
for {
|
for {
|
||||||
timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ")
|
timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ")
|
||||||
timeUpp = scanUint("Please enter the upper limit of the time range (unix timestamp): ")
|
timeUpp = scanUint("Please enter the upper limit of the time range (unix timestamp): ")
|
||||||
t = scanLine("Please enter the topic (hexadecimal): ")
|
t = scanLine("Enter the topic (hex). Press enter to request all messages, regardless of the topic: ")
|
||||||
if len(t) >= whisper.TopicLength*2 {
|
if len(t) == whisper.TopicLength*2 {
|
||||||
x, err := hex.DecodeString(t)
|
x, err := hex.DecodeString(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to parse the topic: %s", err)
|
fmt.Printf("Failed to parse the topic: %s \n", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
xt = whisper.BytesToTopic(x)
|
xt = whisper.BytesToTopic(x)
|
||||||
bloom = whisper.TopicToBloom(xt)
|
bloom = whisper.TopicToBloom(xt)
|
||||||
obfuscateBloom(bloom)
|
obfuscateBloom(bloom)
|
||||||
} else {
|
} else if len(t) == 0 {
|
||||||
bloom = whisper.MakeFullNodeBloom()
|
bloom = whisper.MakeFullNodeBloom()
|
||||||
|
} else {
|
||||||
|
fmt.Println("Error: topic is invalid, request aborted")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if timeUpp == 0 {
|
if timeUpp == 0 {
|
||||||
timeUpp = 0xFFFFFFFF
|
timeUpp = 0xFFFFFFFF
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ type solcOutput struct {
|
||||||
func (s *Solidity) makeArgs() []string {
|
func (s *Solidity) makeArgs() []string {
|
||||||
p := []string{
|
p := []string{
|
||||||
"--combined-json", "bin,abi,userdoc,devdoc",
|
"--combined-json", "bin,abi,userdoc,devdoc",
|
||||||
"--add-std", // include standard lib contracts
|
|
||||||
"--optimize", // code optimizer switched on
|
"--optimize", // code optimizer switched on
|
||||||
}
|
}
|
||||||
if s.Major > 0 || s.Minor > 4 || s.Patch > 6 {
|
if s.Major > 0 || s.Minor > 4 || s.Patch > 6 {
|
||||||
|
|
|
||||||
1
containers/vagrant/.gitignore
vendored
1
containers/vagrant/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
.vagrant
|
|
||||||
|
|
@ -114,7 +114,7 @@ func (c *Compiler) Compile() (string, []error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// next returns the next token and increments the
|
// next returns the next token and increments the
|
||||||
// posititon.
|
// position.
|
||||||
func (c *Compiler) next() token {
|
func (c *Compiler) next() token {
|
||||||
token := c.tokens[c.pos]
|
token := c.tokens[c.pos]
|
||||||
c.pos++
|
c.pos++
|
||||||
|
|
@ -122,7 +122,7 @@ func (c *Compiler) next() token {
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile line compiles a single line instruction e.g.
|
// compile line compiles a single line instruction e.g.
|
||||||
// "push 1", "jump @labal".
|
// "push 1", "jump @label".
|
||||||
func (c *Compiler) compileLine() error {
|
func (c *Compiler) compileLine() error {
|
||||||
n := c.next()
|
n := c.next()
|
||||||
if n.typ != lineStart {
|
if n.typ != lineStart {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ const (
|
||||||
lineEnd // emitted when a line ends
|
lineEnd // emitted when a line ends
|
||||||
invalidStatement // any invalid statement
|
invalidStatement // any invalid statement
|
||||||
element // any element during element parsing
|
element // any element during element parsing
|
||||||
label // label is emitted when a labal is found
|
label // label is emitted when a label is found
|
||||||
labelDef // label definition is emitted when a new label is found
|
labelDef // label definition is emitted when a new label is found
|
||||||
number // number is emitted when a number is found
|
number // number is emitted when a number is found
|
||||||
stringValue // stringValue is emitted when a string has been found
|
stringValue // stringValue is emitted when a string has been found
|
||||||
|
|
|
||||||
|
|
@ -723,10 +723,13 @@ func (bc *BlockChain) Rollback(chain []common.Hash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetReceiptsData computes all the non-consensus fields of the receipts
|
// SetReceiptsData computes all the non-consensus fields of the receipts
|
||||||
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) {
|
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) error {
|
||||||
signer := types.MakeSigner(config, block.Number())
|
signer := types.MakeSigner(config, block.Number())
|
||||||
|
|
||||||
transactions, logIndex := block.Transactions(), uint(0)
|
transactions, logIndex := block.Transactions(), uint(0)
|
||||||
|
if len(transactions) != len(receipts) {
|
||||||
|
return errors.New("transaction and receipt count mismatch")
|
||||||
|
}
|
||||||
|
|
||||||
for j := 0; j < len(receipts); j++ {
|
for j := 0; j < len(receipts); j++ {
|
||||||
// The transaction hash can be retrieved from the transaction itself
|
// The transaction hash can be retrieved from the transaction itself
|
||||||
|
|
@ -754,6 +757,7 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty
|
||||||
logIndex++
|
logIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertReceiptChain attempts to complete an already existing header chain with
|
// InsertReceiptChain attempts to complete an already existing header chain with
|
||||||
|
|
@ -794,7 +798,9 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Compute all the non-consensus fields of the receipts
|
// Compute all the non-consensus fields of the receipts
|
||||||
SetReceiptsData(bc.chainConfig, block, receipts)
|
if err := SetReceiptsData(bc.chainConfig, block, receipts); err != nil {
|
||||||
|
return i, fmt.Errorf("failed to set receipts data: %v", err)
|
||||||
|
}
|
||||||
// Write all the data out into the database
|
// Write all the data out into the database
|
||||||
if err := WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
if err := WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
||||||
return i, fmt.Errorf("failed to write block body: %v", err)
|
return i, fmt.Errorf("failed to write block body: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -82,11 +82,23 @@ func (b *BlockGen) SetExtra(data []byte) {
|
||||||
// added. Notably, contract code relying on the BLOCKHASH instruction
|
// added. Notably, contract code relying on the BLOCKHASH instruction
|
||||||
// will panic during execution.
|
// will panic during execution.
|
||||||
func (b *BlockGen) AddTx(tx *types.Transaction) {
|
func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||||
|
b.AddTxWithChain(nil, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTxWithChain adds a transaction to the generated block. If no coinbase has
|
||||||
|
// been set, the block's coinbase is set to the zero address.
|
||||||
|
//
|
||||||
|
// AddTxWithChain panics if the transaction cannot be executed. In addition to
|
||||||
|
// the protocol-imposed limitations (gas limit, etc.), there are some
|
||||||
|
// further limitations on the content of transactions that can be
|
||||||
|
// added. If contract code relies on the BLOCKHASH instruction,
|
||||||
|
// the block in chain will be returned.
|
||||||
|
func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
|
||||||
if b.gasPool == nil {
|
if b.gasPool == nil {
|
||||||
b.SetCoinbase(common.Address{})
|
b.SetCoinbase(common.Address{})
|
||||||
}
|
}
|
||||||
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
|
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
|
||||||
receipt, _, err := ApplyTransaction(b.config, nil, &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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
core/evm.go
21
core/evm.go
|
|
@ -60,13 +60,26 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
|
||||||
|
|
||||||
// GetHashFn returns a GetHashFunc which retrieves header hashes by number
|
// GetHashFn returns a GetHashFunc which retrieves header hashes by number
|
||||||
func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash {
|
func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash {
|
||||||
|
var cache map[uint64]common.Hash
|
||||||
|
|
||||||
return func(n uint64) common.Hash {
|
return func(n uint64) common.Hash {
|
||||||
for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
|
// If there's no hash cache yet, make one
|
||||||
if header.Number.Uint64() == n {
|
if cache == nil {
|
||||||
return header.Hash()
|
cache = map[uint64]common.Hash{
|
||||||
|
ref.Number.Uint64() - 1: ref.ParentHash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Try to fulfill the request from the cache
|
||||||
|
if hash, ok := cache[n]; ok {
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
// Not cached, iterate the blocks and cache the hashes
|
||||||
|
for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
|
||||||
|
cache[header.Number.Uint64()-1] = header.ParentHash
|
||||||
|
if n == header.Number.Uint64()-1 {
|
||||||
|
return header.ParentHash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
mrand "math/rand"
|
mrand "math/rand"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/EthereumCommonwealth/go-callisto/common"
|
"github.com/EthereumCommonwealth/go-callisto/common"
|
||||||
|
|
@ -32,7 +33,6 @@ import (
|
||||||
"github.com/EthereumCommonwealth/go-callisto/log"
|
"github.com/EthereumCommonwealth/go-callisto/log"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/params"
|
"github.com/EthereumCommonwealth/go-callisto/params"
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
"sync/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ type StateDB struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new state from a given trie
|
// Create a new state from a given trie.
|
||||||
func New(root common.Hash, db Database) (*StateDB, error) {
|
func New(root common.Hash, db Database) (*StateDB, error) {
|
||||||
tr, err := db.OpenTrie(root)
|
tr, err := db.OpenTrie(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -110,7 +110,7 @@ func (self *StateDB) Error() error {
|
||||||
return self.dbErr
|
return self.dbErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset clears out all emphemeral state objects from the state db, but keeps
|
// Reset clears out all ephemeral state objects from the state db, but keeps
|
||||||
// the underlying state trie to avoid reloading data for the next operations.
|
// the underlying state trie to avoid reloading data for the next operations.
|
||||||
func (self *StateDB) Reset(root common.Hash) error {
|
func (self *StateDB) Reset(root common.Hash) error {
|
||||||
tr, err := self.db.OpenTrie(root)
|
tr, err := self.db.OpenTrie(root)
|
||||||
|
|
@ -235,10 +235,10 @@ func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
||||||
return common.BytesToHash(stateObject.CodeHash())
|
return common.BytesToHash(stateObject.CodeHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
|
func (self *StateDB) GetState(addr common.Address, bhash common.Hash) common.Hash {
|
||||||
stateObject := self.getStateObject(a)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.GetState(self.db, b)
|
return stateObject.GetState(self.db, bhash)
|
||||||
}
|
}
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
|
|
@ -250,8 +250,8 @@ func (self *StateDB) Database() Database {
|
||||||
|
|
||||||
// StorageTrie returns the storage trie of an account.
|
// StorageTrie returns the storage trie of an account.
|
||||||
// The return value is a copy and is nil for non-existent accounts.
|
// The return value is a copy and is nil for non-existent accounts.
|
||||||
func (self *StateDB) StorageTrie(a common.Address) Trie {
|
func (self *StateDB) StorageTrie(addr common.Address) Trie {
|
||||||
stateObject := self.getStateObject(a)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +271,7 @@ func (self *StateDB) HasSuicided(addr common.Address) bool {
|
||||||
* SETTERS
|
* SETTERS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// AddBalance adds amount to the account associated with addr
|
// AddBalance adds amount to the account associated with addr.
|
||||||
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := self.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
|
|
@ -279,7 +279,7 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubBalance subtracts amount from the account associated with addr
|
// SubBalance subtracts amount from the account associated with addr.
|
||||||
func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) {
|
func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := self.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
|
|
@ -308,7 +308,7 @@ func (self *StateDB) SetCode(addr common.Address, code []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) {
|
func (self *StateDB) SetState(addr common.Address, key, value common.Hash) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := self.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SetState(self.db, key, value)
|
stateObject.SetState(self.db, key, value)
|
||||||
|
|
@ -337,7 +337,7 @@ func (self *StateDB) Suicide(addr common.Address) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Setting, updating & deleting state object methods
|
// Setting, updating & deleting state object methods.
|
||||||
//
|
//
|
||||||
|
|
||||||
// updateStateObject writes the given object to the trie.
|
// updateStateObject writes the given object to the trie.
|
||||||
|
|
@ -388,7 +388,7 @@ func (self *StateDB) setStateObject(object *stateObject) {
|
||||||
self.stateObjects[object.Address()] = object
|
self.stateObjects[object.Address()] = object
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a state object or create a new state object if nil
|
// Retrieve a state object or create a new state object if nil.
|
||||||
func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
|
func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject == nil || stateObject.deleted {
|
if stateObject == nil || stateObject.deleted {
|
||||||
|
|
|
||||||
|
|
@ -877,15 +877,14 @@ func (pool *TxPool) removeTx(hash common.Hash) {
|
||||||
// Remove the transaction from the pending lists and reset the account nonce
|
// Remove the transaction from the pending lists and reset the account nonce
|
||||||
if pending := pool.pending[addr]; pending != nil {
|
if pending := pool.pending[addr]; pending != nil {
|
||||||
if removed, invalids := pending.Remove(tx); removed {
|
if removed, invalids := pending.Remove(tx); removed {
|
||||||
// If no more transactions are left, remove the list
|
// If no more pending transactions are left, remove the list
|
||||||
if pending.Empty() {
|
if pending.Empty() {
|
||||||
delete(pool.pending, addr)
|
delete(pool.pending, addr)
|
||||||
delete(pool.beats, addr)
|
delete(pool.beats, addr)
|
||||||
} else {
|
}
|
||||||
// Otherwise postpone any invalidated transactions
|
// Postpone any invalidated transactions
|
||||||
for _, tx := range invalids {
|
for _, tx := range invalids {
|
||||||
pool.enqueueTx(tx.Hash(), tx)
|
pool.enqueueTx(tx.Hash(), tx)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Update the account nonce if needed
|
// Update the account nonce if needed
|
||||||
if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce {
|
if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce {
|
||||||
|
|
|
||||||
|
|
@ -557,74 +557,112 @@ func TestTransactionDropping(t *testing.T) {
|
||||||
func TestTransactionPostponing(t *testing.T) {
|
func TestTransactionPostponing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create a test account and fund it
|
// Create the pool to test the postponing with
|
||||||
pool, key := setupTxPool()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
|
||||||
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
|
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account, _ := deriveSender(transaction(0, 0, key))
|
// Create two test accounts to produce different gap profiles with
|
||||||
pool.currentState.AddBalance(account, big.NewInt(1000))
|
keys := make([]*ecdsa.PrivateKey, 2)
|
||||||
|
accs := make([]common.Address, len(keys))
|
||||||
|
|
||||||
|
for i := 0; i < len(keys); i++ {
|
||||||
|
keys[i], _ = crypto.GenerateKey()
|
||||||
|
accs[i] = crypto.PubkeyToAddress(keys[i].PublicKey)
|
||||||
|
|
||||||
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100))
|
||||||
|
}
|
||||||
// Add a batch consecutive pending transactions for validation
|
// Add a batch consecutive pending transactions for validation
|
||||||
txns := []*types.Transaction{}
|
txs := []*types.Transaction{}
|
||||||
for i := 0; i < 100; i++ {
|
for i, key := range keys {
|
||||||
var tx *types.Transaction
|
|
||||||
if i%2 == 0 {
|
for j := 0; j < 100; j++ {
|
||||||
tx = transaction(uint64(i), 100, key)
|
var tx *types.Transaction
|
||||||
} else {
|
if (i+j)%2 == 0 {
|
||||||
tx = transaction(uint64(i), 500, key)
|
tx = transaction(uint64(j), 25000, key)
|
||||||
|
} else {
|
||||||
|
tx = transaction(uint64(j), 50000, key)
|
||||||
|
}
|
||||||
|
txs = append(txs, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, err := range pool.AddRemotes(txs) {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("tx %d: failed to add transactions: %v", i, err)
|
||||||
}
|
}
|
||||||
pool.promoteTx(account, tx.Hash(), tx)
|
|
||||||
txns = append(txns, tx)
|
|
||||||
}
|
}
|
||||||
// Check that pre and post validations leave the pool as is
|
// Check that pre and post validations leave the pool as is
|
||||||
if pool.pending[account].Len() != len(txns) {
|
if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) {
|
||||||
t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns))
|
t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs))
|
||||||
}
|
}
|
||||||
if len(pool.queue) != 0 {
|
if len(pool.queue) != 0 {
|
||||||
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0)
|
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
||||||
}
|
}
|
||||||
if len(pool.all) != len(txns) {
|
if len(pool.all) != len(txs) {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns))
|
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs))
|
||||||
}
|
}
|
||||||
pool.lockedReset(nil, nil)
|
pool.lockedReset(nil, nil)
|
||||||
if pool.pending[account].Len() != len(txns) {
|
if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) {
|
||||||
t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns))
|
t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs))
|
||||||
}
|
}
|
||||||
if len(pool.queue) != 0 {
|
if len(pool.queue) != 0 {
|
||||||
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0)
|
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
||||||
}
|
}
|
||||||
if len(pool.all) != len(txns) {
|
if len(pool.all) != len(txs) {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns))
|
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs))
|
||||||
}
|
}
|
||||||
// Reduce the balance of the account, and check that transactions are reorganised
|
// Reduce the balance of the account, and check that transactions are reorganised
|
||||||
pool.currentState.AddBalance(account, big.NewInt(-750))
|
for _, addr := range accs {
|
||||||
|
pool.currentState.AddBalance(addr, big.NewInt(-1))
|
||||||
|
}
|
||||||
pool.lockedReset(nil, nil)
|
pool.lockedReset(nil, nil)
|
||||||
|
|
||||||
if _, ok := pool.pending[account].txs.items[txns[0].Nonce()]; !ok {
|
// The first account's first transaction remains valid, check that subsequent
|
||||||
t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txns[0])
|
// ones are either filtered out, or queued up for later.
|
||||||
|
if _, ok := pool.pending[accs[0]].txs.items[txs[0].Nonce()]; !ok {
|
||||||
|
t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txs[0])
|
||||||
}
|
}
|
||||||
if _, ok := pool.queue[account].txs.items[txns[0].Nonce()]; ok {
|
if _, ok := pool.queue[accs[0]].txs.items[txs[0].Nonce()]; ok {
|
||||||
t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txns[0])
|
t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txs[0])
|
||||||
}
|
}
|
||||||
for i, tx := range txns[1:] {
|
for i, tx := range txs[1:100] {
|
||||||
if i%2 == 1 {
|
if i%2 == 1 {
|
||||||
if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok {
|
if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok {
|
||||||
t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx)
|
t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx)
|
||||||
}
|
}
|
||||||
if _, ok := pool.queue[account].txs.items[tx.Nonce()]; !ok {
|
if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; !ok {
|
||||||
t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx)
|
t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok {
|
if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok {
|
||||||
t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx)
|
t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx)
|
||||||
}
|
}
|
||||||
if _, ok := pool.queue[account].txs.items[tx.Nonce()]; ok {
|
if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; ok {
|
||||||
t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx)
|
t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(pool.all) != len(txns)/2 {
|
// The second account's first transaction got invalid, check that all transactions
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)/2)
|
// are either filtered out, or queued up for later.
|
||||||
|
if pool.pending[accs[1]] != nil {
|
||||||
|
t.Errorf("invalidated account still has pending transactions")
|
||||||
|
}
|
||||||
|
for i, tx := range txs[100:] {
|
||||||
|
if i%2 == 1 {
|
||||||
|
if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; !ok {
|
||||||
|
t.Errorf("tx %d: valid but future transaction missing from future queue: %v", 100+i, tx)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; ok {
|
||||||
|
t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", 100+i, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(pool.all) != len(txs)/2 {
|
||||||
|
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)/2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -949,11 +987,11 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
|
||||||
account2, _ := deriveSender(transaction(0, 0, key2))
|
account2, _ := deriveSender(transaction(0, 0, key2))
|
||||||
pool2.currentState.AddBalance(account2, big.NewInt(1000000))
|
pool2.currentState.AddBalance(account2, big.NewInt(1000000))
|
||||||
|
|
||||||
txns := []*types.Transaction{}
|
txs := []*types.Transaction{}
|
||||||
for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ {
|
for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ {
|
||||||
txns = append(txns, transaction(origin+i, 100000, key2))
|
txs = append(txs, transaction(origin+i, 100000, key2))
|
||||||
}
|
}
|
||||||
pool2.AddRemotes(txns)
|
pool2.AddRemotes(txs)
|
||||||
|
|
||||||
// Ensure the batch optimization honors the same pool mechanics
|
// Ensure the batch optimization honors the same pool mechanics
|
||||||
if len(pool1.pending) != len(pool2.pending) {
|
if len(pool1.pending) != len(pool2.pending) {
|
||||||
|
|
@ -1124,7 +1162,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
defer sub.Unsubscribe()
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
// Create a number of test accounts and fund them
|
// Create a number of test accounts and fund them
|
||||||
keys := make([]*ecdsa.PrivateKey, 3)
|
keys := make([]*ecdsa.PrivateKey, 4)
|
||||||
for i := 0; i < len(keys); i++ {
|
for i := 0; i < len(keys); i++ {
|
||||||
keys[i], _ = crypto.GenerateKey()
|
keys[i], _ = crypto.GenerateKey()
|
||||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||||
|
|
@ -1136,24 +1174,28 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0]))
|
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0]))
|
||||||
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0]))
|
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0]))
|
||||||
|
|
||||||
|
txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[1]))
|
||||||
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[1]))
|
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[1]))
|
||||||
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[1]))
|
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[1]))
|
||||||
txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[1]))
|
|
||||||
|
|
||||||
ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[2])
|
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[2]))
|
||||||
|
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2]))
|
||||||
|
txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[2]))
|
||||||
|
|
||||||
|
ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[3])
|
||||||
|
|
||||||
// Import the batch and that both pending and queued transactions match up
|
// Import the batch and that both pending and queued transactions match up
|
||||||
pool.AddRemotes(txs)
|
pool.AddRemotes(txs)
|
||||||
pool.AddLocal(ltx)
|
pool.AddLocal(ltx)
|
||||||
|
|
||||||
pending, queued := pool.Stats()
|
pending, queued := pool.Stats()
|
||||||
if pending != 4 {
|
if pending != 7 {
|
||||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4)
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7)
|
||||||
}
|
}
|
||||||
if queued != 3 {
|
if queued != 3 {
|
||||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 4); err != nil {
|
if err := validateEvents(events, 7); err != nil {
|
||||||
t.Fatalf("original event firing failed: %v", err)
|
t.Fatalf("original event firing failed: %v", err)
|
||||||
}
|
}
|
||||||
if err := validateTxPoolInternals(pool); err != nil {
|
if err := validateTxPoolInternals(pool); err != nil {
|
||||||
|
|
@ -1166,8 +1208,8 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
if pending != 2 {
|
if pending != 2 {
|
||||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||||
}
|
}
|
||||||
if queued != 3 {
|
if queued != 5 {
|
||||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 0); err != nil {
|
if err := validateEvents(events, 0); err != nil {
|
||||||
t.Fatalf("reprice event firing failed: %v", err)
|
t.Fatalf("reprice event firing failed: %v", err)
|
||||||
|
|
@ -1179,7 +1221,10 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); err != ErrUnderpriced {
|
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); err != ErrUnderpriced {
|
||||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||||
}
|
}
|
||||||
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced {
|
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced {
|
||||||
|
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||||
|
}
|
||||||
|
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); err != ErrUnderpriced {
|
||||||
t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 0); err != nil {
|
if err := validateEvents(events, 0); err != nil {
|
||||||
|
|
@ -1189,7 +1234,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
t.Fatalf("pool internal state corrupted: %v", err)
|
t.Fatalf("pool internal state corrupted: %v", err)
|
||||||
}
|
}
|
||||||
// However we can add local underpriced transactions
|
// However we can add local underpriced transactions
|
||||||
tx := pricedTransaction(1, 100000, big.NewInt(1), keys[2])
|
tx := pricedTransaction(1, 100000, big.NewInt(1), keys[3])
|
||||||
if err := pool.AddLocal(tx); err != nil {
|
if err := pool.AddLocal(tx); err != nil {
|
||||||
t.Fatalf("failed to add underpriced local transaction: %v", err)
|
t.Fatalf("failed to add underpriced local transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1202,6 +1247,22 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
if err := validateTxPoolInternals(pool); err != nil {
|
if err := validateTxPoolInternals(pool); err != nil {
|
||||||
t.Fatalf("pool internal state corrupted: %v", err)
|
t.Fatalf("pool internal state corrupted: %v", err)
|
||||||
}
|
}
|
||||||
|
// And we can fill gaps with properly priced transactions
|
||||||
|
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil {
|
||||||
|
t.Fatalf("failed to add pending transaction: %v", err)
|
||||||
|
}
|
||||||
|
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(2), keys[1])); err != nil {
|
||||||
|
t.Fatalf("failed to add pending transaction: %v", err)
|
||||||
|
}
|
||||||
|
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(2), keys[2])); err != nil {
|
||||||
|
t.Fatalf("failed to add queued transaction: %v", err)
|
||||||
|
}
|
||||||
|
if err := validateEvents(events, 5); err != nil {
|
||||||
|
t.Fatalf("post-reprice event firing failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := validateTxPoolInternals(pool); err != nil {
|
||||||
|
t.Fatalf("pool internal state corrupted: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that setting the transaction pool gas price to a higher value does not
|
// Tests that setting the transaction pool gas price to a higher value does not
|
||||||
|
|
|
||||||
|
|
@ -17,19 +17,8 @@
|
||||||
/*
|
/*
|
||||||
Package vm implements the Ethereum Virtual Machine.
|
Package vm implements the Ethereum Virtual Machine.
|
||||||
|
|
||||||
The vm package implements two EVMs, a byte code VM and a JIT VM. The BC
|
The vm package implements one EVM, a byte code VM. The BC (Byte Code) VM loops
|
||||||
(Byte Code) VM loops over a set of bytes and executes them according to the set
|
over a set of bytes and executes them according to the set of rules defined
|
||||||
of rules defined in the Ethereum yellow paper. When the BC VM is invoked it
|
in the Ethereum yellow paper.
|
||||||
invokes the JIT VM in a separate goroutine and compiles the byte code in JIT
|
|
||||||
instructions.
|
|
||||||
|
|
||||||
The JIT VM, when invoked, loops around a set of pre-defined instructions until
|
|
||||||
it either runs of gas, causes an internal error, returns or stops.
|
|
||||||
|
|
||||||
The JIT optimiser attempts to pre-compile instructions in to chunks or segments
|
|
||||||
such as multiple PUSH operations and static JUMPs. It does this by analysing the
|
|
||||||
opcodes and attempts to match certain regions to known sets. Whenever the
|
|
||||||
optimiser finds said segments it creates a new instruction and replaces the
|
|
||||||
first occurrence in the sequence.
|
|
||||||
*/
|
*/
|
||||||
package vm
|
package vm
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ type EVM struct {
|
||||||
callGasTemp uint64
|
callGasTemp uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEVM retutrns a new EVM . The returned EVM is not thread safe and should
|
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
|
||||||
// only ever be used *once*.
|
// only ever be used *once*.
|
||||||
func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
|
func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
|
||||||
evm := &EVM{
|
evm := &EVM{
|
||||||
|
|
@ -221,7 +221,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||||
to = AccountRef(caller.Address())
|
to = AccountRef(caller.Address())
|
||||||
)
|
)
|
||||||
// initialise a new contract and set the code that is to be used by the
|
// initialise a new contract and set the code that is to be used by the
|
||||||
// E The contract is a scoped evmironment for this execution context
|
// EVM. The contract is a scoped environment for this execution context
|
||||||
// only.
|
// only.
|
||||||
contract := NewContract(caller, to, value, gas)
|
contract := NewContract(caller, to, value, gas)
|
||||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
|
|
@ -341,7 +341,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||||
evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)
|
evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)
|
||||||
|
|
||||||
// initialise a new contract and set the code that is to be used by the
|
// initialise a new contract and set the code that is to be used by the
|
||||||
// E The contract is a scoped evmironment for this execution context
|
// EVM. The contract is a scoped environment for this execution context
|
||||||
// only.
|
// only.
|
||||||
contract := NewContract(caller, AccountRef(contractAddr), value, gas)
|
contract := NewContract(caller, AccountRef(contractAddr), value, gas)
|
||||||
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
|
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bigZero = new(big.Int)
|
bigZero = new(big.Int)
|
||||||
|
tt255 = math.BigPow(2, 255)
|
||||||
|
tt256 = math.BigPow(2, 256)
|
||||||
errWriteProtection = errors.New("evm: write protection")
|
errWriteProtection = errors.New("evm: write protection")
|
||||||
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
||||||
errExecutionReverted = errors.New("evm: execution reverted")
|
errExecutionReverted = errors.New("evm: execution reverted")
|
||||||
|
|
@ -37,20 +39,18 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
stack.push(math.U256(x.Add(x, y)))
|
math.U256(y.Add(x, y))
|
||||||
|
|
||||||
evm.interpreter.intPool.put(y)
|
|
||||||
|
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
stack.push(math.U256(x.Sub(x, y)))
|
math.U256(y.Sub(x, y))
|
||||||
|
|
||||||
evm.interpreter.intPool.put(y)
|
|
||||||
|
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,44 +64,39 @@ func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
if y.Sign() != 0 {
|
if y.Sign() != 0 {
|
||||||
stack.push(math.U256(x.Div(x, y)))
|
math.U256(y.Div(x, y))
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
y.SetUint64(0)
|
||||||
}
|
}
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
evm.interpreter.intPool.put(y)
|
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
||||||
if y.Sign() == 0 {
|
res := evm.interpreter.intPool.getZero()
|
||||||
stack.push(new(big.Int))
|
|
||||||
return nil, nil
|
if y.Sign() == 0 || x.Sign() == 0 {
|
||||||
|
stack.push(res)
|
||||||
} else {
|
} else {
|
||||||
n := new(big.Int)
|
if x.Sign() != y.Sign() {
|
||||||
if evm.interpreter.intPool.get().Mul(x, y).Sign() < 0 {
|
res.Div(x.Abs(x), y.Abs(y))
|
||||||
n.SetInt64(-1)
|
res.Neg(res)
|
||||||
} else {
|
} else {
|
||||||
n.SetInt64(1)
|
res.Div(x.Abs(x), y.Abs(y))
|
||||||
}
|
}
|
||||||
|
|
||||||
res := x.Div(x.Abs(x), y.Abs(y))
|
|
||||||
res.Mul(res, n)
|
|
||||||
|
|
||||||
stack.push(math.U256(res))
|
stack.push(math.U256(res))
|
||||||
}
|
}
|
||||||
evm.interpreter.intPool.put(y)
|
evm.interpreter.intPool.put(x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
if y.Sign() == 0 {
|
if y.Sign() == 0 {
|
||||||
stack.push(new(big.Int))
|
stack.push(x.SetUint64(0))
|
||||||
} else {
|
} else {
|
||||||
stack.push(math.U256(x.Mod(x, y)))
|
stack.push(math.U256(x.Mod(x, y)))
|
||||||
}
|
}
|
||||||
|
|
@ -111,23 +106,20 @@ func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
||||||
|
|
||||||
func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
||||||
|
res := evm.interpreter.intPool.getZero()
|
||||||
|
|
||||||
if y.Sign() == 0 {
|
if y.Sign() == 0 {
|
||||||
stack.push(new(big.Int))
|
stack.push(res)
|
||||||
} else {
|
} else {
|
||||||
n := new(big.Int)
|
|
||||||
if x.Sign() < 0 {
|
if x.Sign() < 0 {
|
||||||
n.SetInt64(-1)
|
res.Mod(x.Abs(x), y.Abs(y))
|
||||||
|
res.Neg(res)
|
||||||
} else {
|
} else {
|
||||||
n.SetInt64(1)
|
res.Mod(x.Abs(x), y.Abs(y))
|
||||||
}
|
}
|
||||||
|
|
||||||
res := x.Mod(x.Abs(x), y.Abs(y))
|
|
||||||
res.Mul(res, n)
|
|
||||||
|
|
||||||
stack.push(math.U256(res))
|
stack.push(math.U256(res))
|
||||||
}
|
}
|
||||||
evm.interpreter.intPool.put(y)
|
evm.interpreter.intPool.put(x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,80 +153,99 @@ func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
|
||||||
}
|
}
|
||||||
|
|
||||||
func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x := stack.pop()
|
x := stack.peek()
|
||||||
stack.push(math.U256(x.Not(x)))
|
math.U256(x.Not(x))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(y) < 0 {
|
if x.Cmp(y) < 0 {
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
y.SetUint64(1)
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
y.SetUint64(0)
|
||||||
}
|
}
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
evm.interpreter.intPool.put(x, y)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(y) > 0 {
|
if x.Cmp(y) > 0 {
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
y.SetUint64(1)
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
y.SetUint64(0)
|
||||||
}
|
}
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
evm.interpreter.intPool.put(x, y)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(math.S256(y)) < 0 {
|
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
|
||||||
} else {
|
|
||||||
stack.push(new(big.Int))
|
|
||||||
}
|
|
||||||
|
|
||||||
evm.interpreter.intPool.put(x, y)
|
xSign := x.Cmp(tt255)
|
||||||
|
ySign := y.Cmp(tt255)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case xSign >= 0 && ySign < 0:
|
||||||
|
y.SetUint64(1)
|
||||||
|
|
||||||
|
case xSign < 0 && ySign >= 0:
|
||||||
|
y.SetUint64(0)
|
||||||
|
|
||||||
|
default:
|
||||||
|
if x.Cmp(y) < 0 {
|
||||||
|
y.SetUint64(1)
|
||||||
|
} else {
|
||||||
|
y.SetUint64(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(y) > 0 {
|
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
|
||||||
} else {
|
|
||||||
stack.push(new(big.Int))
|
|
||||||
}
|
|
||||||
|
|
||||||
evm.interpreter.intPool.put(x, y)
|
xSign := x.Cmp(tt255)
|
||||||
|
ySign := y.Cmp(tt255)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case xSign >= 0 && ySign < 0:
|
||||||
|
y.SetUint64(0)
|
||||||
|
|
||||||
|
case xSign < 0 && ySign >= 0:
|
||||||
|
y.SetUint64(1)
|
||||||
|
|
||||||
|
default:
|
||||||
|
if x.Cmp(y) > 0 {
|
||||||
|
y.SetUint64(1)
|
||||||
|
} else {
|
||||||
|
y.SetUint64(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(y) == 0 {
|
if x.Cmp(y) == 0 {
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
y.SetUint64(1)
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
y.SetUint64(0)
|
||||||
}
|
}
|
||||||
|
evm.interpreter.intPool.put(x)
|
||||||
evm.interpreter.intPool.put(x, y)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x := stack.pop()
|
x := stack.peek()
|
||||||
if x.Sign() > 0 {
|
if x.Sign() > 0 {
|
||||||
stack.push(new(big.Int))
|
x.SetUint64(0)
|
||||||
} else {
|
} else {
|
||||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
x.SetUint64(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
evm.interpreter.intPool.put(x)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,18 +258,18 @@ func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
||||||
}
|
}
|
||||||
|
|
||||||
func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
stack.push(x.Or(x, y))
|
y.Or(x, y)
|
||||||
|
|
||||||
evm.interpreter.intPool.put(y)
|
evm.interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
stack.push(x.Xor(x, y))
|
y.Xor(x, y)
|
||||||
|
|
||||||
evm.interpreter.intPool.put(y)
|
evm.interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -277,13 +288,12 @@ func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
||||||
func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||||
if z.Cmp(bigZero) > 0 {
|
if z.Cmp(bigZero) > 0 {
|
||||||
add := x.Add(x, y)
|
x.Add(x, y)
|
||||||
add.Mod(add, z)
|
x.Mod(x, z)
|
||||||
stack.push(math.U256(add))
|
stack.push(math.U256(x))
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(x.SetUint64(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
evm.interpreter.intPool.put(y, z)
|
evm.interpreter.intPool.put(y, z)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -291,13 +301,12 @@ func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
||||||
func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||||
if z.Cmp(bigZero) > 0 {
|
if z.Cmp(bigZero) > 0 {
|
||||||
mul := x.Mul(x, y)
|
x.Mul(x, y)
|
||||||
mul.Mod(mul, z)
|
x.Mod(x, z)
|
||||||
stack.push(math.U256(mul))
|
stack.push(math.U256(x))
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(x.SetUint64(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
evm.interpreter.intPool.put(y, z)
|
evm.interpreter.intPool.put(y, z)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -370,8 +379,7 @@ func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
||||||
if evm.vmConfig.EnablePreimageRecording {
|
if evm.vmConfig.EnablePreimageRecording {
|
||||||
evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
|
evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
|
||||||
}
|
}
|
||||||
|
stack.push(evm.interpreter.intPool.get().SetBytes(hash))
|
||||||
stack.push(new(big.Int).SetBytes(hash))
|
|
||||||
|
|
||||||
evm.interpreter.intPool.put(offset, size)
|
evm.interpreter.intPool.put(offset, size)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -383,10 +391,8 @@ func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
|
||||||
}
|
}
|
||||||
|
|
||||||
func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
addr := common.BigToAddress(stack.pop())
|
slot := stack.peek()
|
||||||
balance := evm.StateDB.GetBalance(addr)
|
slot.Set(evm.StateDB.GetBalance(common.BigToAddress(slot)))
|
||||||
|
|
||||||
stack.push(new(big.Int).Set(balance))
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,7 +412,7 @@ func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(new(big.Int).SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
|
stack.push(evm.interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -437,10 +443,11 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory,
|
||||||
memOffset = stack.pop()
|
memOffset = stack.pop()
|
||||||
dataOffset = stack.pop()
|
dataOffset = stack.pop()
|
||||||
length = stack.pop()
|
length = stack.pop()
|
||||||
)
|
|
||||||
defer evm.interpreter.intPool.put(memOffset, dataOffset, length)
|
|
||||||
|
|
||||||
end := new(big.Int).Add(dataOffset, length)
|
end = evm.interpreter.intPool.get().Add(dataOffset, length)
|
||||||
|
)
|
||||||
|
defer evm.interpreter.intPool.put(memOffset, dataOffset, length, end)
|
||||||
|
|
||||||
if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() {
|
if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() {
|
||||||
return nil, errReturnDataOutOfBounds
|
return nil, errReturnDataOutOfBounds
|
||||||
}
|
}
|
||||||
|
|
@ -450,11 +457,8 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
a := stack.pop()
|
slot := stack.peek()
|
||||||
|
slot.SetUint64(uint64(evm.StateDB.GetCodeSize(common.BigToAddress(slot))))
|
||||||
addr := common.BigToAddress(a)
|
|
||||||
a.SetInt64(int64(evm.StateDB.GetCodeSize(addr)))
|
|
||||||
stack.push(a)
|
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -462,6 +466,7 @@ func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, sta
|
||||||
func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
|
l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
|
||||||
stack.push(l)
|
stack.push(l)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -504,9 +509,8 @@ func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
||||||
if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 {
|
if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 {
|
||||||
stack.push(evm.GetHash(num.Uint64()).Big())
|
stack.push(evm.GetHash(num.Uint64()).Big())
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(evm.interpreter.intPool.getZero())
|
||||||
}
|
}
|
||||||
|
|
||||||
evm.interpreter.intPool.put(num, n)
|
evm.interpreter.intPool.put(num, n)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -517,22 +521,22 @@ func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
||||||
}
|
}
|
||||||
|
|
||||||
func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(math.U256(new(big.Int).Set(evm.Time)))
|
stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.Time)))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(math.U256(new(big.Int).Set(evm.BlockNumber)))
|
stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.BlockNumber)))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(math.U256(new(big.Int).Set(evm.Difficulty)))
|
stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.Difficulty)))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(math.U256(new(big.Int).SetUint64(evm.GasLimit)))
|
stack.push(math.U256(evm.interpreter.intPool.get().SetUint64(evm.GasLimit)))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -543,7 +547,7 @@ func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
||||||
|
|
||||||
func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
offset := stack.pop()
|
offset := stack.pop()
|
||||||
val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32))
|
val := evm.interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32))
|
||||||
stack.push(val)
|
stack.push(val)
|
||||||
|
|
||||||
evm.interpreter.intPool.put(offset)
|
evm.interpreter.intPool.put(offset)
|
||||||
|
|
@ -647,9 +651,9 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
// ignore this error and pretend the operation was successful.
|
// ignore this error and pretend the operation was successful.
|
||||||
if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
|
if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
|
||||||
stack.push(new(big.Int))
|
stack.push(evm.interpreter.intPool.getZero())
|
||||||
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||||
stack.push(new(big.Int))
|
stack.push(evm.interpreter.intPool.getZero())
|
||||||
} else {
|
} else {
|
||||||
stack.push(addr.Big())
|
stack.push(addr.Big())
|
||||||
}
|
}
|
||||||
|
|
@ -678,9 +682,9 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
||||||
}
|
}
|
||||||
ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value)
|
ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(new(big.Int))
|
stack.push(evm.interpreter.intPool.getZero())
|
||||||
} else {
|
} else {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||||
}
|
}
|
||||||
if err == nil || err == errExecutionReverted {
|
if err == nil || err == errExecutionReverted {
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
|
|
@ -707,9 +711,9 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
||||||
}
|
}
|
||||||
ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value)
|
ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(new(big.Int))
|
stack.push(evm.interpreter.intPool.getZero())
|
||||||
} else {
|
} else {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||||
}
|
}
|
||||||
if err == nil || err == errExecutionReverted {
|
if err == nil || err == errExecutionReverted {
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
|
|
@ -732,9 +736,9 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
|
||||||
|
|
||||||
ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
|
ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(new(big.Int))
|
stack.push(evm.interpreter.intPool.getZero())
|
||||||
} else {
|
} else {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||||
}
|
}
|
||||||
if err == nil || err == errExecutionReverted {
|
if err == nil || err == errExecutionReverted {
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
|
|
@ -757,9 +761,9 @@ func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
|
||||||
|
|
||||||
ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas)
|
ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(new(big.Int))
|
stack.push(evm.interpreter.intPool.getZero())
|
||||||
} else {
|
} else {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||||
}
|
}
|
||||||
if err == nil || err == errExecutionReverted {
|
if err == nil || err == errExecutionReverted {
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ type twoOperandTest struct {
|
||||||
|
|
||||||
func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
|
func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
)
|
)
|
||||||
|
|
@ -68,7 +68,7 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
|
||||||
|
|
||||||
func TestByteOp(t *testing.T) {
|
func TestByteOp(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
)
|
)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
|
@ -161,6 +161,7 @@ func TestSAR(t *testing.T) {
|
||||||
|
|
||||||
func TestSGT(t *testing.T) {
|
func TestSGT(t *testing.T) {
|
||||||
tests := []twoOperandTest{
|
tests := []twoOperandTest{
|
||||||
|
|
||||||
{"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
|
|
@ -171,6 +172,8 @@ func TestSGT(t *testing.T) {
|
||||||
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
|
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||||
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
|
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||||
|
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
}
|
}
|
||||||
testTwoOperandOp(t, tests, opSgt)
|
testTwoOperandOp(t, tests, opSgt)
|
||||||
}
|
}
|
||||||
|
|
@ -187,13 +190,15 @@ func TestSLT(t *testing.T) {
|
||||||
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||||
|
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000000"},
|
||||||
|
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000001"},
|
||||||
}
|
}
|
||||||
testTwoOperandOp(t, tests, opSlt)
|
testTwoOperandOp(t, tests, opSlt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
|
func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
)
|
)
|
||||||
// convert args
|
// convert args
|
||||||
|
|
@ -349,7 +354,11 @@ func BenchmarkOpEq(b *testing.B) {
|
||||||
|
|
||||||
opBenchmark(b, opEq, x, y)
|
opBenchmark(b, opEq, x, y)
|
||||||
}
|
}
|
||||||
|
func BenchmarkOpEq2(b *testing.B) {
|
||||||
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
||||||
|
y := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201fffffffe"
|
||||||
|
opBenchmark(b, opEq, x, y)
|
||||||
|
}
|
||||||
func BenchmarkOpAnd(b *testing.B) {
|
func BenchmarkOpAnd(b *testing.B) {
|
||||||
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||||
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
||||||
|
|
@ -412,3 +421,7 @@ func BenchmarkOpSAR(b *testing.B) {
|
||||||
|
|
||||||
opBenchmark(b, opSAR, x, y)
|
opBenchmark(b, opSAR, x, y)
|
||||||
}
|
}
|
||||||
|
func BenchmarkOpIsZero(b *testing.B) {
|
||||||
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
||||||
|
opBenchmark(b, opIszero, x)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,6 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Debug enabled debugging Interpreter options
|
// Debug enabled debugging Interpreter options
|
||||||
Debug bool
|
Debug bool
|
||||||
// EnableJit enabled the JIT VM
|
|
||||||
EnableJit bool
|
|
||||||
// ForceJit forces the JIT VM
|
|
||||||
ForceJit bool
|
|
||||||
// Tracer is the op code logger
|
// Tracer is the op code logger
|
||||||
Tracer Tracer
|
Tracer Tracer
|
||||||
// NoRecursion disabled Interpreter call, callcode,
|
// NoRecursion disabled Interpreter call, callcode,
|
||||||
|
|
@ -46,8 +42,8 @@ type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpreter is used to run Ethereum based contracts and will utilise the
|
// Interpreter is used to run Ethereum based contracts and will utilise the
|
||||||
// passed evmironment to query external sources for state information.
|
// passed environment to query external sources for state information.
|
||||||
// The Interpreter will run the byte code VM or JIT VM based on the passed
|
// The Interpreter will run the byte code VM based on the passed
|
||||||
// configuration.
|
// configuration.
|
||||||
type Interpreter struct {
|
type Interpreter struct {
|
||||||
evm *EVM
|
evm *EVM
|
||||||
|
|
@ -188,7 +184,7 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// consume the gas and return an error if not enough gas is available.
|
// consume the gas and return an error if not enough gas is available.
|
||||||
// cost is explicitly set so that the capture state defer method cas get the proper cost
|
// cost is explicitly set so that the capture state defer method can get the proper cost
|
||||||
cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)
|
cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)
|
||||||
if err != nil || !contract.UseGas(cost) {
|
if err != nil || !contract.UseGas(cost) {
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
|
|
|
||||||
|
|
@ -32,24 +32,36 @@ func newIntPool() *intPool {
|
||||||
return &intPool{pool: newstack()}
|
return &intPool{pool: newstack()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get retrieves a big int from the pool, allocating one if the pool is empty.
|
||||||
|
// Note, the returned int's value is arbitrary and will not be zeroed!
|
||||||
func (p *intPool) get() *big.Int {
|
func (p *intPool) get() *big.Int {
|
||||||
if p.pool.len() > 0 {
|
if p.pool.len() > 0 {
|
||||||
return p.pool.pop()
|
return p.pool.pop()
|
||||||
}
|
}
|
||||||
return new(big.Int)
|
return new(big.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getZero retrieves a big int from the pool, setting it to zero or allocating
|
||||||
|
// a new one if the pool is empty.
|
||||||
|
func (p *intPool) getZero() *big.Int {
|
||||||
|
if p.pool.len() > 0 {
|
||||||
|
return p.pool.pop().SetUint64(0)
|
||||||
|
}
|
||||||
|
return new(big.Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// put returns an allocated big int to the pool to be later reused by get calls.
|
||||||
|
// Note, the values as saved as is; neither put nor get zeroes the ints out!
|
||||||
func (p *intPool) put(is ...*big.Int) {
|
func (p *intPool) put(is ...*big.Int) {
|
||||||
if len(p.pool.data) > poolLimit {
|
if len(p.pool.data) > poolLimit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, i := range is {
|
for _, i := range is {
|
||||||
// verifyPool is a build flag. Pool verification makes sure the integrity
|
// verifyPool is a build flag. Pool verification makes sure the integrity
|
||||||
// of the integer pool by comparing values to a default value.
|
// of the integer pool by comparing values to a default value.
|
||||||
if verifyPool {
|
if verifyPool {
|
||||||
i.Set(checkVal)
|
i.Set(checkVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.pool.push(i)
|
p.pool.push(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ type dummyStateDB struct {
|
||||||
|
|
||||||
func TestStoreCapture(t *testing.T) {
|
func TestStoreCapture(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||||
logger = NewStructLogger(nil)
|
logger = NewStructLogger(nil)
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ type Config struct {
|
||||||
GasLimit uint64
|
GasLimit uint64
|
||||||
GasPrice *big.Int
|
GasPrice *big.Int
|
||||||
Value *big.Int
|
Value *big.Int
|
||||||
DisableJit bool // "disable" so it's enabled by default
|
|
||||||
Debug bool
|
Debug bool
|
||||||
EVMConfig vm.Config
|
EVMConfig vm.Config
|
||||||
|
|
||||||
|
|
@ -92,8 +91,7 @@ func setDefaults(cfg *Config) {
|
||||||
// It returns the EVM's return value, the new state and an error if it failed.
|
// It returns the EVM's return value, the new state and an error if it failed.
|
||||||
//
|
//
|
||||||
// Executes sets up a in memory, temporarily, environment for the execution of
|
// Executes sets up a in memory, temporarily, environment for the execution of
|
||||||
// the given code. It enabled the JIT by default and make sure that it's restored
|
// the given code. It makes sure that it's restored to it's original state afterwards.
|
||||||
// to it's original state afterwards.
|
|
||||||
func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
cfg = new(Config)
|
cfg = new(Config)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
// 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
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// +build !evmjit
|
|
||||||
|
|
||||||
package vm
|
|
||||||
|
|
@ -14,50 +14,22 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// 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/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// +build !amd64 appengine gccgo
|
// +build amd64 arm64
|
||||||
|
|
||||||
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
|
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
|
||||||
package bn256
|
package bn256
|
||||||
|
|
||||||
import (
|
import "github.com/EthereumCommonwealth/go-callisto/crypto/bn256/cloudflare"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto/bn256/google"
|
|
||||||
)
|
|
||||||
|
|
||||||
// G1 is an abstract cyclic group. The zero value is suitable for use as the
|
// G1 is an abstract cyclic group. The zero value is suitable for use as the
|
||||||
// output of an operation, but cannot be used as an input.
|
// output of an operation, but cannot be used as an input.
|
||||||
type G1 struct {
|
type G1 = bn256.G1
|
||||||
bn256.G1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add sets e to a+b and then returns e.
|
|
||||||
func (e *G1) Add(a, b *G1) *G1 {
|
|
||||||
e.G1.Add(&a.G1, &b.G1)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScalarMult sets e to a*k and then returns e.
|
|
||||||
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
|
|
||||||
e.G1.ScalarMult(&a.G1, k)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// G2 is an abstract cyclic group. The zero value is suitable for use as the
|
// G2 is an abstract cyclic group. The zero value is suitable for use as the
|
||||||
// output of an operation, but cannot be used as an input.
|
// output of an operation, but cannot be used as an input.
|
||||||
type G2 struct {
|
type G2 = bn256.G2
|
||||||
bn256.G2
|
|
||||||
}
|
|
||||||
|
|
||||||
// PairingCheck calculates the Optimal Ate pairing for a set of points.
|
// PairingCheck calculates the Optimal Ate pairing for a set of points.
|
||||||
func PairingCheck(a []*G1, b []*G2) bool {
|
func PairingCheck(a []*G1, b []*G2) bool {
|
||||||
as := make([]*bn256.G1, len(a))
|
return bn256.PairingCheck(a, b)
|
||||||
for i, p := range a {
|
|
||||||
as[i] = &p.G1
|
|
||||||
}
|
|
||||||
bs := make([]*bn256.G2, len(b))
|
|
||||||
for i, p := range b {
|
|
||||||
bs[i] = &p.G2
|
|
||||||
}
|
|
||||||
return bn256.PairingCheck(as, bs)
|
|
||||||
}
|
}
|
||||||
138
crypto/bn256/bn256_fuzz.go
Normal file
138
crypto/bn256/bn256_fuzz.go
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
// 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/>.
|
||||||
|
|
||||||
|
// +build gofuzz
|
||||||
|
|
||||||
|
package bn256
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
cloudflare "github.com/EthereumCommonwealth/go-callisto/crypto/bn256/cloudflare"
|
||||||
|
google "github.com/EthereumCommonwealth/go-callisto/crypto/bn256/google"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FuzzAdd fuzzez bn256 addition between the Google and Cloudflare libraries.
|
||||||
|
func FuzzAdd(data []byte) int {
|
||||||
|
// Ensure we have enough data in the first place
|
||||||
|
if len(data) != 128 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Ensure both libs can parse the first curve point
|
||||||
|
xc := new(cloudflare.G1)
|
||||||
|
_, errc := xc.Unmarshal(data[:64])
|
||||||
|
|
||||||
|
xg := new(google.G1)
|
||||||
|
_, errg := xg.Unmarshal(data[:64])
|
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) {
|
||||||
|
panic("parse mismatch")
|
||||||
|
} else if errc != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Ensure both libs can parse the second curve point
|
||||||
|
yc := new(cloudflare.G1)
|
||||||
|
_, errc = yc.Unmarshal(data[64:])
|
||||||
|
|
||||||
|
yg := new(google.G1)
|
||||||
|
_, errg = yg.Unmarshal(data[64:])
|
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) {
|
||||||
|
panic("parse mismatch")
|
||||||
|
} else if errc != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Add the two points and ensure they result in the same output
|
||||||
|
rc := new(cloudflare.G1)
|
||||||
|
rc.Add(xc, yc)
|
||||||
|
|
||||||
|
rg := new(google.G1)
|
||||||
|
rg.Add(xg, yg)
|
||||||
|
|
||||||
|
if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
|
||||||
|
panic("add mismatch")
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuzzMul fuzzez bn256 scalar multiplication between the Google and Cloudflare
|
||||||
|
// libraries.
|
||||||
|
func FuzzMul(data []byte) int {
|
||||||
|
// Ensure we have enough data in the first place
|
||||||
|
if len(data) != 96 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Ensure both libs can parse the curve point
|
||||||
|
pc := new(cloudflare.G1)
|
||||||
|
_, errc := pc.Unmarshal(data[:64])
|
||||||
|
|
||||||
|
pg := new(google.G1)
|
||||||
|
_, errg := pg.Unmarshal(data[:64])
|
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) {
|
||||||
|
panic("parse mismatch")
|
||||||
|
} else if errc != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Add the two points and ensure they result in the same output
|
||||||
|
rc := new(cloudflare.G1)
|
||||||
|
rc.ScalarMult(pc, new(big.Int).SetBytes(data[64:]))
|
||||||
|
|
||||||
|
rg := new(google.G1)
|
||||||
|
rg.ScalarMult(pg, new(big.Int).SetBytes(data[64:]))
|
||||||
|
|
||||||
|
if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
|
||||||
|
panic("scalar mul mismatch")
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzPair(data []byte) int {
|
||||||
|
// Ensure we have enough data in the first place
|
||||||
|
if len(data) != 192 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Ensure both libs can parse the curve point
|
||||||
|
pc := new(cloudflare.G1)
|
||||||
|
_, errc := pc.Unmarshal(data[:64])
|
||||||
|
|
||||||
|
pg := new(google.G1)
|
||||||
|
_, errg := pg.Unmarshal(data[:64])
|
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) {
|
||||||
|
panic("parse mismatch")
|
||||||
|
} else if errc != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Ensure both libs can parse the twist point
|
||||||
|
tc := new(cloudflare.G2)
|
||||||
|
_, errc = tc.Unmarshal(data[64:])
|
||||||
|
|
||||||
|
tg := new(google.G2)
|
||||||
|
_, errg = tg.Unmarshal(data[64:])
|
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) {
|
||||||
|
panic("parse mismatch")
|
||||||
|
} else if errc != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Pair the two points and ensure thet result in the same output
|
||||||
|
if cloudflare.PairingCheck([]*cloudflare.G1{pc}, []*cloudflare.G2{tc}) != google.PairingCheck([]*google.G1{pg}, []*google.G2{tg}) {
|
||||||
|
panic("pair mismatch")
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
@ -14,50 +14,22 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// 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/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// +build amd64,!appengine,!gccgo
|
// +build !amd64,!arm64
|
||||||
|
|
||||||
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
|
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
|
||||||
package bn256
|
package bn256
|
||||||
|
|
||||||
import (
|
import "github.com/EthereumCommonwealth/go-callisto/crypto/bn256/google"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
|
|
||||||
)
|
|
||||||
|
|
||||||
// G1 is an abstract cyclic group. The zero value is suitable for use as the
|
// G1 is an abstract cyclic group. The zero value is suitable for use as the
|
||||||
// output of an operation, but cannot be used as an input.
|
// output of an operation, but cannot be used as an input.
|
||||||
type G1 struct {
|
type G1 = bn256.G1
|
||||||
bn256.G1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add sets e to a+b and then returns e.
|
|
||||||
func (e *G1) Add(a, b *G1) *G1 {
|
|
||||||
e.G1.Add(&a.G1, &b.G1)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScalarMult sets e to a*k and then returns e.
|
|
||||||
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
|
|
||||||
e.G1.ScalarMult(&a.G1, k)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// G2 is an abstract cyclic group. The zero value is suitable for use as the
|
// G2 is an abstract cyclic group. The zero value is suitable for use as the
|
||||||
// output of an operation, but cannot be used as an input.
|
// output of an operation, but cannot be used as an input.
|
||||||
type G2 struct {
|
type G2 = bn256.G2
|
||||||
bn256.G2
|
|
||||||
}
|
|
||||||
|
|
||||||
// PairingCheck calculates the Optimal Ate pairing for a set of points.
|
// PairingCheck calculates the Optimal Ate pairing for a set of points.
|
||||||
func PairingCheck(a []*G1, b []*G2) bool {
|
func PairingCheck(a []*G1, b []*G2) bool {
|
||||||
as := make([]*bn256.G1, len(a))
|
return bn256.PairingCheck(a, b)
|
||||||
for i, p := range a {
|
|
||||||
as[i] = &p.G1
|
|
||||||
}
|
|
||||||
bs := make([]*bn256.G2, len(b))
|
|
||||||
for i, p := range b {
|
|
||||||
bs[i] = &p.G2
|
|
||||||
}
|
|
||||||
return bn256.PairingCheck(as, bs)
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// +build amd64,!appengine,!gccgo
|
|
||||||
|
|
||||||
package bn256
|
package bn256
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -183,15 +183,24 @@ func (c *curvePoint) Double(a *curvePoint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
|
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
|
||||||
sum, t := &curvePoint{}, &curvePoint{}
|
precomp := [1 << 2]*curvePoint{nil, {}, {}, {}}
|
||||||
sum.SetInfinity()
|
precomp[1].Set(a)
|
||||||
|
precomp[2].Set(a)
|
||||||
|
gfpMul(&precomp[2].x, &precomp[2].x, xiTo2PSquaredMinus2Over3)
|
||||||
|
precomp[3].Add(precomp[1], precomp[2])
|
||||||
|
|
||||||
for i := scalar.BitLen(); i >= 0; i-- {
|
multiScalar := curveLattice.Multi(scalar)
|
||||||
|
|
||||||
|
sum := &curvePoint{}
|
||||||
|
sum.SetInfinity()
|
||||||
|
t := &curvePoint{}
|
||||||
|
|
||||||
|
for i := len(multiScalar) - 1; i >= 0; i-- {
|
||||||
t.Double(sum)
|
t.Double(sum)
|
||||||
if scalar.Bit(i) != 0 {
|
if multiScalar[i] == 0 {
|
||||||
sum.Add(t, a)
|
|
||||||
} else {
|
|
||||||
sum.Set(t)
|
sum.Set(t)
|
||||||
|
} else {
|
||||||
|
sum.Add(t, precomp[multiScalar[i]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.Set(sum)
|
c.Set(sum)
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build amd64,!appengine,!gccgo
|
|
||||||
|
|
||||||
package bn256
|
package bn256
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
#define storeBlock(a0,a1,a2,a3, r) \
|
|
||||||
MOVQ a0, 0+r \
|
|
||||||
MOVQ a1, 8+r \
|
|
||||||
MOVQ a2, 16+r \
|
|
||||||
MOVQ a3, 24+r
|
|
||||||
|
|
||||||
#define loadBlock(r, a0,a1,a2,a3) \
|
|
||||||
MOVQ 0+r, a0 \
|
|
||||||
MOVQ 8+r, a1 \
|
|
||||||
MOVQ 16+r, a2 \
|
|
||||||
MOVQ 24+r, a3
|
|
||||||
|
|
||||||
#define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \
|
|
||||||
\ // b = a-p
|
|
||||||
MOVQ a0, b0 \
|
|
||||||
MOVQ a1, b1 \
|
|
||||||
MOVQ a2, b2 \
|
|
||||||
MOVQ a3, b3 \
|
|
||||||
MOVQ a4, b4 \
|
|
||||||
\
|
|
||||||
SUBQ ·p2+0(SB), b0 \
|
|
||||||
SBBQ ·p2+8(SB), b1 \
|
|
||||||
SBBQ ·p2+16(SB), b2 \
|
|
||||||
SBBQ ·p2+24(SB), b3 \
|
|
||||||
SBBQ $0, b4 \
|
|
||||||
\
|
|
||||||
\ // if b is negative then return a
|
|
||||||
\ // else return b
|
|
||||||
CMOVQCC b0, a0 \
|
|
||||||
CMOVQCC b1, a1 \
|
|
||||||
CMOVQCC b2, a2 \
|
|
||||||
CMOVQCC b3, a3
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
// +build amd64,!appengine,!gccgo
|
|
||||||
|
|
||||||
package bn256
|
|
||||||
|
|
||||||
// go:noescape
|
|
||||||
func gfpNeg(c, a *gfP)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func gfpAdd(c, a, b *gfP)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func gfpSub(c, a, b *gfP)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func gfpMul(c, a, b *gfP)
|
|
||||||
|
|
@ -1,8 +1,40 @@
|
||||||
// +build amd64,!appengine,!gccgo
|
// +build amd64,!generic
|
||||||
|
|
||||||
#include "gfp.h"
|
#define storeBlock(a0,a1,a2,a3, r) \
|
||||||
#include "mul.h"
|
MOVQ a0, 0+r \
|
||||||
#include "mul_bmi2.h"
|
MOVQ a1, 8+r \
|
||||||
|
MOVQ a2, 16+r \
|
||||||
|
MOVQ a3, 24+r
|
||||||
|
|
||||||
|
#define loadBlock(r, a0,a1,a2,a3) \
|
||||||
|
MOVQ 0+r, a0 \
|
||||||
|
MOVQ 8+r, a1 \
|
||||||
|
MOVQ 16+r, a2 \
|
||||||
|
MOVQ 24+r, a3
|
||||||
|
|
||||||
|
#define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \
|
||||||
|
\ // b = a-p
|
||||||
|
MOVQ a0, b0 \
|
||||||
|
MOVQ a1, b1 \
|
||||||
|
MOVQ a2, b2 \
|
||||||
|
MOVQ a3, b3 \
|
||||||
|
MOVQ a4, b4 \
|
||||||
|
\
|
||||||
|
SUBQ ·p2+0(SB), b0 \
|
||||||
|
SBBQ ·p2+8(SB), b1 \
|
||||||
|
SBBQ ·p2+16(SB), b2 \
|
||||||
|
SBBQ ·p2+24(SB), b3 \
|
||||||
|
SBBQ $0, b4 \
|
||||||
|
\
|
||||||
|
\ // if b is negative then return a
|
||||||
|
\ // else return b
|
||||||
|
CMOVQCC b0, a0 \
|
||||||
|
CMOVQCC b1, a1 \
|
||||||
|
CMOVQCC b2, a2 \
|
||||||
|
CMOVQCC b3, a3
|
||||||
|
|
||||||
|
#include "mul_amd64.h"
|
||||||
|
#include "mul_bmi2_amd64.h"
|
||||||
|
|
||||||
TEXT ·gfpNeg(SB),0,$0-16
|
TEXT ·gfpNeg(SB),0,$0-16
|
||||||
MOVQ ·p2+0(SB), R8
|
MOVQ ·p2+0(SB), R8
|
||||||
|
|
|
||||||
113
crypto/bn256/cloudflare/gfp_arm64.s
Normal file
113
crypto/bn256/cloudflare/gfp_arm64.s
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
// +build arm64,!generic
|
||||||
|
|
||||||
|
#define storeBlock(a0,a1,a2,a3, r) \
|
||||||
|
MOVD a0, 0+r \
|
||||||
|
MOVD a1, 8+r \
|
||||||
|
MOVD a2, 16+r \
|
||||||
|
MOVD a3, 24+r
|
||||||
|
|
||||||
|
#define loadBlock(r, a0,a1,a2,a3) \
|
||||||
|
MOVD 0+r, a0 \
|
||||||
|
MOVD 8+r, a1 \
|
||||||
|
MOVD 16+r, a2 \
|
||||||
|
MOVD 24+r, a3
|
||||||
|
|
||||||
|
#define loadModulus(p0,p1,p2,p3) \
|
||||||
|
MOVD ·p2+0(SB), p0 \
|
||||||
|
MOVD ·p2+8(SB), p1 \
|
||||||
|
MOVD ·p2+16(SB), p2 \
|
||||||
|
MOVD ·p2+24(SB), p3
|
||||||
|
|
||||||
|
#include "mul_arm64.h"
|
||||||
|
|
||||||
|
TEXT ·gfpNeg(SB),0,$0-16
|
||||||
|
MOVD a+8(FP), R0
|
||||||
|
loadBlock(0(R0), R1,R2,R3,R4)
|
||||||
|
loadModulus(R5,R6,R7,R8)
|
||||||
|
|
||||||
|
SUBS R1, R5, R1
|
||||||
|
SBCS R2, R6, R2
|
||||||
|
SBCS R3, R7, R3
|
||||||
|
SBCS R4, R8, R4
|
||||||
|
|
||||||
|
SUBS R5, R1, R5
|
||||||
|
SBCS R6, R2, R6
|
||||||
|
SBCS R7, R3, R7
|
||||||
|
SBCS R8, R4, R8
|
||||||
|
|
||||||
|
CSEL CS, R5, R1, R1
|
||||||
|
CSEL CS, R6, R2, R2
|
||||||
|
CSEL CS, R7, R3, R3
|
||||||
|
CSEL CS, R8, R4, R4
|
||||||
|
|
||||||
|
MOVD c+0(FP), R0
|
||||||
|
storeBlock(R1,R2,R3,R4, 0(R0))
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT ·gfpAdd(SB),0,$0-24
|
||||||
|
MOVD a+8(FP), R0
|
||||||
|
loadBlock(0(R0), R1,R2,R3,R4)
|
||||||
|
MOVD b+16(FP), R0
|
||||||
|
loadBlock(0(R0), R5,R6,R7,R8)
|
||||||
|
loadModulus(R9,R10,R11,R12)
|
||||||
|
MOVD ZR, R0
|
||||||
|
|
||||||
|
ADDS R5, R1
|
||||||
|
ADCS R6, R2
|
||||||
|
ADCS R7, R3
|
||||||
|
ADCS R8, R4
|
||||||
|
ADCS ZR, R0
|
||||||
|
|
||||||
|
SUBS R9, R1, R5
|
||||||
|
SBCS R10, R2, R6
|
||||||
|
SBCS R11, R3, R7
|
||||||
|
SBCS R12, R4, R8
|
||||||
|
SBCS ZR, R0, R0
|
||||||
|
|
||||||
|
CSEL CS, R5, R1, R1
|
||||||
|
CSEL CS, R6, R2, R2
|
||||||
|
CSEL CS, R7, R3, R3
|
||||||
|
CSEL CS, R8, R4, R4
|
||||||
|
|
||||||
|
MOVD c+0(FP), R0
|
||||||
|
storeBlock(R1,R2,R3,R4, 0(R0))
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT ·gfpSub(SB),0,$0-24
|
||||||
|
MOVD a+8(FP), R0
|
||||||
|
loadBlock(0(R0), R1,R2,R3,R4)
|
||||||
|
MOVD b+16(FP), R0
|
||||||
|
loadBlock(0(R0), R5,R6,R7,R8)
|
||||||
|
loadModulus(R9,R10,R11,R12)
|
||||||
|
|
||||||
|
SUBS R5, R1
|
||||||
|
SBCS R6, R2
|
||||||
|
SBCS R7, R3
|
||||||
|
SBCS R8, R4
|
||||||
|
|
||||||
|
CSEL CS, ZR, R9, R9
|
||||||
|
CSEL CS, ZR, R10, R10
|
||||||
|
CSEL CS, ZR, R11, R11
|
||||||
|
CSEL CS, ZR, R12, R12
|
||||||
|
|
||||||
|
ADDS R9, R1
|
||||||
|
ADCS R10, R2
|
||||||
|
ADCS R11, R3
|
||||||
|
ADCS R12, R4
|
||||||
|
|
||||||
|
MOVD c+0(FP), R0
|
||||||
|
storeBlock(R1,R2,R3,R4, 0(R0))
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT ·gfpMul(SB),0,$0-24
|
||||||
|
MOVD a+8(FP), R0
|
||||||
|
loadBlock(0(R0), R1,R2,R3,R4)
|
||||||
|
MOVD b+16(FP), R0
|
||||||
|
loadBlock(0(R0), R5,R6,R7,R8)
|
||||||
|
|
||||||
|
mul(R9,R10,R11,R12,R13,R14,R15,R16)
|
||||||
|
gfpReduce()
|
||||||
|
|
||||||
|
MOVD c+0(FP), R0
|
||||||
|
storeBlock(R1,R2,R3,R4, 0(R0))
|
||||||
|
RET
|
||||||
18
crypto/bn256/cloudflare/gfp_decl.go
Normal file
18
crypto/bn256/cloudflare/gfp_decl.go
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
// +build amd64,!generic arm64,!generic
|
||||||
|
|
||||||
|
package bn256
|
||||||
|
|
||||||
|
// This file contains forward declarations for the architecture-specific
|
||||||
|
// assembly implementations of these functions, provided that they exist.
|
||||||
|
|
||||||
|
// go:noescape
|
||||||
|
func gfpNeg(c, a *gfP)
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func gfpAdd(c, a, b *gfP)
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func gfpSub(c, a, b *gfP)
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func gfpMul(c, a, b *gfP)
|
||||||
173
crypto/bn256/cloudflare/gfp_generic.go
Normal file
173
crypto/bn256/cloudflare/gfp_generic.go
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
// +build !amd64,!arm64 generic
|
||||||
|
|
||||||
|
package bn256
|
||||||
|
|
||||||
|
func gfpCarry(a *gfP, head uint64) {
|
||||||
|
b := &gfP{}
|
||||||
|
|
||||||
|
var carry uint64
|
||||||
|
for i, pi := range p2 {
|
||||||
|
ai := a[i]
|
||||||
|
bi := ai - pi - carry
|
||||||
|
b[i] = bi
|
||||||
|
carry = (pi&^ai | (pi|^ai)&bi) >> 63
|
||||||
|
}
|
||||||
|
carry = carry &^ head
|
||||||
|
|
||||||
|
// If b is negative, then return a.
|
||||||
|
// Else return b.
|
||||||
|
carry = -carry
|
||||||
|
ncarry := ^carry
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
a[i] = (a[i] & carry) | (b[i] & ncarry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gfpNeg(c, a *gfP) {
|
||||||
|
var carry uint64
|
||||||
|
for i, pi := range p2 {
|
||||||
|
ai := a[i]
|
||||||
|
ci := pi - ai - carry
|
||||||
|
c[i] = ci
|
||||||
|
carry = (ai&^pi | (ai|^pi)&ci) >> 63
|
||||||
|
}
|
||||||
|
gfpCarry(c, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gfpAdd(c, a, b *gfP) {
|
||||||
|
var carry uint64
|
||||||
|
for i, ai := range a {
|
||||||
|
bi := b[i]
|
||||||
|
ci := ai + bi + carry
|
||||||
|
c[i] = ci
|
||||||
|
carry = (ai&bi | (ai|bi)&^ci) >> 63
|
||||||
|
}
|
||||||
|
gfpCarry(c, carry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gfpSub(c, a, b *gfP) {
|
||||||
|
t := &gfP{}
|
||||||
|
|
||||||
|
var carry uint64
|
||||||
|
for i, pi := range p2 {
|
||||||
|
bi := b[i]
|
||||||
|
ti := pi - bi - carry
|
||||||
|
t[i] = ti
|
||||||
|
carry = (bi&^pi | (bi|^pi)&ti) >> 63
|
||||||
|
}
|
||||||
|
|
||||||
|
carry = 0
|
||||||
|
for i, ai := range a {
|
||||||
|
ti := t[i]
|
||||||
|
ci := ai + ti + carry
|
||||||
|
c[i] = ci
|
||||||
|
carry = (ai&ti | (ai|ti)&^ci) >> 63
|
||||||
|
}
|
||||||
|
gfpCarry(c, carry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mul(a, b [4]uint64) [8]uint64 {
|
||||||
|
const (
|
||||||
|
mask16 uint64 = 0x0000ffff
|
||||||
|
mask32 uint64 = 0xffffffff
|
||||||
|
)
|
||||||
|
|
||||||
|
var buff [32]uint64
|
||||||
|
for i, ai := range a {
|
||||||
|
a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
|
||||||
|
|
||||||
|
for j, bj := range b {
|
||||||
|
b0, b2 := bj&mask32, bj>>32
|
||||||
|
|
||||||
|
off := 4 * (i + j)
|
||||||
|
buff[off+0] += a0 * b0
|
||||||
|
buff[off+1] += a1 * b0
|
||||||
|
buff[off+2] += a2*b0 + a0*b2
|
||||||
|
buff[off+3] += a3*b0 + a1*b2
|
||||||
|
buff[off+4] += a2 * b2
|
||||||
|
buff[off+5] += a3 * b2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint(1); i < 4; i++ {
|
||||||
|
shift := 16 * i
|
||||||
|
|
||||||
|
var head, carry uint64
|
||||||
|
for j := uint(0); j < 8; j++ {
|
||||||
|
block := 4 * j
|
||||||
|
|
||||||
|
xi := buff[block]
|
||||||
|
yi := (buff[block+i] << shift) + head
|
||||||
|
zi := xi + yi + carry
|
||||||
|
buff[block] = zi
|
||||||
|
carry = (xi&yi | (xi|yi)&^zi) >> 63
|
||||||
|
|
||||||
|
head = buff[block+i] >> (64 - shift)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]}
|
||||||
|
}
|
||||||
|
|
||||||
|
func halfMul(a, b [4]uint64) [4]uint64 {
|
||||||
|
const (
|
||||||
|
mask16 uint64 = 0x0000ffff
|
||||||
|
mask32 uint64 = 0xffffffff
|
||||||
|
)
|
||||||
|
|
||||||
|
var buff [18]uint64
|
||||||
|
for i, ai := range a {
|
||||||
|
a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
|
||||||
|
|
||||||
|
for j, bj := range b {
|
||||||
|
if i+j > 3 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
b0, b2 := bj&mask32, bj>>32
|
||||||
|
|
||||||
|
off := 4 * (i + j)
|
||||||
|
buff[off+0] += a0 * b0
|
||||||
|
buff[off+1] += a1 * b0
|
||||||
|
buff[off+2] += a2*b0 + a0*b2
|
||||||
|
buff[off+3] += a3*b0 + a1*b2
|
||||||
|
buff[off+4] += a2 * b2
|
||||||
|
buff[off+5] += a3 * b2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint(1); i < 4; i++ {
|
||||||
|
shift := 16 * i
|
||||||
|
|
||||||
|
var head, carry uint64
|
||||||
|
for j := uint(0); j < 4; j++ {
|
||||||
|
block := 4 * j
|
||||||
|
|
||||||
|
xi := buff[block]
|
||||||
|
yi := (buff[block+i] << shift) + head
|
||||||
|
zi := xi + yi + carry
|
||||||
|
buff[block] = zi
|
||||||
|
carry = (xi&yi | (xi|yi)&^zi) >> 63
|
||||||
|
|
||||||
|
head = buff[block+i] >> (64 - shift)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [4]uint64{buff[0], buff[4], buff[8], buff[12]}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gfpMul(c, a, b *gfP) {
|
||||||
|
T := mul(*a, *b)
|
||||||
|
m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np)
|
||||||
|
t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2)
|
||||||
|
|
||||||
|
var carry uint64
|
||||||
|
for i, Ti := range T {
|
||||||
|
ti := t[i]
|
||||||
|
zi := Ti + ti + carry
|
||||||
|
T[i] = zi
|
||||||
|
carry = (Ti&ti | (Ti|ti)&^zi) >> 63
|
||||||
|
}
|
||||||
|
|
||||||
|
*c = gfP{T[4], T[5], T[6], T[7]}
|
||||||
|
gfpCarry(c, carry)
|
||||||
|
}
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
// +build !amd64 appengine gccgo
|
|
||||||
|
|
||||||
package bn256
|
|
||||||
|
|
||||||
func gfpNeg(c, a *gfP) {
|
|
||||||
panic("unsupported architecture")
|
|
||||||
}
|
|
||||||
|
|
||||||
func gfpAdd(c, a, b *gfP) {
|
|
||||||
panic("unsupported architecture")
|
|
||||||
}
|
|
||||||
|
|
||||||
func gfpSub(c, a, b *gfP) {
|
|
||||||
panic("unsupported architecture")
|
|
||||||
}
|
|
||||||
|
|
||||||
func gfpMul(c, a, b *gfP) {
|
|
||||||
panic("unsupported architecture")
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// +build amd64,!appengine,!gccgo
|
|
||||||
|
|
||||||
package bn256
|
package bn256
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
115
crypto/bn256/cloudflare/lattice.go
Normal file
115
crypto/bn256/cloudflare/lattice.go
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
package bn256
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
var half = new(big.Int).Rsh(Order, 1)
|
||||||
|
|
||||||
|
var curveLattice = &lattice{
|
||||||
|
vectors: [][]*big.Int{
|
||||||
|
{bigFromBase10("147946756881789319000765030803803410728"), bigFromBase10("147946756881789319010696353538189108491")},
|
||||||
|
{bigFromBase10("147946756881789319020627676272574806254"), bigFromBase10("-147946756881789318990833708069417712965")},
|
||||||
|
},
|
||||||
|
inverse: []*big.Int{
|
||||||
|
bigFromBase10("147946756881789318990833708069417712965"),
|
||||||
|
bigFromBase10("147946756881789319010696353538189108491"),
|
||||||
|
},
|
||||||
|
det: bigFromBase10("43776485743678550444492811490514550177096728800832068687396408373151616991234"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetLattice = &lattice{
|
||||||
|
vectors: [][]*big.Int{
|
||||||
|
{bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697763"), bigFromBase10("9931322734385697764")},
|
||||||
|
{bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848882"), bigFromBase10("-9931322734385697762")},
|
||||||
|
{bigFromBase10("-9931322734385697762"), bigFromBase10("-4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("-4965661367192848882")},
|
||||||
|
{bigFromBase10("9931322734385697763"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881")},
|
||||||
|
},
|
||||||
|
inverse: []*big.Int{
|
||||||
|
bigFromBase10("734653495049373973658254490726798021314063399421879442165"),
|
||||||
|
bigFromBase10("147946756881789319000765030803803410728"),
|
||||||
|
bigFromBase10("-147946756881789319005730692170996259609"),
|
||||||
|
bigFromBase10("1469306990098747947464455738335385361643788813749140841702"),
|
||||||
|
},
|
||||||
|
det: new(big.Int).Set(Order),
|
||||||
|
}
|
||||||
|
|
||||||
|
type lattice struct {
|
||||||
|
vectors [][]*big.Int
|
||||||
|
inverse []*big.Int
|
||||||
|
det *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// decompose takes a scalar mod Order as input and finds a short, positive decomposition of it wrt to the lattice basis.
|
||||||
|
func (l *lattice) decompose(k *big.Int) []*big.Int {
|
||||||
|
n := len(l.inverse)
|
||||||
|
|
||||||
|
// Calculate closest vector in lattice to <k,0,0,...> with Babai's rounding.
|
||||||
|
c := make([]*big.Int, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
c[i] = new(big.Int).Mul(k, l.inverse[i])
|
||||||
|
round(c[i], l.det)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform vectors according to c and subtract <k,0,0,...>.
|
||||||
|
out := make([]*big.Int, n)
|
||||||
|
temp := new(big.Int)
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
out[i] = new(big.Int)
|
||||||
|
|
||||||
|
for j := 0; j < n; j++ {
|
||||||
|
temp.Mul(c[j], l.vectors[j][i])
|
||||||
|
out[i].Add(out[i], temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
out[i].Neg(out[i])
|
||||||
|
out[i].Add(out[i], l.vectors[0][i]).Add(out[i], l.vectors[0][i])
|
||||||
|
}
|
||||||
|
out[0].Add(out[0], k)
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *lattice) Precompute(add func(i, j uint)) {
|
||||||
|
n := uint(len(l.vectors))
|
||||||
|
total := uint(1) << n
|
||||||
|
|
||||||
|
for i := uint(0); i < n; i++ {
|
||||||
|
for j := uint(0); j < total; j++ {
|
||||||
|
if (j>>i)&1 == 1 {
|
||||||
|
add(i, j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *lattice) Multi(scalar *big.Int) []uint8 {
|
||||||
|
decomp := l.decompose(scalar)
|
||||||
|
|
||||||
|
maxLen := 0
|
||||||
|
for _, x := range decomp {
|
||||||
|
if x.BitLen() > maxLen {
|
||||||
|
maxLen = x.BitLen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]uint8, maxLen)
|
||||||
|
for j, x := range decomp {
|
||||||
|
for i := 0; i < maxLen; i++ {
|
||||||
|
out[i] += uint8(x.Bit(i)) << uint(j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// round sets num to num/denom rounded to the nearest integer.
|
||||||
|
func round(num, denom *big.Int) {
|
||||||
|
r := new(big.Int)
|
||||||
|
num.DivMod(num, denom, r)
|
||||||
|
|
||||||
|
if r.Cmp(half) == 1 {
|
||||||
|
num.Add(num, big.NewInt(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
29
crypto/bn256/cloudflare/lattice_test.go
Normal file
29
crypto/bn256/cloudflare/lattice_test.go
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package bn256
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLatticeReduceCurve(t *testing.T) {
|
||||||
|
k, _ := rand.Int(rand.Reader, Order)
|
||||||
|
ks := curveLattice.decompose(k)
|
||||||
|
|
||||||
|
if ks[0].BitLen() > 130 || ks[1].BitLen() > 130 {
|
||||||
|
t.Fatal("reduction too large")
|
||||||
|
} else if ks[0].Sign() < 0 || ks[1].Sign() < 0 {
|
||||||
|
t.Fatal("reduction must be positive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLatticeReduceTarget(t *testing.T) {
|
||||||
|
k, _ := rand.Int(rand.Reader, Order)
|
||||||
|
ks := targetLattice.decompose(k)
|
||||||
|
|
||||||
|
if ks[0].BitLen() > 66 || ks[1].BitLen() > 66 || ks[2].BitLen() > 66 || ks[3].BitLen() > 66 {
|
||||||
|
t.Fatal("reduction too large")
|
||||||
|
} else if ks[0].Sign() < 0 || ks[1].Sign() < 0 || ks[2].Sign() < 0 || ks[3].Sign() < 0 {
|
||||||
|
t.Fatal("reduction must be positive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// +build amd64,!appengine,!gccgo
|
|
||||||
|
|
||||||
package bn256
|
package bn256
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
133
crypto/bn256/cloudflare/mul_arm64.h
Normal file
133
crypto/bn256/cloudflare/mul_arm64.h
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
#define mul(c0,c1,c2,c3,c4,c5,c6,c7) \
|
||||||
|
MUL R1, R5, c0 \
|
||||||
|
UMULH R1, R5, c1 \
|
||||||
|
MUL R1, R6, R0 \
|
||||||
|
ADDS R0, c1 \
|
||||||
|
UMULH R1, R6, c2 \
|
||||||
|
MUL R1, R7, R0 \
|
||||||
|
ADCS R0, c2 \
|
||||||
|
UMULH R1, R7, c3 \
|
||||||
|
MUL R1, R8, R0 \
|
||||||
|
ADCS R0, c3 \
|
||||||
|
UMULH R1, R8, c4 \
|
||||||
|
ADCS ZR, c4 \
|
||||||
|
\
|
||||||
|
MUL R2, R5, R25 \
|
||||||
|
UMULH R2, R5, R26 \
|
||||||
|
MUL R2, R6, R0 \
|
||||||
|
ADDS R0, R26 \
|
||||||
|
UMULH R2, R6, R27 \
|
||||||
|
MUL R2, R7, R0 \
|
||||||
|
ADCS R0, R27 \
|
||||||
|
UMULH R2, R7, R29 \
|
||||||
|
MUL R2, R8, R0 \
|
||||||
|
ADCS R0, R29 \
|
||||||
|
UMULH R2, R8, c5 \
|
||||||
|
ADCS ZR, c5 \
|
||||||
|
ADDS R25, c1 \
|
||||||
|
ADCS R26, c2 \
|
||||||
|
ADCS R27, c3 \
|
||||||
|
ADCS R29, c4 \
|
||||||
|
ADCS ZR, c5 \
|
||||||
|
\
|
||||||
|
MUL R3, R5, R25 \
|
||||||
|
UMULH R3, R5, R26 \
|
||||||
|
MUL R3, R6, R0 \
|
||||||
|
ADDS R0, R26 \
|
||||||
|
UMULH R3, R6, R27 \
|
||||||
|
MUL R3, R7, R0 \
|
||||||
|
ADCS R0, R27 \
|
||||||
|
UMULH R3, R7, R29 \
|
||||||
|
MUL R3, R8, R0 \
|
||||||
|
ADCS R0, R29 \
|
||||||
|
UMULH R3, R8, c6 \
|
||||||
|
ADCS ZR, c6 \
|
||||||
|
ADDS R25, c2 \
|
||||||
|
ADCS R26, c3 \
|
||||||
|
ADCS R27, c4 \
|
||||||
|
ADCS R29, c5 \
|
||||||
|
ADCS ZR, c6 \
|
||||||
|
\
|
||||||
|
MUL R4, R5, R25 \
|
||||||
|
UMULH R4, R5, R26 \
|
||||||
|
MUL R4, R6, R0 \
|
||||||
|
ADDS R0, R26 \
|
||||||
|
UMULH R4, R6, R27 \
|
||||||
|
MUL R4, R7, R0 \
|
||||||
|
ADCS R0, R27 \
|
||||||
|
UMULH R4, R7, R29 \
|
||||||
|
MUL R4, R8, R0 \
|
||||||
|
ADCS R0, R29 \
|
||||||
|
UMULH R4, R8, c7 \
|
||||||
|
ADCS ZR, c7 \
|
||||||
|
ADDS R25, c3 \
|
||||||
|
ADCS R26, c4 \
|
||||||
|
ADCS R27, c5 \
|
||||||
|
ADCS R29, c6 \
|
||||||
|
ADCS ZR, c7
|
||||||
|
|
||||||
|
#define gfpReduce() \
|
||||||
|
\ // m = (T * N') mod R, store m in R1:R2:R3:R4
|
||||||
|
MOVD ·np+0(SB), R17 \
|
||||||
|
MOVD ·np+8(SB), R18 \
|
||||||
|
MOVD ·np+16(SB), R19 \
|
||||||
|
MOVD ·np+24(SB), R20 \
|
||||||
|
\
|
||||||
|
MUL R9, R17, R1 \
|
||||||
|
UMULH R9, R17, R2 \
|
||||||
|
MUL R9, R18, R0 \
|
||||||
|
ADDS R0, R2 \
|
||||||
|
UMULH R9, R18, R3 \
|
||||||
|
MUL R9, R19, R0 \
|
||||||
|
ADCS R0, R3 \
|
||||||
|
UMULH R9, R19, R4 \
|
||||||
|
MUL R9, R20, R0 \
|
||||||
|
ADCS R0, R4 \
|
||||||
|
\
|
||||||
|
MUL R10, R17, R21 \
|
||||||
|
UMULH R10, R17, R22 \
|
||||||
|
MUL R10, R18, R0 \
|
||||||
|
ADDS R0, R22 \
|
||||||
|
UMULH R10, R18, R23 \
|
||||||
|
MUL R10, R19, R0 \
|
||||||
|
ADCS R0, R23 \
|
||||||
|
ADDS R21, R2 \
|
||||||
|
ADCS R22, R3 \
|
||||||
|
ADCS R23, R4 \
|
||||||
|
\
|
||||||
|
MUL R11, R17, R21 \
|
||||||
|
UMULH R11, R17, R22 \
|
||||||
|
MUL R11, R18, R0 \
|
||||||
|
ADDS R0, R22 \
|
||||||
|
ADDS R21, R3 \
|
||||||
|
ADCS R22, R4 \
|
||||||
|
\
|
||||||
|
MUL R12, R17, R21 \
|
||||||
|
ADDS R21, R4 \
|
||||||
|
\
|
||||||
|
\ // m * N
|
||||||
|
loadModulus(R5,R6,R7,R8) \
|
||||||
|
mul(R17,R18,R19,R20,R21,R22,R23,R24) \
|
||||||
|
\
|
||||||
|
\ // Add the 512-bit intermediate to m*N
|
||||||
|
MOVD ZR, R25 \
|
||||||
|
ADDS R9, R17 \
|
||||||
|
ADCS R10, R18 \
|
||||||
|
ADCS R11, R19 \
|
||||||
|
ADCS R12, R20 \
|
||||||
|
ADCS R13, R21 \
|
||||||
|
ADCS R14, R22 \
|
||||||
|
ADCS R15, R23 \
|
||||||
|
ADCS R16, R24 \
|
||||||
|
ADCS ZR, R25 \
|
||||||
|
\
|
||||||
|
\ // Our output is R21:R22:R23:R24. Reduce mod p if necessary.
|
||||||
|
SUBS R5, R21, R10 \
|
||||||
|
SBCS R6, R22, R11 \
|
||||||
|
SBCS R7, R23, R12 \
|
||||||
|
SBCS R8, R24, R13 \
|
||||||
|
\
|
||||||
|
CSEL CS, R10, R21, R1 \
|
||||||
|
CSEL CS, R11, R22, R2 \
|
||||||
|
CSEL CS, R12, R23, R3 \
|
||||||
|
CSEL CS, R13, R24, R4
|
||||||
|
|
@ -230,7 +230,7 @@ func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte,
|
||||||
|
|
||||||
// symDecrypt carries out CTR decryption using the block cipher specified in
|
// symDecrypt carries out CTR decryption using the block cipher specified in
|
||||||
// the parameters
|
// the parameters
|
||||||
func symDecrypt(rand io.Reader, params *ECIESParams, key, ct []byte) (m []byte, err error) {
|
func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {
|
||||||
c, err := params.Cipher(key)
|
c, err := params.Cipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -292,7 +292,7 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt decrypts an ECIES ciphertext.
|
// Decrypt decrypts an ECIES ciphertext.
|
||||||
func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err error) {
|
func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
|
||||||
if len(c) == 0 {
|
if len(c) == 0 {
|
||||||
return nil, ErrInvalidMessage
|
return nil, ErrInvalidMessage
|
||||||
}
|
}
|
||||||
|
|
@ -361,6 +361,6 @@ func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err = symDecrypt(rand, params, Ke, c[mStart:mEnd])
|
m, err = symDecrypt(params, Ke, c[mStart:mEnd])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ func TestEncryptDecrypt(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
|
pt, err := prv2.Decrypt(ct, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
|
@ -281,7 +281,7 @@ func TestEncryptDecrypt(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = prv1.Decrypt(rand.Reader, ct, nil, nil)
|
_, err = prv1.Decrypt(ct, nil, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Println("ecies: encryption should not have succeeded")
|
fmt.Println("ecies: encryption should not have succeeded")
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
|
@ -301,7 +301,7 @@ func TestDecryptShared2(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that decrypting with correct shared data works.
|
// Check that decrypting with correct shared data works.
|
||||||
pt, err := prv.Decrypt(rand.Reader, ct, nil, shared2)
|
pt, err := prv.Decrypt(ct, nil, shared2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -310,10 +310,10 @@ func TestDecryptShared2(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypting without shared data or incorrect shared data fails.
|
// Decrypting without shared data or incorrect shared data fails.
|
||||||
if _, err = prv.Decrypt(rand.Reader, ct, nil, nil); err == nil {
|
if _, err = prv.Decrypt(ct, nil, nil); err == nil {
|
||||||
t.Fatal("ecies: decrypting without shared data didn't fail")
|
t.Fatal("ecies: decrypting without shared data didn't fail")
|
||||||
}
|
}
|
||||||
if _, err = prv.Decrypt(rand.Reader, ct, nil, []byte("garbage")); err == nil {
|
if _, err = prv.Decrypt(ct, nil, []byte("garbage")); err == nil {
|
||||||
t.Fatal("ecies: decrypting with incorrect shared data didn't fail")
|
t.Fatal("ecies: decrypting with incorrect shared data didn't fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -381,7 +381,7 @@ func testParamSelection(t *testing.T, c testCase) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
|
pt, err := prv2.Decrypt(ct, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s (%s)\n", err.Error(), c.Name)
|
fmt.Printf("%s (%s)\n", err.Error(), c.Name)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
|
@ -393,7 +393,7 @@ func testParamSelection(t *testing.T, c testCase) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = prv1.Decrypt(rand.Reader, ct, nil, nil)
|
_, err = prv1.Decrypt(ct, nil, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("ecies: encryption should not have succeeded (%s)\n",
|
fmt.Printf("ecies: encryption should not have succeeded (%s)\n",
|
||||||
c.Name)
|
c.Name)
|
||||||
|
|
@ -422,7 +422,7 @@ func TestBasicKeyValidation(t *testing.T) {
|
||||||
|
|
||||||
for _, b := range badBytes {
|
for _, b := range badBytes {
|
||||||
ct[0] = b
|
ct[0] = b
|
||||||
_, err := prv.Decrypt(rand.Reader, ct, nil, nil)
|
_, err := prv.Decrypt(ct, nil, nil)
|
||||||
if err != ErrInvalidPublicKey {
|
if err != ErrInvalidPublicKey {
|
||||||
fmt.Println("ecies: validated an invalid key")
|
fmt.Println("ecies: validated an invalid key")
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
|
@ -441,14 +441,14 @@ func TestBox(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
|
pt, err := prv2.Decrypt(ct, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(pt, message) {
|
if !bytes.Equal(pt, message) {
|
||||||
t.Fatal("ecies: plaintext doesn't match message")
|
t.Fatal("ecies: plaintext doesn't match message")
|
||||||
}
|
}
|
||||||
if _, err = prv1.Decrypt(rand.Reader, ct, nil, nil); err == nil {
|
if _, err = prv1.Decrypt(ct, nil, nil); err == nil {
|
||||||
t.Fatal("ecies: encryption should not have succeeded")
|
t.Fatal("ecies: encryption should not have succeeded")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,28 +12,27 @@ The client's UI uses [React][React] with JSX syntax, which is validated by the [
|
||||||
As the dashboard depends on certain NPM packages (which are not included in the `go-ethereum` repo), these need to be installed first:
|
As the dashboard depends on certain NPM packages (which are not included in the `go-ethereum` repo), these need to be installed first:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ (cd dashboard/assets && npm install)
|
$ (cd dashboard/assets && yarn install && yarn flow)
|
||||||
$ (cd dashboard/assets && ./node_modules/.bin/flow-typed install)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Normally the dashboard assets are bundled into Geth via `go-bindata` to avoid external dependencies. Rebuilding Geth after each UI modification however is not feasible from a developer perspective. Instead, we can run `webpack` in watch mode to automatically rebundle the UI, and ask `geth` to use external assets to not rely on compiled resources:
|
Normally the dashboard assets are bundled into Geth via `go-bindata` to avoid external dependencies. Rebuilding Geth after each UI modification however is not feasible from a developer perspective. Instead, we can run `yarn dev` to watch for file system changes and refresh the browser automatically.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ (cd dashboard/assets && ./node_modules/.bin/webpack --watch)
|
$ geth --dashboard --vmodule=dashboard=5
|
||||||
$ geth --dashboard --dashboard.assets=dashboard/assets --vmodule=dashboard=5
|
$ (cd dashboard/assets && yarn dev)
|
||||||
```
|
```
|
||||||
|
|
||||||
To bundle up the final UI into Geth, run `go generate`:
|
To bundle up the final UI into Geth, run `go generate`:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ go generate ./dashboard
|
$ (cd dashboard && go generate)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Static type checking
|
### Static type checking
|
||||||
|
|
||||||
Since JavaScript doesn't provide type safety, [Flow][Flow] is used to check types. These are only useful during development, so at the end of the process Babel will strip them.
|
Since JavaScript doesn't provide type safety, [Flow][Flow] is used to check types. These are only useful during development, so at the end of the process Babel will strip them.
|
||||||
|
|
||||||
To take advantage of static type checking, your IDE needs to be prepared for it. In case of [Atom][Atom] a configuration guide can be found [here][Atom config]: Install the [Nuclide][Nuclide] package for Flow support, making sure it installs all of its support packages by enabling `Install Recommended Packages on Startup`, and set the path of the `flow-bin` which were installed previously by `npm`.
|
To take advantage of static type checking, your IDE needs to be prepared for it. In case of [Atom][Atom] a configuration guide can be found [here][Atom config]: Install the [Nuclide][Nuclide] package for Flow support, making sure it installs all of its support packages by enabling `Install Recommended Packages on Startup`, and set the path of the `flow-bin` which were installed previously by `yarn`.
|
||||||
|
|
||||||
For more IDE support install the `linter-eslint` package too, which finds the `.eslintrc` file, and provides real-time linting. Atom warns, that these two packages are incompatible, but they seem to work well together. For third-party library errors and auto-completion [flow-typed][flow-typed] is used.
|
For more IDE support install the `linter-eslint` package too, which finds the `.eslintrc` file, and provides real-time linting. Atom warns, that these two packages are incompatible, but they seem to work well together. For third-party library errors and auto-completion [flow-typed][flow-typed] is used.
|
||||||
|
|
||||||
|
|
@ -41,7 +40,7 @@ For more IDE support install the `linter-eslint` package too, which finds the `.
|
||||||
|
|
||||||
[Webpack][Webpack] offers handy tools for visualizing the bundle's dependency tree and space usage.
|
[Webpack][Webpack] offers handy tools for visualizing the bundle's dependency tree and space usage.
|
||||||
|
|
||||||
* Generate the bundle's profile running `webpack --profile --json > stats.json`
|
* Generate the bundle's profile running `yarn stats`
|
||||||
* For the _dependency tree_ go to [Webpack Analyze][WA], and import `stats.json`
|
* For the _dependency tree_ go to [Webpack Analyze][WA], and import `stats.json`
|
||||||
* For the _space usage_ go to [Webpack Visualizer][WV], and import `stats.json`
|
* For the _space usage_ go to [Webpack Visualizer][WV], and import `stats.json`
|
||||||
|
|
||||||
|
|
|
||||||
4299
dashboard/assets.go
4299
dashboard/assets.go
File diff suppressed because one or more lines are too long
|
|
@ -38,15 +38,15 @@ export const percentPlotter = <T>(text: string, mapper: (T => T) = multiplier(1)
|
||||||
};
|
};
|
||||||
|
|
||||||
// unit contains the units for the bytePlotter.
|
// unit contains the units for the bytePlotter.
|
||||||
const unit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
const unit = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
|
||||||
|
|
||||||
// simplifyBytes returns the simplified version of the given value followed by the unit.
|
// simplifyBytes returns the simplified version of the given value followed by the unit.
|
||||||
const simplifyBytes = (x: number) => {
|
const simplifyBytes = (x: number) => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (; x > 1024 && i < 5; i++) {
|
for (; x > 1024 && i < 8; i++) {
|
||||||
x /= 1024;
|
x /= 1024;
|
||||||
}
|
}
|
||||||
return x.toFixed(2).toString().concat(' ', unit[i]);
|
return x.toFixed(2).toString().concat(' ', unit[i], 'B');
|
||||||
};
|
};
|
||||||
|
|
||||||
// bytePlotter renders a tooltip, which displays the payload as a byte value.
|
// bytePlotter renders a tooltip, which displays the payload as a byte value.
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,11 @@ const defaultContent: Content = {
|
||||||
version: null,
|
version: null,
|
||||||
commit: null,
|
commit: null,
|
||||||
},
|
},
|
||||||
home: {
|
home: {},
|
||||||
|
chain: {},
|
||||||
|
txpool: {},
|
||||||
|
network: {},
|
||||||
|
system: {
|
||||||
activeMemory: [],
|
activeMemory: [],
|
||||||
virtualMemory: [],
|
virtualMemory: [],
|
||||||
networkIngress: [],
|
networkIngress: [],
|
||||||
|
|
@ -91,10 +95,6 @@ const defaultContent: Content = {
|
||||||
diskRead: [],
|
diskRead: [],
|
||||||
diskWrite: [],
|
diskWrite: [],
|
||||||
},
|
},
|
||||||
chain: {},
|
|
||||||
txpool: {},
|
|
||||||
network: {},
|
|
||||||
system: {},
|
|
||||||
logs: {
|
logs: {
|
||||||
log: [],
|
log: [],
|
||||||
},
|
},
|
||||||
|
|
@ -108,7 +108,11 @@ const updaters = {
|
||||||
version: replacer,
|
version: replacer,
|
||||||
commit: replacer,
|
commit: replacer,
|
||||||
},
|
},
|
||||||
home: {
|
home: null,
|
||||||
|
chain: null,
|
||||||
|
txpool: null,
|
||||||
|
network: null,
|
||||||
|
system: {
|
||||||
activeMemory: appender(200),
|
activeMemory: appender(200),
|
||||||
virtualMemory: appender(200),
|
virtualMemory: appender(200),
|
||||||
networkIngress: appender(200),
|
networkIngress: appender(200),
|
||||||
|
|
@ -118,11 +122,7 @@ const updaters = {
|
||||||
diskRead: appender(200),
|
diskRead: appender(200),
|
||||||
diskWrite: appender(200),
|
diskWrite: appender(200),
|
||||||
},
|
},
|
||||||
chain: null,
|
logs: {
|
||||||
txpool: null,
|
|
||||||
network: null,
|
|
||||||
system: null,
|
|
||||||
logs: {
|
|
||||||
log: appender(200),
|
log: appender(200),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -136,7 +136,7 @@ const styles = {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// themeStyles returns the styles generated from the theme for the component.
|
// themeStyles returns the styles generated from the theme for the component.
|
||||||
|
|
@ -178,7 +178,8 @@ class Dashboard extends Component<Props, State> {
|
||||||
// reconnect establishes a websocket connection with the server, listens for incoming messages
|
// reconnect establishes a websocket connection with the server, listens for incoming messages
|
||||||
// and tries to reconnect on connection loss.
|
// and tries to reconnect on connection loss.
|
||||||
reconnect = () => {
|
reconnect = () => {
|
||||||
const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://') + window.location.host}/api`);
|
// PROD is defined by webpack.
|
||||||
|
const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://')}${PROD ? window.location.host : 'localhost:8080'}/api`);
|
||||||
server.onopen = () => {
|
server.onopen = () => {
|
||||||
this.setState({content: defaultContent, shouldUpdate: {}});
|
this.setState({content: defaultContent, shouldUpdate: {}});
|
||||||
};
|
};
|
||||||
|
|
@ -217,7 +218,6 @@ class Dashboard extends Component<Props, State> {
|
||||||
return (
|
return (
|
||||||
<div className={this.props.classes.dashboard} style={styles.dashboard}>
|
<div className={this.props.classes.dashboard} style={styles.dashboard}>
|
||||||
<Header
|
<Header
|
||||||
opened={this.state.sideBar}
|
|
||||||
switchSideBar={this.switchSideBar}
|
switchSideBar={this.switchSideBar}
|
||||||
/>
|
/>
|
||||||
<Body
|
<Body
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,17 @@ import {ResponsiveContainer, AreaChart, Area, Tooltip} from 'recharts';
|
||||||
import ChartRow from './ChartRow';
|
import ChartRow from './ChartRow';
|
||||||
import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from './CustomTooltip';
|
import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from './CustomTooltip';
|
||||||
import {styles as commonStyles} from '../common';
|
import {styles as commonStyles} from '../common';
|
||||||
import type {Content} from '../types/content';
|
import type {General, System} from '../types/content';
|
||||||
|
|
||||||
|
const FOOTER_SYNC_ID = 'footerSyncId';
|
||||||
|
|
||||||
|
const CPU = 'cpu';
|
||||||
|
const MEMORY = 'memory';
|
||||||
|
const DISK = 'disk';
|
||||||
|
const TRAFFIC = 'traffic';
|
||||||
|
|
||||||
|
const TOP = 'Top';
|
||||||
|
const BOTTOM = 'Bottom';
|
||||||
|
|
||||||
// styles contains the constant styles of the component.
|
// styles contains the constant styles of the component.
|
||||||
const styles = {
|
const styles = {
|
||||||
|
|
@ -40,17 +50,16 @@ const styles = {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
},
|
},
|
||||||
doubleChartWrapper: {
|
doubleChartWrapper: {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
width: '99%',
|
width: '99%',
|
||||||
paddingTop: 5,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// themeStyles returns the styles generated from the theme for the component.
|
// themeStyles returns the styles generated from the theme for the component.
|
||||||
const themeStyles: Object = (theme: Object) => ({
|
const themeStyles: Object = (theme: Object) => ({
|
||||||
footer: {
|
footer: {
|
||||||
backgroundColor: theme.palette.background.appBar,
|
backgroundColor: theme.palette.grey[900],
|
||||||
color: theme.palette.getContrastText(theme.palette.background.appBar),
|
color: theme.palette.getContrastText(theme.palette.grey[900]),
|
||||||
zIndex: theme.zIndex.appBar,
|
zIndex: theme.zIndex.appBar,
|
||||||
height: theme.spacing.unit * 10,
|
height: theme.spacing.unit * 10,
|
||||||
},
|
},
|
||||||
|
|
@ -59,111 +68,108 @@ const themeStyles: Object = (theme: Object) => ({
|
||||||
export type Props = {
|
export type Props = {
|
||||||
classes: Object, // injected by withStyles()
|
classes: Object, // injected by withStyles()
|
||||||
theme: Object,
|
theme: Object,
|
||||||
content: Content,
|
general: General,
|
||||||
|
system: System,
|
||||||
shouldUpdate: Object,
|
shouldUpdate: Object,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Footer renders the footer of the dashboard.
|
// Footer renders the footer of the dashboard.
|
||||||
class Footer extends Component<Props> {
|
class Footer extends Component<Props> {
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
return typeof nextProps.shouldUpdate.home !== 'undefined';
|
return typeof nextProps.shouldUpdate.general !== 'undefined' || typeof nextProps.shouldUpdate.system !== 'undefined';
|
||||||
}
|
}
|
||||||
|
|
||||||
// info renders a label with the given values.
|
// halfHeightChart renders an area chart with half of the height of its parent.
|
||||||
info = (about: string, value: ?string) => (value ? (
|
halfHeightChart = (chartProps, tooltip, areaProps) => (
|
||||||
<Typography type='caption' color='inherit'>
|
<ResponsiveContainer width='100%' height='50%'>
|
||||||
<span style={commonStyles.light}>{about}</span> {value}
|
<AreaChart {...chartProps} >
|
||||||
</Typography>
|
{!tooltip || (<Tooltip cursor={false} content={<CustomTooltip tooltip={tooltip} />} />)}
|
||||||
) : null);
|
<Area isAnimationActive={false} type='monotone' {...areaProps} />
|
||||||
|
</AreaChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
);
|
||||||
|
|
||||||
// doubleChart renders a pair of charts separated by the baseline.
|
// doubleChart renders a pair of charts separated by the baseline.
|
||||||
doubleChart = (syncId, topChart, bottomChart) => {
|
doubleChart = (syncId, chartKey, topChart, bottomChart) => {
|
||||||
const topKey = 'topKey';
|
if (!Array.isArray(topChart.data) || !Array.isArray(bottomChart.data)) {
|
||||||
const bottomKey = 'bottomKey';
|
return null;
|
||||||
const topDefault = topChart.default ? topChart.default : 0;
|
}
|
||||||
const bottomDefault = bottomChart.default ? bottomChart.default : 0;
|
const topDefault = topChart.default || 0;
|
||||||
const topTooltip = topChart.tooltip ? (
|
const bottomDefault = bottomChart.default || 0;
|
||||||
<Tooltip cursor={false} content={<CustomTooltip tooltip={topChart.tooltip} />} />
|
const topKey = `${chartKey}${TOP}`;
|
||||||
) : null;
|
const bottomKey = `${chartKey}${BOTTOM}`;
|
||||||
const bottomTooltip = bottomChart.tooltip ? (
|
|
||||||
<Tooltip cursor={false} content={<CustomTooltip tooltip={bottomChart.tooltip} />} />
|
|
||||||
) : null;
|
|
||||||
const topColor = '#8884d8';
|
const topColor = '#8884d8';
|
||||||
const bottomColor = '#82ca9d';
|
const bottomColor = '#82ca9d';
|
||||||
|
|
||||||
// Put the samples of the two charts into the same array in order to avoid problems
|
|
||||||
// at the synchronized area charts. If one of the two arrays doesn't have value at
|
|
||||||
// a given position, give it a 0 default value.
|
|
||||||
let data = [...topChart.data.map(({value}) => {
|
|
||||||
const d = {};
|
|
||||||
d[topKey] = value || topDefault;
|
|
||||||
return d;
|
|
||||||
})];
|
|
||||||
for (let i = 0; i < data.length && i < bottomChart.data.length; i++) {
|
|
||||||
// The value needs to be negative in order to plot it upside down.
|
|
||||||
const d = bottomChart.data[i];
|
|
||||||
data[i][bottomKey] = d && d.value ? -d.value : bottomDefault;
|
|
||||||
}
|
|
||||||
data = [...data, ...bottomChart.data.slice(data.length).map(({value}) => {
|
|
||||||
const d = {};
|
|
||||||
d[topKey] = topDefault;
|
|
||||||
d[bottomKey] = -value || bottomDefault;
|
|
||||||
return d;
|
|
||||||
})];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={styles.doubleChartWrapper}>
|
<div style={styles.doubleChartWrapper}>
|
||||||
<ResponsiveContainer width='100%' height='50%'>
|
{this.halfHeightChart(
|
||||||
<AreaChart data={data} syncId={syncId} >
|
{
|
||||||
{topTooltip}
|
syncId,
|
||||||
<Area type='monotone' dataKey={topKey} stroke={topColor} fill={topColor} />
|
data: topChart.data.map(({value}) => ({[topKey]: value || topDefault})),
|
||||||
</AreaChart>
|
margin: {top: 5, right: 5, bottom: 0, left: 5},
|
||||||
</ResponsiveContainer>
|
},
|
||||||
<div style={{marginTop: -10, width: '100%', height: '50%'}}>
|
topChart.tooltip,
|
||||||
<ResponsiveContainer width='100%' height='100%'>
|
{dataKey: topKey, stroke: topColor, fill: topColor},
|
||||||
<AreaChart data={data} syncId={syncId} >
|
)}
|
||||||
{bottomTooltip}
|
{this.halfHeightChart(
|
||||||
<Area type='monotone' dataKey={bottomKey} stroke={bottomColor} fill={bottomColor} />
|
{
|
||||||
</AreaChart>
|
syncId,
|
||||||
</ResponsiveContainer>
|
data: bottomChart.data.map(({value}) => ({[bottomKey]: -value || -bottomDefault})),
|
||||||
</div>
|
margin: {top: 0, right: 5, bottom: 5, left: 5},
|
||||||
|
},
|
||||||
|
bottomChart.tooltip,
|
||||||
|
{dataKey: bottomKey, stroke: bottomColor, fill: bottomColor},
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {content} = this.props;
|
const {general, system} = this.props;
|
||||||
const {general, home} = content;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}>
|
<Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}>
|
||||||
<Grid item xs style={styles.chartRowWrapper}>
|
<Grid item xs style={styles.chartRowWrapper}>
|
||||||
<ChartRow>
|
<ChartRow>
|
||||||
{this.doubleChart(
|
{this.doubleChart(
|
||||||
'all',
|
FOOTER_SYNC_ID,
|
||||||
{data: home.processCPU, tooltip: percentPlotter('Process')},
|
CPU,
|
||||||
{data: home.systemCPU, tooltip: percentPlotter('System', multiplier(-1))},
|
{data: system.processCPU, tooltip: percentPlotter('Process load')},
|
||||||
|
{data: system.systemCPU, tooltip: percentPlotter('System load', multiplier(-1))},
|
||||||
)}
|
)}
|
||||||
{this.doubleChart(
|
{this.doubleChart(
|
||||||
'all',
|
FOOTER_SYNC_ID,
|
||||||
{data: home.activeMemory, tooltip: bytePlotter('Active')},
|
MEMORY,
|
||||||
{data: home.virtualMemory, tooltip: bytePlotter('Virtual', multiplier(-1))},
|
{data: system.activeMemory, tooltip: bytePlotter('Active memory')},
|
||||||
|
{data: system.virtualMemory, tooltip: bytePlotter('Virtual memory', multiplier(-1))},
|
||||||
)}
|
)}
|
||||||
{this.doubleChart(
|
{this.doubleChart(
|
||||||
'all',
|
FOOTER_SYNC_ID,
|
||||||
{data: home.diskRead, tooltip: bytePerSecPlotter('Disk Read')},
|
DISK,
|
||||||
{data: home.diskWrite, tooltip: bytePerSecPlotter('Disk Write', multiplier(-1))},
|
{data: system.diskRead, tooltip: bytePerSecPlotter('Disk read')},
|
||||||
|
{data: system.diskWrite, tooltip: bytePerSecPlotter('Disk write', multiplier(-1))},
|
||||||
)}
|
)}
|
||||||
{this.doubleChart(
|
{this.doubleChart(
|
||||||
'all',
|
FOOTER_SYNC_ID,
|
||||||
{data: home.networkIngress, tooltip: bytePerSecPlotter('Download')},
|
TRAFFIC,
|
||||||
{data: home.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))},
|
{data: system.networkIngress, tooltip: bytePerSecPlotter('Download')},
|
||||||
|
{data: system.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))},
|
||||||
)}
|
)}
|
||||||
</ChartRow>
|
</ChartRow>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item >
|
<Grid item >
|
||||||
{this.info('Geth', general.version)}
|
<Typography type='caption' color='inherit'>
|
||||||
{this.info('Commit', general.commit ? general.commit.substring(0, 7) : null)}
|
<span style={commonStyles.light}>Geth</span> {general.version}
|
||||||
|
</Typography>
|
||||||
|
{general.commit && (
|
||||||
|
<Typography type='caption' color='inherit'>
|
||||||
|
<span style={commonStyles.light}>{'Commit '}</span>
|
||||||
|
<a href={`https://github.com/EthereumCommonwealth/go-callisto/commit/${general.commit}`} target='_blank' style={{color: 'inherit', textDecoration: 'none'}} >
|
||||||
|
{general.commit.substring(0, 8)}
|
||||||
|
</a>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -21,30 +21,16 @@ import React, {Component} from 'react';
|
||||||
import withStyles from 'material-ui/styles/withStyles';
|
import withStyles from 'material-ui/styles/withStyles';
|
||||||
import AppBar from 'material-ui/AppBar';
|
import AppBar from 'material-ui/AppBar';
|
||||||
import Toolbar from 'material-ui/Toolbar';
|
import Toolbar from 'material-ui/Toolbar';
|
||||||
import Transition from 'react-transition-group/Transition';
|
|
||||||
import IconButton from 'material-ui/IconButton';
|
import IconButton from 'material-ui/IconButton';
|
||||||
|
import Icon from 'material-ui/Icon';
|
||||||
|
import MenuIcon from 'material-ui-icons/Menu';
|
||||||
import Typography from 'material-ui/Typography';
|
import Typography from 'material-ui/Typography';
|
||||||
import ChevronLeftIcon from 'material-ui-icons/ChevronLeft';
|
|
||||||
|
|
||||||
import {DURATION} from '../common';
|
|
||||||
|
|
||||||
// styles contains the constant styles of the component.
|
|
||||||
const styles = {
|
|
||||||
arrow: {
|
|
||||||
default: {
|
|
||||||
transition: `transform ${DURATION}ms`,
|
|
||||||
},
|
|
||||||
transition: {
|
|
||||||
entered: {transform: 'rotate(180deg)'},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// themeStyles returns the styles generated from the theme for the component.
|
// themeStyles returns the styles generated from the theme for the component.
|
||||||
const themeStyles = (theme: Object) => ({
|
const themeStyles = (theme: Object) => ({
|
||||||
header: {
|
header: {
|
||||||
backgroundColor: theme.palette.background.appBar,
|
backgroundColor: theme.palette.grey[900],
|
||||||
color: theme.palette.getContrastText(theme.palette.background.appBar),
|
color: theme.palette.getContrastText(theme.palette.grey[900]),
|
||||||
zIndex: theme.zIndex.appBar,
|
zIndex: theme.zIndex.appBar,
|
||||||
},
|
},
|
||||||
toolbar: {
|
toolbar: {
|
||||||
|
|
@ -53,42 +39,28 @@ const themeStyles = (theme: Object) => ({
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
paddingLeft: theme.spacing.unit,
|
paddingLeft: theme.spacing.unit,
|
||||||
|
fontSize: 3 * theme.spacing.unit,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
classes: Object, // injected by withStyles()
|
classes: Object, // injected by withStyles()
|
||||||
opened: boolean,
|
|
||||||
switchSideBar: () => void,
|
switchSideBar: () => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Header renders the header of the dashboard.
|
// Header renders the header of the dashboard.
|
||||||
class Header extends Component<Props> {
|
class Header extends Component<Props> {
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
return nextProps.opened !== this.props.opened;
|
|
||||||
}
|
|
||||||
|
|
||||||
// arrow renders a button, which changes the sidebar's state.
|
|
||||||
arrow = (transitionState: string) => (
|
|
||||||
<IconButton onClick={this.props.switchSideBar}>
|
|
||||||
<ChevronLeftIcon
|
|
||||||
style={{
|
|
||||||
...styles.arrow.default,
|
|
||||||
...styles.arrow.transition[transitionState],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
);
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {classes, opened} = this.props;
|
const {classes} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar position='static' className={classes.header}>
|
<AppBar position='static' className={classes.header}>
|
||||||
<Toolbar className={classes.toolbar}>
|
<Toolbar className={classes.toolbar}>
|
||||||
<Transition mountOnEnter in={opened} timeout={{enter: DURATION}}>
|
<IconButton onClick={this.props.switchSideBar}>
|
||||||
{this.arrow}
|
<Icon>
|
||||||
</Transition>
|
<MenuIcon />
|
||||||
|
</Icon>
|
||||||
|
</IconButton>
|
||||||
<Typography type='title' color='inherit' noWrap className={classes.title}>
|
<Typography type='title' color='inherit' noWrap className={classes.title}>
|
||||||
Go Ethereum Dashboard
|
Go Ethereum Dashboard
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,8 @@ class Main extends Component<Props> {
|
||||||
<div style={styles.wrapper}>
|
<div style={styles.wrapper}>
|
||||||
<div className={classes.content} style={styles.content}>{children}</div>
|
<div className={classes.content} style={styles.content}>{children}</div>
|
||||||
<Footer
|
<Footer
|
||||||
content={content}
|
general={content.general}
|
||||||
|
system={content.system}
|
||||||
shouldUpdate={shouldUpdate}
|
shouldUpdate={shouldUpdate}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ const styles = {
|
||||||
// themeStyles returns the styles generated from the theme for the component.
|
// themeStyles returns the styles generated from the theme for the component.
|
||||||
const themeStyles = theme => ({
|
const themeStyles = theme => ({
|
||||||
list: {
|
list: {
|
||||||
background: theme.palette.background.appBar,
|
background: theme.palette.grey[900],
|
||||||
},
|
},
|
||||||
listItem: {
|
listItem: {
|
||||||
minWidth: theme.spacing.unit * 3,
|
minWidth: theme.spacing.unit * 7,
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
fontSize: theme.spacing.unit * 3,
|
fontSize: theme.spacing.unit * 3,
|
||||||
|
|
|
||||||
7678
dashboard/assets/package-lock.json
generated
7678
dashboard/assets/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -15,11 +15,11 @@
|
||||||
"css-loader": "^0.28.9",
|
"css-loader": "^0.28.9",
|
||||||
"eslint": "^4.16.0",
|
"eslint": "^4.16.0",
|
||||||
"eslint-config-airbnb": "^16.1.0",
|
"eslint-config-airbnb": "^16.1.0",
|
||||||
"eslint-loader": "^1.9.0",
|
"eslint-loader": "^2.0.0",
|
||||||
|
"eslint-plugin-flowtype": "^2.41.0",
|
||||||
"eslint-plugin-import": "^2.8.0",
|
"eslint-plugin-import": "^2.8.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||||
"eslint-plugin-react": "^7.5.1",
|
"eslint-plugin-react": "^7.5.1",
|
||||||
"eslint-plugin-flowtype": "^2.41.0",
|
|
||||||
"file-loader": "^1.1.6",
|
"file-loader": "^1.1.6",
|
||||||
"flow-bin": "^0.63.1",
|
"flow-bin": "^0.63.1",
|
||||||
"flow-bin-loader": "^1.0.2",
|
"flow-bin-loader": "^1.0.2",
|
||||||
|
|
@ -35,6 +35,13 @@
|
||||||
"style-loader": "^0.19.1",
|
"style-loader": "^0.19.1",
|
||||||
"url": "^0.11.0",
|
"url": "^0.11.0",
|
||||||
"url-loader": "^0.6.2",
|
"url-loader": "^0.6.2",
|
||||||
"webpack": "^3.10.0"
|
"webpack": "^3.10.0",
|
||||||
|
"webpack-dev-server": "^2.11.1"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "NODE_ENV=production webpack",
|
||||||
|
"stats": "webpack --profile --json > stats.json",
|
||||||
|
"dev": "webpack-dev-server --port 8081",
|
||||||
|
"flow": "flow-typed install"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,22 +26,6 @@ export type Content = {
|
||||||
logs: Logs,
|
logs: Logs,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type General = {
|
|
||||||
version: ?string,
|
|
||||||
commit: ?string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Home = {
|
|
||||||
activeMemory: ChartEntries,
|
|
||||||
virtualMemory: ChartEntries,
|
|
||||||
networkIngress: ChartEntries,
|
|
||||||
networkEgress: ChartEntries,
|
|
||||||
processCPU: ChartEntries,
|
|
||||||
systemCPU: ChartEntries,
|
|
||||||
diskRead: ChartEntries,
|
|
||||||
diskWrite: ChartEntries,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ChartEntries = Array<ChartEntry>;
|
export type ChartEntries = Array<ChartEntry>;
|
||||||
|
|
||||||
export type ChartEntry = {
|
export type ChartEntry = {
|
||||||
|
|
@ -49,6 +33,15 @@ export type ChartEntry = {
|
||||||
value: number,
|
value: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type General = {
|
||||||
|
version: ?string,
|
||||||
|
commit: ?string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Home = {
|
||||||
|
/* TODO (kurkomisi) */
|
||||||
|
};
|
||||||
|
|
||||||
export type Chain = {
|
export type Chain = {
|
||||||
/* TODO (kurkomisi) */
|
/* TODO (kurkomisi) */
|
||||||
};
|
};
|
||||||
|
|
@ -62,7 +55,14 @@ export type Network = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type System = {
|
export type System = {
|
||||||
/* TODO (kurkomisi) */
|
activeMemory: ChartEntries,
|
||||||
|
virtualMemory: ChartEntries,
|
||||||
|
networkIngress: ChartEntries,
|
||||||
|
networkEgress: ChartEntries,
|
||||||
|
processCPU: ChartEntries,
|
||||||
|
systemCPU: ChartEntries,
|
||||||
|
diskRead: ChartEntries,
|
||||||
|
diskWrite: ChartEntries,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Logs = {
|
export type Logs = {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ module.exports = {
|
||||||
mangle: false,
|
mangle: false,
|
||||||
beautify: true,
|
beautify: true,
|
||||||
}),
|
}),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
PROD: process.env.NODE_ENV === 'production',
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
|
|
||||||
6551
dashboard/assets/yarn.lock
Normal file
6551
dashboard/assets/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -38,8 +38,4 @@ type Config struct {
|
||||||
|
|
||||||
// Refresh is the refresh rate of the data updates, the chartEntry will be collected this often.
|
// Refresh is the refresh rate of the data updates, the chartEntry will be collected this often.
|
||||||
Refresh time.Duration `toml:",omitempty"`
|
Refresh time.Duration `toml:",omitempty"`
|
||||||
|
|
||||||
// Assets offers a possibility to manually set the dashboard website's location on the server side.
|
|
||||||
// It is useful for debugging, avoids the repeated generation of the binary.
|
|
||||||
Assets string `toml:",omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,17 @@
|
||||||
|
|
||||||
package dashboard
|
package dashboard
|
||||||
|
|
||||||
//go:generate npm --prefix ./assets install
|
//go:generate yarn --cwd ./assets install
|
||||||
//go:generate ./assets/node_modules/.bin/webpack --config ./assets/webpack.config.js --context ./assets
|
//go:generate yarn --cwd ./assets build
|
||||||
//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/dashboard.html assets/bundle.js
|
//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/index.html assets/bundle.js
|
||||||
//go:generate sh -c "sed 's#var _bundleJs#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
//go:generate sh -c "sed 's#var _bundleJs#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
||||||
//go:generate sh -c "sed 's#var _dashboardHtml#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
//go:generate sh -c "sed 's#var _indexHtml#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
||||||
//go:generate gofmt -w -s assets.go
|
//go:generate gofmt -w -s assets.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
@ -62,7 +60,7 @@ type Dashboard struct {
|
||||||
|
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
conns map[uint32]*client // Currently live websocket connections
|
conns map[uint32]*client // Currently live websocket connections
|
||||||
charts *HomeMessage
|
charts *SystemMessage
|
||||||
commit string
|
commit string
|
||||||
lock sync.RWMutex // Lock protecting the dashboard's internals
|
lock sync.RWMutex // Lock protecting the dashboard's internals
|
||||||
|
|
||||||
|
|
@ -84,7 +82,7 @@ func New(config *Config, commit string) (*Dashboard, error) {
|
||||||
conns: make(map[uint32]*client),
|
conns: make(map[uint32]*client),
|
||||||
config: config,
|
config: config,
|
||||||
quit: make(chan chan error),
|
quit: make(chan chan error),
|
||||||
charts: &HomeMessage{
|
charts: &SystemMessage{
|
||||||
ActiveMemory: emptyChartEntries(now, activeMemorySampleLimit, config.Refresh),
|
ActiveMemory: emptyChartEntries(now, activeMemorySampleLimit, config.Refresh),
|
||||||
VirtualMemory: emptyChartEntries(now, virtualMemorySampleLimit, config.Refresh),
|
VirtualMemory: emptyChartEntries(now, virtualMemorySampleLimit, config.Refresh),
|
||||||
NetworkIngress: emptyChartEntries(now, networkIngressSampleLimit, config.Refresh),
|
NetworkIngress: emptyChartEntries(now, networkIngressSampleLimit, config.Refresh),
|
||||||
|
|
@ -180,18 +178,7 @@ func (db *Dashboard) webHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
path := r.URL.String()
|
path := r.URL.String()
|
||||||
if path == "/" {
|
if path == "/" {
|
||||||
path = "/dashboard.html"
|
path = "/index.html"
|
||||||
}
|
|
||||||
// If the path of the assets is manually set
|
|
||||||
if db.config.Assets != "" {
|
|
||||||
blob, err := ioutil.ReadFile(filepath.Join(db.config.Assets, path))
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("Failed to read file", "path", path, "err", err)
|
|
||||||
http.Error(w, "not found", http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Write(blob)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
blob, err := Asset(path[1:])
|
blob, err := Asset(path[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -241,7 +228,7 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) {
|
||||||
Version: fmt.Sprintf("v%d.%d.%d%s", params.VersionMajor, params.VersionMinor, params.VersionPatch, versionMeta),
|
Version: fmt.Sprintf("v%d.%d.%d%s", params.VersionMajor, params.VersionMinor, params.VersionPatch, versionMeta),
|
||||||
Commit: db.commit,
|
Commit: db.commit,
|
||||||
},
|
},
|
||||||
Home: &HomeMessage{
|
System: &SystemMessage{
|
||||||
ActiveMemory: db.charts.ActiveMemory,
|
ActiveMemory: db.charts.ActiveMemory,
|
||||||
VirtualMemory: db.charts.VirtualMemory,
|
VirtualMemory: db.charts.VirtualMemory,
|
||||||
NetworkIngress: db.charts.NetworkIngress,
|
NetworkIngress: db.charts.NetworkIngress,
|
||||||
|
|
@ -277,12 +264,14 @@ func (db *Dashboard) collectData() {
|
||||||
systemCPUUsage := gosigar.Cpu{}
|
systemCPUUsage := gosigar.Cpu{}
|
||||||
systemCPUUsage.Get()
|
systemCPUUsage.Get()
|
||||||
var (
|
var (
|
||||||
|
mem runtime.MemStats
|
||||||
|
|
||||||
prevNetworkIngress = metrics.DefaultRegistry.Get("p2p/InboundTraffic").(metrics.Meter).Count()
|
prevNetworkIngress = metrics.DefaultRegistry.Get("p2p/InboundTraffic").(metrics.Meter).Count()
|
||||||
prevNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
prevNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
||||||
prevProcessCPUTime = getProcessCPUTime()
|
prevProcessCPUTime = getProcessCPUTime()
|
||||||
prevSystemCPUUsage = systemCPUUsage
|
prevSystemCPUUsage = systemCPUUsage
|
||||||
prevDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/input").(metrics.Meter).Count()
|
prevDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/read").(metrics.Meter).Count()
|
||||||
prevDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/output").(metrics.Meter).Count()
|
prevDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/write").(metrics.Meter).Count()
|
||||||
|
|
||||||
frequency = float64(db.config.Refresh / time.Second)
|
frequency = float64(db.config.Refresh / time.Second)
|
||||||
numCPU = float64(runtime.NumCPU())
|
numCPU = float64(runtime.NumCPU())
|
||||||
|
|
@ -300,13 +289,13 @@ func (db *Dashboard) collectData() {
|
||||||
curNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
curNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
||||||
curProcessCPUTime = getProcessCPUTime()
|
curProcessCPUTime = getProcessCPUTime()
|
||||||
curSystemCPUUsage = systemCPUUsage
|
curSystemCPUUsage = systemCPUUsage
|
||||||
curDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/input").(metrics.Meter).Count()
|
curDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/read").(metrics.Meter).Count()
|
||||||
curDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/compact/output").(metrics.Meter).Count()
|
curDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/write").(metrics.Meter).Count()
|
||||||
|
|
||||||
deltaNetworkIngress = float64(curNetworkIngress - prevNetworkIngress)
|
deltaNetworkIngress = float64(curNetworkIngress - prevNetworkIngress)
|
||||||
deltaNetworkEgress = float64(curNetworkEgress - prevNetworkEgress)
|
deltaNetworkEgress = float64(curNetworkEgress - prevNetworkEgress)
|
||||||
deltaProcessCPUTime = curProcessCPUTime - prevProcessCPUTime
|
deltaProcessCPUTime = curProcessCPUTime - prevProcessCPUTime
|
||||||
deltaSystemCPUUsage = systemCPUUsage.Delta(prevSystemCPUUsage)
|
deltaSystemCPUUsage = curSystemCPUUsage.Delta(prevSystemCPUUsage)
|
||||||
deltaDiskRead = curDiskRead - prevDiskRead
|
deltaDiskRead = curDiskRead - prevDiskRead
|
||||||
deltaDiskWrite = curDiskWrite - prevDiskWrite
|
deltaDiskWrite = curDiskWrite - prevDiskWrite
|
||||||
)
|
)
|
||||||
|
|
@ -319,7 +308,6 @@ func (db *Dashboard) collectData() {
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
var mem runtime.MemStats
|
|
||||||
runtime.ReadMemStats(&mem)
|
runtime.ReadMemStats(&mem)
|
||||||
activeMemory := &ChartEntry{
|
activeMemory := &ChartEntry{
|
||||||
Time: now,
|
Time: now,
|
||||||
|
|
@ -363,7 +351,7 @@ func (db *Dashboard) collectData() {
|
||||||
db.charts.DiskWrite = append(db.charts.DiskRead[1:], diskWrite)
|
db.charts.DiskWrite = append(db.charts.DiskRead[1:], diskWrite)
|
||||||
|
|
||||||
db.sendToAll(&Message{
|
db.sendToAll(&Message{
|
||||||
Home: &HomeMessage{
|
System: &SystemMessage{
|
||||||
ActiveMemory: ChartEntries{activeMemory},
|
ActiveMemory: ChartEntries{activeMemory},
|
||||||
VirtualMemory: ChartEntries{virtualMemory},
|
VirtualMemory: ChartEntries{virtualMemory},
|
||||||
NetworkIngress: ChartEntries{networkIngress},
|
NetworkIngress: ChartEntries{networkIngress},
|
||||||
|
|
|
||||||
|
|
@ -28,27 +28,20 @@ type Message struct {
|
||||||
Logs *LogsMessage `json:"logs,omitempty"`
|
Logs *LogsMessage `json:"logs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChartEntries []*ChartEntry
|
||||||
|
|
||||||
|
type ChartEntry struct {
|
||||||
|
Time time.Time `json:"time,omitempty"`
|
||||||
|
Value float64 `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type GeneralMessage struct {
|
type GeneralMessage struct {
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version,omitempty"`
|
||||||
Commit string `json:"commit,omitempty"`
|
Commit string `json:"commit,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HomeMessage struct {
|
type HomeMessage struct {
|
||||||
ActiveMemory ChartEntries `json:"activeMemory,omitempty"`
|
/* TODO (kurkomisi) */
|
||||||
VirtualMemory ChartEntries `json:"virtualMemory,omitempty"`
|
|
||||||
NetworkIngress ChartEntries `json:"networkIngress,omitempty"`
|
|
||||||
NetworkEgress ChartEntries `json:"networkEgress,omitempty"`
|
|
||||||
ProcessCPU ChartEntries `json:"processCPU,omitempty"`
|
|
||||||
SystemCPU ChartEntries `json:"systemCPU,omitempty"`
|
|
||||||
DiskRead ChartEntries `json:"diskRead,omitempty"`
|
|
||||||
DiskWrite ChartEntries `json:"diskWrite,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChartEntries []*ChartEntry
|
|
||||||
|
|
||||||
type ChartEntry struct {
|
|
||||||
Time time.Time `json:"time,omitempty"`
|
|
||||||
Value float64 `json:"value,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainMessage struct {
|
type ChainMessage struct {
|
||||||
|
|
@ -64,7 +57,14 @@ type NetworkMessage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SystemMessage struct {
|
type SystemMessage struct {
|
||||||
/* TODO (kurkomisi) */
|
ActiveMemory ChartEntries `json:"activeMemory,omitempty"`
|
||||||
|
VirtualMemory ChartEntries `json:"virtualMemory,omitempty"`
|
||||||
|
NetworkIngress ChartEntries `json:"networkIngress,omitempty"`
|
||||||
|
NetworkEgress ChartEntries `json:"networkEgress,omitempty"`
|
||||||
|
ProcessCPU ChartEntries `json:"processCPU,omitempty"`
|
||||||
|
SystemCPU ChartEntries `json:"systemCPU,omitempty"`
|
||||||
|
DiskRead ChartEntries `json:"diskRead,omitempty"`
|
||||||
|
DiskWrite ChartEntries `json:"diskWrite,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogsMessage struct {
|
type LogsMessage struct {
|
||||||
|
|
|
||||||
|
|
@ -1296,6 +1296,14 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er
|
||||||
headers = headers[limit:]
|
headers = headers[limit:]
|
||||||
origin += uint64(limit)
|
origin += uint64(limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the highest block number we know if a higher one is found.
|
||||||
|
d.syncStatsLock.Lock()
|
||||||
|
if d.syncStatsChainHeight < origin {
|
||||||
|
d.syncStatsChainHeight = origin - 1
|
||||||
|
}
|
||||||
|
d.syncStatsLock.Unlock()
|
||||||
|
|
||||||
// Signal the content downloaders of the availablility of new tasks
|
// Signal the content downloaders of the availablility of new tasks
|
||||||
for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} {
|
for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} {
|
||||||
select {
|
select {
|
||||||
|
|
|
||||||
|
|
@ -633,7 +633,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert spawns a new goroutine to run a block insertion into the chain. If the
|
// insert spawns a new goroutine to run a block insertion into the chain. If the
|
||||||
// block's number is at the same height as the current import phase, if updates
|
// block's number is at the same height as the current import phase, it updates
|
||||||
// the phase states accordingly.
|
// the phase states accordingly.
|
||||||
func (f *Fetcher) insert(peer string, block *types.Block) {
|
func (f *Fetcher) insert(peer string, block *types.Block) {
|
||||||
hash := block.Hash()
|
hash := block.Hash()
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,14 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
|
||||||
atomic.StoreUint32(&pm.fastSync, 1)
|
atomic.StoreUint32(&pm.fastSync, 1)
|
||||||
mode = downloader.FastSync
|
mode = downloader.FastSync
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mode == downloader.FastSync {
|
||||||
|
// Make sure the peer's total difficulty we are synchronizing is higher.
|
||||||
|
if pm.blockchain.GetTdByHash(pm.blockchain.CurrentFastBlock().Hash()).Cmp(pTd) >= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Run the sync cycle, and disable fast sync if we've went past the pivot block
|
// Run the sync cycle, and disable fast sync if we've went past the pivot block
|
||||||
if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
|
if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/syndtr/goleveldb/leveldb/filter"
|
"github.com/syndtr/goleveldb/leveldb/filter"
|
||||||
"github.com/syndtr/goleveldb/leveldb/iterator"
|
"github.com/syndtr/goleveldb/leveldb/iterator"
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var OpenFileLimit = 64
|
var OpenFileLimit = 64
|
||||||
|
|
@ -37,15 +38,11 @@ type LDBDatabase struct {
|
||||||
fn string // filename for reporting
|
fn string // filename for reporting
|
||||||
db *leveldb.DB // LevelDB instance
|
db *leveldb.DB // LevelDB instance
|
||||||
|
|
||||||
getTimer metrics.Timer // Timer for measuring the database get request counts and latencies
|
|
||||||
putTimer metrics.Timer // Timer for measuring the database put request counts and latencies
|
|
||||||
delTimer metrics.Timer // Timer for measuring the database delete request counts and latencies
|
|
||||||
missMeter metrics.Meter // Meter for measuring the missed database get requests
|
|
||||||
readMeter metrics.Meter // Meter for measuring the database get request data usage
|
|
||||||
writeMeter metrics.Meter // Meter for measuring the database put request data usage
|
|
||||||
compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction
|
compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction
|
||||||
compReadMeter metrics.Meter // Meter for measuring the data read during compaction
|
compReadMeter metrics.Meter // Meter for measuring the data read during compaction
|
||||||
compWriteMeter metrics.Meter // Meter for measuring the data written during compaction
|
compWriteMeter metrics.Meter // Meter for measuring the data written during compaction
|
||||||
|
diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read
|
||||||
|
diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written
|
||||||
|
|
||||||
quitLock sync.Mutex // Mutex protecting the quit channel access
|
quitLock sync.Mutex // Mutex protecting the quit channel access
|
||||||
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
|
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
|
||||||
|
|
@ -94,16 +91,9 @@ func (db *LDBDatabase) Path() string {
|
||||||
|
|
||||||
// Put puts the given key / value to the queue
|
// Put puts the given key / value to the queue
|
||||||
func (db *LDBDatabase) Put(key []byte, value []byte) error {
|
func (db *LDBDatabase) Put(key []byte, value []byte) error {
|
||||||
// Measure the database put latency, if requested
|
|
||||||
if db.putTimer != nil {
|
|
||||||
defer db.putTimer.UpdateSince(time.Now())
|
|
||||||
}
|
|
||||||
// Generate the data to write to disk, update the meter and write
|
// Generate the data to write to disk, update the meter and write
|
||||||
//value = rle.Compress(value)
|
//value = rle.Compress(value)
|
||||||
|
|
||||||
if db.writeMeter != nil {
|
|
||||||
db.writeMeter.Mark(int64(len(value)))
|
|
||||||
}
|
|
||||||
return db.db.Put(key, value, nil)
|
return db.db.Put(key, value, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,32 +103,17 @@ func (db *LDBDatabase) Has(key []byte) (bool, error) {
|
||||||
|
|
||||||
// Get returns the given key if it's present.
|
// Get returns the given key if it's present.
|
||||||
func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
|
func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
|
||||||
// Measure the database get latency, if requested
|
|
||||||
if db.getTimer != nil {
|
|
||||||
defer db.getTimer.UpdateSince(time.Now())
|
|
||||||
}
|
|
||||||
// Retrieve the key and increment the miss counter if not found
|
// Retrieve the key and increment the miss counter if not found
|
||||||
dat, err := db.db.Get(key, nil)
|
dat, err := db.db.Get(key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if db.missMeter != nil {
|
|
||||||
db.missMeter.Mark(1)
|
|
||||||
}
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Otherwise update the actually retrieved amount of data
|
|
||||||
if db.readMeter != nil {
|
|
||||||
db.readMeter.Mark(int64(len(dat)))
|
|
||||||
}
|
|
||||||
return dat, nil
|
return dat, nil
|
||||||
//return rle.Decompress(dat)
|
//return rle.Decompress(dat)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete deletes the key from the queue and database
|
// Delete deletes the key from the queue and database
|
||||||
func (db *LDBDatabase) Delete(key []byte) error {
|
func (db *LDBDatabase) Delete(key []byte) error {
|
||||||
// Measure the database delete latency, if requested
|
|
||||||
if db.delTimer != nil {
|
|
||||||
defer db.delTimer.UpdateSince(time.Now())
|
|
||||||
}
|
|
||||||
// Execute the actual operation
|
// Execute the actual operation
|
||||||
return db.db.Delete(key, nil)
|
return db.db.Delete(key, nil)
|
||||||
}
|
}
|
||||||
|
|
@ -147,6 +122,11 @@ func (db *LDBDatabase) NewIterator() iterator.Iterator {
|
||||||
return db.db.NewIterator(nil, nil)
|
return db.db.NewIterator(nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewIteratorWithPrefix returns a iterator to iterate over subset of database content with a particular prefix.
|
||||||
|
func (db *LDBDatabase) NewIteratorWithPrefix(prefix []byte) iterator.Iterator {
|
||||||
|
return db.db.NewIterator(util.BytesPrefix(prefix), nil)
|
||||||
|
}
|
||||||
|
|
||||||
func (db *LDBDatabase) Close() {
|
func (db *LDBDatabase) Close() {
|
||||||
// Stop the metrics collection to avoid internal database races
|
// Stop the metrics collection to avoid internal database races
|
||||||
db.quitLock.Lock()
|
db.quitLock.Lock()
|
||||||
|
|
@ -178,15 +158,11 @@ func (db *LDBDatabase) Meter(prefix string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Initialize all the metrics collector at the requested prefix
|
// Initialize all the metrics collector at the requested prefix
|
||||||
db.getTimer = metrics.NewRegisteredTimer(prefix+"user/gets", nil)
|
|
||||||
db.putTimer = metrics.NewRegisteredTimer(prefix+"user/puts", nil)
|
|
||||||
db.delTimer = metrics.NewRegisteredTimer(prefix+"user/dels", nil)
|
|
||||||
db.missMeter = metrics.NewRegisteredMeter(prefix+"user/misses", nil)
|
|
||||||
db.readMeter = metrics.NewRegisteredMeter(prefix+"user/reads", nil)
|
|
||||||
db.writeMeter = metrics.NewRegisteredMeter(prefix+"user/writes", nil)
|
|
||||||
db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
|
db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
|
||||||
db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
|
db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
|
||||||
db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
|
db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
|
||||||
|
db.diskReadMeter = metrics.NewRegisteredMeter(prefix+"disk/read", nil)
|
||||||
|
db.diskWriteMeter = metrics.NewRegisteredMeter(prefix+"disk/write", nil)
|
||||||
|
|
||||||
// Create a quit channel for the periodic collector and run it
|
// Create a quit channel for the periodic collector and run it
|
||||||
db.quitLock.Lock()
|
db.quitLock.Lock()
|
||||||
|
|
@ -207,12 +183,17 @@ func (db *LDBDatabase) Meter(prefix string) {
|
||||||
// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294
|
// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294
|
||||||
// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884
|
// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884
|
||||||
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
|
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
|
||||||
|
//
|
||||||
|
// This is how the iostats look like (currently):
|
||||||
|
// Read(MB):3895.04860 Write(MB):3654.64712
|
||||||
func (db *LDBDatabase) meter(refresh time.Duration) {
|
func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
// Create the counters to store current and previous values
|
// Create the counters to store current and previous compaction values
|
||||||
counters := make([][]float64, 2)
|
compactions := make([][]float64, 2)
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
counters[i] = make([]float64, 3)
|
compactions[i] = make([]float64, 3)
|
||||||
}
|
}
|
||||||
|
// Create storage for iostats.
|
||||||
|
var iostats [2]float64
|
||||||
// Iterate ad infinitum and collect the stats
|
// Iterate ad infinitum and collect the stats
|
||||||
for i := 1; ; i++ {
|
for i := 1; ; i++ {
|
||||||
// Retrieve the database stats
|
// Retrieve the database stats
|
||||||
|
|
@ -233,8 +214,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
lines = lines[3:]
|
lines = lines[3:]
|
||||||
|
|
||||||
// Iterate over all the table rows, and accumulate the entries
|
// Iterate over all the table rows, and accumulate the entries
|
||||||
for j := 0; j < len(counters[i%2]); j++ {
|
for j := 0; j < len(compactions[i%2]); j++ {
|
||||||
counters[i%2][j] = 0
|
compactions[i%2][j] = 0
|
||||||
}
|
}
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
parts := strings.Split(line, "|")
|
parts := strings.Split(line, "|")
|
||||||
|
|
@ -247,19 +228,60 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
db.log.Error("Compaction entry parsing failed", "err", err)
|
db.log.Error("Compaction entry parsing failed", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
counters[i%2][idx] += value
|
compactions[i%2][idx] += value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update all the requested meters
|
// Update all the requested meters
|
||||||
if db.compTimeMeter != nil {
|
if db.compTimeMeter != nil {
|
||||||
db.compTimeMeter.Mark(int64((counters[i%2][0] - counters[(i-1)%2][0]) * 1000 * 1000 * 1000))
|
db.compTimeMeter.Mark(int64((compactions[i%2][0] - compactions[(i-1)%2][0]) * 1000 * 1000 * 1000))
|
||||||
}
|
}
|
||||||
if db.compReadMeter != nil {
|
if db.compReadMeter != nil {
|
||||||
db.compReadMeter.Mark(int64((counters[i%2][1] - counters[(i-1)%2][1]) * 1024 * 1024))
|
db.compReadMeter.Mark(int64((compactions[i%2][1] - compactions[(i-1)%2][1]) * 1024 * 1024))
|
||||||
}
|
}
|
||||||
if db.compWriteMeter != nil {
|
if db.compWriteMeter != nil {
|
||||||
db.compWriteMeter.Mark(int64((counters[i%2][2] - counters[(i-1)%2][2]) * 1024 * 1024))
|
db.compWriteMeter.Mark(int64((compactions[i%2][2] - compactions[(i-1)%2][2]) * 1024 * 1024))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve the database iostats.
|
||||||
|
ioStats, err := db.db.GetProperty("leveldb.iostats")
|
||||||
|
if err != nil {
|
||||||
|
db.log.Error("Failed to read database iostats", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parts := strings.Split(ioStats, " ")
|
||||||
|
if len(parts) < 2 {
|
||||||
|
db.log.Error("Bad syntax of ioStats", "ioStats", ioStats)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r := strings.Split(parts[0], ":")
|
||||||
|
if len(r) < 2 {
|
||||||
|
db.log.Error("Bad syntax of read entry", "entry", parts[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
read, err := strconv.ParseFloat(r[1], 64)
|
||||||
|
if err != nil {
|
||||||
|
db.log.Error("Read entry parsing failed", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w := strings.Split(parts[1], ":")
|
||||||
|
if len(w) < 2 {
|
||||||
|
db.log.Error("Bad syntax of write entry", "entry", parts[1])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
write, err := strconv.ParseFloat(w[1], 64)
|
||||||
|
if err != nil {
|
||||||
|
db.log.Error("Write entry parsing failed", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if db.diskReadMeter != nil {
|
||||||
|
db.diskReadMeter.Mark(int64((read - iostats[0]) * 1024 * 1024))
|
||||||
|
}
|
||||||
|
if db.diskWriteMeter != nil {
|
||||||
|
db.diskWriteMeter.Mark(int64((write - iostats[1]) * 1024 * 1024))
|
||||||
|
}
|
||||||
|
iostats[0] = read
|
||||||
|
iostats[1] = write
|
||||||
|
|
||||||
// Sleep a bit, then repeat the stats collection
|
// Sleep a bit, then repeat the stats collection
|
||||||
select {
|
select {
|
||||||
case errc := <-db.quitChan:
|
case errc := <-db.quitChan:
|
||||||
|
|
|
||||||
|
|
@ -1338,10 +1338,10 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
|
||||||
|
|
||||||
if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.From && signer.Hash(p) == wantSigHash {
|
if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.From && signer.Hash(p) == wantSigHash {
|
||||||
// Match. Re-sign and send the transaction.
|
// Match. Re-sign and send the transaction.
|
||||||
if gasPrice != nil {
|
if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 {
|
||||||
sendArgs.GasPrice = gasPrice
|
sendArgs.GasPrice = gasPrice
|
||||||
}
|
}
|
||||||
if gasLimit != nil {
|
if gasLimit != nil && *gasLimit != 0 {
|
||||||
sendArgs.Gas = gasLimit
|
sendArgs.Gas = gasLimit
|
||||||
}
|
}
|
||||||
signedTx, err := s.sign(sendArgs.From, sendArgs.toTransaction())
|
signedTx, err := s.sign(sendArgs.From, sendArgs.toTransaction())
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,9 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num
|
||||||
genesis := core.GetCanonicalHash(odr.Database(), 0)
|
genesis := core.GetCanonicalHash(odr.Database(), 0)
|
||||||
config, _ := core.GetChainConfig(odr.Database(), genesis)
|
config, _ := core.GetChainConfig(odr.Database(), genesis)
|
||||||
|
|
||||||
core.SetReceiptsData(config, block, receipts)
|
if err := core.SetReceiptsData(config, block, receipts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
core.WriteBlockReceipts(odr.Database(), hash, number, receipts)
|
core.WriteBlockReceipts(odr.Database(), hash, number, receipts)
|
||||||
}
|
}
|
||||||
return receipts, nil
|
return receipts, nil
|
||||||
|
|
|
||||||
|
|
@ -58,18 +58,18 @@ type trustedCheckpoint struct {
|
||||||
var (
|
var (
|
||||||
mainnetCheckpoint = trustedCheckpoint{
|
mainnetCheckpoint = trustedCheckpoint{
|
||||||
name: "mainnet",
|
name: "mainnet",
|
||||||
sectionIdx: 157,
|
sectionIdx: 161,
|
||||||
sectionHead: common.HexToHash("1963c080887ca7f406c2bb114293eea83e54f783f94df24b447f7e3b6317c747"),
|
sectionHead: common.HexToHash("75b0c4baa7a62cece48abdcb03b6f31601961c9bece67dcd61df87aad4fc0d8d"),
|
||||||
chtRoot: common.HexToHash("42abc436567dfb678a38fa6a9f881aa4c8a4cc8eaa2def08359292c3d0bd48ec"),
|
chtRoot: common.HexToHash("bbbfaa67b29716348997ec21a39c03b8d1fb973f6a43740b865595ba26ee812f"),
|
||||||
bloomTrieRoot: common.HexToHash("281c9f8fb3cb8b37ae45e9907ef8f3b19cd22c54e297c2d6c09c1db1593dce42"),
|
bloomTrieRoot: common.HexToHash("d6db6e6248354d7453391ce97830072a28ea4216be0bd95a5db9f53b1a64677b"),
|
||||||
}
|
}
|
||||||
|
|
||||||
ropstenCheckpoint = trustedCheckpoint{
|
ropstenCheckpoint = trustedCheckpoint{
|
||||||
name: "ropsten",
|
name: "ropsten",
|
||||||
sectionIdx: 83,
|
sectionIdx: 87,
|
||||||
sectionHead: common.HexToHash("3ca623586bc0da35f1fc8d9b6b55950f3b1f69be9c6501846a2df672adb61236"),
|
sectionHead: common.HexToHash("ebc0adcb30ed21cbe95bd77499cc1af0bada621fee3644cb80dbcf1444c123fe"),
|
||||||
chtRoot: common.HexToHash("8f08ec7783969768c6ef06e5fe3398223cbf4ae2907b676da7b6fe6c7f55b059"),
|
chtRoot: common.HexToHash("d9830f4893c821ddf149b8cb9d3e3bfe3109d2eea8e3c4a4ede7c8b2ee8a7800"),
|
||||||
bloomTrieRoot: common.HexToHash("02d86d3c6a87f8f8a92c2a59bbba2132ff6f9f61b0915a5dc28a9d8279219fd0"),
|
bloomTrieRoot: common.HexToHash("c76e12d713f65b84c5a36d06bc77d0c8419248ea0b36e0812a78b76aa6da0ddb"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,7 @@ out:
|
||||||
|
|
||||||
func (self *Miner) Start(coinbase common.Address) {
|
func (self *Miner) Start(coinbase common.Address) {
|
||||||
atomic.StoreInt32(&self.shouldStart, 1)
|
atomic.StoreInt32(&self.shouldStart, 1)
|
||||||
self.worker.setEtherbase(coinbase)
|
self.SetEtherbase(coinbase)
|
||||||
self.coinbase = coinbase
|
|
||||||
|
|
||||||
if atomic.LoadInt32(&self.canStart) == 0 {
|
if atomic.LoadInt32(&self.canStart) == 0 {
|
||||||
log.Info("Network syncing, will start miner afterwards")
|
log.Info("Network syncing, will start miner afterwards")
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import (
|
||||||
"github.com/EthereumCommonwealth/go-callisto/p2p"
|
"github.com/EthereumCommonwealth/go-callisto/p2p"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/p2p/nat"
|
"github.com/EthereumCommonwealth/go-callisto/p2p/nat"
|
||||||
"github.com/EthereumCommonwealth/go-callisto/params"
|
"github.com/EthereumCommonwealth/go-callisto/params"
|
||||||
whisper "github.com/EthereumCommonwealth/go-callisto/whisper/whisperv5"
|
whisper "github.com/EthereumCommonwealth/go-callisto/whisper/whisperv6"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeConfig represents the collection of configuration values to fine tune the Geth
|
// NodeConfig represents the collection of configuration values to fine tune the Geth
|
||||||
|
|
|
||||||
|
|
@ -491,7 +491,7 @@ func readHandshakeMsg(msg plainDecoder, plainSize int, prv *ecdsa.PrivateKey, r
|
||||||
}
|
}
|
||||||
// Attempt decoding pre-EIP-8 "plain" format.
|
// Attempt decoding pre-EIP-8 "plain" format.
|
||||||
key := ecies.ImportECDSA(prv)
|
key := ecies.ImportECDSA(prv)
|
||||||
if dec, err := key.Decrypt(rand.Reader, buf, nil, nil); err == nil {
|
if dec, err := key.Decrypt(buf, nil, nil); err == nil {
|
||||||
msg.decodePlain(dec)
|
msg.decodePlain(dec)
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
@ -505,7 +505,7 @@ func readHandshakeMsg(msg plainDecoder, plainSize int, prv *ecdsa.PrivateKey, r
|
||||||
if _, err := io.ReadFull(r, buf[plainSize:]); err != nil {
|
if _, err := io.ReadFull(r, buf[plainSize:]); err != nil {
|
||||||
return buf, err
|
return buf, err
|
||||||
}
|
}
|
||||||
dec, err := key.Decrypt(rand.Reader, buf[2:], nil, prefix)
|
dec, err := key.Decrypt(buf[2:], nil, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return buf, err
|
return buf, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VersionMajor = 1 // Major version component of the current release
|
VersionMajor = 1 // Major version component of the current release
|
||||||
VersionMinor = 8 // Minor version component of the current release
|
VersionMinor = 8 // Minor version component of the current release
|
||||||
VersionPatch = 2 // Patch version component of the current release
|
VersionPatch = 4 // Patch version component of the current release
|
||||||
VersionMeta = "stable" // Version metadata to append to the version string
|
VersionMeta = "unstable" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version holds the textual version string.
|
// Version holds the textual version string.
|
||||||
|
|
|
||||||
13
rpc/http.go
13
rpc/http.go
|
|
@ -27,16 +27,16 @@ import (
|
||||||
"mime"
|
"mime"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/cors"
|
"github.com/rs/cors"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
contentType = "application/json"
|
contentType = "application/json"
|
||||||
maxHTTPRequestContentLength = 1024 * 128
|
maxRequestContentLength = 1024 * 128
|
||||||
)
|
)
|
||||||
|
|
||||||
var nullAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:0")
|
var nullAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:0")
|
||||||
|
|
@ -169,7 +169,8 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
// All checks passed, create a codec that reads direct from the request body
|
// All checks passed, create a codec that reads direct from the request body
|
||||||
// untilEOF and writes the response to w and order the server to process a
|
// untilEOF and writes the response to w and order the server to process a
|
||||||
// single request.
|
// single request.
|
||||||
codec := NewJSONCodec(&httpReadWriteNopCloser{r.Body, w})
|
body := io.LimitReader(r.Body, maxRequestContentLength)
|
||||||
|
codec := NewJSONCodec(&httpReadWriteNopCloser{body, w})
|
||||||
defer codec.Close()
|
defer codec.Close()
|
||||||
|
|
||||||
w.Header().Set("content-type", contentType)
|
w.Header().Set("content-type", contentType)
|
||||||
|
|
@ -182,8 +183,8 @@ func validateRequest(r *http.Request) (int, error) {
|
||||||
if r.Method == http.MethodPut || r.Method == http.MethodDelete {
|
if r.Method == http.MethodPut || r.Method == http.MethodDelete {
|
||||||
return http.StatusMethodNotAllowed, errors.New("method not allowed")
|
return http.StatusMethodNotAllowed, errors.New("method not allowed")
|
||||||
}
|
}
|
||||||
if r.ContentLength > maxHTTPRequestContentLength {
|
if r.ContentLength > maxRequestContentLength {
|
||||||
err := fmt.Errorf("content length too large (%d>%d)", r.ContentLength, maxHTTPRequestContentLength)
|
err := fmt.Errorf("content length too large (%d>%d)", r.ContentLength, maxRequestContentLength)
|
||||||
return http.StatusRequestEntityTooLarge, err
|
return http.StatusRequestEntityTooLarge, err
|
||||||
}
|
}
|
||||||
mt, _, err := mime.ParseMediaType(r.Header.Get("content-type"))
|
mt, _, err := mime.ParseMediaType(r.Header.Get("content-type"))
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ func TestHTTPErrorResponseWithPut(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHTTPErrorResponseWithMaxContentLength(t *testing.T) {
|
func TestHTTPErrorResponseWithMaxContentLength(t *testing.T) {
|
||||||
body := make([]rune, maxHTTPRequestContentLength+1)
|
body := make([]rune, maxRequestContentLength+1)
|
||||||
testHTTPErrorResponse(t,
|
testHTTPErrorResponse(t,
|
||||||
http.MethodPost, contentType, string(body), http.StatusRequestEntityTooLarge)
|
http.MethodPost, contentType, string(body), http.StatusRequestEntityTooLarge)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
46
rpc/json.go
46
rpc/json.go
|
|
@ -76,13 +76,13 @@ type jsonNotification struct {
|
||||||
// jsonCodec reads and writes JSON-RPC messages to the underlying connection. It
|
// jsonCodec reads and writes JSON-RPC messages to the underlying connection. It
|
||||||
// also has support for parsing arguments and serializing (result) objects.
|
// also has support for parsing arguments and serializing (result) objects.
|
||||||
type jsonCodec struct {
|
type jsonCodec struct {
|
||||||
closer sync.Once // close closed channel once
|
closer sync.Once // close closed channel once
|
||||||
closed chan interface{} // closed on Close
|
closed chan interface{} // closed on Close
|
||||||
decMu sync.Mutex // guards d
|
decMu sync.Mutex // guards the decoder
|
||||||
d *json.Decoder // decodes incoming requests
|
decode func(v interface{}) error // decoder to allow multiple transports
|
||||||
encMu sync.Mutex // guards e
|
encMu sync.Mutex // guards the encoder
|
||||||
e *json.Encoder // encodes responses
|
encode func(v interface{}) error // encoder to allow multiple transports
|
||||||
rw io.ReadWriteCloser // connection
|
rw io.ReadWriteCloser // connection
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err *jsonError) Error() string {
|
func (err *jsonError) Error() string {
|
||||||
|
|
@ -96,11 +96,29 @@ func (err *jsonError) ErrorCode() int {
|
||||||
return err.Code
|
return err.Code
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewJSONCodec creates a new RPC server codec with support for JSON-RPC 2.0
|
// NewCodec creates a new RPC server codec with support for JSON-RPC 2.0 based
|
||||||
|
// on explicitly given encoding and decoding methods.
|
||||||
|
func NewCodec(rwc io.ReadWriteCloser, encode, decode func(v interface{}) error) ServerCodec {
|
||||||
|
return &jsonCodec{
|
||||||
|
closed: make(chan interface{}),
|
||||||
|
encode: encode,
|
||||||
|
decode: decode,
|
||||||
|
rw: rwc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewJSONCodec creates a new RPC server codec with support for JSON-RPC 2.0.
|
||||||
func NewJSONCodec(rwc io.ReadWriteCloser) ServerCodec {
|
func NewJSONCodec(rwc io.ReadWriteCloser) ServerCodec {
|
||||||
d := json.NewDecoder(rwc)
|
enc := json.NewEncoder(rwc)
|
||||||
d.UseNumber()
|
dec := json.NewDecoder(rwc)
|
||||||
return &jsonCodec{closed: make(chan interface{}), d: d, e: json.NewEncoder(rwc), rw: rwc}
|
dec.UseNumber()
|
||||||
|
|
||||||
|
return &jsonCodec{
|
||||||
|
closed: make(chan interface{}),
|
||||||
|
encode: enc.Encode,
|
||||||
|
decode: dec.Decode,
|
||||||
|
rw: rwc,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isBatch returns true when the first non-whitespace characters is '['
|
// isBatch returns true when the first non-whitespace characters is '['
|
||||||
|
|
@ -123,14 +141,12 @@ func (c *jsonCodec) ReadRequestHeaders() ([]rpcRequest, bool, Error) {
|
||||||
defer c.decMu.Unlock()
|
defer c.decMu.Unlock()
|
||||||
|
|
||||||
var incomingMsg json.RawMessage
|
var incomingMsg json.RawMessage
|
||||||
if err := c.d.Decode(&incomingMsg); err != nil {
|
if err := c.decode(&incomingMsg); err != nil {
|
||||||
return nil, false, &invalidRequestError{err.Error()}
|
return nil, false, &invalidRequestError{err.Error()}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isBatch(incomingMsg) {
|
if isBatch(incomingMsg) {
|
||||||
return parseBatchRequest(incomingMsg)
|
return parseBatchRequest(incomingMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseRequest(incomingMsg)
|
return parseRequest(incomingMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,7 +354,7 @@ func (c *jsonCodec) Write(res interface{}) error {
|
||||||
c.encMu.Lock()
|
c.encMu.Lock()
|
||||||
defer c.encMu.Unlock()
|
defer c.encMu.Unlock()
|
||||||
|
|
||||||
return c.e.Encode(res)
|
return c.encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the underlying connection
|
// Close the underlying connection
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,10 @@
|
||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -32,6 +34,23 @@ import (
|
||||||
"gopkg.in/fatih/set.v0"
|
"gopkg.in/fatih/set.v0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// websocketJSONCodec is a custom JSON codec with payload size enforcement and
|
||||||
|
// special number parsing.
|
||||||
|
var websocketJSONCodec = websocket.Codec{
|
||||||
|
// Marshal is the stock JSON marshaller used by the websocket library too.
|
||||||
|
Marshal: func(v interface{}) ([]byte, byte, error) {
|
||||||
|
msg, err := json.Marshal(v)
|
||||||
|
return msg, websocket.TextFrame, err
|
||||||
|
},
|
||||||
|
// Unmarshal is a specialized unmarshaller to properly convert numbers.
|
||||||
|
Unmarshal: func(msg []byte, payloadType byte, v interface{}) error {
|
||||||
|
dec := json.NewDecoder(bytes.NewReader(msg))
|
||||||
|
dec.UseNumber()
|
||||||
|
|
||||||
|
return dec.Decode(v)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// WebsocketHandler returns a handler that serves JSON-RPC to WebSocket connections.
|
// WebsocketHandler returns a handler that serves JSON-RPC to WebSocket connections.
|
||||||
//
|
//
|
||||||
// allowedOrigins should be a comma-separated list of allowed origin URLs.
|
// allowedOrigins should be a comma-separated list of allowed origin URLs.
|
||||||
|
|
@ -40,7 +59,16 @@ func (srv *Server) WebsocketHandler(allowedOrigins []string) http.Handler {
|
||||||
return websocket.Server{
|
return websocket.Server{
|
||||||
Handshake: wsHandshakeValidator(allowedOrigins),
|
Handshake: wsHandshakeValidator(allowedOrigins),
|
||||||
Handler: func(conn *websocket.Conn) {
|
Handler: func(conn *websocket.Conn) {
|
||||||
srv.ServeCodec(NewJSONCodec(conn), OptionMethodInvocation|OptionSubscriptions)
|
// Create a custom encode/decode pair to enforce payload size and number encoding
|
||||||
|
conn.MaxPayloadBytes = maxRequestContentLength
|
||||||
|
|
||||||
|
encoder := func(v interface{}) error {
|
||||||
|
return websocketJSONCodec.Send(conn, v)
|
||||||
|
}
|
||||||
|
decoder := func(v interface{}) error {
|
||||||
|
return websocketJSONCodec.Receive(conn, v)
|
||||||
|
}
|
||||||
|
srv.ServeCodec(NewCodec(conn, encoder, decoder), OptionMethodInvocation|OptionSubscriptions)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue