mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
Merge remote-tracking branch 'refs/remotes/ethereum/master' into rebase-1.5.9
This commit is contained in:
commit
5822644626
435 changed files with 22107 additions and 7895 deletions
59
.travis.yml
59
.travis.yml
|
|
@ -5,29 +5,38 @@ matrix:
|
||||||
include:
|
include:
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
go: 1.5.4
|
sudo: required
|
||||||
env:
|
|
||||||
- GO15VENDOREXPERIMENT=1
|
|
||||||
- os: linux
|
|
||||||
dist: trusty
|
|
||||||
go: 1.6.2
|
|
||||||
- os: linux
|
|
||||||
dist: trusty
|
|
||||||
go: 1.7.5
|
go: 1.7.5
|
||||||
|
script:
|
||||||
|
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install fuse
|
||||||
|
- sudo modprobe fuse
|
||||||
|
- sudo chmod 666 /dev/fuse
|
||||||
|
- sudo chown root:$USER /etc/fuse.conf
|
||||||
|
- go run build/ci.go install
|
||||||
|
- go run build/ci.go test -coverage
|
||||||
|
|
||||||
# These are the latest Go versions, only run go vet and misspell on these
|
# These are the latest Go versions.
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
|
sudo: required
|
||||||
go: 1.8
|
go: 1.8
|
||||||
script:
|
script:
|
||||||
|
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install fuse
|
||||||
|
- sudo modprobe fuse
|
||||||
|
- sudo chmod 666 /dev/fuse
|
||||||
|
- sudo chown root:$USER /etc/fuse.conf
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
- go run build/ci.go test -coverage -vet -misspell
|
- go run build/ci.go test -coverage -misspell
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.8
|
go: 1.8
|
||||||
|
sudo: required
|
||||||
script:
|
script:
|
||||||
|
- brew update
|
||||||
|
- brew install caskroom/cask/brew-cask
|
||||||
|
- brew cask install osxfuse
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
- go run build/ci.go test -coverage -vet -misspell
|
- go run build/ci.go test -coverage -misspell
|
||||||
|
|
||||||
# This builder does the Ubuntu PPA and Linux Azure uploads
|
# This builder does the Ubuntu PPA and Linux Azure uploads
|
||||||
- os: linux
|
- os: linux
|
||||||
|
|
@ -66,6 +75,32 @@ matrix:
|
||||||
# - CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64
|
# - CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64
|
||||||
# - go run build/ci.go archive -arch arm64 -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
|
||||||
|
|
||||||
|
# This builder does the Linux Azure MIPS xgo uploads
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
sudo: required
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
go: 1.8
|
||||||
|
env:
|
||||||
|
- azure-linux-mips
|
||||||
|
script:
|
||||||
|
- 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
|
||||||
|
- go run build/ci.go archive -arch mips -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
|
|
||||||
|
- go run build/ci.go xgo --alltools -- --targets=linux/mipsle --ldflags '-extldflags "-static"' -v
|
||||||
|
- for bin in build/bin/*-linux-mipsle; do mv -f "${bin}" "${bin/-linux-mipsle/}"; done
|
||||||
|
- go run build/ci.go archive -arch mipsle -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
|
|
||||||
|
- go run build/ci.go xgo --alltools -- --targets=linux/mips64 --ldflags '-extldflags "-static"' -v
|
||||||
|
- for bin in build/bin/*-linux-mips64; do mv -f "${bin}" "${bin/-linux-mips64/}"; done
|
||||||
|
- go run build/ci.go archive -arch mips64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
|
|
||||||
|
- go run build/ci.go xgo --alltools -- --targets=linux/mips64le --ldflags '-extldflags "-static"' -v
|
||||||
|
- for bin in build/bin/*-linux-mips64le; do mv -f "${bin}" "${bin/-linux-mips64le/}"; done
|
||||||
|
- go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
|
|
||||||
# This builder is a temporary fallback for building ARM64 while Go 1.8 is fixed
|
# This builder is a temporary fallback for building ARM64 while Go 1.8 is fixed
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
|
|
@ -131,7 +166,7 @@ matrix:
|
||||||
|
|
||||||
# Build the iOS framework and upload it to CocoaPods and Azure
|
# Build the iOS framework and upload it to CocoaPods and Azure
|
||||||
- gem uninstall cocoapods -a
|
- gem uninstall cocoapods -a
|
||||||
- gem install cocoapods --pre
|
- gem install cocoapods
|
||||||
|
|
||||||
- mv ~/.cocoapods/repos/master ~/.cocoapods/repos/master.bak
|
- mv ~/.cocoapods/repos/master ~/.cocoapods/repos/master.bak
|
||||||
- sed -i '.bak' 's/repo.join/!repo.join/g' $(dirname `gem which cocoapods`)/cocoapods/sources_manager.rb
|
- sed -i '.bak' 's/repo.join/!repo.join/g' $(dirname `gem which cocoapods`)/cocoapods/sources_manager.rb
|
||||||
|
|
|
||||||
43
Makefile
43
Makefile
|
|
@ -40,6 +40,15 @@ test: all
|
||||||
clean:
|
clean:
|
||||||
rm -fr build/_workspace/pkg/ $(GOBIN)/*
|
rm -fr build/_workspace/pkg/ $(GOBIN)/*
|
||||||
|
|
||||||
|
# The devtools target installs tools required for 'go generate'.
|
||||||
|
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
||||||
|
|
||||||
|
devtools:
|
||||||
|
go get -u golang.org/x/tools/cmd/stringer
|
||||||
|
go get -u github.com/jteeuwen/go-bindata/go-bindata
|
||||||
|
go get -u github.com/fjl/gencodec
|
||||||
|
go install ./cmd/abigen
|
||||||
|
|
||||||
# Cross Compilation Targets (xgo)
|
# Cross Compilation Targets (xgo)
|
||||||
|
|
||||||
gexp-cross: gexp-linux gexp-darwin gexp-windows gexp-android gexp-ios
|
gexp-cross: gexp-linux gexp-darwin gexp-windows gexp-android gexp-ios
|
||||||
|
|
@ -51,12 +60,12 @@ gexp-linux: gexp-linux-386 gexp-linux-amd64 gexp-linux-arm gexp-linux-mips64 gex
|
||||||
@ls -ld $(GOBIN)/gexp-linux-*
|
@ls -ld $(GOBIN)/gexp-linux-*
|
||||||
|
|
||||||
gexp-linux-386:
|
gexp-linux-386:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/386 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/386 -v ./cmd/gexp
|
||||||
@echo "Linux 386 cross compilation done:"
|
@echo "Linux 386 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-linux-* | grep 386
|
@ls -ld $(GOBIN)/gexp-linux-* | grep 386
|
||||||
|
|
||||||
gexp-linux-amd64:
|
gexp-linux-amd64:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/amd64 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/amd64 -v ./cmd/gexp
|
||||||
@echo "Linux amd64 cross compilation done:"
|
@echo "Linux amd64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-linux-* | grep amd64
|
@ls -ld $(GOBIN)/gexp-linux-* | grep amd64
|
||||||
|
|
||||||
|
|
@ -65,32 +74,42 @@ gexp-linux-arm: gexp-linux-arm-5 gexp-linux-arm-6 gexp-linux-arm-7 gexp-linux-ar
|
||||||
@ls -ld $(GOBIN)/gexp-linux-* | grep arm
|
@ls -ld $(GOBIN)/gexp-linux-* | grep arm
|
||||||
|
|
||||||
gexp-linux-arm-5:
|
gexp-linux-arm-5:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-5 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-5 -v ./cmd/gexp
|
||||||
@echo "Linux ARMv5 cross compilation done:"
|
@echo "Linux ARMv5 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-linux-* | grep arm-5
|
@ls -ld $(GOBIN)/gexp-linux-* | grep arm-5
|
||||||
|
|
||||||
gexp-linux-arm-6:
|
gexp-linux-arm-6:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-6 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-6 -v ./cmd/gexp
|
||||||
@echo "Linux ARMv6 cross compilation done:"
|
@echo "Linux ARMv6 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-linux-* | grep arm-6
|
@ls -ld $(GOBIN)/gexp-linux-* | grep arm-6
|
||||||
|
|
||||||
gexp-linux-arm-7:
|
gexp-linux-arm-7:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-7 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-7 -v ./cmd/gexp
|
||||||
@echo "Linux ARMv7 cross compilation done:"
|
@echo "Linux ARMv7 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-linux-* | grep arm-7
|
@ls -ld $(GOBIN)/gexp-linux-* | grep arm-7
|
||||||
|
|
||||||
gexp-linux-arm64:
|
gexp-linux-arm64:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm64 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm64 -v ./cmd/gexp
|
||||||
@echo "Linux ARM64 cross compilation done:"
|
@echo "Linux ARM64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-linux-* | grep arm64
|
@ls -ld $(GOBIN)/gexp-linux-* | grep arm64
|
||||||
|
|
||||||
|
gexp-linux-mips:
|
||||||
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips --ldflags '-extldflags "-static"' -v ./cmd/gexp
|
||||||
|
@echo "Linux MIPS cross compilation done:"
|
||||||
|
@ls -ld $(GOBIN)/gexp-linux-* | grep mips
|
||||||
|
|
||||||
|
gexp-linux-mipsle:
|
||||||
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mipsle --ldflags '-extldflags "-static"' -v ./cmd/gexp
|
||||||
|
@echo "Linux MIPSle cross compilation done:"
|
||||||
|
@ls -ld $(GOBIN)/gexp-linux-* | grep mipsle
|
||||||
|
|
||||||
gexp-linux-mips64:
|
gexp-linux-mips64:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/mips64 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64 --ldflags '-extldflags "-static"' -v ./cmd/gexp
|
||||||
@echo "Linux MIPS64 cross compilation done:"
|
@echo "Linux MIPS64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-linux-* | grep mips64
|
@ls -ld $(GOBIN)/gexp-linux-* | grep mips64
|
||||||
|
|
||||||
gexp-linux-mips64le:
|
gexp-linux-mips64le:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/mips64le -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64le --ldflags '-extldflags "-static"' -v ./cmd/gexp
|
||||||
@echo "Linux MIPS64le cross compilation done:"
|
@echo "Linux MIPS64le cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-linux-* | grep mips64le
|
@ls -ld $(GOBIN)/gexp-linux-* | grep mips64le
|
||||||
|
|
||||||
|
|
@ -99,12 +118,12 @@ gexp-darwin: gexp-darwin-386 gexp-darwin-amd64
|
||||||
@ls -ld $(GOBIN)/gexp-darwin-*
|
@ls -ld $(GOBIN)/gexp-darwin-*
|
||||||
|
|
||||||
gexp-darwin-386:
|
gexp-darwin-386:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=darwin/386 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/386 -v ./cmd/gexp
|
||||||
@echo "Darwin 386 cross compilation done:"
|
@echo "Darwin 386 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-darwin-* | grep 386
|
@ls -ld $(GOBIN)/gexp-darwin-* | grep 386
|
||||||
|
|
||||||
gexp-darwin-amd64:
|
gexp-darwin-amd64:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=darwin/amd64 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/amd64 -v ./cmd/gexp
|
||||||
@echo "Darwin amd64 cross compilation done:"
|
@echo "Darwin amd64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-darwin-* | grep amd64
|
@ls -ld $(GOBIN)/gexp-darwin-* | grep amd64
|
||||||
|
|
||||||
|
|
@ -113,11 +132,11 @@ gexp-windows: gexp-windows-386 gexp-windows-amd64
|
||||||
@ls -ld $(GOBIN)/gexp-windows-*
|
@ls -ld $(GOBIN)/gexp-windows-*
|
||||||
|
|
||||||
gexp-windows-386:
|
gexp-windows-386:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=windows/386 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=windows/386 -v ./cmd/gexp
|
||||||
@echo "Windows 386 cross compilation done:"
|
@echo "Windows 386 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-windows-* | grep 386
|
@ls -ld $(GOBIN)/gexp-windows-* | grep 386
|
||||||
|
|
||||||
gexp-windows-amd64:
|
gexp-windows-amd64:
|
||||||
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=windows/amd64 -v ./cmd/gexp
|
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=windows/amd64 -v ./cmd/gexp
|
||||||
@echo "Windows amd64 cross compilation done:"
|
@echo "Windows amd64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/gexp-windows-* | grep amd64
|
@ls -ld $(GOBIN)/gexp-windows-* | grep amd64
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ For prerequisites and detailed build instructions please read the
|
||||||
[Installation Instructions](https://github.com/expanse-org/go-expanse/wiki/Building-Expanse)
|
[Installation Instructions](https://github.com/expanse-org/go-expanse/wiki/Building-Expanse)
|
||||||
on the wiki.
|
on the wiki.
|
||||||
|
|
||||||
Building gexp requires both a Go and a C compiler.
|
Building gexp requires both a Go (version 1.7 or later) and a C compiler.
|
||||||
You can install them using your favourite package manager.
|
You can install them using your favourite package manager.
|
||||||
Once the dependencies are installed, run
|
Once the dependencies are installed, run
|
||||||
|
|
||||||
|
|
@ -112,7 +112,7 @@ docker run -d --name expanse-node -v /Users/alice/expanse:/root \
|
||||||
|
|
||||||
This will start gexp in fast sync mode with a DB memory allowance of 512MB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image.
|
This will start gexp in fast sync mode with a DB memory allowance of 512MB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image.
|
||||||
|
|
||||||
### Programatically interfacing Gexp nodes
|
### Pragmatically interfacing Gexp nodes
|
||||||
|
|
||||||
As a developer, sooner rather than later you'll want to start interacting with Gexp and the Expanse
|
As a developer, sooner rather than later you'll want to start interacting with Gexp and the Expanse
|
||||||
network via your own programs and not manually through the console. To aid this, Gexp has built in
|
network via your own programs and not manually through the console. To aid this, Gexp has built in
|
||||||
|
|
@ -120,6 +120,7 @@ support for a JSON-RPC based APIs ([standard APIs](https://github.com/expanse-or
|
||||||
[Gexp specific APIs](https://github.com/expanse-org/go-expanse/wiki/Management-APIs)). These can be
|
[Gexp specific APIs](https://github.com/expanse-org/go-expanse/wiki/Management-APIs)). These can be
|
||||||
exposed via HTTP, WebSockets and IPC (unix sockets on unix based platroms, and named pipes on Windows).
|
exposed via HTTP, WebSockets and IPC (unix sockets on unix based platroms, and named pipes on Windows).
|
||||||
|
|
||||||
|
|
||||||
The IPC interface is enabled by default and exposes all the APIs supported by Gexp, whereas the HTTP
|
The IPC interface is enabled by default and exposes all the APIs supported by Gexp, whereas the HTTP
|
||||||
and WS interfaces need to manually be enabled and only expose a subset of APIs due to security reasons.
|
and WS interfaces need to manually be enabled and only expose a subset of APIs due to security reasons.
|
||||||
These can be turned on/off and configured as you'd expect.
|
These can be turned on/off and configured as you'd expect.
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package abi
|
package abi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -129,16 +130,15 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
var size int
|
var size int
|
||||||
var offset int
|
var offset int
|
||||||
if t.Type.IsSlice {
|
if t.Type.IsSlice {
|
||||||
|
|
||||||
// get the offset which determines the start of this array ...
|
// get the offset which determines the start of this array ...
|
||||||
offset = int(common.BytesToBig(output[index : index+32]).Uint64())
|
offset = int(binary.BigEndian.Uint64(output[index+24 : index+32]))
|
||||||
if offset+32 > len(output) {
|
if offset+32 > len(output) {
|
||||||
return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
|
return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
|
||||||
}
|
}
|
||||||
|
|
||||||
slice = output[offset:]
|
slice = output[offset:]
|
||||||
// ... starting with the size of the array in elements ...
|
// ... starting with the size of the array in elements ...
|
||||||
size = int(common.BytesToBig(slice[:32]).Uint64())
|
size = int(binary.BigEndian.Uint64(slice[24:32]))
|
||||||
slice = slice[32:]
|
slice = slice[32:]
|
||||||
// ... and make sure that we've at the very least the amount of bytes
|
// ... and make sure that we've at the very least the amount of bytes
|
||||||
// available in the buffer.
|
// available in the buffer.
|
||||||
|
|
@ -147,7 +147,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// reslice to match the required size
|
// reslice to match the required size
|
||||||
slice = slice[:(size * 32)]
|
slice = slice[:size*32]
|
||||||
} else if t.Type.IsArray {
|
} else if t.Type.IsArray {
|
||||||
//get the number of elements in the array
|
//get the number of elements in the array
|
||||||
size = t.Type.SliceSize
|
size = t.Type.SliceSize
|
||||||
|
|
@ -165,33 +165,12 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
inter interface{} // interface type
|
inter interface{} // interface type
|
||||||
returnOutput = slice[i*32 : i*32+32] // the return output
|
returnOutput = slice[i*32 : i*32+32] // the return output
|
||||||
)
|
)
|
||||||
|
|
||||||
// set inter to the correct type (cast)
|
// set inter to the correct type (cast)
|
||||||
switch elem.T {
|
switch elem.T {
|
||||||
case IntTy, UintTy:
|
case IntTy, UintTy:
|
||||||
bigNum := common.BytesToBig(returnOutput)
|
inter = readInteger(t.Type.Kind, returnOutput)
|
||||||
switch t.Type.Kind {
|
|
||||||
case reflect.Uint8:
|
|
||||||
inter = uint8(bigNum.Uint64())
|
|
||||||
case reflect.Uint16:
|
|
||||||
inter = uint16(bigNum.Uint64())
|
|
||||||
case reflect.Uint32:
|
|
||||||
inter = uint32(bigNum.Uint64())
|
|
||||||
case reflect.Uint64:
|
|
||||||
inter = bigNum.Uint64()
|
|
||||||
case reflect.Int8:
|
|
||||||
inter = int8(bigNum.Int64())
|
|
||||||
case reflect.Int16:
|
|
||||||
inter = int16(bigNum.Int64())
|
|
||||||
case reflect.Int32:
|
|
||||||
inter = int32(bigNum.Int64())
|
|
||||||
case reflect.Int64:
|
|
||||||
inter = bigNum.Int64()
|
|
||||||
default:
|
|
||||||
inter = common.BytesToBig(returnOutput)
|
|
||||||
}
|
|
||||||
case BoolTy:
|
case BoolTy:
|
||||||
inter = common.BytesToBig(returnOutput).Uint64() > 0
|
inter = !allZero(returnOutput)
|
||||||
case AddressTy:
|
case AddressTy:
|
||||||
inter = common.BytesToAddress(returnOutput)
|
inter = common.BytesToAddress(returnOutput)
|
||||||
case HashTy:
|
case HashTy:
|
||||||
|
|
@ -207,6 +186,38 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
return refSlice.Interface(), nil
|
return refSlice.Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readInteger(kind reflect.Kind, b []byte) interface{} {
|
||||||
|
switch kind {
|
||||||
|
case reflect.Uint8:
|
||||||
|
return uint8(b[len(b)-1])
|
||||||
|
case reflect.Uint16:
|
||||||
|
return binary.BigEndian.Uint16(b[len(b)-2:])
|
||||||
|
case reflect.Uint32:
|
||||||
|
return binary.BigEndian.Uint32(b[len(b)-4:])
|
||||||
|
case reflect.Uint64:
|
||||||
|
return binary.BigEndian.Uint64(b[len(b)-8:])
|
||||||
|
case reflect.Int8:
|
||||||
|
return int8(b[len(b)-1])
|
||||||
|
case reflect.Int16:
|
||||||
|
return int16(binary.BigEndian.Uint16(b[len(b)-2:]))
|
||||||
|
case reflect.Int32:
|
||||||
|
return int32(binary.BigEndian.Uint32(b[len(b)-4:]))
|
||||||
|
case reflect.Int64:
|
||||||
|
return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
|
||||||
|
default:
|
||||||
|
return new(big.Int).SetBytes(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func allZero(b []byte) bool {
|
||||||
|
for _, byte := range b {
|
||||||
|
if byte != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// toGoType parses the input and casts it to the proper type defined by the ABI
|
// toGoType parses the input and casts it to the proper type defined by the ABI
|
||||||
// argument in T.
|
// argument in T.
|
||||||
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
|
|
@ -226,12 +237,12 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
switch t.Type.T {
|
switch t.Type.T {
|
||||||
case StringTy, BytesTy: // variable arrays are written at the end of the return bytes
|
case StringTy, BytesTy: // variable arrays are written at the end of the return bytes
|
||||||
// parse offset from which we should start reading
|
// parse offset from which we should start reading
|
||||||
offset := int(common.BytesToBig(output[index : index+32]).Uint64())
|
offset := int(binary.BigEndian.Uint64(output[index+24 : index+32]))
|
||||||
if offset+32 > len(output) {
|
if offset+32 > len(output) {
|
||||||
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32)
|
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32)
|
||||||
}
|
}
|
||||||
// parse the size up until we should be reading
|
// parse the size up until we should be reading
|
||||||
size := int(common.BytesToBig(output[offset : offset+32]).Uint64())
|
size := int(binary.BigEndian.Uint64(output[offset+24 : offset+32]))
|
||||||
if offset+32+size > len(output) {
|
if offset+32+size > len(output) {
|
||||||
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+size)
|
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+size)
|
||||||
}
|
}
|
||||||
|
|
@ -245,32 +256,9 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
// convert the bytes to whatever is specified by the ABI.
|
// convert the bytes to whatever is specified by the ABI.
|
||||||
switch t.Type.T {
|
switch t.Type.T {
|
||||||
case IntTy, UintTy:
|
case IntTy, UintTy:
|
||||||
bigNum := common.BytesToBig(returnOutput)
|
return readInteger(t.Type.Kind, returnOutput), nil
|
||||||
|
|
||||||
// If the type is a integer convert to the integer type
|
|
||||||
// specified by the ABI.
|
|
||||||
switch t.Type.Kind {
|
|
||||||
case reflect.Uint8:
|
|
||||||
return uint8(bigNum.Uint64()), nil
|
|
||||||
case reflect.Uint16:
|
|
||||||
return uint16(bigNum.Uint64()), nil
|
|
||||||
case reflect.Uint32:
|
|
||||||
return uint32(bigNum.Uint64()), nil
|
|
||||||
case reflect.Uint64:
|
|
||||||
return uint64(bigNum.Uint64()), nil
|
|
||||||
case reflect.Int8:
|
|
||||||
return int8(bigNum.Int64()), nil
|
|
||||||
case reflect.Int16:
|
|
||||||
return int16(bigNum.Int64()), nil
|
|
||||||
case reflect.Int32:
|
|
||||||
return int32(bigNum.Int64()), nil
|
|
||||||
case reflect.Int64:
|
|
||||||
return int64(bigNum.Int64()), nil
|
|
||||||
case reflect.Ptr:
|
|
||||||
return bigNum, nil
|
|
||||||
}
|
|
||||||
case BoolTy:
|
case BoolTy:
|
||||||
return common.BytesToBig(returnOutput).Uint64() > 0, nil
|
return !allZero(returnOutput), nil
|
||||||
case AddressTy:
|
case AddressTy:
|
||||||
return common.BytesToAddress(returnOutput), nil
|
return common.BytesToAddress(returnOutput), nil
|
||||||
case HashTy:
|
case HashTy:
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,13 @@
|
||||||
package bind
|
package bind
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse"
|
"github.com/expanse-org/go-expanse"
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package backends
|
package backends
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -25,6 +26,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse"
|
"github.com/expanse-org/go-expanse"
|
||||||
"github.com/expanse-org/go-expanse/accounts/abi/bind"
|
"github.com/expanse-org/go-expanse/accounts/abi/bind"
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
"github.com/expanse-org/go-expanse/core"
|
"github.com/expanse-org/go-expanse/core"
|
||||||
"github.com/expanse-org/go-expanse/core/state"
|
"github.com/expanse-org/go-expanse/core/state"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
|
|
@ -32,12 +34,9 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/event"
|
"github.com/expanse-org/go-expanse/event"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
"golang.org/x/net/context"
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
|
|
||||||
var chainConfig = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), EIP150Block: new(big.Int), EIP158Block: new(big.Int)}
|
|
||||||
|
|
||||||
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
|
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
|
||||||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
||||||
|
|
||||||
|
|
@ -58,11 +57,12 @@ type SimulatedBackend struct {
|
||||||
|
|
||||||
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
||||||
// for testing purposes.
|
// for testing purposes.
|
||||||
func NewSimulatedBackend(accounts ...core.GenesisAccount) *SimulatedBackend {
|
func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
|
||||||
database, _ := ethdb.NewMemDatabase()
|
database, _ := ethdb.NewMemDatabase()
|
||||||
core.WriteGenesisBlockForTesting(database, accounts...)
|
genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc}
|
||||||
blockchain, _ := core.NewBlockChain(database, chainConfig, new(core.FakePow), new(event.TypeMux), vm.Config{})
|
genesis.MustCommit(database)
|
||||||
backend := &SimulatedBackend{database: database, blockchain: blockchain}
|
blockchain, _ := core.NewBlockChain(database, genesis.Config, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config}
|
||||||
backend.rollback()
|
backend.rollback()
|
||||||
return backend
|
return backend
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +88,7 @@ func (b *SimulatedBackend) Rollback() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SimulatedBackend) rollback() {
|
func (b *SimulatedBackend) rollback() {
|
||||||
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
|
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
|
||||||
b.pendingBlock = blocks[0]
|
b.pendingBlock = blocks[0]
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
|
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
|
||||||
}
|
}
|
||||||
|
|
@ -236,7 +236,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
if call.GasPrice == nil {
|
if call.GasPrice == nil {
|
||||||
call.GasPrice = big.NewInt(1)
|
call.GasPrice = big.NewInt(1)
|
||||||
}
|
}
|
||||||
if call.Gas == nil || call.Gas.BitLen() == 0 {
|
if call.Gas == nil || call.Gas.Sign() == 0 {
|
||||||
call.Gas = big.NewInt(50000000)
|
call.Gas = big.NewInt(50000000)
|
||||||
}
|
}
|
||||||
if call.Value == nil {
|
if call.Value == nil {
|
||||||
|
|
@ -244,15 +244,15 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
}
|
}
|
||||||
// Set infinite balance to the fake caller account.
|
// Set infinite balance to the fake caller account.
|
||||||
from := statedb.GetOrNewStateObject(call.From)
|
from := statedb.GetOrNewStateObject(call.From)
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(math.MaxBig256)
|
||||||
// Execute the call.
|
// Execute the call.
|
||||||
msg := callmsg{call}
|
msg := callmsg{call}
|
||||||
|
|
||||||
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
|
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
|
||||||
// Create a new environment which holds all relevant information
|
// Create a new environment which holds all relevant information
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEVM(evmContext, statedb, chainConfig, vm.Config{})
|
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
|
||||||
gaspool := new(core.GasPool).AddGas(common.MaxBig)
|
gaspool := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||||
return ret, gasUsed, err
|
return ret, gasUsed, err
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +272,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
||||||
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
|
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), 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.AddTx(tx)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package bind
|
package bind
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -26,7 +27,6 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignerFn is a signer function callback when a contract requires a method to
|
// SignerFn is a signer function callback when a contract requires a method to
|
||||||
|
|
@ -35,7 +35,8 @@ type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Tra
|
||||||
|
|
||||||
// CallOpts is the collection of options to fine tune a contract call request.
|
// CallOpts is the collection of options to fine tune a contract call request.
|
||||||
type CallOpts struct {
|
type CallOpts struct {
|
||||||
Pending bool // Whether to operate on the pending state or the last known one
|
Pending bool // Whether to operate on the pending state or the last known one
|
||||||
|
From common.Address // Optional the sender address, otherwise the first account is used
|
||||||
|
|
||||||
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +109,7 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
msg = ethereum.CallMsg{To: &c.address, Data: input}
|
msg = ethereum.CallMsg{From: opts.From, To: &c.address, Data: input}
|
||||||
ctx = ensureContext(opts.Context)
|
ctx = ensureContext(opts.Context)
|
||||||
code []byte
|
code []byte
|
||||||
output []byte
|
output []byte
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
auth := bind.NewKeyedTransactor(key)
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
|
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
|
||||||
|
|
||||||
// Deploy an interaction tester contract and call a transaction on it
|
// Deploy an interaction tester contract and call a transaction on it
|
||||||
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
|
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
|
||||||
|
|
@ -210,7 +210,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
auth := bind.NewKeyedTransactor(key)
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
|
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
|
||||||
|
|
||||||
// Deploy a tuple tester contract and execute a structured call on it
|
// Deploy a tuple tester contract and execute a structured call on it
|
||||||
_, _, getter, err := DeployGetter(auth, sim)
|
_, _, getter, err := DeployGetter(auth, sim)
|
||||||
|
|
@ -242,7 +242,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
auth := bind.NewKeyedTransactor(key)
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
|
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
|
||||||
|
|
||||||
// Deploy a tuple tester contract and execute a structured call on it
|
// Deploy a tuple tester contract and execute a structured call on it
|
||||||
_, _, tupler, err := DeployTupler(auth, sim)
|
_, _, tupler, err := DeployTupler(auth, sim)
|
||||||
|
|
@ -284,7 +284,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
auth := bind.NewKeyedTransactor(key)
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
|
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
|
||||||
|
|
||||||
// Deploy a slice tester contract and execute a n array call on it
|
// Deploy a slice tester contract and execute a n array call on it
|
||||||
_, _, slicer, err := DeploySlicer(auth, sim)
|
_, _, slicer, err := DeploySlicer(auth, sim)
|
||||||
|
|
@ -318,7 +318,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
auth := bind.NewKeyedTransactor(key)
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
|
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
|
||||||
|
|
||||||
// Deploy a default method invoker contract and execute its default method
|
// Deploy a default method invoker contract and execute its default method
|
||||||
_, _, defaulter, err := DeployDefaulter(auth, sim)
|
_, _, defaulter, err := DeployDefaulter(auth, sim)
|
||||||
|
|
@ -351,7 +351,7 @@ var bindTests = []struct {
|
||||||
`[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
|
`[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
|
||||||
`
|
`
|
||||||
// Create a simulator and wrap a non-deployed contract
|
// Create a simulator and wrap a non-deployed contract
|
||||||
sim := backends.NewSimulatedBackend()
|
sim := backends.NewSimulatedBackend(nil)
|
||||||
|
|
||||||
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -387,7 +387,7 @@ var bindTests = []struct {
|
||||||
// Generate a new random account and a funded simulator
|
// Generate a new random account and a funded simulator
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
auth := bind.NewKeyedTransactor(key)
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
|
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
|
||||||
|
|
||||||
// Deploy a funky gas pattern contract
|
// Deploy a funky gas pattern contract
|
||||||
_, _, limiter, err := DeployFunkyGasPattern(auth, sim)
|
_, _, limiter, err := DeployFunkyGasPattern(auth, sim)
|
||||||
|
|
@ -408,6 +408,45 @@ var bindTests = []struct {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
// Test that constant functions can be called from an (optional) specified address
|
||||||
|
{
|
||||||
|
`CallFrom`,
|
||||||
|
`
|
||||||
|
contract CallFrom {
|
||||||
|
function callFrom() constant returns(address) {
|
||||||
|
return msg.sender;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, `6060604052346000575b6086806100176000396000f300606060405263ffffffff60e060020a60003504166349f8e98281146022575b6000565b34600057602c6055565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b335b905600a165627a7a72305820aef6b7685c0fa24ba6027e4870404a57df701473fe4107741805c19f5138417c0029`,
|
||||||
|
`[{"constant":true,"inputs":[],"name":"callFrom","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}]`,
|
||||||
|
`
|
||||||
|
// Generate a new random account and a funded simulator
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
auth := bind.NewKeyedTransactor(key)
|
||||||
|
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
|
||||||
|
|
||||||
|
// Deploy a sender tester contract and execute a structured call on it
|
||||||
|
_, _, callfrom, err := DeployCallFrom(auth, sim)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to deploy sender contract: %v", err)
|
||||||
|
}
|
||||||
|
sim.Commit()
|
||||||
|
|
||||||
|
if res, err := callfrom.CallFrom(nil); err != nil {
|
||||||
|
t.Errorf("Failed to call constant function: %v", err)
|
||||||
|
} else if res != (common.Address{}) {
|
||||||
|
t.Errorf("Invalid address returned, want: %x, got: %x", (common.Address{}), res)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range []common.Address{common.Address{}, common.Address{1}, common.Address{2}} {
|
||||||
|
if res, err := callfrom.CallFrom(&bind.CallOpts{From: addr}); err != nil {
|
||||||
|
t.Fatalf("Failed to call constant function: %v", err)
|
||||||
|
} else if res != addr {
|
||||||
|
t.Fatalf("Invalid address returned, want: %x, got: %x", addr, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that packages generated by the binder can be successfully compiled and
|
// Tests that packages generated by the binder can be successfully compiled and
|
||||||
|
|
@ -419,7 +458,7 @@ func TestBindings(t *testing.T) {
|
||||||
t.Skip("go sdk not found for testing")
|
t.Skip("go sdk not found for testing")
|
||||||
}
|
}
|
||||||
// Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845)
|
// Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845)
|
||||||
linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend())\n}")
|
linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}")
|
||||||
linkTestDeps, err := imports.Process("", []byte(linkTestCode), nil)
|
linkTestDeps, err := imports.Process("", []byte(linkTestCode), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed check for goimports symlink bug: %v", err)
|
t.Fatalf("failed check for goimports symlink bug: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -17,31 +17,31 @@
|
||||||
package bind
|
package bind
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WaitMined waits for tx to be mined on the blockchain.
|
// WaitMined waits for tx to be mined on the blockchain.
|
||||||
// It stops waiting when the context is canceled.
|
// It stops waiting when the context is canceled.
|
||||||
func WaitMined(ctx context.Context, b DeployBackend, tx *types.Transaction) (*types.Receipt, error) {
|
func WaitMined(ctx context.Context, b DeployBackend, tx *types.Transaction) (*types.Receipt, error) {
|
||||||
queryTicker := time.NewTicker(1 * time.Second)
|
queryTicker := time.NewTicker(time.Second)
|
||||||
defer queryTicker.Stop()
|
defer queryTicker.Stop()
|
||||||
loghash := tx.Hash().Hex()[:8]
|
|
||||||
|
logger := log.New("hash", tx.Hash())
|
||||||
for {
|
for {
|
||||||
receipt, err := b.TransactionReceipt(ctx, tx.Hash())
|
receipt, err := b.TransactionReceipt(ctx, tx.Hash())
|
||||||
if receipt != nil {
|
if receipt != nil {
|
||||||
return receipt, nil
|
return receipt, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Detail).Infof("tx %x error: %v", loghash, err)
|
logger.Trace("Receipt retrieval failed", "err", err)
|
||||||
} else {
|
} else {
|
||||||
glog.V(logger.Detail).Infof("tx %x not yet mined...", loghash)
|
logger.Trace("Transaction not yet mined")
|
||||||
}
|
}
|
||||||
// Wait for the next round.
|
// Wait for the next round.
|
||||||
select {
|
select {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package bind_test
|
package bind_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -27,7 +28,6 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/core"
|
"github.com/expanse-org/go-expanse/core"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
|
@ -53,9 +53,8 @@ var waitDeployedTests = map[string]struct {
|
||||||
|
|
||||||
func TestWaitDeployed(t *testing.T) {
|
func TestWaitDeployed(t *testing.T) {
|
||||||
for name, test := range waitDeployedTests {
|
for name, test := range waitDeployedTests {
|
||||||
backend := backends.NewSimulatedBackend(core.GenesisAccount{
|
backend := backends.NewSimulatedBackend(core.GenesisAlloc{
|
||||||
Address: crypto.PubkeyToAddress(testKey.PublicKey),
|
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)},
|
||||||
Balance: big.NewInt(10000000000),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create the transaction.
|
// Create the transaction.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -58,7 +59,7 @@ var (
|
||||||
|
|
||||||
// U256 converts a big Int into a 256bit EVM number.
|
// U256 converts a big Int into a 256bit EVM number.
|
||||||
func U256(n *big.Int) []byte {
|
func U256(n *big.Int) []byte {
|
||||||
return common.LeftPadBytes(common.U256(n).Bytes(), 32)
|
return math.PaddedBigBytes(math.U256(n), 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
|
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
)
|
)
|
||||||
|
|
||||||
// packBytesSlice packs the given bytes as [L, V] as the canonical representation
|
// packBytesSlice packs the given bytes as [L, V] as the canonical representation
|
||||||
|
|
@ -45,9 +46,9 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
|
||||||
return common.LeftPadBytes(reflectValue.Bytes(), 32)
|
return common.LeftPadBytes(reflectValue.Bytes(), 32)
|
||||||
case BoolTy:
|
case BoolTy:
|
||||||
if reflectValue.Bool() {
|
if reflectValue.Bool() {
|
||||||
return common.LeftPadBytes(common.Big1.Bytes(), 32)
|
return math.PaddedBigBytes(common.Big1, 32)
|
||||||
} else {
|
} else {
|
||||||
return common.LeftPadBytes(common.Big0.Bytes(), 32)
|
return math.PaddedBigBytes(common.Big0, 32)
|
||||||
}
|
}
|
||||||
case BytesTy:
|
case BytesTy:
|
||||||
if reflectValue.Kind() == reflect.Array {
|
if reflectValue.Kind() == reflect.Array {
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,7 @@ import (
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/accounts"
|
"github.com/expanse-org/go-expanse/accounts"
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Minimum amount of time between cache reloads. This limit applies if the platform does
|
// Minimum amount of time between cache reloads. This limit applies if the platform does
|
||||||
|
|
@ -210,8 +209,8 @@ func (ac *accountCache) close() {
|
||||||
// Callers must hold ac.mu.
|
// Callers must hold ac.mu.
|
||||||
func (ac *accountCache) reload() {
|
func (ac *accountCache) reload() {
|
||||||
accounts, err := ac.scan()
|
accounts, err := ac.scan()
|
||||||
if err != nil && glog.V(logger.Debug) {
|
if err != nil {
|
||||||
glog.Errorf("can't load keys: %v", err)
|
log.Debug("Failed to reload keystore contents", "err", err)
|
||||||
}
|
}
|
||||||
ac.all = accounts
|
ac.all = accounts
|
||||||
sort.Sort(ac.all)
|
sort.Sort(ac.all)
|
||||||
|
|
@ -225,7 +224,7 @@ func (ac *accountCache) reload() {
|
||||||
case ac.notify <- struct{}{}:
|
case ac.notify <- struct{}{}:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
glog.V(logger.Debug).Infof("reloaded keys, cache has %d accounts", len(ac.all))
|
log.Debug("Reloaded keystore contents", "accounts", len(ac.all))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ac *accountCache) scan() ([]accounts.Account, error) {
|
func (ac *accountCache) scan() ([]accounts.Account, error) {
|
||||||
|
|
@ -244,12 +243,14 @@ func (ac *accountCache) scan() ([]accounts.Account, error) {
|
||||||
for _, fi := range files {
|
for _, fi := range files {
|
||||||
path := filepath.Join(ac.keydir, fi.Name())
|
path := filepath.Join(ac.keydir, fi.Name())
|
||||||
if skipKeyFile(fi) {
|
if skipKeyFile(fi) {
|
||||||
glog.V(logger.Detail).Infof("ignoring file %s", path)
|
log.Trace("Ignoring file on account scan", "path", path)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
logger := log.New("path", path)
|
||||||
|
|
||||||
fd, err := os.Open(path)
|
fd, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Detail).Infoln(err)
|
logger.Trace("Failed to open keystore file", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf.Reset(fd)
|
buf.Reset(fd)
|
||||||
|
|
@ -259,9 +260,9 @@ func (ac *accountCache) scan() ([]accounts.Account, error) {
|
||||||
addr := common.HexToAddress(keyJSON.Address)
|
addr := common.HexToAddress(keyJSON.Address)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
glog.V(logger.Debug).Infof("can't decode key %s: %v", path, err)
|
logger.Debug("Failed to decode keystore key", "err", err)
|
||||||
case (addr == common.Address{}):
|
case (addr == common.Address{}):
|
||||||
glog.V(logger.Debug).Infof("can't decode key %s: missing or zero address", path)
|
logger.Debug("Failed to decode keystore key", "err", "missing or zero address")
|
||||||
default:
|
default:
|
||||||
addrs = append(addrs, accounts.Account{Address: addr, URL: accounts.URL{Scheme: KeyStoreScheme, Path: path}})
|
addrs = append(addrs, accounts.Account{Address: addr, URL: accounts.URL{Scheme: KeyStoreScheme, Path: path}})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"github.com/expanse-org/go-expanse/crypto/randentropy"
|
"github.com/expanse-org/go-expanse/crypto/randentropy"
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
|
|
@ -115,8 +116,7 @@ func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
encryptKey := derivedKey[:16]
|
encryptKey := derivedKey[:16]
|
||||||
keyBytes0 := crypto.FromECDSA(key.PrivateKey)
|
keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32)
|
||||||
keyBytes := common.LeftPadBytes(keyBytes0, 32)
|
|
||||||
|
|
||||||
iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
|
iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
|
||||||
cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
|
cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@ package keystore
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/rjeczalik/notify"
|
"github.com/rjeczalik/notify"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -64,15 +63,16 @@ func (w *watcher) loop() {
|
||||||
w.starting = false
|
w.starting = false
|
||||||
w.ac.mu.Unlock()
|
w.ac.mu.Unlock()
|
||||||
}()
|
}()
|
||||||
|
logger := log.New("path", w.ac.keydir)
|
||||||
|
|
||||||
err := notify.Watch(w.ac.keydir, w.ev, notify.All)
|
if err := notify.Watch(w.ac.keydir, w.ev, notify.All); err != nil {
|
||||||
if err != nil {
|
logger.Trace("Failed to watch keystore folder", "err", err)
|
||||||
glog.V(logger.Detail).Infof("can't watch %s: %v", w.ac.keydir, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer notify.Stop(w.ev)
|
defer notify.Stop(w.ev)
|
||||||
glog.V(logger.Detail).Infof("now watching %s", w.ac.keydir)
|
|
||||||
defer glog.V(logger.Detail).Infof("no longer watching %s", w.ac.keydir)
|
logger.Trace("Started watching keystore folder")
|
||||||
|
defer logger.Trace("Stopped watching keystore folder")
|
||||||
|
|
||||||
w.ac.mu.Lock()
|
w.ac.mu.Lock()
|
||||||
w.running = true
|
w.running = true
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,15 @@ func (u URL) String() string {
|
||||||
return u.Path
|
return u.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TerminalString implements the log.TerminalStringer interface.
|
||||||
|
func (u URL) TerminalString() string {
|
||||||
|
url := u.String()
|
||||||
|
if len(url) > 32 {
|
||||||
|
return url[:31] + "…"
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaller interface.
|
// MarshalJSON implements the json.Marshaller interface.
|
||||||
func (u URL) MarshalJSON() ([]byte, error) {
|
func (u URL) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(u.String())
|
return json.Marshal(u.String())
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/accounts"
|
"github.com/expanse-org/go-expanse/accounts"
|
||||||
"github.com/expanse-org/go-expanse/event"
|
"github.com/expanse-org/go-expanse/event"
|
||||||
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/karalabe/hid"
|
"github.com/karalabe/hid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -120,7 +121,7 @@ func (hub *LedgerHub) refreshWallets() {
|
||||||
}
|
}
|
||||||
// If there are no more wallets or the device is before the next, wrap new wallet
|
// If there are no more wallets or the device is before the next, wrap new wallet
|
||||||
if len(hub.wallets) == 0 || hub.wallets[0].URL().Cmp(url) > 0 {
|
if len(hub.wallets) == 0 || hub.wallets[0].URL().Cmp(url) > 0 {
|
||||||
wallet := &ledgerWallet{url: &url, info: ledger}
|
wallet := &ledgerWallet{url: &url, info: ledger, log: log.New("url", url)}
|
||||||
|
|
||||||
events = append(events, accounts.WalletEvent{Wallet: wallet, Arrive: true})
|
events = append(events, accounts.WalletEvent{Wallet: wallet, Arrive: true})
|
||||||
wallets = append(wallets, wallet)
|
wallets = append(wallets, wallet)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
package usbwallet
|
package usbwallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
@ -33,12 +34,11 @@ import (
|
||||||
ethereum "github.com/expanse-org/go-expanse"
|
ethereum "github.com/expanse-org/go-expanse"
|
||||||
"github.com/expanse-org/go-expanse/accounts"
|
"github.com/expanse-org/go-expanse/accounts"
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/hexutil"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/rlp"
|
"github.com/expanse-org/go-expanse/rlp"
|
||||||
"github.com/karalabe/hid"
|
"github.com/karalabe/hid"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Maximum time between wallet health checks to detect USB unplugs.
|
// Maximum time between wallet health checks to detect USB unplugs.
|
||||||
|
|
@ -123,6 +123,8 @@ type ledgerWallet struct {
|
||||||
// must only ever hold a *read* lock to stateLock.
|
// must only ever hold a *read* lock to stateLock.
|
||||||
commsLock chan struct{} // Mutex (buf=1) for the USB comms without keeping the state locked
|
commsLock chan struct{} // Mutex (buf=1) for the USB comms without keeping the state locked
|
||||||
stateLock sync.RWMutex // Protects read and write access to the wallet struct fields
|
stateLock sync.RWMutex // Protects read and write access to the wallet struct fields
|
||||||
|
|
||||||
|
log log.Logger // Contextual logger to tag the ledger with its id
|
||||||
}
|
}
|
||||||
|
|
||||||
// URL implements accounts.Wallet, returning the URL of the Ledger device.
|
// URL implements accounts.Wallet, returning the URL of the Ledger device.
|
||||||
|
|
@ -220,8 +222,8 @@ func (w *ledgerWallet) Open(passphrase string) error {
|
||||||
// - libusb on Windows doesn't support hotplug, so we can't detect USB unplugs
|
// - libusb on Windows doesn't support hotplug, so we can't detect USB unplugs
|
||||||
// - communication timeout on the Ledger requires a device power cycle to fix
|
// - communication timeout on the Ledger requires a device power cycle to fix
|
||||||
func (w *ledgerWallet) heartbeat() {
|
func (w *ledgerWallet) heartbeat() {
|
||||||
glog.V(logger.Debug).Infof("%s health-check started", w.url.String())
|
w.log.Debug("Ledger health-check started")
|
||||||
defer glog.V(logger.Debug).Infof("%s health-check stopped", w.url.String())
|
defer w.log.Debug("Ledger health-check stopped")
|
||||||
|
|
||||||
// Execute heartbeat checks until termination or error
|
// Execute heartbeat checks until termination or error
|
||||||
var (
|
var (
|
||||||
|
|
@ -260,7 +262,7 @@ func (w *ledgerWallet) heartbeat() {
|
||||||
}
|
}
|
||||||
// In case of error, wait for termination
|
// In case of error, wait for termination
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Debug).Infof("%s health-check failed: %v", w.url.String(), err)
|
w.log.Debug("Ledger health-check failed", "err", err)
|
||||||
errc = <-w.healthQuit
|
errc = <-w.healthQuit
|
||||||
}
|
}
|
||||||
errc <- err
|
errc <- err
|
||||||
|
|
@ -348,8 +350,8 @@ func (w *ledgerWallet) Accounts() []accounts.Account {
|
||||||
// selfDerive is an account derivation loop that upon request attempts to find
|
// selfDerive is an account derivation loop that upon request attempts to find
|
||||||
// new non-zero accounts.
|
// new non-zero accounts.
|
||||||
func (w *ledgerWallet) selfDerive() {
|
func (w *ledgerWallet) selfDerive() {
|
||||||
glog.V(logger.Debug).Infof("%s self-derivation started", w.url.String())
|
w.log.Debug("Ledger self-derivation started")
|
||||||
defer glog.V(logger.Debug).Infof("%s self-derivation stopped", w.url.String())
|
defer w.log.Debug("Ledger self-derivation stopped")
|
||||||
|
|
||||||
// Execute self-derivations until termination or error
|
// Execute self-derivations until termination or error
|
||||||
var (
|
var (
|
||||||
|
|
@ -394,7 +396,7 @@ func (w *ledgerWallet) selfDerive() {
|
||||||
// Retrieve the next derived Ethereum account
|
// Retrieve the next derived Ethereum account
|
||||||
if nextAddr == (common.Address{}) {
|
if nextAddr == (common.Address{}) {
|
||||||
if nextAddr, err = w.ledgerDerive(nextPath); err != nil {
|
if nextAddr, err = w.ledgerDerive(nextPath); err != nil {
|
||||||
glog.V(logger.Warn).Infof("%s self-derivation failed: %v", w.url.String(), err)
|
w.log.Warn("Ledger account derivation failed", "err", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -405,16 +407,16 @@ func (w *ledgerWallet) selfDerive() {
|
||||||
)
|
)
|
||||||
balance, err = w.deriveChain.BalanceAt(context, nextAddr, nil)
|
balance, err = w.deriveChain.BalanceAt(context, nextAddr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Warn).Infof("%s self-derivation balance retrieval failed: %v", w.url.String(), err)
|
w.log.Warn("Ledger balance retrieval failed", "err", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
nonce, err = w.deriveChain.NonceAt(context, nextAddr, nil)
|
nonce, err = w.deriveChain.NonceAt(context, nextAddr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Warn).Infof("%s self-derivation nonce retrieval failed: %v", w.url.String(), err)
|
w.log.Warn("Ledger nonce retrieval failed", "err", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// If the next account is empty, stop self-derivation, but add it nonetheless
|
// If the next account is empty, stop self-derivation, but add it nonetheless
|
||||||
if balance.BitLen() == 0 && nonce == 0 {
|
if balance.Sign() == 0 && nonce == 0 {
|
||||||
empty = true
|
empty = true
|
||||||
}
|
}
|
||||||
// We've just self-derived a new account, start tracking it locally
|
// We've just self-derived a new account, start tracking it locally
|
||||||
|
|
@ -430,7 +432,7 @@ func (w *ledgerWallet) selfDerive() {
|
||||||
|
|
||||||
// Display a log message to the user for new (or previously empty accounts)
|
// Display a log message to the user for new (or previously empty accounts)
|
||||||
if _, known := w.paths[nextAddr]; !known || (!empty && nextAddr == w.deriveNextAddr) {
|
if _, known := w.paths[nextAddr]; !known || (!empty && nextAddr == w.deriveNextAddr) {
|
||||||
glog.V(logger.Info).Infof("%s discovered %s (balance %22v, nonce %4d) at %s", w.url.String(), nextAddr.Hex(), balance, nonce, path)
|
w.log.Info("Ledger discovered new account", "address", nextAddr, "path", path, "balance", balance, "nonce", nonce)
|
||||||
}
|
}
|
||||||
// Fetch the next potential account
|
// Fetch the next potential account
|
||||||
if !empty {
|
if !empty {
|
||||||
|
|
@ -469,7 +471,7 @@ func (w *ledgerWallet) selfDerive() {
|
||||||
}
|
}
|
||||||
// In case of error, wait for termination
|
// In case of error, wait for termination
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Debug).Infof("%s self-derivation failed: %s", w.url.String(), err)
|
w.log.Debug("Ledger self-derivation failed", "err", err)
|
||||||
errc = <-w.deriveQuit
|
errc = <-w.deriveQuit
|
||||||
}
|
}
|
||||||
errc <- err
|
errc <- err
|
||||||
|
|
@ -849,9 +851,7 @@ func (w *ledgerWallet) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 l
|
||||||
apdu = nil
|
apdu = nil
|
||||||
}
|
}
|
||||||
// Send over to the device
|
// Send over to the device
|
||||||
if glog.V(logger.Detail) {
|
w.log.Trace("Data chunk sent to the Ledger", "chunk", hexutil.Bytes(chunk))
|
||||||
glog.Infof("-> %s: %x", w.device.Path, chunk)
|
|
||||||
}
|
|
||||||
if _, err := w.device.Write(chunk); err != nil {
|
if _, err := w.device.Write(chunk); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -864,9 +864,8 @@ func (w *ledgerWallet) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 l
|
||||||
if _, err := io.ReadFull(w.device, chunk); err != nil {
|
if _, err := io.ReadFull(w.device, chunk); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if glog.V(logger.Detail) {
|
w.log.Trace("Data chunk received from the Ledger", "chunk", hexutil.Bytes(chunk))
|
||||||
glog.Infof("<- %s: %x", w.device.Path, chunk)
|
|
||||||
}
|
|
||||||
// Make sure the transport header matches
|
// Make sure the transport header matches
|
||||||
if chunk[0] != 0x01 || chunk[1] != 0x01 || chunk[2] != 0x05 {
|
if chunk[0] != 0x01 || chunk[1] != 0x01 || chunk[2] != 0x05 {
|
||||||
return nil, errReplyInvalidHeader
|
return nil, errReplyInvalidHeader
|
||||||
|
|
|
||||||
|
|
@ -34,4 +34,4 @@ after_build:
|
||||||
- GO run build\ci.go archive -type zip
|
- GO run build\ci.go archive -type zip
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: gexp-*.zip
|
- path: gexp-*.zip
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
# Vendored Dependencies
|
|
||||||
|
|
||||||
Dependencies are almost all vendored in at the standard Go `/vendor` path. This allows
|
|
||||||
people to build go-expanse using the standard toolchain without any particular package
|
|
||||||
manager. It also plays nicely with `go get`, not requiring external code to be relied on.
|
|
||||||
|
|
||||||
The one single dependent package missing from `vendor` is `golang.org/x/net/context`. As
|
|
||||||
this is a package exposed via public library APIs, it must not be vendored as dependent
|
|
||||||
code woulnd't be able to instantiate.
|
|
||||||
|
|
||||||
To allow reproducible builds of go-expanse nonetheless that don't need network access
|
|
||||||
during build time to fetch `golang.org/x/net/context`, a version was copied into our repo
|
|
||||||
at the very specific `/build/_vendor` path, which is added automatically by all CI build
|
|
||||||
scripts and the makefile too.
|
|
||||||
|
|
||||||
# Debian Packaging
|
# Debian Packaging
|
||||||
|
|
||||||
Tagged releases and develop branch commits are available as installable Debian packages
|
Tagged releases and develop branch commits are available as installable Debian packages
|
||||||
|
|
|
||||||
93
build/ci.go
93
build/ci.go
|
|
@ -23,15 +23,15 @@ Usage: go run ci.go <command> <command flags/arguments>
|
||||||
|
|
||||||
Available commands are:
|
Available commands are:
|
||||||
|
|
||||||
install [-arch architecture] [ packages... ] -- builds packages and executables
|
install [ -arch architecture ] [ packages... ] -- builds packages and executables
|
||||||
test [ -coverage ] [ -vet ] [ -misspell ] [ packages... ] -- runs the tests
|
test [ -coverage ] [ -misspell ] [ packages... ] -- runs the tests
|
||||||
archive [-arch architecture] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts
|
archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts
|
||||||
importkeys -- imports signing keys from env
|
importkeys -- imports signing keys from env
|
||||||
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
||||||
nsis -- creates a Windows NSIS installer
|
nsis -- creates a Windows NSIS installer
|
||||||
aar [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an Android archive
|
aar [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an Android archive
|
||||||
xcode [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an iOS XCode framework
|
xcode [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an iOS XCode framework
|
||||||
xgo [ options ] -- cross builds according to options
|
xgo [ -alltools ] [ options ] -- cross builds according to options
|
||||||
|
|
||||||
For all commands, -n prevents execution of external programs (dry run mode).
|
For all commands, -n prevents execution of external programs (dry run mode).
|
||||||
|
|
||||||
|
|
@ -70,6 +70,7 @@ var (
|
||||||
allToolsArchiveFiles = []string{
|
allToolsArchiveFiles = []string{
|
||||||
"COPYING",
|
"COPYING",
|
||||||
executablePath("abigen"),
|
executablePath("abigen"),
|
||||||
|
executablePath("bootnode"),
|
||||||
executablePath("evm"),
|
executablePath("evm"),
|
||||||
executablePath("gexp"),
|
executablePath("gexp"),
|
||||||
executablePath("swarm"),
|
executablePath("swarm"),
|
||||||
|
|
@ -82,6 +83,10 @@ var (
|
||||||
Name: "gexp",
|
Name: "gexp",
|
||||||
Description: "Expanse CLI client.",
|
Description: "Expanse CLI client.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "bootnode",
|
||||||
|
Description: "Ethereum bootnode.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "rlpdump",
|
Name: "rlpdump",
|
||||||
Description: "Developer utility tool that prints RLP structures.",
|
Description: "Developer utility tool that prints RLP structures.",
|
||||||
|
|
@ -157,9 +162,9 @@ 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 runtime.Version() < "go1.4" && !strings.HasPrefix(runtime.Version(), "devel") {
|
if runtime.Version() < "go1.7" && !strings.HasPrefix(runtime.Version(), "devel") {
|
||||||
log.Println("You have Go version", runtime.Version())
|
log.Println("You have Go version", runtime.Version())
|
||||||
log.Println("go-expanse requires at least Go version 1.4 and cannot")
|
log.Println("go-expanse requires at least Go version 1.7 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)
|
||||||
}
|
}
|
||||||
|
|
@ -168,6 +173,8 @@ func doInstall(cmdline []string) {
|
||||||
if flag.NArg() > 0 {
|
if flag.NArg() > 0 {
|
||||||
packages = flag.Args()
|
packages = flag.Args()
|
||||||
}
|
}
|
||||||
|
packages = build.ExpandPackagesNoVendor(packages)
|
||||||
|
|
||||||
if *arch == "" || *arch == runtime.GOARCH {
|
if *arch == "" || *arch == runtime.GOARCH {
|
||||||
goinstall := goTool("install", buildFlags(env)...)
|
goinstall := goTool("install", buildFlags(env)...)
|
||||||
goinstall.Args = append(goinstall.Args, "-v")
|
goinstall.Args = append(goinstall.Args, "-v")
|
||||||
|
|
@ -210,20 +217,9 @@ func doInstall(cmdline []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildFlags(env build.Environment) (flags []string) {
|
func buildFlags(env build.Environment) (flags []string) {
|
||||||
if os.Getenv("GO_OPENCL") != "" {
|
|
||||||
flags = append(flags, "-tags", "opencl")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since Go 1.5, the separator char for link time assignments
|
|
||||||
// is '=' and using ' ' prints a warning. However, Go < 1.5 does
|
|
||||||
// not support using '='.
|
|
||||||
sep := " "
|
|
||||||
if runtime.Version() > "go1.5" || strings.Contains(runtime.Version(), "devel") {
|
|
||||||
sep = "="
|
|
||||||
}
|
|
||||||
// Set gitCommit constant via link-time assignment.
|
// Set gitCommit constant via link-time assignment.
|
||||||
if env.Commit != "" {
|
if env.Commit != "" {
|
||||||
flags = append(flags, "-ldflags", "-X main.gitCommit"+sep+env.Commit)
|
flags = append(flags, "-ldflags", "-X main.gitCommit="+env.Commit)
|
||||||
}
|
}
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
@ -244,10 +240,7 @@ func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd {
|
||||||
cmd.Args = append(cmd.Args, []string{"-ldflags", "-extldflags -Wl,--allow-multiple-definition"}...)
|
cmd.Args = append(cmd.Args, []string{"-ldflags", "-extldflags -Wl,--allow-multiple-definition"}...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd.Env = []string{
|
cmd.Env = []string{"GOPATH=" + build.GOPATH()}
|
||||||
"GO15VENDOREXPERIMENT=1",
|
|
||||||
"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)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -269,7 +262,6 @@ func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd {
|
||||||
|
|
||||||
func doTest(cmdline []string) {
|
func doTest(cmdline []string) {
|
||||||
var (
|
var (
|
||||||
vet = flag.Bool("vet", false, "Whether to run go vet")
|
|
||||||
misspell = flag.Bool("misspell", false, "Whether to run the spell checker")
|
misspell = flag.Bool("misspell", false, "Whether to run the spell checker")
|
||||||
coverage = flag.Bool("coverage", false, "Whether to record code coverage")
|
coverage = flag.Bool("coverage", false, "Whether to record code coverage")
|
||||||
)
|
)
|
||||||
|
|
@ -279,23 +271,10 @@ func doTest(cmdline []string) {
|
||||||
if len(flag.CommandLine.Args()) > 0 {
|
if len(flag.CommandLine.Args()) > 0 {
|
||||||
packages = flag.CommandLine.Args()
|
packages = flag.CommandLine.Args()
|
||||||
}
|
}
|
||||||
if len(packages) == 1 && packages[0] == "./..." {
|
packages = build.ExpandPackagesNoVendor(packages)
|
||||||
// Resolve ./... manually since go vet will fail on vendored stuff
|
|
||||||
out, err := goTool("list", "./...").CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("package listing failed: %v\n%s", err, string(out))
|
|
||||||
}
|
|
||||||
packages = []string{}
|
|
||||||
for _, line := range strings.Split(string(out), "\n") {
|
|
||||||
if !strings.Contains(line, "vendor") {
|
|
||||||
packages = append(packages, strings.TrimSpace(line))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Run analysis tools before the tests.
|
// Run analysis tools before the tests.
|
||||||
if *vet {
|
build.MustRun(goTool("vet", packages...))
|
||||||
build.MustRun(goTool("vet", packages...))
|
|
||||||
}
|
|
||||||
if *misspell {
|
if *misspell {
|
||||||
spellcheck(packages)
|
spellcheck(packages)
|
||||||
}
|
}
|
||||||
|
|
@ -917,6 +896,9 @@ func newPodMetadata(env build.Environment, archive string) podMetadata {
|
||||||
// Cross compilation
|
// Cross compilation
|
||||||
|
|
||||||
func doXgo(cmdline []string) {
|
func doXgo(cmdline []string) {
|
||||||
|
var (
|
||||||
|
alltools = flag.Bool("alltools", false, `Flag whether we're building all known tools, or only on in particular`)
|
||||||
|
)
|
||||||
flag.CommandLine.Parse(cmdline)
|
flag.CommandLine.Parse(cmdline)
|
||||||
env := build.Env()
|
env := build.Env()
|
||||||
|
|
||||||
|
|
@ -924,8 +906,27 @@ func doXgo(cmdline []string) {
|
||||||
gogetxgo := goTool("get", "github.com/karalabe/xgo")
|
gogetxgo := goTool("get", "github.com/karalabe/xgo")
|
||||||
build.MustRun(gogetxgo)
|
build.MustRun(gogetxgo)
|
||||||
|
|
||||||
// Execute the actual cross compilation
|
// If all tools building is requested, build everything the builder wants
|
||||||
xgo := xgoTool(append(buildFlags(env), flag.Args()...))
|
args := append(buildFlags(env), flag.Args()...)
|
||||||
|
|
||||||
|
if *alltools {
|
||||||
|
args = append(args, []string{"--dest", GOBIN}...)
|
||||||
|
for _, res := range allToolsArchiveFiles {
|
||||||
|
if strings.HasPrefix(res, GOBIN) {
|
||||||
|
// Binary tool found, cross build it explicitly
|
||||||
|
args = append(args, "./"+filepath.Join("cmd", filepath.Base(res)))
|
||||||
|
xgo := xgoTool(args)
|
||||||
|
build.MustRun(xgo)
|
||||||
|
args = args[:len(args)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Otherwise xxecute the explicit cross compilation
|
||||||
|
path := args[len(args)-1]
|
||||||
|
args = append(args[:len(args)-1], []string{"--dest", GOBIN, path}...)
|
||||||
|
|
||||||
|
xgo := xgoTool(args)
|
||||||
build.MustRun(xgo)
|
build.MustRun(xgo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ fi
|
||||||
|
|
||||||
# Set up the environment to use the workspace.
|
# Set up the environment to use the workspace.
|
||||||
GOPATH="$workspace"
|
GOPATH="$workspace"
|
||||||
GO15VENDOREXPERIMENT=1
|
export GOPATH
|
||||||
export GOPATH GO15VENDOREXPERIMENT
|
|
||||||
|
|
||||||
# Run the command inside the workspace.
|
# Run the command inside the workspace.
|
||||||
cd "$ethdir/go-expanse"
|
cd "$ethdir/go-expanse"
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ var (
|
||||||
// boring stuff
|
// boring stuff
|
||||||
"vendor/", "tests/files/", "build/",
|
"vendor/", "tests/files/", "build/",
|
||||||
// don't relicense vendored sources
|
// don't relicense vendored sources
|
||||||
"crypto/sha3/", "crypto/ecies/", "logger/glog/",
|
"crypto/sha3/", "crypto/ecies/", "log/",
|
||||||
"crypto/secp256k1/curve.go",
|
"crypto/secp256k1/curve.go",
|
||||||
// don't license generated files
|
// don't license generated files
|
||||||
"contracts/chequebook/contract/",
|
"contracts/chequebook/contract/",
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import (
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/cmd/utils"
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/p2p/discover"
|
"github.com/expanse-org/go-expanse/p2p/discover"
|
||||||
"github.com/expanse-org/go-expanse/p2p/discv5"
|
"github.com/expanse-org/go-expanse/p2p/discv5"
|
||||||
"github.com/expanse-org/go-expanse/p2p/nat"
|
"github.com/expanse-org/go-expanse/p2p/nat"
|
||||||
|
|
@ -42,15 +42,19 @@ func main() {
|
||||||
natdesc = flag.String("nat", "none", "port mapping mechanism (any|none|upnp|pmp|extip:<IP>)")
|
natdesc = flag.String("nat", "none", "port mapping mechanism (any|none|upnp|pmp|extip:<IP>)")
|
||||||
netrestrict = flag.String("netrestrict", "", "restrict network communication to the given IP networks (CIDR masks)")
|
netrestrict = flag.String("netrestrict", "", "restrict network communication to the given IP networks (CIDR masks)")
|
||||||
runv5 = flag.Bool("v5", false, "run a v5 topic discovery bootnode")
|
runv5 = flag.Bool("v5", false, "run a v5 topic discovery bootnode")
|
||||||
|
verbosity = flag.Int("verbosity", int(log.LvlInfo), "log verbosity (0-9)")
|
||||||
|
vmodule = flag.String("vmodule", "", "log verbosity pattern")
|
||||||
|
|
||||||
nodeKey *ecdsa.PrivateKey
|
nodeKey *ecdsa.PrivateKey
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
flag.Var(glog.GetVerbosity(), "verbosity", "log verbosity (0-9)")
|
|
||||||
flag.Var(glog.GetVModule(), "vmodule", "log verbosity pattern")
|
|
||||||
glog.SetToStderr(true)
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
|
||||||
|
glogger.Verbosity(log.Lvl(*verbosity))
|
||||||
|
glogger.Vmodule(*vmodule)
|
||||||
|
log.Root().SetHandler(glogger)
|
||||||
|
|
||||||
natm, err := nat.Parse(*natdesc)
|
natm, err := nat.Parse(*natdesc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("-nat: %v", err)
|
utils.Fatalf("-nat: %v", err)
|
||||||
|
|
|
||||||
55
cmd/evm/compiler.go
Normal file
55
cmd/evm/compiler.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/cmd/evm/internal/compiler"
|
||||||
|
|
||||||
|
cli "gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var compileCommand = cli.Command{
|
||||||
|
Action: compileCmd,
|
||||||
|
Name: "compile",
|
||||||
|
Usage: "compiles easm source to evm binary",
|
||||||
|
ArgsUsage: "<file>",
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileCmd(ctx *cli.Context) error {
|
||||||
|
debug := ctx.GlobalBool(DebugFlag.Name)
|
||||||
|
|
||||||
|
if len(ctx.Args().First()) == 0 {
|
||||||
|
return errors.New("filename required")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := ctx.Args().First()
|
||||||
|
src, err := ioutil.ReadFile(fn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bin, err := compiler.Compile(fn, src, debug)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(bin)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
53
cmd/evm/disasm.go
Normal file
53
cmd/evm/disasm.go
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/core/asm"
|
||||||
|
cli "gopkg.in/urfave/cli.v1"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var disasmCommand = cli.Command{
|
||||||
|
Action: disasmCmd,
|
||||||
|
Name: "disasm",
|
||||||
|
Usage: "disassembles evm binary",
|
||||||
|
ArgsUsage: "<file>",
|
||||||
|
}
|
||||||
|
|
||||||
|
func disasmCmd(ctx *cli.Context) error {
|
||||||
|
if len(ctx.Args().First()) == 0 {
|
||||||
|
return errors.New("filename required")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := ctx.Args().First()
|
||||||
|
in, err := ioutil.ReadFile(fn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
code := strings.TrimSpace(string(in[:]))
|
||||||
|
fmt.Printf("%v\n", code)
|
||||||
|
if err = asm.PrintDisassembled(code); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
39
cmd/evm/internal/compiler/compiler.go
Normal file
39
cmd/evm/internal/compiler/compiler.go
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package compiler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/core/asm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Compile(fn string, src []byte, debug bool) (string, error) {
|
||||||
|
compiler := asm.NewCompiler(debug)
|
||||||
|
compiler.Feed(asm.Lex(fn, src, debug))
|
||||||
|
|
||||||
|
bin, compileErrors := compiler.Compile()
|
||||||
|
if len(compileErrors) > 0 {
|
||||||
|
// report errors
|
||||||
|
for _, err := range compileErrors {
|
||||||
|
fmt.Printf("%s:%v\n", fn, err)
|
||||||
|
}
|
||||||
|
return "", errors.New("compiling failed")
|
||||||
|
}
|
||||||
|
return bin, nil
|
||||||
|
}
|
||||||
132
cmd/evm/main.go
132
cmd/evm/main.go
|
|
@ -19,19 +19,10 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
goruntime "runtime"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/cmd/utils"
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
"github.com/expanse-org/go-expanse/common"
|
|
||||||
"github.com/expanse-org/go-expanse/core/state"
|
|
||||||
"github.com/expanse-org/go-expanse/core/vm"
|
|
||||||
"github.com/expanse-org/go-expanse/core/vm/runtime"
|
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -52,20 +43,20 @@ var (
|
||||||
Name: "codefile",
|
Name: "codefile",
|
||||||
Usage: "file containing EVM code",
|
Usage: "file containing EVM code",
|
||||||
}
|
}
|
||||||
GasFlag = cli.StringFlag{
|
GasFlag = cli.Uint64Flag{
|
||||||
Name: "gas",
|
Name: "gas",
|
||||||
Usage: "gas limit for the evm",
|
Usage: "gas limit for the evm",
|
||||||
Value: "10000000000",
|
Value: 10000000000,
|
||||||
}
|
}
|
||||||
PriceFlag = cli.StringFlag{
|
PriceFlag = utils.BigFlag{
|
||||||
Name: "price",
|
Name: "price",
|
||||||
Usage: "price set for the evm",
|
Usage: "price set for the evm",
|
||||||
Value: "0",
|
Value: new(big.Int),
|
||||||
}
|
}
|
||||||
ValueFlag = cli.StringFlag{
|
ValueFlag = utils.BigFlag{
|
||||||
Name: "value",
|
Name: "value",
|
||||||
Usage: "value set for the evm",
|
Usage: "value set for the evm",
|
||||||
Value: "0",
|
Value: new(big.Int),
|
||||||
}
|
}
|
||||||
DumpFlag = cli.BoolFlag{
|
DumpFlag = cli.BoolFlag{
|
||||||
Name: "dump",
|
Name: "dump",
|
||||||
|
|
@ -75,10 +66,6 @@ var (
|
||||||
Name: "input",
|
Name: "input",
|
||||||
Usage: "input for the EVM",
|
Usage: "input for the EVM",
|
||||||
}
|
}
|
||||||
SysStatFlag = cli.BoolFlag{
|
|
||||||
Name: "sysstat",
|
|
||||||
Usage: "display system stats",
|
|
||||||
}
|
|
||||||
VerbosityFlag = cli.IntFlag{
|
VerbosityFlag = cli.IntFlag{
|
||||||
Name: "verbosity",
|
Name: "verbosity",
|
||||||
Usage: "sets the verbosity level",
|
Usage: "sets the verbosity level",
|
||||||
|
|
@ -98,7 +85,6 @@ func init() {
|
||||||
CreateFlag,
|
CreateFlag,
|
||||||
DebugFlag,
|
DebugFlag,
|
||||||
VerbosityFlag,
|
VerbosityFlag,
|
||||||
SysStatFlag,
|
|
||||||
CodeFlag,
|
CodeFlag,
|
||||||
CodeFileFlag,
|
CodeFileFlag,
|
||||||
GasFlag,
|
GasFlag,
|
||||||
|
|
@ -108,107 +94,11 @@ func init() {
|
||||||
InputFlag,
|
InputFlag,
|
||||||
DisableGasMeteringFlag,
|
DisableGasMeteringFlag,
|
||||||
}
|
}
|
||||||
app.Action = run
|
app.Commands = []cli.Command{
|
||||||
}
|
compileCommand,
|
||||||
|
disasmCommand,
|
||||||
func run(ctx *cli.Context) error {
|
runCommand,
|
||||||
glog.SetToStderr(true)
|
|
||||||
glog.SetV(ctx.GlobalInt(VerbosityFlag.Name))
|
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
|
||||||
sender := statedb.CreateAccount(common.StringToAddress("sender"))
|
|
||||||
|
|
||||||
logger := vm.NewStructLogger(nil)
|
|
||||||
|
|
||||||
tstart := time.Now()
|
|
||||||
|
|
||||||
var (
|
|
||||||
code []byte
|
|
||||||
ret []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
if ctx.GlobalString(CodeFlag.Name) != "" {
|
|
||||||
code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))
|
|
||||||
} else {
|
|
||||||
var hexcode []byte
|
|
||||||
if ctx.GlobalString(CodeFileFlag.Name) != "" {
|
|
||||||
var err error
|
|
||||||
hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Could not load code from file: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
hexcode, err = ioutil.ReadAll(os.Stdin)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Could not load code from stdin: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
code = common.Hex2Bytes(string(hexcode[:]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.GlobalBool(CreateFlag.Name) {
|
|
||||||
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
|
|
||||||
ret, _, err = runtime.Create(input, &runtime.Config{
|
|
||||||
Origin: sender.Address(),
|
|
||||||
State: statedb,
|
|
||||||
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(),
|
|
||||||
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
|
||||||
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
|
||||||
EVMConfig: vm.Config{
|
|
||||||
Tracer: logger,
|
|
||||||
Debug: ctx.GlobalBool(DebugFlag.Name),
|
|
||||||
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
|
|
||||||
receiver.SetCode(crypto.Keccak256Hash(code), code)
|
|
||||||
|
|
||||||
ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
|
|
||||||
Origin: sender.Address(),
|
|
||||||
State: statedb,
|
|
||||||
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(),
|
|
||||||
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
|
||||||
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
|
||||||
EVMConfig: vm.Config{
|
|
||||||
Tracer: logger,
|
|
||||||
Debug: ctx.GlobalBool(DebugFlag.Name),
|
|
||||||
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
vmdone := time.Since(tstart)
|
|
||||||
|
|
||||||
if ctx.GlobalBool(DumpFlag.Name) {
|
|
||||||
statedb.Commit(true)
|
|
||||||
fmt.Println(string(statedb.Dump()))
|
|
||||||
}
|
|
||||||
vm.StdErrFormat(logger.StructLogs())
|
|
||||||
|
|
||||||
if ctx.GlobalBool(SysStatFlag.Name) {
|
|
||||||
var mem goruntime.MemStats
|
|
||||||
goruntime.ReadMemStats(&mem)
|
|
||||||
fmt.Printf("vm took %v\n", vmdone)
|
|
||||||
fmt.Printf(`alloc: %d
|
|
||||||
tot alloc: %d
|
|
||||||
no. malloc: %d
|
|
||||||
heap alloc: %d
|
|
||||||
heap objs: %d
|
|
||||||
num gc: %d
|
|
||||||
`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("OUT: 0x%x", ret)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf(" error: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
151
cmd/evm/runner.go
Normal file
151
cmd/evm/runner.go
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
goruntime "runtime"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/cmd/evm/internal/compiler"
|
||||||
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/core/state"
|
||||||
|
"github.com/expanse-org/go-expanse/core/vm"
|
||||||
|
"github.com/expanse-org/go-expanse/core/vm/runtime"
|
||||||
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
|
"github.com/expanse-org/go-expanse/log"
|
||||||
|
cli "gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var runCommand = cli.Command{
|
||||||
|
Action: runCmd,
|
||||||
|
Name: "run",
|
||||||
|
Usage: "run arbitrary evm binary",
|
||||||
|
ArgsUsage: "<code>",
|
||||||
|
Description: `The run command runs arbitrary EVM code.`,
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCmd(ctx *cli.Context) error {
|
||||||
|
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
|
||||||
|
glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name)))
|
||||||
|
log.Root().SetHandler(glogger)
|
||||||
|
|
||||||
|
var (
|
||||||
|
db, _ = ethdb.NewMemDatabase()
|
||||||
|
statedb, _ = state.New(common.Hash{}, db)
|
||||||
|
sender = common.StringToAddress("sender")
|
||||||
|
logger = vm.NewStructLogger(nil)
|
||||||
|
)
|
||||||
|
statedb.CreateAccount(sender)
|
||||||
|
|
||||||
|
var (
|
||||||
|
code []byte
|
||||||
|
ret []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if fn := ctx.Args().First(); len(fn) > 0 {
|
||||||
|
src, err := ioutil.ReadFile(fn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bin, err := compiler.Compile(fn, src, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
code = common.Hex2Bytes(bin)
|
||||||
|
} else if ctx.GlobalString(CodeFlag.Name) != "" {
|
||||||
|
code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))
|
||||||
|
} else {
|
||||||
|
var hexcode []byte
|
||||||
|
if ctx.GlobalString(CodeFileFlag.Name) != "" {
|
||||||
|
var err error
|
||||||
|
hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Could not load code from file: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
hexcode, err = ioutil.ReadAll(os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Could not load code from stdin: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n")))
|
||||||
|
}
|
||||||
|
|
||||||
|
runtimeConfig := runtime.Config{
|
||||||
|
Origin: sender,
|
||||||
|
State: statedb,
|
||||||
|
GasLimit: ctx.GlobalUint64(GasFlag.Name),
|
||||||
|
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
|
||||||
|
Value: utils.GlobalBig(ctx, ValueFlag.Name),
|
||||||
|
EVMConfig: vm.Config{
|
||||||
|
Tracer: logger,
|
||||||
|
Debug: ctx.GlobalBool(DebugFlag.Name),
|
||||||
|
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tstart := time.Now()
|
||||||
|
if ctx.GlobalBool(CreateFlag.Name) {
|
||||||
|
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
|
||||||
|
ret, _, err = runtime.Create(input, &runtimeConfig)
|
||||||
|
} else {
|
||||||
|
receiver := common.StringToAddress("receiver")
|
||||||
|
statedb.SetCode(receiver, code)
|
||||||
|
|
||||||
|
ret, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig)
|
||||||
|
}
|
||||||
|
execTime := time.Since(tstart)
|
||||||
|
|
||||||
|
if ctx.GlobalBool(DumpFlag.Name) {
|
||||||
|
statedb.Commit(true)
|
||||||
|
fmt.Println(string(statedb.Dump()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.GlobalBool(DebugFlag.Name) {
|
||||||
|
fmt.Fprintln(os.Stderr, "#### TRACE ####")
|
||||||
|
vm.WriteTrace(os.Stderr, logger.StructLogs())
|
||||||
|
fmt.Fprintln(os.Stderr, "#### LOGS ####")
|
||||||
|
vm.WriteLogs(os.Stderr, statedb.Logs())
|
||||||
|
|
||||||
|
var mem goruntime.MemStats
|
||||||
|
goruntime.ReadMemStats(&mem)
|
||||||
|
fmt.Fprintf(os.Stderr, `evm execution time: %v
|
||||||
|
heap objects: %d
|
||||||
|
allocations: %d
|
||||||
|
total allocations: %d
|
||||||
|
GC calls: %d
|
||||||
|
|
||||||
|
`, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("0x%x", ret)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf(" error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -25,8 +25,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/cmd/utils"
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
"github.com/expanse-org/go-expanse/console"
|
"github.com/expanse-org/go-expanse/console"
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -203,11 +202,11 @@ func unlockAccount(ctx *cli.Context, ks *keystore.KeyStore, address string, i in
|
||||||
password := getPassPhrase(prompt, false, i, passwords)
|
password := getPassPhrase(prompt, false, i, passwords)
|
||||||
err = ks.Unlock(account, password)
|
err = ks.Unlock(account, password)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
glog.V(logger.Info).Infof("Unlocked account %x", account.Address)
|
log.Info("Unlocked account", "address", account.Address.Hex())
|
||||||
return account, password
|
return account, password
|
||||||
}
|
}
|
||||||
if err, ok := err.(*keystore.AmbiguousAddrError); ok {
|
if err, ok := err.(*keystore.AmbiguousAddrError); ok {
|
||||||
glog.V(logger.Info).Infof("Unlocked account %x", account.Address)
|
log.Info("Unlocked account", "address", account.Address.Hex())
|
||||||
return ambiguousAddrRecovery(ks, err, password), password
|
return ambiguousAddrRecovery(ks, err, password), password
|
||||||
}
|
}
|
||||||
if err != keystore.ErrDecrypt {
|
if err != keystore.ErrDecrypt {
|
||||||
|
|
@ -217,6 +216,7 @@ func unlockAccount(ctx *cli.Context, ks *keystore.KeyStore, address string, i in
|
||||||
}
|
}
|
||||||
// All trials expended to unlock account, bail out
|
// All trials expended to unlock account, bail out
|
||||||
utils.Fatalf("Failed to unlock account %s (%v)", address, err)
|
utils.Fatalf("Failed to unlock account %s (%v)", address, err)
|
||||||
|
|
||||||
return accounts.Account{}, ""
|
return accounts.Account{}, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,8 @@ Passphrase: {{.InputLine "foobar"}}
|
||||||
gexp.expectExit()
|
gexp.expectExit()
|
||||||
|
|
||||||
wantMessages := []string{
|
wantMessages := []string{
|
||||||
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
|
"Unlocked account",
|
||||||
|
"=0xf466859ead1932d743d622cb74fc058882e8648a",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if !strings.Contains(gexp.stderrText(), m) {
|
if !strings.Contains(gexp.stderrText(), m) {
|
||||||
|
|
@ -189,8 +190,9 @@ Passphrase: {{.InputLine "foobar"}}
|
||||||
gexp.expectExit()
|
gexp.expectExit()
|
||||||
|
|
||||||
wantMessages := []string{
|
wantMessages := []string{
|
||||||
"Unlocked account 7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
|
"Unlocked account",
|
||||||
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
|
"=0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
|
||||||
|
"=0x289d485d9771714cce91d3393d764e1311907acc",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if !strings.Contains(gexp.stderrText(), m) {
|
if !strings.Contains(gexp.stderrText(), m) {
|
||||||
|
|
@ -208,8 +210,9 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
|
||||||
gexp.expectExit()
|
gexp.expectExit()
|
||||||
|
|
||||||
wantMessages := []string{
|
wantMessages := []string{
|
||||||
"Unlocked account 7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
|
"Unlocked account",
|
||||||
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
|
"=0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
|
||||||
|
"=0x289d485d9771714cce91d3393d764e1311907acc",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if !strings.Contains(gexp.stderrText(), m) {
|
if !strings.Contains(gexp.stderrText(), m) {
|
||||||
|
|
@ -257,7 +260,8 @@ In order to avoid this warning, you need to remove the following duplicate key f
|
||||||
gexp.expectExit()
|
gexp.expectExit()
|
||||||
|
|
||||||
wantMessages := []string{
|
wantMessages := []string{
|
||||||
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
|
"Unlocked account",
|
||||||
|
"=0xf466859ead1932d743d622cb74fc058882e8648a",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if !strings.Contains(gexp.stderrText(), m) {
|
if !strings.Contains(gexp.stderrText(), m) {
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
@ -32,8 +32,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/core/state"
|
"github.com/expanse-org/go-expanse/core/state"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/trie"
|
"github.com/expanse-org/go-expanse/trie"
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
|
@ -56,10 +55,13 @@ participating.
|
||||||
Action: importChain,
|
Action: importChain,
|
||||||
Name: "import",
|
Name: "import",
|
||||||
Usage: "Import a blockchain file",
|
Usage: "Import a blockchain file",
|
||||||
ArgsUsage: "<filename>",
|
ArgsUsage: "<filename> (<filename 2> ... <filename N>) ",
|
||||||
Category: "BLOCKCHAIN COMMANDS",
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
Description: `
|
Description: `
|
||||||
TODO: Please write this
|
The import command imports blocks from an RLP-encoded form. The form can be one file
|
||||||
|
with several RLP-encoded blocks, or several files can be used.
|
||||||
|
If only one file is used, import error will result in failure. If several files are used,
|
||||||
|
processing will proceed even if an individual RLP-file import failure occurs.
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
exportCommand = cli.Command{
|
exportCommand = cli.Command{
|
||||||
|
|
@ -73,16 +75,6 @@ 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.
|
||||||
`,
|
|
||||||
}
|
|
||||||
upgradedbCommand = cli.Command{
|
|
||||||
Action: upgradeDB,
|
|
||||||
Name: "upgradedb",
|
|
||||||
Usage: "Upgrade chainblock database",
|
|
||||||
ArgsUsage: " ",
|
|
||||||
Category: "BLOCKCHAIN COMMANDS",
|
|
||||||
Description: `
|
|
||||||
TODO: Please write this
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
removedbCommand = cli.Command{
|
removedbCommand = cli.Command{
|
||||||
|
|
@ -119,22 +111,27 @@ func initGenesis(ctx *cli.Context) error {
|
||||||
stack := makeFullNode(ctx)
|
stack := makeFullNode(ctx)
|
||||||
chaindb := utils.MakeChainDatabase(ctx, stack)
|
chaindb := utils.MakeChainDatabase(ctx, stack)
|
||||||
|
|
||||||
genesisFile, err := os.Open(genesisPath)
|
file, err := os.Open(genesisPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("failed to read genesis file: %v", err)
|
utils.Fatalf("failed to read genesis file: %v", err)
|
||||||
}
|
}
|
||||||
defer genesisFile.Close()
|
defer file.Close()
|
||||||
|
|
||||||
block, err := core.WriteGenesisBlock(chaindb, genesisFile)
|
genesis := new(core.Genesis)
|
||||||
|
if err := json.NewDecoder(file).Decode(genesis); err != nil {
|
||||||
|
utils.Fatalf("invalid genesis file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, hash, err := core.SetupGenesisBlock(chaindb, genesis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("failed to write genesis block: %v", err)
|
utils.Fatalf("failed to write genesis block: %v", err)
|
||||||
}
|
}
|
||||||
glog.V(logger.Info).Infof("successfully wrote genesis block and/or chain rule set: %x", block.Hash())
|
log.Info("Successfully wrote genesis state", "hash", hash)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func importChain(ctx *cli.Context) error {
|
func importChain(ctx *cli.Context) error {
|
||||||
if len(ctx.Args()) != 1 {
|
if len(ctx.Args()) < 1 {
|
||||||
utils.Fatalf("This command requires an argument.")
|
utils.Fatalf("This command requires an argument.")
|
||||||
}
|
}
|
||||||
stack := makeFullNode(ctx)
|
stack := makeFullNode(ctx)
|
||||||
|
|
@ -158,9 +155,19 @@ func importChain(ctx *cli.Context) error {
|
||||||
}()
|
}()
|
||||||
// Import the chain
|
// Import the chain
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
|
|
||||||
utils.Fatalf("Import error: %v", err)
|
if len(ctx.Args()) == 1 {
|
||||||
|
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
|
||||||
|
utils.Fatalf("Import error: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, arg := range ctx.Args() {
|
||||||
|
if err := utils.ImportChain(chain, arg); err != nil {
|
||||||
|
log.Error("Import error", "file", arg, "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Import done in %v.\n\n", time.Since(start))
|
fmt.Printf("Import done in %v.\n\n", time.Since(start))
|
||||||
|
|
||||||
// Output pre-compaction stats mostly to see the import trashing
|
// Output pre-compaction stats mostly to see the import trashing
|
||||||
|
|
@ -183,6 +190,10 @@ func importChain(ctx *cli.Context) error {
|
||||||
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
|
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
|
||||||
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
|
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
|
||||||
|
|
||||||
|
if ctx.GlobalIsSet(utils.NoCompactionFlag.Name) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Compact the entire database to more accurately measure disk io and print the stats
|
// Compact the entire database to more accurately measure disk io and print the stats
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
fmt.Println("Compacting entire database...")
|
fmt.Println("Compacting entire database...")
|
||||||
|
|
@ -256,49 +267,6 @@ func removeDB(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func upgradeDB(ctx *cli.Context) error {
|
|
||||||
glog.Infoln("Upgrading blockchain database")
|
|
||||||
|
|
||||||
stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
|
|
||||||
chain, chainDb := utils.MakeChain(ctx, stack)
|
|
||||||
bcVersion := core.GetBlockChainVersion(chainDb)
|
|
||||||
if bcVersion == 0 {
|
|
||||||
bcVersion = core.BlockChainVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
// Export the current chain.
|
|
||||||
filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("20060102_150405"))
|
|
||||||
exportFile := filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), filename)
|
|
||||||
if err := utils.ExportChain(chain, exportFile); err != nil {
|
|
||||||
utils.Fatalf("Unable to export chain for reimport %s", err)
|
|
||||||
}
|
|
||||||
chainDb.Close()
|
|
||||||
if dir := dbDirectory(chainDb); dir != "" {
|
|
||||||
os.RemoveAll(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import the chain file.
|
|
||||||
chain, chainDb = utils.MakeChain(ctx, stack)
|
|
||||||
core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
|
|
||||||
err := utils.ImportChain(chain, exportFile)
|
|
||||||
chainDb.Close()
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile)
|
|
||||||
} else {
|
|
||||||
os.Remove(exportFile)
|
|
||||||
glog.Infoln("Import finished")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dbDirectory(db ethdb.Database) string {
|
|
||||||
ldb, ok := db.(*ethdb.LDBDatabase)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return ldb.Path()
|
|
||||||
}
|
|
||||||
|
|
||||||
func dump(ctx *cli.Context) error {
|
func dump(ctx *cli.Context) error {
|
||||||
stack := makeFullNode(ctx)
|
stack := makeFullNode(ctx)
|
||||||
chain, chainDb := utils.MakeChain(ctx, stack)
|
chain, chainDb := utils.MakeChain(ctx, stack)
|
||||||
|
|
@ -330,9 +298,3 @@ func hashish(x string) bool {
|
||||||
_, err := strconv.Atoi(x)
|
_, err := strconv.Atoi(x)
|
||||||
return err != nil
|
return err != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeAll(dbs ...ethdb.Database) {
|
|
||||||
for _, db := range dbs {
|
|
||||||
db.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -29,13 +29,13 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/accounts/keystore"
|
"github.com/expanse-org/go-expanse/accounts/keystore"
|
||||||
"github.com/expanse-org/go-expanse/cmd/utils"
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/hexutil"
|
||||||
"github.com/expanse-org/go-expanse/console"
|
"github.com/expanse-org/go-expanse/console"
|
||||||
"github.com/expanse-org/go-expanse/contracts/release"
|
"github.com/expanse-org/go-expanse/contracts/release"
|
||||||
"github.com/expanse-org/go-expanse/eth"
|
"github.com/expanse-org/go-expanse/eth"
|
||||||
"github.com/expanse-org/go-expanse/ethclient"
|
"github.com/expanse-org/go-expanse/ethclient"
|
||||||
"github.com/expanse-org/go-expanse/internal/debug"
|
"github.com/expanse-org/go-expanse/internal/debug"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/metrics"
|
"github.com/expanse-org/go-expanse/metrics"
|
||||||
"github.com/expanse-org/go-expanse/node"
|
"github.com/expanse-org/go-expanse/node"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
|
|
@ -66,7 +66,6 @@ func init() {
|
||||||
initCommand,
|
initCommand,
|
||||||
importCommand,
|
importCommand,
|
||||||
exportCommand,
|
exportCommand,
|
||||||
upgradedbCommand,
|
|
||||||
removedbCommand,
|
removedbCommand,
|
||||||
dumpCommand,
|
dumpCommand,
|
||||||
// See monitorcmd.go:
|
// See monitorcmd.go:
|
||||||
|
|
@ -92,6 +91,12 @@ func init() {
|
||||||
utils.BootnodesFlag,
|
utils.BootnodesFlag,
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
utils.KeyStoreDirFlag,
|
utils.KeyStoreDirFlag,
|
||||||
|
utils.EthashCacheDirFlag,
|
||||||
|
utils.EthashCachesInMemoryFlag,
|
||||||
|
utils.EthashCachesOnDiskFlag,
|
||||||
|
utils.EthashDatasetDirFlag,
|
||||||
|
utils.EthashDatasetsInMemoryFlag,
|
||||||
|
utils.EthashDatasetsOnDiskFlag,
|
||||||
utils.FastSyncFlag,
|
utils.FastSyncFlag,
|
||||||
utils.LightModeFlag,
|
utils.LightModeFlag,
|
||||||
utils.LightServFlag,
|
utils.LightServFlag,
|
||||||
|
|
@ -107,7 +112,6 @@ func init() {
|
||||||
utils.GasPriceFlag,
|
utils.GasPriceFlag,
|
||||||
utils.MinerThreadsFlag,
|
utils.MinerThreadsFlag,
|
||||||
utils.MiningEnabledFlag,
|
utils.MiningEnabledFlag,
|
||||||
utils.AutoDAGFlag,
|
|
||||||
utils.TargetGasLimitFlag,
|
utils.TargetGasLimitFlag,
|
||||||
utils.NATFlag,
|
utils.NATFlag,
|
||||||
utils.NoDiscoverFlag,
|
utils.NoDiscoverFlag,
|
||||||
|
|
@ -141,6 +145,7 @@ func init() {
|
||||||
utils.EthStatsURLFlag,
|
utils.EthStatsURLFlag,
|
||||||
utils.MetricsEnabledFlag,
|
utils.MetricsEnabledFlag,
|
||||||
utils.FakePoWFlag,
|
utils.FakePoWFlag,
|
||||||
|
utils.NoCompactionFlag,
|
||||||
utils.SolcPathFlag,
|
utils.SolcPathFlag,
|
||||||
utils.GpoMinGasPriceFlag,
|
utils.GpoMinGasPriceFlag,
|
||||||
utils.GpoMaxGasPriceFlag,
|
utils.GpoMaxGasPriceFlag,
|
||||||
|
|
@ -204,11 +209,10 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
||||||
}{uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), clientIdentifier, runtime.Version(), runtime.GOOS}
|
}{uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), clientIdentifier, runtime.Version(), runtime.GOOS}
|
||||||
extra, err := rlp.EncodeToBytes(clientInfo)
|
extra, err := rlp.EncodeToBytes(clientInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
|
log.Warn("Failed to set canonical miner information", "err", err)
|
||||||
}
|
}
|
||||||
if uint64(len(extra)) > params.MaximumExtraDataSize {
|
if uint64(len(extra)) > params.MaximumExtraDataSize {
|
||||||
glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
|
log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize)
|
||||||
glog.V(logger.Debug).Infof("extra: %x\n", extra)
|
|
||||||
extra = nil
|
extra = nil
|
||||||
}
|
}
|
||||||
stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
|
stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
|
||||||
|
|
@ -273,7 +277,7 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||||
// Open and self derive any wallets already attached
|
// Open and self derive any wallets already attached
|
||||||
for _, wallet := range stack.AccountManager().Wallets() {
|
for _, wallet := range stack.AccountManager().Wallets() {
|
||||||
if err := wallet.Open(""); err != nil {
|
if err := wallet.Open(""); err != nil {
|
||||||
glog.V(logger.Warn).Infof("Failed to open wallet %s: %v", wallet.URL(), err)
|
log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
|
||||||
} else {
|
} else {
|
||||||
wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
|
wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
|
||||||
}
|
}
|
||||||
|
|
@ -282,13 +286,13 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||||
for event := range events {
|
for event := range events {
|
||||||
if event.Arrive {
|
if event.Arrive {
|
||||||
if err := event.Wallet.Open(""); err != nil {
|
if err := event.Wallet.Open(""); err != nil {
|
||||||
glog.V(logger.Info).Infof("New wallet appeared: %s, failed to open: %s", event.Wallet.URL(), err)
|
log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
|
||||||
} else {
|
} else {
|
||||||
glog.V(logger.Info).Infof("New wallet appeared: %s, %s", event.Wallet.URL(), event.Wallet.Status())
|
log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", event.Wallet.Status())
|
||||||
event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
|
event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
glog.V(logger.Info).Infof("Old wallet dropped: %s", event.Wallet.URL())
|
log.Info("Old wallet dropped", "url", event.Wallet.URL())
|
||||||
event.Wallet.Close()
|
event.Wallet.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/ethash"
|
|
||||||
"github.com/expanse-org/go-expanse/cmd/utils"
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
"github.com/expanse-org/go-expanse/eth"
|
"github.com/expanse-org/go-expanse/eth"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@ func makedag(ctx *cli.Context) error {
|
||||||
utils.Fatalf("Can't find dir")
|
utils.Fatalf("Can't find dir")
|
||||||
}
|
}
|
||||||
fmt.Println("making DAG, this could take awhile...")
|
fmt.Println("making DAG, this could take awhile...")
|
||||||
ethash.MakeDAG(blockNum, dir)
|
pow.MakeDataset(blockNum, dir)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
wrongArgs()
|
wrongArgs()
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,17 @@ var AppHelpFlagGroups = []flagGroup{
|
||||||
utils.LightKDFFlag,
|
utils.LightKDFFlag,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "ETHASH",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.EthashCacheDirFlag,
|
||||||
|
utils.EthashCachesInMemoryFlag,
|
||||||
|
utils.EthashCachesOnDiskFlag,
|
||||||
|
utils.EthashDatasetDirFlag,
|
||||||
|
utils.EthashDatasetsInMemoryFlag,
|
||||||
|
utils.EthashDatasetsOnDiskFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "PERFORMANCE TUNING",
|
Name: "PERFORMANCE TUNING",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
|
@ -131,7 +142,6 @@ var AppHelpFlagGroups = []flagGroup{
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
utils.MiningEnabledFlag,
|
utils.MiningEnabledFlag,
|
||||||
utils.MinerThreadsFlag,
|
utils.MinerThreadsFlag,
|
||||||
utils.AutoDAGFlag,
|
|
||||||
utils.EtherbaseFlag,
|
utils.EtherbaseFlag,
|
||||||
utils.TargetGasLimitFlag,
|
utils.TargetGasLimitFlag,
|
||||||
utils.GasPriceFlag,
|
utils.GasPriceFlag,
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/swarm/storage"
|
"github.com/expanse-org/go-expanse/swarm/storage"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
@ -26,14 +25,14 @@ import (
|
||||||
func cleandb(ctx *cli.Context) {
|
func cleandb(ctx *cli.Context) {
|
||||||
args := ctx.Args()
|
args := ctx.Args()
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
log.Fatal("need path to chunks database as the first and only argument")
|
utils.Fatalf("Need path to chunks database as the first and only argument")
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkDbPath := args[0]
|
chunkDbPath := args[0]
|
||||||
hash := storage.MakeHashFunc("SHA3")
|
hash := storage.MakeHashFunc("SHA3")
|
||||||
dbStore, err := storage.NewDbStore(chunkDbPath, hash, 10000000, 0)
|
dbStore, err := storage.NewDbStore(chunkDbPath, hash, 10000000, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("cannot initialise dbstore: %v", err)
|
utils.Fatalf("Cannot initialise dbstore: %v", err)
|
||||||
}
|
}
|
||||||
dbStore.Cleanup()
|
dbStore.Cleanup()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
"github.com/expanse-org/go-expanse/swarm/storage"
|
"github.com/expanse-org/go-expanse/swarm/storage"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
@ -29,12 +29,11 @@ import (
|
||||||
func hash(ctx *cli.Context) {
|
func hash(ctx *cli.Context) {
|
||||||
args := ctx.Args()
|
args := ctx.Args()
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
log.Fatal("Usage: swarm hash <file name>")
|
utils.Fatalf("Usage: swarm hash <file name>")
|
||||||
}
|
}
|
||||||
f, err := os.Open(args[0])
|
f, err := os.Open(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error opening file " + args[1])
|
utils.Fatalf("Error opening file " + args[1])
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
|
|
@ -42,7 +41,7 @@ func hash(ctx *cli.Context) {
|
||||||
chunker := storage.NewTreeChunker(storage.NewChunkerParams())
|
chunker := storage.NewTreeChunker(storage.NewChunkerParams())
|
||||||
key, err := chunker.Split(f, stat.Size(), nil, nil, nil)
|
key, err := chunker.Split(f, stat.Size(), nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("%v\n", err)
|
utils.Fatalf("%v\n", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%v\n", key)
|
fmt.Printf("%v\n", key)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"github.com/expanse-org/go-expanse/ethclient"
|
"github.com/expanse-org/go-expanse/ethclient"
|
||||||
"github.com/expanse-org/go-expanse/internal/debug"
|
"github.com/expanse-org/go-expanse/internal/debug"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/node"
|
"github.com/expanse-org/go-expanse/node"
|
||||||
"github.com/expanse-org/go-expanse/p2p"
|
"github.com/expanse-org/go-expanse/p2p"
|
||||||
"github.com/expanse-org/go-expanse/p2p/discover"
|
"github.com/expanse-org/go-expanse/p2p/discover"
|
||||||
|
|
@ -123,7 +122,7 @@ func init() {
|
||||||
// Override flag defaults so bzzd can run alongside gexp.
|
// Override flag defaults so bzzd can run alongside gexp.
|
||||||
utils.ListenPortFlag.Value = 30399
|
utils.ListenPortFlag.Value = 30399
|
||||||
utils.IPCPathFlag.Value = utils.DirectoryString{Value: "bzzd.ipc"}
|
utils.IPCPathFlag.Value = utils.DirectoryString{Value: "bzzd.ipc"}
|
||||||
utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3"
|
utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, swarmfs, web3"
|
||||||
|
|
||||||
// Set up the cli app.
|
// Set up the cli app.
|
||||||
app.Action = bzzd
|
app.Action = bzzd
|
||||||
|
|
@ -278,7 +277,7 @@ func bzzd(ctx *cli.Context) error {
|
||||||
signal.Notify(sigc, syscall.SIGTERM)
|
signal.Notify(sigc, syscall.SIGTERM)
|
||||||
defer signal.Stop(sigc)
|
defer signal.Stop(sigc)
|
||||||
<-sigc
|
<-sigc
|
||||||
glog.V(logger.Info).Infoln("Got sigterm, shutting down...")
|
log.Info("Got sigterm, shutting swarm down...")
|
||||||
stack.Stop()
|
stack.Stop()
|
||||||
}()
|
}()
|
||||||
networkId := ctx.GlobalUint64(SwarmNetworkIdFlag.Name)
|
networkId := ctx.GlobalUint64(SwarmNetworkIdFlag.Name)
|
||||||
|
|
@ -343,7 +342,7 @@ func getAccount(ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey {
|
||||||
}
|
}
|
||||||
// Try to load the arg as a hex key file.
|
// Try to load the arg as a hex key file.
|
||||||
if key, err := crypto.LoadECDSA(keyid); err == nil {
|
if key, err := crypto.LoadECDSA(keyid); err == nil {
|
||||||
glog.V(logger.Info).Infof("swarm account key loaded: %#x", crypto.PubkeyToAddress(key.PublicKey))
|
log.Info("Swarm account key loaded", "address", crypto.PubkeyToAddress(key.PublicKey))
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
// Otherwise try getting it from the keystore.
|
// Otherwise try getting it from the keystore.
|
||||||
|
|
@ -400,7 +399,7 @@ func injectBootnodes(srv *p2p.Server, nodes []string) {
|
||||||
for _, url := range nodes {
|
for _, url := range nodes {
|
||||||
n, err := discover.ParseNode(url)
|
n, err := discover.ParseNode(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("invalid bootnode %q", err)
|
log.Error("Invalid swarm bootnode", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
srv.AddPeer(n)
|
srv.AddPeer(n)
|
||||||
|
|
|
||||||
|
|
@ -18,40 +18,39 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gopkg.in/urfave/cli.v1"
|
"encoding/json"
|
||||||
"log"
|
"fmt"
|
||||||
"mime"
|
"mime"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"fmt"
|
|
||||||
"encoding/json"
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func add(ctx *cli.Context) {
|
func add(ctx *cli.Context) {
|
||||||
|
|
||||||
args := ctx.Args()
|
args := ctx.Args()
|
||||||
if len(args) < 3 {
|
if len(args) < 3 {
|
||||||
log.Fatal("need atleast three arguments <MHASH> <path> <HASH> [<content-type>]")
|
utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH> [<content-type>]")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mhash = args[0]
|
mhash = args[0]
|
||||||
path = args[1]
|
path = args[1]
|
||||||
hash = args[2]
|
hash = args[2]
|
||||||
|
|
||||||
ctype string
|
ctype string
|
||||||
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
||||||
mroot manifest
|
mroot manifest
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if len(args) > 3 {
|
if len(args) > 3 {
|
||||||
ctype = args[3]
|
ctype = args[3]
|
||||||
} else {
|
} else {
|
||||||
ctype = mime.TypeByExtension(filepath.Ext(path))
|
ctype = mime.TypeByExtension(filepath.Ext(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
newManifest := addEntryToManifest (ctx, mhash, path, hash, ctype)
|
newManifest := addEntryToManifest(ctx, mhash, path, hash, ctype)
|
||||||
fmt.Println(newManifest)
|
fmt.Println(newManifest)
|
||||||
|
|
||||||
if !wantManifest {
|
if !wantManifest {
|
||||||
|
|
@ -66,17 +65,17 @@ func update(ctx *cli.Context) {
|
||||||
|
|
||||||
args := ctx.Args()
|
args := ctx.Args()
|
||||||
if len(args) < 3 {
|
if len(args) < 3 {
|
||||||
log.Fatal("need atleast three arguments <MHASH> <path> <HASH>")
|
utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH>")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mhash = args[0]
|
mhash = args[0]
|
||||||
path = args[1]
|
path = args[1]
|
||||||
hash = args[2]
|
hash = args[2]
|
||||||
|
|
||||||
ctype string
|
ctype string
|
||||||
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
||||||
mroot manifest
|
mroot manifest
|
||||||
)
|
)
|
||||||
if len(args) > 3 {
|
if len(args) > 3 {
|
||||||
ctype = args[3]
|
ctype = args[3]
|
||||||
|
|
@ -84,7 +83,7 @@ func update(ctx *cli.Context) {
|
||||||
ctype = mime.TypeByExtension(filepath.Ext(path))
|
ctype = mime.TypeByExtension(filepath.Ext(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
newManifest := updateEntryInManifest (ctx, mhash, path, hash, ctype)
|
newManifest := updateEntryInManifest(ctx, mhash, path, hash, ctype)
|
||||||
fmt.Println(newManifest)
|
fmt.Println(newManifest)
|
||||||
|
|
||||||
if !wantManifest {
|
if !wantManifest {
|
||||||
|
|
@ -98,18 +97,18 @@ func update(ctx *cli.Context) {
|
||||||
func remove(ctx *cli.Context) {
|
func remove(ctx *cli.Context) {
|
||||||
args := ctx.Args()
|
args := ctx.Args()
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
log.Fatal("need atleast two arguments <MHASH> <path>")
|
utils.Fatalf("Need atleast two arguments <MHASH> <path>")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mhash = args[0]
|
mhash = args[0]
|
||||||
path = args[1]
|
path = args[1]
|
||||||
|
|
||||||
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
||||||
mroot manifest
|
mroot manifest
|
||||||
)
|
)
|
||||||
|
|
||||||
newManifest := removeEntryFromManifest (ctx, mhash, path)
|
newManifest := removeEntryFromManifest(ctx, mhash, path)
|
||||||
fmt.Println(newManifest)
|
fmt.Println(newManifest)
|
||||||
|
|
||||||
if !wantManifest {
|
if !wantManifest {
|
||||||
|
|
@ -120,35 +119,34 @@ func remove(ctx *cli.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEntryToManifest(ctx *cli.Context, mhash , path, hash , ctype string) string {
|
func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||||
client = &client{api: bzzapi}
|
client = &client{api: bzzapi}
|
||||||
longestPathEntry = manifestEntry{
|
longestPathEntry = manifestEntry{
|
||||||
Path: "",
|
Path: "",
|
||||||
Hash: "",
|
Hash: "",
|
||||||
ContentType: "",
|
ContentType: "",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
mroot, err := client.downloadManifest(mhash)
|
mroot, err := client.downloadManifest(mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("manifest download failed:", err)
|
utils.Fatalf("Manifest download failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: check if the "hash" to add is valid and present in swarm
|
//TODO: check if the "hash" to add is valid and present in swarm
|
||||||
_, err = client.downloadManifest(hash)
|
_, err = client.downloadManifest(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("hash to add is not present:", err)
|
utils.Fatalf("Hash to add is not present: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// See if we path is in this Manifest or do we have to dig deeper
|
// See if we path is in this Manifest or do we have to dig deeper
|
||||||
for _, entry := range mroot.Entries {
|
for _, entry := range mroot.Entries {
|
||||||
if path == entry.Path {
|
if path == entry.Path {
|
||||||
log.Fatal(path, "Already present, not adding anything")
|
utils.Fatalf("Path %s already present, not adding anything", path)
|
||||||
}else {
|
} else {
|
||||||
if entry.ContentType == "application/bzz-manifest+json" {
|
if entry.ContentType == "application/bzz-manifest+json" {
|
||||||
prfxlen := strings.HasPrefix(path, entry.Path)
|
prfxlen := strings.HasPrefix(path, entry.Path)
|
||||||
if prfxlen && len(path) > len(longestPathEntry.Path) {
|
if prfxlen && len(path) > len(longestPathEntry.Path) {
|
||||||
|
|
@ -161,7 +159,7 @@ func addEntryToManifest(ctx *cli.Context, mhash , path, hash , ctype string) st
|
||||||
if longestPathEntry.Path != "" {
|
if longestPathEntry.Path != "" {
|
||||||
// Load the child Manifest add the entry there
|
// Load the child Manifest add the entry there
|
||||||
newPath := path[len(longestPathEntry.Path):]
|
newPath := path[len(longestPathEntry.Path):]
|
||||||
newHash := addEntryToManifest (ctx, longestPathEntry.Hash, newPath, hash, ctype)
|
newHash := addEntryToManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
|
||||||
|
|
||||||
// Replace the hash for parent Manifests
|
// Replace the hash for parent Manifests
|
||||||
newMRoot := manifest{}
|
newMRoot := manifest{}
|
||||||
|
|
@ -182,47 +180,43 @@ func addEntryToManifest(ctx *cli.Context, mhash , path, hash , ctype string) st
|
||||||
mroot.Entries = append(mroot.Entries, newEntry)
|
mroot.Entries = append(mroot.Entries, newEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
newManifestHash, err := client.uploadManifest(mroot)
|
newManifestHash, err := client.uploadManifest(mroot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("manifest upload failed:", err)
|
utils.Fatalf("Manifest upload failed: %v", err)
|
||||||
}
|
}
|
||||||
return newManifestHash
|
return newManifestHash
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateEntryInManifest(ctx *cli.Context, mhash , path, hash , ctype string) string {
|
func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||||
client = &client{api: bzzapi}
|
client = &client{api: bzzapi}
|
||||||
newEntry = manifestEntry{
|
newEntry = manifestEntry{
|
||||||
Path: "",
|
Path: "",
|
||||||
Hash: "",
|
Hash: "",
|
||||||
ContentType: "",
|
ContentType: "",
|
||||||
}
|
}
|
||||||
longestPathEntry = manifestEntry{
|
longestPathEntry = manifestEntry{
|
||||||
Path: "",
|
Path: "",
|
||||||
Hash: "",
|
Hash: "",
|
||||||
ContentType: "",
|
ContentType: "",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
mroot, err := client.downloadManifest(mhash)
|
mroot, err := client.downloadManifest(mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("manifest download failed:", err)
|
utils.Fatalf("Manifest download failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: check if the "hash" with which to update is valid and present in swarm
|
//TODO: check if the "hash" with which to update is valid and present in swarm
|
||||||
|
|
||||||
|
|
||||||
// See if we path is in this Manifest or do we have to dig deeper
|
// See if we path is in this Manifest or do we have to dig deeper
|
||||||
for _, entry := range mroot.Entries {
|
for _, entry := range mroot.Entries {
|
||||||
if path == entry.Path {
|
if path == entry.Path {
|
||||||
newEntry = entry
|
newEntry = entry
|
||||||
}else {
|
} else {
|
||||||
if entry.ContentType == "application/bzz-manifest+json" {
|
if entry.ContentType == "application/bzz-manifest+json" {
|
||||||
prfxlen := strings.HasPrefix(path, entry.Path)
|
prfxlen := strings.HasPrefix(path, entry.Path)
|
||||||
if prfxlen && len(path) > len(longestPathEntry.Path) {
|
if prfxlen && len(path) > len(longestPathEntry.Path) {
|
||||||
|
|
@ -233,13 +227,13 @@ func updateEntryInManifest(ctx *cli.Context, mhash , path, hash , ctype string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if longestPathEntry.Path == "" && newEntry.Path == "" {
|
if longestPathEntry.Path == "" && newEntry.Path == "" {
|
||||||
log.Fatal(path, " Path not present in the Manifest, not setting anything")
|
utils.Fatalf("Path %s not present in the Manifest, not setting anything", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if longestPathEntry.Path != "" {
|
if longestPathEntry.Path != "" {
|
||||||
// Load the child Manifest add the entry there
|
// Load the child Manifest add the entry there
|
||||||
newPath := path[len(longestPathEntry.Path):]
|
newPath := path[len(longestPathEntry.Path):]
|
||||||
newHash := updateEntryInManifest (ctx, longestPathEntry.Hash, newPath, hash, ctype)
|
newHash := updateEntryInManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
|
||||||
|
|
||||||
// Replace the hash for parent Manifests
|
// Replace the hash for parent Manifests
|
||||||
newMRoot := manifest{}
|
newMRoot := manifest{}
|
||||||
|
|
@ -271,43 +265,40 @@ func updateEntryInManifest(ctx *cli.Context, mhash , path, hash , ctype string)
|
||||||
mroot = newMRoot
|
mroot = newMRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
newManifestHash, err := client.uploadManifest(mroot)
|
newManifestHash, err := client.uploadManifest(mroot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("manifest upload failed:", err)
|
utils.Fatalf("Manifest upload failed: %v", err)
|
||||||
}
|
}
|
||||||
return newManifestHash
|
return newManifestHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeEntryFromManifest(ctx *cli.Context, mhash , path string) string {
|
func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||||
client = &client{api: bzzapi}
|
client = &client{api: bzzapi}
|
||||||
entryToRemove = manifestEntry{
|
entryToRemove = manifestEntry{
|
||||||
Path: "",
|
Path: "",
|
||||||
Hash: "",
|
Hash: "",
|
||||||
ContentType: "",
|
ContentType: "",
|
||||||
}
|
}
|
||||||
longestPathEntry = manifestEntry{
|
longestPathEntry = manifestEntry{
|
||||||
Path: "",
|
Path: "",
|
||||||
Hash: "",
|
Hash: "",
|
||||||
ContentType: "",
|
ContentType: "",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
mroot, err := client.downloadManifest(mhash)
|
mroot, err := client.downloadManifest(mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("manifest download failed:", err)
|
utils.Fatalf("Manifest download failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// See if we path is in this Manifest or do we have to dig deeper
|
// See if we path is in this Manifest or do we have to dig deeper
|
||||||
for _, entry := range mroot.Entries {
|
for _, entry := range mroot.Entries {
|
||||||
if path == entry.Path {
|
if path == entry.Path {
|
||||||
entryToRemove = entry
|
entryToRemove = entry
|
||||||
}else {
|
} else {
|
||||||
if entry.ContentType == "application/bzz-manifest+json" {
|
if entry.ContentType == "application/bzz-manifest+json" {
|
||||||
prfxlen := strings.HasPrefix(path, entry.Path)
|
prfxlen := strings.HasPrefix(path, entry.Path)
|
||||||
if prfxlen && len(path) > len(longestPathEntry.Path) {
|
if prfxlen && len(path) > len(longestPathEntry.Path) {
|
||||||
|
|
@ -318,13 +309,13 @@ func removeEntryFromManifest(ctx *cli.Context, mhash , path string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if longestPathEntry.Path == "" && entryToRemove.Path == "" {
|
if longestPathEntry.Path == "" && entryToRemove.Path == "" {
|
||||||
log.Fatal(path, "Path not present in the Manifest, not removing anything")
|
utils.Fatalf("Path %s not present in the Manifest, not removing anything", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if longestPathEntry.Path != "" {
|
if longestPathEntry.Path != "" {
|
||||||
// Load the child Manifest remove the entry there
|
// Load the child Manifest remove the entry there
|
||||||
newPath := path[len(longestPathEntry.Path):]
|
newPath := path[len(longestPathEntry.Path):]
|
||||||
newHash := removeEntryFromManifest (ctx, longestPathEntry.Hash, newPath)
|
newHash := removeEntryFromManifest(ctx, longestPathEntry.Hash, newPath)
|
||||||
|
|
||||||
// Replace the hash for parent Manifests
|
// Replace the hash for parent Manifests
|
||||||
newMRoot := manifest{}
|
newMRoot := manifest{}
|
||||||
|
|
@ -348,13 +339,9 @@ func removeEntryFromManifest(ctx *cli.Context, mhash , path string) string {
|
||||||
mroot = newMRoot
|
mroot = newMRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
newManifestHash, err := client.uploadManifest(mroot)
|
newManifestHash, err := client.uploadManifest(mroot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("manifest upload failed:", err)
|
utils.Fatalf("Manifest upload failed: %v", err)
|
||||||
}
|
}
|
||||||
return newManifestHash
|
return newManifestHash
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -32,6 +31,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/cmd/utils"
|
||||||
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -44,7 +45,7 @@ func upload(ctx *cli.Context) {
|
||||||
defaultPath = ctx.GlobalString(SwarmUploadDefaultPath.Name)
|
defaultPath = ctx.GlobalString(SwarmUploadDefaultPath.Name)
|
||||||
)
|
)
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
log.Fatal("need filename as the first and only argument")
|
utils.Fatalf("Need filename as the first and only argument")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -53,25 +54,25 @@ func upload(ctx *cli.Context) {
|
||||||
)
|
)
|
||||||
fi, err := os.Stat(expandPath(file))
|
fi, err := os.Stat(expandPath(file))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
utils.Fatalf("Failed to stat file: %v", err)
|
||||||
}
|
}
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
if !recursive {
|
if !recursive {
|
||||||
log.Fatal("argument is a directory and recursive upload is disabled")
|
utils.Fatalf("Argument is a directory and recursive upload is disabled")
|
||||||
}
|
}
|
||||||
if !wantManifest {
|
if !wantManifest {
|
||||||
log.Fatal("manifest is required for directory uploads")
|
utils.Fatalf("Manifest is required for directory uploads")
|
||||||
}
|
}
|
||||||
mhash, err := client.uploadDirectory(file, defaultPath)
|
mhash, err := client.uploadDirectory(file, defaultPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
utils.Fatalf("Failed to upload directory: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Println(mhash)
|
fmt.Println(mhash)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entry, err := client.uploadFile(file, fi)
|
entry, err := client.uploadFile(file, fi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("upload failed:", err)
|
utils.Fatalf("Upload failed: %v", err)
|
||||||
}
|
}
|
||||||
mroot := manifest{[]manifestEntry{entry}}
|
mroot := manifest{[]manifestEntry{entry}}
|
||||||
if !wantManifest {
|
if !wantManifest {
|
||||||
|
|
@ -82,7 +83,7 @@ func upload(ctx *cli.Context) {
|
||||||
}
|
}
|
||||||
hash, err := client.uploadManifest(mroot)
|
hash, err := client.uploadManifest(mroot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("manifest upload failed:", err)
|
utils.Fatalf("Manifest upload failed: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Println(hash)
|
fmt.Println(hash)
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +174,7 @@ func (c *client) uploadFileContent(file string, fi os.FileInfo) (string, error)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
log.Printf("uploading file %s (%d bytes)", file, fi.Size())
|
log.Info("Uploading swarm content", "file", file, "bytes", fi.Size())
|
||||||
return c.postRaw("application/octet-stream", fi.Size(), fd)
|
return c.postRaw("application/octet-stream", fi.Size(), fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,7 +183,7 @@ func (c *client) uploadManifest(m manifest) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
log.Println("uploading manifest")
|
log.Info("Uploading swarm manifest")
|
||||||
return c.postRaw("application/json", int64(len(jsm)), ioutil.NopCloser(bytes.NewReader(jsm)))
|
return c.postRaw("application/json", int64(len(jsm)), ioutil.NopCloser(bytes.NewReader(jsm)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +193,7 @@ func (c *client) uploadToManifest(mhash string, path string, fpath string, fi os
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
log.Printf("uploading file %s (%d bytes) and adding path %v", fpath, fi.Size(), path)
|
log.Info("Uploading swarm content and path", "file", fpath, "bytes", fi.Size(), "path", path)
|
||||||
req, err := http.NewRequest("PUT", c.api+"/bzz:/"+mhash+"/"+path, fd)
|
req, err := http.NewRequest("PUT", c.api+"/bzz:/"+mhash+"/"+path, fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -233,7 +234,7 @@ func (c *client) postRaw(mimetype string, size int64, body io.ReadCloser) (strin
|
||||||
func (c *client) downloadManifest(mhash string) (manifest, error) {
|
func (c *client) downloadManifest(mhash string) (manifest, error) {
|
||||||
|
|
||||||
mroot := manifest{}
|
mroot := manifest{}
|
||||||
req, err := http.NewRequest("GET", c.api + "/bzzr:/" + mhash, nil)
|
req, err := http.NewRequest("GET", c.api+"/bzzr:/"+mhash, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mroot, err
|
return mroot, err
|
||||||
}
|
}
|
||||||
|
|
@ -254,4 +255,4 @@ func (c *client) downloadManifest(mhash string) (manifest, error) {
|
||||||
return mroot, fmt.Errorf("Manifest %v is malformed: %v", mhash, err)
|
return mroot, fmt.Errorf("Manifest %v is malformed: %v", mhash, err)
|
||||||
}
|
}
|
||||||
return mroot, err
|
return mroot, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,13 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"regexp"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
|
||||||
"github.com/expanse-org/go-expanse/core"
|
"github.com/expanse-org/go-expanse/core"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/internal/debug"
|
"github.com/expanse-org/go-expanse/internal/debug"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/node"
|
"github.com/expanse-org/go-expanse/node"
|
||||||
"github.com/expanse-org/go-expanse/rlp"
|
"github.com/expanse-org/go-expanse/rlp"
|
||||||
)
|
)
|
||||||
|
|
@ -41,15 +38,6 @@ const (
|
||||||
importBatchSize = 2500
|
importBatchSize = 2500
|
||||||
)
|
)
|
||||||
|
|
||||||
func openLogFile(Datadir string, filename string) *os.File {
|
|
||||||
path := common.AbsolutePath(Datadir, filename)
|
|
||||||
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
|
|
||||||
}
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalf formats a message to standard error and exits the program.
|
// Fatalf formats a message to standard error and exits the program.
|
||||||
// The message is also printed to standard output if standard error
|
// The message is also printed to standard output if standard error
|
||||||
// is redirected to a different file.
|
// is redirected to a different file.
|
||||||
|
|
@ -79,12 +67,12 @@ func StartNode(stack *node.Node) {
|
||||||
signal.Notify(sigc, os.Interrupt)
|
signal.Notify(sigc, os.Interrupt)
|
||||||
defer signal.Stop(sigc)
|
defer signal.Stop(sigc)
|
||||||
<-sigc
|
<-sigc
|
||||||
glog.V(logger.Info).Infoln("Got interrupt, shutting down...")
|
log.Info("Got interrupt, shutting down...")
|
||||||
go stack.Stop()
|
go stack.Stop()
|
||||||
for i := 10; i > 0; i-- {
|
for i := 10; i > 0; i-- {
|
||||||
<-sigc
|
<-sigc
|
||||||
if i > 1 {
|
if i > 1 {
|
||||||
glog.V(logger.Info).Infof("Already shutting down, interrupt %d more times for panic.", i-1)
|
log.Warn("Already shutting down, interrupt more to panic.", "times", i-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug.Exit() // ensure trace and CPU profile data is flushed.
|
debug.Exit() // ensure trace and CPU profile data is flushed.
|
||||||
|
|
@ -92,19 +80,6 @@ func StartNode(stack *node.Node) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatTransactionData(data string) []byte {
|
|
||||||
d := common.StringToByteFunc(data, func(s string) (ret []byte) {
|
|
||||||
slice := regexp.MustCompile(`\n|\s`).Split(s, 1000000000)
|
|
||||||
for _, dataItem := range slice {
|
|
||||||
d := common.FormatData(dataItem)
|
|
||||||
ret = append(ret, d...)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func ImportChain(chain *core.BlockChain, fn string) error {
|
func ImportChain(chain *core.BlockChain, fn string) error {
|
||||||
// Watch for Ctrl-C while the import is running.
|
// Watch for Ctrl-C while the import is running.
|
||||||
// If a signal is received, the import will stop at the next batch.
|
// If a signal is received, the import will stop at the next batch.
|
||||||
|
|
@ -115,7 +90,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
|
||||||
defer close(interrupt)
|
defer close(interrupt)
|
||||||
go func() {
|
go func() {
|
||||||
if _, ok := <-interrupt; ok {
|
if _, ok := <-interrupt; ok {
|
||||||
glog.Info("caught interrupt during import, will stop at next batch")
|
log.Info("Interrupted during import, stopping at next batch")
|
||||||
}
|
}
|
||||||
close(stop)
|
close(stop)
|
||||||
}()
|
}()
|
||||||
|
|
@ -128,7 +103,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.Infoln("Importing blockchain ", fn)
|
log.Info("Importing blockchain", "file", fn)
|
||||||
fh, err := os.Open(fn)
|
fh, err := os.Open(fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -176,8 +151,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
|
||||||
return fmt.Errorf("interrupted")
|
return fmt.Errorf("interrupted")
|
||||||
}
|
}
|
||||||
if hasAllBlocks(chain, blocks[:i]) {
|
if hasAllBlocks(chain, blocks[:i]) {
|
||||||
glog.Infof("skipping batch %d, all blocks present [%x / %x]",
|
log.Info("Skipping batch as all blocks present", "batch", batch, "first", blocks[0].Hash(), "last", blocks[i-1].Hash())
|
||||||
batch, blocks[0].Hash().Bytes()[:4], blocks[i-1].Hash().Bytes()[:4])
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,7 +172,7 @@ func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExportChain(blockchain *core.BlockChain, fn string) error {
|
func ExportChain(blockchain *core.BlockChain, fn string) error {
|
||||||
glog.Infoln("Exporting blockchain to ", fn)
|
log.Info("Exporting blockchain", "file", fn)
|
||||||
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
|
||||||
|
|
@ -214,13 +188,13 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
|
||||||
if err := blockchain.Export(writer); err != nil {
|
if err := blockchain.Export(writer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
glog.Infoln("Exported blockchain to ", fn)
|
log.Info("Exported blockchain", "file", fn)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
|
func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
|
||||||
glog.Infoln("Exporting blockchain to ", fn)
|
log.Info("Exporting blockchain", "file", fn)
|
||||||
// TODO verify mode perms
|
// TODO verify mode perms
|
||||||
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 {
|
||||||
|
|
@ -237,6 +211,6 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
|
||||||
if err := blockchain.ExportN(writer, first, last); err != nil {
|
if err := blockchain.ExportN(writer, first, last); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
glog.Infoln("Exported blockchain to ", fn)
|
log.Info("Exported blockchain to", "file", fn)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,17 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Custom type which is registered in the flags library which cli uses for
|
// Custom type which is registered in the flags library which cli uses for
|
||||||
|
|
@ -44,10 +49,9 @@ func (self *DirectoryString) Set(value string) error {
|
||||||
// Custom cli.Flag type which expand the received string to an absolute path.
|
// Custom cli.Flag type which expand the received string to an absolute path.
|
||||||
// e.g. ~/.ethereum -> /home/username/.ethereum
|
// e.g. ~/.ethereum -> /home/username/.ethereum
|
||||||
type DirectoryFlag struct {
|
type DirectoryFlag struct {
|
||||||
Name string
|
Name string
|
||||||
Value DirectoryString
|
Value DirectoryString
|
||||||
Usage string
|
Usage string
|
||||||
EnvVar string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self DirectoryFlag) String() string {
|
func (self DirectoryFlag) String() string {
|
||||||
|
|
@ -55,7 +59,7 @@ func (self DirectoryFlag) String() string {
|
||||||
if len(self.Value.Value) > 0 {
|
if len(self.Value.Value) > 0 {
|
||||||
fmtString = "%s \"%v\"\t%v"
|
fmtString = "%s \"%v\"\t%v"
|
||||||
}
|
}
|
||||||
return withEnvHint(self.EnvVar, fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage))
|
return fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func eachName(longName string, fn func(string)) {
|
func eachName(longName string, fn func(string)) {
|
||||||
|
|
@ -69,21 +73,65 @@ func eachName(longName string, fn func(string)) {
|
||||||
// called by cli library, grabs variable from environment (if in env)
|
// called by cli library, grabs variable from environment (if in env)
|
||||||
// and adds variable to flag set for parsing.
|
// and adds variable to flag set for parsing.
|
||||||
func (self DirectoryFlag) Apply(set *flag.FlagSet) {
|
func (self DirectoryFlag) Apply(set *flag.FlagSet) {
|
||||||
if self.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(self.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
|
||||||
self.Value.Value = envVal
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(self.Name, func(name string) {
|
eachName(self.Name, func(name string) {
|
||||||
set.Var(&self.Value, self.Name, self.Usage)
|
set.Var(&self.Value, self.Name, self.Usage)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BigFlag is a command line flag that accepts 256 bit big integers in decimal or
|
||||||
|
// hexadecimal syntax.
|
||||||
|
type BigFlag struct {
|
||||||
|
Name string
|
||||||
|
Value *big.Int
|
||||||
|
Usage string
|
||||||
|
}
|
||||||
|
|
||||||
|
// bigValue turns *big.Int into a flag.Value
|
||||||
|
type bigValue big.Int
|
||||||
|
|
||||||
|
func (b *bigValue) String() string {
|
||||||
|
if b == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return (*big.Int)(b).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bigValue) Set(s string) error {
|
||||||
|
int, ok := math.ParseBig256(s)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("invalid integer syntax")
|
||||||
|
}
|
||||||
|
*b = (bigValue)(*int)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f BigFlag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f BigFlag) String() string {
|
||||||
|
fmtString := "%s %v\t%v"
|
||||||
|
if f.Value != nil {
|
||||||
|
fmtString = "%s \"%v\"\t%v"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f BigFlag) Apply(set *flag.FlagSet) {
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
set.Var((*bigValue)(f.Value), f.Name, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalBig returns the value of a BigFlag from the global flag set.
|
||||||
|
func GlobalBig(ctx *cli.Context, name string) *big.Int {
|
||||||
|
val := ctx.GlobalGeneric(name)
|
||||||
|
if val == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*big.Int)(val.(*bigValue))
|
||||||
|
}
|
||||||
|
|
||||||
func prefixFor(name string) (prefix string) {
|
func prefixFor(name string) (prefix string) {
|
||||||
if len(name) == 1 {
|
if len(name) == 1 {
|
||||||
prefix = "-"
|
prefix = "-"
|
||||||
|
|
@ -106,14 +154,6 @@ func prefixedNames(fullName string) (prefixed string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func withEnvHint(envVar, str string) string {
|
|
||||||
envText := ""
|
|
||||||
if envVar != "" {
|
|
||||||
envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
|
|
||||||
}
|
|
||||||
return str + envText
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self DirectoryFlag) GetName() string {
|
func (self DirectoryFlag) GetName() string {
|
||||||
return self.Name
|
return self.Name
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/ethash"
|
|
||||||
"github.com/expanse-org/go-expanse/accounts"
|
"github.com/expanse-org/go-expanse/accounts"
|
||||||
"github.com/expanse-org/go-expanse/accounts/keystore"
|
"github.com/expanse-org/go-expanse/accounts/keystore"
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
|
@ -41,8 +41,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/ethstats"
|
"github.com/expanse-org/go-expanse/ethstats"
|
||||||
"github.com/expanse-org/go-expanse/event"
|
"github.com/expanse-org/go-expanse/event"
|
||||||
"github.com/expanse-org/go-expanse/les"
|
"github.com/expanse-org/go-expanse/les"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/metrics"
|
"github.com/expanse-org/go-expanse/metrics"
|
||||||
"github.com/expanse-org/go-expanse/node"
|
"github.com/expanse-org/go-expanse/node"
|
||||||
"github.com/expanse-org/go-expanse/p2p/discover"
|
"github.com/expanse-org/go-expanse/p2p/discover"
|
||||||
|
|
@ -115,6 +114,34 @@ var (
|
||||||
Name: "keystore",
|
Name: "keystore",
|
||||||
Usage: "Directory for the keystore (default = inside the datadir)",
|
Usage: "Directory for the keystore (default = inside the datadir)",
|
||||||
}
|
}
|
||||||
|
EthashCacheDirFlag = DirectoryFlag{
|
||||||
|
Name: "ethash.cachedir",
|
||||||
|
Usage: "Directory to store the ethash verification caches (default = inside the datadir)",
|
||||||
|
}
|
||||||
|
EthashCachesInMemoryFlag = cli.IntFlag{
|
||||||
|
Name: "ethash.cachesinmem",
|
||||||
|
Usage: "Number of recent ethash caches to keep in memory (16MB each)",
|
||||||
|
Value: 2,
|
||||||
|
}
|
||||||
|
EthashCachesOnDiskFlag = cli.IntFlag{
|
||||||
|
Name: "ethash.cachesondisk",
|
||||||
|
Usage: "Number of recent ethash caches to keep on disk (16MB each)",
|
||||||
|
Value: 3,
|
||||||
|
}
|
||||||
|
EthashDatasetDirFlag = DirectoryFlag{
|
||||||
|
Name: "ethash.dagdir",
|
||||||
|
Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
|
||||||
|
}
|
||||||
|
EthashDatasetsInMemoryFlag = cli.IntFlag{
|
||||||
|
Name: "ethash.dagsinmem",
|
||||||
|
Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
|
||||||
|
Value: 1,
|
||||||
|
}
|
||||||
|
EthashDatasetsOnDiskFlag = cli.IntFlag{
|
||||||
|
Name: "ethash.dagsondisk",
|
||||||
|
Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
|
||||||
|
Value: 2,
|
||||||
|
}
|
||||||
NetworkIdFlag = cli.IntFlag{
|
NetworkIdFlag = cli.IntFlag{
|
||||||
Name: "networkid",
|
Name: "networkid",
|
||||||
Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten)",
|
Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten)",
|
||||||
|
|
@ -180,24 +207,20 @@ var (
|
||||||
Usage: "Number of CPU threads to use for mining",
|
Usage: "Number of CPU threads to use for mining",
|
||||||
Value: runtime.NumCPU(),
|
Value: runtime.NumCPU(),
|
||||||
}
|
}
|
||||||
TargetGasLimitFlag = cli.StringFlag{
|
TargetGasLimitFlag = cli.Uint64Flag{
|
||||||
Name: "targetgaslimit",
|
Name: "targetgaslimit",
|
||||||
Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine",
|
Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine",
|
||||||
Value: params.GenesisGasLimit.String(),
|
Value: params.GenesisGasLimit.Uint64(),
|
||||||
}
|
|
||||||
AutoDAGFlag = cli.BoolFlag{
|
|
||||||
Name: "autodag",
|
|
||||||
Usage: "Enable automatic DAG pregeneration",
|
|
||||||
}
|
}
|
||||||
EtherbaseFlag = cli.StringFlag{
|
EtherbaseFlag = cli.StringFlag{
|
||||||
Name: "etherbase",
|
Name: "etherbase",
|
||||||
Usage: "Public address for block mining rewards (default = first account created)",
|
Usage: "Public address for block mining rewards (default = first account created)",
|
||||||
Value: "0",
|
Value: "0",
|
||||||
}
|
}
|
||||||
GasPriceFlag = cli.StringFlag{
|
GasPriceFlag = BigFlag{
|
||||||
Name: "gasprice",
|
Name: "gasprice",
|
||||||
Usage: "Minimal gas price to accept for mining a transactions",
|
Usage: "Minimal gas price to accept for mining a transactions",
|
||||||
Value: new(big.Int).Mul(big.NewInt(20), common.Shannon).String(),
|
Value: big.NewInt(20 * params.Shannon),
|
||||||
}
|
}
|
||||||
ExtraDataFlag = cli.StringFlag{
|
ExtraDataFlag = cli.StringFlag{
|
||||||
Name: "extradata",
|
Name: "extradata",
|
||||||
|
|
@ -245,7 +268,10 @@ var (
|
||||||
Name: "fakepow",
|
Name: "fakepow",
|
||||||
Usage: "Disables proof-of-work verification",
|
Usage: "Disables proof-of-work verification",
|
||||||
}
|
}
|
||||||
|
NoCompactionFlag = cli.BoolFlag{
|
||||||
|
Name: "nocompaction",
|
||||||
|
Usage: "Disables db compaction after import",
|
||||||
|
}
|
||||||
// RPC settings
|
// RPC settings
|
||||||
RPCEnabledFlag = cli.BoolFlag{
|
RPCEnabledFlag = cli.BoolFlag{
|
||||||
Name: "rpc",
|
Name: "rpc",
|
||||||
|
|
@ -383,15 +409,15 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gas price oracle settings
|
// Gas price oracle settings
|
||||||
GpoMinGasPriceFlag = cli.StringFlag{
|
GpoMinGasPriceFlag = BigFlag{
|
||||||
Name: "gpomin",
|
Name: "gpomin",
|
||||||
Usage: "Minimum suggested gas price",
|
Usage: "Minimum suggested gas price",
|
||||||
Value: new(big.Int).Mul(big.NewInt(20), common.Shannon).String(),
|
Value: big.NewInt(20 * params.Shannon),
|
||||||
}
|
}
|
||||||
GpoMaxGasPriceFlag = cli.StringFlag{
|
GpoMaxGasPriceFlag = BigFlag{
|
||||||
Name: "gpomax",
|
Name: "gpomax",
|
||||||
Usage: "Maximum suggested gas price",
|
Usage: "Maximum suggested gas price",
|
||||||
Value: new(big.Int).Mul(big.NewInt(500), common.Shannon).String(),
|
Value: big.NewInt(500 * params.Shannon),
|
||||||
}
|
}
|
||||||
GpoFullBlockRatioFlag = cli.IntFlag{
|
GpoFullBlockRatioFlag = cli.IntFlag{
|
||||||
Name: "gpofull",
|
Name: "gpofull",
|
||||||
|
|
@ -430,6 +456,36 @@ func MakeDataDir(ctx *cli.Context) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeEthashCacheDir returns the directory to use for storing the ethash cache
|
||||||
|
// dumps.
|
||||||
|
func MakeEthashCacheDir(ctx *cli.Context) string {
|
||||||
|
if ctx.GlobalIsSet(EthashCacheDirFlag.Name) && ctx.GlobalString(EthashCacheDirFlag.Name) == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if !ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
|
||||||
|
return "ethash"
|
||||||
|
}
|
||||||
|
return ctx.GlobalString(EthashCacheDirFlag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeEthashDatasetDir returns the directory to use for storing the full ethash
|
||||||
|
// dataset dumps.
|
||||||
|
func MakeEthashDatasetDir(ctx *cli.Context) string {
|
||||||
|
if !ctx.GlobalIsSet(EthashDatasetDirFlag.Name) {
|
||||||
|
home := os.Getenv("HOME")
|
||||||
|
if home == "" {
|
||||||
|
if user, err := user.Current(); err == nil {
|
||||||
|
home = user.HomeDir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
return filepath.Join(home, "AppData", "Ethash")
|
||||||
|
}
|
||||||
|
return filepath.Join(home, ".ethash")
|
||||||
|
}
|
||||||
|
return ctx.GlobalString(EthashDatasetDirFlag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
// MakeIPCPath creates an IPC path configuration from the set command line flags,
|
// MakeIPCPath creates an IPC path configuration from the set command line flags,
|
||||||
// returning an empty string if IPC was explicitly disabled, or the set path.
|
// returning an empty string if IPC was explicitly disabled, or the set path.
|
||||||
func MakeIPCPath(ctx *cli.Context) string {
|
func MakeIPCPath(ctx *cli.Context) string {
|
||||||
|
|
@ -493,7 +549,7 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
||||||
for _, url := range urls {
|
for _, url := range urls {
|
||||||
node, err := discover.ParseNode(url)
|
node, err := discover.ParseNode(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
log.Error("Bootstrap URL invalid", "enode", url, "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
bootnodes = append(bootnodes, node)
|
bootnodes = append(bootnodes, node)
|
||||||
|
|
@ -513,7 +569,7 @@ func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node {
|
||||||
for _, url := range urls {
|
for _, url := range urls {
|
||||||
node, err := discv5.ParseNode(url)
|
node, err := discv5.ParseNode(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
log.Error("Bootstrap URL invalid", "enode", url, "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
bootnodes = append(bootnodes, node)
|
bootnodes = append(bootnodes, node)
|
||||||
|
|
@ -610,7 +666,7 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error
|
||||||
func MakeEtherbase(ks *keystore.KeyStore, ctx *cli.Context) common.Address {
|
func MakeEtherbase(ks *keystore.KeyStore, ctx *cli.Context) common.Address {
|
||||||
accounts := ks.Accounts()
|
accounts := ks.Accounts()
|
||||||
if !ctx.GlobalIsSet(EtherbaseFlag.Name) && len(accounts) == 0 {
|
if !ctx.GlobalIsSet(EtherbaseFlag.Name) && len(accounts) == 0 {
|
||||||
glog.V(logger.Error).Infoln("WARNING: No etherbase set and no accounts found as default")
|
log.Warn("No etherbase set and no accounts found as default")
|
||||||
return common.Address{}
|
return common.Address{}
|
||||||
}
|
}
|
||||||
etherbase := ctx.GlobalString(EtherbaseFlag.Name)
|
etherbase := ctx.GlobalString(EtherbaseFlag.Name)
|
||||||
|
|
@ -730,7 +786,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||||
|
|
||||||
ethConf := ð.Config{
|
ethConf := ð.Config{
|
||||||
Etherbase: MakeEtherbase(ks, ctx),
|
Etherbase: MakeEtherbase(ks, ctx),
|
||||||
ChainConfig: MakeChainConfig(ctx, stack),
|
|
||||||
FastSync: ctx.GlobalBool(FastSyncFlag.Name),
|
FastSync: ctx.GlobalBool(FastSyncFlag.Name),
|
||||||
LightMode: ctx.GlobalBool(LightModeFlag.Name),
|
LightMode: ctx.GlobalBool(LightModeFlag.Name),
|
||||||
LightServ: ctx.GlobalInt(LightServFlag.Name),
|
LightServ: ctx.GlobalInt(LightServFlag.Name),
|
||||||
|
|
@ -742,15 +797,20 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||||
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
|
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
|
||||||
ExtraData: MakeMinerExtra(extra, ctx),
|
ExtraData: MakeMinerExtra(extra, ctx),
|
||||||
DocRoot: ctx.GlobalString(DocRootFlag.Name),
|
DocRoot: ctx.GlobalString(DocRootFlag.Name),
|
||||||
GasPrice: common.String2Big(ctx.GlobalString(GasPriceFlag.Name)),
|
GasPrice: GlobalBig(ctx, GasPriceFlag.Name),
|
||||||
GpoMinGasPrice: common.String2Big(ctx.GlobalString(GpoMinGasPriceFlag.Name)),
|
GpoMinGasPrice: GlobalBig(ctx, GpoMinGasPriceFlag.Name),
|
||||||
GpoMaxGasPrice: common.String2Big(ctx.GlobalString(GpoMaxGasPriceFlag.Name)),
|
GpoMaxGasPrice: GlobalBig(ctx, GpoMaxGasPriceFlag.Name),
|
||||||
GpoFullBlockRatio: ctx.GlobalInt(GpoFullBlockRatioFlag.Name),
|
GpoFullBlockRatio: ctx.GlobalInt(GpoFullBlockRatioFlag.Name),
|
||||||
GpobaseStepDown: ctx.GlobalInt(GpobaseStepDownFlag.Name),
|
GpobaseStepDown: ctx.GlobalInt(GpobaseStepDownFlag.Name),
|
||||||
GpobaseStepUp: ctx.GlobalInt(GpobaseStepUpFlag.Name),
|
GpobaseStepUp: ctx.GlobalInt(GpobaseStepUpFlag.Name),
|
||||||
GpobaseCorrectionFactor: ctx.GlobalInt(GpobaseCorrectionFactorFlag.Name),
|
GpobaseCorrectionFactor: ctx.GlobalInt(GpobaseCorrectionFactorFlag.Name),
|
||||||
SolcPath: ctx.GlobalString(SolcPathFlag.Name),
|
SolcPath: ctx.GlobalString(SolcPathFlag.Name),
|
||||||
AutoDAG: ctx.GlobalBool(AutoDAGFlag.Name) || ctx.GlobalBool(MiningEnabledFlag.Name),
|
EthashCacheDir: MakeEthashCacheDir(ctx),
|
||||||
|
EthashCachesInMem: ctx.GlobalInt(EthashCachesInMemoryFlag.Name),
|
||||||
|
EthashCachesOnDisk: ctx.GlobalInt(EthashCachesOnDiskFlag.Name),
|
||||||
|
EthashDatasetDir: MakeEthashDatasetDir(ctx),
|
||||||
|
EthashDatasetsInMem: ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name),
|
||||||
|
EthashDatasetsOnDisk: ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name),
|
||||||
EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name),
|
EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -761,7 +821,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||||
ethConf.NetworkId = 3
|
ethConf.NetworkId = 3
|
||||||
}
|
}
|
||||||
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
|
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
|
||||||
|
|
||||||
case ctx.GlobalBool(DevModeFlag.Name):
|
case ctx.GlobalBool(DevModeFlag.Name):
|
||||||
ethConf.Genesis = core.DevGenesisBlock()
|
ethConf.Genesis = core.DevGenesisBlock()
|
||||||
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
|
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
|
||||||
|
|
@ -820,66 +879,7 @@ func RegisterEthStatsService(stack *node.Node, url string) {
|
||||||
|
|
||||||
// SetupNetwork configures the system for either the main net or some test network.
|
// SetupNetwork configures the system for either the main net or some test network.
|
||||||
func SetupNetwork(ctx *cli.Context) {
|
func SetupNetwork(ctx *cli.Context) {
|
||||||
params.TargetGasLimit = common.String2Big(ctx.GlobalString(TargetGasLimitFlag.Name))
|
params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name))
|
||||||
}
|
|
||||||
|
|
||||||
// MakeChainConfig reads the chain configuration from the database in ctx.Datadir.
|
|
||||||
func MakeChainConfig(ctx *cli.Context, stack *node.Node) *params.ChainConfig {
|
|
||||||
db := MakeChainDatabase(ctx, stack)
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return MakeChainConfigFromDb(ctx, db)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeChainConfigFromDb reads the chain configuration from the given database.
|
|
||||||
func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainConfig {
|
|
||||||
// If the chain is already initialized, use any existing chain configs
|
|
||||||
config := new(params.ChainConfig)
|
|
||||||
|
|
||||||
genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0), 0)
|
|
||||||
if genesis != nil {
|
|
||||||
storedConfig, err := core.GetChainConfig(db, genesis.Hash())
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
config = storedConfig
|
|
||||||
case core.ChainConfigNotFoundErr:
|
|
||||||
// No configs found, use empty, will populate below
|
|
||||||
default:
|
|
||||||
Fatalf("Could not make chain configuration: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set chain id in case it's zero.
|
|
||||||
if config.ChainId == nil {
|
|
||||||
config.ChainId = new(big.Int)
|
|
||||||
}
|
|
||||||
// Check whether we are allowed to set default config params or not:
|
|
||||||
// - If no genesis is set, we're running either mainnet or testnet (private nets use `gexp init`)
|
|
||||||
// - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet)
|
|
||||||
defaults := genesis == nil ||
|
|
||||||
(genesis.Hash() == params.MainNetGenesisHash && !ctx.GlobalBool(TestNetFlag.Name)) ||
|
|
||||||
(genesis.Hash() == params.TestNetGenesisHash && ctx.GlobalBool(TestNetFlag.Name))
|
|
||||||
|
|
||||||
if defaults {
|
|
||||||
if ctx.GlobalBool(TestNetFlag.Name) {
|
|
||||||
config = params.TestnetChainConfig
|
|
||||||
} else {
|
|
||||||
// Homestead fork
|
|
||||||
config.HomesteadBlock = params.MainNetHomesteadBlock
|
|
||||||
// DAO fork
|
|
||||||
config.DAOForkBlock = params.MainNetDAOForkBlock
|
|
||||||
config.DAOForkSupport = true
|
|
||||||
|
|
||||||
// DoS reprice fork
|
|
||||||
config.EIP150Block = params.MainNetHomesteadGasRepriceBlock
|
|
||||||
config.EIP150Hash = params.MainNetHomesteadGasRepriceHash
|
|
||||||
|
|
||||||
// DoS state cleanup fork
|
|
||||||
config.EIP155Block = params.MainNetSpuriousDragon
|
|
||||||
config.EIP158Block = params.MainNetSpuriousDragon
|
|
||||||
config.ChainId = params.MainNetChainID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChainDbName(ctx *cli.Context) string {
|
func ChainDbName(ctx *cli.Context) string {
|
||||||
|
|
@ -905,27 +905,34 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
|
||||||
return chainDb
|
return chainDb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MakeGenesis(ctx *cli.Context) *core.Genesis {
|
||||||
|
var genesis *core.Genesis
|
||||||
|
switch {
|
||||||
|
case ctx.GlobalBool(TestNetFlag.Name):
|
||||||
|
genesis = core.DefaultTestnetGenesisBlock()
|
||||||
|
case ctx.GlobalBool(DevModeFlag.Name):
|
||||||
|
genesis = core.DevGenesisBlock()
|
||||||
|
}
|
||||||
|
return genesis
|
||||||
|
}
|
||||||
|
|
||||||
// MakeChain creates a chain manager from set command line flags.
|
// MakeChain creates a chain manager from set command line flags.
|
||||||
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
|
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
|
||||||
var err error
|
var err error
|
||||||
chainDb = MakeChainDatabase(ctx, stack)
|
chainDb = MakeChainDatabase(ctx, stack)
|
||||||
|
|
||||||
if ctx.GlobalBool(TestNetFlag.Name) {
|
seal := pow.PoW(pow.FakePow{})
|
||||||
_, err := core.WriteTestNetGenesisBlock(chainDb)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalln(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
chainConfig := MakeChainConfigFromDb(ctx, chainDb)
|
|
||||||
|
|
||||||
pow := pow.PoW(core.FakePow{})
|
|
||||||
if !ctx.GlobalBool(FakePoWFlag.Name) {
|
if !ctx.GlobalBool(FakePoWFlag.Name) {
|
||||||
pow = ethash.New()
|
seal = pow.NewFullEthash("", 1, 0, "", 1, 0)
|
||||||
}
|
}
|
||||||
chain, err = core.NewBlockChain(chainDb, chainConfig, pow, new(event.TypeMux), vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)})
|
config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Could not start chainmanager: %v", err)
|
Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
|
||||||
|
chain, err = core.NewBlockChain(chainDb, config, seal, new(event.TypeMux), vmcfg)
|
||||||
|
if err != nil {
|
||||||
|
Fatalf("Can't create BlockChain: %v", err)
|
||||||
}
|
}
|
||||||
return chain, chainDb
|
return chain, chainDb
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/sha1"
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
|
@ -38,8 +36,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
"github.com/expanse-org/go-expanse/console"
|
"github.com/expanse-org/go-expanse/console"
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/p2p"
|
"github.com/expanse-org/go-expanse/p2p"
|
||||||
"github.com/expanse-org/go-expanse/p2p/discover"
|
"github.com/expanse-org/go-expanse/p2p/discover"
|
||||||
"github.com/expanse-org/go-expanse/p2p/nat"
|
"github.com/expanse-org/go-expanse/p2p/nat"
|
||||||
|
|
@ -49,6 +46,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const quitCommand = "~Q"
|
const quitCommand = "~Q"
|
||||||
|
const symKeyName = "da919ea33001b04dfc630522e33078ec0df11"
|
||||||
|
|
||||||
// singletons
|
// singletons
|
||||||
var (
|
var (
|
||||||
|
|
@ -67,7 +65,8 @@ var (
|
||||||
asymKey *ecdsa.PrivateKey
|
asymKey *ecdsa.PrivateKey
|
||||||
nodeid *ecdsa.PrivateKey
|
nodeid *ecdsa.PrivateKey
|
||||||
topic whisper.TopicType
|
topic whisper.TopicType
|
||||||
filterID uint32
|
filterID string
|
||||||
|
symPass string
|
||||||
msPassword string
|
msPassword string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -82,13 +81,13 @@ var (
|
||||||
testMode = flag.Bool("t", false, "use of predefined parameters for diagnostics")
|
testMode = flag.Bool("t", false, "use of predefined parameters for diagnostics")
|
||||||
generateKey = flag.Bool("k", false, "generate and show the private key")
|
generateKey = flag.Bool("k", false, "generate and show the private key")
|
||||||
|
|
||||||
|
argVerbosity = flag.Int("verbosity", int(log.LvlWarn), "log verbosity level")
|
||||||
argTTL = flag.Uint("ttl", 30, "time-to-live for messages in seconds")
|
argTTL = flag.Uint("ttl", 30, "time-to-live for messages in seconds")
|
||||||
argWorkTime = flag.Uint("work", 5, "work time in seconds")
|
argWorkTime = flag.Uint("work", 5, "work time in seconds")
|
||||||
argPoW = flag.Float64("pow", whisper.MinimumPoW, "PoW for normal messages in float format (e.g. 2.7)")
|
argPoW = flag.Float64("pow", whisper.MinimumPoW, "PoW for normal messages in float format (e.g. 2.7)")
|
||||||
argServerPoW = flag.Float64("mspow", whisper.MinimumPoW, "PoW requirement for Mail Server request")
|
argServerPoW = flag.Float64("mspow", whisper.MinimumPoW, "PoW requirement for Mail Server request")
|
||||||
|
|
||||||
argIP = flag.String("ip", "", "IP address and port of this node (e.g. 127.0.0.1:42786)")
|
argIP = flag.String("ip", "", "IP address and port of this node (e.g. 127.0.0.1:42786)")
|
||||||
argSalt = flag.String("salt", "", "salt (for topic and key derivation)")
|
|
||||||
argPub = flag.String("pub", "", "public key for asymmetric encryption")
|
argPub = flag.String("pub", "", "public key for asymmetric encryption")
|
||||||
argDBPath = flag.String("dbpath", "", "path to the server's DB directory")
|
argDBPath = flag.String("dbpath", "", "path to the server's DB directory")
|
||||||
argIDFile = flag.String("idfile", "", "file name with node id (private key)")
|
argIDFile = flag.String("idfile", "", "file name with node id (private key)")
|
||||||
|
|
@ -146,7 +145,6 @@ func echo() {
|
||||||
fmt.Printf("pow = %f \n", *argPoW)
|
fmt.Printf("pow = %f \n", *argPoW)
|
||||||
fmt.Printf("mspow = %f \n", *argServerPoW)
|
fmt.Printf("mspow = %f \n", *argServerPoW)
|
||||||
fmt.Printf("ip = %s \n", *argIP)
|
fmt.Printf("ip = %s \n", *argIP)
|
||||||
fmt.Printf("salt = %s \n", *argSalt)
|
|
||||||
fmt.Printf("pub = %s \n", common.ToHex(crypto.FromECDSAPub(pub)))
|
fmt.Printf("pub = %s \n", common.ToHex(crypto.FromECDSAPub(pub)))
|
||||||
fmt.Printf("idfile = %s \n", *argIDFile)
|
fmt.Printf("idfile = %s \n", *argIDFile)
|
||||||
fmt.Printf("dbpath = %s \n", *argDBPath)
|
fmt.Printf("dbpath = %s \n", *argDBPath)
|
||||||
|
|
@ -154,8 +152,7 @@ func echo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initialize() {
|
func initialize() {
|
||||||
glog.SetV(logger.Warn)
|
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*argVerbosity), log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
|
||||||
glog.SetToStderr(true)
|
|
||||||
|
|
||||||
done = make(chan struct{})
|
done = make(chan struct{})
|
||||||
var peers []*discover.Node
|
var peers []*discover.Node
|
||||||
|
|
@ -172,10 +169,7 @@ func initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *testMode {
|
if *testMode {
|
||||||
password := []byte("test password for symmetric encryption")
|
symPass = "wwww" // ascii code: 0x77777777
|
||||||
salt := []byte("test salt for symmetric encryption")
|
|
||||||
symKey = pbkdf2.Key(password, salt, 64, 32, sha256.New)
|
|
||||||
topic = whisper.TopicType{0xFF, 0xFF, 0xFF, 0xFF}
|
|
||||||
msPassword = "mail server test password"
|
msPassword = "mail server test password"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,20 +280,18 @@ func configureNode() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !*asymmetricMode && !*forwarderMode && !*testMode {
|
if !*asymmetricMode && !*forwarderMode {
|
||||||
pass, err := console.Stdin.PromptPassword("Please enter the password: ")
|
if len(symPass) == 0 {
|
||||||
if err != nil {
|
symPass, err = console.Stdin.PromptPassword("Please enter the password: ")
|
||||||
utils.Fatalf("Failed to read passphrase: %v", err)
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read passphrase: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(*argSalt) == 0 {
|
shh.AddSymKey(symKeyName, []byte(symPass))
|
||||||
argSalt = scanLineA("Please enter the salt: ")
|
symKey = shh.GetSymKey(symKeyName)
|
||||||
}
|
|
||||||
|
|
||||||
symKey = pbkdf2.Key([]byte(pass), []byte(*argSalt), 65356, 32, sha256.New)
|
|
||||||
|
|
||||||
if len(*argTopic) == 0 {
|
if len(*argTopic) == 0 {
|
||||||
generateTopic([]byte(pass), []byte(*argSalt))
|
generateTopic([]byte(symPass))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -315,19 +307,17 @@ func configureNode() {
|
||||||
Topics: []whisper.TopicType{topic},
|
Topics: []whisper.TopicType{topic},
|
||||||
AcceptP2P: p2pAccept,
|
AcceptP2P: p2pAccept,
|
||||||
}
|
}
|
||||||
filterID = shh.Watch(&filter)
|
filterID, err = shh.Watch(&filter)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to install filter: %s", err)
|
||||||
|
}
|
||||||
fmt.Printf("Filter is configured for the topic: %x \n", topic)
|
fmt.Printf("Filter is configured for the topic: %x \n", topic)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateTopic(password, salt []byte) {
|
func generateTopic(password []byte) {
|
||||||
const rounds = 4000
|
x := pbkdf2.Key(password, password, 8196, 128, sha512.New)
|
||||||
const size = 128
|
for i := 0; i < len(x); i++ {
|
||||||
x1 := pbkdf2.Key(password, salt, rounds, size, sha512.New)
|
topic[i%whisper.TopicLength] ^= x[i]
|
||||||
x2 := pbkdf2.Key(password, salt, rounds, size, sha1.New)
|
|
||||||
x3 := pbkdf2.Key(x1, x2, rounds, size, sha256.New)
|
|
||||||
|
|
||||||
for i := 0; i < size; i++ {
|
|
||||||
topic[i%whisper.TopicLength] ^= x3[i]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -379,9 +369,9 @@ func sendLoop() {
|
||||||
if *asymmetricMode {
|
if *asymmetricMode {
|
||||||
// print your own message for convenience,
|
// print your own message for convenience,
|
||||||
// because in asymmetric mode it is impossible to decrypt it
|
// because in asymmetric mode it is impossible to decrypt it
|
||||||
hour, min, sec := time.Now().Clock()
|
timestamp := time.Now().Unix()
|
||||||
from := crypto.PubkeyToAddress(asymKey.PublicKey)
|
from := crypto.PubkeyToAddress(asymKey.PublicKey)
|
||||||
fmt.Printf("\n%02d:%02d:%02d <%x>: %s\n", hour, min, sec, from, s)
|
fmt.Printf("\n%d <%x>: %s\n", timestamp, from, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
common/.gitignore
vendored
12
common/.gitignore
vendored
|
|
@ -1,12 +0,0 @@
|
||||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
|
||||||
#
|
|
||||||
# If you find yourself ignoring temporary files generated by your text editor
|
|
||||||
# or operating system, you probably want to add a global ignore instead:
|
|
||||||
# git config --global core.excludesfile ~/.gitignore_global
|
|
||||||
|
|
||||||
/tmp
|
|
||||||
*/**/*un~
|
|
||||||
*un~
|
|
||||||
.DS_Store
|
|
||||||
*/**/.DS_Store
|
|
||||||
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
language: go
|
|
||||||
go:
|
|
||||||
- 1.2
|
|
||||||
140
common/big.go
140
common/big.go
|
|
@ -20,137 +20,11 @@ import "math/big"
|
||||||
|
|
||||||
// Common big integers often used
|
// Common big integers often used
|
||||||
var (
|
var (
|
||||||
Big1 = big.NewInt(1)
|
Big1 = big.NewInt(1)
|
||||||
Big2 = big.NewInt(2)
|
Big2 = big.NewInt(2)
|
||||||
Big3 = big.NewInt(3)
|
Big3 = big.NewInt(3)
|
||||||
Big0 = big.NewInt(0)
|
Big0 = big.NewInt(0)
|
||||||
BigTrue = Big1
|
Big32 = big.NewInt(32)
|
||||||
BigFalse = Big0
|
Big256 = big.NewInt(0xff)
|
||||||
Big32 = big.NewInt(32)
|
Big257 = big.NewInt(257)
|
||||||
Big36 = big.NewInt(36)
|
|
||||||
Big97 = big.NewInt(97)
|
|
||||||
Big98 = big.NewInt(98)
|
|
||||||
Big256 = big.NewInt(0xff)
|
|
||||||
Big257 = big.NewInt(257)
|
|
||||||
MaxBig = String2Big("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Big pow
|
|
||||||
//
|
|
||||||
// Returns the power of two big integers
|
|
||||||
func BigPow(a, b int) *big.Int {
|
|
||||||
c := new(big.Int)
|
|
||||||
c.Exp(big.NewInt(int64(a)), big.NewInt(int64(b)), big.NewInt(0))
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Big
|
|
||||||
//
|
|
||||||
// Shortcut for new(big.Int).SetString(..., 0)
|
|
||||||
func Big(num string) *big.Int {
|
|
||||||
n := new(big.Int)
|
|
||||||
n.SetString(num, 0)
|
|
||||||
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes2Big
|
|
||||||
//
|
|
||||||
func BytesToBig(data []byte) *big.Int {
|
|
||||||
n := new(big.Int)
|
|
||||||
n.SetBytes(data)
|
|
||||||
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
func Bytes2Big(data []byte) *big.Int { return BytesToBig(data) }
|
|
||||||
func BigD(data []byte) *big.Int { return BytesToBig(data) }
|
|
||||||
|
|
||||||
func String2Big(num string) *big.Int {
|
|
||||||
n := new(big.Int)
|
|
||||||
n.SetString(num, 0)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func BitTest(num *big.Int, i int) bool {
|
|
||||||
return num.Bit(i) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// To256
|
|
||||||
//
|
|
||||||
// "cast" the big int to a 256 big int (i.e., limit to)
|
|
||||||
var tt256 = new(big.Int).Lsh(big.NewInt(1), 256)
|
|
||||||
var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
|
|
||||||
var tt255 = new(big.Int).Lsh(big.NewInt(1), 255)
|
|
||||||
|
|
||||||
func U256(x *big.Int) *big.Int {
|
|
||||||
//if x.Cmp(Big0) < 0 {
|
|
||||||
// return new(big.Int).Add(tt256, x)
|
|
||||||
// }
|
|
||||||
|
|
||||||
x.And(x, tt256m1)
|
|
||||||
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
func S256(x *big.Int) *big.Int {
|
|
||||||
if x.Cmp(tt255) < 0 {
|
|
||||||
return x
|
|
||||||
} else {
|
|
||||||
// We don't want to modify x, ever
|
|
||||||
return new(big.Int).Sub(x, tt256)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FirstBitSet(v *big.Int) int {
|
|
||||||
for i := 0; i < v.BitLen(); i++ {
|
|
||||||
if v.Bit(i) > 0 {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return v.BitLen()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Big to bytes
|
|
||||||
//
|
|
||||||
// Returns the bytes of a big integer with the size specified by **base**
|
|
||||||
// Attempts to pad the byte array with zeros.
|
|
||||||
func BigToBytes(num *big.Int, base int) []byte {
|
|
||||||
ret := make([]byte, base/8)
|
|
||||||
|
|
||||||
if len(num.Bytes()) > base/8 {
|
|
||||||
return num.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Big copy
|
|
||||||
//
|
|
||||||
// Creates a copy of the given big integer
|
|
||||||
func BigCopy(src *big.Int) *big.Int {
|
|
||||||
return new(big.Int).Set(src)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Big max
|
|
||||||
//
|
|
||||||
// Returns the maximum size big integer
|
|
||||||
func BigMax(x, y *big.Int) *big.Int {
|
|
||||||
if x.Cmp(y) < 0 {
|
|
||||||
return y
|
|
||||||
}
|
|
||||||
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
// Big min
|
|
||||||
//
|
|
||||||
// Returns the minimum size big integer
|
|
||||||
func BigMin(x, y *big.Int) *big.Int {
|
|
||||||
if x.Cmp(y) > 0 {
|
|
||||||
return y
|
|
||||||
}
|
|
||||||
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
// Copyright 2014 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMisc(t *testing.T) {
|
|
||||||
a := Big("10")
|
|
||||||
b := Big("57896044618658097711785492504343953926634992332820282019728792003956564819968")
|
|
||||||
c := []byte{1, 2, 3, 4}
|
|
||||||
z := BitTest(a, 1)
|
|
||||||
|
|
||||||
if !z {
|
|
||||||
t.Error("Expected true got", z)
|
|
||||||
}
|
|
||||||
|
|
||||||
U256(a)
|
|
||||||
S256(a)
|
|
||||||
|
|
||||||
U256(b)
|
|
||||||
S256(b)
|
|
||||||
|
|
||||||
BigD(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBigMax(t *testing.T) {
|
|
||||||
a := Big("10")
|
|
||||||
b := Big("5")
|
|
||||||
|
|
||||||
max1 := BigMax(a, b)
|
|
||||||
if max1 != a {
|
|
||||||
t.Errorf("Expected %d got %d", a, max1)
|
|
||||||
}
|
|
||||||
|
|
||||||
max2 := BigMax(b, a)
|
|
||||||
if max2 != a {
|
|
||||||
t.Errorf("Expected %d got %d", a, max2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBigMin(t *testing.T) {
|
|
||||||
a := Big("10")
|
|
||||||
b := Big("5")
|
|
||||||
|
|
||||||
min1 := BigMin(a, b)
|
|
||||||
if min1 != b {
|
|
||||||
t.Errorf("Expected %d got %d", b, min1)
|
|
||||||
}
|
|
||||||
|
|
||||||
min2 := BigMin(b, a)
|
|
||||||
if min2 != b {
|
|
||||||
t.Errorf("Expected %d got %d", b, min2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBigCopy(t *testing.T) {
|
|
||||||
a := Big("10")
|
|
||||||
b := BigCopy(a)
|
|
||||||
c := Big("1000000000000")
|
|
||||||
y := BigToBytes(b, 16)
|
|
||||||
ybytes := []byte{0, 10}
|
|
||||||
z := BigToBytes(c, 16)
|
|
||||||
zbytes := []byte{232, 212, 165, 16, 0}
|
|
||||||
|
|
||||||
if !bytes.Equal(y, ybytes) {
|
|
||||||
t.Error("Got", ybytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(z, zbytes) {
|
|
||||||
t.Error("Got", zbytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
155
common/bytes.go
155
common/bytes.go
|
|
@ -18,12 +18,7 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ToHex(b []byte) string {
|
func ToHex(b []byte) string {
|
||||||
|
|
@ -48,65 +43,6 @@ func FromHex(s string) []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number to bytes
|
|
||||||
//
|
|
||||||
// Returns the number in bytes with the specified base
|
|
||||||
func NumberToBytes(num interface{}, bits int) []byte {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
err := binary.Write(buf, binary.BigEndian, num)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("NumberToBytes failed:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.Bytes()[buf.Len()-(bits/8):]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes to number
|
|
||||||
//
|
|
||||||
// Attempts to cast a byte slice to a unsigned integer
|
|
||||||
func BytesToNumber(b []byte) uint64 {
|
|
||||||
var number uint64
|
|
||||||
|
|
||||||
// Make sure the buffer is 64bits
|
|
||||||
data := make([]byte, 8)
|
|
||||||
data = append(data[:len(b)], b...)
|
|
||||||
|
|
||||||
buf := bytes.NewReader(data)
|
|
||||||
err := binary.Read(buf, binary.BigEndian, &number)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("BytesToNumber failed:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return number
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read variable int
|
|
||||||
//
|
|
||||||
// Read a variable length number in big endian byte order
|
|
||||||
func ReadVarInt(buff []byte) (ret uint64) {
|
|
||||||
switch l := len(buff); {
|
|
||||||
case l > 4:
|
|
||||||
d := LeftPadBytes(buff, 8)
|
|
||||||
binary.Read(bytes.NewReader(d), binary.BigEndian, &ret)
|
|
||||||
case l > 2:
|
|
||||||
var num uint32
|
|
||||||
d := LeftPadBytes(buff, 4)
|
|
||||||
binary.Read(bytes.NewReader(d), binary.BigEndian, &num)
|
|
||||||
ret = uint64(num)
|
|
||||||
case l > 1:
|
|
||||||
var num uint16
|
|
||||||
d := LeftPadBytes(buff, 2)
|
|
||||||
binary.Read(bytes.NewReader(d), binary.BigEndian, &num)
|
|
||||||
ret = uint64(num)
|
|
||||||
default:
|
|
||||||
var num uint8
|
|
||||||
binary.Read(bytes.NewReader(buff), binary.BigEndian, &num)
|
|
||||||
ret = uint64(num)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy bytes
|
// Copy bytes
|
||||||
//
|
//
|
||||||
// Returns an exact copy of the provided bytes
|
// Returns an exact copy of the provided bytes
|
||||||
|
|
@ -152,53 +88,6 @@ func Hex2BytesFixed(str string, flen int) []byte {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) {
|
|
||||||
if len(str) > 1 && str[0:2] == "0x" && !strings.Contains(str, "\n") {
|
|
||||||
ret = Hex2Bytes(str[2:])
|
|
||||||
} else {
|
|
||||||
ret = cb(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatData(data string) []byte {
|
|
||||||
if len(data) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Simple stupid
|
|
||||||
d := new(big.Int)
|
|
||||||
if data[0:1] == "\"" && data[len(data)-1:] == "\"" {
|
|
||||||
return RightPadBytes([]byte(data[1:len(data)-1]), 32)
|
|
||||||
} else if len(data) > 1 && data[:2] == "0x" {
|
|
||||||
d.SetBytes(Hex2Bytes(data[2:]))
|
|
||||||
} else {
|
|
||||||
d.SetString(data, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
return BigToBytes(d, 256)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseData(data ...interface{}) (ret []byte) {
|
|
||||||
for _, item := range data {
|
|
||||||
switch t := item.(type) {
|
|
||||||
case string:
|
|
||||||
var str []byte
|
|
||||||
if IsHex(t) {
|
|
||||||
str = Hex2Bytes(t[2:])
|
|
||||||
} else {
|
|
||||||
str = []byte(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = append(ret, RightPadBytes(str, 32)...)
|
|
||||||
case []byte:
|
|
||||||
ret = append(ret, LeftPadBytes(t, 32)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func RightPadBytes(slice []byte, l int) []byte {
|
func RightPadBytes(slice []byte, l int) []byte {
|
||||||
if l < len(slice) {
|
if l < len(slice) {
|
||||||
return slice
|
return slice
|
||||||
|
|
@ -220,47 +109,3 @@ func LeftPadBytes(slice []byte, l int) []byte {
|
||||||
|
|
||||||
return padded
|
return padded
|
||||||
}
|
}
|
||||||
|
|
||||||
func LeftPadString(str string, l int) string {
|
|
||||||
if l < len(str) {
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
zeros := Bytes2Hex(make([]byte, (l-len(str))/2))
|
|
||||||
|
|
||||||
return zeros + str
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func RightPadString(str string, l int) string {
|
|
||||||
if l < len(str) {
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
zeros := Bytes2Hex(make([]byte, (l-len(str))/2))
|
|
||||||
|
|
||||||
return str + zeros
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToAddress(slice []byte) (addr []byte) {
|
|
||||||
if len(slice) < 20 {
|
|
||||||
addr = LeftPadBytes(slice, 20)
|
|
||||||
} else if len(slice) > 20 {
|
|
||||||
addr = slice[len(slice)-20:]
|
|
||||||
} else {
|
|
||||||
addr = slice
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = CopyBytes(addr)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func ByteSliceToInterface(slice [][]byte) (ret []interface{}) {
|
|
||||||
for _, i := range slice {
|
|
||||||
ret = append(ret, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -27,54 +27,6 @@ type BytesSuite struct{}
|
||||||
|
|
||||||
var _ = checker.Suite(&BytesSuite{})
|
var _ = checker.Suite(&BytesSuite{})
|
||||||
|
|
||||||
func (s *BytesSuite) TestNumberToBytes(c *checker.C) {
|
|
||||||
// data1 := int(1)
|
|
||||||
// res1 := NumberToBytes(data1, 16)
|
|
||||||
// c.Check(res1, checker.Panics)
|
|
||||||
|
|
||||||
var data2 float64 = 3.141592653
|
|
||||||
exp2 := []byte{0xe9, 0x38}
|
|
||||||
res2 := NumberToBytes(data2, 16)
|
|
||||||
c.Assert(res2, checker.DeepEquals, exp2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BytesSuite) TestBytesToNumber(c *checker.C) {
|
|
||||||
datasmall := []byte{0xe9, 0x38, 0xe9, 0x38}
|
|
||||||
datalarge := []byte{0xe9, 0x38, 0xe9, 0x38, 0xe9, 0x38, 0xe9, 0x38}
|
|
||||||
|
|
||||||
var expsmall uint64 = 0xe938e938
|
|
||||||
var explarge uint64 = 0x0
|
|
||||||
|
|
||||||
ressmall := BytesToNumber(datasmall)
|
|
||||||
reslarge := BytesToNumber(datalarge)
|
|
||||||
|
|
||||||
c.Assert(ressmall, checker.Equals, expsmall)
|
|
||||||
c.Assert(reslarge, checker.Equals, explarge)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BytesSuite) TestReadVarInt(c *checker.C) {
|
|
||||||
data8 := []byte{1, 2, 3, 4, 5, 6, 7, 8}
|
|
||||||
data4 := []byte{1, 2, 3, 4}
|
|
||||||
data2 := []byte{1, 2}
|
|
||||||
data1 := []byte{1}
|
|
||||||
|
|
||||||
exp8 := uint64(72623859790382856)
|
|
||||||
exp4 := uint64(16909060)
|
|
||||||
exp2 := uint64(258)
|
|
||||||
exp1 := uint64(1)
|
|
||||||
|
|
||||||
res8 := ReadVarInt(data8)
|
|
||||||
res4 := ReadVarInt(data4)
|
|
||||||
res2 := ReadVarInt(data2)
|
|
||||||
res1 := ReadVarInt(data1)
|
|
||||||
|
|
||||||
c.Assert(res8, checker.Equals, exp8)
|
|
||||||
c.Assert(res4, checker.Equals, exp4)
|
|
||||||
c.Assert(res2, checker.Equals, exp2)
|
|
||||||
c.Assert(res1, checker.Equals, exp1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BytesSuite) TestCopyBytes(c *checker.C) {
|
func (s *BytesSuite) TestCopyBytes(c *checker.C) {
|
||||||
data1 := []byte{1, 2, 3, 4}
|
data1 := []byte{1, 2, 3, 4}
|
||||||
exp1 := []byte{1, 2, 3, 4}
|
exp1 := []byte{1, 2, 3, 4}
|
||||||
|
|
@ -95,22 +47,6 @@ func (s *BytesSuite) TestIsHex(c *checker.C) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BytesSuite) TestParseDataString(c *checker.C) {
|
|
||||||
res1 := ParseData("hello", "world", "0x0106")
|
|
||||||
data := "68656c6c6f000000000000000000000000000000000000000000000000000000776f726c640000000000000000000000000000000000000000000000000000000106000000000000000000000000000000000000000000000000000000000000"
|
|
||||||
exp1 := Hex2Bytes(data)
|
|
||||||
c.Assert(res1, checker.DeepEquals, exp1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BytesSuite) TestParseDataBytes(c *checker.C) {
|
|
||||||
data1 := []byte{232, 212, 165, 16, 0}
|
|
||||||
exp1 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 212, 165, 16, 0}
|
|
||||||
|
|
||||||
res1 := ParseData(data1)
|
|
||||||
c.Assert(res1, checker.DeepEquals, exp1)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BytesSuite) TestLeftPadBytes(c *checker.C) {
|
func (s *BytesSuite) TestLeftPadBytes(c *checker.C) {
|
||||||
val1 := []byte{1, 2, 3, 4}
|
val1 := []byte{1, 2, 3, 4}
|
||||||
exp1 := []byte{0, 0, 0, 0, 1, 2, 3, 4}
|
exp1 := []byte{0, 0, 0, 0, 1, 2, 3, 4}
|
||||||
|
|
@ -122,28 +58,6 @@ func (s *BytesSuite) TestLeftPadBytes(c *checker.C) {
|
||||||
c.Assert(res2, checker.DeepEquals, val1)
|
c.Assert(res2, checker.DeepEquals, val1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BytesSuite) TestFormatData(c *checker.C) {
|
|
||||||
data1 := ""
|
|
||||||
data2 := "0xa9e67e00"
|
|
||||||
data3 := "a9e67e"
|
|
||||||
data4 := "\"a9e67e00\""
|
|
||||||
|
|
||||||
// exp1 := []byte{}
|
|
||||||
exp2 := []byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0xa9, 0xe6, 0x7e, 00}
|
|
||||||
exp3 := []byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00}
|
|
||||||
exp4 := []byte{0x61, 0x39, 0x65, 0x36, 0x37, 0x65, 0x30, 0x30, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00}
|
|
||||||
|
|
||||||
res1 := FormatData(data1)
|
|
||||||
res2 := FormatData(data2)
|
|
||||||
res3 := FormatData(data3)
|
|
||||||
res4 := FormatData(data4)
|
|
||||||
|
|
||||||
c.Assert(res1, checker.IsNil)
|
|
||||||
c.Assert(res2, checker.DeepEquals, exp2)
|
|
||||||
c.Assert(res3, checker.DeepEquals, exp3)
|
|
||||||
c.Assert(res4, checker.DeepEquals, exp4)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BytesSuite) TestRightPadBytes(c *checker.C) {
|
func (s *BytesSuite) TestRightPadBytes(c *checker.C) {
|
||||||
val := []byte{1, 2, 3, 4}
|
val := []byte{1, 2, 3, 4}
|
||||||
exp := []byte{1, 2, 3, 4, 0, 0, 0, 0}
|
exp := []byte{1, 2, 3, 4, 0, 0, 0, 0}
|
||||||
|
|
@ -155,28 +69,6 @@ func (s *BytesSuite) TestRightPadBytes(c *checker.C) {
|
||||||
c.Assert(resshrt, checker.DeepEquals, val)
|
c.Assert(resshrt, checker.DeepEquals, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BytesSuite) TestLeftPadString(c *checker.C) {
|
|
||||||
val := "test"
|
|
||||||
exp := "\x30\x30\x30\x30" + val
|
|
||||||
|
|
||||||
resstd := LeftPadString(val, 8)
|
|
||||||
resshrt := LeftPadString(val, 2)
|
|
||||||
|
|
||||||
c.Assert(resstd, checker.Equals, exp)
|
|
||||||
c.Assert(resshrt, checker.Equals, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BytesSuite) TestRightPadString(c *checker.C) {
|
|
||||||
val := "test"
|
|
||||||
exp := val + "\x30\x30\x30\x30"
|
|
||||||
|
|
||||||
resstd := RightPadString(val, 8)
|
|
||||||
resshrt := RightPadString(val, 2)
|
|
||||||
|
|
||||||
c.Assert(resstd, checker.Equals, exp)
|
|
||||||
c.Assert(resshrt, checker.Equals, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFromHex(t *testing.T) {
|
func TestFromHex(t *testing.T) {
|
||||||
input := "0x01"
|
input := "0x01"
|
||||||
expected := []byte{1}
|
expected := []byte{1}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ var (
|
||||||
ErrOddLength = errors.New("hex string has odd length")
|
ErrOddLength = errors.New("hex string has odd length")
|
||||||
ErrUint64Range = errors.New("hex number does not fit into 64 bits")
|
ErrUint64Range = errors.New("hex number does not fit into 64 bits")
|
||||||
ErrUintRange = fmt.Errorf("hex number does not fit into %d bits", uintBits)
|
ErrUintRange = fmt.Errorf("hex number does not fit into %d bits", uintBits)
|
||||||
|
ErrBig256Range = errors.New("hex number does not fit into 256 bits")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Decode decodes a hex string with 0x prefix.
|
// Decode decodes a hex string with 0x prefix.
|
||||||
|
|
@ -59,7 +60,11 @@ func Decode(input string) ([]byte, error) {
|
||||||
if !has0xPrefix(input) {
|
if !has0xPrefix(input) {
|
||||||
return nil, ErrMissingPrefix
|
return nil, ErrMissingPrefix
|
||||||
}
|
}
|
||||||
return hex.DecodeString(input[2:])
|
b, err := hex.DecodeString(input[2:])
|
||||||
|
if err != nil {
|
||||||
|
err = mapError(err)
|
||||||
|
}
|
||||||
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
|
// MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
|
||||||
|
|
@ -126,11 +131,15 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBig decodes a hex string with 0x prefix as a quantity.
|
// DecodeBig decodes a hex string with 0x prefix as a quantity.
|
||||||
|
// Numbers larger than 256 bits are not accepted.
|
||||||
func DecodeBig(input string) (*big.Int, error) {
|
func DecodeBig(input string) (*big.Int, error) {
|
||||||
raw, err := checkNumber(input)
|
raw, err := checkNumber(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(raw) > 64 {
|
||||||
|
return nil, ErrBig256Range
|
||||||
|
}
|
||||||
words := make([]big.Word, len(raw)/bigWordNibbles+1)
|
words := make([]big.Word, len(raw)/bigWordNibbles+1)
|
||||||
end := len(raw)
|
end := len(raw)
|
||||||
for i := range words {
|
for i := range words {
|
||||||
|
|
@ -169,7 +178,7 @@ func EncodeBig(bigint *big.Int) string {
|
||||||
if nbits == 0 {
|
if nbits == 0 {
|
||||||
return "0x0"
|
return "0x0"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("0x%x", bigint)
|
return fmt.Sprintf("%#x", bigint)
|
||||||
}
|
}
|
||||||
|
|
||||||
func has0xPrefix(input string) bool {
|
func has0xPrefix(input string) bool {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package hexutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
@ -29,9 +28,10 @@ type marshalTest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type unmarshalTest struct {
|
type unmarshalTest struct {
|
||||||
input string
|
input string
|
||||||
want interface{}
|
want interface{}
|
||||||
wantErr error
|
wantErr error // if set, decoding must fail on any platform
|
||||||
|
wantErr32bit error // if set, decoding must fail on 32bit platforms (used for Uint tests)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -47,6 +47,7 @@ var (
|
||||||
{referenceBig("ff"), "0xff"},
|
{referenceBig("ff"), "0xff"},
|
||||||
{referenceBig("112233445566778899aabbccddeeff"), "0x112233445566778899aabbccddeeff"},
|
{referenceBig("112233445566778899aabbccddeeff"), "0x112233445566778899aabbccddeeff"},
|
||||||
{referenceBig("80a7f2c1bcc396c00"), "0x80a7f2c1bcc396c00"},
|
{referenceBig("80a7f2c1bcc396c00"), "0x80a7f2c1bcc396c00"},
|
||||||
|
{referenceBig("-80a7f2c1bcc396c00"), "-0x80a7f2c1bcc396c00"},
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeUint64Tests = []marshalTest{
|
encodeUint64Tests = []marshalTest{
|
||||||
|
|
@ -56,14 +57,21 @@ var (
|
||||||
{uint64(0x1122334455667788), "0x1122334455667788"},
|
{uint64(0x1122334455667788), "0x1122334455667788"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encodeUintTests = []marshalTest{
|
||||||
|
{uint(0), "0x0"},
|
||||||
|
{uint(1), "0x1"},
|
||||||
|
{uint(0xff), "0xff"},
|
||||||
|
{uint(0x11223344), "0x11223344"},
|
||||||
|
}
|
||||||
|
|
||||||
decodeBytesTests = []unmarshalTest{
|
decodeBytesTests = []unmarshalTest{
|
||||||
// invalid
|
// invalid
|
||||||
{input: ``, wantErr: ErrEmptyString},
|
{input: ``, wantErr: ErrEmptyString},
|
||||||
{input: `0`, wantErr: ErrMissingPrefix},
|
{input: `0`, wantErr: ErrMissingPrefix},
|
||||||
{input: `0x0`, wantErr: hex.ErrLength},
|
{input: `0x0`, wantErr: ErrOddLength},
|
||||||
{input: `0x023`, wantErr: hex.ErrLength},
|
{input: `0x023`, wantErr: ErrOddLength},
|
||||||
{input: `0xxx`, wantErr: hex.InvalidByteError('x')},
|
{input: `0xxx`, wantErr: ErrSyntax},
|
||||||
{input: `0x01zz01`, wantErr: hex.InvalidByteError('z')},
|
{input: `0x01zz01`, wantErr: ErrSyntax},
|
||||||
// valid
|
// valid
|
||||||
{input: `0x`, want: []byte{}},
|
{input: `0x`, want: []byte{}},
|
||||||
{input: `0X`, want: []byte{}},
|
{input: `0X`, want: []byte{}},
|
||||||
|
|
@ -83,6 +91,10 @@ var (
|
||||||
{input: `0x01`, wantErr: ErrLeadingZero},
|
{input: `0x01`, wantErr: ErrLeadingZero},
|
||||||
{input: `0xx`, wantErr: ErrSyntax},
|
{input: `0xx`, wantErr: ErrSyntax},
|
||||||
{input: `0x1zz01`, wantErr: ErrSyntax},
|
{input: `0x1zz01`, wantErr: ErrSyntax},
|
||||||
|
{
|
||||||
|
input: `0x10000000000000000000000000000000000000000000000000000000000000000`,
|
||||||
|
wantErr: ErrBig256Range,
|
||||||
|
},
|
||||||
// valid
|
// valid
|
||||||
{input: `0x0`, want: big.NewInt(0)},
|
{input: `0x0`, want: big.NewInt(0)},
|
||||||
{input: `0x2`, want: big.NewInt(0x2)},
|
{input: `0x2`, want: big.NewInt(0x2)},
|
||||||
|
|
@ -99,6 +111,10 @@ var (
|
||||||
input: `0xffffffffffffffffffffffffffffffffffff`,
|
input: `0xffffffffffffffffffffffffffffffffffff`,
|
||||||
want: referenceBig("ffffffffffffffffffffffffffffffffffff"),
|
want: referenceBig("ffffffffffffffffffffffffffffffffffff"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`,
|
||||||
|
want: referenceBig("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
decodeUint64Tests = []unmarshalTest{
|
decodeUint64Tests = []unmarshalTest{
|
||||||
|
|
|
||||||
|
|
@ -25,28 +25,33 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
jsonNull = []byte("null")
|
textZero = []byte(`0x0`)
|
||||||
jsonZero = []byte(`"0x0"`)
|
errNonString = errors.New("cannot unmarshal non-string as hex data")
|
||||||
errNonString = errors.New("cannot unmarshal non-string as hex data")
|
|
||||||
errNegativeBigInt = errors.New("hexutil.Big: can't marshal negative integer")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bytes marshals/unmarshals as a JSON string with 0x prefix.
|
// Bytes marshals/unmarshals as a JSON string with 0x prefix.
|
||||||
// The empty slice marshals as "0x".
|
// The empty slice marshals as "0x".
|
||||||
type Bytes []byte
|
type Bytes []byte
|
||||||
|
|
||||||
// MarshalJSON implements json.Marshaler.
|
// MarshalText implements encoding.TextMarshaler
|
||||||
func (b Bytes) MarshalJSON() ([]byte, error) {
|
func (b Bytes) MarshalText() ([]byte, error) {
|
||||||
result := make([]byte, len(b)*2+4)
|
result := make([]byte, len(b)*2+2)
|
||||||
copy(result, `"0x`)
|
copy(result, `0x`)
|
||||||
hex.Encode(result[3:], b)
|
hex.Encode(result[2:], b)
|
||||||
result[len(result)-1] = '"'
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler.
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
func (b *Bytes) UnmarshalJSON(input []byte) error {
|
func (b *Bytes) UnmarshalJSON(input []byte) error {
|
||||||
raw, err := checkJSON(input)
|
if !isString(input) {
|
||||||
|
return errNonString
|
||||||
|
}
|
||||||
|
return b.UnmarshalText(input[1 : len(input)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (b *Bytes) UnmarshalText(input []byte) error {
|
||||||
|
raw, err := checkText(input, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -64,17 +69,11 @@ func (b Bytes) String() string {
|
||||||
return Encode(b)
|
return Encode(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON decodes input as a JSON string with 0x prefix. The length of out
|
// UnmarshalFixedText decodes the input as a string with 0x prefix. The length of out
|
||||||
// determines the required input length. This function is commonly used to implement the
|
// determines the required input length. This function is commonly used to implement the
|
||||||
// UnmarshalJSON method for fixed-size types:
|
// UnmarshalText method for fixed-size types.
|
||||||
//
|
func UnmarshalFixedText(typname string, input, out []byte) error {
|
||||||
// type Foo [8]byte
|
raw, err := checkText(input, true)
|
||||||
//
|
|
||||||
// func (f *Foo) UnmarshalJSON(input []byte) error {
|
|
||||||
// return hexutil.UnmarshalJSON("Foo", input, f[:])
|
|
||||||
// }
|
|
||||||
func UnmarshalJSON(typname string, input, out []byte) error {
|
|
||||||
raw, err := checkJSON(input)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -91,34 +90,57 @@ func UnmarshalJSON(typname string, input, out []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Big marshals/unmarshals as a JSON string with 0x prefix. The zero value marshals as
|
// UnmarshalFixedUnprefixedText decodes the input as a string with optional 0x prefix. The
|
||||||
// "0x0". Negative integers are not supported at this time. Attempting to marshal them
|
// length of out determines the required input length. This function is commonly used to
|
||||||
// will return an error.
|
// implement the UnmarshalText method for fixed-size types.
|
||||||
|
func UnmarshalFixedUnprefixedText(typname string, input, out []byte) error {
|
||||||
|
raw, err := checkText(input, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(raw)/2 != len(out) {
|
||||||
|
return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname)
|
||||||
|
}
|
||||||
|
// Pre-verify syntax before modifying out.
|
||||||
|
for _, b := range raw {
|
||||||
|
if decodeNibble(b) == badNibble {
|
||||||
|
return ErrSyntax
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hex.Decode(out, raw)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Big marshals/unmarshals as a JSON string with 0x prefix.
|
||||||
|
// The zero value marshals as "0x0".
|
||||||
|
//
|
||||||
|
// Negative integers are not supported at this time. Attempting to marshal them will
|
||||||
|
// return an error. Values larger than 256bits are rejected by Unmarshal but will be
|
||||||
|
// marshaled without error.
|
||||||
type Big big.Int
|
type Big big.Int
|
||||||
|
|
||||||
// MarshalJSON implements json.Marshaler.
|
// MarshalText implements encoding.TextMarshaler
|
||||||
func (b *Big) MarshalJSON() ([]byte, error) {
|
func (b Big) MarshalText() ([]byte, error) {
|
||||||
if b == nil {
|
return []byte(EncodeBig((*big.Int)(&b))), nil
|
||||||
return jsonNull, nil
|
|
||||||
}
|
|
||||||
bigint := (*big.Int)(b)
|
|
||||||
if bigint.Sign() == -1 {
|
|
||||||
return nil, errNegativeBigInt
|
|
||||||
}
|
|
||||||
nbits := bigint.BitLen()
|
|
||||||
if nbits == 0 {
|
|
||||||
return jsonZero, nil
|
|
||||||
}
|
|
||||||
enc := fmt.Sprintf(`"0x%x"`, bigint)
|
|
||||||
return []byte(enc), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler.
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
func (b *Big) UnmarshalJSON(input []byte) error {
|
func (b *Big) UnmarshalJSON(input []byte) error {
|
||||||
raw, err := checkNumberJSON(input)
|
if !isString(input) {
|
||||||
|
return errNonString
|
||||||
|
}
|
||||||
|
return b.UnmarshalText(input[1 : len(input)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler
|
||||||
|
func (b *Big) UnmarshalText(input []byte) error {
|
||||||
|
raw, err := checkNumberText(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if len(raw) > 64 {
|
||||||
|
return ErrBig256Range
|
||||||
|
}
|
||||||
words := make([]big.Word, len(raw)/bigWordNibbles+1)
|
words := make([]big.Word, len(raw)/bigWordNibbles+1)
|
||||||
end := len(raw)
|
end := len(raw)
|
||||||
for i := range words {
|
for i := range words {
|
||||||
|
|
@ -156,18 +178,25 @@ func (b *Big) String() string {
|
||||||
// The zero value marshals as "0x0".
|
// The zero value marshals as "0x0".
|
||||||
type Uint64 uint64
|
type Uint64 uint64
|
||||||
|
|
||||||
// MarshalJSON implements json.Marshaler.
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
func (b Uint64) MarshalJSON() ([]byte, error) {
|
func (b Uint64) MarshalText() ([]byte, error) {
|
||||||
buf := make([]byte, 3, 12)
|
buf := make([]byte, 2, 10)
|
||||||
copy(buf, `"0x`)
|
copy(buf, `0x`)
|
||||||
buf = strconv.AppendUint(buf, uint64(b), 16)
|
buf = strconv.AppendUint(buf, uint64(b), 16)
|
||||||
buf = append(buf, '"')
|
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler.
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
func (b *Uint64) UnmarshalJSON(input []byte) error {
|
func (b *Uint64) UnmarshalJSON(input []byte) error {
|
||||||
raw, err := checkNumberJSON(input)
|
if !isString(input) {
|
||||||
|
return errNonString
|
||||||
|
}
|
||||||
|
return b.UnmarshalText(input[1 : len(input)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler
|
||||||
|
func (b *Uint64) UnmarshalText(input []byte) error {
|
||||||
|
raw, err := checkNumberText(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -196,19 +225,27 @@ func (b Uint64) String() string {
|
||||||
// The zero value marshals as "0x0".
|
// The zero value marshals as "0x0".
|
||||||
type Uint uint
|
type Uint uint
|
||||||
|
|
||||||
// MarshalJSON implements json.Marshaler.
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
func (b Uint) MarshalJSON() ([]byte, error) {
|
func (b Uint) MarshalText() ([]byte, error) {
|
||||||
return Uint64(b).MarshalJSON()
|
return Uint64(b).MarshalText()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler.
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
func (b *Uint) UnmarshalJSON(input []byte) error {
|
func (b *Uint) UnmarshalJSON(input []byte) error {
|
||||||
|
if !isString(input) {
|
||||||
|
return errNonString
|
||||||
|
}
|
||||||
|
return b.UnmarshalText(input[1 : len(input)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (b *Uint) UnmarshalText(input []byte) error {
|
||||||
var u64 Uint64
|
var u64 Uint64
|
||||||
err := u64.UnmarshalJSON(input)
|
err := u64.UnmarshalText(input)
|
||||||
if err != nil {
|
if u64 > Uint64(^uint(0)) || err == ErrUint64Range {
|
||||||
return err
|
|
||||||
} else if u64 > Uint64(^uint(0)) {
|
|
||||||
return ErrUintRange
|
return ErrUintRange
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
*b = Uint(u64)
|
*b = Uint(u64)
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -227,28 +264,22 @@ func bytesHave0xPrefix(input []byte) bool {
|
||||||
return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
|
return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkJSON(input []byte) (raw []byte, err error) {
|
func checkText(input []byte, wantPrefix bool) ([]byte, error) {
|
||||||
if !isString(input) {
|
if len(input) == 0 {
|
||||||
return nil, errNonString
|
|
||||||
}
|
|
||||||
if len(input) == 2 {
|
|
||||||
return nil, nil // empty strings are allowed
|
return nil, nil // empty strings are allowed
|
||||||
}
|
}
|
||||||
if !bytesHave0xPrefix(input[1:]) {
|
if bytesHave0xPrefix(input) {
|
||||||
|
input = input[2:]
|
||||||
|
} else if wantPrefix {
|
||||||
return nil, ErrMissingPrefix
|
return nil, ErrMissingPrefix
|
||||||
}
|
}
|
||||||
input = input[3 : len(input)-1]
|
|
||||||
if len(input)%2 != 0 {
|
if len(input)%2 != 0 {
|
||||||
return nil, ErrOddLength
|
return nil, ErrOddLength
|
||||||
}
|
}
|
||||||
return input, nil
|
return input, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkNumberJSON(input []byte) (raw []byte, err error) {
|
func checkNumberText(input []byte) (raw []byte, err error) {
|
||||||
if !isString(input) {
|
|
||||||
return nil, errNonString
|
|
||||||
}
|
|
||||||
input = input[1 : len(input)-1]
|
|
||||||
if len(input) == 0 {
|
if len(input) == 0 {
|
||||||
return nil, nil // empty strings are allowed
|
return nil, nil // empty strings are allowed
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
// Copyright 2017 The go-ethereum Authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -14,26 +14,32 @@
|
||||||
// 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/>.
|
||||||
|
|
||||||
package secp256k1
|
package hexutil_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"encoding/json"
|
||||||
"encoding/hex"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"testing"
|
"github.com/expanse-org/go-expanse/common/hexutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReadBits(t *testing.T) {
|
type MyType [5]byte
|
||||||
check := func(input string) {
|
|
||||||
want, _ := hex.DecodeString(input)
|
func (v *MyType) UnmarshalText(input []byte) error {
|
||||||
int, _ := new(big.Int).SetString(input, 16)
|
return hexutil.UnmarshalFixedText("MyType", input, v[:])
|
||||||
buf := make([]byte, len(want))
|
}
|
||||||
readBits(buf, int)
|
|
||||||
if !bytes.Equal(buf, want) {
|
func (v MyType) String() string {
|
||||||
t.Errorf("have: %x\nwant: %x", buf, want)
|
return hexutil.Bytes(v[:]).String()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
check("000000000000000000000000000000000000000000000000000000FEFCF3F8F0")
|
func ExampleUnmarshalFixedText() {
|
||||||
check("0000000000012345000000000000000000000000000000000000FEFCF3F8F0")
|
var v1, v2 MyType
|
||||||
check("18F8F8F1000111000110011100222004330052300000000000000000FEFCF3F8F0")
|
fmt.Println("v1 error:", json.Unmarshal([]byte(`"0x01"`), &v1))
|
||||||
|
fmt.Println("v2 error:", json.Unmarshal([]byte(`"0x0101010101"`), &v2))
|
||||||
|
fmt.Println("v2:", v2)
|
||||||
|
// Output:
|
||||||
|
// v1 error: hex string has length 2, want 10 for MyType
|
||||||
|
// v2 error: <nil>
|
||||||
|
// v2: 0x0101010101
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +19,8 @@ package hexutil
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
@ -55,9 +57,11 @@ func referenceBytes(s string) []byte {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errJSONEOF = errors.New("unexpected end of JSON input")
|
||||||
|
|
||||||
var unmarshalBytesTests = []unmarshalTest{
|
var unmarshalBytesTests = []unmarshalTest{
|
||||||
// invalid encoding
|
// invalid encoding
|
||||||
{input: "", wantErr: errNonString},
|
{input: "", wantErr: errJSONEOF},
|
||||||
{input: "null", wantErr: errNonString},
|
{input: "null", wantErr: errNonString},
|
||||||
{input: "10", wantErr: errNonString},
|
{input: "10", wantErr: errNonString},
|
||||||
{input: `"0"`, wantErr: ErrMissingPrefix},
|
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||||
|
|
@ -80,7 +84,7 @@ var unmarshalBytesTests = []unmarshalTest{
|
||||||
func TestUnmarshalBytes(t *testing.T) {
|
func TestUnmarshalBytes(t *testing.T) {
|
||||||
for _, test := range unmarshalBytesTests {
|
for _, test := range unmarshalBytesTests {
|
||||||
var v Bytes
|
var v Bytes
|
||||||
err := v.UnmarshalJSON([]byte(test.input))
|
err := json.Unmarshal([]byte(test.input), &v)
|
||||||
if !checkError(t, test.input, err, test.wantErr) {
|
if !checkError(t, test.input, err, test.wantErr) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +108,7 @@ func BenchmarkUnmarshalBytes(b *testing.B) {
|
||||||
func TestMarshalBytes(t *testing.T) {
|
func TestMarshalBytes(t *testing.T) {
|
||||||
for _, test := range encodeBytesTests {
|
for _, test := range encodeBytesTests {
|
||||||
in := test.input.([]byte)
|
in := test.input.([]byte)
|
||||||
out, err := Bytes(in).MarshalJSON()
|
out, err := json.Marshal(Bytes(in))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%x: %v", in, err)
|
t.Errorf("%x: %v", in, err)
|
||||||
continue
|
continue
|
||||||
|
|
@ -122,7 +126,7 @@ func TestMarshalBytes(t *testing.T) {
|
||||||
|
|
||||||
var unmarshalBigTests = []unmarshalTest{
|
var unmarshalBigTests = []unmarshalTest{
|
||||||
// invalid encoding
|
// invalid encoding
|
||||||
{input: "", wantErr: errNonString},
|
{input: "", wantErr: errJSONEOF},
|
||||||
{input: "null", wantErr: errNonString},
|
{input: "null", wantErr: errNonString},
|
||||||
{input: "10", wantErr: errNonString},
|
{input: "10", wantErr: errNonString},
|
||||||
{input: `"0"`, wantErr: ErrMissingPrefix},
|
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||||
|
|
@ -130,6 +134,10 @@ var unmarshalBigTests = []unmarshalTest{
|
||||||
{input: `"0x01"`, wantErr: ErrLeadingZero},
|
{input: `"0x01"`, wantErr: ErrLeadingZero},
|
||||||
{input: `"0xx"`, wantErr: ErrSyntax},
|
{input: `"0xx"`, wantErr: ErrSyntax},
|
||||||
{input: `"0x1zz01"`, wantErr: ErrSyntax},
|
{input: `"0x1zz01"`, wantErr: ErrSyntax},
|
||||||
|
{
|
||||||
|
input: `"0x10000000000000000000000000000000000000000000000000000000000000000"`,
|
||||||
|
wantErr: ErrBig256Range,
|
||||||
|
},
|
||||||
|
|
||||||
// valid encoding
|
// valid encoding
|
||||||
{input: `""`, want: big.NewInt(0)},
|
{input: `""`, want: big.NewInt(0)},
|
||||||
|
|
@ -148,12 +156,16 @@ var unmarshalBigTests = []unmarshalTest{
|
||||||
input: `"0xffffffffffffffffffffffffffffffffffff"`,
|
input: `"0xffffffffffffffffffffffffffffffffffff"`,
|
||||||
want: referenceBig("ffffffffffffffffffffffffffffffffffff"),
|
want: referenceBig("ffffffffffffffffffffffffffffffffffff"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: `"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"`,
|
||||||
|
want: referenceBig("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalBig(t *testing.T) {
|
func TestUnmarshalBig(t *testing.T) {
|
||||||
for _, test := range unmarshalBigTests {
|
for _, test := range unmarshalBigTests {
|
||||||
var v Big
|
var v Big
|
||||||
err := v.UnmarshalJSON([]byte(test.input))
|
err := json.Unmarshal([]byte(test.input), &v)
|
||||||
if !checkError(t, test.input, err, test.wantErr) {
|
if !checkError(t, test.input, err, test.wantErr) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +189,7 @@ func BenchmarkUnmarshalBig(b *testing.B) {
|
||||||
func TestMarshalBig(t *testing.T) {
|
func TestMarshalBig(t *testing.T) {
|
||||||
for _, test := range encodeBigTests {
|
for _, test := range encodeBigTests {
|
||||||
in := test.input.(*big.Int)
|
in := test.input.(*big.Int)
|
||||||
out, err := (*Big)(in).MarshalJSON()
|
out, err := json.Marshal((*Big)(in))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d: %v", in, err)
|
t.Errorf("%d: %v", in, err)
|
||||||
continue
|
continue
|
||||||
|
|
@ -195,7 +207,7 @@ func TestMarshalBig(t *testing.T) {
|
||||||
|
|
||||||
var unmarshalUint64Tests = []unmarshalTest{
|
var unmarshalUint64Tests = []unmarshalTest{
|
||||||
// invalid encoding
|
// invalid encoding
|
||||||
{input: "", wantErr: errNonString},
|
{input: "", wantErr: errJSONEOF},
|
||||||
{input: "null", wantErr: errNonString},
|
{input: "null", wantErr: errNonString},
|
||||||
{input: "10", wantErr: errNonString},
|
{input: "10", wantErr: errNonString},
|
||||||
{input: `"0"`, wantErr: ErrMissingPrefix},
|
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||||
|
|
@ -219,7 +231,7 @@ var unmarshalUint64Tests = []unmarshalTest{
|
||||||
func TestUnmarshalUint64(t *testing.T) {
|
func TestUnmarshalUint64(t *testing.T) {
|
||||||
for _, test := range unmarshalUint64Tests {
|
for _, test := range unmarshalUint64Tests {
|
||||||
var v Uint64
|
var v Uint64
|
||||||
err := v.UnmarshalJSON([]byte(test.input))
|
err := json.Unmarshal([]byte(test.input), &v)
|
||||||
if !checkError(t, test.input, err, test.wantErr) {
|
if !checkError(t, test.input, err, test.wantErr) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -241,7 +253,7 @@ func BenchmarkUnmarshalUint64(b *testing.B) {
|
||||||
func TestMarshalUint64(t *testing.T) {
|
func TestMarshalUint64(t *testing.T) {
|
||||||
for _, test := range encodeUint64Tests {
|
for _, test := range encodeUint64Tests {
|
||||||
in := test.input.(uint64)
|
in := test.input.(uint64)
|
||||||
out, err := Uint64(in).MarshalJSON()
|
out, err := json.Marshal(Uint64(in))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d: %v", in, err)
|
t.Errorf("%d: %v", in, err)
|
||||||
continue
|
continue
|
||||||
|
|
@ -256,3 +268,107 @@ func TestMarshalUint64(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMarshalUint(t *testing.T) {
|
||||||
|
for _, test := range encodeUintTests {
|
||||||
|
in := test.input.(uint)
|
||||||
|
out, err := json.Marshal(Uint(in))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d: %v", in, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if want := `"` + test.want + `"`; string(out) != want {
|
||||||
|
t.Errorf("%d: MarshalJSON output mismatch: got %q, want %q", in, out, want)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if out := (Uint)(in).String(); out != test.want {
|
||||||
|
t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// These are variables (not constants) to avoid constant overflow
|
||||||
|
// checks in the compiler on 32bit platforms.
|
||||||
|
maxUint33bits = uint64(^uint32(0)) + 1
|
||||||
|
maxUint64bits = ^uint64(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
var unmarshalUintTests = []unmarshalTest{
|
||||||
|
// invalid encoding
|
||||||
|
{input: "", wantErr: errJSONEOF},
|
||||||
|
{input: "null", wantErr: errNonString},
|
||||||
|
{input: "10", wantErr: errNonString},
|
||||||
|
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||||
|
{input: `"0x"`, wantErr: ErrEmptyNumber},
|
||||||
|
{input: `"0x01"`, wantErr: ErrLeadingZero},
|
||||||
|
{input: `"0x100000000"`, want: uint(maxUint33bits), wantErr32bit: ErrUintRange},
|
||||||
|
{input: `"0xfffffffffffffffff"`, wantErr: ErrUintRange},
|
||||||
|
{input: `"0xx"`, wantErr: ErrSyntax},
|
||||||
|
{input: `"0x1zz01"`, wantErr: ErrSyntax},
|
||||||
|
|
||||||
|
// valid encoding
|
||||||
|
{input: `""`, want: uint(0)},
|
||||||
|
{input: `"0x0"`, want: uint(0)},
|
||||||
|
{input: `"0x2"`, want: uint(0x2)},
|
||||||
|
{input: `"0x2F2"`, want: uint(0x2f2)},
|
||||||
|
{input: `"0X2F2"`, want: uint(0x2f2)},
|
||||||
|
{input: `"0x1122aaff"`, want: uint(0x1122aaff)},
|
||||||
|
{input: `"0xbbb"`, want: uint(0xbbb)},
|
||||||
|
{input: `"0xffffffff"`, want: uint(0xffffffff)},
|
||||||
|
{input: `"0xffffffffffffffff"`, want: uint(maxUint64bits), wantErr32bit: ErrUintRange},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalUint(t *testing.T) {
|
||||||
|
for _, test := range unmarshalUintTests {
|
||||||
|
var v Uint
|
||||||
|
err := json.Unmarshal([]byte(test.input), &v)
|
||||||
|
if uintBits == 32 && test.wantErr32bit != nil {
|
||||||
|
checkError(t, test.input, err, test.wantErr32bit)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !checkError(t, test.input, err, test.wantErr) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if uint(v) != test.want.(uint) {
|
||||||
|
t.Errorf("input %s: value mismatch: got %d, want %d", test.input, v, test.want)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalFixedUnprefixedText(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
want []byte
|
||||||
|
wantErr error
|
||||||
|
}{
|
||||||
|
{input: "0x2", wantErr: ErrOddLength},
|
||||||
|
{input: "2", wantErr: ErrOddLength},
|
||||||
|
{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
|
||||||
|
{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
|
||||||
|
// check that output is not modified for partially correct input
|
||||||
|
{input: "444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
|
||||||
|
{input: "0x444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
|
||||||
|
// valid inputs
|
||||||
|
{input: "44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
|
||||||
|
{input: "0x44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
out := make([]byte, 4)
|
||||||
|
err := UnmarshalFixedUnprefixedText("x", []byte(test.input), out)
|
||||||
|
switch {
|
||||||
|
case err == nil && test.wantErr != nil:
|
||||||
|
t.Errorf("%q: got no error, expected %q", test.input, test.wantErr)
|
||||||
|
case err != nil && test.wantErr == nil:
|
||||||
|
t.Errorf("%q: unexpected error %q", test.input, err)
|
||||||
|
case err != nil && err.Error() != test.wantErr.Error():
|
||||||
|
t.Errorf("%q: error mismatch: got %q, want %q", test.input, err, test.wantErr)
|
||||||
|
}
|
||||||
|
if test.want != nil && !bytes.Equal(out, test.want) {
|
||||||
|
t.Errorf("%q: output mismatch: got %x, want %x", test.input, out, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
190
common/icap.go
190
common/icap.go
|
|
@ -1,190 +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/>.
|
|
||||||
|
|
||||||
// Spec at https://github.com/ethereum/wiki/wiki/ICAP:-Inter-exchange-Client-Address-Protocol
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"math/big"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
Base36Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
ICAPLengthError = errors.New("Invalid ICAP length")
|
|
||||||
ICAPEncodingError = errors.New("Invalid ICAP encoding")
|
|
||||||
ICAPChecksumError = errors.New("Invalid ICAP checksum")
|
|
||||||
ICAPCountryCodeError = errors.New("Invalid ICAP country code")
|
|
||||||
ICAPAssetIdentError = errors.New("Invalid ICAP asset identifier")
|
|
||||||
ICAPInstCodeError = errors.New("Invalid ICAP institution code")
|
|
||||||
ICAPClientIdentError = errors.New("Invalid ICAP client identifier")
|
|
||||||
)
|
|
||||||
|
|
||||||
func ICAPToAddress(s string) (Address, error) {
|
|
||||||
switch len(s) {
|
|
||||||
case 35: // "XE" + 2 digit checksum + 31 base-36 chars of address
|
|
||||||
return parseICAP(s)
|
|
||||||
case 34: // "XE" + 2 digit checksum + 30 base-36 chars of address
|
|
||||||
return parseICAP(s)
|
|
||||||
case 20: // "XE" + 2 digit checksum + 3-char asset identifier +
|
|
||||||
// 4-char institution identifier + 9-char institution client identifier
|
|
||||||
return parseIndirectICAP(s)
|
|
||||||
default:
|
|
||||||
return Address{}, ICAPLengthError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseICAP(s string) (Address, error) {
|
|
||||||
if !strings.HasPrefix(s, "XE") {
|
|
||||||
return Address{}, ICAPCountryCodeError
|
|
||||||
}
|
|
||||||
if err := validCheckSum(s); err != nil {
|
|
||||||
return Address{}, err
|
|
||||||
}
|
|
||||||
// checksum is ISO13616, Ethereum address is base-36
|
|
||||||
bigAddr, _ := new(big.Int).SetString(s[4:], 36)
|
|
||||||
return BigToAddress(bigAddr), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseIndirectICAP(s string) (Address, error) {
|
|
||||||
if !strings.HasPrefix(s, "XE") {
|
|
||||||
return Address{}, ICAPCountryCodeError
|
|
||||||
}
|
|
||||||
if s[4:7] != "ETH" {
|
|
||||||
return Address{}, ICAPAssetIdentError
|
|
||||||
}
|
|
||||||
if err := validCheckSum(s); err != nil {
|
|
||||||
return Address{}, err
|
|
||||||
}
|
|
||||||
// TODO: integrate with ICAP namereg
|
|
||||||
return Address{}, errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddressToICAP(a Address) (string, error) {
|
|
||||||
enc := base36Encode(a.Big())
|
|
||||||
// zero padd encoded address to Direct ICAP length if needed
|
|
||||||
if len(enc) < 30 {
|
|
||||||
enc = join(strings.Repeat("0", 30-len(enc)), enc)
|
|
||||||
}
|
|
||||||
icap := join("XE", checkDigits(enc), enc)
|
|
||||||
return icap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: integrate with ICAP namereg when it's available
|
|
||||||
func AddressToIndirectICAP(a Address, instCode string) (string, error) {
|
|
||||||
// return addressToIndirectICAP(a, instCode)
|
|
||||||
return "", errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func addressToIndirectICAP(a Address, instCode string) (string, error) {
|
|
||||||
// TODO: add addressToClientIdent which grabs client ident from ICAP namereg
|
|
||||||
//clientIdent := addressToClientIdent(a)
|
|
||||||
clientIdent := "todo"
|
|
||||||
return clientIdentToIndirectICAP(instCode, clientIdent)
|
|
||||||
}
|
|
||||||
|
|
||||||
func clientIdentToIndirectICAP(instCode, clientIdent string) (string, error) {
|
|
||||||
if len(instCode) != 4 || !validBase36(instCode) {
|
|
||||||
return "", ICAPInstCodeError
|
|
||||||
}
|
|
||||||
if len(clientIdent) != 9 || !validBase36(instCode) {
|
|
||||||
return "", ICAPClientIdentError
|
|
||||||
}
|
|
||||||
|
|
||||||
// currently ETH is only valid asset identifier
|
|
||||||
s := join("ETH", instCode, clientIdent)
|
|
||||||
return join("XE", checkDigits(s), s), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN
|
|
||||||
func validCheckSum(s string) error {
|
|
||||||
s = join(s[4:], s[:4])
|
|
||||||
expanded, err := iso13616Expand(s)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
checkSumNum, _ := new(big.Int).SetString(expanded, 10)
|
|
||||||
if checkSumNum.Mod(checkSumNum, Big97).Cmp(Big1) != 0 {
|
|
||||||
return ICAPChecksumError
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkDigits(s string) string {
|
|
||||||
expanded, _ := iso13616Expand(strings.Join([]string{s, "XE00"}, ""))
|
|
||||||
num, _ := new(big.Int).SetString(expanded, 10)
|
|
||||||
num.Sub(Big98, num.Mod(num, Big97))
|
|
||||||
|
|
||||||
checkDigits := num.String()
|
|
||||||
// zero padd checksum
|
|
||||||
if len(checkDigits) == 1 {
|
|
||||||
checkDigits = join("0", checkDigits)
|
|
||||||
}
|
|
||||||
return checkDigits
|
|
||||||
}
|
|
||||||
|
|
||||||
// not base-36, but expansion to decimal literal: A = 10, B = 11, ... Z = 35
|
|
||||||
func iso13616Expand(s string) (string, error) {
|
|
||||||
var parts []string
|
|
||||||
if !validBase36(s) {
|
|
||||||
return "", ICAPEncodingError
|
|
||||||
}
|
|
||||||
for _, c := range s {
|
|
||||||
i := uint64(c)
|
|
||||||
if i >= 65 {
|
|
||||||
parts = append(parts, strconv.FormatUint(uint64(c)-55, 10))
|
|
||||||
} else {
|
|
||||||
parts = append(parts, string(c))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return join(parts...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func base36Encode(i *big.Int) string {
|
|
||||||
var chars []rune
|
|
||||||
x := new(big.Int)
|
|
||||||
for {
|
|
||||||
x.Mod(i, Big36)
|
|
||||||
chars = append(chars, rune(Base36Chars[x.Uint64()]))
|
|
||||||
i.Div(i, Big36)
|
|
||||||
if i.Cmp(Big0) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// reverse slice
|
|
||||||
for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
|
|
||||||
chars[i], chars[j] = chars[j], chars[i]
|
|
||||||
}
|
|
||||||
return string(chars)
|
|
||||||
}
|
|
||||||
|
|
||||||
func validBase36(s string) bool {
|
|
||||||
for _, c := range s {
|
|
||||||
i := uint64(c)
|
|
||||||
// 0-9 or A-Z
|
|
||||||
if i < 48 || (i > 57 && i < 65) || i > 90 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func join(s ...string) string {
|
|
||||||
return strings.Join(s, "")
|
|
||||||
}
|
|
||||||
|
|
@ -1,91 +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/>.
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
/* More test vectors:
|
|
||||||
https://github.com/ethereum/web3.js/blob/master/test/iban.fromAddress.js
|
|
||||||
https://github.com/ethereum/web3.js/blob/master/test/iban.toAddress.js
|
|
||||||
https://github.com/ethereum/web3.js/blob/master/test/iban.isValid.js
|
|
||||||
https://github.com/ethereum/libethereum/blob/develop/test/libethcore/icap.cpp
|
|
||||||
*/
|
|
||||||
|
|
||||||
type icapTest struct {
|
|
||||||
name string
|
|
||||||
addr string
|
|
||||||
icap string
|
|
||||||
}
|
|
||||||
|
|
||||||
var icapOKTests = []icapTest{
|
|
||||||
{"Direct1", "0x52dc504a422f0e2a9e7632a34a50f1a82f8224c7", "XE499OG1EH8ZZI0KXC6N83EKGT1BM97P2O7"},
|
|
||||||
{"Direct2", "0x11c5496aee77c1ba1f0854206a26dda82a81d6d8", "XE1222Q908LN1QBBU6XUQSO1OHWJIOS46OO"},
|
|
||||||
{"DirectZeroPrefix", "0x00c5496aee77c1ba1f0854206a26dda82a81d6d8", "XE7338O073KYGTWWZN0F2WZ0R8PX5ZPPZS"},
|
|
||||||
{"DirectDoubleZeroPrefix", "0x0000a5327eab78357cbf2ae8f3d49fd9d90c7d22", "XE0600DQK33XDTYUCRI0KYM5ELAKXDWWF6"},
|
|
||||||
}
|
|
||||||
|
|
||||||
var icapInvalidTests = []icapTest{
|
|
||||||
{"DirectInvalidCheckSum", "", "XE7438O073KYGTWWZN0F2WZ0R8PX5ZPPZS"},
|
|
||||||
{"DirectInvalidCountryCode", "", "XD7338O073KYGTWWZN0F2WZ0R8PX5ZPPZS"},
|
|
||||||
{"DirectInvalidLength36", "", "XE499OG1EH8ZZI0KXC6N83EKGT1BM97P2O77"},
|
|
||||||
{"DirectInvalidLength33", "", "XE499OG1EH8ZZI0KXC6N83EKGT1BM97P2"},
|
|
||||||
|
|
||||||
{"IndirectInvalidCheckSum", "", "XE35ETHXREGGOPHERSSS"},
|
|
||||||
{"IndirectInvalidAssetIdentifier", "", "XE34ETHXREGGOPHERSSS"},
|
|
||||||
{"IndirectInvalidLength19", "", "XE34ETHXREGGOPHERSS"},
|
|
||||||
{"IndirectInvalidLength21", "", "XE34ETHXREGGOPHERSSSS"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestICAPOK(t *testing.T) {
|
|
||||||
for _, test := range icapOKTests {
|
|
||||||
decodeEncodeTest(HexToAddress(test.addr), test.icap, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestICAPInvalid(t *testing.T) {
|
|
||||||
for _, test := range icapInvalidTests {
|
|
||||||
failedDecodingTest(test.icap, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeEncodeTest(addr0 Address, icap0 string, t *testing.T) {
|
|
||||||
icap1, err := AddressToICAP(addr0)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("ICAP encoding failed: %s", err)
|
|
||||||
}
|
|
||||||
if icap1 != icap0 {
|
|
||||||
t.Errorf("ICAP mismatch: have: %s want: %s", icap1, icap0)
|
|
||||||
}
|
|
||||||
|
|
||||||
addr1, err := ICAPToAddress(icap0)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("ICAP decoding failed: %s", err)
|
|
||||||
}
|
|
||||||
if addr1 != addr0 {
|
|
||||||
t.Errorf("Address mismatch: have: %x want: %x", addr1, addr0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func failedDecodingTest(icap string, t *testing.T) {
|
|
||||||
addr, err := ICAPToAddress(icap)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected ICAP decoding to fail.")
|
|
||||||
}
|
|
||||||
if addr != (Address{}) {
|
|
||||||
t.Errorf("Expected empty Address on failed ICAP decoding.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
// Copyright 2014 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"reflect"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The list type is an anonymous slice handler which can be used
|
|
||||||
// for containing any slice type to use in an environment which
|
|
||||||
// does not support slice types (e.g., JavaScript, QML)
|
|
||||||
type List struct {
|
|
||||||
mut sync.Mutex
|
|
||||||
val interface{}
|
|
||||||
list reflect.Value
|
|
||||||
Length int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialise a new list. Panics if non-slice type is given.
|
|
||||||
func NewList(t interface{}) *List {
|
|
||||||
list := reflect.ValueOf(t)
|
|
||||||
if list.Kind() != reflect.Slice {
|
|
||||||
panic("list container initialized with a non-slice type")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &List{sync.Mutex{}, t, list, list.Len()}
|
|
||||||
}
|
|
||||||
|
|
||||||
func EmptyList() *List {
|
|
||||||
return NewList([]interface{}{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get N element from the embedded slice. Returns nil if OOB.
|
|
||||||
func (self *List) Get(i int) interface{} {
|
|
||||||
if self.list.Len() > i {
|
|
||||||
self.mut.Lock()
|
|
||||||
defer self.mut.Unlock()
|
|
||||||
|
|
||||||
i := self.list.Index(i).Interface()
|
|
||||||
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *List) GetAsJson(i int) interface{} {
|
|
||||||
e := self.Get(i)
|
|
||||||
|
|
||||||
r, _ := json.Marshal(e)
|
|
||||||
|
|
||||||
return string(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appends value at the end of the slice. Panics when incompatible value
|
|
||||||
// is given.
|
|
||||||
func (self *List) Append(v interface{}) {
|
|
||||||
self.mut.Lock()
|
|
||||||
defer self.mut.Unlock()
|
|
||||||
|
|
||||||
self.list = reflect.Append(self.list, reflect.ValueOf(v))
|
|
||||||
self.Length = self.list.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the underlying slice as interface.
|
|
||||||
func (self *List) Interface() interface{} {
|
|
||||||
return self.list.Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
// For JavaScript <3
|
|
||||||
func (self *List) ToJSON() string {
|
|
||||||
// make(T, 0) != nil
|
|
||||||
list := make([]interface{}, 0)
|
|
||||||
for i := 0; i < self.Length; i++ {
|
|
||||||
list = append(list, self.Get(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
data, _ := json.Marshal(list)
|
|
||||||
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
179
common/math/big.go
Normal file
179
common/math/big.go
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Package math provides integer math utilities.
|
||||||
|
package math
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
tt255 = BigPow(2, 255)
|
||||||
|
tt256 = BigPow(2, 256)
|
||||||
|
tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1))
|
||||||
|
MaxBig256 = new(big.Int).Set(tt256m1)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// number of bits in a big.Word
|
||||||
|
wordBits = 32 << (uint64(^big.Word(0)) >> 63)
|
||||||
|
// number of bytes in a big.Word
|
||||||
|
wordBytes = wordBits / 8
|
||||||
|
)
|
||||||
|
|
||||||
|
// HexOrDecimal256 marshals big.Int as hex or decimal.
|
||||||
|
type HexOrDecimal256 big.Int
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (i *HexOrDecimal256) UnmarshalText(input []byte) error {
|
||||||
|
bigint, ok := ParseBig256(string(input))
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("invalid hex or decimal integer %q", input)
|
||||||
|
}
|
||||||
|
*i = HexOrDecimal256(*bigint)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
|
func (i *HexOrDecimal256) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(fmt.Sprintf("%#x", (*big.Int)(i))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseBig256 parses s as a 256 bit integer in decimal or hexadecimal syntax.
|
||||||
|
// Leading zeros are accepted. The empty string parses as zero.
|
||||||
|
func ParseBig256(s string) (*big.Int, bool) {
|
||||||
|
if s == "" {
|
||||||
|
return new(big.Int), true
|
||||||
|
}
|
||||||
|
var bigint *big.Int
|
||||||
|
var ok bool
|
||||||
|
if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") {
|
||||||
|
bigint, ok = new(big.Int).SetString(s[2:], 16)
|
||||||
|
} else {
|
||||||
|
bigint, ok = new(big.Int).SetString(s, 10)
|
||||||
|
}
|
||||||
|
if ok && bigint.BitLen() > 256 {
|
||||||
|
bigint, ok = nil, false
|
||||||
|
}
|
||||||
|
return bigint, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustParseBig parses s as a 256 bit big integer and panics if the string is invalid.
|
||||||
|
func MustParseBig256(s string) *big.Int {
|
||||||
|
v, ok := ParseBig256(s)
|
||||||
|
if !ok {
|
||||||
|
panic("invalid 256 bit integer: " + s)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// BigPow returns a ** b as a big integer.
|
||||||
|
func BigPow(a, b int64) *big.Int {
|
||||||
|
r := big.NewInt(a)
|
||||||
|
return r.Exp(r, big.NewInt(b), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BigMax returns the larger of x or y.
|
||||||
|
func BigMax(x, y *big.Int) *big.Int {
|
||||||
|
if x.Cmp(y) < 0 {
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// BigMin returns the smaller of x or y.
|
||||||
|
func BigMin(x, y *big.Int) *big.Int {
|
||||||
|
if x.Cmp(y) > 0 {
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// FirstBitSet returns the index of the first 1 bit in v, counting from LSB.
|
||||||
|
func FirstBitSet(v *big.Int) int {
|
||||||
|
for i := 0; i < v.BitLen(); i++ {
|
||||||
|
if v.Bit(i) > 0 {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v.BitLen()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaddedBigBytes encodes a big integer as a big-endian byte slice. The length
|
||||||
|
// of the slice is at least n bytes.
|
||||||
|
func PaddedBigBytes(bigint *big.Int, n int) []byte {
|
||||||
|
if bigint.BitLen()/8 >= n {
|
||||||
|
return bigint.Bytes()
|
||||||
|
}
|
||||||
|
ret := make([]byte, n)
|
||||||
|
ReadBits(bigint, ret)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadBits encodes the absolute value of bigint as big-endian bytes. Callers must ensure
|
||||||
|
// that buf has enough space. If buf is too short the result will be incomplete.
|
||||||
|
func ReadBits(bigint *big.Int, buf []byte) {
|
||||||
|
i := len(buf)
|
||||||
|
for _, d := range bigint.Bits() {
|
||||||
|
for j := 0; j < wordBytes && i > 0; j++ {
|
||||||
|
i--
|
||||||
|
buf[i] = byte(d)
|
||||||
|
d >>= 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// U256 encodes as a 256 bit two's complement number. This operation is destructive.
|
||||||
|
func U256(x *big.Int) *big.Int {
|
||||||
|
return x.And(x, tt256m1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// S256 interprets x as a two's complement number.
|
||||||
|
// x must not exceed 256 bits (the result is undefined if it does) and is not modified.
|
||||||
|
//
|
||||||
|
// S256(0) = 0
|
||||||
|
// S256(1) = 1
|
||||||
|
// S256(2**255) = -2**255
|
||||||
|
// S256(2**256-1) = -1
|
||||||
|
func S256(x *big.Int) *big.Int {
|
||||||
|
if x.Cmp(tt255) < 0 {
|
||||||
|
return x
|
||||||
|
} else {
|
||||||
|
return new(big.Int).Sub(x, tt256)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exp implements exponentiation by squaring.
|
||||||
|
// Exp returns a newly-allocated big integer and does not change
|
||||||
|
// base or exponent. The result is truncated to 256 bits.
|
||||||
|
//
|
||||||
|
// Courtesy @karalabe and @chfast
|
||||||
|
func Exp(base, exponent *big.Int) *big.Int {
|
||||||
|
result := big.NewInt(1)
|
||||||
|
|
||||||
|
for _, word := range exponent.Bits() {
|
||||||
|
for i := 0; i < wordBits; i++ {
|
||||||
|
if word&1 == 1 {
|
||||||
|
U256(result.Mul(result, base))
|
||||||
|
}
|
||||||
|
U256(base.Mul(base, base))
|
||||||
|
word >>= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
220
common/math/big_test.go
Normal file
220
common/math/big_test.go
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
// Copyright 2014 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package math
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHexOrDecimal256(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
num *big.Int
|
||||||
|
ok bool
|
||||||
|
}{
|
||||||
|
{"", big.NewInt(0), true},
|
||||||
|
{"0", big.NewInt(0), true},
|
||||||
|
{"0x0", big.NewInt(0), true},
|
||||||
|
{"12345678", big.NewInt(12345678), true},
|
||||||
|
{"0x12345678", big.NewInt(0x12345678), true},
|
||||||
|
{"0X12345678", big.NewInt(0x12345678), true},
|
||||||
|
// Tests for leading zero behaviour:
|
||||||
|
{"0123456789", big.NewInt(123456789), true}, // note: not octal
|
||||||
|
{"00", big.NewInt(0), true},
|
||||||
|
{"0x00", big.NewInt(0), true},
|
||||||
|
{"0x012345678abc", big.NewInt(0x12345678abc), true},
|
||||||
|
// Invalid syntax:
|
||||||
|
{"abcdef", nil, false},
|
||||||
|
{"0xgg", nil, false},
|
||||||
|
// Larger than 256 bits:
|
||||||
|
{"115792089237316195423570985008687907853269984665640564039457584007913129639936", nil, false},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
var num HexOrDecimal256
|
||||||
|
err := num.UnmarshalText([]byte(test.input))
|
||||||
|
if (err == nil) != test.ok {
|
||||||
|
t.Errorf("ParseBig(%q) -> (err == nil) == %t, want %t", test.input, err == nil, test.ok)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if test.num != nil && (*big.Int)(&num).Cmp(test.num) != 0 {
|
||||||
|
t.Errorf("ParseBig(%q) -> %d, want %d", test.input, (*big.Int)(&num), test.num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMustParseBig256(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if recover() == nil {
|
||||||
|
t.Error("MustParseBig should've panicked")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
MustParseBig256("ggg")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBigMax(t *testing.T) {
|
||||||
|
a := big.NewInt(10)
|
||||||
|
b := big.NewInt(5)
|
||||||
|
|
||||||
|
max1 := BigMax(a, b)
|
||||||
|
if max1 != a {
|
||||||
|
t.Errorf("Expected %d got %d", a, max1)
|
||||||
|
}
|
||||||
|
|
||||||
|
max2 := BigMax(b, a)
|
||||||
|
if max2 != a {
|
||||||
|
t.Errorf("Expected %d got %d", a, max2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBigMin(t *testing.T) {
|
||||||
|
a := big.NewInt(10)
|
||||||
|
b := big.NewInt(5)
|
||||||
|
|
||||||
|
min1 := BigMin(a, b)
|
||||||
|
if min1 != b {
|
||||||
|
t.Errorf("Expected %d got %d", b, min1)
|
||||||
|
}
|
||||||
|
|
||||||
|
min2 := BigMin(b, a)
|
||||||
|
if min2 != b {
|
||||||
|
t.Errorf("Expected %d got %d", b, min2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFirstBigSet(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
num *big.Int
|
||||||
|
ix int
|
||||||
|
}{
|
||||||
|
{big.NewInt(0), 0},
|
||||||
|
{big.NewInt(1), 0},
|
||||||
|
{big.NewInt(2), 1},
|
||||||
|
{big.NewInt(0x100), 8},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
if ix := FirstBitSet(test.num); ix != test.ix {
|
||||||
|
t.Errorf("FirstBitSet(b%b) = %d, want %d", test.num, ix, test.ix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaddedBigBytes(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
num *big.Int
|
||||||
|
n int
|
||||||
|
result []byte
|
||||||
|
}{
|
||||||
|
{num: big.NewInt(0), n: 4, result: []byte{0, 0, 0, 0}},
|
||||||
|
{num: big.NewInt(1), n: 4, result: []byte{0, 0, 0, 1}},
|
||||||
|
{num: big.NewInt(512), n: 4, result: []byte{0, 0, 2, 0}},
|
||||||
|
{num: BigPow(2, 32), n: 4, result: []byte{1, 0, 0, 0, 0}},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
if result := PaddedBigBytes(test.num, test.n); !bytes.Equal(result, test.result) {
|
||||||
|
t.Errorf("PaddedBigBytes(%d, %d) = %v, want %v", test.num, test.n, result, test.result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPaddedBigBytes(b *testing.B) {
|
||||||
|
bigint := MustParseBig256("123456789123456789123456789123456789")
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
PaddedBigBytes(bigint, 32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadBits(t *testing.T) {
|
||||||
|
check := func(input string) {
|
||||||
|
want, _ := hex.DecodeString(input)
|
||||||
|
int, _ := new(big.Int).SetString(input, 16)
|
||||||
|
buf := make([]byte, len(want))
|
||||||
|
ReadBits(int, buf)
|
||||||
|
if !bytes.Equal(buf, want) {
|
||||||
|
t.Errorf("have: %x\nwant: %x", buf, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check("000000000000000000000000000000000000000000000000000000FEFCF3F8F0")
|
||||||
|
check("0000000000012345000000000000000000000000000000000000FEFCF3F8F0")
|
||||||
|
check("18F8F8F1000111000110011100222004330052300000000000000000FEFCF3F8F0")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestU256(t *testing.T) {
|
||||||
|
tests := []struct{ x, y *big.Int }{
|
||||||
|
{x: big.NewInt(0), y: big.NewInt(0)},
|
||||||
|
{x: big.NewInt(1), y: big.NewInt(1)},
|
||||||
|
{x: BigPow(2, 255), y: BigPow(2, 255)},
|
||||||
|
{x: BigPow(2, 256), y: big.NewInt(0)},
|
||||||
|
{x: new(big.Int).Add(BigPow(2, 256), big.NewInt(1)), y: big.NewInt(1)},
|
||||||
|
// negative values
|
||||||
|
{x: big.NewInt(-1), y: new(big.Int).Sub(BigPow(2, 256), big.NewInt(1))},
|
||||||
|
{x: big.NewInt(-2), y: new(big.Int).Sub(BigPow(2, 256), big.NewInt(2))},
|
||||||
|
{x: BigPow(2, -255), y: big.NewInt(1)},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
if y := U256(new(big.Int).Set(test.x)); y.Cmp(test.y) != 0 {
|
||||||
|
t.Errorf("U256(%x) = %x, want %x", test.x, y, test.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestS256(t *testing.T) {
|
||||||
|
tests := []struct{ x, y *big.Int }{
|
||||||
|
{x: big.NewInt(0), y: big.NewInt(0)},
|
||||||
|
{x: big.NewInt(1), y: big.NewInt(1)},
|
||||||
|
{x: big.NewInt(2), y: big.NewInt(2)},
|
||||||
|
{
|
||||||
|
x: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
|
||||||
|
y: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: BigPow(2, 255),
|
||||||
|
y: new(big.Int).Neg(BigPow(2, 255)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(1)),
|
||||||
|
y: big.NewInt(-1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(2)),
|
||||||
|
y: big.NewInt(-2),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
if y := S256(test.x); y.Cmp(test.y) != 0 {
|
||||||
|
t.Errorf("S256(%x) = %x, want %x", test.x, y, test.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExp(t *testing.T) {
|
||||||
|
tests := []struct{ base, exponent, result *big.Int }{
|
||||||
|
{base: big.NewInt(0), exponent: big.NewInt(0), result: big.NewInt(1)},
|
||||||
|
{base: big.NewInt(1), exponent: big.NewInt(0), result: big.NewInt(1)},
|
||||||
|
{base: big.NewInt(1), exponent: big.NewInt(1), result: big.NewInt(1)},
|
||||||
|
{base: big.NewInt(1), exponent: big.NewInt(2), result: big.NewInt(1)},
|
||||||
|
{base: big.NewInt(3), exponent: big.NewInt(144), result: MustParseBig256("507528786056415600719754159741696356908742250191663887263627442114881")},
|
||||||
|
{base: big.NewInt(2), exponent: big.NewInt(255), result: MustParseBig256("57896044618658097711785492504343953926634992332820282019728792003956564819968")},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
if result := Exp(test.base, test.exponent); result.Cmp(test.result) != 0 {
|
||||||
|
t.Errorf("Exp(%d, %d) = %d, want %d", test.base, test.exponent, result, test.result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,82 +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/>.
|
|
||||||
|
|
||||||
package math
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type summer struct {
|
|
||||||
numbers []*big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s summer) Len() int { return len(s.numbers) }
|
|
||||||
func (s summer) Sum(i int) *big.Int {
|
|
||||||
return s.numbers[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSum(t *testing.T) {
|
|
||||||
summer := summer{numbers: []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}}
|
|
||||||
sum := Sum(summer)
|
|
||||||
if sum.Cmp(big.NewInt(6)) != 0 {
|
|
||||||
t.Errorf("got sum = %d, want 6", sum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDist(t *testing.T) {
|
|
||||||
var vectors = []Vector{
|
|
||||||
{big.NewInt(1000), big.NewInt(1234)},
|
|
||||||
{big.NewInt(500), big.NewInt(10023)},
|
|
||||||
{big.NewInt(1034), big.NewInt(1987)},
|
|
||||||
{big.NewInt(1034), big.NewInt(1987)},
|
|
||||||
{big.NewInt(8983), big.NewInt(1977)},
|
|
||||||
{big.NewInt(98382), big.NewInt(1887)},
|
|
||||||
{big.NewInt(12398), big.NewInt(1287)},
|
|
||||||
{big.NewInt(12398), big.NewInt(1487)},
|
|
||||||
{big.NewInt(12398), big.NewInt(1987)},
|
|
||||||
{big.NewInt(12398), big.NewInt(128)},
|
|
||||||
{big.NewInt(12398), big.NewInt(1987)},
|
|
||||||
{big.NewInt(1398), big.NewInt(187)},
|
|
||||||
{big.NewInt(12328), big.NewInt(1927)},
|
|
||||||
{big.NewInt(12398), big.NewInt(1987)},
|
|
||||||
{big.NewInt(22398), big.NewInt(1287)},
|
|
||||||
{big.NewInt(1370), big.NewInt(1981)},
|
|
||||||
{big.NewInt(12398), big.NewInt(1957)},
|
|
||||||
{big.NewInt(42198), big.NewInt(1987)},
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorsBy(GasSort).Sort(vectors)
|
|
||||||
fmt.Println(vectors)
|
|
||||||
|
|
||||||
BP := big.NewInt(15)
|
|
||||||
GL := big.NewInt(1000000)
|
|
||||||
EP := big.NewInt(100)
|
|
||||||
fmt.Println("BP", BP, "GL", GL, "EP", EP)
|
|
||||||
GP := GasPrice(BP, GL, EP)
|
|
||||||
fmt.Println("GP =", GP, "Wei per GU")
|
|
||||||
|
|
||||||
S := len(vectors) / 4
|
|
||||||
fmt.Println("L", len(vectors), "S", S)
|
|
||||||
for i := 1; i <= S*4; i += S {
|
|
||||||
fmt.Printf("T%d = %v\n", i, vectors[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
g := VectorSum(GasSum).Sum(vectors)
|
|
||||||
fmt.Printf("G = ∑g* (%v)\n", g)
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,84 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package math
|
package math
|
||||||
|
|
||||||
import gmath "math"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
const (
|
||||||
* NOTE: The following methods need to be optimised using either bit checking or asm
|
// Integer limit values.
|
||||||
*/
|
MaxInt8 = 1<<7 - 1
|
||||||
|
MinInt8 = -1 << 7
|
||||||
|
MaxInt16 = 1<<15 - 1
|
||||||
|
MinInt16 = -1 << 15
|
||||||
|
MaxInt32 = 1<<31 - 1
|
||||||
|
MinInt32 = -1 << 31
|
||||||
|
MaxInt64 = 1<<63 - 1
|
||||||
|
MinInt64 = -1 << 63
|
||||||
|
MaxUint8 = 1<<8 - 1
|
||||||
|
MaxUint16 = 1<<16 - 1
|
||||||
|
MaxUint32 = 1<<32 - 1
|
||||||
|
MaxUint64 = 1<<64 - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// HexOrDecimal64 marshals uint64 as hex or decimal.
|
||||||
|
type HexOrDecimal64 uint64
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (i *HexOrDecimal64) UnmarshalText(input []byte) error {
|
||||||
|
int, ok := ParseUint64(string(input))
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("invalid hex or decimal integer %q", input)
|
||||||
|
}
|
||||||
|
*i = HexOrDecimal64(int)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
|
func (i HexOrDecimal64) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(fmt.Sprintf("%#x", uint64(i))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseUint64 parses s as an integer in decimal or hexadecimal syntax.
|
||||||
|
// Leading zeros are accepted. The empty string parses as zero.
|
||||||
|
func ParseUint64(s string) (uint64, bool) {
|
||||||
|
if s == "" {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") {
|
||||||
|
v, err := strconv.ParseUint(s[2:], 16, 64)
|
||||||
|
return v, err == nil
|
||||||
|
}
|
||||||
|
v, err := strconv.ParseUint(s, 10, 64)
|
||||||
|
return v, err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustParseUint64 parses s as an integer and panics if the string is invalid.
|
||||||
|
func MustParseUint64(s string) uint64 {
|
||||||
|
v, ok := ParseUint64(s)
|
||||||
|
if !ok {
|
||||||
|
panic("invalid unsigned 64 bit integer: " + s)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: The following methods need to be optimised using either bit checking or asm
|
||||||
|
|
||||||
// SafeSub returns subtraction result and whether overflow occurred.
|
// SafeSub returns subtraction result and whether overflow occurred.
|
||||||
func SafeSub(x, y uint64) (uint64, bool) {
|
func SafeSub(x, y uint64) (uint64, bool) {
|
||||||
|
|
@ -13,7 +87,7 @@ func SafeSub(x, y uint64) (uint64, bool) {
|
||||||
|
|
||||||
// SafeAdd returns the result and whether overflow occurred.
|
// SafeAdd returns the result and whether overflow occurred.
|
||||||
func SafeAdd(x, y uint64) (uint64, bool) {
|
func SafeAdd(x, y uint64) (uint64, bool) {
|
||||||
return x + y, y > gmath.MaxUint64-x
|
return x + y, y > MaxUint64-x
|
||||||
}
|
}
|
||||||
|
|
||||||
// SafeMul returns multiplication result and whether overflow occurred.
|
// SafeMul returns multiplication result and whether overflow occurred.
|
||||||
|
|
@ -21,5 +95,5 @@ func SafeMul(x, y uint64) (uint64, bool) {
|
||||||
if x == 0 || y == 0 {
|
if x == 0 || y == 0 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
return x * y, y > gmath.MaxUint64/x
|
return x * y, y > MaxUint64/x
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,22 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package math
|
package math
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gmath "math"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -21,17 +36,18 @@ func TestOverflow(t *testing.T) {
|
||||||
op operation
|
op operation
|
||||||
}{
|
}{
|
||||||
// add operations
|
// add operations
|
||||||
{gmath.MaxUint64, 1, true, add},
|
{MaxUint64, 1, true, add},
|
||||||
{gmath.MaxUint64 - 1, 1, false, add},
|
{MaxUint64 - 1, 1, false, add},
|
||||||
|
|
||||||
// sub operations
|
// sub operations
|
||||||
{0, 1, true, sub},
|
{0, 1, true, sub},
|
||||||
{0, 0, false, sub},
|
{0, 0, false, sub},
|
||||||
|
|
||||||
// mul operations
|
// mul operations
|
||||||
|
{0, 0, false, mul},
|
||||||
{10, 10, false, mul},
|
{10, 10, false, mul},
|
||||||
{gmath.MaxUint64, 2, true, mul},
|
{MaxUint64, 2, true, mul},
|
||||||
{gmath.MaxUint64, 1, false, mul},
|
{MaxUint64, 1, false, mul},
|
||||||
} {
|
} {
|
||||||
var overflows bool
|
var overflows bool
|
||||||
switch test.op {
|
switch test.op {
|
||||||
|
|
@ -48,3 +64,53 @@ func TestOverflow(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHexOrDecimal64(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
num uint64
|
||||||
|
ok bool
|
||||||
|
}{
|
||||||
|
{"", 0, true},
|
||||||
|
{"0", 0, true},
|
||||||
|
{"0x0", 0, true},
|
||||||
|
{"12345678", 12345678, true},
|
||||||
|
{"0x12345678", 0x12345678, true},
|
||||||
|
{"0X12345678", 0x12345678, true},
|
||||||
|
// Tests for leading zero behaviour:
|
||||||
|
{"0123456789", 123456789, true}, // note: not octal
|
||||||
|
{"0x00", 0, true},
|
||||||
|
{"0x012345678abc", 0x12345678abc, true},
|
||||||
|
// Invalid syntax:
|
||||||
|
{"abcdef", 0, false},
|
||||||
|
{"0xgg", 0, false},
|
||||||
|
// Doesn't fit into 64 bits:
|
||||||
|
{"18446744073709551617", 0, false},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
var num HexOrDecimal64
|
||||||
|
err := num.UnmarshalText([]byte(test.input))
|
||||||
|
if (err == nil) != test.ok {
|
||||||
|
t.Errorf("ParseUint64(%q) -> (err == nil) = %t, want %t", test.input, err == nil, test.ok)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err == nil && uint64(num) != test.num {
|
||||||
|
t.Errorf("ParseUint64(%q) -> %d, want %d", test.input, num, test.num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMustParseUint64(t *testing.T) {
|
||||||
|
if v := MustParseUint64("12345"); v != 12345 {
|
||||||
|
t.Errorf(`MustParseUint64("12345") = %d, want 12345`, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMustParseUint64Panic(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if recover() == nil {
|
||||||
|
t.Error("MustParseBig should've panicked")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
MustParseUint64("ggg")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type StorageSize float64
|
type StorageSize float64
|
||||||
|
|
@ -36,54 +35,3 @@ func (self StorageSize) String() string {
|
||||||
func (self StorageSize) Int64() int64 {
|
func (self StorageSize) Int64() int64 {
|
||||||
return int64(self)
|
return int64(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The different number of units
|
|
||||||
var (
|
|
||||||
Douglas = BigPow(10, 42)
|
|
||||||
Einstein = BigPow(10, 21)
|
|
||||||
Ether = BigPow(10, 18)
|
|
||||||
Finney = BigPow(10, 15)
|
|
||||||
Szabo = BigPow(10, 12)
|
|
||||||
Shannon = BigPow(10, 9)
|
|
||||||
Babbage = BigPow(10, 6)
|
|
||||||
Ada = BigPow(10, 3)
|
|
||||||
Wei = big.NewInt(1)
|
|
||||||
)
|
|
||||||
|
|
||||||
//
|
|
||||||
// Currency to string
|
|
||||||
// Returns a string representing a human readable format
|
|
||||||
func CurrencyToString(num *big.Int) string {
|
|
||||||
var (
|
|
||||||
fin *big.Int = num
|
|
||||||
denom string = "Wei"
|
|
||||||
)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case num.Cmp(Ether) >= 0:
|
|
||||||
fin = new(big.Int).Div(num, Ether)
|
|
||||||
denom = "Ether"
|
|
||||||
case num.Cmp(Finney) >= 0:
|
|
||||||
fin = new(big.Int).Div(num, Finney)
|
|
||||||
denom = "Finney"
|
|
||||||
case num.Cmp(Szabo) >= 0:
|
|
||||||
fin = new(big.Int).Div(num, Szabo)
|
|
||||||
denom = "Szabo"
|
|
||||||
case num.Cmp(Shannon) >= 0:
|
|
||||||
fin = new(big.Int).Div(num, Shannon)
|
|
||||||
denom = "Shannon"
|
|
||||||
case num.Cmp(Babbage) >= 0:
|
|
||||||
fin = new(big.Int).Div(num, Babbage)
|
|
||||||
denom = "Babbage"
|
|
||||||
case num.Cmp(Ada) >= 0:
|
|
||||||
fin = new(big.Int).Div(num, Ada)
|
|
||||||
denom = "Ada"
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO add comment clarifying expected behavior
|
|
||||||
if len(fin.String()) > 5 {
|
|
||||||
return fmt.Sprintf("%sE%d %s", fin.String()[0:5], len(fin.String())-5, denom)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%v %s", fin, denom)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -17,43 +17,22 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"testing"
|
||||||
|
|
||||||
checker "gopkg.in/check.v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SizeSuite struct{}
|
func TestStorageSizeString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
size StorageSize
|
||||||
|
str string
|
||||||
|
}{
|
||||||
|
{2381273, "2.38 mB"},
|
||||||
|
{2192, "2.19 kB"},
|
||||||
|
{12, "12.00 B"},
|
||||||
|
}
|
||||||
|
|
||||||
var _ = checker.Suite(&SizeSuite{})
|
for _, test := range tests {
|
||||||
|
if test.size.String() != test.str {
|
||||||
func (s *SizeSuite) TestStorageSizeString(c *checker.C) {
|
t.Errorf("%f: got %q, want %q", float64(test.size), test.size.String(), test.str)
|
||||||
data1 := 2381273
|
}
|
||||||
data2 := 2192
|
}
|
||||||
data3 := 12
|
|
||||||
|
|
||||||
exp1 := "2.38 mB"
|
|
||||||
exp2 := "2.19 kB"
|
|
||||||
exp3 := "12.00 B"
|
|
||||||
|
|
||||||
c.Assert(StorageSize(data1).String(), checker.Equals, exp1)
|
|
||||||
c.Assert(StorageSize(data2).String(), checker.Equals, exp2)
|
|
||||||
c.Assert(StorageSize(data3).String(), checker.Equals, exp3)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SizeSuite) TestCommon(c *checker.C) {
|
|
||||||
ether := CurrencyToString(BigPow(10, 19))
|
|
||||||
finney := CurrencyToString(BigPow(10, 16))
|
|
||||||
szabo := CurrencyToString(BigPow(10, 13))
|
|
||||||
shannon := CurrencyToString(BigPow(10, 10))
|
|
||||||
babbage := CurrencyToString(BigPow(10, 7))
|
|
||||||
ada := CurrencyToString(BigPow(10, 4))
|
|
||||||
wei := CurrencyToString(big.NewInt(10))
|
|
||||||
|
|
||||||
c.Assert(ether, checker.Equals, "10 Ether")
|
|
||||||
c.Assert(finney, checker.Equals, "10 Finney")
|
|
||||||
c.Assert(szabo, checker.Equals, "10 Szabo")
|
|
||||||
c.Assert(shannon, checker.Equals, "10 Shannon")
|
|
||||||
c.Assert(babbage, checker.Equals, "10 Babbage")
|
|
||||||
c.Assert(ada, checker.Equals, "10 Ada")
|
|
||||||
c.Assert(wei, checker.Equals, "10 Wei")
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
103
common/types.go
103
common/types.go
|
|
@ -17,6 +17,7 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
@ -30,13 +31,8 @@ const (
|
||||||
AddressLength = 20
|
AddressLength = 20
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
|
||||||
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
|
type Hash [HashLength]byte
|
||||||
Hash [HashLength]byte
|
|
||||||
|
|
||||||
// Address represents the 20 byte address of an Ethereum account.
|
|
||||||
Address [AddressLength]byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func BytesToHash(b []byte) Hash {
|
func BytesToHash(b []byte) Hash {
|
||||||
var h Hash
|
var h Hash
|
||||||
|
|
@ -47,22 +43,38 @@ func StringToHash(s string) Hash { return BytesToHash([]byte(s)) }
|
||||||
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
||||||
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
||||||
|
|
||||||
// Don't use the default 'String' method in case we want to overwrite
|
|
||||||
|
|
||||||
// Get the string representation of the underlying hash
|
// Get the string representation of the underlying hash
|
||||||
func (h Hash) Str() string { return string(h[:]) }
|
func (h Hash) Str() string { return string(h[:]) }
|
||||||
func (h Hash) Bytes() []byte { return h[:] }
|
func (h Hash) Bytes() []byte { return h[:] }
|
||||||
func (h Hash) Big() *big.Int { return Bytes2Big(h[:]) }
|
func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
|
||||||
func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
|
func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
|
||||||
|
|
||||||
// UnmarshalJSON parses a hash in its hex from to a hash.
|
// TerminalString implements log.TerminalStringer, formatting a string for console
|
||||||
func (h *Hash) UnmarshalJSON(input []byte) error {
|
// output during logging.
|
||||||
return hexutil.UnmarshalJSON("Hash", input, h[:])
|
func (h Hash) TerminalString() string {
|
||||||
|
return fmt.Sprintf("%x…%x", h[:3], h[29:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize given hash to JSON
|
// String implements the stringer interface and is used also by the logger when
|
||||||
func (h Hash) MarshalJSON() ([]byte, error) {
|
// doing full logging into a file.
|
||||||
return hexutil.Bytes(h[:]).MarshalJSON()
|
func (h Hash) String() string {
|
||||||
|
return h.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format implements fmt.Formatter, forcing the byte slice to be formatted as is,
|
||||||
|
// without going through the stringer interface used for logging.
|
||||||
|
func (h Hash) Format(s fmt.State, c rune) {
|
||||||
|
fmt.Fprintf(s, "%"+string(c), h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText parses a hash in hex syntax.
|
||||||
|
func (h *Hash) UnmarshalText(input []byte) error {
|
||||||
|
return hexutil.UnmarshalFixedText("Hash", input, h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText returns the hex representation of h.
|
||||||
|
func (h Hash) MarshalText() ([]byte, error) {
|
||||||
|
return hexutil.Bytes(h[:]).MarshalText()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the hash to the value of b. If b is larger than len(h) it will panic
|
// Sets the hash to the value of b. If b is larger than len(h) it will panic
|
||||||
|
|
@ -97,7 +109,24 @@ func EmptyHash(h Hash) bool {
|
||||||
return h == Hash{}
|
return h == Hash{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnprefixedHash allows marshaling a Hash without 0x prefix.
|
||||||
|
type UnprefixedHash Hash
|
||||||
|
|
||||||
|
// UnmarshalText decodes the hash from hex. The 0x prefix is optional.
|
||||||
|
func (h *UnprefixedHash) UnmarshalText(input []byte) error {
|
||||||
|
return hexutil.UnmarshalFixedUnprefixedText("UnprefixedHash", input, h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText encodes the hash as hex.
|
||||||
|
func (h UnprefixedHash) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(hex.EncodeToString(h[:])), nil
|
||||||
|
}
|
||||||
|
|
||||||
/////////// Address
|
/////////// Address
|
||||||
|
|
||||||
|
// Address represents the 20 byte address of an Ethereum account.
|
||||||
|
type Address [AddressLength]byte
|
||||||
|
|
||||||
func BytesToAddress(b []byte) Address {
|
func BytesToAddress(b []byte) Address {
|
||||||
var a Address
|
var a Address
|
||||||
a.SetBytes(b)
|
a.SetBytes(b)
|
||||||
|
|
@ -122,10 +151,21 @@ func IsHexAddress(s string) bool {
|
||||||
// Get the string representation of the underlying address
|
// Get the string representation of the underlying address
|
||||||
func (a Address) Str() string { return string(a[:]) }
|
func (a Address) Str() string { return string(a[:]) }
|
||||||
func (a Address) Bytes() []byte { return a[:] }
|
func (a Address) Bytes() []byte { return a[:] }
|
||||||
func (a Address) Big() *big.Int { return Bytes2Big(a[:]) }
|
func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) }
|
||||||
func (a Address) Hash() Hash { return BytesToHash(a[:]) }
|
func (a Address) Hash() Hash { return BytesToHash(a[:]) }
|
||||||
func (a Address) Hex() string { return hexutil.Encode(a[:]) }
|
func (a Address) Hex() string { return hexutil.Encode(a[:]) }
|
||||||
|
|
||||||
|
// String implements the stringer interface and is used also by the logger.
|
||||||
|
func (a Address) String() string {
|
||||||
|
return a.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format implements fmt.Formatter, forcing the byte slice to be formatted as is,
|
||||||
|
// without going through the stringer interface used for logging.
|
||||||
|
func (a Address) Format(s fmt.State, c rune) {
|
||||||
|
fmt.Fprintf(s, "%"+string(c), a[:])
|
||||||
|
}
|
||||||
|
|
||||||
// Sets the address to the value of b. If b is larger than len(a) it will panic
|
// Sets the address to the value of b. If b is larger than len(a) it will panic
|
||||||
func (a *Address) SetBytes(b []byte) {
|
func (a *Address) SetBytes(b []byte) {
|
||||||
if len(b) > len(a) {
|
if len(b) > len(a) {
|
||||||
|
|
@ -144,22 +184,25 @@ func (a *Address) Set(other Address) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize given address to JSON
|
// MarshalText returns the hex representation of a.
|
||||||
func (a Address) MarshalJSON() ([]byte, error) {
|
func (a Address) MarshalText() ([]byte, error) {
|
||||||
return hexutil.Bytes(a[:]).MarshalJSON()
|
return hexutil.Bytes(a[:]).MarshalText()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse address from raw json data
|
// UnmarshalText parses a hash in hex syntax.
|
||||||
func (a *Address) UnmarshalJSON(input []byte) error {
|
func (a *Address) UnmarshalText(input []byte) error {
|
||||||
return hexutil.UnmarshalJSON("Address", input, a[:])
|
return hexutil.UnmarshalFixedText("Address", input, a[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// PP Pretty Prints a byte slice in the following format:
|
// UnprefixedHash allows marshaling an Address without 0x prefix.
|
||||||
// hex(value[:4])...(hex[len(value)-4:])
|
type UnprefixedAddress Address
|
||||||
func PP(value []byte) string {
|
|
||||||
if len(value) <= 8 {
|
|
||||||
return Bytes2Hex(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%x...%x", value[:4], value[len(value)-4])
|
// UnmarshalText decodes the address from hex. The 0x prefix is optional.
|
||||||
|
func (a *UnprefixedAddress) UnmarshalText(input []byte) error {
|
||||||
|
return hexutil.UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText encodes the address as hex.
|
||||||
|
func (a UnprefixedAddress) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(hex.EncodeToString(a[:])), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ func HexTo_N_(s string) _N_ { return BytesTo_N_(FromHex(s)) }
|
||||||
// Get the string representation of the underlying hash
|
// Get the string representation of the underlying hash
|
||||||
func (h _N_) Str() string { return string(h[:]) }
|
func (h _N_) Str() string { return string(h[:]) }
|
||||||
func (h _N_) Bytes() []byte { return h[:] }
|
func (h _N_) Bytes() []byte { return h[:] }
|
||||||
func (h _N_) Big() *big.Int { return Bytes2Big(h[:]) }
|
func (h _N_) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
|
||||||
func (h _N_) Hex() string { return "0x" + Bytes2Hex(h[:]) }
|
func (h _N_) Hex() string { return "0x" + Bytes2Hex(h[:]) }
|
||||||
|
|
||||||
// Sets the hash to the value of b. If b is larger than len(h) it will panic
|
// Sets the hash to the value of b. If b is larger than len(h) it will panic
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -37,7 +38,6 @@ func TestBytesConversion(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHashJsonValidation(t *testing.T) {
|
func TestHashJsonValidation(t *testing.T) {
|
||||||
var h Hash
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
Prefix string
|
Prefix string
|
||||||
Size int
|
Size int
|
||||||
|
|
@ -52,7 +52,8 @@ func TestHashJsonValidation(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
input := `"` + test.Prefix + strings.Repeat("0", test.Size) + `"`
|
input := `"` + test.Prefix + strings.Repeat("0", test.Size) + `"`
|
||||||
err := h.UnmarshalJSON([]byte(input))
|
var v Hash
|
||||||
|
err := json.Unmarshal([]byte(input), &v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if test.Error != "" {
|
if test.Error != "" {
|
||||||
t.Errorf("%s: error mismatch: have nil, want %q", input, test.Error)
|
t.Errorf("%s: error mismatch: have nil, want %q", input, test.Error)
|
||||||
|
|
@ -66,7 +67,6 @@ func TestHashJsonValidation(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddressUnmarshalJSON(t *testing.T) {
|
func TestAddressUnmarshalJSON(t *testing.T) {
|
||||||
var a Address
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
Input string
|
Input string
|
||||||
ShouldErr bool
|
ShouldErr bool
|
||||||
|
|
@ -81,7 +81,8 @@ func TestAddressUnmarshalJSON(t *testing.T) {
|
||||||
{`"0x0000000000000000000000000000000000000010"`, false, big.NewInt(16)},
|
{`"0x0000000000000000000000000000000000000010"`, false, big.NewInt(16)},
|
||||||
}
|
}
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
err := a.UnmarshalJSON([]byte(test.Input))
|
var v Address
|
||||||
|
err := json.Unmarshal([]byte(test.Input), &v)
|
||||||
if err != nil && !test.ShouldErr {
|
if err != nil && !test.ShouldErr {
|
||||||
t.Errorf("test #%d: unexpected error: %v", i, err)
|
t.Errorf("test #%d: unexpected error: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
@ -89,8 +90,8 @@ func TestAddressUnmarshalJSON(t *testing.T) {
|
||||||
if test.ShouldErr {
|
if test.ShouldErr {
|
||||||
t.Errorf("test #%d: expected error, got none", i)
|
t.Errorf("test #%d: expected error, got none", i)
|
||||||
}
|
}
|
||||||
if a.Big().Cmp(test.Output) != 0 {
|
if v.Big().Cmp(test.Output) != 0 {
|
||||||
t.Errorf("test #%d: address mismatch: have %v, want %v", i, a.Big(), test.Output)
|
t.Errorf("test #%d: address mismatch: have %v, want %v", i, v.Big(), test.Output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/rpc"
|
"github.com/expanse-org/go-expanse/rpc"
|
||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
)
|
)
|
||||||
|
|
@ -306,7 +305,7 @@ func setError(resp *otto.Object, code int, msg string) {
|
||||||
func throwJSException(msg interface{}) otto.Value {
|
func throwJSException(msg interface{}) otto.Value {
|
||||||
val, err := otto.ToValue(msg)
|
val, err := otto.ToValue(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Error).Infof("Failed to serialize JavaScript exception %v: %v", msg, err)
|
log.Error("Failed to serialize JavaScript exception", "exception", msg, "err", err)
|
||||||
}
|
}
|
||||||
panic(val)
|
panic(val)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,17 +21,16 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/core"
|
||||||
"github.com/expanse-org/go-expanse/eth"
|
"github.com/expanse-org/go-expanse/eth"
|
||||||
"github.com/expanse-org/go-expanse/internal/jsre"
|
"github.com/expanse-org/go-expanse/internal/jsre"
|
||||||
"github.com/expanse-org/go-expanse/node"
|
"github.com/expanse-org/go-expanse/node"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -97,9 +96,9 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
|
||||||
t.Fatalf("failed to create node: %v", err)
|
t.Fatalf("failed to create node: %v", err)
|
||||||
}
|
}
|
||||||
ethConf := ð.Config{
|
ethConf := ð.Config{
|
||||||
ChainConfig: ¶ms.ChainConfig{HomesteadBlock: new(big.Int), ChainId: new(big.Int)},
|
Genesis: core.DevGenesisBlock(),
|
||||||
Etherbase: common.HexToAddress(testAddress),
|
Etherbase: common.HexToAddress(testAddress),
|
||||||
PowTest: true,
|
PowTest: true,
|
||||||
}
|
}
|
||||||
if confOverride != nil {
|
if confOverride != nil {
|
||||||
confOverride(ethConf)
|
confOverride(ethConf)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ package chequebook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -37,13 +38,12 @@ import (
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/accounts/abi/bind"
|
"github.com/expanse-org/go-expanse/accounts/abi/bind"
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/hexutil"
|
||||||
"github.com/expanse-org/go-expanse/contracts/chequebook/contract"
|
"github.com/expanse-org/go-expanse/contracts/chequebook/contract"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/swarm/services/swap/swap"
|
"github.com/expanse-org/go-expanse/swarm/services/swap/swap"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(zelig): watch peer solvency and notify of bouncing cheques
|
// TODO(zelig): watch peer solvency and notify of bouncing cheques
|
||||||
|
|
@ -105,6 +105,8 @@ type Chequebook struct {
|
||||||
txhash string // tx hash of last deposit tx
|
txhash string // tx hash of last deposit tx
|
||||||
threshold *big.Int // threshold that triggers autodeposit if not nil
|
threshold *big.Int // threshold that triggers autodeposit if not nil
|
||||||
buffer *big.Int // buffer to keep on top of balance for fork protection
|
buffer *big.Int // buffer to keep on top of balance for fork protection
|
||||||
|
|
||||||
|
log log.Logger // contextual logger with the contrac address embedded
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Chequebook) String() string {
|
func (self *Chequebook) String() string {
|
||||||
|
|
@ -136,11 +138,12 @@ func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.Priva
|
||||||
owner: transactOpts.From,
|
owner: transactOpts.From,
|
||||||
contract: chbook,
|
contract: chbook,
|
||||||
session: session,
|
session: session,
|
||||||
|
log: log.New("contract", contractAddr),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contractAddr != common.Address{}) {
|
if (contractAddr != common.Address{}) {
|
||||||
self.setBalanceFromBlockChain()
|
self.setBalanceFromBlockChain()
|
||||||
glog.V(logger.Detail).Infof("new chequebook initialised from %s (owner: %v, balance: %s)", contractAddr.Hex(), self.owner.Hex(), self.balance.String())
|
self.log.Trace("New chequebook initialised", "owner", self.owner, "balance", self.balance)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +151,7 @@ func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.Priva
|
||||||
func (self *Chequebook) setBalanceFromBlockChain() {
|
func (self *Chequebook) setBalanceFromBlockChain() {
|
||||||
balance, err := self.backend.BalanceAt(context.TODO(), self.contractAddr, nil)
|
balance, err := self.backend.BalanceAt(context.TODO(), self.contractAddr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Error).Infof("can't get balance: %v", err)
|
log.Error("Failed to retrieve chequebook balance", "err", err)
|
||||||
} else {
|
} else {
|
||||||
self.balance.Set(balance)
|
self.balance.Set(balance)
|
||||||
}
|
}
|
||||||
|
|
@ -161,7 +164,6 @@ func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend, chec
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self, _ = NewChequebook(path, common.Address{}, prvKey, backend)
|
self, _ = NewChequebook(path, common.Address{}, prvKey, backend)
|
||||||
|
|
||||||
err = json.Unmarshal(data, self)
|
err = json.Unmarshal(data, self)
|
||||||
|
|
@ -171,8 +173,7 @@ func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend, chec
|
||||||
if checkBalance {
|
if checkBalance {
|
||||||
self.setBalanceFromBlockChain()
|
self.setBalanceFromBlockChain()
|
||||||
}
|
}
|
||||||
|
log.Trace("Loaded chequebook from disk", "path", path)
|
||||||
glog.V(logger.Detail).Infof("loaded chequebook (%s, owner: %v, balance: %v) initialised from %v", self.contractAddr.Hex(), self.owner.Hex(), self.balance, path)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +228,7 @@ func (self *Chequebook) Save() (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
glog.V(logger.Detail).Infof("saving chequebook (%s) to %v", self.contractAddr.Hex(), self.path)
|
self.log.Trace("Saving chequebook to disk", self.path)
|
||||||
|
|
||||||
return ioutil.WriteFile(self.path, data, os.ModePerm)
|
return ioutil.WriteFile(self.path, data, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +249,7 @@ func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
|
|
||||||
if amount.Cmp(common.Big0) <= 0 {
|
if amount.Sign() <= 0 {
|
||||||
return nil, fmt.Errorf("amount must be greater than zero (%v)", amount)
|
return nil, fmt.Errorf("amount must be greater than zero (%v)", amount)
|
||||||
}
|
}
|
||||||
if self.balance.Cmp(amount) < 0 {
|
if self.balance.Cmp(amount) < 0 {
|
||||||
|
|
@ -340,12 +341,12 @@ func (self *Chequebook) deposit(amount *big.Int) (string, error) {
|
||||||
chbookRaw := &contract.ChequebookRaw{Contract: self.contract}
|
chbookRaw := &contract.ChequebookRaw{Contract: self.contract}
|
||||||
tx, err := chbookRaw.Transfer(depositTransactor)
|
tx, err := chbookRaw.Transfer(depositTransactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Warn).Infof("error depositing %d wei to chequebook (%s, balance: %v, target: %v): %v", amount, self.contractAddr.Hex(), self.balance, self.buffer, err)
|
self.log.Warn("Failed to fund chequebook", "amount", amount, "balance", self.balance, "target", self.buffer, "err", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// assume that transaction is actually successful, we add the amount to balance right away
|
// assume that transaction is actually successful, we add the amount to balance right away
|
||||||
self.balance.Add(self.balance, amount)
|
self.balance.Add(self.balance, amount)
|
||||||
glog.V(logger.Detail).Infof("deposited %d wei to chequebook (%s, balance: %v, target: %v)", amount, self.contractAddr.Hex(), self.balance, self.buffer)
|
self.log.Trace("Deposited funds to chequebook", "amount", amount, "balance", self.balance, "target", self.buffer)
|
||||||
return tx.Hash().Hex(), nil
|
return tx.Hash().Hex(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -441,6 +442,7 @@ type Inbox struct {
|
||||||
maxUncashed *big.Int // threshold that triggers autocashing
|
maxUncashed *big.Int // threshold that triggers autocashing
|
||||||
cashed *big.Int // cumulative amount cashed
|
cashed *big.Int // cumulative amount cashed
|
||||||
cheque *Cheque // last cheque, nil if none yet received
|
cheque *Cheque // last cheque, nil if none yet received
|
||||||
|
log log.Logger // contextual logger with the contrac address embedded
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInbox creates an Inbox. An Inboxes is not persisted, the cumulative sum is updated
|
// NewInbox creates an Inbox. An Inboxes is not persisted, the cumulative sum is updated
|
||||||
|
|
@ -468,8 +470,9 @@ func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address
|
||||||
signer: signer,
|
signer: signer,
|
||||||
session: session,
|
session: session,
|
||||||
cashed: new(big.Int).Set(common.Big0),
|
cashed: new(big.Int).Set(common.Big0),
|
||||||
|
log: log.New("contract", contractAddr),
|
||||||
}
|
}
|
||||||
glog.V(logger.Detail).Infof("initialised inbox (%s -> %s) expected signer: %x", self.contract.Hex(), self.beneficiary.Hex(), crypto.FromECDSAPub(signer))
|
self.log.Trace("New chequebook inbox initialized", "beneficiary", self.beneficiary, "signer", hexutil.Bytes(crypto.FromECDSAPub(signer)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -491,7 +494,7 @@ func (self *Inbox) Stop() {
|
||||||
func (self *Inbox) Cash() (txhash string, err error) {
|
func (self *Inbox) Cash() (txhash string, err error) {
|
||||||
if self.cheque != nil {
|
if self.cheque != nil {
|
||||||
txhash, err = self.cheque.Cash(self.session)
|
txhash, err = self.cheque.Cash(self.session)
|
||||||
glog.V(logger.Detail).Infof("cashing cheque (total: %v) on chequebook (%s) sending to %v", self.cheque.Amount, self.contract.Hex(), self.beneficiary.Hex())
|
self.log.Trace("Cashing in chequebook cheque", "amount", self.cheque.Amount, "beneficiary", self.beneficiary)
|
||||||
self.cashed = self.cheque.Amount
|
self.cashed = self.cheque.Amount
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
@ -516,7 +519,7 @@ func (self *Inbox) autoCash(cashInterval time.Duration) {
|
||||||
self.quit = nil
|
self.quit = nil
|
||||||
}
|
}
|
||||||
// if maxUncashed is set to 0, then autocash on receipt
|
// if maxUncashed is set to 0, then autocash on receipt
|
||||||
if cashInterval == time.Duration(0) || self.maxUncashed != nil && self.maxUncashed.Cmp(common.Big0) == 0 {
|
if cashInterval == time.Duration(0) || self.maxUncashed != nil && self.maxUncashed.Sign() == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -575,7 +578,7 @@ func (self *Inbox) Receive(promise swap.Promise) (*big.Int, error) {
|
||||||
self.Cash()
|
self.Cash()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glog.V(logger.Detail).Infof("received cheque of %v wei in inbox (%s, uncashed: %v)", amount, self.contract.Hex(), uncashed)
|
self.log.Trace("Received cheque in chequebook inbox", "amount", amount, "uncashed", uncashed)
|
||||||
}
|
}
|
||||||
|
|
||||||
return amount, err
|
return amount, err
|
||||||
|
|
@ -583,7 +586,7 @@ func (self *Inbox) Receive(promise swap.Promise) (*big.Int, error) {
|
||||||
|
|
||||||
// Verify verifies cheque for signer, contract, beneficiary, amount, valid signature.
|
// Verify verifies cheque for signer, contract, beneficiary, amount, valid signature.
|
||||||
func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) {
|
func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) {
|
||||||
glog.V(logger.Detail).Infof("verify cheque: %v - sum: %v", self, sum)
|
log.Trace("Verifying chequebook cheque", "cheque", self, "sum", sum)
|
||||||
if sum == nil {
|
if sum == nil {
|
||||||
return nil, fmt.Errorf("invalid amount")
|
return nil, fmt.Errorf("invalid amount")
|
||||||
}
|
}
|
||||||
|
|
@ -598,7 +601,7 @@ func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary com
|
||||||
amount := new(big.Int).Set(self.Amount)
|
amount := new(big.Int).Set(self.Amount)
|
||||||
if sum != nil {
|
if sum != nil {
|
||||||
amount.Sub(amount, sum)
|
amount.Sub(amount, sum)
|
||||||
if amount.Cmp(common.Big0) <= 0 {
|
if amount.Sign() <= 0 {
|
||||||
return nil, fmt.Errorf("incorrect amount: %v <= 0", amount)
|
return nil, fmt.Errorf("incorrect amount: %v <= 0", amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,11 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func newTestBackend() *backends.SimulatedBackend {
|
func newTestBackend() *backends.SimulatedBackend {
|
||||||
return backends.NewSimulatedBackend(
|
return backends.NewSimulatedBackend(core.GenesisAlloc{
|
||||||
core.GenesisAccount{Address: addr0, Balance: big.NewInt(1000000000)},
|
addr0: {Balance: big.NewInt(1000000000)},
|
||||||
core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000000)},
|
addr1: {Balance: big.NewInt(1000000000)},
|
||||||
core.GenesisAccount{Address: addr2, Balance: big.NewInt(1000000000)},
|
addr2: {Balance: big.NewInt(1000000000)},
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {
|
func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {
|
||||||
|
|
@ -88,7 +88,7 @@ func TestIssueAndReceive(t *testing.T) {
|
||||||
t.Fatalf("expected no error, got %v", err)
|
t.Fatalf("expected no error, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if chbook.Balance().Cmp(common.Big0) != 0 {
|
if chbook.Balance().Sign() != 0 {
|
||||||
t.Errorf("expected: %v, got %v", "0", chbook.Balance())
|
t.Errorf("expected: %v, got %v", "0", chbook.Balance())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestENS(t *testing.T) {
|
func TestENS(t *testing.T) {
|
||||||
contractBackend := backends.NewSimulatedBackend(core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000000)})
|
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}})
|
||||||
transactOpts := bind.NewKeyedTransactor(key)
|
transactOpts := bind.NewKeyedTransactor(key)
|
||||||
// Workaround for bug estimating gas in the call to Register
|
// Workaround for bug estimating gas in the call to Register
|
||||||
transactOpts.GasLimit = big.NewInt(1000000)
|
transactOpts.GasLimit = big.NewInt(1000000)
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,11 @@ func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.Privat
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth := bind.NewKeyedTransactor(key)
|
auth := bind.NewKeyedTransactor(key)
|
||||||
|
|
||||||
accounts := []core.GenesisAccount{{Address: auth.From, Balance: big.NewInt(10000000000)}}
|
alloc := core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}
|
||||||
for _, key := range prefund {
|
for _, key := range prefund {
|
||||||
accounts = append(accounts, core.GenesisAccount{Address: crypto.PubkeyToAddress(key.PublicKey), Balance: big.NewInt(10000000000)})
|
alloc[crypto.PubkeyToAddress(key.PublicKey)] = core.GenesisAccount{Balance: big.NewInt(10000000000)}
|
||||||
}
|
}
|
||||||
sim := backends.NewSimulatedBackend(accounts...)
|
sim := backends.NewSimulatedBackend(alloc)
|
||||||
|
|
||||||
// Deploy a version oracle contract, commit and return
|
// Deploy a version oracle contract, commit and return
|
||||||
_, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From})
|
_, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From})
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package release
|
||||||
//go:generate abigen --sol ./contract.sol --pkg release --out ./contract.go
|
//go:generate abigen --sol ./contract.sol --pkg release --out ./contract.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -29,12 +30,10 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/eth"
|
"github.com/expanse-org/go-expanse/eth"
|
||||||
"github.com/expanse-org/go-expanse/internal/ethapi"
|
"github.com/expanse-org/go-expanse/internal/ethapi"
|
||||||
"github.com/expanse-org/go-expanse/les"
|
"github.com/expanse-org/go-expanse/les"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/node"
|
"github.com/expanse-org/go-expanse/node"
|
||||||
"github.com/expanse-org/go-expanse/p2p"
|
"github.com/expanse-org/go-expanse/p2p"
|
||||||
"github.com/expanse-org/go-expanse/rpc"
|
"github.com/expanse-org/go-expanse/rpc"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interval to check for new releases
|
// Interval to check for new releases
|
||||||
|
|
@ -117,46 +116,49 @@ func (r *ReleaseService) checker() {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
// If the time arrived, check for a new release
|
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
// Rechedule the timer before continuing
|
// Rechedule the timer before continuing
|
||||||
timer.Reset(releaseRecheckInterval)
|
timer.Reset(releaseRecheckInterval)
|
||||||
|
r.checkVersion()
|
||||||
// Retrieve the current version, and handle missing contracts gracefully
|
|
||||||
ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
opts := &bind.CallOpts{Context: ctx}
|
|
||||||
version, err := r.oracle.CurrentVersion(opts)
|
|
||||||
if err != nil {
|
|
||||||
if err == bind.ErrNoCode {
|
|
||||||
glog.V(logger.Debug).Infof("Release oracle not found at %x", r.config.Oracle)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
glog.V(logger.Error).Infof("Failed to retrieve current release: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Version was successfully retrieved, notify if newer than ours
|
|
||||||
if version.Major > r.config.Major ||
|
|
||||||
(version.Major == r.config.Major && version.Minor > r.config.Minor) ||
|
|
||||||
(version.Major == r.config.Major && version.Minor == r.config.Minor && version.Patch > r.config.Patch) {
|
|
||||||
|
|
||||||
warning := fmt.Sprintf("Client v%d.%d.%d-%x seems older than the latest upstream release v%d.%d.%d-%x",
|
|
||||||
r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4], version.Major, version.Minor, version.Patch, version.Commit[:4])
|
|
||||||
howtofix := fmt.Sprintf("Please check https://github.com/expanse-org/go-expanse/releases for new releases")
|
|
||||||
separator := strings.Repeat("-", len(warning))
|
|
||||||
|
|
||||||
glog.V(logger.Warn).Info(separator)
|
|
||||||
glog.V(logger.Warn).Info(warning)
|
|
||||||
glog.V(logger.Warn).Info(howtofix)
|
|
||||||
glog.V(logger.Warn).Info(separator)
|
|
||||||
} else {
|
|
||||||
glog.V(logger.Debug).Infof("Client v%d.%d.%d-%x seems up to date with upstream v%d.%d.%d-%x",
|
|
||||||
r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4], version.Major, version.Minor, version.Patch, version.Commit[:4])
|
|
||||||
}
|
|
||||||
|
|
||||||
// If termination was requested, return
|
|
||||||
case errc := <-r.quit:
|
case errc := <-r.quit:
|
||||||
errc <- nil
|
errc <- nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ReleaseService) checkVersion() {
|
||||||
|
// Retrieve the current version, and handle missing contracts gracefully
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
|
opts := &bind.CallOpts{Context: ctx}
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
version, err := r.oracle.CurrentVersion(opts)
|
||||||
|
if err != nil {
|
||||||
|
if err == bind.ErrNoCode {
|
||||||
|
log.Debug("Release oracle not found", "contract", r.config.Oracle)
|
||||||
|
} else {
|
||||||
|
log.Error("Failed to retrieve current release", "err", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Version was successfully retrieved, notify if newer than ours
|
||||||
|
if version.Major > r.config.Major ||
|
||||||
|
(version.Major == r.config.Major && version.Minor > r.config.Minor) ||
|
||||||
|
(version.Major == r.config.Major && version.Minor == r.config.Minor && version.Patch > r.config.Patch) {
|
||||||
|
|
||||||
|
warning := fmt.Sprintf("Client v%d.%d.%d-%x seems older than the latest upstream release v%d.%d.%d-%x",
|
||||||
|
r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4], version.Major, version.Minor, version.Patch, version.Commit[:4])
|
||||||
|
howtofix := fmt.Sprintf("Please check https://github.com/expanse-org/go-expanse/releases for new releases")
|
||||||
|
separator := strings.Repeat("-", len(warning))
|
||||||
|
|
||||||
|
log.Warn(separator)
|
||||||
|
log.Warn(warning)
|
||||||
|
log.Warn(howtofix)
|
||||||
|
log.Warn(separator)
|
||||||
|
} else {
|
||||||
|
log.Debug("Client seems up to date with upstream",
|
||||||
|
"local", fmt.Sprintf("v%d.%d.%d-%x", r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4]),
|
||||||
|
"upstream", fmt.Sprintf("v%d.%d.%d-%x", version.Major, version.Minor, version.Patch, version.Commit[:4]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
139
core/asm/asm.go
Normal file
139
core/asm/asm.go
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Provides support for dealing with EVM assembly instructions (e.g., disassembling them).
|
||||||
|
package asm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/core/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Iterator for disassembled EVM instructions
|
||||||
|
type instructionIterator struct {
|
||||||
|
code []byte
|
||||||
|
pc uint64
|
||||||
|
arg []byte
|
||||||
|
op vm.OpCode
|
||||||
|
error error
|
||||||
|
started bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new instruction iterator.
|
||||||
|
func NewInstructionIterator(code []byte) *instructionIterator {
|
||||||
|
it := new(instructionIterator)
|
||||||
|
it.code = code
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if there is a next instruction and moves on.
|
||||||
|
func (it *instructionIterator) Next() bool {
|
||||||
|
if it.error != nil || uint64(len(it.code)) <= it.pc {
|
||||||
|
// We previously reached an error or the end.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if it.started {
|
||||||
|
// Since the iteration has been already started we move to the next instruction.
|
||||||
|
if it.arg != nil {
|
||||||
|
it.pc += uint64(len(it.arg))
|
||||||
|
}
|
||||||
|
it.pc++
|
||||||
|
} else {
|
||||||
|
// We start the iteration from the first instruction.
|
||||||
|
it.started = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint64(len(it.code)) <= it.pc {
|
||||||
|
// We reached the end.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
it.op = vm.OpCode(it.code[it.pc])
|
||||||
|
if it.op.IsPush() {
|
||||||
|
a := uint64(it.op) - uint64(vm.PUSH1) + 1
|
||||||
|
u := it.pc + 1 + a
|
||||||
|
if uint64(len(it.code)) <= it.pc || uint64(len(it.code)) < u {
|
||||||
|
it.error = fmt.Errorf("incomplete push instruction at %v", it.pc)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
it.arg = it.code[it.pc+1 : u]
|
||||||
|
} else {
|
||||||
|
it.arg = nil
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns any error that may have been encountered.
|
||||||
|
func (it *instructionIterator) Error() error {
|
||||||
|
return it.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the PC of the current instruction.
|
||||||
|
func (it *instructionIterator) PC() uint64 {
|
||||||
|
return it.pc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the opcode of the current instruction.
|
||||||
|
func (it *instructionIterator) Op() vm.OpCode {
|
||||||
|
return it.op
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the argument of the current instruction.
|
||||||
|
func (it *instructionIterator) Arg() []byte {
|
||||||
|
return it.arg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pretty-print all disassembled EVM instructions to stdout.
|
||||||
|
func PrintDisassembled(code string) error {
|
||||||
|
script, err := hex.DecodeString(code)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
it := NewInstructionIterator(script)
|
||||||
|
for it.Next() {
|
||||||
|
if it.Arg() != nil && 0 < len(it.Arg()) {
|
||||||
|
fmt.Printf("%06v: %v 0x%x\n", it.PC(), it.Op(), it.Arg())
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%06v: %v\n", it.PC(), it.Op())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := it.Error(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return all disassembled EVM instructions in human-readable format.
|
||||||
|
func Disassemble(script []byte) ([]string, error) {
|
||||||
|
instrs := make([]string, 0)
|
||||||
|
|
||||||
|
it := NewInstructionIterator(script)
|
||||||
|
for it.Next() {
|
||||||
|
if it.Arg() != nil && 0 < len(it.Arg()) {
|
||||||
|
instrs = append(instrs, fmt.Sprintf("%06v: %v 0x%x\n", it.PC(), it.Op(), it.Arg()))
|
||||||
|
} else {
|
||||||
|
instrs = append(instrs, fmt.Sprintf("%06v: %v\n", it.PC(), it.Op()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := it.Error(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return instrs, nil
|
||||||
|
}
|
||||||
74
core/asm/asm_test.go
Normal file
74
core/asm/asm_test.go
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package asm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tests disassembling the instructions for valid evm code
|
||||||
|
func TestInstructionIteratorValid(t *testing.T) {
|
||||||
|
cnt := 0
|
||||||
|
script, _ := hex.DecodeString("61000000")
|
||||||
|
|
||||||
|
it := NewInstructionIterator(script)
|
||||||
|
for it.Next() {
|
||||||
|
cnt++
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := it.Error(); err != nil {
|
||||||
|
t.Errorf("Expected 2, but encountered error %v instead.", err)
|
||||||
|
}
|
||||||
|
if cnt != 2 {
|
||||||
|
t.Errorf("Expected 2, but got %v instead.", cnt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests disassembling the instructions for invalid evm code
|
||||||
|
func TestInstructionIteratorInvalid(t *testing.T) {
|
||||||
|
cnt := 0
|
||||||
|
script, _ := hex.DecodeString("6100")
|
||||||
|
|
||||||
|
it := NewInstructionIterator(script)
|
||||||
|
for it.Next() {
|
||||||
|
cnt++
|
||||||
|
}
|
||||||
|
|
||||||
|
if it.Error() == nil {
|
||||||
|
t.Errorf("Expected an error, but got %v instead.", cnt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests disassembling the instructions for empty evm code
|
||||||
|
func TestInstructionIteratorEmpty(t *testing.T) {
|
||||||
|
cnt := 0
|
||||||
|
script, _ := hex.DecodeString("")
|
||||||
|
|
||||||
|
it := NewInstructionIterator(script)
|
||||||
|
for it.Next() {
|
||||||
|
cnt++
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := it.Error(); err != nil {
|
||||||
|
t.Errorf("Expected 0, but encountered error %v instead.", err)
|
||||||
|
}
|
||||||
|
if cnt != 0 {
|
||||||
|
t.Errorf("Expected 0, but got %v instead.", cnt)
|
||||||
|
}
|
||||||
|
}
|
||||||
281
core/asm/compiler.go
Normal file
281
core/asm/compiler.go
Normal file
|
|
@ -0,0 +1,281 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package asm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
|
"github.com/expanse-org/go-expanse/core/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compiler contains information about the parsed source
|
||||||
|
// and holds the tokens for the program.
|
||||||
|
type Compiler struct {
|
||||||
|
tokens []token
|
||||||
|
binary []interface{}
|
||||||
|
|
||||||
|
labels map[string]int
|
||||||
|
|
||||||
|
pc, pos int
|
||||||
|
|
||||||
|
debug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// newCompiler returns a new allocated compiler.
|
||||||
|
func NewCompiler(debug bool) *Compiler {
|
||||||
|
return &Compiler{
|
||||||
|
labels: make(map[string]int),
|
||||||
|
debug: debug,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed feeds tokens in to ch and are interpreted by
|
||||||
|
// the compiler.
|
||||||
|
//
|
||||||
|
// feed is the first pass in the compile stage as it
|
||||||
|
// collect the used labels in the program and keeps a
|
||||||
|
// program counter which is used to determine the locations
|
||||||
|
// of the jump dests. The labels can than be used in the
|
||||||
|
// second stage to push labels and determine the right
|
||||||
|
// position.
|
||||||
|
func (c *Compiler) Feed(ch <-chan token) {
|
||||||
|
for i := range ch {
|
||||||
|
switch i.typ {
|
||||||
|
case number:
|
||||||
|
num := math.MustParseBig256(i.text).Bytes()
|
||||||
|
if len(num) == 0 {
|
||||||
|
num = []byte{0}
|
||||||
|
}
|
||||||
|
c.pc += len(num)
|
||||||
|
case stringValue:
|
||||||
|
c.pc += len(i.text) - 2
|
||||||
|
case element:
|
||||||
|
c.pc++
|
||||||
|
case labelDef:
|
||||||
|
c.labels[i.text] = c.pc
|
||||||
|
c.pc++
|
||||||
|
case label:
|
||||||
|
c.pc += 5
|
||||||
|
}
|
||||||
|
|
||||||
|
c.tokens = append(c.tokens, i)
|
||||||
|
}
|
||||||
|
if c.debug {
|
||||||
|
fmt.Fprintln(os.Stderr, "found", len(c.labels), "labels")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile compiles the current tokens and returns a
|
||||||
|
// binary string that can be interpreted by the EVM
|
||||||
|
// and an error if it failed.
|
||||||
|
//
|
||||||
|
// compile is the second stage in the compile phase
|
||||||
|
// which compiles the tokens to EVM instructions.
|
||||||
|
func (c *Compiler) Compile() (string, []error) {
|
||||||
|
var errors []error
|
||||||
|
// continue looping over the tokens until
|
||||||
|
// the stack has been exhausted.
|
||||||
|
for c.pos < len(c.tokens) {
|
||||||
|
if err := c.compileLine(); err != nil {
|
||||||
|
errors = append(errors, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn the binary to hex
|
||||||
|
var bin string
|
||||||
|
for _, v := range c.binary {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case vm.OpCode:
|
||||||
|
bin += fmt.Sprintf("%x", []byte{byte(v)})
|
||||||
|
case []byte:
|
||||||
|
bin += fmt.Sprintf("%x", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bin, errors
|
||||||
|
}
|
||||||
|
|
||||||
|
// next returns the next token and increments the
|
||||||
|
// posititon.
|
||||||
|
func (c *Compiler) next() token {
|
||||||
|
token := c.tokens[c.pos]
|
||||||
|
c.pos++
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
// compile line compiles a single line instruction e.g.
|
||||||
|
// "push 1", "jump @labal".
|
||||||
|
func (c *Compiler) compileLine() error {
|
||||||
|
n := c.next()
|
||||||
|
if n.typ != lineStart {
|
||||||
|
return compileErr(n, n.typ.String(), lineStart.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
lvalue := c.next()
|
||||||
|
switch lvalue.typ {
|
||||||
|
case eof:
|
||||||
|
return nil
|
||||||
|
case element:
|
||||||
|
if err := c.compileElement(lvalue); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case labelDef:
|
||||||
|
c.compileLabel()
|
||||||
|
case lineEnd:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return compileErr(lvalue, lvalue.text, fmt.Sprintf("%v or %v", labelDef, element))
|
||||||
|
}
|
||||||
|
|
||||||
|
if n := c.next(); n.typ != lineEnd {
|
||||||
|
return compileErr(n, n.text, lineEnd.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// compileNumber compiles the number to bytes
|
||||||
|
func (c *Compiler) compileNumber(element token) (int, error) {
|
||||||
|
num := math.MustParseBig256(element.text).Bytes()
|
||||||
|
if len(num) == 0 {
|
||||||
|
num = []byte{0}
|
||||||
|
}
|
||||||
|
c.pushBin(num)
|
||||||
|
return len(num), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// compileElement compiles the element (push & label or both)
|
||||||
|
// to a binary representation and may error if incorrect statements
|
||||||
|
// where fed.
|
||||||
|
func (c *Compiler) compileElement(element token) error {
|
||||||
|
// check for a jump. jumps must be read and compiled
|
||||||
|
// from right to left.
|
||||||
|
if isJump(element.text) {
|
||||||
|
rvalue := c.next()
|
||||||
|
switch rvalue.typ {
|
||||||
|
case number:
|
||||||
|
// TODO figure out how to return the error properly
|
||||||
|
c.compileNumber(rvalue)
|
||||||
|
case stringValue:
|
||||||
|
// strings are quoted, remove them.
|
||||||
|
c.pushBin(rvalue.text[1 : len(rvalue.text)-2])
|
||||||
|
case label:
|
||||||
|
c.pushBin(vm.PUSH4)
|
||||||
|
pos := big.NewInt(int64(c.labels[rvalue.text])).Bytes()
|
||||||
|
pos = append(make([]byte, 4-len(pos)), pos...)
|
||||||
|
c.pushBin(pos)
|
||||||
|
default:
|
||||||
|
return compileErr(rvalue, rvalue.text, "number, string or label")
|
||||||
|
}
|
||||||
|
// push the operation
|
||||||
|
c.pushBin(toBinary(element.text))
|
||||||
|
return nil
|
||||||
|
} else if isPush(element.text) {
|
||||||
|
// handle pushes. pushes are read from left to right.
|
||||||
|
var value []byte
|
||||||
|
|
||||||
|
rvalue := c.next()
|
||||||
|
switch rvalue.typ {
|
||||||
|
case number:
|
||||||
|
value = math.MustParseBig256(rvalue.text).Bytes()
|
||||||
|
if len(value) == 0 {
|
||||||
|
value = []byte{0}
|
||||||
|
}
|
||||||
|
case stringValue:
|
||||||
|
value = []byte(rvalue.text[1 : len(rvalue.text)-1])
|
||||||
|
case label:
|
||||||
|
value = make([]byte, 4)
|
||||||
|
copy(value, big.NewInt(int64(c.labels[rvalue.text])).Bytes())
|
||||||
|
default:
|
||||||
|
return compileErr(rvalue, rvalue.text, "number, string or label")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(value) > 32 {
|
||||||
|
return fmt.Errorf("%d type error: unsupported string or number with size > 32", rvalue.lineno)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.pushBin(vm.OpCode(int(vm.PUSH1) - 1 + len(value)))
|
||||||
|
c.pushBin(value)
|
||||||
|
} else {
|
||||||
|
c.pushBin(toBinary(element.text))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// compileLabel pushes a jumpdest to the binary slice.
|
||||||
|
func (c *Compiler) compileLabel() {
|
||||||
|
c.pushBin(vm.JUMPDEST)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pushBin pushes the value v to the binary stack.
|
||||||
|
func (c *Compiler) pushBin(v interface{}) {
|
||||||
|
if c.debug {
|
||||||
|
fmt.Printf("%d: %v\n", len(c.binary), v)
|
||||||
|
}
|
||||||
|
c.binary = append(c.binary, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isPush returns whether the string op is either any of
|
||||||
|
// push(N).
|
||||||
|
func isPush(op string) bool {
|
||||||
|
if op == "push" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isJump returns whether the string op is jump(i)
|
||||||
|
func isJump(op string) bool {
|
||||||
|
return op == "jumpi" || op == "jump"
|
||||||
|
}
|
||||||
|
|
||||||
|
// toBinary converts text to a vm.OpCode
|
||||||
|
func toBinary(text string) vm.OpCode {
|
||||||
|
if isPush(text) {
|
||||||
|
text = "push1"
|
||||||
|
}
|
||||||
|
return vm.StringToOp(strings.ToUpper(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
type compileError struct {
|
||||||
|
got string
|
||||||
|
want string
|
||||||
|
|
||||||
|
lineno int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err compileError) Error() string {
|
||||||
|
return fmt.Sprintf("%d syntax error: unexpected %v, expected %v", err.lineno, err.got, err.want)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errExpBol = errors.New("expected beginning of line")
|
||||||
|
errExpElementOrLabel = errors.New("expected beginning of line")
|
||||||
|
)
|
||||||
|
|
||||||
|
func compileErr(c token, got, want string) error {
|
||||||
|
return compileError{
|
||||||
|
got: got,
|
||||||
|
want: want,
|
||||||
|
lineno: c.lineno,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2016 The go-ethereum Authors
|
// Copyright 2017 The go-ethereum Authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -14,13 +14,23 @@
|
||||||
// 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/>.
|
||||||
|
|
||||||
// Contains the wrappers from the math/big package that require Go 1.7 and above.
|
package asm
|
||||||
|
|
||||||
// +build go1.7
|
import "testing"
|
||||||
|
|
||||||
package gexp
|
func lexAll(src string) []token {
|
||||||
|
ch := Lex("test.asm", []byte(src), false)
|
||||||
|
|
||||||
// GetString returns the value of x as a formatted string in some number base.
|
var tokens []token
|
||||||
func (bi *BigInt) GetString(base int) string {
|
for i := range ch {
|
||||||
return bi.bigint.Text(base)
|
tokens = append(tokens, i)
|
||||||
|
}
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComment(t *testing.T) {
|
||||||
|
tokens := lexAll(";; this is a comment")
|
||||||
|
if len(tokens) != 2 { // {new line, EOF}
|
||||||
|
t.Error("expected no tokens")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
291
core/asm/lexer.go
Normal file
291
core/asm/lexer.go
Normal file
|
|
@ -0,0 +1,291 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package asm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// stateFn is used through the lifetime of the
|
||||||
|
// lexer to parse the different values at the
|
||||||
|
// current state.
|
||||||
|
type stateFn func(*lexer) stateFn
|
||||||
|
|
||||||
|
// token is emitted when the lexer has discovered
|
||||||
|
// a new parsable token. These are delivered over
|
||||||
|
// the tokens channels of the lexer
|
||||||
|
type token struct {
|
||||||
|
typ tokenType
|
||||||
|
lineno int
|
||||||
|
text string
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokenType are the different types the lexer
|
||||||
|
// is able to parse and return.
|
||||||
|
type tokenType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
eof tokenType = iota // end of file
|
||||||
|
lineStart // emitted when a line starts
|
||||||
|
lineEnd // emitted when a line ends
|
||||||
|
invalidStatement // any invalid statement
|
||||||
|
element // any element during element parsing
|
||||||
|
label // label is emitted when a labal is found
|
||||||
|
labelDef // label definition is emitted when a new label is found
|
||||||
|
number // number is emitted when a number is found
|
||||||
|
stringValue // stringValue is emitted when a string has been found
|
||||||
|
|
||||||
|
Numbers = "1234567890" // characters representing any decimal number
|
||||||
|
HexadecimalNumbers = Numbers + "aAbBcCdDeEfF" // characters representing any hexadecimal
|
||||||
|
Alpha = "abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ" // characters representing alphanumeric
|
||||||
|
)
|
||||||
|
|
||||||
|
// String implements stringer
|
||||||
|
func (it tokenType) String() string {
|
||||||
|
if int(it) > len(stringtokenTypes) {
|
||||||
|
return "invalid"
|
||||||
|
}
|
||||||
|
return stringtokenTypes[it]
|
||||||
|
}
|
||||||
|
|
||||||
|
var stringtokenTypes = []string{
|
||||||
|
eof: "EOF",
|
||||||
|
invalidStatement: "invalid statement",
|
||||||
|
element: "element",
|
||||||
|
lineEnd: "end of line",
|
||||||
|
lineStart: "new line",
|
||||||
|
label: "label",
|
||||||
|
labelDef: "label definition",
|
||||||
|
number: "number",
|
||||||
|
stringValue: "string",
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexer is the basic construct for parsing
|
||||||
|
// source code and turning them in to tokens.
|
||||||
|
// Tokens are interpreted by the compiler.
|
||||||
|
type lexer struct {
|
||||||
|
input string // input contains the source code of the program
|
||||||
|
|
||||||
|
tokens chan token // tokens is used to deliver tokens to the listener
|
||||||
|
state stateFn // the current state function
|
||||||
|
|
||||||
|
lineno int // current line number in the source file
|
||||||
|
start, pos, width int // positions for lexing and returning value
|
||||||
|
|
||||||
|
debug bool // flag for triggering debug output
|
||||||
|
}
|
||||||
|
|
||||||
|
// lex lexes the program by name with the given source. It returns a
|
||||||
|
// channel on which the tokens are delivered.
|
||||||
|
func Lex(name string, source []byte, debug bool) <-chan token {
|
||||||
|
ch := make(chan token)
|
||||||
|
l := &lexer{
|
||||||
|
input: string(source),
|
||||||
|
tokens: ch,
|
||||||
|
state: lexLine,
|
||||||
|
debug: debug,
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
l.emit(lineStart)
|
||||||
|
for l.state != nil {
|
||||||
|
l.state = l.state(l)
|
||||||
|
}
|
||||||
|
l.emit(eof)
|
||||||
|
close(l.tokens)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// next returns the next rune in the program's source.
|
||||||
|
func (l *lexer) next() (rune rune) {
|
||||||
|
if l.pos >= len(l.input) {
|
||||||
|
l.width = 0
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
|
||||||
|
l.pos += l.width
|
||||||
|
return rune
|
||||||
|
}
|
||||||
|
|
||||||
|
// backup backsup the last parsed element (multi-character)
|
||||||
|
func (l *lexer) backup() {
|
||||||
|
l.pos -= l.width
|
||||||
|
}
|
||||||
|
|
||||||
|
// peek returns the next rune but does not advance the seeker
|
||||||
|
func (l *lexer) peek() rune {
|
||||||
|
r := l.next()
|
||||||
|
l.backup()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore advances the seeker and ignores the value
|
||||||
|
func (l *lexer) ignore() {
|
||||||
|
l.start = l.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accepts checks whether the given input matches the next rune
|
||||||
|
func (l *lexer) accept(valid string) bool {
|
||||||
|
if strings.IndexRune(valid, l.next()) >= 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
l.backup()
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// acceptRun will continue to advance the seeker until valid
|
||||||
|
// can no longer be met.
|
||||||
|
func (l *lexer) acceptRun(valid string) {
|
||||||
|
for strings.IndexRune(valid, l.next()) >= 0 {
|
||||||
|
}
|
||||||
|
l.backup()
|
||||||
|
}
|
||||||
|
|
||||||
|
// acceptRunUntil is the inverse of acceptRun and will continue
|
||||||
|
// to advance the seeker until the rune has been found.
|
||||||
|
func (l *lexer) acceptRunUntil(until rune) bool {
|
||||||
|
// Continues running until a rune is found
|
||||||
|
for i := l.next(); strings.IndexRune(string(until), i) == -1; i = l.next() {
|
||||||
|
if i == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// blob returns the current value
|
||||||
|
func (l *lexer) blob() string {
|
||||||
|
return l.input[l.start:l.pos]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emits a new token on to token channel for processing
|
||||||
|
func (l *lexer) emit(t tokenType) {
|
||||||
|
token := token{t, l.lineno, l.blob()}
|
||||||
|
|
||||||
|
if l.debug {
|
||||||
|
fmt.Fprintf(os.Stderr, "%04d: (%-20v) %s\n", token.lineno, token.typ, token.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.tokens <- token
|
||||||
|
l.start = l.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexLine is state function for lexing lines
|
||||||
|
func lexLine(l *lexer) stateFn {
|
||||||
|
for {
|
||||||
|
switch r := l.next(); {
|
||||||
|
case r == '\n':
|
||||||
|
l.emit(lineEnd)
|
||||||
|
l.ignore()
|
||||||
|
l.lineno++
|
||||||
|
|
||||||
|
l.emit(lineStart)
|
||||||
|
case r == ';' && l.peek() == ';':
|
||||||
|
return lexComment
|
||||||
|
case isSpace(r):
|
||||||
|
l.ignore()
|
||||||
|
case isAlphaNumeric(r) || r == '_':
|
||||||
|
return lexElement
|
||||||
|
case isNumber(r):
|
||||||
|
return lexNumber
|
||||||
|
case r == '@':
|
||||||
|
l.ignore()
|
||||||
|
return lexLabel
|
||||||
|
case r == '"':
|
||||||
|
return lexInsideString
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexComment parses the current position until the end
|
||||||
|
// of the line and discards the text.
|
||||||
|
func lexComment(l *lexer) stateFn {
|
||||||
|
l.acceptRunUntil('\n')
|
||||||
|
l.ignore()
|
||||||
|
|
||||||
|
return lexLine
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexLabel parses the current label, emits and returns
|
||||||
|
// the lex text state function to advance the parsing
|
||||||
|
// process.
|
||||||
|
func lexLabel(l *lexer) stateFn {
|
||||||
|
l.acceptRun(Alpha + "_")
|
||||||
|
|
||||||
|
l.emit(label)
|
||||||
|
|
||||||
|
return lexLine
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexInsideString lexes the inside of a string until
|
||||||
|
// until the state function finds the closing quote.
|
||||||
|
// It returns the lex text state function.
|
||||||
|
func lexInsideString(l *lexer) stateFn {
|
||||||
|
if l.acceptRunUntil('"') {
|
||||||
|
l.emit(stringValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lexLine
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexNumber(l *lexer) stateFn {
|
||||||
|
acceptance := Numbers
|
||||||
|
if l.accept("0") && l.accept("xX") {
|
||||||
|
acceptance = HexadecimalNumbers
|
||||||
|
}
|
||||||
|
l.acceptRun(acceptance)
|
||||||
|
|
||||||
|
l.emit(number)
|
||||||
|
|
||||||
|
return lexLine
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexElement(l *lexer) stateFn {
|
||||||
|
l.acceptRun(Alpha + "_" + Numbers)
|
||||||
|
|
||||||
|
if l.peek() == ':' {
|
||||||
|
l.emit(labelDef)
|
||||||
|
|
||||||
|
l.accept(":")
|
||||||
|
l.ignore()
|
||||||
|
} else {
|
||||||
|
l.emit(element)
|
||||||
|
}
|
||||||
|
return lexLine
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAlphaNumeric(t rune) bool {
|
||||||
|
return unicode.IsLetter(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSpace(t rune) bool {
|
||||||
|
return unicode.IsSpace(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNumber(t rune) bool {
|
||||||
|
return unicode.IsNumber(t)
|
||||||
|
}
|
||||||
|
|
@ -24,12 +24,14 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/core/vm"
|
"github.com/expanse-org/go-expanse/core/vm"
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/event"
|
"github.com/expanse-org/go-expanse/event"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkInsertChain_empty_memdb(b *testing.B) {
|
func BenchmarkInsertChain_empty_memdb(b *testing.B) {
|
||||||
|
|
@ -73,7 +75,7 @@ var (
|
||||||
// This is the content of the genesis block used by the benchmarks.
|
// This is the content of the genesis block used by the benchmarks.
|
||||||
benchRootKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
benchRootKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
benchRootAddr = crypto.PubkeyToAddress(benchRootKey.PublicKey)
|
benchRootAddr = crypto.PubkeyToAddress(benchRootKey.PublicKey)
|
||||||
benchRootFunds = common.BigPow(2, 100)
|
benchRootFunds = math.BigPow(2, 100)
|
||||||
)
|
)
|
||||||
|
|
||||||
// genValueTx returns a block generator that includes a single
|
// genValueTx returns a block generator that includes a single
|
||||||
|
|
@ -164,13 +166,17 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
||||||
|
|
||||||
// Generate a chain of b.N blocks using the supplied block
|
// Generate a chain of b.N blocks using the supplied block
|
||||||
// generator function.
|
// generator function.
|
||||||
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds})
|
gspec := Genesis{
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, b.N, gen)
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: GenesisAlloc{benchRootAddr: {Balance: benchRootFunds}},
|
||||||
|
}
|
||||||
|
genesis := gspec.MustCommit(db)
|
||||||
|
chain, _ := GenerateChain(gspec.Config, genesis, db, b.N, gen)
|
||||||
|
|
||||||
// Time the insertion of the new chain.
|
// Time the insertion of the new chain.
|
||||||
// State and blocks are stored in the same DB.
|
// State and blocks are stored in the same DB.
|
||||||
evmux := new(event.TypeMux)
|
evmux := new(event.TypeMux)
|
||||||
chainman, _ := NewBlockChain(db, ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, FakePow{}, evmux, vm.Config{})
|
chainman, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
|
||||||
defer chainman.Stop()
|
defer chainman.Stop()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
@ -280,7 +286,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{})
|
chain, err := NewBlockChain(db, params.TestChainConfig, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error creating chain: %v", err)
|
b.Fatalf("error creating chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
"github.com/expanse-org/go-expanse/core/state"
|
"github.com/expanse-org/go-expanse/core/state"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
"github.com/expanse-org/go-expanse/pow"
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
"gopkg.in/fatih/set.v0"
|
"gopkg.in/fatih/set.v0"
|
||||||
|
|
@ -170,7 +171,7 @@ func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error {
|
||||||
for h := range ancestors {
|
for h := range ancestors {
|
||||||
branch += fmt.Sprintf(" O - %x\n |\n", h)
|
branch += fmt.Sprintf(" O - %x\n |\n", h)
|
||||||
}
|
}
|
||||||
glog.Infoln(branch)
|
log.Warn(branch)
|
||||||
return UncleError("uncle[%d](%x) is ancestor", i, hash[:4])
|
return UncleError("uncle[%d](%x) is ancestor", i, hash[:4])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,7 +211,7 @@ func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Heade
|
||||||
}
|
}
|
||||||
|
|
||||||
if uncle {
|
if uncle {
|
||||||
if header.Time.Cmp(common.MaxBig) == 1 {
|
if header.Time.Cmp(math.MaxBig256) == 1 {
|
||||||
return BlockTSTooBigErr
|
return BlockTSTooBigErr
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -244,7 +245,7 @@ func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Heade
|
||||||
|
|
||||||
if checkPow {
|
if checkPow {
|
||||||
// Verify the nonce of the header. Return an error if it's not valid
|
// Verify the nonce of the header. Return an error if it's not valid
|
||||||
if !pow.Verify(types.NewBlockWithHeader(header)) {
|
if err := pow.Verify(types.NewBlockWithHeader(header)); err != nil {
|
||||||
return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()}
|
return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -340,7 +341,7 @@ func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *b
|
||||||
expDiff := periodCount.Sub(periodCount, common.Big2)
|
expDiff := periodCount.Sub(periodCount, common.Big2)
|
||||||
expDiff.Exp(common.Big2, expDiff, nil)
|
expDiff.Exp(common.Big2, expDiff, nil)
|
||||||
diff.Add(diff, expDiff)
|
diff.Add(diff, expDiff)
|
||||||
diff = common.BigMax(diff, params.MinimumDifficulty)
|
diff = math.BigMax(diff, params.MinimumDifficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff
|
return diff
|
||||||
|
|
@ -368,13 +369,13 @@ func CalcGasLimit(parent *types.Block) *big.Int {
|
||||||
*/
|
*/
|
||||||
gl := new(big.Int).Sub(parent.GasLimit(), decay)
|
gl := new(big.Int).Sub(parent.GasLimit(), decay)
|
||||||
gl = gl.Add(gl, contrib)
|
gl = gl.Add(gl, contrib)
|
||||||
gl.Set(common.BigMax(gl, params.MinGasLimit))
|
gl.Set(math.BigMax(gl, params.MinGasLimit))
|
||||||
|
|
||||||
// however, if we're now below the target (TargetGasLimit) we increase the
|
// however, if we're now below the target (TargetGasLimit) we increase the
|
||||||
// limit as much as we can (parentGasLimit / 1024 -1)
|
// limit as much as we can (parentGasLimit / 1024 -1)
|
||||||
if gl.Cmp(params.TargetGasLimit) < 0 {
|
if gl.Cmp(params.TargetGasLimit) < 0 {
|
||||||
gl.Add(parent.GasLimit(), decay)
|
gl.Add(parent.GasLimit(), decay)
|
||||||
gl.Set(common.BigMin(gl, params.TargetGasLimit))
|
gl.Set(math.BigMin(gl, params.TargetGasLimit))
|
||||||
}
|
}
|
||||||
return gl
|
return gl
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,50 +17,36 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
"github.com/expanse-org/go-expanse/core/state"
|
"github.com/expanse-org/go-expanse/core/state"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/core/vm"
|
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/event"
|
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testChainConfig() *params.ChainConfig {
|
func testGenesis(account common.Address, balance *big.Int) *Genesis {
|
||||||
return params.TestChainConfig
|
return &Genesis{
|
||||||
//return ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)}
|
Config: params.TestChainConfig,
|
||||||
}
|
Alloc: GenesisAlloc{account: {Balance: balance}},
|
||||||
|
|
||||||
func proc() (Validator, *BlockChain) {
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
var mux event.TypeMux
|
|
||||||
|
|
||||||
WriteTestNetGenesisBlock(db)
|
|
||||||
blockchain, err := NewBlockChain(db, testChainConfig(), thePow(), &mux, vm.Config{})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
}
|
||||||
return blockchain.validator, blockchain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNumber(t *testing.T) {
|
func TestNumber(t *testing.T) {
|
||||||
_, chain := proc()
|
chain := newTestBlockChain()
|
||||||
|
|
||||||
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
|
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
|
||||||
cfg := testChainConfig()
|
header := makeHeader(chain.config, chain.Genesis(), statedb)
|
||||||
header := makeHeader(cfg, chain.Genesis(), statedb)
|
|
||||||
header.Number = big.NewInt(3)
|
header.Number = big.NewInt(3)
|
||||||
err := ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false)
|
err := ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
|
||||||
if err != BlockNumberErr {
|
if err != BlockNumberErr {
|
||||||
t.Errorf("expected block number error, got %q", err)
|
t.Errorf("expected block number error, got %q", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
header = makeHeader(cfg, chain.Genesis(), statedb)
|
header = makeHeader(chain.config, chain.Genesis(), statedb)
|
||||||
err = ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false)
|
err = ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
|
||||||
if err == BlockNumberErr {
|
if err == BlockNumberErr {
|
||||||
t.Errorf("didn't expect block number error")
|
t.Errorf("didn't expect block number error")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/event"
|
"github.com/expanse-org/go-expanse/event"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/metrics"
|
"github.com/expanse-org/go-expanse/metrics"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
"github.com/expanse-org/go-expanse/pow"
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
|
|
@ -161,9 +160,9 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.P
|
||||||
headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64())
|
headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64())
|
||||||
// make sure the headerByNumber (if present) is in our current canonical chain
|
// make sure the headerByNumber (if present) is in our current canonical chain
|
||||||
if headerByNumber != nil && headerByNumber.Hash() == header.Hash() {
|
if headerByNumber != nil && headerByNumber.Hash() == header.Hash() {
|
||||||
glog.V(logger.Error).Infof("Found bad hash, rewinding chain to block #%d [%x…]", header.Number, header.ParentHash[:4])
|
log.Error("Found bad hash, rewinding chain", "number", header.Number, "hash", header.ParentHash)
|
||||||
bc.SetHead(header.Number.Uint64() - 1)
|
bc.SetHead(header.Number.Uint64() - 1)
|
||||||
glog.V(logger.Error).Infoln("Chain rewind was successful, resuming normal operation")
|
log.Error("Chain rewind was successful, resuming normal operation")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -183,16 +182,25 @@ func (self *BlockChain) loadLastState() error {
|
||||||
head := GetHeadBlockHash(self.chainDb)
|
head := GetHeadBlockHash(self.chainDb)
|
||||||
if head == (common.Hash{}) {
|
if head == (common.Hash{}) {
|
||||||
// Corrupt or empty database, init from scratch
|
// Corrupt or empty database, init from scratch
|
||||||
self.Reset()
|
log.Warn("Empty database, resetting chain")
|
||||||
} else {
|
return self.Reset()
|
||||||
if block := self.GetBlockByHash(head); block != nil {
|
|
||||||
// Block found, set as the current head
|
|
||||||
self.currentBlock = block
|
|
||||||
} else {
|
|
||||||
// Corrupt or empty database, init from scratch
|
|
||||||
self.Reset()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Make sure the entire head block is available
|
||||||
|
currentBlock := self.GetBlockByHash(head)
|
||||||
|
if currentBlock == nil {
|
||||||
|
// Corrupt or empty database, init from scratch
|
||||||
|
log.Warn("Head block missing, resetting chain", "hash", head)
|
||||||
|
return self.Reset()
|
||||||
|
}
|
||||||
|
// Make sure the state associated with the block is available
|
||||||
|
if _, err := state.New(currentBlock.Root(), self.chainDb); err != nil {
|
||||||
|
// Dangling block without a state associated, init from scratch
|
||||||
|
log.Warn("Head state missing, resetting chain", "number", currentBlock.Number(), "hash", currentBlock.Hash())
|
||||||
|
return self.Reset()
|
||||||
|
}
|
||||||
|
// Everything seems to be fine, set as the head block
|
||||||
|
self.currentBlock = currentBlock
|
||||||
|
|
||||||
// Restore the last known head header
|
// Restore the last known head header
|
||||||
currentHeader := self.currentBlock.Header()
|
currentHeader := self.currentBlock.Header()
|
||||||
if head := GetHeadHeaderHash(self.chainDb); head != (common.Hash{}) {
|
if head := GetHeadHeaderHash(self.chainDb); head != (common.Hash{}) {
|
||||||
|
|
@ -201,6 +209,7 @@ func (self *BlockChain) loadLastState() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.hc.SetCurrentHeader(currentHeader)
|
self.hc.SetCurrentHeader(currentHeader)
|
||||||
|
|
||||||
// Restore the last known head fast block
|
// Restore the last known head fast block
|
||||||
self.currentFastBlock = self.currentBlock
|
self.currentFastBlock = self.currentBlock
|
||||||
if head := GetHeadFastBlockHash(self.chainDb); head != (common.Hash{}) {
|
if head := GetHeadFastBlockHash(self.chainDb); head != (common.Hash{}) {
|
||||||
|
|
@ -214,16 +223,18 @@ func (self *BlockChain) loadLastState() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
self.stateCache = statedb
|
self.stateCache = statedb
|
||||||
self.stateCache.GetAccount(common.Address{})
|
|
||||||
|
|
||||||
// Issue a status log for the user
|
// Issue a status log for the user
|
||||||
headerTd := self.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64())
|
headerTd := self.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64())
|
||||||
blockTd := self.GetTd(self.currentBlock.Hash(), self.currentBlock.NumberU64())
|
blockTd := self.GetTd(self.currentBlock.Hash(), self.currentBlock.NumberU64())
|
||||||
fastTd := self.GetTd(self.currentFastBlock.Hash(), self.currentFastBlock.NumberU64())
|
fastTd := self.GetTd(self.currentFastBlock.Hash(), self.currentFastBlock.NumberU64())
|
||||||
|
|
||||||
glog.V(logger.Info).Infof("Last header: #%d [%x…] TD=%v", currentHeader.Number, currentHeader.Hash().Bytes()[:4], headerTd)
|
log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd)
|
||||||
glog.V(logger.Info).Infof("Last block: #%d [%x…] TD=%v", self.currentBlock.Number(), self.currentBlock.Hash().Bytes()[:4], blockTd)
|
log.Info("Loaded most recent local full block", "number", self.currentBlock.Number(), "hash", self.currentBlock.Hash(), "td", blockTd)
|
||||||
glog.V(logger.Info).Infof("Fast block: #%d [%x…] TD=%v", self.currentFastBlock.Number(), self.currentFastBlock.Hash().Bytes()[:4], fastTd)
|
log.Info("Loaded most recent local fast block", "number", self.currentFastBlock.Number(), "hash", self.currentFastBlock.Hash(), "td", fastTd)
|
||||||
|
|
||||||
|
// Try to be smart and issue a pow verification for the head to pre-generate caches
|
||||||
|
go self.pow.Verify(types.NewBlockWithHeader(currentHeader))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -232,14 +243,18 @@ func (self *BlockChain) loadLastState() error {
|
||||||
// above the new head will be deleted and the new one set. In the case of blocks
|
// above the new head will be deleted and the new one set. In the case of blocks
|
||||||
// though, the head may be further rewound if block bodies are missing (non-archive
|
// though, the head may be further rewound if block bodies are missing (non-archive
|
||||||
// nodes after a fast sync).
|
// nodes after a fast sync).
|
||||||
func (bc *BlockChain) SetHead(head uint64) {
|
func (bc *BlockChain) SetHead(head uint64) error {
|
||||||
|
log.Warn("Rewinding blockchain", "target", head)
|
||||||
|
|
||||||
bc.mu.Lock()
|
bc.mu.Lock()
|
||||||
defer bc.mu.Unlock()
|
defer bc.mu.Unlock()
|
||||||
|
|
||||||
|
// Rewind the header chain, deleting all block bodies until then
|
||||||
delFn := func(hash common.Hash, num uint64) {
|
delFn := func(hash common.Hash, num uint64) {
|
||||||
DeleteBody(bc.chainDb, hash, num)
|
DeleteBody(bc.chainDb, hash, num)
|
||||||
}
|
}
|
||||||
bc.hc.SetHead(head, delFn)
|
bc.hc.SetHead(head, delFn)
|
||||||
|
currentHeader := bc.hc.CurrentHeader()
|
||||||
|
|
||||||
// Clear out any stale content from the caches
|
// Clear out any stale content from the caches
|
||||||
bc.bodyCache.Purge()
|
bc.bodyCache.Purge()
|
||||||
|
|
@ -247,29 +262,34 @@ func (bc *BlockChain) SetHead(head uint64) {
|
||||||
bc.blockCache.Purge()
|
bc.blockCache.Purge()
|
||||||
bc.futureBlocks.Purge()
|
bc.futureBlocks.Purge()
|
||||||
|
|
||||||
// Update all computed fields to the new head
|
// Rewind the block chain, ensuring we don't end up with a stateless head block
|
||||||
currentHeader := bc.hc.CurrentHeader()
|
|
||||||
if bc.currentBlock != nil && currentHeader.Number.Uint64() < bc.currentBlock.NumberU64() {
|
if bc.currentBlock != nil && currentHeader.Number.Uint64() < bc.currentBlock.NumberU64() {
|
||||||
bc.currentBlock = bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())
|
bc.currentBlock = bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())
|
||||||
}
|
}
|
||||||
|
if bc.currentBlock != nil {
|
||||||
|
if _, err := state.New(bc.currentBlock.Root(), bc.chainDb); err != nil {
|
||||||
|
// Rewound state missing, rolled back to before pivot, reset to genesis
|
||||||
|
bc.currentBlock = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Rewind the fast block in a simpleton way to the target head
|
||||||
if bc.currentFastBlock != nil && currentHeader.Number.Uint64() < bc.currentFastBlock.NumberU64() {
|
if bc.currentFastBlock != nil && currentHeader.Number.Uint64() < bc.currentFastBlock.NumberU64() {
|
||||||
bc.currentFastBlock = bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())
|
bc.currentFastBlock = bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())
|
||||||
}
|
}
|
||||||
|
// If either blocks reached nil, reset to the genesis state
|
||||||
if bc.currentBlock == nil {
|
if bc.currentBlock == nil {
|
||||||
bc.currentBlock = bc.genesisBlock
|
bc.currentBlock = bc.genesisBlock
|
||||||
}
|
}
|
||||||
if bc.currentFastBlock == nil {
|
if bc.currentFastBlock == nil {
|
||||||
bc.currentFastBlock = bc.genesisBlock
|
bc.currentFastBlock = bc.genesisBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := WriteHeadBlockHash(bc.chainDb, bc.currentBlock.Hash()); err != nil {
|
if err := WriteHeadBlockHash(bc.chainDb, bc.currentBlock.Hash()); err != nil {
|
||||||
glog.Fatalf("failed to reset head block hash: %v", err)
|
log.Crit("Failed to reset head full block", "err", err)
|
||||||
}
|
}
|
||||||
if err := WriteHeadFastBlockHash(bc.chainDb, bc.currentFastBlock.Hash()); err != nil {
|
if err := WriteHeadFastBlockHash(bc.chainDb, bc.currentFastBlock.Hash()); err != nil {
|
||||||
glog.Fatalf("failed to reset head fast block hash: %v", err)
|
log.Crit("Failed to reset head fast block", "err", err)
|
||||||
}
|
}
|
||||||
bc.loadLastState()
|
return bc.loadLastState()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FastSyncCommitHead sets the current head block to the one defined by the hash
|
// FastSyncCommitHead sets the current head block to the one defined by the hash
|
||||||
|
|
@ -288,7 +308,7 @@ func (self *BlockChain) FastSyncCommitHead(hash common.Hash) error {
|
||||||
self.currentBlock = block
|
self.currentBlock = block
|
||||||
self.mu.Unlock()
|
self.mu.Unlock()
|
||||||
|
|
||||||
glog.V(logger.Info).Infof("committed block #%d [%x…] as new head", block.Number(), hash[:4])
|
log.Info("Committed new head block", "number", block.Number(), "hash", hash)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -377,25 +397,26 @@ func (self *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset purges the entire blockchain, restoring it to its genesis state.
|
// Reset purges the entire blockchain, restoring it to its genesis state.
|
||||||
func (bc *BlockChain) Reset() {
|
func (bc *BlockChain) Reset() error {
|
||||||
bc.ResetWithGenesisBlock(bc.genesisBlock)
|
return bc.ResetWithGenesisBlock(bc.genesisBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetWithGenesisBlock purges the entire blockchain, restoring it to the
|
// ResetWithGenesisBlock purges the entire blockchain, restoring it to the
|
||||||
// specified genesis state.
|
// specified genesis state.
|
||||||
func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) {
|
func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
|
||||||
// Dump the entire block chain and purge the caches
|
// Dump the entire block chain and purge the caches
|
||||||
bc.SetHead(0)
|
if err := bc.SetHead(0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
bc.mu.Lock()
|
bc.mu.Lock()
|
||||||
defer bc.mu.Unlock()
|
defer bc.mu.Unlock()
|
||||||
|
|
||||||
// Prepare the genesis block and reinitialise the chain
|
// Prepare the genesis block and reinitialise the chain
|
||||||
if err := bc.hc.WriteTd(genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil {
|
if err := bc.hc.WriteTd(genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil {
|
||||||
glog.Fatalf("failed to write genesis block TD: %v", err)
|
log.Crit("Failed to write genesis block TD", "err", err)
|
||||||
}
|
}
|
||||||
if err := WriteBlock(bc.chainDb, genesis); err != nil {
|
if err := WriteBlock(bc.chainDb, genesis); err != nil {
|
||||||
glog.Fatalf("failed to write genesis block: %v", err)
|
log.Crit("Failed to write genesis block", "err", err)
|
||||||
}
|
}
|
||||||
bc.genesisBlock = genesis
|
bc.genesisBlock = genesis
|
||||||
bc.insert(bc.genesisBlock)
|
bc.insert(bc.genesisBlock)
|
||||||
|
|
@ -403,6 +424,8 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) {
|
||||||
bc.hc.SetGenesis(bc.genesisBlock.Header())
|
bc.hc.SetGenesis(bc.genesisBlock.Header())
|
||||||
bc.hc.SetCurrentHeader(bc.genesisBlock.Header())
|
bc.hc.SetCurrentHeader(bc.genesisBlock.Header())
|
||||||
bc.currentFastBlock = bc.genesisBlock
|
bc.currentFastBlock = bc.genesisBlock
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export writes the active chain to the given writer.
|
// Export writes the active chain to the given writer.
|
||||||
|
|
@ -418,8 +441,7 @@ func (self *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error {
|
||||||
if first > last {
|
if first > last {
|
||||||
return fmt.Errorf("export failed: first (%d) is greater than last (%d)", first, last)
|
return fmt.Errorf("export failed: first (%d) is greater than last (%d)", first, last)
|
||||||
}
|
}
|
||||||
|
log.Info("Exporting batch of blocks", "count", last-first+1)
|
||||||
glog.V(logger.Info).Infof("exporting %d blocks...\n", last-first+1)
|
|
||||||
|
|
||||||
for nr := first; nr <= last; nr++ {
|
for nr := first; nr <= last; nr++ {
|
||||||
block := self.GetBlockByNumber(nr)
|
block := self.GetBlockByNumber(nr)
|
||||||
|
|
@ -447,10 +469,10 @@ func (bc *BlockChain) insert(block *types.Block) {
|
||||||
|
|
||||||
// Add the block to the canonical chain number scheme and mark as the head
|
// Add the block to the canonical chain number scheme and mark as the head
|
||||||
if err := WriteCanonicalHash(bc.chainDb, block.Hash(), block.NumberU64()); err != nil {
|
if err := WriteCanonicalHash(bc.chainDb, block.Hash(), block.NumberU64()); err != nil {
|
||||||
glog.Fatalf("failed to insert block number: %v", err)
|
log.Crit("Failed to insert block number", "err", err)
|
||||||
}
|
}
|
||||||
if err := WriteHeadBlockHash(bc.chainDb, block.Hash()); err != nil {
|
if err := WriteHeadBlockHash(bc.chainDb, block.Hash()); err != nil {
|
||||||
glog.Fatalf("failed to insert head block hash: %v", err)
|
log.Crit("Failed to insert head block hash", "err", err)
|
||||||
}
|
}
|
||||||
bc.currentBlock = block
|
bc.currentBlock = block
|
||||||
|
|
||||||
|
|
@ -459,7 +481,7 @@ func (bc *BlockChain) insert(block *types.Block) {
|
||||||
bc.hc.SetCurrentHeader(block.Header())
|
bc.hc.SetCurrentHeader(block.Header())
|
||||||
|
|
||||||
if err := WriteHeadFastBlockHash(bc.chainDb, block.Hash()); err != nil {
|
if err := WriteHeadFastBlockHash(bc.chainDb, block.Hash()); err != nil {
|
||||||
glog.Fatalf("failed to insert head fast block hash: %v", err)
|
log.Crit("Failed to insert head fast block hash", "err", err)
|
||||||
}
|
}
|
||||||
bc.currentFastBlock = block
|
bc.currentFastBlock = block
|
||||||
}
|
}
|
||||||
|
|
@ -590,8 +612,7 @@ func (bc *BlockChain) Stop() {
|
||||||
atomic.StoreInt32(&bc.procInterrupt, 1)
|
atomic.StoreInt32(&bc.procInterrupt, 1)
|
||||||
|
|
||||||
bc.wg.Wait()
|
bc.wg.Wait()
|
||||||
|
log.Info("Blockchain manager stopped")
|
||||||
glog.V(logger.Info).Infoln("Chain manager stopped")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BlockChain) procFutureBlocks() {
|
func (self *BlockChain) procFutureBlocks() {
|
||||||
|
|
@ -685,11 +706,11 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
|
||||||
for i := 1; i < len(blockChain); i++ {
|
for i := 1; i < len(blockChain); i++ {
|
||||||
if blockChain[i].NumberU64() != blockChain[i-1].NumberU64()+1 || blockChain[i].ParentHash() != blockChain[i-1].Hash() {
|
if blockChain[i].NumberU64() != blockChain[i-1].NumberU64()+1 || blockChain[i].ParentHash() != blockChain[i-1].Hash() {
|
||||||
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
||||||
failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, blockChain[i-1].NumberU64(),
|
log.Error("Non contiguous receipt insert", "number", blockChain[i].Number(), "hash", blockChain[i].Hash(), "parent", blockChain[i].ParentHash(),
|
||||||
blockChain[i-1].Hash().Bytes()[:4], i, blockChain[i].NumberU64(), blockChain[i].Hash().Bytes()[:4], blockChain[i].ParentHash().Bytes()[:4])
|
"prevnumber", blockChain[i-1].Number(), "prevhash", blockChain[i-1].Hash())
|
||||||
|
|
||||||
glog.V(logger.Error).Info(failure.Error())
|
return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, blockChain[i-1].NumberU64(),
|
||||||
return 0, failure
|
blockChain[i-1].Hash().Bytes()[:4], i, blockChain[i].NumberU64(), blockChain[i].Hash().Bytes()[:4], blockChain[i].ParentHash().Bytes()[:4])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Pre-checks passed, start the block body and receipt imports
|
// Pre-checks passed, start the block body and receipt imports
|
||||||
|
|
@ -736,31 +757,31 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
|
||||||
if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
||||||
errs[index] = fmt.Errorf("failed to write block body: %v", err)
|
errs[index] = fmt.Errorf("failed to write block body: %v", err)
|
||||||
atomic.AddInt32(&failed, 1)
|
atomic.AddInt32(&failed, 1)
|
||||||
glog.Fatal(errs[index])
|
log.Crit("Failed to write block body", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := WriteBlockReceipts(self.chainDb, block.Hash(), block.NumberU64(), receipts); err != nil {
|
if err := WriteBlockReceipts(self.chainDb, block.Hash(), block.NumberU64(), receipts); err != nil {
|
||||||
errs[index] = fmt.Errorf("failed to write block receipts: %v", err)
|
errs[index] = fmt.Errorf("failed to write block receipts: %v", err)
|
||||||
atomic.AddInt32(&failed, 1)
|
atomic.AddInt32(&failed, 1)
|
||||||
glog.Fatal(errs[index])
|
log.Crit("Failed to write block receipts", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil {
|
if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil {
|
||||||
errs[index] = fmt.Errorf("failed to write log blooms: %v", err)
|
errs[index] = fmt.Errorf("failed to write log blooms: %v", err)
|
||||||
atomic.AddInt32(&failed, 1)
|
atomic.AddInt32(&failed, 1)
|
||||||
glog.Fatal(errs[index])
|
log.Crit("Failed to write log blooms", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := WriteTransactions(self.chainDb, block); err != nil {
|
if err := WriteTransactions(self.chainDb, block); err != nil {
|
||||||
errs[index] = fmt.Errorf("failed to write individual transactions: %v", err)
|
errs[index] = fmt.Errorf("failed to write individual transactions: %v", err)
|
||||||
atomic.AddInt32(&failed, 1)
|
atomic.AddInt32(&failed, 1)
|
||||||
glog.Fatal(errs[index])
|
log.Crit("Failed to write individual transactions", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := WriteReceipts(self.chainDb, receipts); err != nil {
|
if err := WriteReceipts(self.chainDb, receipts); err != nil {
|
||||||
errs[index] = fmt.Errorf("failed to write individual receipts: %v", err)
|
errs[index] = fmt.Errorf("failed to write individual receipts: %v", err)
|
||||||
atomic.AddInt32(&failed, 1)
|
atomic.AddInt32(&failed, 1)
|
||||||
glog.Fatal(errs[index])
|
log.Crit("Failed to write individual receipts", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
atomic.AddInt32(&stats.processed, 1)
|
atomic.AddInt32(&stats.processed, 1)
|
||||||
|
|
@ -786,28 +807,27 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if atomic.LoadInt32(&self.procInterrupt) == 1 {
|
if atomic.LoadInt32(&self.procInterrupt) == 1 {
|
||||||
glog.V(logger.Debug).Infoln("premature abort during receipt chain processing")
|
log.Debug("Premature abort during receipts processing")
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
// Update the head fast sync block if better
|
// Update the head fast sync block if better
|
||||||
self.mu.Lock()
|
self.mu.Lock()
|
||||||
|
|
||||||
head := blockChain[len(errs)-1]
|
head := blockChain[len(errs)-1]
|
||||||
if self.GetTd(self.currentFastBlock.Hash(), self.currentFastBlock.NumberU64()).Cmp(self.GetTd(head.Hash(), head.NumberU64())) < 0 {
|
if td := self.GetTd(head.Hash(), head.NumberU64()); td != nil { // Rewind may have occurred, skip in that case
|
||||||
if err := WriteHeadFastBlockHash(self.chainDb, head.Hash()); err != nil {
|
if self.GetTd(self.currentFastBlock.Hash(), self.currentFastBlock.NumberU64()).Cmp(td) < 0 {
|
||||||
glog.Fatalf("failed to update head fast block hash: %v", err)
|
if err := WriteHeadFastBlockHash(self.chainDb, head.Hash()); err != nil {
|
||||||
|
log.Crit("Failed to update head fast block hash", "err", err)
|
||||||
|
}
|
||||||
|
self.currentFastBlock = head
|
||||||
}
|
}
|
||||||
self.currentFastBlock = head
|
|
||||||
}
|
}
|
||||||
self.mu.Unlock()
|
self.mu.Unlock()
|
||||||
|
|
||||||
// Report some public statistics so the user has a clue what's going on
|
// Report some public statistics so the user has a clue what's going on
|
||||||
first, last := blockChain[0], blockChain[len(blockChain)-1]
|
last := blockChain[len(blockChain)-1]
|
||||||
|
log.Info("Imported new block receipts", "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)),
|
||||||
ignored := ""
|
"number", last.Number(), "hash", last.Hash(), "ignored", stats.ignored)
|
||||||
if stats.ignored > 0 {
|
|
||||||
ignored = fmt.Sprintf(" (%d ignored)", stats.ignored)
|
|
||||||
}
|
|
||||||
glog.V(logger.Info).Infof("imported %4d receipts in %9v. #%d [%x… / %x…]%s", stats.processed, common.PrettyDuration(time.Since(start)), last.Number(), first.Hash().Bytes()[:4], last.Hash().Bytes()[:4], ignored)
|
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
@ -831,10 +851,10 @@ func (self *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err
|
||||||
|
|
||||||
// Irrelevant of the canonical status, write the block itself to the database
|
// Irrelevant of the canonical status, write the block itself to the database
|
||||||
if err := self.hc.WriteTd(block.Hash(), block.NumberU64(), externTd); err != nil {
|
if err := self.hc.WriteTd(block.Hash(), block.NumberU64(), externTd); err != nil {
|
||||||
glog.Fatalf("failed to write block total difficulty: %v", err)
|
log.Crit("Failed to write block total difficulty", "err", err)
|
||||||
}
|
}
|
||||||
if err := WriteBlock(self.chainDb, block); err != nil {
|
if err := WriteBlock(self.chainDb, block); err != nil {
|
||||||
glog.Fatalf("failed to write block contents: %v", err)
|
log.Crit("Failed to write block contents", "err", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the total difficulty is higher than our known, add it to the canonical chain
|
// If the total difficulty is higher than our known, add it to the canonical chain
|
||||||
|
|
@ -865,11 +885,11 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
for i := 1; i < len(chain); i++ {
|
for i := 1; i < len(chain); i++ {
|
||||||
if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() {
|
if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() {
|
||||||
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
||||||
failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])",
|
log.Error("Non contiguous block insert", "number", chain[i].Number(), "hash", chain[i].Hash(),
|
||||||
i-1, chain[i-1].NumberU64(), chain[i-1].Hash().Bytes()[:4], i, chain[i].NumberU64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash().Bytes()[:4])
|
"parent", chain[i].ParentHash(), "prevnumber", chain[i-1].Number(), "prevhash", chain[i-1].Hash())
|
||||||
|
|
||||||
glog.V(logger.Error).Info(failure.Error())
|
return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].NumberU64(),
|
||||||
return 0, failure
|
chain[i-1].Hash().Bytes()[:4], i, chain[i].NumberU64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash().Bytes()[:4])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Pre-checks passed, start the full block imports
|
// Pre-checks passed, start the full block imports
|
||||||
|
|
@ -895,7 +915,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
|
|
||||||
for i, block := range chain {
|
for i, block := range chain {
|
||||||
if atomic.LoadInt32(&self.procInterrupt) == 1 {
|
if atomic.LoadInt32(&self.procInterrupt) == 1 {
|
||||||
glog.V(logger.Debug).Infoln("Premature abort during block chain processing")
|
log.Debug("Premature abort during blocks processing")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
bstart := time.Now()
|
bstart := time.Now()
|
||||||
|
|
@ -905,8 +925,8 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
r := <-nonceResults
|
r := <-nonceResults
|
||||||
nonceChecked[r.index] = true
|
nonceChecked[r.index] = true
|
||||||
if !r.valid {
|
if !r.valid {
|
||||||
block := chain[r.index]
|
invalid := chain[r.index]
|
||||||
return r.index, &BlockNonceErr{Hash: block.Hash(), Number: block.Number(), Nonce: block.Nonce()}
|
return r.index, &BlockNonceErr{Hash: invalid.Hash(), Number: invalid.Number(), Nonce: invalid.Nonce()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -980,7 +1000,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
// coalesce logs for later processing
|
// coalesce logs for later processing
|
||||||
coalescedLogs = append(coalescedLogs, logs...)
|
coalescedLogs = append(coalescedLogs, logs...)
|
||||||
|
|
||||||
if err := WriteBlockReceipts(self.chainDb, block.Hash(), block.NumberU64(), receipts); err != nil {
|
if err = WriteBlockReceipts(self.chainDb, block.Hash(), block.NumberU64(), receipts); err != nil {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -992,9 +1012,9 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
case CanonStatTy:
|
case CanonStatTy:
|
||||||
if glog.V(logger.Debug) {
|
log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), "uncles", len(block.Uncles()),
|
||||||
glog.Infof("inserted block #%d [%x…] in %9v: %3d txs %7v gas %d uncles.", block.Number(), block.Hash().Bytes()[0:4], common.PrettyDuration(time.Since(bstart)), len(block.Transactions()), block.GasUsed(), len(block.Uncles()))
|
"txs", len(block.Transactions()), "gas", block.GasUsed(), "elapsed", common.PrettyDuration(time.Since(bstart)))
|
||||||
}
|
|
||||||
blockInsertTimer.UpdateSince(bstart)
|
blockInsertTimer.UpdateSince(bstart)
|
||||||
events = append(events, ChainEvent{block, block.Hash(), logs})
|
events = append(events, ChainEvent{block, block.Hash(), logs})
|
||||||
|
|
||||||
|
|
@ -1015,23 +1035,19 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
case SideStatTy:
|
case SideStatTy:
|
||||||
if glog.V(logger.Detail) {
|
log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), "diff", block.Difficulty(), "elapsed",
|
||||||
glog.Infof("inserted forked block #%d [%x…] (TD=%v) in %9v: %3d txs %d uncles.", block.Number(), block.Hash().Bytes()[0:4], block.Difficulty(), common.PrettyDuration(time.Since(bstart)), len(block.Transactions()), len(block.Uncles()))
|
common.PrettyDuration(time.Since(bstart)), "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()))
|
||||||
}
|
|
||||||
blockInsertTimer.UpdateSince(bstart)
|
blockInsertTimer.UpdateSince(bstart)
|
||||||
events = append(events, ChainSideEvent{block})
|
events = append(events, ChainSideEvent{block})
|
||||||
|
|
||||||
case SplitStatTy:
|
case SplitStatTy:
|
||||||
events = append(events, ChainSplitEvent{block, logs})
|
events = append(events, ChainSplitEvent{block, logs})
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.processed++
|
stats.processed++
|
||||||
if glog.V(logger.Info) {
|
stats.usedGas += usedGas.Uint64()
|
||||||
stats.usedGas += usedGas.Uint64()
|
stats.report(chain, i)
|
||||||
stats.report(chain, i)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
go self.postChainEvents(events, coalescedLogs)
|
go self.postChainEvents(events, coalescedLogs)
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
|
|
@ -1059,19 +1075,22 @@ func (st *insertStats) report(chain []*types.Block, index int) {
|
||||||
)
|
)
|
||||||
// If we're at the last block of the batch or report period reached, log
|
// If we're at the last block of the batch or report period reached, log
|
||||||
if index == len(chain)-1 || elapsed >= statsReportLimit {
|
if index == len(chain)-1 || elapsed >= statsReportLimit {
|
||||||
start, end := chain[st.lastIndex], chain[index]
|
var (
|
||||||
txcount := countTransactions(chain[st.lastIndex : index+1])
|
end = chain[index]
|
||||||
|
txs = countTransactions(chain[st.lastIndex : index+1])
|
||||||
var hashes, extra string
|
)
|
||||||
if st.queued > 0 || st.ignored > 0 {
|
context := []interface{}{
|
||||||
extra = fmt.Sprintf(" (%d queued %d ignored)", st.queued, st.ignored)
|
"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
|
||||||
|
"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed),
|
||||||
|
"number", end.Number(), "hash", end.Hash(),
|
||||||
}
|
}
|
||||||
if st.processed > 1 {
|
if st.queued > 0 {
|
||||||
hashes = fmt.Sprintf("%x… / %x…", start.Hash().Bytes()[:4], end.Hash().Bytes()[:4])
|
context = append(context, []interface{}{"queued", st.queued}...)
|
||||||
} else {
|
|
||||||
hashes = fmt.Sprintf("%x…", end.Hash().Bytes()[:4])
|
|
||||||
}
|
}
|
||||||
glog.Infof("imported %4d blocks, %5d txs (%7.3f Mg) in %9v (%6.3f Mg/s). #%v [%s]%s", st.processed, txcount, float64(st.usedGas)/1000000, common.PrettyDuration(elapsed), float64(st.usedGas)*1000/float64(elapsed), end.Number(), hashes, extra)
|
if st.ignored > 0 {
|
||||||
|
context = append(context, []interface{}{"ignored", st.ignored}...)
|
||||||
|
}
|
||||||
|
log.Info("Imported new chain segment", context...)
|
||||||
|
|
||||||
*st = insertStats{startTime: now, lastIndex: index}
|
*st = insertStats{startTime: now, lastIndex: index}
|
||||||
}
|
}
|
||||||
|
|
@ -1151,22 +1170,17 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||||
return fmt.Errorf("Invalid new chain")
|
return fmt.Errorf("Invalid new chain")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Ensure the user sees large reorgs
|
||||||
if oldLen := len(oldChain); oldLen > 63 || glog.V(logger.Debug) {
|
if len(oldChain) > 0 && len(newChain) > 0 {
|
||||||
newLen := len(newChain)
|
logFn := log.Debug
|
||||||
newLast := newChain[0]
|
if len(oldChain) > 63 {
|
||||||
newFirst := newChain[newLen-1]
|
logFn = log.Warn
|
||||||
oldLast := oldChain[0]
|
}
|
||||||
oldFirst := oldChain[oldLen-1]
|
logFn("Chain split detected", "number", commonBlock.Number(), "hash", commonBlock.Hash(),
|
||||||
glog.Infof("Chain split detected after #%v [%x…]. Reorganising chain (-%v +%v blocks), rejecting #%v-#%v [%x…/%x…] in favour of #%v-#%v [%x…/%x…]",
|
"drop", len(oldChain), "dropfrom", oldChain[0].Hash(), "add", len(newChain), "addfrom", newChain[0].Hash())
|
||||||
commonBlock.Number(), commonBlock.Hash().Bytes()[:4],
|
} else {
|
||||||
oldLen, newLen,
|
log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "newnum", newBlock.Number(), "newhash", newBlock.Hash())
|
||||||
oldFirst.Number(), oldLast.Number(),
|
|
||||||
oldFirst.Hash().Bytes()[:4], oldLast.Hash().Bytes()[:4],
|
|
||||||
newFirst.Number(), newLast.Number(),
|
|
||||||
newFirst.Hash().Bytes()[:4], newLast.Hash().Bytes()[:4])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var addedTxs types.Transactions
|
var addedTxs types.Transactions
|
||||||
// insert blocks. Order does not matter. Last block will be written in ImportChain itself which creates the new head properly
|
// insert blocks. Order does not matter. Last block will be written in ImportChain itself which creates the new head properly
|
||||||
for _, block := range newChain {
|
for _, block := range newChain {
|
||||||
|
|
@ -1272,12 +1286,12 @@ func (bc *BlockChain) addBadBlock(block *types.Block) {
|
||||||
// reportBlock logs a bad block error.
|
// reportBlock logs a bad block error.
|
||||||
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
|
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
|
||||||
bc.addBadBlock(block)
|
bc.addBadBlock(block)
|
||||||
if glog.V(logger.Error) {
|
|
||||||
var receiptString string
|
var receiptString string
|
||||||
for _, receipt := range receipts {
|
for _, receipt := range receipts {
|
||||||
receiptString += fmt.Sprintf("\t%v\n", receipt)
|
receiptString += fmt.Sprintf("\t%v\n", receipt)
|
||||||
}
|
}
|
||||||
glog.Errorf(`
|
log.Error(fmt.Sprintf(`
|
||||||
########## BAD BLOCK #########
|
########## BAD BLOCK #########
|
||||||
Chain config: %v
|
Chain config: %v
|
||||||
|
|
||||||
|
|
@ -1287,8 +1301,7 @@ Hash: 0x%x
|
||||||
|
|
||||||
Error: %v
|
Error: %v
|
||||||
##############################
|
##############################
|
||||||
`, bc.config, block.Number(), block.Hash(), receiptString, err)
|
`, bc.config, block.Number(), block.Hash(), receiptString, err))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertHeaderChain attempts to insert the given header chain in to the local
|
// InsertHeaderChain attempts to insert the given header chain in to the local
|
||||||
|
|
@ -1300,6 +1313,11 @@ Error: %v
|
||||||
// of the header retrieval mechanisms already need to verify nonces, as well as
|
// of the header retrieval mechanisms already need to verify nonces, as well as
|
||||||
// because nonces can be verified sparsely, not needing to check each.
|
// because nonces can be verified sparsely, not needing to check each.
|
||||||
func (self *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
|
func (self *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
|
||||||
|
start := time.Now()
|
||||||
|
if i, err := self.hc.ValidateHeaderChain(chain, checkFreq); err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure only one thread manipulates the chain at once
|
// Make sure only one thread manipulates the chain at once
|
||||||
self.chainmu.Lock()
|
self.chainmu.Lock()
|
||||||
defer self.chainmu.Unlock()
|
defer self.chainmu.Unlock()
|
||||||
|
|
@ -1315,7 +1333,7 @@ func (self *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.hc.InsertHeaderChain(chain, checkFreq, whFunc)
|
return self.hc.InsertHeaderChain(chain, whFunc, start)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeHeader writes a header into the local chain, given that its parent is
|
// writeHeader writes a header into the local chain, given that its parent is
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/ethash"
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
"github.com/expanse-org/go-expanse/core/state"
|
"github.com/expanse-org/go-expanse/core/state"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
|
|
@ -37,29 +32,21 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/event"
|
"github.com/expanse-org/go-expanse/event"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
"github.com/expanse-org/go-expanse/pow"
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
"github.com/expanse-org/go-expanse/rlp"
|
|
||||||
"github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
// newTestBlockChain creates a blockchain without validation.
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
func newTestBlockChain() *BlockChain {
|
||||||
}
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
gspec := &Genesis{
|
||||||
func thePow() pow.PoW {
|
Config: params.TestChainConfig,
|
||||||
pow, _ := ethash.NewForTesting()
|
Difficulty: big.NewInt(1),
|
||||||
return pow
|
|
||||||
}
|
|
||||||
|
|
||||||
func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain {
|
|
||||||
var eventMux event.TypeMux
|
|
||||||
WriteTestNetGenesisBlock(db)
|
|
||||||
blockchain, err := NewBlockChain(db, testChainConfig(), thePow(), &eventMux, vm.Config{})
|
|
||||||
if err != nil {
|
|
||||||
t.Error("failed creating blockchain:", err)
|
|
||||||
t.FailNow()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
gspec.MustCommit(db)
|
||||||
|
blockchain, err := NewBlockChain(db, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
blockchain.SetValidator(bproc{})
|
||||||
return blockchain
|
return blockchain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,21 +164,6 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadChain(fn string, t *testing.T) (types.Blocks, error) {
|
|
||||||
fh, err := os.OpenFile(filepath.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer fh.Close()
|
|
||||||
|
|
||||||
var chain types.Blocks
|
|
||||||
if err := rlp.Decode(fh, &chain); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return chain, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) {
|
func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) {
|
||||||
_, err := blockchain.InsertChain(chain)
|
_, err := blockchain.InsertChain(chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -202,12 +174,10 @@ func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLastBlock(t *testing.T) {
|
func TestLastBlock(t *testing.T) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
bchain := newTestBlockChain()
|
||||||
|
block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0]
|
||||||
bchain := theBlockChain(db, t)
|
|
||||||
block := makeBlockChain(bchain.CurrentBlock(), 1, db, 0)[0]
|
|
||||||
bchain.insert(block)
|
bchain.insert(block)
|
||||||
if block.Hash() != GetHeadBlockHash(db) {
|
if block.Hash() != GetHeadBlockHash(bchain.chainDb) {
|
||||||
t.Errorf("Write/Get HeadBlockHash failed")
|
t.Errorf("Write/Get HeadBlockHash failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -346,88 +316,6 @@ func testBrokenChain(t *testing.T, full bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChainInsertions(t *testing.T) {
|
|
||||||
t.Skip("Skipped: outdated test files")
|
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
|
|
||||||
chain1, err := loadChain("valid1", t)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
chain2, err := loadChain("valid2", t)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
blockchain := theBlockChain(db, t)
|
|
||||||
|
|
||||||
const max = 2
|
|
||||||
done := make(chan bool, max)
|
|
||||||
|
|
||||||
go insertChain(done, blockchain, chain1, t)
|
|
||||||
go insertChain(done, blockchain, chain2, t)
|
|
||||||
|
|
||||||
for i := 0; i < max; i++ {
|
|
||||||
<-done
|
|
||||||
}
|
|
||||||
|
|
||||||
if chain2[len(chain2)-1].Hash() != blockchain.CurrentBlock().Hash() {
|
|
||||||
t.Error("chain2 is canonical and shouldn't be")
|
|
||||||
}
|
|
||||||
|
|
||||||
if chain1[len(chain1)-1].Hash() != blockchain.CurrentBlock().Hash() {
|
|
||||||
t.Error("chain1 isn't canonical and should be")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestChainMultipleInsertions(t *testing.T) {
|
|
||||||
t.Skip("Skipped: outdated test files")
|
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
|
|
||||||
const max = 4
|
|
||||||
chains := make([]types.Blocks, max)
|
|
||||||
var longest int
|
|
||||||
for i := 0; i < max; i++ {
|
|
||||||
var err error
|
|
||||||
name := "valid" + strconv.Itoa(i+1)
|
|
||||||
chains[i], err = loadChain(name, t)
|
|
||||||
if len(chains[i]) >= len(chains[longest]) {
|
|
||||||
longest = i
|
|
||||||
}
|
|
||||||
fmt.Println("loaded", name, "with a length of", len(chains[i]))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blockchain := theBlockChain(db, t)
|
|
||||||
|
|
||||||
done := make(chan bool, max)
|
|
||||||
for i, chain := range chains {
|
|
||||||
// XXX the go routine would otherwise reference the same (chain[3]) variable and fail
|
|
||||||
i := i
|
|
||||||
chain := chain
|
|
||||||
go func() {
|
|
||||||
insertChain(done, blockchain, chain, t)
|
|
||||||
fmt.Println(i, "done")
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < max; i++ {
|
|
||||||
<-done
|
|
||||||
}
|
|
||||||
|
|
||||||
if chains[longest][len(chains[longest])-1].Hash() != blockchain.CurrentBlock().Hash() {
|
|
||||||
t.Error("Invalid canonical chain")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type bproc struct{}
|
type bproc struct{}
|
||||||
|
|
||||||
func (bproc) ValidateBlock(*types.Block) error { return nil }
|
func (bproc) ValidateBlock(*types.Block) error { return nil }
|
||||||
|
|
@ -458,6 +346,7 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
TxHash: types.EmptyRootHash,
|
TxHash: types.EmptyRootHash,
|
||||||
ReceiptHash: types.EmptyRootHash,
|
ReceiptHash: types.EmptyRootHash,
|
||||||
|
Time: big.NewInt(int64(i) + 1),
|
||||||
}
|
}
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
header.ParentHash = genesis.Hash()
|
header.ParentHash = genesis.Hash()
|
||||||
|
|
@ -470,29 +359,6 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
|
||||||
return chain
|
return chain
|
||||||
}
|
}
|
||||||
|
|
||||||
func chm(genesis *types.Block, db ethdb.Database) *BlockChain {
|
|
||||||
var eventMux event.TypeMux
|
|
||||||
bc := &BlockChain{
|
|
||||||
chainDb: db,
|
|
||||||
genesisBlock: genesis,
|
|
||||||
eventMux: &eventMux,
|
|
||||||
pow: FakePow{},
|
|
||||||
config: testChainConfig(),
|
|
||||||
}
|
|
||||||
valFn := func() HeaderValidator { return bc.Validator() }
|
|
||||||
bc.hc, _ = NewHeaderChain(db, testChainConfig(), valFn, bc.getProcInterrupt)
|
|
||||||
bc.bodyCache, _ = lru.New(100)
|
|
||||||
bc.bodyRLPCache, _ = lru.New(100)
|
|
||||||
bc.blockCache, _ = lru.New(100)
|
|
||||||
bc.futureBlocks, _ = lru.New(100)
|
|
||||||
bc.badBlocks, _ = lru.New(10)
|
|
||||||
bc.SetValidator(bproc{})
|
|
||||||
bc.SetProcessor(bproc{})
|
|
||||||
bc.ResetWithGenesisBlock(genesis)
|
|
||||||
|
|
||||||
return bc
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests that reorganising a long difficult chain after a short easy one
|
// Tests that reorganising a long difficult chain after a short easy one
|
||||||
// overwrites the canonical numbers and links in the database.
|
// overwrites the canonical numbers and links in the database.
|
||||||
func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) }
|
func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) }
|
||||||
|
|
@ -512,18 +378,15 @@ func testReorgShort(t *testing.T, full bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testReorg(t *testing.T, first, second []int, td int64, full bool) {
|
func testReorg(t *testing.T, first, second []int, td int64, full bool) {
|
||||||
// Create a pristine block chain
|
bc := newTestBlockChain()
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
genesis, _ := WriteTestNetGenesisBlock(db)
|
|
||||||
bc := chm(genesis, db)
|
|
||||||
|
|
||||||
// Insert an easy and a difficult chain afterwards
|
// Insert an easy and a difficult chain afterwards
|
||||||
if full {
|
if full {
|
||||||
bc.InsertChain(makeBlockChainWithDiff(genesis, first, 11))
|
bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, first, 11))
|
||||||
bc.InsertChain(makeBlockChainWithDiff(genesis, second, 22))
|
bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, second, 22))
|
||||||
} else {
|
} else {
|
||||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1)
|
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
|
||||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1)
|
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
|
||||||
}
|
}
|
||||||
// Check that the chain is valid number and link wise
|
// Check that the chain is valid number and link wise
|
||||||
if full {
|
if full {
|
||||||
|
|
@ -542,7 +405,7 @@ func testReorg(t *testing.T, first, second []int, td int64, full bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Make sure the chain total difficulty is the correct one
|
// Make sure the chain total difficulty is the correct one
|
||||||
want := new(big.Int).Add(genesis.Difficulty(), big.NewInt(td))
|
want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
|
||||||
if full {
|
if full {
|
||||||
if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 {
|
if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 {
|
||||||
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
|
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
|
||||||
|
|
@ -559,19 +422,16 @@ func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) }
|
||||||
func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) }
|
func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) }
|
||||||
|
|
||||||
func testBadHashes(t *testing.T, full bool) {
|
func testBadHashes(t *testing.T, full bool) {
|
||||||
// Create a pristine block chain
|
bc := newTestBlockChain()
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
genesis, _ := WriteTestNetGenesisBlock(db)
|
|
||||||
bc := chm(genesis, db)
|
|
||||||
|
|
||||||
// Create a chain, ban a hash and try to import
|
// Create a chain, ban a hash and try to import
|
||||||
var err error
|
var err error
|
||||||
if full {
|
if full {
|
||||||
blocks := makeBlockChainWithDiff(genesis, []int{1, 2, 4}, 10)
|
blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
|
||||||
BadHashes[blocks[2].Header().Hash()] = true
|
BadHashes[blocks[2].Header().Hash()] = true
|
||||||
_, err = bc.InsertChain(blocks)
|
_, err = bc.InsertChain(blocks)
|
||||||
} else {
|
} else {
|
||||||
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 4}, 10)
|
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
|
||||||
BadHashes[headers[2].Hash()] = true
|
BadHashes[headers[2].Hash()] = true
|
||||||
_, err = bc.InsertHeaderChain(headers, 1)
|
_, err = bc.InsertHeaderChain(headers, 1)
|
||||||
}
|
}
|
||||||
|
|
@ -586,14 +446,11 @@ func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) }
|
||||||
func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) }
|
func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) }
|
||||||
|
|
||||||
func testReorgBadHashes(t *testing.T, full bool) {
|
func testReorgBadHashes(t *testing.T, full bool) {
|
||||||
// Create a pristine block chain
|
bc := newTestBlockChain()
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
genesis, _ := WriteTestNetGenesisBlock(db)
|
|
||||||
bc := chm(genesis, db)
|
|
||||||
|
|
||||||
// Create a chain, import and ban afterwards
|
// Create a chain, import and ban afterwards
|
||||||
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
|
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
|
||||||
blocks := makeBlockChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
|
blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
|
||||||
|
|
||||||
if full {
|
if full {
|
||||||
if _, err := bc.InsertChain(blocks); err != nil {
|
if _, err := bc.InsertChain(blocks); err != nil {
|
||||||
|
|
@ -614,8 +471,9 @@ func testReorgBadHashes(t *testing.T, full bool) {
|
||||||
BadHashes[headers[3].Hash()] = true
|
BadHashes[headers[3].Hash()] = true
|
||||||
defer func() { delete(BadHashes, headers[3].Hash()) }()
|
defer func() { delete(BadHashes, headers[3].Hash()) }()
|
||||||
}
|
}
|
||||||
// Create a new chain manager and check it rolled back the state
|
|
||||||
ncm, err := NewBlockChain(db, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{})
|
// Create a new BlockChain and check that it rolled back the state.
|
||||||
|
ncm, err := NewBlockChain(bc.chainDb, bc.config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
t.Fatalf("failed to create new chain manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -669,7 +527,7 @@ func testInsertNonceError(t *testing.T, full bool) {
|
||||||
failHash = headers[failAt].Hash()
|
failHash = headers[failAt].Hash()
|
||||||
|
|
||||||
blockchain.pow = failPow{failNum}
|
blockchain.pow = failPow{failNum}
|
||||||
blockchain.validator = NewBlockValidator(testChainConfig(), blockchain, failPow{failNum})
|
blockchain.validator = NewBlockValidator(params.TestChainConfig, blockchain, failPow{failNum})
|
||||||
|
|
||||||
failRes, err = blockchain.InsertHeaderChain(headers, 1)
|
failRes, err = blockchain.InsertHeaderChain(headers, 1)
|
||||||
}
|
}
|
||||||
|
|
@ -711,10 +569,11 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
genesis = GenesisBlockForTesting(gendb, address, funds)
|
gspec = testGenesis(address, funds)
|
||||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
genesis = gspec.MustCommit(gendb)
|
||||||
|
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
||||||
)
|
)
|
||||||
blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, 1024, func(i int, block *BlockGen) {
|
blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, 1024, func(i int, block *BlockGen) {
|
||||||
block.SetCoinbase(common.Address{0x00})
|
block.SetCoinbase(common.Address{0x00})
|
||||||
|
|
||||||
// If the block number is multiple of 3, send a few bonus transactions to the miner
|
// If the block number is multiple of 3, send a few bonus transactions to the miner
|
||||||
|
|
@ -734,17 +593,17 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
})
|
})
|
||||||
// Import the chain as an archive node for the comparison baseline
|
// Import the chain as an archive node for the comparison baseline
|
||||||
archiveDb, _ := ethdb.NewMemDatabase()
|
archiveDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds})
|
gspec.MustCommit(archiveDb)
|
||||||
|
archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
archive, _ := NewBlockChain(archiveDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{})
|
|
||||||
|
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
t.Fatalf("failed to process block %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast import the chain as a non-archive node to test
|
// Fast import the chain as a non-archive node to test
|
||||||
fastDb, _ := ethdb.NewMemDatabase()
|
fastDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{})
|
fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
|
@ -794,10 +653,11 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
genesis = GenesisBlockForTesting(gendb, address, funds)
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}
|
||||||
|
genesis = gspec.MustCommit(gendb)
|
||||||
)
|
)
|
||||||
height := uint64(1024)
|
height := uint64(1024)
|
||||||
blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, int(height), nil)
|
blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, int(height), nil)
|
||||||
|
|
||||||
// Configure a subchain to roll back
|
// Configure a subchain to roll back
|
||||||
remove := []common.Hash{}
|
remove := []common.Hash{}
|
||||||
|
|
@ -818,9 +678,9 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Import the chain as an archive node and ensure all pointers are updated
|
// Import the chain as an archive node and ensure all pointers are updated
|
||||||
archiveDb, _ := ethdb.NewMemDatabase()
|
archiveDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds})
|
gspec.MustCommit(archiveDb)
|
||||||
|
|
||||||
archive, _ := NewBlockChain(archiveDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{})
|
archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
t.Fatalf("failed to process block %d: %v", n, err)
|
||||||
|
|
@ -831,8 +691,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
|
|
||||||
// Import the chain as a non-archive node and ensure all pointers are updated
|
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||||
fastDb, _ := ethdb.NewMemDatabase()
|
fastDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{})
|
fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
|
@ -850,8 +710,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
|
|
||||||
// Import the chain as a light node and ensure all pointers are updated
|
// Import the chain as a light node and ensure all pointers are updated
|
||||||
lightDb, _ := ethdb.NewMemDatabase()
|
lightDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(lightDb, GenesisAccount{address, funds})
|
gspec.MustCommit(lightDb)
|
||||||
light, _ := NewBlockChain(lightDb, testChainConfig(), FakePow{}, new(event.TypeMux), vm.Config{})
|
light, _ := NewBlockChain(lightDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
||||||
t.Fatalf("failed to insert header %d: %v", n, err)
|
t.Fatalf("failed to insert header %d: %v", n, err)
|
||||||
|
|
@ -863,9 +723,6 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
|
|
||||||
// Tests that chain reorganisations handle transaction removals and reinsertions.
|
// Tests that chain reorganisations handle transaction removals and reinsertions.
|
||||||
func TestChainTxReorgs(t *testing.T) {
|
func TestChainTxReorgs(t *testing.T) {
|
||||||
params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be.
|
|
||||||
params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
|
@ -874,13 +731,19 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
gspec = &Genesis{
|
||||||
)
|
Config: params.TestChainConfig,
|
||||||
genesis := WriteGenesisBlockForTesting(db,
|
GasLimit: 3141592,
|
||||||
GenesisAccount{addr1, big.NewInt(1000000)},
|
Alloc: GenesisAlloc{
|
||||||
GenesisAccount{addr2, big.NewInt(1000000)},
|
addr1: {Balance: big.NewInt(1000000)},
|
||||||
GenesisAccount{addr3, big.NewInt(1000000)},
|
addr2: {Balance: big.NewInt(1000000)},
|
||||||
|
addr3: {Balance: big.NewInt(1000000)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
genesis = gspec.MustCommit(db)
|
||||||
|
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create two transactions shared between the chains:
|
// Create two transactions shared between the chains:
|
||||||
// - postponed: transaction included at a later block in the forked chain
|
// - postponed: transaction included at a later block in the forked chain
|
||||||
// - swapped: transaction included at the same block number in the forked chain
|
// - swapped: transaction included at the same block number in the forked chain
|
||||||
|
|
@ -898,7 +761,7 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
// - futureAdd: transaction added after the reorg has already finished
|
// - futureAdd: transaction added after the reorg has already finished
|
||||||
var pastAdd, freshAdd, futureAdd *types.Transaction
|
var pastAdd, freshAdd, futureAdd *types.Transaction
|
||||||
|
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
|
pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
|
||||||
|
|
@ -917,13 +780,13 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
})
|
})
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
evmux := &event.TypeMux{}
|
evmux := &event.TypeMux{}
|
||||||
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux, vm.Config{})
|
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// overwrite the old chain
|
// overwrite the old chain
|
||||||
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
|
chain, _ = GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
|
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
|
||||||
|
|
@ -975,23 +838,20 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogReorgs(t *testing.T) {
|
func TestLogReorgs(t *testing.T) {
|
||||||
params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be.
|
|
||||||
params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
// this code generates a log
|
// this code generates a log
|
||||||
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
|
||||||
)
|
genesis = gspec.MustCommit(db)
|
||||||
genesis := WriteGenesisBlockForTesting(db,
|
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
||||||
GenesisAccount{addr1, big.NewInt(10000000000000)},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
evmux := &event.TypeMux{}
|
var evmux event.TypeMux
|
||||||
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux, vm.Config{})
|
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &evmux, vm.Config{})
|
||||||
|
|
||||||
subs := evmux.Subscribe(RemovedLogsEvent{})
|
subs := evmux.Subscribe(RemovedLogsEvent{})
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
|
||||||
|
|
@ -1023,19 +883,20 @@ func TestReorgSideEvent(t *testing.T) {
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)})
|
gspec = testGenesis(addr1, big.NewInt(10000000000000))
|
||||||
signer = types.NewEIP155Signer(big.NewInt(1))
|
genesis = gspec.MustCommit(db)
|
||||||
|
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
||||||
)
|
)
|
||||||
|
|
||||||
evmux := &event.TypeMux{}
|
evmux := &event.TypeMux{}
|
||||||
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux, vm.Config{})
|
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
|
||||||
|
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})
|
chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {})
|
||||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert chain: %v", err)
|
t.Fatalf("failed to insert chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) {
|
replacementBlocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, gen *BlockGen) {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1)
|
||||||
if i == 2 {
|
if i == 2 {
|
||||||
gen.OffsetTime(-1)
|
gen.OffsetTime(-1)
|
||||||
|
|
@ -1098,28 +959,21 @@ done:
|
||||||
|
|
||||||
// Tests if the canonical block can be fetched from the database during chain insertion.
|
// Tests if the canonical block can be fetched from the database during chain insertion.
|
||||||
func TestCanonicalBlockRetrieval(t *testing.T) {
|
func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||||
var (
|
bc := newTestBlockChain()
|
||||||
db, _ = ethdb.NewMemDatabase()
|
chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {})
|
||||||
genesis = WriteGenesisBlockForTesting(db)
|
|
||||||
)
|
|
||||||
|
|
||||||
evmux := &event.TypeMux{}
|
|
||||||
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux, vm.Config{})
|
|
||||||
|
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
|
|
||||||
|
|
||||||
for i := range chain {
|
for i := range chain {
|
||||||
go func(block *types.Block) {
|
go func(block *types.Block) {
|
||||||
// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
|
// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
|
||||||
for {
|
for {
|
||||||
ch := GetCanonicalHash(db, block.NumberU64())
|
ch := GetCanonicalHash(bc.chainDb, block.NumberU64())
|
||||||
if ch == (common.Hash{}) {
|
if ch == (common.Hash{}) {
|
||||||
continue // busy wait for canonical hash to be written
|
continue // busy wait for canonical hash to be written
|
||||||
}
|
}
|
||||||
if ch != block.Hash() {
|
if ch != block.Hash() {
|
||||||
t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())
|
t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())
|
||||||
}
|
}
|
||||||
fb := GetBlock(db, ch, block.NumberU64())
|
fb := GetBlock(bc.chainDb, ch, block.NumberU64())
|
||||||
if fb == nil {
|
if fb == nil {
|
||||||
t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())
|
t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())
|
||||||
}
|
}
|
||||||
|
|
@ -1130,7 +984,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||||
}
|
}
|
||||||
}(chain[i])
|
}(chain[i])
|
||||||
|
|
||||||
blockchain.InsertChain(types.Blocks{chain[i]})
|
bc.InsertChain(types.Blocks{chain[i]})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1142,13 +996,16 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
deleteAddr = common.Address{1}
|
deleteAddr = common.Address{1}
|
||||||
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds}, GenesisAccount{deleteAddr, new(big.Int)})
|
gspec = &Genesis{
|
||||||
config = ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
|
Config: ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
|
||||||
mux event.TypeMux
|
Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
|
||||||
|
}
|
||||||
|
genesis = gspec.MustCommit(db)
|
||||||
|
mux event.TypeMux
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, config, FakePow{}, &mux, vm.Config{})
|
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
|
||||||
blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, block *BlockGen) {
|
||||||
var (
|
var (
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
err error
|
err error
|
||||||
|
|
@ -1170,7 +1027,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
|
|
||||||
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
|
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -1182,7 +1039,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
|
|
||||||
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
|
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -1210,7 +1067,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate an invalid chain id transaction
|
// generate an invalid chain id transaction
|
||||||
config = ¶ms.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
|
config := ¶ms.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
|
||||||
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) {
|
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) {
|
||||||
var (
|
var (
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
|
|
@ -1242,22 +1099,24 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
theAddr = common.Address{1}
|
theAddr = common.Address{1}
|
||||||
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds})
|
gspec = &Genesis{
|
||||||
config = ¶ms.ChainConfig{
|
Config: ¶ms.ChainConfig{
|
||||||
ChainId: big.NewInt(1),
|
ChainId: big.NewInt(1),
|
||||||
HomesteadBlock: new(big.Int),
|
HomesteadBlock: new(big.Int),
|
||||||
EIP155Block: new(big.Int),
|
EIP155Block: new(big.Int),
|
||||||
EIP158Block: big.NewInt(2),
|
EIP158Block: big.NewInt(2),
|
||||||
|
},
|
||||||
|
Alloc: GenesisAlloc{address: {Balance: funds}},
|
||||||
}
|
}
|
||||||
mux event.TypeMux
|
genesis = gspec.MustCommit(db)
|
||||||
|
mux event.TypeMux
|
||||||
blockchain, _ = NewBlockChain(db, config, FakePow{}, &mux, vm.Config{})
|
blockchain, _ = NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
|
||||||
)
|
)
|
||||||
blocks, _ := GenerateChain(config, genesis, db, 3, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, block *BlockGen) {
|
||||||
var (
|
var (
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
err error
|
err error
|
||||||
signer = types.NewEIP155Signer(config.ChainId)
|
signer = types.NewEIP155Signer(gspec.Config.ChainId)
|
||||||
)
|
)
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
@ -1285,7 +1144,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if blockchain.stateCache.Exist(theAddr) {
|
if blockchain.stateCache.Exist(theAddr) {
|
||||||
t.Error("account should not expect")
|
t.Error("account should not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
// account musn't be created post eip 161
|
// account musn't be created post eip 161
|
||||||
|
|
@ -1293,6 +1152,6 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if blockchain.stateCache.Exist(theAddr) {
|
if blockchain.stateCache.Exist(theAddr) {
|
||||||
t.Error("account should not expect")
|
t.Error("account should not exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,30 +30,6 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/pow"
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: move this to another package.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// MakeChainConfig returns a new ChainConfig with the ethereum default chain settings.
|
|
||||||
func MakeChainConfig() *params.ChainConfig {
|
|
||||||
return ¶ms.ChainConfig{
|
|
||||||
HomesteadBlock: big.NewInt(0),
|
|
||||||
DAOForkBlock: nil,
|
|
||||||
DAOForkSupport: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FakePow is a non-validating proof of work implementation.
|
|
||||||
// It returns true from Verify for any block.
|
|
||||||
type FakePow struct{}
|
|
||||||
|
|
||||||
func (f FakePow) Search(block pow.Block, stop <-chan struct{}, index int) (uint64, []byte) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
func (f FakePow) Verify(block pow.Block) bool { return true }
|
|
||||||
func (f FakePow) GetHashrate() int64 { return 0 }
|
|
||||||
func (f FakePow) Turbo(bool) {}
|
|
||||||
|
|
||||||
// So we can deterministically seed different blockchains
|
// So we can deterministically seed different blockchains
|
||||||
var (
|
var (
|
||||||
canonicalSeed = 1
|
canonicalSeed = 1
|
||||||
|
|
@ -165,7 +141,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
|
||||||
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
|
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
|
||||||
panic("block time out of range")
|
panic("block time out of range")
|
||||||
}
|
}
|
||||||
b.header.Difficulty = CalcDifficulty(MakeChainConfig(), b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty())
|
b.header.Difficulty = CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateChain creates a chain of n blocks. The first block's
|
// GenerateChain creates a chain of n blocks. The first block's
|
||||||
|
|
@ -181,14 +157,13 @@ func (b *BlockGen) OffsetTime(seconds int64) {
|
||||||
// values. Inserting them into BlockChain requires use of FakePow or
|
// values. Inserting them into BlockChain requires use of FakePow or
|
||||||
// a similar non-validating proof of work implementation.
|
// a similar non-validating proof of work implementation.
|
||||||
func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
|
func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
|
||||||
|
if config == nil {
|
||||||
|
config = params.TestChainConfig
|
||||||
|
}
|
||||||
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
||||||
genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
||||||
b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb, config: config}
|
b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb, config: config}
|
||||||
|
|
||||||
// Mutate the state and block according to any hard-fork specs
|
// Mutate the state and block according to any hard-fork specs
|
||||||
if config == nil {
|
|
||||||
config = MakeChainConfig()
|
|
||||||
}
|
|
||||||
if daoBlock := config.DAOForkBlock; daoBlock != nil {
|
if daoBlock := config.DAOForkBlock; daoBlock != nil {
|
||||||
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
|
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
|
||||||
if h.Number.Cmp(daoBlock) >= 0 && h.Number.Cmp(limit) < 0 {
|
if h.Number.Cmp(daoBlock) >= 0 && h.Number.Cmp(limit) < 0 {
|
||||||
|
|
@ -237,7 +212,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
|
||||||
Root: state.IntermediateRoot(config.IsEIP158(parent.Number())),
|
Root: state.IntermediateRoot(config.IsEIP158(parent.Number())),
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
Coinbase: parent.Coinbase(),
|
||||||
Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
|
Difficulty: CalcDifficulty(config, time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
|
||||||
GasLimit: CalcGasLimit(parent),
|
GasLimit: CalcGasLimit(parent),
|
||||||
GasUsed: new(big.Int),
|
GasUsed: new(big.Int),
|
||||||
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
||||||
|
|
@ -249,14 +224,12 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
|
||||||
// chain. Depending on the full flag, if creates either a full block chain or a
|
// chain. Depending on the full flag, if creates either a full block chain or a
|
||||||
// header only chain.
|
// header only chain.
|
||||||
func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
|
func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
|
||||||
// Create the new chain database
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
|
||||||
evmux := &event.TypeMux{}
|
|
||||||
|
|
||||||
// Initialize a fresh chain with only a genesis block
|
// Initialize a fresh chain with only a genesis block
|
||||||
genesis, _ := WriteTestNetGenesisBlock(db)
|
gspec := new(Genesis)
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, MakeChainConfig(), FakePow{}, evmux, vm.Config{})
|
blockchain, _ := NewBlockChain(db, params.AllProtocolChanges, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
// Create and inject the requested chain
|
// Create and inject the requested chain
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return db, blockchain, nil
|
return db, blockchain, nil
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,10 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/event"
|
"github.com/expanse-org/go-expanse/event"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleGenerateChain() {
|
func ExampleGenerateChain() {
|
||||||
params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be.
|
|
||||||
params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
|
@ -40,19 +38,20 @@ func ExampleGenerateChain() {
|
||||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
signer = types.HomesteadSigner{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
chainConfig := ¶ms.ChainConfig{
|
|
||||||
HomesteadBlock: new(big.Int),
|
|
||||||
}
|
|
||||||
// Ensure that key1 has some funds in the genesis block.
|
// Ensure that key1 has some funds in the genesis block.
|
||||||
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)})
|
gspec := &Genesis{
|
||||||
|
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||||
|
Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
|
||||||
|
}
|
||||||
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
// This call generates a chain of 5 blocks. The function runs for
|
// This call generates a chain of 5 blocks. The function runs for
|
||||||
// each block and adds different features to gen based on the
|
// each block and adds different features to gen based on the
|
||||||
// block index.
|
// block index.
|
||||||
chain, _ := GenerateChain(chainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
|
signer := types.HomesteadSigner{}
|
||||||
|
chain, _ := GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, addr1 sends addr2 some ether.
|
// In block 1, addr1 sends addr2 some ether.
|
||||||
|
|
@ -82,7 +81,7 @@ func ExampleGenerateChain() {
|
||||||
|
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
evmux := &event.TypeMux{}
|
evmux := &event.TypeMux{}
|
||||||
blockchain, _ := NewBlockChain(db, chainConfig, FakePow{}, evmux, vm.Config{})
|
blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
|
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ func verifyNonces(checker pow.PoW, items []pow.Block) (chan<- struct{}, <-chan n
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go func() {
|
go func() {
|
||||||
for index := range tasks {
|
for index := range tasks {
|
||||||
results <- nonceCheckResult{index: index, valid: checker.Verify(items[index])}
|
results <- nonceCheckResult{index: index, valid: checker.Verify(items[index]) == nil}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -35,12 +36,16 @@ type failPow struct {
|
||||||
failing uint64
|
failing uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pow failPow) Search(pow.Block, <-chan struct{}, int) (uint64, []byte) {
|
func (pow failPow) Search(pow.Block, <-chan struct{}) (uint64, []byte) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
func (pow failPow) Verify(block pow.Block) bool { return block.NumberU64() != pow.failing }
|
func (pow failPow) Verify(block pow.Block) error {
|
||||||
func (pow failPow) GetHashrate() int64 { return 0 }
|
if block.NumberU64() == pow.failing {
|
||||||
func (pow failPow) Turbo(bool) {}
|
return errors.New("failed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (pow failPow) Hashrate() float64 { return 0 }
|
||||||
|
|
||||||
// delayedPow is a non-validating proof of work implementation, that returns true
|
// delayedPow is a non-validating proof of work implementation, that returns true
|
||||||
// from Verify for all blocks, but delays them the configured amount of time.
|
// from Verify for all blocks, but delays them the configured amount of time.
|
||||||
|
|
@ -48,12 +53,11 @@ type delayedPow struct {
|
||||||
delay time.Duration
|
delay time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pow delayedPow) Search(pow.Block, <-chan struct{}, int) (uint64, []byte) {
|
func (pow delayedPow) Search(pow.Block, <-chan struct{}) (uint64, []byte) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
func (pow delayedPow) Verify(block pow.Block) bool { time.Sleep(pow.delay); return true }
|
func (pow delayedPow) Verify(block pow.Block) error { time.Sleep(pow.delay); return nil }
|
||||||
func (pow delayedPow) GetHashrate() int64 { return 0 }
|
func (pow delayedPow) Hashrate() float64 { return 0 }
|
||||||
func (pow delayedPow) Turbo(bool) {}
|
|
||||||
|
|
||||||
// Tests that simple POW verification works, for both good and bad blocks.
|
// Tests that simple POW verification works, for both good and bad blocks.
|
||||||
func TestPowVerification(t *testing.T) {
|
func TestPowVerification(t *testing.T) {
|
||||||
|
|
@ -75,11 +79,11 @@ func TestPowVerification(t *testing.T) {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case full && valid:
|
case full && valid:
|
||||||
_, results = verifyNoncesFromBlocks(FakePow{}, []*types.Block{blocks[i]})
|
_, results = verifyNoncesFromBlocks(pow.FakePow{}, []*types.Block{blocks[i]})
|
||||||
case full && !valid:
|
case full && !valid:
|
||||||
_, results = verifyNoncesFromBlocks(failPow{blocks[i].NumberU64()}, []*types.Block{blocks[i]})
|
_, results = verifyNoncesFromBlocks(failPow{blocks[i].NumberU64()}, []*types.Block{blocks[i]})
|
||||||
case !full && valid:
|
case !full && valid:
|
||||||
_, results = verifyNoncesFromHeaders(FakePow{}, []*types.Header{headers[i]})
|
_, results = verifyNoncesFromHeaders(pow.FakePow{}, []*types.Header{headers[i]})
|
||||||
case !full && !valid:
|
case !full && !valid:
|
||||||
_, results = verifyNoncesFromHeaders(failPow{headers[i].Number.Uint64()}, []*types.Header{headers[i]})
|
_, results = verifyNoncesFromHeaders(failPow{headers[i].Number.Uint64()}, []*types.Header{headers[i]})
|
||||||
}
|
}
|
||||||
|
|
@ -134,11 +138,11 @@ func testPowConcurrentVerification(t *testing.T, threads int) {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case full && valid:
|
case full && valid:
|
||||||
_, results = verifyNoncesFromBlocks(FakePow{}, blocks)
|
_, results = verifyNoncesFromBlocks(pow.FakePow{}, blocks)
|
||||||
case full && !valid:
|
case full && !valid:
|
||||||
_, results = verifyNoncesFromBlocks(failPow{uint64(len(blocks) - 1)}, blocks)
|
_, results = verifyNoncesFromBlocks(failPow{uint64(len(blocks) - 1)}, blocks)
|
||||||
case !full && valid:
|
case !full && valid:
|
||||||
_, results = verifyNoncesFromHeaders(FakePow{}, headers)
|
_, results = verifyNoncesFromHeaders(pow.FakePow{}, headers)
|
||||||
case !full && !valid:
|
case !full && !valid:
|
||||||
_, results = verifyNoncesFromHeaders(failPow{uint64(len(headers) - 1)}, headers)
|
_, results = verifyNoncesFromHeaders(failPow{uint64(len(headers) - 1)}, headers)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
core/dao.go
12
core/dao.go
|
|
@ -62,13 +62,13 @@ func ValidateDAOHeaderExtraData(config *params.ChainConfig, header *types.Header
|
||||||
// contract.
|
// contract.
|
||||||
func ApplyDAOHardFork(statedb *state.StateDB) {
|
func ApplyDAOHardFork(statedb *state.StateDB) {
|
||||||
// Retrieve the contract to refund balances into
|
// Retrieve the contract to refund balances into
|
||||||
refund := statedb.GetOrNewStateObject(params.DAORefundContract)
|
if !statedb.Exist(params.DAORefundContract) {
|
||||||
|
statedb.CreateAccount(params.DAORefundContract)
|
||||||
|
}
|
||||||
|
|
||||||
// Move every DAO account and extra-balance account funds into the refund contract
|
// Move every DAO account and extra-balance account funds into the refund contract
|
||||||
for _, addr := range params.DAODrainList {
|
for _, addr := range params.DAODrainList() {
|
||||||
if account := statedb.GetStateObject(addr); account != nil {
|
statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
|
||||||
refund.AddBalance(account.Balance())
|
statedb.SetBalance(addr, new(big.Int))
|
||||||
account.SetBalance(new(big.Int))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/event"
|
"github.com/expanse-org/go-expanse/event"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests that DAO-fork enabled clients can properly filter out fork-commencing
|
// Tests that DAO-fork enabled clients can properly filter out fork-commencing
|
||||||
|
|
@ -33,19 +34,20 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
|
|
||||||
// Generate a common prefix for both pro-forkers and non-forkers
|
// Generate a common prefix for both pro-forkers and non-forkers
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
genesis := WriteGenesisBlockForTesting(db)
|
gspec := new(Genesis)
|
||||||
|
genesis := gspec.MustCommit(db)
|
||||||
prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
|
prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
|
||||||
|
|
||||||
// Create the concurrent, conflicting two nodes
|
// Create the concurrent, conflicting two nodes
|
||||||
proDb, _ := ethdb.NewMemDatabase()
|
proDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(proDb)
|
gspec.MustCommit(proDb)
|
||||||
proConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
|
proConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
|
||||||
proBc, _ := NewBlockChain(proDb, proConf, new(FakePow), new(event.TypeMux), vm.Config{})
|
proBc, _ := NewBlockChain(proDb, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
conDb, _ := ethdb.NewMemDatabase()
|
conDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(conDb)
|
gspec.MustCommit(conDb)
|
||||||
conConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
|
conConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
|
||||||
conBc, _ := NewBlockChain(conDb, conConf, new(FakePow), new(event.TypeMux), vm.Config{})
|
conBc, _ := NewBlockChain(conDb, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
if _, err := proBc.InsertChain(prefix); err != nil {
|
if _, err := proBc.InsertChain(prefix); err != nil {
|
||||||
t.Fatalf("pro-fork: failed to import chain prefix: %v", err)
|
t.Fatalf("pro-fork: failed to import chain prefix: %v", err)
|
||||||
|
|
@ -57,8 +59,8 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
|
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
|
||||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
// Create a pro-fork block, and try to feed into the no-fork chain
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, conConf, new(FakePow), new(event.TypeMux), vm.Config{})
|
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
|
||||||
for j := 0; j < len(blocks)/2; j++ {
|
for j := 0; j < len(blocks)/2; j++ {
|
||||||
|
|
@ -78,8 +80,8 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Create a no-fork block, and try to feed into the pro-fork chain
|
// Create a no-fork block, and try to feed into the pro-fork chain
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, proConf, new(FakePow), new(event.TypeMux), vm.Config{})
|
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
|
||||||
for j := 0; j < len(blocks)/2; j++ {
|
for j := 0; j < len(blocks)/2; j++ {
|
||||||
|
|
@ -100,8 +102,8 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, conConf, new(FakePow), new(event.TypeMux), vm.Config{})
|
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
|
||||||
for j := 0; j < len(blocks)/2; j++ {
|
for j := 0; j < len(blocks)/2; j++ {
|
||||||
|
|
@ -116,8 +118,8 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, proConf, new(FakePow), new(event.TypeMux), vm.Config{})
|
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
|
||||||
for j := 0; j < len(blocks)/2; j++ {
|
for j := 0; j < len(blocks)/2; j++ {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/metrics"
|
"github.com/expanse-org/go-expanse/metrics"
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
"github.com/expanse-org/go-expanse/rlp"
|
"github.com/expanse-org/go-expanse/rlp"
|
||||||
|
|
@ -107,7 +106,7 @@ func GetBlockNumber(db ethdb.Database, hash common.Hash) uint64 {
|
||||||
}
|
}
|
||||||
header := new(types.Header)
|
header := new(types.Header)
|
||||||
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
|
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
|
||||||
glog.Fatalf("failed to decode block header: %v", err)
|
log.Crit("Failed to decode block header", "err", err)
|
||||||
}
|
}
|
||||||
return header.Number.Uint64()
|
return header.Number.Uint64()
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +166,7 @@ func GetHeader(db ethdb.Database, hash common.Hash, number uint64) *types.Header
|
||||||
}
|
}
|
||||||
header := new(types.Header)
|
header := new(types.Header)
|
||||||
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
|
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
|
||||||
glog.V(logger.Error).Infof("invalid block header RLP for hash %x: %v", hash, err)
|
log.Error("Invalid block header RLP", "hash", hash, "err", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return header
|
return header
|
||||||
|
|
@ -191,7 +190,7 @@ func GetBody(db ethdb.Database, hash common.Hash, number uint64) *types.Body {
|
||||||
}
|
}
|
||||||
body := new(types.Body)
|
body := new(types.Body)
|
||||||
if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
|
if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
|
||||||
glog.V(logger.Error).Infof("invalid block body RLP for hash %x: %v", hash, err)
|
log.Error("Invalid block body RLP", "hash", hash, "err", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return body
|
return body
|
||||||
|
|
@ -209,7 +208,7 @@ func GetTd(db ethdb.Database, hash common.Hash, number uint64) *big.Int {
|
||||||
}
|
}
|
||||||
td := new(big.Int)
|
td := new(big.Int)
|
||||||
if err := rlp.Decode(bytes.NewReader(data), td); err != nil {
|
if err := rlp.Decode(bytes.NewReader(data), td); err != nil {
|
||||||
glog.V(logger.Error).Infof("invalid block total difficulty RLP for hash %x: %v", hash, err)
|
log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return td
|
return td
|
||||||
|
|
@ -247,7 +246,7 @@ func GetBlockReceipts(db ethdb.Database, hash common.Hash, number uint64) types.
|
||||||
}
|
}
|
||||||
storageReceipts := []*types.ReceiptForStorage{}
|
storageReceipts := []*types.ReceiptForStorage{}
|
||||||
if err := rlp.DecodeBytes(data, &storageReceipts); err != nil {
|
if err := rlp.DecodeBytes(data, &storageReceipts); err != nil {
|
||||||
glog.V(logger.Error).Infof("invalid receipt array RLP for hash %x: %v", hash, err)
|
log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
receipts := make(types.Receipts, len(storageReceipts))
|
receipts := make(types.Receipts, len(storageReceipts))
|
||||||
|
|
@ -286,15 +285,15 @@ func GetTransaction(db ethdb.Database, hash common.Hash) (*types.Transaction, co
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReceipt returns a receipt by hash
|
// GetReceipt returns a receipt by hash
|
||||||
func GetReceipt(db ethdb.Database, txHash common.Hash) *types.Receipt {
|
func GetReceipt(db ethdb.Database, hash common.Hash) *types.Receipt {
|
||||||
data, _ := db.Get(append(receiptsPrefix, txHash[:]...))
|
data, _ := db.Get(append(receiptsPrefix, hash[:]...))
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var receipt types.ReceiptForStorage
|
var receipt types.ReceiptForStorage
|
||||||
err := rlp.DecodeBytes(data, &receipt)
|
err := rlp.DecodeBytes(data, &receipt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Debug).Infoln("GetReceipt err:", err)
|
log.Error("Invalid receipt RLP", "hash", hash, "err", err)
|
||||||
}
|
}
|
||||||
return (*types.Receipt)(&receipt)
|
return (*types.Receipt)(&receipt)
|
||||||
}
|
}
|
||||||
|
|
@ -303,7 +302,7 @@ func GetReceipt(db ethdb.Database, txHash common.Hash) *types.Receipt {
|
||||||
func WriteCanonicalHash(db ethdb.Database, hash common.Hash, number uint64) error {
|
func WriteCanonicalHash(db ethdb.Database, hash common.Hash, number uint64) error {
|
||||||
key := append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...)
|
key := append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...)
|
||||||
if err := db.Put(key, hash.Bytes()); err != nil {
|
if err := db.Put(key, hash.Bytes()); err != nil {
|
||||||
glog.Fatalf("failed to store number to hash mapping into database: %v", err)
|
log.Crit("Failed to store number to hash mapping", "err", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -311,7 +310,7 @@ func WriteCanonicalHash(db ethdb.Database, hash common.Hash, number uint64) erro
|
||||||
// WriteHeadHeaderHash stores the head header's hash.
|
// WriteHeadHeaderHash stores the head header's hash.
|
||||||
func WriteHeadHeaderHash(db ethdb.Database, hash common.Hash) error {
|
func WriteHeadHeaderHash(db ethdb.Database, hash common.Hash) error {
|
||||||
if err := db.Put(headHeaderKey, hash.Bytes()); err != nil {
|
if err := db.Put(headHeaderKey, hash.Bytes()); err != nil {
|
||||||
glog.Fatalf("failed to store last header's hash into database: %v", err)
|
log.Crit("Failed to store last header's hash", "err", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -319,7 +318,7 @@ func WriteHeadHeaderHash(db ethdb.Database, hash common.Hash) error {
|
||||||
// WriteHeadBlockHash stores the head block's hash.
|
// WriteHeadBlockHash stores the head block's hash.
|
||||||
func WriteHeadBlockHash(db ethdb.Database, hash common.Hash) error {
|
func WriteHeadBlockHash(db ethdb.Database, hash common.Hash) error {
|
||||||
if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
|
if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
|
||||||
glog.Fatalf("failed to store last block's hash into database: %v", err)
|
log.Crit("Failed to store last block's hash", "err", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -327,7 +326,7 @@ func WriteHeadBlockHash(db ethdb.Database, hash common.Hash) error {
|
||||||
// WriteHeadFastBlockHash stores the fast head block's hash.
|
// WriteHeadFastBlockHash stores the fast head block's hash.
|
||||||
func WriteHeadFastBlockHash(db ethdb.Database, hash common.Hash) error {
|
func WriteHeadFastBlockHash(db ethdb.Database, hash common.Hash) error {
|
||||||
if err := db.Put(headFastKey, hash.Bytes()); err != nil {
|
if err := db.Put(headFastKey, hash.Bytes()); err != nil {
|
||||||
glog.Fatalf("failed to store last fast block's hash into database: %v", err)
|
log.Crit("Failed to store last fast block's hash", "err", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -343,13 +342,12 @@ func WriteHeader(db ethdb.Database, header *types.Header) error {
|
||||||
encNum := encodeBlockNumber(num)
|
encNum := encodeBlockNumber(num)
|
||||||
key := append(blockHashPrefix, hash...)
|
key := append(blockHashPrefix, hash...)
|
||||||
if err := db.Put(key, encNum); err != nil {
|
if err := db.Put(key, encNum); err != nil {
|
||||||
glog.Fatalf("failed to store hash to number mapping into database: %v", err)
|
log.Crit("Failed to store hash to number mapping", "err", err)
|
||||||
}
|
}
|
||||||
key = append(append(headerPrefix, encNum...), hash...)
|
key = append(append(headerPrefix, encNum...), hash...)
|
||||||
if err := db.Put(key, data); err != nil {
|
if err := db.Put(key, data); err != nil {
|
||||||
glog.Fatalf("failed to store header into database: %v", err)
|
log.Crit("Failed to store header", "err", err)
|
||||||
}
|
}
|
||||||
glog.V(logger.Debug).Infof("stored header #%v [%x…]", header.Number, hash[:4])
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -366,9 +364,8 @@ func WriteBody(db ethdb.Database, hash common.Hash, number uint64, body *types.B
|
||||||
func WriteBodyRLP(db ethdb.Database, hash common.Hash, number uint64, rlp rlp.RawValue) error {
|
func WriteBodyRLP(db ethdb.Database, hash common.Hash, number uint64, rlp rlp.RawValue) error {
|
||||||
key := append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
key := append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
if err := db.Put(key, rlp); err != nil {
|
if err := db.Put(key, rlp); err != nil {
|
||||||
glog.Fatalf("failed to store block body into database: %v", err)
|
log.Crit("Failed to store block body", "err", err)
|
||||||
}
|
}
|
||||||
glog.V(logger.Debug).Infof("stored block body [%x…]", hash.Bytes()[:4])
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,9 +377,8 @@ func WriteTd(db ethdb.Database, hash common.Hash, number uint64, td *big.Int) er
|
||||||
}
|
}
|
||||||
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...)
|
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...)
|
||||||
if err := db.Put(key, data); err != nil {
|
if err := db.Put(key, data); err != nil {
|
||||||
glog.Fatalf("failed to store block total difficulty into database: %v", err)
|
log.Crit("Failed to store block total difficulty", "err", err)
|
||||||
}
|
}
|
||||||
glog.V(logger.Debug).Infof("stored block total difficulty [%x…]: %v", hash.Bytes()[:4], td)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -415,9 +411,8 @@ func WriteBlockReceipts(db ethdb.Database, hash common.Hash, number uint64, rece
|
||||||
// Store the flattened receipt slice
|
// Store the flattened receipt slice
|
||||||
key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
if err := db.Put(key, bytes); err != nil {
|
if err := db.Put(key, bytes); err != nil {
|
||||||
glog.Fatalf("failed to store block receipts into database: %v", err)
|
log.Crit("Failed to store block receipts", "err", err)
|
||||||
}
|
}
|
||||||
glog.V(logger.Debug).Infof("stored block receipts [%x…]", hash.Bytes()[:4])
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -435,7 +430,7 @@ func WriteTransactions(db ethdb.Database, block *types.Block) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := batch.Put(tx.Hash().Bytes(), data); err != nil {
|
if err = batch.Put(tx.Hash().Bytes(), data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Encode and queue up the transaction metadata for storage
|
// Encode and queue up the transaction metadata for storage
|
||||||
|
|
@ -458,7 +453,7 @@ func WriteTransactions(db ethdb.Database, block *types.Block) error {
|
||||||
}
|
}
|
||||||
// Write the scheduled data into the database
|
// Write the scheduled data into the database
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
glog.Fatalf("failed to store transactions into database: %v", err)
|
log.Crit("Failed to store transactions", "err", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -490,7 +485,7 @@ func WriteReceipts(db ethdb.Database, receipts types.Receipts) error {
|
||||||
}
|
}
|
||||||
// Write the scheduled data into the database
|
// Write the scheduled data into the database
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
glog.Fatalf("failed to store receipts into database: %v", err)
|
log.Crit("Failed to store receipts", "err", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -540,24 +535,6 @@ func DeleteReceipt(db ethdb.Database, hash common.Hash) {
|
||||||
db.Delete(append(receiptsPrefix, hash.Bytes()...))
|
db.Delete(append(receiptsPrefix, hash.Bytes()...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// [deprecated by the header/block split, remove eventually]
|
|
||||||
// GetBlockByHashOld returns the old combined block corresponding to the hash
|
|
||||||
// or nil if not found. This method is only used by the upgrade mechanism to
|
|
||||||
// access the old combined block representation. It will be dropped after the
|
|
||||||
// network transitions to eth/63.
|
|
||||||
func GetBlockByHashOld(db ethdb.Database, hash common.Hash) *types.Block {
|
|
||||||
data, _ := db.Get(append(oldBlockHashPrefix, hash[:]...))
|
|
||||||
if len(data) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var block types.StorageBlock
|
|
||||||
if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
|
|
||||||
glog.V(logger.Error).Infof("invalid block RLP for hash %x: %v", hash, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return (*types.Block)(&block)
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a formatted MIP mapped key by adding prefix, canonical number and level
|
// returns a formatted MIP mapped key by adding prefix, canonical number and level
|
||||||
//
|
//
|
||||||
// ex. fn(98, 1000) = (prefix || 1000 || 0)
|
// ex. fn(98, 1000) = (prefix || 1000 || 0)
|
||||||
|
|
@ -614,7 +591,7 @@ func WritePreimages(db ethdb.Database, number uint64, preimages map[common.Hash]
|
||||||
for hash, preimage := range preimages {
|
for hash, preimage := range preimages {
|
||||||
if _, err := table.Get(hash.Bytes()); err != nil {
|
if _, err := table.Get(hash.Bytes()); err != nil {
|
||||||
batch.Put(hash.Bytes(), preimage)
|
batch.Put(hash.Bytes(), preimage)
|
||||||
hitCount += 1
|
hitCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
preimageCounter.Inc(int64(len(preimages)))
|
preimageCounter.Inc(int64(len(preimages)))
|
||||||
|
|
@ -623,7 +600,6 @@ func WritePreimages(db ethdb.Database, number uint64, preimages map[common.Hash]
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
return fmt.Errorf("preimage write fail for block %d: %v", number, err)
|
return fmt.Errorf("preimage write fail for block %d: %v", number, err)
|
||||||
}
|
}
|
||||||
glog.V(logger.Debug).Infof("%d preimages in block %d, including %d new", len(preimages), number, hitCount)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/crypto"
|
"github.com/expanse-org/go-expanse/crypto"
|
||||||
"github.com/expanse-org/go-expanse/crypto/sha3"
|
"github.com/expanse-org/go-expanse/crypto/sha3"
|
||||||
|
|
@ -53,11 +54,11 @@ func (d *diffTest) UnmarshalJSON(b []byte) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
d.ParentTimestamp = common.String2Big(ext.ParentTimestamp).Uint64()
|
d.ParentTimestamp = math.MustParseUint64(ext.ParentTimestamp)
|
||||||
d.ParentDifficulty = common.String2Big(ext.ParentDifficulty)
|
d.ParentDifficulty = math.MustParseBig256(ext.ParentDifficulty)
|
||||||
d.CurrentTimestamp = common.String2Big(ext.CurrentTimestamp).Uint64()
|
d.CurrentTimestamp = math.MustParseUint64(ext.CurrentTimestamp)
|
||||||
d.CurrentBlocknumber = common.String2Big(ext.CurrentBlocknumber)
|
d.CurrentBlocknumber = math.MustParseBig256(ext.CurrentBlocknumber)
|
||||||
d.CurrentDifficulty = common.String2Big(ext.CurrentDifficulty)
|
d.CurrentDifficulty = math.MustParseBig256(ext.CurrentDifficulty)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -561,7 +562,7 @@ func TestMipmapChain(t *testing.T) {
|
||||||
)
|
)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)})
|
genesis := testGenesis(addr, big.NewInt(1000000)).MustCommit(db)
|
||||||
chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
|
chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
|
|
|
||||||
106
core/gen_genesis.go
Normal file
106
core/gen_genesis.go
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
// generated by github.com/fjl/gencodec, do not edit.
|
||||||
|
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/hexutil"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
|
"github.com/expanse-org/go-expanse/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (g *Genesis) MarshalJSON() ([]byte, error) {
|
||||||
|
type GenesisJSON struct {
|
||||||
|
ChainConfig *params.ChainConfig `json:"config" optional:"true"`
|
||||||
|
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
|
||||||
|
Timestamp *math.HexOrDecimal64 `json:"timestamp" optional:"true"`
|
||||||
|
ParentHash *common.Hash `json:"parentHash" optional:"true"`
|
||||||
|
ExtraData hexutil.Bytes `json:"extraData" optional:"true"`
|
||||||
|
GasLimit *math.HexOrDecimal64 `json:"gasLimit"`
|
||||||
|
Difficulty *math.HexOrDecimal256 `json:"difficulty"`
|
||||||
|
Mixhash *common.Hash `json:"mixHash" optional:"true"`
|
||||||
|
Coinbase *common.Address `json:"coinbase" optional:"true"`
|
||||||
|
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc"`
|
||||||
|
}
|
||||||
|
var enc GenesisJSON
|
||||||
|
enc.ChainConfig = g.Config
|
||||||
|
enc.Nonce = (*math.HexOrDecimal64)(&g.Nonce)
|
||||||
|
enc.Timestamp = (*math.HexOrDecimal64)(&g.Timestamp)
|
||||||
|
enc.ParentHash = &g.ParentHash
|
||||||
|
if g.ExtraData != nil {
|
||||||
|
enc.ExtraData = g.ExtraData
|
||||||
|
}
|
||||||
|
enc.GasLimit = (*math.HexOrDecimal64)(&g.GasLimit)
|
||||||
|
enc.Difficulty = (*math.HexOrDecimal256)(g.Difficulty)
|
||||||
|
enc.Mixhash = &g.Mixhash
|
||||||
|
enc.Coinbase = &g.Coinbase
|
||||||
|
if g.Alloc != nil {
|
||||||
|
enc.Alloc = make(map[common.UnprefixedAddress]GenesisAccount, len(g.Alloc))
|
||||||
|
for k, v := range g.Alloc {
|
||||||
|
enc.Alloc[common.UnprefixedAddress(k)] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json.Marshal(&enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Genesis) UnmarshalJSON(input []byte) error {
|
||||||
|
type GenesisJSON struct {
|
||||||
|
ChainConfig *params.ChainConfig `json:"config" optional:"true"`
|
||||||
|
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
|
||||||
|
Timestamp *math.HexOrDecimal64 `json:"timestamp" optional:"true"`
|
||||||
|
ParentHash *common.Hash `json:"parentHash" optional:"true"`
|
||||||
|
ExtraData hexutil.Bytes `json:"extraData" optional:"true"`
|
||||||
|
GasLimit *math.HexOrDecimal64 `json:"gasLimit"`
|
||||||
|
Difficulty *math.HexOrDecimal256 `json:"difficulty"`
|
||||||
|
Mixhash *common.Hash `json:"mixHash" optional:"true"`
|
||||||
|
Coinbase *common.Address `json:"coinbase" optional:"true"`
|
||||||
|
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc"`
|
||||||
|
}
|
||||||
|
var dec GenesisJSON
|
||||||
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var x Genesis
|
||||||
|
if dec.ChainConfig != nil {
|
||||||
|
x.Config = dec.ChainConfig
|
||||||
|
}
|
||||||
|
if dec.Nonce != nil {
|
||||||
|
x.Nonce = uint64(*dec.Nonce)
|
||||||
|
}
|
||||||
|
if dec.Timestamp != nil {
|
||||||
|
x.Timestamp = uint64(*dec.Timestamp)
|
||||||
|
}
|
||||||
|
if dec.ParentHash != nil {
|
||||||
|
x.ParentHash = *dec.ParentHash
|
||||||
|
}
|
||||||
|
if dec.ExtraData != nil {
|
||||||
|
x.ExtraData = dec.ExtraData
|
||||||
|
}
|
||||||
|
if dec.GasLimit == nil {
|
||||||
|
return errors.New("missing required field 'gasLimit' for Genesis")
|
||||||
|
}
|
||||||
|
x.GasLimit = uint64(*dec.GasLimit)
|
||||||
|
if dec.Difficulty == nil {
|
||||||
|
return errors.New("missing required field 'difficulty' for Genesis")
|
||||||
|
}
|
||||||
|
x.Difficulty = (*big.Int)(dec.Difficulty)
|
||||||
|
if dec.Mixhash != nil {
|
||||||
|
x.Mixhash = *dec.Mixhash
|
||||||
|
}
|
||||||
|
if dec.Coinbase != nil {
|
||||||
|
x.Coinbase = *dec.Coinbase
|
||||||
|
}
|
||||||
|
if dec.Alloc == nil {
|
||||||
|
return errors.New("missing required field 'alloc' for Genesis")
|
||||||
|
}
|
||||||
|
x.Alloc = make(GenesisAlloc, len(dec.Alloc))
|
||||||
|
for k, v := range dec.Alloc {
|
||||||
|
x.Alloc[common.Address(k)] = v
|
||||||
|
}
|
||||||
|
*g = x
|
||||||
|
return nil
|
||||||
|
}
|
||||||
61
core/gen_genesis_account.go
Normal file
61
core/gen_genesis_account.go
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
// generated by github.com/fjl/gencodec, do not edit.
|
||||||
|
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/hexutil"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (g *GenesisAccount) MarshalJSON() ([]byte, error) {
|
||||||
|
type GenesisAccountJSON struct {
|
||||||
|
Code hexutil.Bytes `json:"code" optional:"true"`
|
||||||
|
Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
|
||||||
|
Balance *math.HexOrDecimal256 `json:"balance"`
|
||||||
|
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
|
||||||
|
}
|
||||||
|
var enc GenesisAccountJSON
|
||||||
|
if g.Code != nil {
|
||||||
|
enc.Code = g.Code
|
||||||
|
}
|
||||||
|
if g.Storage != nil {
|
||||||
|
enc.Storage = g.Storage
|
||||||
|
}
|
||||||
|
enc.Balance = (*math.HexOrDecimal256)(g.Balance)
|
||||||
|
enc.Nonce = (*math.HexOrDecimal64)(&g.Nonce)
|
||||||
|
return json.Marshal(&enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GenesisAccount) UnmarshalJSON(input []byte) error {
|
||||||
|
type GenesisAccountJSON struct {
|
||||||
|
Code hexutil.Bytes `json:"code" optional:"true"`
|
||||||
|
Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
|
||||||
|
Balance *math.HexOrDecimal256 `json:"balance"`
|
||||||
|
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
|
||||||
|
}
|
||||||
|
var dec GenesisAccountJSON
|
||||||
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var x GenesisAccount
|
||||||
|
if dec.Code != nil {
|
||||||
|
x.Code = dec.Code
|
||||||
|
}
|
||||||
|
if dec.Storage != nil {
|
||||||
|
x.Storage = dec.Storage
|
||||||
|
}
|
||||||
|
if dec.Balance == nil {
|
||||||
|
return errors.New("missing required field 'balance' for GenesisAccount")
|
||||||
|
}
|
||||||
|
x.Balance = (*big.Int)(dec.Balance)
|
||||||
|
if dec.Nonce != nil {
|
||||||
|
x.Nonce = uint64(*dec.Nonce)
|
||||||
|
}
|
||||||
|
*g = x
|
||||||
|
return nil
|
||||||
|
}
|
||||||
376
core/genesis.go
376
core/genesis.go
|
|
@ -17,200 +17,286 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"compress/bzip2"
|
"errors"
|
||||||
"compress/gzip"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/common/hexutil"
|
||||||
|
"github.com/expanse-org/go-expanse/common/math"
|
||||||
"github.com/expanse-org/go-expanse/core/state"
|
"github.com/expanse-org/go-expanse/core/state"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
|
"github.com/expanse-org/go-expanse/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteGenesisBlock writes the genesis block to the database as block number 0
|
//go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
|
||||||
func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, error) {
|
//go:generate gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go
|
||||||
contents, err := ioutil.ReadAll(reader)
|
|
||||||
|
var errGenesisNoConfig = errors.New("genesis has no chain configuration")
|
||||||
|
|
||||||
|
// Genesis specifies the header fields, state of a genesis block. It also defines hard
|
||||||
|
// fork switch-over blocks through the chain configuration.
|
||||||
|
type Genesis struct {
|
||||||
|
Config *params.ChainConfig `json:"config" optional:"true"`
|
||||||
|
Nonce uint64 `json:"nonce" optional:"true"`
|
||||||
|
Timestamp uint64 `json:"timestamp" optional:"true"`
|
||||||
|
ParentHash common.Hash `json:"parentHash" optional:"true"`
|
||||||
|
ExtraData []byte `json:"extraData" optional:"true"`
|
||||||
|
GasLimit uint64 `json:"gasLimit"`
|
||||||
|
Difficulty *big.Int `json:"difficulty"`
|
||||||
|
Mixhash common.Hash `json:"mixHash" optional:"true"`
|
||||||
|
Coinbase common.Address `json:"coinbase" optional:"true"`
|
||||||
|
Alloc GenesisAlloc `json:"alloc"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenesisAlloc specifies the initial state that is part of the genesis block.
|
||||||
|
type GenesisAlloc map[common.Address]GenesisAccount
|
||||||
|
|
||||||
|
// GenesisAccount is an account in the state of the genesis block.
|
||||||
|
type GenesisAccount struct {
|
||||||
|
Code []byte `json:"code" optional:"true"`
|
||||||
|
Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
|
||||||
|
Balance *big.Int `json:"balance"`
|
||||||
|
Nonce uint64 `json:"nonce" optional:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// field type overrides for gencodec
|
||||||
|
type genesisSpecMarshaling struct {
|
||||||
|
Nonce math.HexOrDecimal64
|
||||||
|
Timestamp math.HexOrDecimal64
|
||||||
|
ExtraData hexutil.Bytes
|
||||||
|
GasLimit math.HexOrDecimal64
|
||||||
|
Difficulty *math.HexOrDecimal256
|
||||||
|
Alloc map[common.UnprefixedAddress]GenesisAccount
|
||||||
|
}
|
||||||
|
type genesisAccountMarshaling struct {
|
||||||
|
Code hexutil.Bytes
|
||||||
|
Balance *math.HexOrDecimal256
|
||||||
|
Nonce math.HexOrDecimal64
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenesisMismatchError is raised when trying to overwrite an existing
|
||||||
|
// genesis block with an incompatible one.
|
||||||
|
type GenesisMismatchError struct {
|
||||||
|
Stored, New common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *GenesisMismatchError) Error() string {
|
||||||
|
return fmt.Sprintf("wrong genesis block in database (have %x, new %x)", e.Stored[:8], e.New[:8])
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupGenesisBlock writes or updates the genesis block in db.
|
||||||
|
// The block that will be used is:
|
||||||
|
//
|
||||||
|
// genesis == nil genesis != nil
|
||||||
|
// +------------------------------------------
|
||||||
|
// db has no genesis | main-net default | genesis
|
||||||
|
// db has genesis | from DB | genesis (if compatible)
|
||||||
|
//
|
||||||
|
// The stored chain configuration will be updated if it is compatible (i.e. does not
|
||||||
|
// specify a fork block below the local head block). In case of a conflict, the
|
||||||
|
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
|
||||||
|
//
|
||||||
|
// The returned chain configuration is never nil.
|
||||||
|
func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
|
||||||
|
if genesis != nil && genesis.Config == nil {
|
||||||
|
return params.AllProtocolChanges, common.Hash{}, errGenesisNoConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just commit the new block if there is no stored genesis block.
|
||||||
|
stored := GetCanonicalHash(db, 0)
|
||||||
|
if (stored == common.Hash{}) {
|
||||||
|
if genesis == nil {
|
||||||
|
log.Info("Writing default main-net genesis block")
|
||||||
|
genesis = DefaultGenesisBlock()
|
||||||
|
} else {
|
||||||
|
log.Info("Writing custom genesis block")
|
||||||
|
}
|
||||||
|
block, err := genesis.Commit(db)
|
||||||
|
return genesis.Config, block.Hash(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the genesis block is already written.
|
||||||
|
if genesis != nil {
|
||||||
|
block, _ := genesis.ToBlock()
|
||||||
|
hash := block.Hash()
|
||||||
|
if hash != stored {
|
||||||
|
return genesis.Config, block.Hash(), &GenesisMismatchError{stored, hash}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the existing chain configuration.
|
||||||
|
newcfg := genesis.configOrDefault(stored)
|
||||||
|
storedcfg, err := GetChainConfig(db, stored)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
if err == ChainConfigNotFoundErr {
|
||||||
}
|
// This case happens if a genesis write was interrupted.
|
||||||
|
log.Warn("Found genesis block without chain config")
|
||||||
var genesis struct {
|
err = WriteChainConfig(db, stored, newcfg)
|
||||||
ChainConfig *params.ChainConfig `json:"config"`
|
|
||||||
Nonce string
|
|
||||||
Timestamp string
|
|
||||||
ParentHash string
|
|
||||||
ExtraData string
|
|
||||||
GasLimit string
|
|
||||||
Difficulty string
|
|
||||||
Mixhash string
|
|
||||||
Coinbase string
|
|
||||||
Alloc map[string]struct {
|
|
||||||
Code string
|
|
||||||
Storage map[string]string
|
|
||||||
Balance string
|
|
||||||
Nonce string
|
|
||||||
}
|
}
|
||||||
|
return newcfg, stored, err
|
||||||
|
}
|
||||||
|
// Special case: don't change the existing config of a non-mainnet chain if no new
|
||||||
|
// config is supplied. These chains would get AllProtocolChanges (and a compat error)
|
||||||
|
// if we just continued here.
|
||||||
|
if genesis == nil && stored != params.MainNetGenesisHash {
|
||||||
|
return storedcfg, stored, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(contents, &genesis); err != nil {
|
// Check config compatibility and write the config. Compatibility errors
|
||||||
return nil, err
|
// are returned to the caller unless we're already at block zero.
|
||||||
|
height := GetBlockNumber(db, GetHeadHeaderHash(db))
|
||||||
|
if height == missingNumber {
|
||||||
|
return newcfg, stored, fmt.Errorf("missing block number for head header hash")
|
||||||
}
|
}
|
||||||
|
compatErr := storedcfg.CheckCompatible(newcfg, height)
|
||||||
|
if compatErr != nil && height != 0 && compatErr.RewindTo != 0 {
|
||||||
|
return newcfg, stored, compatErr
|
||||||
|
}
|
||||||
|
return newcfg, stored, WriteChainConfig(db, stored, newcfg)
|
||||||
|
}
|
||||||
|
|
||||||
// creating with empty hash always works
|
func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
|
||||||
statedb, _ := state.New(common.Hash{}, chainDb)
|
switch {
|
||||||
for addr, account := range genesis.Alloc {
|
case g != nil:
|
||||||
address := common.HexToAddress(addr)
|
return g.Config
|
||||||
statedb.AddBalance(address, common.String2Big(account.Balance))
|
case ghash == params.MainNetGenesisHash:
|
||||||
statedb.SetCode(address, common.FromHex(account.Code))
|
return params.MainnetChainConfig
|
||||||
statedb.SetNonce(address, common.String2Big(account.Nonce).Uint64())
|
case ghash == params.TestNetGenesisHash:
|
||||||
|
return params.TestnetChainConfig
|
||||||
|
default:
|
||||||
|
return params.AllProtocolChanges
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBlock creates the block and state of a genesis specification.
|
||||||
|
func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) {
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
statedb, _ := state.New(common.Hash{}, db)
|
||||||
|
for addr, account := range g.Alloc {
|
||||||
|
statedb.AddBalance(addr, account.Balance)
|
||||||
|
statedb.SetCode(addr, account.Code)
|
||||||
|
statedb.SetNonce(addr, account.Nonce)
|
||||||
for key, value := range account.Storage {
|
for key, value := range account.Storage {
|
||||||
statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
|
statedb.SetState(addr, key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root, stateBatch := statedb.CommitBatch(false)
|
root := statedb.IntermediateRoot(false)
|
||||||
|
head := &types.Header{
|
||||||
difficulty := common.String2Big(genesis.Difficulty)
|
Nonce: types.EncodeNonce(g.Nonce),
|
||||||
block := types.NewBlock(&types.Header{
|
Time: new(big.Int).SetUint64(g.Timestamp),
|
||||||
Nonce: types.EncodeNonce(common.String2Big(genesis.Nonce).Uint64()),
|
ParentHash: g.ParentHash,
|
||||||
Time: common.String2Big(genesis.Timestamp),
|
Extra: g.ExtraData,
|
||||||
ParentHash: common.HexToHash(genesis.ParentHash),
|
GasLimit: new(big.Int).SetUint64(g.GasLimit),
|
||||||
Extra: common.FromHex(genesis.ExtraData),
|
Difficulty: g.Difficulty,
|
||||||
GasLimit: common.String2Big(genesis.GasLimit),
|
MixDigest: g.Mixhash,
|
||||||
Difficulty: difficulty,
|
Coinbase: g.Coinbase,
|
||||||
MixDigest: common.HexToHash(genesis.Mixhash),
|
|
||||||
Coinbase: common.HexToAddress(genesis.Coinbase),
|
|
||||||
Root: root,
|
Root: root,
|
||||||
}, nil, nil, nil)
|
|
||||||
|
|
||||||
if block := GetBlock(chainDb, block.Hash(), block.NumberU64()); block != nil {
|
|
||||||
glog.V(logger.Info).Infoln("Genesis block already in chain. Writing canonical number")
|
|
||||||
err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return block, nil
|
|
||||||
}
|
}
|
||||||
|
if g.GasLimit == 0 {
|
||||||
|
head.GasLimit = params.GenesisGasLimit
|
||||||
|
}
|
||||||
|
if g.Difficulty == nil {
|
||||||
|
head.Difficulty = params.GenesisDifficulty
|
||||||
|
}
|
||||||
|
return types.NewBlock(head, nil, nil, nil), statedb
|
||||||
|
}
|
||||||
|
|
||||||
if err := stateBatch.Write(); err != nil {
|
// Commit writes the block and state of a genesis specification to the database.
|
||||||
|
// The block is committed as the canonical head block.
|
||||||
|
func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
|
||||||
|
block, statedb := g.ToBlock()
|
||||||
|
if _, err := statedb.CommitTo(db, false); err != nil {
|
||||||
return nil, fmt.Errorf("cannot write state: %v", err)
|
return nil, fmt.Errorf("cannot write state: %v", err)
|
||||||
}
|
}
|
||||||
if err := WriteTd(chainDb, block.Hash(), block.NumberU64(), difficulty); err != nil {
|
if err := WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := WriteBlock(chainDb, block); err != nil {
|
if err := WriteBlock(db, block); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := WriteBlockReceipts(chainDb, block.Hash(), block.NumberU64(), nil); err != nil {
|
if err := WriteBlockReceipts(db, block.Hash(), block.NumberU64(), nil); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()); err != nil {
|
if err := WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := WriteHeadBlockHash(chainDb, block.Hash()); err != nil {
|
if err := WriteHeadBlockHash(db, block.Hash()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := WriteChainConfig(chainDb, block.Hash(), genesis.ChainConfig); err != nil {
|
if err := WriteHeadHeaderHash(db, block.Hash()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
config := g.Config
|
||||||
return block, nil
|
if config == nil {
|
||||||
|
config = params.AllProtocolChanges
|
||||||
|
}
|
||||||
|
return block, WriteChainConfig(db, block.Hash(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenesisBlockForTesting creates a block in which addr has the given wei balance.
|
// MustCommit writes the genesis block and state to db, panicking on error.
|
||||||
// The state trie of the block is written to db. the passed db needs to contain a state root
|
// The block is committed as the canonical head block.
|
||||||
|
func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
|
||||||
|
block, err := g.Commit(db)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenesisBlockForTesting creates and writes a block in which addr has the given wei balance.
|
||||||
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
|
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
g := Genesis{Alloc: GenesisAlloc{addr: {Balance: balance}}}
|
||||||
obj := statedb.GetOrNewStateObject(addr)
|
return g.MustCommit(db)
|
||||||
obj.SetBalance(balance)
|
}
|
||||||
root, err := statedb.Commit(false)
|
|
||||||
if err != nil {
|
// DefaultGenesisBlock returns the Ethereum main net genesis block.
|
||||||
panic(fmt.Sprintf("cannot write state: %v", err))
|
func DefaultGenesisBlock() *Genesis {
|
||||||
|
return &Genesis{
|
||||||
|
Config: params.MainnetChainConfig,
|
||||||
|
Nonce: 66,
|
||||||
|
ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"),
|
||||||
|
GasLimit: 5000,
|
||||||
|
Difficulty: big.NewInt(17179869184),
|
||||||
|
Alloc: decodePrealloc(mainnetAllocData),
|
||||||
}
|
}
|
||||||
block := types.NewBlock(&types.Header{
|
|
||||||
Difficulty: params.GenesisDifficulty,
|
|
||||||
GasLimit: params.GenesisGasLimit,
|
|
||||||
Root: root,
|
|
||||||
}, nil, nil, nil)
|
|
||||||
return block
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenesisAccount struct {
|
// DefaultTestnetGenesisBlock returns the Ropsten network genesis block.
|
||||||
Address common.Address
|
func DefaultTestnetGenesisBlock() *Genesis {
|
||||||
Balance *big.Int
|
return &Genesis{
|
||||||
}
|
Config: params.TestnetChainConfig,
|
||||||
|
Nonce: 66,
|
||||||
func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount) *types.Block {
|
ExtraData: hexutil.MustDecode("0x3535353535353535353535353535353535353535353535353535353535353535"),
|
||||||
accountJson := "{"
|
GasLimit: 16777216,
|
||||||
for i, account := range accounts {
|
Difficulty: big.NewInt(1048576),
|
||||||
if i != 0 {
|
Alloc: decodePrealloc(testnetAllocData),
|
||||||
accountJson += ","
|
|
||||||
}
|
|
||||||
accountJson += fmt.Sprintf(`"0x%x":{"balance":"0x%x"}`, account.Address, account.Balance.Bytes())
|
|
||||||
}
|
}
|
||||||
accountJson += "}"
|
|
||||||
|
|
||||||
testGenesis := fmt.Sprintf(`{
|
|
||||||
"nonce":"0x%x",
|
|
||||||
"gasLimit":"0x%x",
|
|
||||||
"difficulty":"0x%x",
|
|
||||||
"alloc": %s
|
|
||||||
}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), accountJson)
|
|
||||||
block, _ := WriteGenesisBlock(db, strings.NewReader(testGenesis))
|
|
||||||
return block
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteDefaultGenesisBlock assembles the official Ethereum genesis block and
|
// DevGenesisBlock returns the 'geth --dev' genesis block.
|
||||||
// writes it - along with all associated state - into a chain database.
|
func DevGenesisBlock() *Genesis {
|
||||||
func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
|
return &Genesis{
|
||||||
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock()))
|
Config: params.AllProtocolChanges,
|
||||||
}
|
Nonce: 42,
|
||||||
|
GasLimit: 4712388,
|
||||||
// WriteTestNetGenesisBlock assembles the test network genesis block and
|
Difficulty: big.NewInt(131072),
|
||||||
// writes it - along with all associated state - into a chain database.
|
Alloc: decodePrealloc(devAllocData),
|
||||||
func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
|
|
||||||
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultGenesisBlock assembles a JSON string representing the default Ethereum
|
|
||||||
// genesis block.
|
|
||||||
func DefaultGenesisBlock() string {
|
|
||||||
reader, err := gzip.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultGenesisBlock)))
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to access default genesis: %v", err))
|
|
||||||
}
|
}
|
||||||
blob, err := ioutil.ReadAll(reader)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to load default genesis: %v", err))
|
|
||||||
}
|
|
||||||
return string(blob)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultTestnetGenesisBlock assembles a JSON string representing the default Ethereum
|
func decodePrealloc(data string) GenesisAlloc {
|
||||||
// test network genesis block.
|
var p []struct{ Addr, Balance *big.Int }
|
||||||
func DefaultTestnetGenesisBlock() string {
|
if err := rlp.NewStream(strings.NewReader(data), 0).Decode(&p); err != nil {
|
||||||
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock)))
|
panic(err)
|
||||||
blob, err := ioutil.ReadAll(reader)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to load default genesis: %v", err))
|
|
||||||
}
|
}
|
||||||
return string(blob)
|
ga := make(GenesisAlloc, len(p))
|
||||||
}
|
for _, account := range p {
|
||||||
|
ga[common.BigToAddress(account.Addr)] = GenesisAccount{Balance: account.Balance}
|
||||||
// DevGenesisBlock assembles a JSON string representing a local dev genesis block.
|
|
||||||
func DevGenesisBlock() string {
|
|
||||||
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultDevnetGenesisBlock)))
|
|
||||||
blob, err := ioutil.ReadAll(reader)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to load dev genesis: %v", err))
|
|
||||||
}
|
}
|
||||||
return string(blob)
|
return ga
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
core/genesis_alloc.go
Normal file
25
core/genesis_alloc.go
Normal file
File diff suppressed because one or more lines are too long
161
core/genesis_test.go
Normal file
161
core/genesis_test.go
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/expanse-org/go-expanse/common"
|
||||||
|
"github.com/expanse-org/go-expanse/core/vm"
|
||||||
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
|
"github.com/expanse-org/go-expanse/event"
|
||||||
|
"github.com/expanse-org/go-expanse/params"
|
||||||
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDefaultGenesisBlock(t *testing.T) {
|
||||||
|
block, _ := DefaultGenesisBlock().ToBlock()
|
||||||
|
if block.Hash() != params.MainNetGenesisHash {
|
||||||
|
t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash(), params.MainNetGenesisHash)
|
||||||
|
}
|
||||||
|
block, _ = DefaultTestnetGenesisBlock().ToBlock()
|
||||||
|
if block.Hash() != params.TestNetGenesisHash {
|
||||||
|
t.Errorf("wrong testnet genesis hash, got %v, want %v", block.Hash(), params.TestNetGenesisHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetupGenesis(t *testing.T) {
|
||||||
|
var (
|
||||||
|
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
|
||||||
|
customg = Genesis{
|
||||||
|
Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3)},
|
||||||
|
Alloc: GenesisAlloc{
|
||||||
|
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
oldcustomg = customg
|
||||||
|
)
|
||||||
|
oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
|
||||||
|
wantConfig *params.ChainConfig
|
||||||
|
wantHash common.Hash
|
||||||
|
wantErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "genesis without ChainConfig",
|
||||||
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||||
|
return SetupGenesisBlock(db, new(Genesis))
|
||||||
|
},
|
||||||
|
wantErr: errGenesisNoConfig,
|
||||||
|
wantConfig: params.AllProtocolChanges,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no block in DB, genesis == nil",
|
||||||
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||||
|
return SetupGenesisBlock(db, nil)
|
||||||
|
},
|
||||||
|
wantHash: params.MainNetGenesisHash,
|
||||||
|
wantConfig: params.MainnetChainConfig,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mainnet block in DB, genesis == nil",
|
||||||
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||||
|
DefaultGenesisBlock().MustCommit(db)
|
||||||
|
return SetupGenesisBlock(db, nil)
|
||||||
|
},
|
||||||
|
wantHash: params.MainNetGenesisHash,
|
||||||
|
wantConfig: params.MainnetChainConfig,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom block in DB, genesis == nil",
|
||||||
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||||
|
customg.MustCommit(db)
|
||||||
|
return SetupGenesisBlock(db, nil)
|
||||||
|
},
|
||||||
|
wantHash: customghash,
|
||||||
|
wantConfig: customg.Config,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom block in DB, genesis == testnet",
|
||||||
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||||
|
customg.MustCommit(db)
|
||||||
|
return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
|
||||||
|
},
|
||||||
|
wantErr: &GenesisMismatchError{Stored: customghash, New: params.TestNetGenesisHash},
|
||||||
|
wantHash: params.TestNetGenesisHash,
|
||||||
|
wantConfig: params.TestnetChainConfig,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "compatible config in DB",
|
||||||
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||||
|
oldcustomg.MustCommit(db)
|
||||||
|
return SetupGenesisBlock(db, &customg)
|
||||||
|
},
|
||||||
|
wantHash: customghash,
|
||||||
|
wantConfig: customg.Config,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "incompatible config in DB",
|
||||||
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||||
|
// Commit the 'old' genesis block with Homestead transition at #2.
|
||||||
|
// Advance to block #4, past the homestead transition block of customg.
|
||||||
|
genesis := oldcustomg.MustCommit(db)
|
||||||
|
bc, _ := NewBlockChain(db, oldcustomg.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
|
||||||
|
bc.SetValidator(bproc{})
|
||||||
|
bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
|
||||||
|
bc.CurrentBlock()
|
||||||
|
// This should return a compatibility error.
|
||||||
|
return SetupGenesisBlock(db, &customg)
|
||||||
|
},
|
||||||
|
wantHash: customghash,
|
||||||
|
wantConfig: customg.Config,
|
||||||
|
wantErr: ¶ms.ConfigCompatError{
|
||||||
|
What: "Homestead fork block",
|
||||||
|
StoredConfig: big.NewInt(2),
|
||||||
|
NewConfig: big.NewInt(3),
|
||||||
|
RewindTo: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
config, hash, err := test.fn(db)
|
||||||
|
// Check the return values.
|
||||||
|
if !reflect.DeepEqual(err, test.wantErr) {
|
||||||
|
spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
|
||||||
|
t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(config, test.wantConfig) {
|
||||||
|
t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig)
|
||||||
|
}
|
||||||
|
if hash != test.wantHash {
|
||||||
|
t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
|
||||||
|
} else if err == nil {
|
||||||
|
// Check database content.
|
||||||
|
stored := GetBlock(db, test.wantHash, 0)
|
||||||
|
if stored.Hash() != test.wantHash {
|
||||||
|
t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -30,8 +30,7 @@ import (
|
||||||
"github.com/expanse-org/go-expanse/common"
|
"github.com/expanse-org/go-expanse/common"
|
||||||
"github.com/expanse-org/go-expanse/core/types"
|
"github.com/expanse-org/go-expanse/core/types"
|
||||||
"github.com/expanse-org/go-expanse/ethdb"
|
"github.com/expanse-org/go-expanse/ethdb"
|
||||||
"github.com/expanse-org/go-expanse/logger"
|
"github.com/expanse-org/go-expanse/log"
|
||||||
"github.com/expanse-org/go-expanse/logger/glog"
|
|
||||||
"github.com/expanse-org/go-expanse/params"
|
"github.com/expanse-org/go-expanse/params"
|
||||||
"github.com/expanse-org/go-expanse/pow"
|
"github.com/expanse-org/go-expanse/pow"
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
|
|
@ -98,12 +97,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValid
|
||||||
|
|
||||||
hc.genesisHeader = hc.GetHeaderByNumber(0)
|
hc.genesisHeader = hc.GetHeaderByNumber(0)
|
||||||
if hc.genesisHeader == nil {
|
if hc.genesisHeader == nil {
|
||||||
genesisBlock, err := WriteDefaultGenesisBlock(chainDb)
|
return nil, ErrNoGenesis
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
glog.V(logger.Info).Infoln("WARNING: Wrote default expanse genesis block")
|
|
||||||
hc.genesisHeader = genesisBlock.Header()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hc.currentHeader = hc.genesisHeader
|
hc.currentHeader = hc.genesisHeader
|
||||||
|
|
@ -155,12 +149,11 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
|
||||||
|
|
||||||
// Irrelevant of the canonical status, write the td and header to the database
|
// Irrelevant of the canonical status, write the td and header to the database
|
||||||
if err := hc.WriteTd(hash, number, externTd); err != nil {
|
if err := hc.WriteTd(hash, number, externTd); err != nil {
|
||||||
glog.Fatalf("failed to write header total difficulty: %v", err)
|
log.Crit("Failed to write header total difficulty", "err", err)
|
||||||
}
|
}
|
||||||
if err := WriteHeader(hc.chainDb, header); err != nil {
|
if err := WriteHeader(hc.chainDb, header); err != nil {
|
||||||
glog.Fatalf("failed to write header contents: %v", err)
|
log.Crit("Failed to write header content", "err", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the total difficulty is higher than our known, add it to the canonical chain
|
// If the total difficulty is higher than our known, add it to the canonical chain
|
||||||
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
||||||
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
||||||
|
|
@ -186,15 +179,13 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
|
||||||
headNumber = headHeader.Number.Uint64() - 1
|
headNumber = headHeader.Number.Uint64() - 1
|
||||||
headHeader = hc.GetHeader(headHash, headNumber)
|
headHeader = hc.GetHeader(headHash, headNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extend the canonical chain with the new header
|
// Extend the canonical chain with the new header
|
||||||
if err := WriteCanonicalHash(hc.chainDb, hash, number); err != nil {
|
if err := WriteCanonicalHash(hc.chainDb, hash, number); err != nil {
|
||||||
glog.Fatalf("failed to insert header number: %v", err)
|
log.Crit("Failed to insert header number", "err", err)
|
||||||
}
|
}
|
||||||
if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil {
|
if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil {
|
||||||
glog.Fatalf("failed to insert head header hash: %v", err)
|
log.Crit("Failed to insert head header hash", "err", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hc.currentHeaderHash, hc.currentHeader = hash, types.CopyHeader(header)
|
hc.currentHeaderHash, hc.currentHeader = hash, types.CopyHeader(header)
|
||||||
|
|
||||||
status = CanonStatTy
|
status = CanonStatTy
|
||||||
|
|
@ -223,21 +214,19 @@ type WhCallback func(*types.Header) error
|
||||||
// should be done or not. The reason behind the optional check is because some
|
// should be done or not. The reason behind the optional check is because some
|
||||||
// of the header retrieval mechanisms already need to verfy nonces, as well as
|
// of the header retrieval mechanisms already need to verfy nonces, as well as
|
||||||
// because nonces can be verified sparsely, not needing to check each.
|
// because nonces can be verified sparsely, not needing to check each.
|
||||||
func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, writeHeader WhCallback) (int, error) {
|
|
||||||
|
func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
|
||||||
// Do a sanity check that the provided chain is actually ordered and linked
|
// Do a sanity check that the provided chain is actually ordered and linked
|
||||||
for i := 1; i < len(chain); i++ {
|
for i := 1; i < len(chain); i++ {
|
||||||
if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() {
|
if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() {
|
||||||
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
||||||
failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])",
|
log.Error("Non contiguous header insert", "number", chain[i].Number, "hash", chain[i].Hash(),
|
||||||
i-1, chain[i-1].Number.Uint64(), chain[i-1].Hash().Bytes()[:4], i, chain[i].Number.Uint64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash.Bytes()[:4])
|
"parent", chain[i].ParentHash, "prevnumber", chain[i-1].Number, "prevhash", chain[i-1].Hash())
|
||||||
|
|
||||||
glog.V(logger.Error).Info(failure.Error())
|
return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].Number,
|
||||||
return 0, failure
|
chain[i-1].Hash().Bytes()[:4], i, chain[i].Number, chain[i].Hash().Bytes()[:4], chain[i].ParentHash[:4])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Collect some import statistics to report on
|
|
||||||
stats := struct{ processed, ignored int }{}
|
|
||||||
start := time.Now()
|
|
||||||
|
|
||||||
// Generate the list of headers that should be POW verified
|
// Generate the list of headers that should be POW verified
|
||||||
verify := make([]bool, len(chain))
|
verify := make([]bool, len(chain))
|
||||||
|
|
@ -313,11 +302,18 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCallback, start time.Time) (int, error) {
|
||||||
|
// Collect some import statistics to report on
|
||||||
|
stats := struct{ processed, ignored int }{}
|
||||||
// All headers passed verification, import them into the database
|
// All headers passed verification, import them into the database
|
||||||
for i, header := range chain {
|
for i, header := range chain {
|
||||||
// Short circuit insertion if shutting down
|
// Short circuit insertion if shutting down
|
||||||
if hc.procInterrupt() {
|
if hc.procInterrupt() {
|
||||||
glog.V(logger.Debug).Infoln("premature abort during header chain processing")
|
log.Debug("Premature abort during headers processing")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
hash := header.Hash()
|
hash := header.Hash()
|
||||||
|
|
@ -333,13 +329,9 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w
|
||||||
stats.processed++
|
stats.processed++
|
||||||
}
|
}
|
||||||
// Report some public statistics so the user has a clue what's going on
|
// Report some public statistics so the user has a clue what's going on
|
||||||
first, last := chain[0], chain[len(chain)-1]
|
last := chain[len(chain)-1]
|
||||||
|
log.Info("Imported new block headers", "count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)),
|
||||||
ignored := ""
|
"number", last.Number, "hash", last.Hash(), "ignored", stats.ignored)
|
||||||
if stats.ignored > 0 {
|
|
||||||
ignored = fmt.Sprintf(" (%d ignored)", stats.ignored)
|
|
||||||
}
|
|
||||||
glog.V(logger.Info).Infof("imported %4d headers%s in %9v. #%v [%x… / %x…]", stats.processed, ignored, common.PrettyDuration(time.Since(start)), last.Number, first.Hash().Bytes()[:4], last.Hash().Bytes()[:4])
|
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
@ -360,7 +352,7 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
chain = append(chain, next)
|
chain = append(chain, next)
|
||||||
if header.Number.Cmp(common.Big0) == 0 {
|
if header.Number.Sign() == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -446,7 +438,7 @@ func (hc *HeaderChain) CurrentHeader() *types.Header {
|
||||||
// SetCurrentHeader sets the current head header of the canonical chain.
|
// SetCurrentHeader sets the current head header of the canonical chain.
|
||||||
func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
|
func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
|
||||||
if err := WriteHeadHeaderHash(hc.chainDb, head.Hash()); err != nil {
|
if err := WriteHeadHeaderHash(hc.chainDb, head.Hash()); err != nil {
|
||||||
glog.Fatalf("failed to insert head header hash: %v", err)
|
log.Crit("Failed to insert head header hash", "err", err)
|
||||||
}
|
}
|
||||||
hc.currentHeader = head
|
hc.currentHeader = head
|
||||||
hc.currentHeaderHash = head.Hash()
|
hc.currentHeaderHash = head.Hash()
|
||||||
|
|
@ -489,7 +481,7 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
|
||||||
hc.currentHeaderHash = hc.currentHeader.Hash()
|
hc.currentHeaderHash = hc.currentHeader.Hash()
|
||||||
|
|
||||||
if err := WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash); err != nil {
|
if err := WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash); err != nil {
|
||||||
glog.Fatalf("failed to reset head header hash: %v", err)
|
log.Crit("Failed to reset head header hash", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue