Merge pull request #71 from AnilChinchawale/master

XinFin Delegated Proof of Stake
This commit is contained in:
Anil Chinchawale 2019-03-18 16:25:45 +05:30 committed by GitHub
commit 147b94cf77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
246 changed files with 14040 additions and 18472 deletions

View file

@ -1,26 +0,0 @@
Hi there,
please note that this is an issue tracker reserved for bug reports and feature requests.
For general questions please use the gitter channel or the Ethereum stack exchange at https://ethereum.stackexchange.com.
#### System information
Geth version: `geth version`
OS & Version: Windows/Linux/OSX
Commit hash : (if `develop`)
#### Expected behaviour
#### Actual behaviour
#### Steps to reproduce the behaviour
#### Backtrace
````
[backtrace]
````

5
.gitignore vendored
View file

@ -25,7 +25,7 @@ build/_vendor/pkg
# used by the Makefile
/build/_workspace/
/build/bin/
/geth*.zip
/XDC*.zip
# travis
profile.tmp
@ -37,6 +37,9 @@ profile.cov
# VS Code
.vscode
# Vim
.*.sw*
# dashboard
/dashboard/assets/flow-typed
/dashboard/assets/node_modules

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "tests"]
path = tests/testdata
url = https://github.com/ethereum/tests

View file

@ -1,209 +0,0 @@
language: go
go_import_path: github.com/ethereum/go-ethereum
sudo: false
matrix:
include:
- os: linux
dist: trusty
sudo: required
go: 1.9.x
script:
- sudo modprobe fuse
- sudo chmod 666 /dev/fuse
- sudo chown root:$USER /etc/fuse.conf
- go run build/ci.go install
- go run build/ci.go test -coverage
# These are the latest Go versions.
- os: linux
dist: trusty
sudo: required
go: "1.10"
script:
- sudo modprobe fuse
- sudo chmod 666 /dev/fuse
- sudo chown root:$USER /etc/fuse.conf
- go run build/ci.go install
- go run build/ci.go test -coverage
- os: osx
go: "1.10"
script:
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
- brew update
- brew install caskroom/cask/brew-cask
- brew cask install osxfuse
- go run build/ci.go install
- go run build/ci.go test -coverage
# This builder only tests code linters on latest version of Go
- os: linux
dist: trusty
go: "1.10"
env:
- lint
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go lint
# This builder does the Ubuntu PPA upload
- os: linux
dist: trusty
go: "1.10"
env:
- ubuntu-ppa
git:
submodules: false # avoid cloning ethereum/tests
addons:
apt:
packages:
- devscripts
- debhelper
- dput
- fakeroot
script:
- go run build/ci.go debsrc -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -upload ppa:ethereum/ethereum
# This builder does the Linux Azure uploads
- os: linux
dist: trusty
sudo: required
go: "1.10"
env:
- azure-linux
git:
submodules: false # avoid cloning ethereum/tests
addons:
apt:
packages:
- gcc-multilib
script:
# Build for the primary platforms that Trusty can manage
- go run build/ci.go install
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go install -arch 386
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# Switch over GCC to cross compilation (breaks 386, hence why do it here only)
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross
- sudo ln -s /usr/include/asm-generic /usr/include/asm
- GOARM=5 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
- GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- GOARM=6 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
- GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- GOARM=7 go run build/ci.go install -arch arm -cc arm-linux-gnueabihf-gcc
- GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go install -arch arm64 -cc aarch64-linux-gnu-gcc
- 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
services:
- docker
go: "1.10"
env:
- azure-linux-mips
git:
submodules: false # avoid cloning ethereum/tests
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 does the Android Maven and Azure uploads
- os: linux
dist: precise # Needed for the android tools
addons:
apt:
packages:
- oracle-java8-installer
- oracle-java8-set-default
language: android
android:
components:
- platform-tools
- tools
- android-15
- android-19
- android-24
env:
- azure-android
- maven-android
git:
submodules: false # avoid cloning ethereum/tests
before_install:
- curl https://storage.googleapis.com/golang/go1.10.linux-amd64.tar.gz | tar -xz
- export PATH=`pwd`/go/bin:$PATH
- export GOROOT=`pwd`/go
- export GOPATH=$HOME/go
script:
# Build the Android archive and upload it to Maven Central and Azure
- curl https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip -o android-ndk-r15c.zip
- unzip -q android-ndk-r15c.zip && rm android-ndk-r15c.zip
- mv android-ndk-r15c $HOME
- export ANDROID_NDK=$HOME/android-ndk-r15c
- mkdir -p $GOPATH/src/github.com/ethereum
- ln -s `pwd` $GOPATH/src/github.com/ethereum
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
- os: osx
go: "1.10"
env:
- azure-osx
- azure-ios
- cocoapods-ios
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go install
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
# Build the iOS framework and upload it to CocoaPods and Azure
- gem uninstall cocoapods -a -x
- gem install cocoapods
- 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
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git clone --depth=1 https://github.com/CocoaPods/Specs.git ~/.cocoapods/repos/master && pod setup --verbose; fi
- xctool -version
- xcrun simctl list
# Workaround for https://github.com/golang/go/issues/23749
- export CGO_CFLAGS_ALLOW='-fmodules|-fblocks|-fobjc-arc'
- go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
# This builder does the Azure archive purges to avoid accumulating junk
- os: linux
dist: trusty
go: "1.10"
env:
- azure-purge
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go purge -store gethstore/builds -days 14
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
on_success: change
on_failure: always

View file

@ -1,16 +1,23 @@
# Build Geth in a stock Go builder container
FROM golang:1.10-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers
ADD . /go-ethereum
RUN cd /go-ethereum && make geth
ADD . /XDCchain
RUN cd /XDCchain && make XDC
# Pull Geth into a second stage deploy alpine container
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
LABEL maintainer="anil@xinfin.org"
EXPOSE 8545 8546 30303 30303/udp 30304/udp
ENTRYPOINT ["geth"]
WORKDIR /XDCchain
COPY --from=builder /XDCchain/build/bin/XDC /usr/local/bin/XDC
RUN chmod +x /usr/local/bin/XDC
EXPOSE 8545
EXPOSE 30303
ENTRYPOINT ["/usr/local/bin/XDC"]
CMD ["--help"]

View file

@ -1,15 +0,0 @@
# Build Geth in a stock Go builder container
FROM golang:1.10-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers
ADD . /go-ethereum
RUN cd /go-ethereum && make all
# Pull all binaries into a second stage deploy alpine container
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/
EXPOSE 8545 8546 30303 30303/udp 30304/udp

24
Dockerfile.bootnode Normal file
View file

@ -0,0 +1,24 @@
FROM golang:1.10-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers
ADD . /XDCchain
RUN cd /XDCchain && make bootnode
RUN chmod +x /XDCchain/build/bin/bootnode
FROM alpine:latest
LABEL maintainer="anil@xinfin.org"
WORKDIR /XDCchain
COPY --from=builder /XDCchain/build/bin/bootnode /usr/local/bin/bootnode
COPY docker/bootnode ./
EXPOSE 30301
ENTRYPOINT ["./entrypoint.sh"]
CMD ["-verbosity", "6", "-nodekey", "bootnode.key", "--addr", ":30301"]

39
Dockerfile.node Normal file
View file

@ -0,0 +1,39 @@
FROM golang:1.10-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers
ADD . /XDChain
RUN cd /XDChain \
&& make XDC\
&& chmod +x /XDCchain/build/bin/XDC
FROM alpine:latest
LABEL maintainer="anil@xinfin.org"
WORKDIR /XDChain
COPY --from=builder /XDCchain/build/bin/XDC /usr/local/bin/XDC
ENV IDENTITY ''
ENV PASSWORD ''
ENV PRIVATE_KEY ''
ENV BOOTNODES ''
ENV EXTIP ''
ENV VERBOSITY 3
ENV SYNC_MODE 'full'
ENV NETWORK_ID '89'
ENV WS_SECRET ''
ENV NETSTATS_HOST 'netstats-server'
ENV NETSTATS_PORT '3000'
ENV ANNOUNCE_TXS ''
RUN apk add --no-cache ca-certificates
COPY docker/XDChain ./
COPY genesis/ ./
EXPOSE 8545 8546 30303 30303/udp
ENTRYPOINT ["./entrypoint.sh"]

159
Makefile
View file

@ -1,146 +1,93 @@
# This Makefile is meant to be used by people that do not usually work
# with Go source code. If you know what GOPATH is then you probably
# don't need to bother with make.
.PHONY: geth android ios geth-cross swarm evm all test clean
.PHONY: geth-linux geth-linux-386 geth-linux-amd64 geth-linux-mips64 geth-linux-mips64le
.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
.PHONY: geth-windows geth-windows-386 geth-windows-amd64
.PHONY: XDC XDC-cross evm all test clean
.PHONY: XDC-linux XDC-linux-386 XDC-linux-amd64 XDC-linux-mips64 XDC-linux-mips64le
.PHONY: XDC-darwin XDC-darwin-386 XDC-darwin-amd64
GOBIN = $(shell pwd)/build/bin
GOFMT = gofmt
GO ?= latest
GO_PACKAGES = .
GO_FILES := $(shell find $(shell go list -f '{{.Dir}}' $(GO_PACKAGES)) -name \*.go)
geth:
build/env.sh go run build/ci.go install ./cmd/geth
@echo "Done building."
@echo "Run \"$(GOBIN)/geth\" to launch geth."
GIT = git
swarm:
build/env.sh go run build/ci.go install ./cmd/swarm
XDC:
build/env.sh go run build/ci.go install ./cmd/XDC
@echo "Done building."
@echo "Run \"$(GOBIN)/swarm\" to launch swarm."
@echo "Run \"$(GOBIN)/XDC\" to launch XDC."
bootnode:
build/env.sh go run build/ci.go install ./cmd/bootnode
@echo "Done building."
@echo "Run \"$(GOBIN)/bootnode\" to launch a bootnode."
puppeth:
build/env.sh go run build/ci.go install ./cmd/puppeth
@echo "Done building."
@echo "Run \"$(GOBIN)/puppeth\" to launch puppeth."
all:
build/env.sh go run build/ci.go install
android:
build/env.sh go run build/ci.go aar --local
@echo "Done building."
@echo "Import \"$(GOBIN)/geth.aar\" to use the library."
ios:
build/env.sh go run build/ci.go xcode --local
@echo "Done building."
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
test: all
build/env.sh go run build/ci.go test
clean:
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:
env GOBIN= go get -u golang.org/x/tools/cmd/stringer
env GOBIN= go get -u github.com/kevinburke/go-bindata/go-bindata
env GOBIN= go get -u github.com/fjl/gencodec
env GOBIN= go get -u github.com/golang/protobuf/protoc-gen-go
env GOBIN= go install ./cmd/abigen
@type "npm" 2> /dev/null || echo 'Please install node.js and npm'
@type "solc" 2> /dev/null || echo 'Please install solc'
@type "protoc" 2> /dev/null || echo 'Please install protoc'
# Cross Compilation Targets (xgo)
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
XDC-cross: XDC-linux XDC-darwin
@echo "Full cross compilation done:"
@ls -ld $(GOBIN)/geth-*
@ls -ld $(GOBIN)/XDC-*
geth-linux: geth-linux-386 geth-linux-amd64 geth-linux-arm geth-linux-mips64 geth-linux-mips64le
XDC-linux: XDC-linux-386 XDC-linux-amd64 XDC-linux-mips64 XDC-linux-mips64le
@echo "Linux cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-*
@ls -ld $(GOBIN)/XDC-linux-*
geth-linux-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/386 -v ./cmd/geth
XDC-linux-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/386 -v ./cmd/XDC
@echo "Linux 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep 386
@ls -ld $(GOBIN)/XDC-linux-* | grep 386
geth-linux-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/amd64 -v ./cmd/geth
XDC-linux-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/amd64 -v ./cmd/XDC
@echo "Linux amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep amd64
@ls -ld $(GOBIN)/XDC-linux-* | grep amd64
geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
@echo "Linux ARM cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm
geth-linux-arm-5:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-5 -v ./cmd/geth
@echo "Linux ARMv5 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-5
geth-linux-arm-6:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-6 -v ./cmd/geth
@echo "Linux ARMv6 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-6
geth-linux-arm-7:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-7 -v ./cmd/geth
@echo "Linux ARMv7 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-7
geth-linux-arm64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm64 -v ./cmd/geth
@echo "Linux ARM64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm64
geth-linux-mips:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips --ldflags '-extldflags "-static"' -v ./cmd/geth
XDC-linux-mips:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips --ldflags '-extldflags "-static"' -v ./cmd/XDC
@echo "Linux MIPS cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips
@ls -ld $(GOBIN)/XDC-linux-* | grep mips
geth-linux-mipsle:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mipsle --ldflags '-extldflags "-static"' -v ./cmd/geth
XDC-linux-mipsle:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mipsle --ldflags '-extldflags "-static"' -v ./cmd/XDC
@echo "Linux MIPSle cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mipsle
@ls -ld $(GOBIN)/XDC-linux-* | grep mipsle
geth-linux-mips64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64 --ldflags '-extldflags "-static"' -v ./cmd/geth
XDC-linux-mips64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64 --ldflags '-extldflags "-static"' -v ./cmd/XDC
@echo "Linux MIPS64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips64
@ls -ld $(GOBIN)/XDC-linux-* | grep mips64
geth-linux-mips64le:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64le --ldflags '-extldflags "-static"' -v ./cmd/geth
XDC-linux-mips64le:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64le --ldflags '-extldflags "-static"' -v ./cmd/XDC
@echo "Linux MIPS64le cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips64le
@ls -ld $(GOBIN)/XDC-linux-* | grep mips64le
geth-darwin: geth-darwin-386 geth-darwin-amd64
XDC-darwin: XDC-darwin-386 XDC-darwin-amd64
@echo "Darwin cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-*
@ls -ld $(GOBIN)/XDC-darwin-*
geth-darwin-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/386 -v ./cmd/geth
XDC-darwin-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/386 -v ./cmd/XDC
@echo "Darwin 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-* | grep 386
@ls -ld $(GOBIN)/XDC-darwin-* | grep 386
geth-darwin-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/amd64 -v ./cmd/geth
XDC-darwin-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/amd64 -v ./cmd/XDC
@echo "Darwin amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-* | grep amd64
@ls -ld $(GOBIN)/XDC-darwin-* | grep amd64
geth-windows: geth-windows-386 geth-windows-amd64
@echo "Windows cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-*
geth-windows-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=windows/386 -v ./cmd/geth
@echo "Windows 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep 386
geth-windows-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=windows/amd64 -v ./cmd/geth
@echo "Windows amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep amd64
gofmt:
$(GOFMT) -s -w $(GO_FILES)
$(GIT) checkout vendor

314
README.md
View file

@ -1,311 +1,3 @@
## Go Ethereum
Official golang implementation of the Ethereum protocol.
[![API Reference](
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
)](https://godoc.org/github.com/ethereum/go-ethereum)
[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
[![Travis](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Automated builds are available for stable releases and the unstable master branch.
Binary archives are published at https://geth.ethereum.org/downloads/.
## Building the source
For prerequisites and detailed build instructions please read the
[Installation Instructions](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum)
on the wiki.
Building geth requires both a Go (version 1.7 or later) and a C compiler.
You can install them using your favourite package manager.
Once the dependencies are installed, run
make geth
or, to build the full suite of utilities:
make all
## Executables
The go-ethereum project comes with several wrappers/executables found in the `cmd` directory.
| Command | Description |
|:----------:|-------------|
| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default) archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) for command line options. |
| `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) with expanded functionality if the contract bytecode is also available. However it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) wiki page for details. |
| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. |
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. |
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
| `swarm` | swarm daemon and tools. This is the entrypoint for the swarm network. `swarm --help` for command line options and subcommands. See https://swarm-guide.readthedocs.io for swarm documentation. |
| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. |
## Running geth
Going through all the possible command line flags is out of scope here (please consult our
[CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)), but we've
enumerated a few common parameter combos to get you up to speed quickly on how you can run your
own Geth instance.
### Full node on the main Ethereum network
By far the most common scenario is people wanting to simply interact with the Ethereum network:
create accounts; transfer funds; deploy and interact with contracts. For this particular use-case
the user doesn't care about years-old historical data, so we can fast-sync quickly to the current
state of the network. To do so:
```
$ geth console
```
This command will:
* Start geth in fast sync mode (default, can be changed with the `--syncmode` flag), causing it to
download more data in exchange for avoiding processing the entire history of the Ethereum network,
which is very CPU intensive.
* Start up Geth's built-in interactive [JavaScript console](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console),
(via the trailing `console` subcommand) through which you can invoke all official [`web3` methods](https://github.com/ethereum/wiki/wiki/JavaScript-API)
as well as Geth's own [management APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs).
This too is optional and if you leave it out you can always attach to an already running Geth instance
with `geth attach`.
### Full node on the Ethereum test network
Transitioning towards developers, if you'd like to play around with creating Ethereum contracts, you
almost certainly would like to do that without any real money involved until you get the hang of the
entire system. In other words, instead of attaching to the main network, you want to join the **test**
network with your node, which is fully equivalent to the main network, but with play-Ether only.
```
$ geth --testnet console
```
The `console` subcommand have the exact same meaning as above and they are equally useful on the
testnet too. Please see above for their explanations if you've skipped to here.
Specifying the `--testnet` flag however will reconfigure your Geth instance a bit:
* Instead of using the default data directory (`~/.ethereum` on Linux for example), Geth will nest
itself one level deeper into a `testnet` subfolder (`~/.ethereum/testnet` on Linux). Note, on OSX
and Linux this also means that attaching to a running testnet node requires the use of a custom
endpoint since `geth attach` will try to attach to a production node endpoint by default. E.g.
`geth attach <datadir>/testnet/geth.ipc`. Windows users are not affected by this.
* Instead of connecting the main Ethereum network, the client will connect to the test network,
which uses different P2P bootnodes, different network IDs and genesis states.
*Note: Although there are some internal protective measures to prevent transactions from crossing
over between the main network and test network, you should make sure to always use separate accounts
for play-money and real-money. Unless you manually move accounts, Geth will by default correctly
separate the two networks and will not make any accounts available between them.*
### Full node on the Rinkeby test network
The above test network is a cross client one based on the ethash proof-of-work consensus algorithm. As such, it has certain extra overhead and is more susceptible to reorganization attacks due to the network's low difficulty / security. Go Ethereum also supports connecting to a proof-of-authority based test network called [*Rinkeby*](https://www.rinkeby.io) (operated by members of the community). This network is lighter, more secure, but is only supported by go-ethereum.
```
$ geth --rinkeby console
```
### Configuration
As an alternative to passing the numerous flags to the `geth` binary, you can also pass a configuration file via:
```
$ geth --config /path/to/your_config.toml
```
To get an idea how the file should look like you can use the `dumpconfig` subcommand to export your existing configuration:
```
$ geth --your-favourite-flags dumpconfig
```
*Note: This works only with geth v1.6.0 and above.*
#### Docker quick start
One of the quickest ways to get Ethereum up and running on your machine is by using Docker:
```
docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \
-p 8545:8545 -p 30303:30303 \
ethereum/client-go
```
This will start geth in fast-sync mode with a DB memory allowance of 1GB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image.
Do not forget `--rpcaddr 0.0.0.0`, if you want to access RPC from other containers and/or hosts. By default, `geth` binds to the local interface and RPC endpoints is not accessible from the outside.
### Programatically interfacing Geth nodes
As a developer, sooner rather than later you'll want to start interacting with Geth and the Ethereum
network via your own programs and not manually through the console. To aid this, Geth has built in
support for a JSON-RPC based APIs ([standard APIs](https://github.com/ethereum/wiki/wiki/JSON-RPC) and
[Geth specific APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs)). These can be
exposed via HTTP, WebSockets and IPC (unix sockets on unix based platforms, and named pipes on Windows).
The IPC interface is enabled by default and exposes all the APIs supported by Geth, whereas the HTTP
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.
HTTP based JSON-RPC API options:
* `--rpc` Enable the HTTP-RPC server
* `--rpcaddr` HTTP-RPC server listening interface (default: "localhost")
* `--rpcport` HTTP-RPC server listening port (default: 8545)
* `--rpcapi` API's offered over the HTTP-RPC interface (default: "eth,net,web3")
* `--rpccorsdomain` Comma separated list of domains from which to accept cross origin requests (browser enforced)
* `--ws` Enable the WS-RPC server
* `--wsaddr` WS-RPC server listening interface (default: "localhost")
* `--wsport` WS-RPC server listening port (default: 8546)
* `--wsapi` API's offered over the WS-RPC interface (default: "eth,net,web3")
* `--wsorigins` Origins from which to accept websockets requests
* `--ipcdisable` Disable the IPC-RPC server
* `--ipcapi` API's offered over the IPC-RPC interface (default: "admin,debug,eth,miner,net,personal,shh,txpool,web3")
* `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it)
You'll need to use your own programming environments' capabilities (libraries, tools, etc) to connect
via HTTP, WS or IPC to a Geth node configured with the above flags and you'll need to speak [JSON-RPC](http://www.jsonrpc.org/specification)
on all transports. You can reuse the same connection for multiple requests!
**Note: Please understand the security implications of opening up an HTTP/WS based transport before
doing so! Hackers on the internet are actively trying to subvert Ethereum nodes with exposed APIs!
Further, all browser tabs can access locally running webservers, so malicious webpages could try to
subvert locally available APIs!**
### Operating a private network
Maintaining your own private network is more involved as a lot of configurations taken for granted in
the official networks need to be manually set up.
#### Defining the private genesis state
First, you'll need to create the genesis state of your networks, which all nodes need to be aware of
and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`):
```json
{
"config": {
"chainId": 0,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
}
```
The above fields should be fine for most purposes, although we'd recommend changing the `nonce` to
some random value so you prevent unknown remote nodes from being able to connect to you. If you'd
like to pre-fund some accounts for easier testing, you can populate the `alloc` field with account
configs:
```json
"alloc": {
"0x0000000000000000000000000000000000000001": {"balance": "111111111"},
"0x0000000000000000000000000000000000000002": {"balance": "222222222"}
}
```
With the genesis state defined in the above JSON file, you'll need to initialize **every** Geth node
with it prior to starting it up to ensure all blockchain parameters are correctly set:
```
$ geth init path/to/genesis.json
```
#### Creating the rendezvous point
With all nodes that you want to run initialized to the desired genesis state, you'll need to start a
bootstrap node that others can use to find each other in your network and/or over the internet. The
clean way is to configure and run a dedicated bootnode:
```
$ bootnode --genkey=boot.key
$ bootnode --nodekey=boot.key
```
With the bootnode online, it will display an [`enode` URL](https://github.com/ethereum/wiki/wiki/enode-url-format)
that other nodes can use to connect to it and exchange peer information. Make sure to replace the
displayed IP address information (most probably `[::]`) with your externally accessible IP to get the
actual `enode` URL.
*Note: You could also use a full fledged Geth node as a bootnode, but it's the less recommended way.*
#### Starting up your member nodes
With the bootnode operational and externally reachable (you can try `telnet <ip> <port>` to ensure
it's indeed reachable), start every subsequent Geth node pointed to the bootnode for peer discovery
via the `--bootnodes` flag. It will probably also be desirable to keep the data directory of your
private network separated, so do also specify a custom `--datadir` flag.
```
$ geth --datadir=path/to/custom/data/folder --bootnodes=<bootnode-enode-url-from-above>
```
*Note: Since your network will be completely cut off from the main and test networks, you'll also
need to configure a miner to process transactions and create new blocks for you.*
#### Running a private miner
Mining on the public Ethereum network is a complex task as it's only feasible using GPUs, requiring
an OpenCL or CUDA enabled `ethminer` instance. For information on such a setup, please consult the
[EtherMining subreddit](https://www.reddit.com/r/EtherMining/) and the [Genoil miner](https://github.com/Genoil/cpp-ethereum)
repository.
In a private network setting however, a single CPU miner instance is more than enough for practical
purposes as it can produce a stable stream of blocks at the correct intervals without needing heavy
resources (consider running on a single thread, no need for multiple ones either). To start a Geth
instance for mining, run it with all your usual flags, extended by:
```
$ geth <usual-flags> --mine --minerthreads=1 --etherbase=0x0000000000000000000000000000000000000000
```
Which will start mining blocks and transactions on a single CPU thread, crediting all proceedings to
the account specified by `--etherbase`. You can further tune the mining by changing the default gas
limit blocks converge to (`--targetgaslimit`) and the price transactions are accepted at (`--gasprice`).
## Contribution
Thank you for considering to help out with the source code! We welcome contributions from
anyone on the internet, and are grateful for even the smallest of fixes!
If you'd like to contribute to go-ethereum, please fork, fix, commit and send a pull request
for the maintainers to review and merge into the main code base. If you wish to submit more
complex changes though, please check up with the core devs first on [our gitter channel](https://gitter.im/ethereum/go-ethereum)
to ensure those changes are in line with the general philosophy of the project and/or get some
early feedback which can make both your efforts much lighter as well as our review and merge
procedures quick and simple.
Please make sure your contributions adhere to our coding guidelines:
* Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
* Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
* Pull requests need to be based on and opened against the `master` branch.
* Commit messages should be prefixed with the package(s) they modify.
* E.g. "eth, rpc: make trace configs optional"
Please see the [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
for more details on configuring your environment, managing project dependencies and testing procedures.
## License
The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the
[GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html), also
included in our repository in the `COPYING.LESSER` file.
The go-ethereum binaries (i.e. all code inside of the `cmd` directory) is licensed under the
[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), also included
in our repository in the `COPYING` file.
## XinFin
Blockchain for decentralized applications, token issuance and integration
https://xinfin.org

View file

@ -1 +1 @@
1.8.4
0.1.1

View file

@ -157,6 +157,19 @@ func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Addres
return val[:], nil
}
// ForEachStorageAt returns func to read all keys, values in the storage
func (b *SimulatedBackend) ForEachStorageAt(ctx context.Context, contract common.Address, blockNumber *big.Int, f func(key, val common.Hash) bool) error {
b.mu.Lock()
defer b.mu.Unlock()
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
return errBlockNumberUnsupported
}
statedb, _ := b.blockchain.State()
statedb.ForEachStorage(contract, f)
return nil
}
// TransactionReceipt returns the receipt of a transaction.
func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
receipt, _, _, _ := core.GetReceipt(b.database, txHash)

View file

@ -205,7 +205,8 @@ func writeKeyFile(file string, content []byte) error {
// UTC--<created_at UTC ISO8601>-<address hex>
func keyFileName(keyAddr common.Address) string {
ts := time.Now().UTC()
return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:]))
// return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:]))
return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), keyAddr.String())
}
func toISO8601(t time.Time) string {

View file

@ -152,7 +152,8 @@ func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
MAC: hex.EncodeToString(mac),
}
encryptedKeyJSONV3 := encryptedKeyJSONV3{
hex.EncodeToString(key.Address[:]),
// hex.EncodeToString(key.Address[:]),
key.Address.String(),
cryptoStruct,
key.Id.String(),
version,

View file

@ -26,14 +26,8 @@ Available commands are:
install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables
test [ -coverage ] [ packages... ] -- runs the tests
lint -- runs certain pre-selected linters
archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts
importkeys -- imports signing keys from env
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
nsis -- creates a Windows NSIS installer
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
xgo [ -alltools ] [ options ] -- cross builds according to options
purge [ -store blobstore ] [ -days threshold ] -- purges old archives from the blobstore
For all commands, -n prevents execution of external programs (dry run mode).
@ -41,9 +35,6 @@ For all commands, -n prevents execution of external programs (dry run mode).
package main
import (
"bufio"
"bytes"
"encoding/base64"
"flag"
"fmt"
"go/parser"
@ -53,21 +44,13 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strings"
"time"
"github.com/ethereum/go-ethereum/internal/build"
)
var (
// Files that end up in the geth*.zip archive.
gethArchiveFiles = []string{
"COPYING",
executablePath("geth"),
}
// Files that end up in the geth-alltools*.zip archive.
allToolsArchiveFiles = []string{
"COPYING",
@ -80,49 +63,6 @@ var (
executablePath("swarm"),
executablePath("wnode"),
}
// A debian package is created for all executables listed here.
debExecutables = []debExecutable{
{
Name: "abigen",
Description: "Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages.",
},
{
Name: "bootnode",
Description: "Ethereum bootnode.",
},
{
Name: "evm",
Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
},
{
Name: "geth",
Description: "Ethereum CLI client.",
},
{
Name: "puppeth",
Description: "Ethereum private network manager.",
},
{
Name: "rlpdump",
Description: "Developer utility tool that prints RLP structures.",
},
{
Name: "swarm",
Description: "Ethereum Swarm daemon and tools",
},
{
Name: "wnode",
Description: "Ethereum Whisper diagnostic tool",
},
}
// Distros for which packages are created.
// Note: vivid is unsupported because there is no golang-1.6 package for it.
// Note: wily is unsupported because it was officially deprecated on lanchpad.
// Note: yakkety is unsupported because it was officially deprecated on lanchpad.
// Note: zesty is unsupported because it was officially deprecated on lanchpad.
debDistros = []string{"trusty", "xenial", "artful", "bionic"}
)
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
@ -150,20 +90,8 @@ func main() {
doTest(os.Args[2:])
case "lint":
doLint(os.Args[2:])
case "archive":
doArchive(os.Args[2:])
case "debsrc":
doDebianSource(os.Args[2:])
case "nsis":
doWindowsInstaller(os.Args[2:])
case "aar":
doAndroidArchive(os.Args[2:])
case "xcode":
doXCodeFramework(os.Args[2:])
case "xgo":
doXgo(os.Args[2:])
case "purge":
doPurge(os.Args[2:])
default:
log.Fatal("unknown command ", os.Args[1])
}
@ -188,7 +116,7 @@ func doInstall(cmdline []string) {
if minor < 9 {
log.Println("You have Go version", runtime.Version())
log.Println("go-ethereum requires at least Go version 1.9 and cannot")
log.Println("XDC requires at least Go version 1.9 and cannot")
log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
os.Exit(1)
}
@ -345,586 +273,6 @@ func doLint(cmdline []string) {
}
}
// Release Packaging
func doArchive(cmdline []string) {
var (
arch = flag.String("arch", runtime.GOARCH, "Architecture cross packaging")
atype = flag.String("type", "zip", "Type of archive to write (zip|tar)")
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. LINUX_SIGNING_KEY)`)
upload = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`)
ext string
)
flag.CommandLine.Parse(cmdline)
switch *atype {
case "zip":
ext = ".zip"
case "tar":
ext = ".tar.gz"
default:
log.Fatal("unknown archive type: ", atype)
}
var (
env = build.Env()
base = archiveBasename(*arch, env)
geth = "geth-" + base + ext
alltools = "geth-alltools-" + base + ext
)
maybeSkipArchive(env)
if err := build.WriteArchive(geth, gethArchiveFiles); err != nil {
log.Fatal(err)
}
if err := build.WriteArchive(alltools, allToolsArchiveFiles); err != nil {
log.Fatal(err)
}
for _, archive := range []string{geth, alltools} {
if err := archiveUpload(archive, *upload, *signer); err != nil {
log.Fatal(err)
}
}
}
func archiveBasename(arch string, env build.Environment) string {
platform := runtime.GOOS + "-" + arch
if arch == "arm" {
platform += os.Getenv("GOARM")
}
if arch == "android" {
platform = "android-all"
}
if arch == "ios" {
platform = "ios-all"
}
return platform + "-" + archiveVersion(env)
}
func archiveVersion(env build.Environment) string {
version := build.VERSION()
if isUnstableBuild(env) {
version += "-unstable"
}
if env.Commit != "" {
version += "-" + env.Commit[:8]
}
return version
}
func archiveUpload(archive string, blobstore string, signer string) error {
// If signing was requested, generate the signature files
if signer != "" {
pgpkey, err := base64.StdEncoding.DecodeString(os.Getenv(signer))
if err != nil {
return fmt.Errorf("invalid base64 %s", signer)
}
if err := build.PGPSignFile(archive, archive+".asc", string(pgpkey)); err != nil {
return err
}
}
// If uploading to Azure was requested, push the archive possibly with its signature
if blobstore != "" {
auth := build.AzureBlobstoreConfig{
Account: strings.Split(blobstore, "/")[0],
Token: os.Getenv("AZURE_BLOBSTORE_TOKEN"),
Container: strings.SplitN(blobstore, "/", 2)[1],
}
if err := build.AzureBlobstoreUpload(archive, filepath.Base(archive), auth); err != nil {
return err
}
if signer != "" {
if err := build.AzureBlobstoreUpload(archive+".asc", filepath.Base(archive+".asc"), auth); err != nil {
return err
}
}
}
return nil
}
// skips archiving for some build configurations.
func maybeSkipArchive(env build.Environment) {
if env.IsPullRequest {
log.Printf("skipping because this is a PR build")
os.Exit(0)
}
if env.IsCronJob {
log.Printf("skipping because this is a cron job")
os.Exit(0)
}
if env.Branch != "master" && !strings.HasPrefix(env.Tag, "v1.") {
log.Printf("skipping because branch %q, tag %q is not on the whitelist", env.Branch, env.Tag)
os.Exit(0)
}
}
// Debian Packaging
func doDebianSource(cmdline []string) {
var (
signer = flag.String("signer", "", `Signing key name, also used as package author`)
upload = flag.String("upload", "", `Where to upload the source package (usually "ppa:ethereum/ethereum")`)
workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`)
now = time.Now()
)
flag.CommandLine.Parse(cmdline)
*workdir = makeWorkdir(*workdir)
env := build.Env()
maybeSkipArchive(env)
// Import the signing key.
if b64key := os.Getenv("PPA_SIGNING_KEY"); b64key != "" {
key, err := base64.StdEncoding.DecodeString(b64key)
if err != nil {
log.Fatal("invalid base64 PPA_SIGNING_KEY")
}
gpg := exec.Command("gpg", "--import")
gpg.Stdin = bytes.NewReader(key)
build.MustRun(gpg)
}
// Create the packages.
for _, distro := range debDistros {
meta := newDebMetadata(distro, *signer, env, now)
pkgdir := stageDebianSource(*workdir, meta)
debuild := exec.Command("debuild", "-S", "-sa", "-us", "-uc")
debuild.Dir = pkgdir
build.MustRun(debuild)
changes := fmt.Sprintf("%s_%s_source.changes", meta.Name(), meta.VersionString())
changes = filepath.Join(*workdir, changes)
if *signer != "" {
build.MustRunCommand("debsign", changes)
}
if *upload != "" {
build.MustRunCommand("dput", *upload, changes)
}
}
}
func makeWorkdir(wdflag string) string {
var err error
if wdflag != "" {
err = os.MkdirAll(wdflag, 0744)
} else {
wdflag, err = ioutil.TempDir("", "geth-build-")
}
if err != nil {
log.Fatal(err)
}
return wdflag
}
func isUnstableBuild(env build.Environment) bool {
if env.Tag != "" {
return false
}
return true
}
type debMetadata struct {
Env build.Environment
// go-ethereum version being built. Note that this
// is not the debian package version. The package version
// is constructed by VersionString.
Version string
Author string // "name <email>", also selects signing key
Distro, Time string
Executables []debExecutable
}
type debExecutable struct {
Name, Description string
}
func newDebMetadata(distro, author string, env build.Environment, t time.Time) debMetadata {
if author == "" {
// No signing key, use default author.
author = "Ethereum Builds <fjl@ethereum.org>"
}
return debMetadata{
Env: env,
Author: author,
Distro: distro,
Version: build.VERSION(),
Time: t.Format(time.RFC1123Z),
Executables: debExecutables,
}
}
// Name returns the name of the metapackage that depends
// on all executable packages.
func (meta debMetadata) Name() string {
if isUnstableBuild(meta.Env) {
return "ethereum-unstable"
}
return "ethereum"
}
// VersionString returns the debian version of the packages.
func (meta debMetadata) VersionString() string {
vsn := meta.Version
if meta.Env.Buildnum != "" {
vsn += "+build" + meta.Env.Buildnum
}
if meta.Distro != "" {
vsn += "+" + meta.Distro
}
return vsn
}
// ExeList returns the list of all executable packages.
func (meta debMetadata) ExeList() string {
names := make([]string, len(meta.Executables))
for i, e := range meta.Executables {
names[i] = meta.ExeName(e)
}
return strings.Join(names, ", ")
}
// ExeName returns the package name of an executable package.
func (meta debMetadata) ExeName(exe debExecutable) string {
if isUnstableBuild(meta.Env) {
return exe.Name + "-unstable"
}
return exe.Name
}
// ExeConflicts returns the content of the Conflicts field
// for executable packages.
func (meta debMetadata) ExeConflicts(exe debExecutable) string {
if isUnstableBuild(meta.Env) {
// Set up the conflicts list so that the *-unstable packages
// cannot be installed alongside the regular version.
//
// https://www.debian.org/doc/debian-policy/ch-relationships.html
// is very explicit about Conflicts: and says that Breaks: should
// be preferred and the conflicting files should be handled via
// alternates. We might do this eventually but using a conflict is
// easier now.
return "ethereum, " + exe.Name
}
return ""
}
func stageDebianSource(tmpdir string, meta debMetadata) (pkgdir string) {
pkg := meta.Name() + "-" + meta.VersionString()
pkgdir = filepath.Join(tmpdir, pkg)
if err := os.Mkdir(pkgdir, 0755); err != nil {
log.Fatal(err)
}
// Copy the source code.
build.MustRunCommand("git", "checkout-index", "-a", "--prefix", pkgdir+string(filepath.Separator))
// Put the debian build files in place.
debian := filepath.Join(pkgdir, "debian")
build.Render("build/deb.rules", filepath.Join(debian, "rules"), 0755, meta)
build.Render("build/deb.changelog", filepath.Join(debian, "changelog"), 0644, meta)
build.Render("build/deb.control", filepath.Join(debian, "control"), 0644, meta)
build.Render("build/deb.copyright", filepath.Join(debian, "copyright"), 0644, meta)
build.RenderString("8\n", filepath.Join(debian, "compat"), 0644, meta)
build.RenderString("3.0 (native)\n", filepath.Join(debian, "source/format"), 0644, meta)
for _, exe := range meta.Executables {
install := filepath.Join(debian, meta.ExeName(exe)+".install")
docs := filepath.Join(debian, meta.ExeName(exe)+".docs")
build.Render("build/deb.install", install, 0644, exe)
build.Render("build/deb.docs", docs, 0644, exe)
}
return pkgdir
}
// Windows installer
func doWindowsInstaller(cmdline []string) {
// Parse the flags and make skip installer generation on PRs
var (
arch = flag.String("arch", runtime.GOARCH, "Architecture for cross build packaging")
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. WINDOWS_SIGNING_KEY)`)
upload = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`)
workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`)
)
flag.CommandLine.Parse(cmdline)
*workdir = makeWorkdir(*workdir)
env := build.Env()
maybeSkipArchive(env)
// Aggregate binaries that are included in the installer
var (
devTools []string
allTools []string
gethTool string
)
for _, file := range allToolsArchiveFiles {
if file == "COPYING" { // license, copied later
continue
}
allTools = append(allTools, filepath.Base(file))
if filepath.Base(file) == "geth.exe" {
gethTool = file
} else {
devTools = append(devTools, file)
}
}
// Render NSIS scripts: Installer NSIS contains two installer sections,
// first section contains the geth binary, second section holds the dev tools.
templateData := map[string]interface{}{
"License": "COPYING",
"Geth": gethTool,
"DevTools": devTools,
}
build.Render("build/nsis.geth.nsi", filepath.Join(*workdir, "geth.nsi"), 0644, nil)
build.Render("build/nsis.install.nsh", filepath.Join(*workdir, "install.nsh"), 0644, templateData)
build.Render("build/nsis.uninstall.nsh", filepath.Join(*workdir, "uninstall.nsh"), 0644, allTools)
build.Render("build/nsis.pathupdate.nsh", filepath.Join(*workdir, "PathUpdate.nsh"), 0644, nil)
build.Render("build/nsis.envvarupdate.nsh", filepath.Join(*workdir, "EnvVarUpdate.nsh"), 0644, nil)
build.CopyFile(filepath.Join(*workdir, "SimpleFC.dll"), "build/nsis.simplefc.dll", 0755)
build.CopyFile(filepath.Join(*workdir, "COPYING"), "COPYING", 0755)
// Build the installer. This assumes that all the needed files have been previously
// built (don't mix building and packaging to keep cross compilation complexity to a
// minimum).
version := strings.Split(build.VERSION(), ".")
if env.Commit != "" {
version[2] += "-" + env.Commit[:8]
}
installer, _ := filepath.Abs("geth-" + archiveBasename(*arch, env) + ".exe")
build.MustRunCommand("makensis.exe",
"/DOUTPUTFILE="+installer,
"/DMAJORVERSION="+version[0],
"/DMINORVERSION="+version[1],
"/DBUILDVERSION="+version[2],
"/DARCH="+*arch,
filepath.Join(*workdir, "geth.nsi"),
)
// Sign and publish installer.
if err := archiveUpload(installer, *upload, *signer); err != nil {
log.Fatal(err)
}
}
// Android archives
func doAndroidArchive(cmdline []string) {
var (
local = flag.Bool("local", false, `Flag whether we're only doing a local build (skip Maven artifacts)`)
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. ANDROID_SIGNING_KEY)`)
deploy = flag.String("deploy", "", `Destination to deploy the archive (usually "https://oss.sonatype.org")`)
upload = flag.String("upload", "", `Destination to upload the archive (usually "gethstore/builds")`)
)
flag.CommandLine.Parse(cmdline)
env := build.Env()
// Sanity check that the SDK and NDK are installed and set
if os.Getenv("ANDROID_HOME") == "" {
log.Fatal("Please ensure ANDROID_HOME points to your Android SDK")
}
if os.Getenv("ANDROID_NDK") == "" {
log.Fatal("Please ensure ANDROID_NDK points to your Android NDK")
}
// Build the Android archive and Maven resources
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK")))
build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile"))
if *local {
// If we're building locally, copy bundle to build dir and skip Maven
os.Rename("geth.aar", filepath.Join(GOBIN, "geth.aar"))
return
}
meta := newMavenMetadata(env)
build.Render("build/mvn.pom", meta.Package+".pom", 0755, meta)
// Skip Maven deploy and Azure upload for PR builds
maybeSkipArchive(env)
// Sign and upload the archive to Azure
archive := "geth-" + archiveBasename("android", env) + ".aar"
os.Rename("geth.aar", archive)
if err := archiveUpload(archive, *upload, *signer); err != nil {
log.Fatal(err)
}
// Sign and upload all the artifacts to Maven Central
os.Rename(archive, meta.Package+".aar")
if *signer != "" && *deploy != "" {
// Import the signing key into the local GPG instance
if b64key := os.Getenv(*signer); b64key != "" {
key, err := base64.StdEncoding.DecodeString(b64key)
if err != nil {
log.Fatalf("invalid base64 %s", *signer)
}
gpg := exec.Command("gpg", "--import")
gpg.Stdin = bytes.NewReader(key)
build.MustRun(gpg)
}
// Upload the artifacts to Sonatype and/or Maven Central
repo := *deploy + "/service/local/staging/deploy/maven2"
if meta.Develop {
repo = *deploy + "/content/repositories/snapshots"
}
build.MustRunCommand("mvn", "gpg:sign-and-deploy-file",
"-settings=build/mvn.settings", "-Durl="+repo, "-DrepositoryId=ossrh",
"-DpomFile="+meta.Package+".pom", "-Dfile="+meta.Package+".aar")
}
}
func gomobileTool(subcmd string, args ...string) *exec.Cmd {
cmd := exec.Command(filepath.Join(GOBIN, "gomobile"), subcmd)
cmd.Args = append(cmd.Args, args...)
cmd.Env = []string{
"GOPATH=" + build.GOPATH(),
"PATH=" + GOBIN + string(os.PathListSeparator) + os.Getenv("PATH"),
}
for _, e := range os.Environ() {
if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "PATH=") {
continue
}
cmd.Env = append(cmd.Env, e)
}
return cmd
}
type mavenMetadata struct {
Version string
Package string
Develop bool
Contributors []mavenContributor
}
type mavenContributor struct {
Name string
Email string
}
func newMavenMetadata(env build.Environment) mavenMetadata {
// Collect the list of authors from the repo root
contribs := []mavenContributor{}
if authors, err := os.Open("AUTHORS"); err == nil {
defer authors.Close()
scanner := bufio.NewScanner(authors)
for scanner.Scan() {
// Skip any whitespace from the authors list
line := strings.TrimSpace(scanner.Text())
if line == "" || line[0] == '#' {
continue
}
// Split the author and insert as a contributor
re := regexp.MustCompile("([^<]+) <(.+)>")
parts := re.FindStringSubmatch(line)
if len(parts) == 3 {
contribs = append(contribs, mavenContributor{Name: parts[1], Email: parts[2]})
}
}
}
// Render the version and package strings
version := build.VERSION()
if isUnstableBuild(env) {
version += "-SNAPSHOT"
}
return mavenMetadata{
Version: version,
Package: "geth-" + version,
Develop: isUnstableBuild(env),
Contributors: contribs,
}
}
// XCode frameworks
func doXCodeFramework(cmdline []string) {
var (
local = flag.Bool("local", false, `Flag whether we're only doing a local build (skip Maven artifacts)`)
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. IOS_SIGNING_KEY)`)
deploy = flag.String("deploy", "", `Destination to deploy the archive (usually "trunk")`)
upload = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`)
)
flag.CommandLine.Parse(cmdline)
env := build.Env()
// Build the iOS XCode framework
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
build.MustRun(gomobileTool("init"))
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
if *local {
// If we're building locally, use the build folder and stop afterwards
bind.Dir, _ = filepath.Abs(GOBIN)
build.MustRun(bind)
return
}
archive := "geth-" + archiveBasename("ios", env)
if err := os.Mkdir(archive, os.ModePerm); err != nil {
log.Fatal(err)
}
bind.Dir, _ = filepath.Abs(archive)
build.MustRun(bind)
build.MustRunCommand("tar", "-zcvf", archive+".tar.gz", archive)
// Skip CocoaPods deploy and Azure upload for PR builds
maybeSkipArchive(env)
// Sign and upload the framework to Azure
if err := archiveUpload(archive+".tar.gz", *upload, *signer); err != nil {
log.Fatal(err)
}
// Prepare and upload a PodSpec to CocoaPods
if *deploy != "" {
meta := newPodMetadata(env, archive)
build.Render("build/pod.podspec", "Geth.podspec", 0755, meta)
build.MustRunCommand("pod", *deploy, "push", "Geth.podspec", "--allow-warnings", "--verbose")
}
}
type podMetadata struct {
Version string
Commit string
Archive string
Contributors []podContributor
}
type podContributor struct {
Name string
Email string
}
func newPodMetadata(env build.Environment, archive string) podMetadata {
// Collect the list of authors from the repo root
contribs := []podContributor{}
if authors, err := os.Open("AUTHORS"); err == nil {
defer authors.Close()
scanner := bufio.NewScanner(authors)
for scanner.Scan() {
// Skip any whitespace from the authors list
line := strings.TrimSpace(scanner.Text())
if line == "" || line[0] == '#' {
continue
}
// Split the author and insert as a contributor
re := regexp.MustCompile("([^<]+) <(.+)>")
parts := re.FindStringSubmatch(line)
if len(parts) == 3 {
contribs = append(contribs, podContributor{Name: parts[1], Email: parts[2]})
}
}
}
version := build.VERSION()
if isUnstableBuild(env) {
version += "-unstable." + env.Buildnum
}
return podMetadata{
Archive: archive,
Version: version,
Commit: env.Commit,
Contributors: contribs,
}
}
// Cross compilation
func doXgo(cmdline []string) {
@ -976,62 +324,3 @@ func xgoTool(args []string) *exec.Cmd {
}
return cmd
}
// Binary distribution cleanups
func doPurge(cmdline []string) {
var (
store = flag.String("store", "", `Destination from where to purge archives (usually "gethstore/builds")`)
limit = flag.Int("days", 30, `Age threshold above which to delete unstalbe archives`)
)
flag.CommandLine.Parse(cmdline)
if env := build.Env(); !env.IsCronJob {
log.Printf("skipping because not a cron job")
os.Exit(0)
}
// Create the azure authentication and list the current archives
auth := build.AzureBlobstoreConfig{
Account: strings.Split(*store, "/")[0],
Token: os.Getenv("AZURE_BLOBSTORE_TOKEN"),
Container: strings.SplitN(*store, "/", 2)[1],
}
blobs, err := build.AzureBlobstoreList(auth)
if err != nil {
log.Fatal(err)
}
// Iterate over the blobs, collect and sort all unstable builds
for i := 0; i < len(blobs); i++ {
if !strings.Contains(blobs[i].Name, "unstable") {
blobs = append(blobs[:i], blobs[i+1:]...)
i--
}
}
for i := 0; i < len(blobs); i++ {
for j := i + 1; j < len(blobs); j++ {
iTime, err := time.Parse(time.RFC1123, blobs[i].Properties.LastModified)
if err != nil {
log.Fatal(err)
}
jTime, err := time.Parse(time.RFC1123, blobs[j].Properties.LastModified)
if err != nil {
log.Fatal(err)
}
if iTime.After(jTime) {
blobs[i], blobs[j] = blobs[j], blobs[i]
}
}
}
// Filter out all archives more recent that the given threshold
for i, blob := range blobs {
timestamp, _ := time.Parse(time.RFC1123, blob.Properties.LastModified)
if time.Since(timestamp) < time.Duration(*limit)*24*time.Hour {
blobs = blobs[:i]
break
}
}
// Delete all marked as such and return
if err := build.AzureBlobstoreDelete(auth, blobs); err != nil {
log.Fatal(err)
}
}

View file

@ -1,5 +0,0 @@
{{.Name}} ({{.VersionString}}) {{.Distro}}; urgency=low
* git build of {{.Env.Commit}}
-- {{.Author}} {{.Time}}

View file

@ -1,25 +0,0 @@
Source: {{.Name}}
Section: science
Priority: extra
Maintainer: {{.Author}}
Build-Depends: debhelper (>= 8.0.0), golang-1.10
Standards-Version: 3.9.5
Homepage: https://ethereum.org
Vcs-Git: git://github.com/ethereum/go-ethereum.git
Vcs-Browser: https://github.com/ethereum/go-ethereum
Package: {{.Name}}
Architecture: any
Depends: ${misc:Depends}, {{.ExeList}}
Description: Meta-package to install geth and other tools
Meta-package to install geth and other tools
{{range .Executables}}
Package: {{$.ExeName .}}
Conflicts: {{$.ExeConflicts .}}
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Built-Using: ${misc:Built-Using}
Description: {{.Description}}
{{.Description}}
{{end}}

View file

@ -1,14 +0,0 @@
Copyright 2016 The go-ethereum Authors
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/>.

View file

@ -1 +0,0 @@
AUTHORS

View file

@ -1 +0,0 @@
build/bin/{{.Name}} usr/bin

View file

@ -1,13 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
override_dh_auto_build:
build/env.sh /usr/lib/go-1.10/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
override_dh_auto_test:
%:
dh $@

View file

@ -1,57 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.ethereum</groupId>
<artifactId>geth</artifactId>
<version>{{.Version}}</version>
<packaging>aar</packaging>
<name>Android Ethereum Client</name>
<description>Android port of the go-ethereum libraries and node</description>
<url>https://github.com/ethereum/go-ethereum</url>
<inceptionYear>2015</inceptionYear>
<licenses>
<license>
<name>GNU Lesser General Public License, Version 3.0</name>
<url>https://www.gnu.org/licenses/lgpl-3.0.en.html</url>
<distribution>repo</distribution>
</license>
</licenses>
<organization>
<name>Ethereum</name>
<url>https://ethereum.org</url>
</organization>
<developers>
<developer>
<id>karalabe</id>
<name>Péter Szilágyi</name>
<email>peterke@gmail.com</email>
<url>https://github.com/karalabe</url>
<properties>
<picUrl>https://www.gravatar.com/avatar/2ecbf0f5b4b79eebf8c193e5d324357f?s=256</picUrl>
</properties>
</developer>
</developers>
<contributors>{{range .Contributors}}
<contributor>
<name>{{.Name}}</name>
<email>{{.Email}}</email>
</contributor>{{end}}
</contributors>
<issueManagement>
<system>GitHub Issues</system>
<url>https://github.com/ethereum/go-ethereum/issues/</url>
</issueManagement>
<scm>
<url>https://github.com/ethereum/go-ethereum</url>
</scm>
</project>

View file

@ -1,24 +0,0 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>ossrh</id>
<username>${env.ANDROID_SONATYPE_USERNAME}</username>
<password>${env.ANDROID_SONATYPE_PASSWORD}</password>
</server>
</servers>
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.executable>gpg</gpg.executable>
<gpg.passphrase></gpg.passphrase>
</properties>
</profile>
</profiles>
</settings>

View file

@ -1,327 +0,0 @@
/**
* EnvVarUpdate.nsh
* : Environmental Variables: append, prepend, and remove entries
*
* WARNING: If you use StrFunc.nsh header then include it before this file
* with all required definitions. This is to avoid conflicts
*
* Usage:
* ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
*
* Credits:
* Version 1.0
* * Cal Turney (turnec2)
* * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
* function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
* WriteEnvStr, and un.DeleteEnvStr
* * Diego Pedroso (deguix) for StrTok
* * Kevin English (kenglish_hi) for StrContains
* * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry
* (dandaman32) for StrReplace
*
* Version 1.1 (compatibility with StrFunc.nsh)
* * techtonik
*
* http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
*
*/
!ifndef ENVVARUPDATE_FUNCTION
!define ENVVARUPDATE_FUNCTION
!verbose push
!verbose 3
!include "LogicLib.nsh"
!include "WinMessages.NSH"
!include "StrFunc.nsh"
; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
!macro _IncludeStrFunction StrFuncName
!ifndef ${StrFuncName}_INCLUDED
${${StrFuncName}}
!endif
!ifndef Un${StrFuncName}_INCLUDED
${Un${StrFuncName}}
!endif
!define un.${StrFuncName} "${Un${StrFuncName}}"
!macroend
!insertmacro _IncludeStrFunction StrTok
!insertmacro _IncludeStrFunction StrStr
!insertmacro _IncludeStrFunction StrRep
; ---------------------------------- Macro Definitions ----------------------------------------
!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
Push "${EnvVarName}"
Push "${Action}"
Push "${RegLoc}"
Push "${PathString}"
Call EnvVarUpdate
Pop "${ResultVar}"
!macroend
!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
Push "${EnvVarName}"
Push "${Action}"
Push "${RegLoc}"
Push "${PathString}"
Call un.EnvVarUpdate
Pop "${ResultVar}"
!macroend
!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
; ---------------------------------- Macro Definitions end-------------------------------------
;----------------------------------- EnvVarUpdate start----------------------------------------
!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
!define hkcu_current_user 'HKCU "Environment"'
!macro EnvVarUpdate UN
Function ${UN}EnvVarUpdate
Push $0
Exch 4
Exch $1
Exch 3
Exch $2
Exch 2
Exch $3
Exch
Exch $4
Push $5
Push $6
Push $7
Push $8
Push $9
Push $R0
/* After this point:
-------------------------
$0 = ResultVar (returned)
$1 = EnvVarName (input)
$2 = Action (input)
$3 = RegLoc (input)
$4 = PathString (input)
$5 = Orig EnvVar (read from registry)
$6 = Len of $0 (temp)
$7 = tempstr1 (temp)
$8 = Entry counter (temp)
$9 = tempstr2 (temp)
$R0 = tempChar (temp) */
; Step 1: Read contents of EnvVarName from RegLoc
;
; Check for empty EnvVarName
${If} $1 == ""
SetErrors
DetailPrint "ERROR: EnvVarName is blank"
Goto EnvVarUpdate_Restore_Vars
${EndIf}
; Check for valid Action
${If} $2 != "A"
${AndIf} $2 != "P"
${AndIf} $2 != "R"
SetErrors
DetailPrint "ERROR: Invalid Action - must be A, P, or R"
Goto EnvVarUpdate_Restore_Vars
${EndIf}
${If} $3 == HKLM
ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5
${ElseIf} $3 == HKCU
ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5
${Else}
SetErrors
DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
Goto EnvVarUpdate_Restore_Vars
${EndIf}
; Check for empty PathString
${If} $4 == ""
SetErrors
DetailPrint "ERROR: PathString is blank"
Goto EnvVarUpdate_Restore_Vars
${EndIf}
; Make sure we've got some work to do
${If} $5 == ""
${AndIf} $2 == "R"
SetErrors
DetailPrint "$1 is empty - Nothing to remove"
Goto EnvVarUpdate_Restore_Vars
${EndIf}
; Step 2: Scrub EnvVar
;
StrCpy $0 $5 ; Copy the contents to $0
; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
; after the last one are not removed here but instead in Step 3)
${If} $0 != "" ; If EnvVar is not empty ...
${Do}
${${UN}StrStr} $7 $0 " ;"
${If} $7 == ""
${ExitDo}
${EndIf}
${${UN}StrRep} $0 $0 " ;" ";" ; Remove '<space>;'
${Loop}
${Do}
${${UN}StrStr} $7 $0 "; "
${If} $7 == ""
${ExitDo}
${EndIf}
${${UN}StrRep} $0 $0 "; " ";" ; Remove ';<space>'
${Loop}
${Do}
${${UN}StrStr} $7 $0 ";;"
${If} $7 == ""
${ExitDo}
${EndIf}
${${UN}StrRep} $0 $0 ";;" ";"
${Loop}
; Remove a leading or trailing semicolon from EnvVar
StrCpy $7 $0 1 0
${If} $7 == ";"
StrCpy $0 $0 "" 1 ; Change ';<EnvVar>' to '<EnvVar>'
${EndIf}
StrLen $6 $0
IntOp $6 $6 - 1
StrCpy $7 $0 1 $6
${If} $7 == ";"
StrCpy $0 $0 $6 ; Change ';<EnvVar>' to '<EnvVar>'
${EndIf}
; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug
${EndIf}
/* Step 3. Remove all instances of the target path/string (even if "A" or "P")
$6 = bool flag (1 = found and removed PathString)
$7 = a string (e.g. path) delimited by semicolon(s)
$8 = entry counter starting at 0
$9 = copy of $0
$R0 = tempChar */
${If} $5 != "" ; If EnvVar is not empty ...
StrCpy $9 $0
StrCpy $0 ""
StrCpy $8 0
StrCpy $6 0
${Do}
${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter
${If} $7 == "" ; If we've run out of entries,
${ExitDo} ; were done
${EndIf} ;
; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
${Do}
StrCpy $R0 $7 1
${If} $R0 != " "
${ExitDo}
${EndIf}
StrCpy $7 $7 "" 1 ; Remove leading space
${Loop}
${Do}
StrCpy $R0 $7 1 -1
${If} $R0 != " "
${ExitDo}
${EndIf}
StrCpy $7 $7 -1 ; Remove trailing space
${Loop}
${If} $7 == $4 ; If string matches, remove it by not appending it
StrCpy $6 1 ; Set 'found' flag
${ElseIf} $7 != $4 ; If string does NOT match
${AndIf} $0 == "" ; and the 1st string being added to $0,
StrCpy $0 $7 ; copy it to $0 without a prepended semicolon
${ElseIf} $7 != $4 ; If string does NOT match
${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0,
StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon
${EndIf} ;
IntOp $8 $8 + 1 ; Bump counter
${Loop} ; Check for duplicates until we run out of paths
${EndIf}
; Step 4: Perform the requested Action
;
${If} $2 != "R" ; If Append or Prepend
${If} $6 == 1 ; And if we found the target
DetailPrint "Target is already present in $1. It will be removed and"
${EndIf}
${If} $0 == "" ; If EnvVar is (now) empty
StrCpy $0 $4 ; just copy PathString to EnvVar
${If} $6 == 0 ; If found flag is either 0
${OrIf} $6 == "" ; or blank (if EnvVarName is empty)
DetailPrint "$1 was empty and has been updated with the target"
${EndIf}
${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty),
StrCpy $0 $0;$4 ; append PathString
${If} $6 == 1
DetailPrint "appended to $1"
${Else}
DetailPrint "Target was appended to $1"
${EndIf}
${Else} ; If Prepend (and EnvVar is not empty),
StrCpy $0 $4;$0 ; prepend PathString
${If} $6 == 1
DetailPrint "prepended to $1"
${Else}
DetailPrint "Target was prepended to $1"
${EndIf}
${EndIf}
${Else} ; If Action = Remove
${If} $6 == 1 ; and we found the target
DetailPrint "Target was found and removed from $1"
${Else}
DetailPrint "Target was NOT found in $1 (nothing to remove)"
${EndIf}
${If} $0 == ""
DetailPrint "$1 is now empty"
${EndIf}
${EndIf}
; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change
;
ClearErrors
${If} $3 == HKLM
WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section
${ElseIf} $3 == HKCU
WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section
${EndIf}
IfErrors 0 +4
MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
DetailPrint "Could not write updated $1 to $3"
Goto EnvVarUpdate_Restore_Vars
; "Export" our change
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
EnvVarUpdate_Restore_Vars:
;
; Restore the user's variables and return ResultVar
Pop $R0
Pop $9
Pop $8
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Push $0 ; Push my $0 (ResultVar)
Exch
Pop $0 ; Restore his $0
FunctionEnd
!macroend ; EnvVarUpdate UN
!insertmacro EnvVarUpdate ""
!insertmacro EnvVarUpdate "un."
;----------------------------------- EnvVarUpdate end----------------------------------------
!verbose pop
!endif

View file

@ -1,70 +0,0 @@
# Builds a Windows installer with NSIS.
# It expects the following command line arguments:
# - OUTPUTFILE, filename of the installer (without extension)
# - MAJORVERSION, major build version
# - MINORVERSION, minor build version
# - BUILDVERSION, build id version
#
# The created installer executes the following steps:
# 1. install geth for all users
# 2. install optional development tools such as abigen
# 3. create an uninstaller
# 4. configures the Windows firewall for geth
# 5. create geth, attach and uninstall start menu entries
# 6. configures the registry that allows Windows to manage the package through its platform tools
# 7. adds the environment system wide variable ETHEREUM_SOCKET
# 8. adds the install directory to %PATH%
#
# Requirements:
# - NSIS, http://nsis.sourceforge.net/Main_Page
# - NSIS Large Strings build, http://nsis.sourceforge.net/Special_Builds
# - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi)
#
# After intalling NSIS extra the NSIS Large Strings build zip and replace the makensis.exe and the
# files found in Stub.
#
# based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller
#
# TODO:
# - sign installer
CRCCheck on
!define GROUPNAME "Ethereum"
!define APPNAME "Geth"
!define DESCRIPTION "Official Go implementation of the Ethereum protocol"
!addplugindir .\
# Require admin rights on NT6+ (When UAC is turned on)
RequestExecutionLevel admin
# Use LZMA compression
SetCompressor /SOLID lzma
!include LogicLib.nsh
!include PathUpdate.nsh
!include EnvVarUpdate.nsh
!macro VerifyUserIsAdmin
UserInfo::GetAccountType
pop $0
${If} $0 != "admin" # Require admin rights on NT4+
messageBox mb_iconstop "Administrator rights required!"
setErrorLevel 740 # ERROR_ELEVATION_REQUIRED
quit
${EndIf}
!macroend
function .onInit
# make vars are global for all users since geth is installed global
setShellVarContext all
!insertmacro VerifyUserIsAdmin
${If} ${ARCH} == "amd64"
StrCpy $InstDir "$PROGRAMFILES64\${APPNAME}"
${Else}
StrCpy $InstDir "$PROGRAMFILES32\${APPNAME}"
${Endif}
functionEnd
!include install.nsh
!include uninstall.nsh

View file

@ -1,103 +0,0 @@
Name "geth ${MAJORVERSION}.${MINORVERSION}.${BUILDVERSION}" # VERSION variables set through command line arguments
InstallDir "$InstDir"
OutFile "${OUTPUTFILE}" # set through command line arguments
# Links for "Add/Remove Programs"
!define HELPURL "https://github.com/ethereum/go-ethereum/issues"
!define UPDATEURL "https://github.com/ethereum/go-ethereum/releases"
!define ABOUTURL "https://github.com/ethereum/go-ethereum#ethereum-go"
!define /date NOW "%Y%m%d"
PageEx license
LicenseData {{.License}}
PageExEnd
# Install geth binary
Section "Geth" GETH_IDX
SetOutPath $INSTDIR
file {{.Geth}}
# Create start menu launcher
createDirectory "$SMPROGRAMS\${APPNAME}"
createShortCut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\geth.exe" "--fast" "--cache=512"
createShortCut "$SMPROGRAMS\${APPNAME}\Attach.lnk" "$INSTDIR\geth.exe" "attach" "" ""
createShortCut "$SMPROGRAMS\${APPNAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "" ""
# Firewall - remove rules (if exists)
SimpleFC::AdvRemoveRule "Geth incoming peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth outgoing peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)"
# Firewall - add rules
SimpleFC::AdvAddRule "Geth incoming peers (TCP:30303)" "" 6 1 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" 30303 "" "" ""
SimpleFC::AdvAddRule "Geth outgoing peers (TCP:30303)" "" 6 2 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" "" 30303 "" ""
SimpleFC::AdvAddRule "Geth UDP discovery (UDP:30303)" "" 17 2 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" "" 30303 "" ""
# Set default IPC endpoint (https://github.com/ethereum/EIPs/issues/147)
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc"
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\geth.ipc"
# Add instdir to PATH
Push "$INSTDIR"
Call AddToPath
SectionEnd
# Install optional develop tools.
Section /o "Development tools" DEV_TOOLS_IDX
SetOutPath $INSTDIR
{{range .DevTools}}file {{.}}
{{end}}
SectionEnd
# Return on top of stack the total size (as DWORD) of the selected/installed sections.
Var GetInstalledSize.total
Function GetInstalledSize
StrCpy $GetInstalledSize.total 0
${if} ${SectionIsSelected} ${GETH_IDX}
SectionGetSize ${GETH_IDX} $0
IntOp $GetInstalledSize.total $GetInstalledSize.total + $0
${endif}
${if} ${SectionIsSelected} ${DEV_TOOLS_IDX}
SectionGetSize ${DEV_TOOLS_IDX} $0
IntOp $GetInstalledSize.total $GetInstalledSize.total + $0
${endif}
IntFmt $GetInstalledSize.total "0x%08X" $GetInstalledSize.total
Push $GetInstalledSize.total
FunctionEnd
# Write registry, Windows uses these values in various tools such as add/remove program.
# PowerShell: Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, InstallLocation, InstallDate | Format-Table AutoSize
function .onInstSuccess
# Save information in registry in HKEY_LOCAL_MACHINE branch, Windows add/remove functionality depends on this
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayName" "${GROUPNAME} - ${APPNAME} - ${DESCRIPTION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "InstallLocation" "$INSTDIR"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "InstallDate" "${NOW}"
# Wait for Alex
#WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\logo.ico$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "Publisher" "${GROUPNAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "HelpLink" "${HELPURL}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "URLUpdateInfo" "${UPDATEURL}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "URLInfoAbout" "${ABOUTURL}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayVersion" "${MAJORVERSION}.${MINORVERSION}.${BUILDVERSION}"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "VersionMajor" ${MAJORVERSION}
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "VersionMinor" ${MINORVERSION}
# There is no option for modifying or repairing the install
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "NoRepair" 1
Call GetInstalledSize
Pop $0
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "EstimatedSize" "$0"
# Create uninstaller
writeUninstaller "$INSTDIR\uninstall.exe"
functionEnd
Page components
Page directory
Page instfiles

View file

@ -1,153 +0,0 @@
!include "WinMessages.nsh"
; see https://support.microsoft.com/en-us/kb/104011
!define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
; HKEY_LOCAL_MACHINE = 0x80000002
; AddToPath - Appends dir to PATH
; (does not work on Win9x/ME)
;
; Usage:
; Push "dir"
; Call AddToPath
Function AddToPath
Exch $0
Push $1
Push $2
Push $3
Push $4
; NSIS ReadRegStr returns empty string on string overflow
; Native calls are used here to check actual length of PATH
; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3)
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
IntCmp $4 0 0 done done
; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2))
; RegCloseKey($3)
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
System::Call "advapi32::RegCloseKey(i $3)"
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA
DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}"
Goto done
IntCmp $4 0 +5 ; $4 != NO_ERROR
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND
DetailPrint "AddToPath: unexpected error code $4"
Goto done
StrCpy $1 ""
; Check if already in PATH
Push "$1;"
Push "$0;"
Call StrStr
Pop $2
StrCmp $2 "" 0 done
Push "$1;"
Push "$0\;"
Call StrStr
Pop $2
StrCmp $2 "" 0 done
; Prevent NSIS string overflow
StrLen $2 $0
StrLen $3 $1
IntOp $2 $2 + $3
IntOp $2 $2 + 2 ; $2 = strlen(dir) + strlen(PATH) + sizeof(";")
IntCmp $2 ${NSIS_MAX_STRLEN} +4 +4 0
DetailPrint "AddToPath: new length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK "PATH not updated, new length $2 > ${NSIS_MAX_STRLEN}."
Goto done
; Append dir to PATH
DetailPrint "Add to PATH: $0"
StrCpy $2 $1 1 -1
StrCmp $2 ";" 0 +2
StrCpy $1 $1 -1 ; remove trailing ';'
StrCmp $1 "" +2 ; no leading ';'
StrCpy $0 "$1;$0"
WriteRegExpandStr ${Environ} "PATH" $0
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
done:
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
; RemoveFromPath - Removes dir from PATH
;
; Usage:
; Push "dir"
; Call RemoveFromPath
Function un.RemoveFromPath
Exch $0
Push $1
Push $2
Push $3
Push $4
Push $5
Push $6
; NSIS ReadRegStr returns empty string on string overflow
; Native calls are used here to check actual length of PATH
; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3)
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
IntCmp $4 0 0 done done
; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2))
; RegCloseKey($3)
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
System::Call "advapi32::RegCloseKey(i $3)"
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA
DetailPrint "RemoveFromPath: original length $2 > ${NSIS_MAX_STRLEN}"
MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}"
Goto done
IntCmp $4 0 +5 ; $4 != NO_ERROR
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND
DetailPrint "RemoveFromPath: unexpected error code $4"
Goto done
StrCpy $1 ""
; length < ${NSIS_MAX_STRLEN} -> ReadRegStr can be used
ReadRegStr $1 ${Environ} "PATH"
StrCpy $5 $1 1 -1
StrCmp $5 ";" +2
StrCpy $1 "$1;" ; ensure trailing ';'
Push $1
Push "$0;"
Call un.StrStr
Pop $2 ; pos of our dir
StrCmp $2 "" done
DetailPrint "Remove from PATH: $0"
StrLen $3 "$0;"
StrLen $4 $2
StrCpy $5 $1 -$4 ; $5 is now the part before the path to remove
StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove
StrCpy $3 "$5$6"
StrCpy $5 $3 1 -1
StrCmp $5 ";" 0 +2
StrCpy $3 $3 -1 ; remove trailing ';'
WriteRegExpandStr ${Environ} "PATH" $3
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
done:
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd

Binary file not shown.

Binary file not shown.

View file

@ -1,33 +0,0 @@
Section "Uninstall"
# uninstall for all users
setShellVarContext all
# Delete (optionally) installed files
{{range $}}Delete $INSTDIR\{{.}}
{{end}}
Delete $INSTDIR\uninstall.exe
# Delete install directory
rmDir $INSTDIR
# Delete start menu launcher
Delete "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk"
Delete "$SMPROGRAMS\${APPNAME}\Attach.lnk"
Delete "$SMPROGRAMS\${APPNAME}\Uninstall.lnk"
rmDir "$SMPROGRAMS\${APPNAME}"
# Firewall - remove rules if exists
SimpleFC::AdvRemoveRule "Geth incoming peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth outgoing peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)"
# Remove IPC endpoint (https://github.com/ethereum/EIPs/issues/147)
${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc"
# Remove install directory from PATH
Push "$INSTDIR"
Call un.RemoveFromPath
# Cleanup registry (deletes all sub keys)
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}"
SectionEnd

View file

@ -1,22 +0,0 @@
Pod::Spec.new do |spec|
spec.name = 'Geth'
spec.version = '{{.Version}}'
spec.license = { :type => 'GNU Lesser General Public License, Version 3.0' }
spec.homepage = 'https://github.com/ethereum/go-ethereum'
spec.authors = { {{range .Contributors}}
'{{.Name}}' => '{{.Email}}',{{end}}
}
spec.summary = 'iOS Ethereum Client'
spec.source = { :git => 'https://github.com/ethereum/go-ethereum.git', :commit => '{{.Commit}}' }
spec.platform = :ios
spec.ios.deployment_target = '9.0'
spec.ios.vendored_frameworks = 'Frameworks/Geth.framework'
spec.prepare_command = <<-CMD
curl https://gethstore.blob.core.windows.net/builds/{{.Archive}}.tar.gz | tar -xvz
mkdir Frameworks
mv {{.Archive}}/Geth.framework Frameworks
rm -rf {{.Archive}}
CMD
end

View file

@ -1,395 +0,0 @@
// +build none
/*
This command generates GPL license headers on top of all source files.
You can run it once per month, before cutting a release or just
whenever you feel like it.
go run update-license.go
All authors (people who have contributed code) are listed in the
AUTHORS file. The author names are mapped and deduplicated using the
.mailmap file. You can use .mailmap to set the canonical name and
address for each author. See git-shortlog(1) for an explanation of the
.mailmap format.
Please review the resulting diff to check whether the correct
copyright assignments are performed.
*/
package main
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"text/template"
"time"
)
var (
// only files with these extensions will be considered
extensions = []string{".go", ".js", ".qml"}
// paths with any of these prefixes will be skipped
skipPrefixes = []string{
// boring stuff
"vendor/", "tests/testdata/", "build/",
// don't relicense vendored sources
"cmd/internal/browser",
"consensus/ethash/xor.go",
"crypto/bn256/",
"crypto/ecies/",
"crypto/secp256k1/curve.go",
"crypto/sha3/",
"internal/jsre/deps",
"log/",
"common/bitutil/bitutil",
// don't license generated files
"contracts/chequebook/contract/code.go",
}
// paths with this prefix are licensed as GPL. all other files are LGPL.
gplPrefixes = []string{"cmd/"}
// this regexp must match the entire license comment at the
// beginning of each file.
licenseCommentRE = regexp.MustCompile(`^//\s*(Copyright|This file is part of).*?\n(?://.*?\n)*\n*`)
// this text appears at the start of AUTHORS
authorsFileHeader = "# This is the official list of go-ethereum authors for copyright purposes.\n\n"
)
// this template generates the license comment.
// its input is an info structure.
var licenseT = template.Must(template.New("").Parse(`
// Copyright {{.Year}} The go-ethereum Authors
// This file is part of {{.Whole false}}.
//
// {{.Whole true}} is free software: you can redistribute it and/or modify
// it under the terms of the GNU {{.License}} as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// {{.Whole true}} 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 {{.License}} for more details.
//
// You should have received a copy of the GNU {{.License}}
// along with {{.Whole false}}. If not, see <http://www.gnu.org/licenses/>.
`[1:]))
type info struct {
file string
Year int64
}
func (i info) License() string {
if i.gpl() {
return "General Public License"
}
return "Lesser General Public License"
}
func (i info) ShortLicense() string {
if i.gpl() {
return "GPL"
}
return "LGPL"
}
func (i info) Whole(startOfSentence bool) string {
if i.gpl() {
return "go-ethereum"
}
if startOfSentence {
return "The go-ethereum library"
}
return "the go-ethereum library"
}
func (i info) gpl() bool {
for _, p := range gplPrefixes {
if strings.HasPrefix(i.file, p) {
return true
}
}
return false
}
func main() {
var (
files = getFiles()
filec = make(chan string)
infoc = make(chan *info, 20)
wg sync.WaitGroup
)
writeAuthors(files)
go func() {
for _, f := range files {
filec <- f
}
close(filec)
}()
for i := runtime.NumCPU(); i >= 0; i-- {
// getting file info is slow and needs to be parallel.
// it traverses git history for each file.
wg.Add(1)
go getInfo(filec, infoc, &wg)
}
go func() {
wg.Wait()
close(infoc)
}()
writeLicenses(infoc)
}
func skipFile(path string) bool {
if strings.Contains(path, "/testdata/") {
return true
}
for _, p := range skipPrefixes {
if strings.HasPrefix(path, p) {
return true
}
}
return false
}
func getFiles() []string {
cmd := exec.Command("git", "ls-tree", "-r", "--name-only", "HEAD")
var files []string
err := doLines(cmd, func(line string) {
if skipFile(line) {
return
}
ext := filepath.Ext(line)
for _, wantExt := range extensions {
if ext == wantExt {
goto keep
}
}
return
keep:
files = append(files, line)
})
if err != nil {
log.Fatal("error getting files:", err)
}
return files
}
var authorRegexp = regexp.MustCompile(`\s*[0-9]+\s*(.*)`)
func gitAuthors(files []string) []string {
cmds := []string{"shortlog", "-s", "-n", "-e", "HEAD", "--"}
cmds = append(cmds, files...)
cmd := exec.Command("git", cmds...)
var authors []string
err := doLines(cmd, func(line string) {
m := authorRegexp.FindStringSubmatch(line)
if len(m) > 1 {
authors = append(authors, m[1])
}
})
if err != nil {
log.Fatalln("error getting authors:", err)
}
return authors
}
func readAuthors() []string {
content, err := ioutil.ReadFile("AUTHORS")
if err != nil && !os.IsNotExist(err) {
log.Fatalln("error reading AUTHORS:", err)
}
var authors []string
for _, a := range bytes.Split(content, []byte("\n")) {
if len(a) > 0 && a[0] != '#' {
authors = append(authors, string(a))
}
}
// Retranslate existing authors through .mailmap.
// This should catch email address changes.
authors = mailmapLookup(authors)
return authors
}
func mailmapLookup(authors []string) []string {
if len(authors) == 0 {
return nil
}
cmds := []string{"check-mailmap", "--"}
cmds = append(cmds, authors...)
cmd := exec.Command("git", cmds...)
var translated []string
err := doLines(cmd, func(line string) {
translated = append(translated, line)
})
if err != nil {
log.Fatalln("error translating authors:", err)
}
return translated
}
func writeAuthors(files []string) {
merge := make(map[string]bool)
// Add authors that Git reports as contributorxs.
// This is the primary source of author information.
for _, a := range gitAuthors(files) {
merge[a] = true
}
// Add existing authors from the file. This should ensure that we
// never lose authors, even if Git stops listing them. We can also
// add authors manually this way.
for _, a := range readAuthors() {
merge[a] = true
}
// Write sorted list of authors back to the file.
var result []string
for a := range merge {
result = append(result, a)
}
sort.Strings(result)
content := new(bytes.Buffer)
content.WriteString(authorsFileHeader)
for _, a := range result {
content.WriteString(a)
content.WriteString("\n")
}
fmt.Println("writing AUTHORS")
if err := ioutil.WriteFile("AUTHORS", content.Bytes(), 0644); err != nil {
log.Fatalln(err)
}
}
func getInfo(files <-chan string, out chan<- *info, wg *sync.WaitGroup) {
for file := range files {
stat, err := os.Lstat(file)
if err != nil {
fmt.Printf("ERROR %s: %v\n", file, err)
continue
}
if !stat.Mode().IsRegular() {
continue
}
if isGenerated(file) {
continue
}
info, err := fileInfo(file)
if err != nil {
fmt.Printf("ERROR %s: %v\n", file, err)
continue
}
out <- info
}
wg.Done()
}
func isGenerated(file string) bool {
fd, err := os.Open(file)
if err != nil {
return false
}
defer fd.Close()
buf := make([]byte, 2048)
n, _ := fd.Read(buf)
buf = buf[:n]
for _, l := range bytes.Split(buf, []byte("\n")) {
if bytes.HasPrefix(l, []byte("// Code generated")) {
return true
}
}
return false
}
// fileInfo finds the lowest year in which the given file was committed.
func fileInfo(file string) (*info, error) {
info := &info{file: file, Year: int64(time.Now().Year())}
cmd := exec.Command("git", "log", "--follow", "--find-renames=80", "--find-copies=80", "--pretty=format:%ai", "--", file)
err := doLines(cmd, func(line string) {
y, err := strconv.ParseInt(line[:4], 10, 64)
if err != nil {
fmt.Printf("cannot parse year: %q", line[:4])
}
if y < info.Year {
info.Year = y
}
})
return info, err
}
func writeLicenses(infos <-chan *info) {
for i := range infos {
writeLicense(i)
}
}
func writeLicense(info *info) {
fi, err := os.Stat(info.file)
if os.IsNotExist(err) {
fmt.Println("skipping (does not exist)", info.file)
return
}
if err != nil {
log.Fatalf("error stat'ing %s: %v\n", info.file, err)
}
content, err := ioutil.ReadFile(info.file)
if err != nil {
log.Fatalf("error reading %s: %v\n", info.file, err)
}
// Construct new file content.
buf := new(bytes.Buffer)
licenseT.Execute(buf, info)
if m := licenseCommentRE.FindIndex(content); m != nil && m[0] == 0 {
buf.Write(content[:m[0]])
buf.Write(content[m[1]:])
} else {
buf.Write(content)
}
// Write it to the file.
if bytes.Equal(content, buf.Bytes()) {
fmt.Println("skipping (no changes)", info.file)
return
}
fmt.Println("writing", info.ShortLicense(), info.file)
if err := ioutil.WriteFile(info.file, buf.Bytes(), fi.Mode()); err != nil {
log.Fatalf("error writing %s: %v", info.file, err)
}
}
func doLines(cmd *exec.Cmd, f func(string)) error {
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
if err := cmd.Start(); err != nil {
return err
}
s := bufio.NewScanner(stdout)
for s.Scan() {
f(s.Text())
}
if s.Err() != nil {
return s.Err()
}
if err := cmd.Wait(); err != nil {
return fmt.Errorf("%v (for %s)", err, strings.Join(cmd.Args, " "))
}
return nil
}

View file

@ -1,32 +0,0 @@
machine:
services:
- docker
dependencies:
cache_directories:
- "~/.ethash" # Cache the ethash DAG generated by hive for consecutive builds
- "~/.docker" # Cache all docker images manually to avoid lengthy rebuilds
override:
# Restore all previously cached docker images
- mkdir -p ~/.docker
- for img in `ls ~/.docker`; do docker load -i ~/.docker/$img; done
# Pull in and hive, restore cached ethash DAGs and do a dry run
- go get -u github.com/karalabe/hive
- (cd ~/.go_workspace/src/github.com/karalabe/hive && mkdir -p workspace/ethash/ ~/.ethash)
- (cd ~/.go_workspace/src/github.com/karalabe/hive && cp -r ~/.ethash/. workspace/ethash/)
- (cd ~/.go_workspace/src/github.com/karalabe/hive && hive --docker-noshell --client=NONE --test=. --sim=. --loglevel=6)
# Cache all the docker images and the ethash DAGs
- for img in `docker images | grep -v "^<none>" | tail -n +2 | awk '{print $1}'`; do docker save $img > ~/.docker/`echo $img | tr '/' ':'`.tar; done
- cp -r ~/.go_workspace/src/github.com/karalabe/hive/workspace/ethash/. ~/.ethash
test:
override:
# Build Geth and move into a known folder
- make geth
- cp ./build/bin/geth $HOME/geth
# Run hive and move all generated logs into the public artifacts folder
- (cd ~/.go_workspace/src/github.com/karalabe/hive && hive --docker-noshell --client=go-ethereum:local --override=$HOME/geth --test=. --sim=.)
- cp -r ~/.go_workspace/src/github.com/karalabe/hive/workspace/logs/* $CIRCLE_ARTIFACTS

View file

@ -32,11 +32,11 @@ import (
var (
walletCommand = cli.Command{
Name: "wallet",
Usage: "Manage Ethereum presale wallets",
Usage: "Manage XDCchain presale wallets",
ArgsUsage: "",
Category: "ACCOUNT COMMANDS",
Description: `
geth wallet import /path/to/my/presale.wallet
XDC wallet import /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a
@ -45,7 +45,7 @@ passwordfile as argument containing the wallet password in plaintext.`,
{
Name: "import",
Usage: "Import Ethereum presale wallet",
Usage: "Import XDCchain presale wallet",
ArgsUsage: "<keyFile>",
Action: utils.MigrateFlags(importWallet),
Category: "ACCOUNT COMMANDS",
@ -56,7 +56,7 @@ passwordfile as argument containing the wallet password in plaintext.`,
utils.LightKDFFlag,
},
Description: `
geth wallet [options] /path/to/my/presale.wallet
XDC wallet [options] /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a
@ -112,7 +112,7 @@ Print a short summary of all accounts`,
utils.LightKDFFlag,
},
Description: `
geth account new
XDC account new
Creates a new account and prints the address.
@ -137,7 +137,7 @@ password to file or expose in any other way.
utils.LightKDFFlag,
},
Description: `
geth account update <address>
XDC account update <address>
Update an existing account.
@ -149,7 +149,7 @@ format to the newest format or change the password for an account.
For non-interactive use the passphrase can be specified with the --password flag:
geth account update [options] <address>
XDC account update [options] <address>
Since only one password can be given, only format update can be performed,
changing your password is only possible interactively.
@ -167,7 +167,7 @@ changing your password is only possible interactively.
},
ArgsUsage: "<keyFile>",
Description: `
geth account import <keyfile>
XDC account import <keyfile>
Imports an unencrypted private key from <keyfile> and creates a new account.
Prints the address.
@ -180,7 +180,7 @@ You must remember this passphrase to unlock your account in the future.
For non-interactive use the passphrase can be specified with the -password flag:
geth account import [options] <keyfile>
XDC account import [options] <keyfile>
Note:
As you can directly copy your encrypted accounts to another ethereum instance,
@ -291,7 +291,7 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr
// accountCreate creates a new account into the keystore defined by the CLI flags.
func accountCreate(ctx *cli.Context) error {
cfg := gethConfig{Node: defaultNodeConfig()}
cfg := XDCConfig{Node: defaultNodeConfig()}
// Load config file.
if file := ctx.GlobalString(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil {
@ -312,7 +312,7 @@ func accountCreate(ctx *cli.Context) error {
if err != nil {
utils.Fatalf("Failed to create account: %v", err)
}
fmt.Printf("Address: {%x}\n", address)
fmt.Printf("Address: {xdc%x}\n", address)
return nil
}
@ -353,7 +353,7 @@ func importWallet(ctx *cli.Context) error {
if err != nil {
utils.Fatalf("%v", err)
}
fmt.Printf("Address: {%x}\n", acct.Address)
fmt.Printf("Address: {xdc%x}\n", acct.Address)
return nil
}
@ -374,6 +374,6 @@ func accountImport(ctx *cli.Context) error {
if err != nil {
utils.Fatalf("Could not create the account: %v", err)
}
fmt.Printf("Address: {%x}\n", acct.Address)
fmt.Printf("Address: {xdc%x}\n", acct.Address)
return nil
}

View file

@ -43,22 +43,22 @@ func tmpDatadirWithKeystore(t *testing.T) string {
}
func TestAccountListEmpty(t *testing.T) {
geth := runGeth(t, "account", "list")
geth.ExpectExit()
XDC := runXDC(t, "account", "list")
XDC.ExpectExit()
}
func TestAccountList(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, "account", "list", "--datadir", datadir)
defer geth.ExpectExit()
XDC := runXDC(t, "account", "list", "--datadir", datadir)
defer XDC.ExpectExit()
if runtime.GOOS == "windows" {
geth.Expect(`
XDC.Expect(`
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz
`)
} else {
geth.Expect(`
XDC.Expect(`
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz
@ -67,21 +67,21 @@ Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/k
}
func TestAccountNew(t *testing.T) {
geth := runGeth(t, "account", "new", "--lightkdf")
defer geth.ExpectExit()
geth.Expect(`
XDC := runXDC(t, "account", "new", "--lightkdf")
defer XDC.ExpectExit()
XDC.Expect(`
Your new account is locked with a password. Please give a password. Do not forget this password.
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "foobar"}}
Repeat passphrase: {{.InputLine "foobar"}}
`)
geth.ExpectRegexp(`Address: \{[0-9a-f]{40}\}\n`)
XDC.ExpectRegexp(`Address: \{[0-9a-f]{40}\}\n`)
}
func TestAccountNewBadRepeat(t *testing.T) {
geth := runGeth(t, "account", "new", "--lightkdf")
defer geth.ExpectExit()
geth.Expect(`
XDC := runXDC(t, "account", "new", "--lightkdf")
defer XDC.ExpectExit()
XDC.Expect(`
Your new account is locked with a password. Please give a password. Do not forget this password.
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "something"}}
@ -92,11 +92,11 @@ Fatal: Passphrases do not match
func TestAccountUpdate(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, "account", "update",
XDC := runXDC(t, "account", "update",
"--datadir", datadir, "--lightkdf",
"f466859ead1932d743d622cb74fc058882e8648a")
defer geth.ExpectExit()
geth.Expect(`
defer XDC.ExpectExit()
XDC.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "foobar"}}
@ -107,24 +107,24 @@ Repeat passphrase: {{.InputLine "foobar2"}}
}
func TestWalletImport(t *testing.T) {
geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer geth.ExpectExit()
geth.Expect(`
XDC := runXDC(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer XDC.ExpectExit()
XDC.Expect(`
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "foo"}}
Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f}
`)
files, err := ioutil.ReadDir(filepath.Join(geth.Datadir, "keystore"))
files, err := ioutil.ReadDir(filepath.Join(XDC.Datadir, "keystore"))
if len(files) != 1 {
t.Errorf("expected one key file in keystore directory, found %d files (error: %v)", len(files), err)
}
}
func TestWalletImportBadPassword(t *testing.T) {
geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer geth.ExpectExit()
geth.Expect(`
XDC := runXDC(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer XDC.ExpectExit()
XDC.Expect(`
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "wrong"}}
Fatal: could not decrypt key with given passphrase
@ -133,23 +133,23 @@ Fatal: could not decrypt key with given passphrase
func TestUnlockFlag(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t,
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"js", "testdata/empty.js")
geth.Expect(`
XDC.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "foobar"}}
`)
geth.ExpectExit()
XDC.ExpectExit()
wantMessages := []string{
"Unlocked account",
"=0xf466859eAD1932D743d622CB74FC058882E8648A",
}
for _, m := range wantMessages {
if !strings.Contains(geth.StderrText(), m) {
if !strings.Contains(XDC.StderrText(), m) {
t.Errorf("stderr text does not contain %q", m)
}
}
@ -157,11 +157,11 @@ Passphrase: {{.InputLine "foobar"}}
func TestUnlockFlagWrongPassword(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t,
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a")
defer geth.ExpectExit()
geth.Expect(`
defer XDC.ExpectExit()
XDC.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "wrong1"}}
@ -176,18 +176,18 @@ Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could
// https://github.com/ethereum/go-ethereum/issues/1785
func TestUnlockFlagMultiIndex(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t,
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "0,2",
"js", "testdata/empty.js")
geth.Expect(`
XDC.Expect(`
Unlocking account 0 | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "foobar"}}
Unlocking account 2 | Attempt 1/3
Passphrase: {{.InputLine "foobar"}}
`)
geth.ExpectExit()
XDC.ExpectExit()
wantMessages := []string{
"Unlocked account",
@ -195,7 +195,7 @@ Passphrase: {{.InputLine "foobar"}}
"=0x289d485D9771714CCe91D3393D764E1311907ACc",
}
for _, m := range wantMessages {
if !strings.Contains(geth.StderrText(), m) {
if !strings.Contains(XDC.StderrText(), m) {
t.Errorf("stderr text does not contain %q", m)
}
}
@ -203,11 +203,11 @@ Passphrase: {{.InputLine "foobar"}}
func TestUnlockFlagPasswordFile(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t,
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--password", "testdata/passwords.txt", "--unlock", "0,2",
"js", "testdata/empty.js")
geth.ExpectExit()
XDC.ExpectExit()
wantMessages := []string{
"Unlocked account",
@ -215,7 +215,7 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
"=0x289d485D9771714CCe91D3393D764E1311907ACc",
}
for _, m := range wantMessages {
if !strings.Contains(geth.StderrText(), m) {
if !strings.Contains(XDC.StderrText(), m) {
t.Errorf("stderr text does not contain %q", m)
}
}
@ -223,29 +223,29 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t,
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--password", "testdata/wrong-passwords.txt", "--unlock", "0,2")
defer geth.ExpectExit()
geth.Expect(`
defer XDC.ExpectExit()
XDC.Expect(`
Fatal: Failed to unlock account 0 (could not decrypt key with given passphrase)
`)
}
func TestUnlockFlagAmbiguous(t *testing.T) {
store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
geth := runGeth(t,
XDC := runXDC(t,
"--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"js", "testdata/empty.js")
defer geth.ExpectExit()
defer XDC.ExpectExit()
// Helper for the expect template, returns absolute keystore path.
geth.SetTemplateFunc("keypath", func(file string) string {
XDC.SetTemplateFunc("keypath", func(file string) string {
abs, _ := filepath.Abs(filepath.Join(store, file))
return abs
})
geth.Expect(`
XDC.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "foobar"}}
@ -257,14 +257,14 @@ Your passphrase unlocked keystore://{{keypath "1"}}
In order to avoid this warning, you need to remove the following duplicate key files:
keystore://{{keypath "2"}}
`)
geth.ExpectExit()
XDC.ExpectExit()
wantMessages := []string{
"Unlocked account",
"=0xf466859eAD1932D743d622CB74FC058882E8648A",
}
for _, m := range wantMessages {
if !strings.Contains(geth.StderrText(), m) {
if !strings.Contains(XDC.StderrText(), m) {
t.Errorf("stderr text does not contain %q", m)
}
}
@ -272,17 +272,17 @@ In order to avoid this warning, you need to remove the following duplicate key f
func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) {
store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
geth := runGeth(t,
XDC := runXDC(t,
"--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a")
defer geth.ExpectExit()
defer XDC.ExpectExit()
// Helper for the expect template, returns absolute keystore path.
geth.SetTemplateFunc("keypath", func(file string) string {
XDC.SetTemplateFunc("keypath", func(file string) string {
abs, _ := filepath.Abs(filepath.Join(store, file))
return abs
})
geth.Expect(`
XDC.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Passphrase: {{.InputLine "wrong"}}
@ -292,5 +292,5 @@ Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a:
Testing your passphrase against all of them...
Fatal: None of the listed files could be unlocked.
`)
geth.ExpectExit()
XDC.ExpectExit()
}

View file

@ -36,7 +36,7 @@ import (
var bugCommand = cli.Command{
Action: utils.MigrateFlags(reportBug),
Name: "bug",
Usage: "opens a window to report a bug on the geth repo",
Usage: "opens a window to report a bug on the XDC repo",
ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
}

View file

@ -190,7 +190,7 @@ func initGenesis(ctx *cli.Context) error {
utils.Fatalf("invalid genesis file: %v", err)
}
// Open an initialise both full and light databases
stack := makeFullNode(ctx)
stack, _ := makeFullNode(ctx)
for _, name := range []string{"chaindata", "lightchaindata"} {
chaindb, err := stack.OpenDatabase(name, 0, 0)
if err != nil {
@ -209,7 +209,7 @@ func importChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
stack := makeFullNode(ctx)
stack, _ := makeFullNode(ctx)
chain, chainDb := utils.MakeChain(ctx, stack)
defer chainDb.Close()
@ -303,7 +303,7 @@ func exportChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
stack := makeFullNode(ctx)
stack, _ := makeFullNode(ctx)
chain, _ := utils.MakeChain(ctx, stack)
start := time.Now()
@ -336,7 +336,7 @@ func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
stack := makeFullNode(ctx)
stack, _ := makeFullNode(ctx)
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
start := time.Now()
@ -352,7 +352,7 @@ func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
stack := makeFullNode(ctx)
stack, _ := makeFullNode(ctx)
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
start := time.Now()
@ -369,7 +369,7 @@ func copyDb(ctx *cli.Context) error {
utils.Fatalf("Source chaindata directory path argument missing")
}
// Initialize a new chain for the running node to sync into
stack := makeFullNode(ctx)
stack, _ := makeFullNode(ctx)
chain, chainDb := utils.MakeChain(ctx, stack)
syncmode := *utils.GlobalTextMarshaler(ctx, utils.SyncModeFlag.Name).(*downloader.SyncMode)
@ -441,7 +441,7 @@ func removeDB(ctx *cli.Context) error {
}
func dump(ctx *cli.Context) error {
stack := makeFullNode(ctx)
stack, _ := makeFullNode(ctx)
chain, chainDb := utils.MakeChain(ctx, stack)
for _, arg := range ctx.Args() {
var block *types.Block

View file

@ -20,16 +20,19 @@ import (
"bufio"
"errors"
"fmt"
"gopkg.in/urfave/cli.v1"
"io"
"os"
"reflect"
"strings"
"unicode"
cli "gopkg.in/urfave/cli.v1"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/dashboard"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
@ -71,24 +74,38 @@ var tomlSettings = toml.Config{
}
type ethstatsConfig struct {
URL string `toml:",omitempty"`
URL string
}
type gethConfig struct {
Eth eth.Config
Shh whisper.Config
Node node.Config
Ethstats ethstatsConfig
Dashboard dashboard.Config
type account struct {
Unlocks []string
Passwords []string
}
func loadConfig(file string, cfg *gethConfig) error {
type Bootnodes struct {
Mainnet []string
Testnet []string
}
type XDCConfig struct {
Eth eth.Config
Shh whisper.Config
Node node.Config
Ethstats ethstatsConfig
Dashboard dashboard.Config
Account account
StakeEnable bool
Bootnodes Bootnodes
Verbosity int
NAT string
}
func loadConfig(file string, cfg *XDCConfig) error {
f, err := os.Open(file)
if err != nil {
return err
}
defer f.Close()
err = tomlSettings.NewDecoder(bufio.NewReader(f)).Decode(cfg)
// Add file name to errors that have a line number.
if _, ok := err.(*toml.LineError); ok {
@ -103,25 +120,69 @@ func defaultNodeConfig() node.Config {
cfg.Version = params.VersionWithCommit(gitCommit)
cfg.HTTPModules = append(cfg.HTTPModules, "eth", "shh")
cfg.WSModules = append(cfg.WSModules, "eth", "shh")
cfg.IPCPath = "geth.ipc"
cfg.IPCPath = "XDC.ipc"
return cfg
}
func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
func makeConfigNode(ctx *cli.Context) (*node.Node, XDCConfig) {
// Load defaults.
cfg := gethConfig{
Eth: eth.DefaultConfig,
Shh: whisper.DefaultConfig,
Node: defaultNodeConfig(),
Dashboard: dashboard.DefaultConfig,
cfg := XDCConfig{
Eth: eth.DefaultConfig,
Shh: whisper.DefaultConfig,
Node: defaultNodeConfig(),
Dashboard: dashboard.DefaultConfig,
StakeEnable: true,
Verbosity: 3,
NAT: "",
}
// Load config file.
if file := ctx.GlobalString(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err)
}
}
if ctx.GlobalIsSet(utils.StakingEnabledFlag.Name) {
cfg.StakeEnable = ctx.GlobalBool(utils.StakingEnabledFlag.Name)
}
if !ctx.GlobalIsSet(debug.VerbosityFlag.Name) {
debug.Glogger.Verbosity(log.Lvl(cfg.Verbosity))
}
if !ctx.GlobalIsSet(utils.NATFlag.Name) && cfg.NAT != "" {
ctx.Set(utils.NATFlag.Name, cfg.NAT)
}
// Check testnet is enable.
if ctx.GlobalBool(utils.XDCTestnetFlag.Name) {
common.IsTestnet = true
}
// Check rollback hash exist.
if rollbackHash := ctx.GlobalString(utils.RollbackFlag.Name); rollbackHash != "" {
common.RollbackHash = common.HexToHash(rollbackHash)
}
// Check GasPrice
common.MinGasPrice = common.DefaultMinGasPrice
if ctx.GlobalIsSet(utils.GasPriceFlag.Name) {
if gasPrice := int64(ctx.GlobalInt(utils.GasPriceFlag.Name)); gasPrice > common.DefaultMinGasPrice {
common.MinGasPrice = gasPrice
}
}
// read passwords from environment
passwords := []string{}
for _, env := range cfg.Account.Passwords {
if trimmed := strings.TrimSpace(env); trimmed != "" {
value := os.Getenv(trimmed)
for _, info := range strings.Split(value, ",") {
if trimmed2 := strings.TrimSpace(info); trimmed2 != "" {
passwords = append(passwords, trimmed2)
}
}
}
}
cfg.Account.Passwords = passwords
// Apply flags.
utils.SetNodeConfig(ctx, &cfg.Node)
@ -140,6 +201,19 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
return stack, cfg
}
func applyValues(values []string, params *[]string) {
data := []string{}
for _, value := range values {
if trimmed := strings.TrimSpace(value); trimmed != "" {
data = append(data, trimmed)
}
}
if len(data) > 0 {
*params = data
}
}
// enableWhisper returns true in case one of the whisper flags is set.
func enableWhisper(ctx *cli.Context) bool {
for _, flag := range whisperFlags {
@ -150,7 +224,7 @@ func enableWhisper(ctx *cli.Context) bool {
return false
}
func makeFullNode(ctx *cli.Context) *node.Node {
func makeFullNode(ctx *cli.Context) (*node.Node, XDCConfig) {
stack, cfg := makeConfigNode(ctx)
utils.RegisterEthService(stack, &cfg.Eth)
@ -175,7 +249,7 @@ func makeFullNode(ctx *cli.Context) *node.Node {
if cfg.Ethstats.URL != "" {
utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
}
return stack
return stack, cfg
}
// dumpConfig is the dumpconfig command.

View file

@ -41,7 +41,7 @@ var (
Flags: append(append(append(nodeFlags, rpcFlags...), consoleFlags...), whisperFlags...),
Category: "CONSOLE COMMANDS",
Description: `
The Geth console is an interactive shell for the JavaScript runtime environment
The XDC console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.`,
}
@ -54,10 +54,10 @@ See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.`,
Flags: append(consoleFlags, utils.DataDirFlag),
Category: "CONSOLE COMMANDS",
Description: `
The Geth console is an interactive shell for the JavaScript runtime environment
The XDC console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.
This command allows to open a console on a running geth node.`,
This command allows to open a console on a running XDC node.`,
}
javascriptCommand = cli.Command{
@ -73,18 +73,18 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Cons
}
)
// localConsole starts a new geth node, attaching a JavaScript console to it at the
// localConsole starts a new XDC node, attaching a JavaScript console to it at the
// same time.
func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
node := makeFullNode(ctx)
startNode(ctx, node)
node, cfg := makeFullNode(ctx)
startNode(ctx, node, cfg)
defer node.Stop()
// Attach to the newly started node and start the JavaScript console
client, err := node.Attach()
if err != nil {
utils.Fatalf("Failed to attach to the inproc geth: %v", err)
utils.Fatalf("Failed to attach to the inproc XDC: %v", err)
}
config := console.Config{
DataDir: utils.MakeDataDir(ctx),
@ -111,10 +111,10 @@ func localConsole(ctx *cli.Context) error {
return nil
}
// remoteConsole will connect to a remote geth instance, attaching a JavaScript
// remoteConsole will connect to a remote XDC instance, attaching a JavaScript
// console to it.
func remoteConsole(ctx *cli.Context) error {
// Attach to a remotely running geth instance and start the JavaScript console
// Attach to a remotely running XDC instance and start the JavaScript console
endpoint := ctx.Args().First()
if endpoint == "" {
path := node.DefaultDataDir()
@ -128,11 +128,12 @@ func remoteConsole(ctx *cli.Context) error {
path = filepath.Join(path, "rinkeby")
}
}
endpoint = fmt.Sprintf("%s/geth.ipc", path)
endpoint = fmt.Sprintf("%s/XDC.ipc", path)
}
client, err := dialRPC(endpoint)
if err != nil {
utils.Fatalf("Unable to attach to remote geth: %v", err)
utils.Fatalf("Unable to attach to remote XDC: %v", err)
}
config := console.Config{
DataDir: utils.MakeDataDir(ctx),
@ -161,7 +162,7 @@ func remoteConsole(ctx *cli.Context) error {
// dialRPC returns a RPC client which connects to the given endpoint.
// The check for empty endpoint implements the defaulting logic
// for "geth attach" and "geth monitor" with no argument.
// for "XDC attach" and "XDC monitor" with no argument.
func dialRPC(endpoint string) (*rpc.Client, error) {
if endpoint == "" {
endpoint = node.DefaultIPCEndpoint(clientIdentifier)
@ -173,19 +174,19 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
return rpc.Dial(endpoint)
}
// ephemeralConsole starts a new geth node, attaches an ephemeral JavaScript
// ephemeralConsole starts a new XDC node, attaches an ephemeral JavaScript
// console to it, executes each of the files specified as arguments and tears
// everything down.
func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
node := makeFullNode(ctx)
startNode(ctx, node)
node, cfg := makeFullNode(ctx)
startNode(ctx, node, cfg)
defer node.Stop()
// Attach to the newly started node and start the JavaScript console
client, err := node.Attach()
if err != nil {
utils.Fatalf("Failed to attach to the inproc geth: %v", err)
utils.Fatalf("Failed to attach to the inproc XDC: %v", err)
}
config := console.Config{
DataDir: utils.MakeDataDir(ctx),

View file

@ -31,7 +31,7 @@ import (
)
const (
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0"
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0"
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
)
@ -40,25 +40,25 @@ const (
func TestConsoleWelcome(t *testing.T) {
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
// Start a geth console, make sure it's cleaned up and terminate the console
geth := runGeth(t,
// Start a XDC console, make sure it's cleaned up and terminate the console
XDC := runXDC(t,
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
"--etherbase", coinbase, "--shh",
"--etherbase", coinbase,
"console")
// Gather all the infos the welcome message needs to contain
geth.SetTemplateFunc("goos", func() string { return runtime.GOOS })
geth.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
geth.SetTemplateFunc("gover", runtime.Version)
geth.SetTemplateFunc("gethver", func() string { return params.Version })
geth.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
geth.SetTemplateFunc("apis", func() string { return ipcAPIs })
XDC.SetTemplateFunc("goos", func() string { return runtime.GOOS })
XDC.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
XDC.SetTemplateFunc("gover", runtime.Version)
XDC.SetTemplateFunc("XDCver", func() string { return params.Version })
XDC.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
XDC.SetTemplateFunc("apis", func() string { return ipcAPIs })
// Verify the actual welcome message to the required template
geth.Expect(`
Welcome to the Geth JavaScript console!
XDC.Expect(`
Welcome to the XDC JavaScript console!
instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}}
instance: XDC/v{{XDCver}}/{{goos}}-{{goarch}}/{{gover}}
coinbase: {{.Etherbase}}
at block: 0 ({{niltime}})
datadir: {{.Datadir}}
@ -66,7 +66,7 @@ at block: 0 ({{niltime}})
> {{.InputLine "exit"}}
`)
geth.ExpectExit()
XDC.ExpectExit()
}
// Tests that a console can be attached to a running node via various means.
@ -75,57 +75,55 @@ func TestIPCAttachWelcome(t *testing.T) {
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
var ipc string
if runtime.GOOS == "windows" {
ipc = `\\.\pipe\geth` + strconv.Itoa(trulyRandInt(100000, 999999))
ipc = `\\.\pipe\XDC` + strconv.Itoa(trulyRandInt(100000, 999999))
} else {
ws := tmpdir(t)
defer os.RemoveAll(ws)
ipc = filepath.Join(ws, "geth.ipc")
ipc = filepath.Join(ws, "XDC.ipc")
}
// Note: we need --shh because testAttachWelcome checks for default
// list of ipc modules and shh is included there.
geth := runGeth(t,
XDC := runXDC(t,
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
"--etherbase", coinbase, "--shh", "--ipcpath", ipc)
"--etherbase", coinbase, "--ipcpath", ipc)
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs)
testAttachWelcome(t, XDC, "ipc:"+ipc, ipcAPIs)
geth.Interrupt()
geth.ExpectExit()
XDC.Interrupt()
XDC.ExpectExit()
}
func TestHTTPAttachWelcome(t *testing.T) {
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P
geth := runGeth(t,
XDC := runXDC(t,
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
"--etherbase", coinbase, "--rpc", "--rpcport", port)
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
testAttachWelcome(t, geth, "http://localhost:"+port, httpAPIs)
testAttachWelcome(t, XDC, "http://localhost:"+port, httpAPIs)
geth.Interrupt()
geth.ExpectExit()
XDC.Interrupt()
XDC.ExpectExit()
}
func TestWSAttachWelcome(t *testing.T) {
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P
geth := runGeth(t,
XDC := runXDC(t,
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
"--etherbase", coinbase, "--ws", "--wsport", port)
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
testAttachWelcome(t, geth, "ws://localhost:"+port, httpAPIs)
testAttachWelcome(t, XDC, "ws://localhost:"+port, httpAPIs)
geth.Interrupt()
geth.ExpectExit()
XDC.Interrupt()
XDC.ExpectExit()
}
func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
// Attach to a running geth note and terminate immediately
attach := runGeth(t, "attach", endpoint)
func testAttachWelcome(t *testing.T, XDC *testXDC, endpoint, apis string) {
// Attach to a running XDC note and terminate immediately
attach := runXDC(t, "attach", endpoint)
defer attach.ExpectExit()
attach.CloseStdin()
@ -133,18 +131,18 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
attach.SetTemplateFunc("goos", func() string { return runtime.GOOS })
attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
attach.SetTemplateFunc("gover", runtime.Version)
attach.SetTemplateFunc("gethver", func() string { return params.Version })
attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase })
attach.SetTemplateFunc("XDCver", func() string { return params.Version })
attach.SetTemplateFunc("etherbase", func() string { return XDC.Etherbase })
attach.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
attach.SetTemplateFunc("datadir", func() string { return XDC.Datadir })
attach.SetTemplateFunc("apis", func() string { return apis })
// Verify the actual welcome message to the required template
attach.Expect(`
Welcome to the Geth JavaScript console!
Welcome to the XDC JavaScript console!
instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}}
instance: XDC/v{{XDCver}}/{{goos}}-{{goarch}}/{{gover}}
coinbase: {{etherbase}}
at block: 0 ({{niltime}}){{if ipc}}
datadir: {{datadir}}{{end}}

View file

@ -77,7 +77,7 @@ var daoProForkGenesis = `{
}
}`
var daoGenesisHash = common.HexToHash("5e1fc79cb4ffa4739177b5408045cd5d51c6cf766133f23f7cd72ee1f8d790e0")
var daoGenesisHash = common.HexToHash("29a4b5d743bfbda3a7461974d49c62bf23ba5df9c8b01de8256e2ac2a9ae1cd8")
var daoGenesisForkBlock = big.NewInt(314)
// TestDAOForkBlockNewChain tests that the DAO hard-fork number and the nodes support/opposition is correctly
@ -106,28 +106,28 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
datadir := tmpdir(t)
defer os.RemoveAll(datadir)
// Start a Geth instance with the requested flags set and immediately terminate
// Start a XDC instance with the requested flags set and immediately terminate
if genesis != "" {
json := filepath.Join(datadir, "genesis.json")
if err := ioutil.WriteFile(json, []byte(genesis), 0600); err != nil {
t.Fatalf("test %d: failed to write genesis file: %v", test, err)
}
runGeth(t, "--datadir", datadir, "init", json).WaitExit()
runXDC(t, "--datadir", datadir, "init", json).WaitExit()
} else {
// Force chain initialization
args := []string{"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir}
geth := runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...)
geth.WaitExit()
XDC := runXDC(t, append(args, []string{"--exec", "2+2", "console"}...)...)
XDC.WaitExit()
}
// Retrieve the DAO config flag from the database
path := filepath.Join(datadir, "geth", "chaindata")
path := filepath.Join(datadir, "XDC", "chaindata")
db, err := ethdb.NewLDBDatabase(path, 0, 0)
if err != nil {
t.Fatalf("test %d: failed to open test database: %v", test, err)
}
defer db.Close()
genesisHash := common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
genesisHash := common.HexToHash("8d13370621558f4ed0da587934473c0404729f28b0ff1d50e5fdd840457a2f17")
if genesis != "" {
genesisHash = daoGenesisHash
}

View file

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// geth is the official command-line client for Ethereum.
package main
import (
@ -29,7 +28,9 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/XDPoS"
"github.com/ethereum/go-ethereum/console"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/debug"
@ -40,16 +41,14 @@ import (
)
const (
clientIdentifier = "geth" // Client identifier to advertise over the network
clientIdentifier = "XDC" // Client identifier to advertise over the network
)
var (
// Git SHA1 commit hash of the release (set via linker flags)
gitCommit = ""
// Ethereum address of the Geth release oracle.
relOracle = common.HexToAddress("0xfa7b9770ca4cb04296cac84f37736d4041251cdf")
// The app that holds all commands and flags.
app = utils.NewApp(gitCommit, "the go-ethereum command line interface")
app = utils.NewApp(gitCommit, "the XDCchain command line interface")
// flags that configure the node
nodeFlags = []cli.Flag{
utils.IdentityFlag,
@ -60,17 +59,17 @@ var (
utils.BootnodesV5Flag,
utils.DataDirFlag,
utils.KeyStoreDirFlag,
utils.NoUSBFlag,
utils.DashboardEnabledFlag,
utils.DashboardAddrFlag,
utils.DashboardPortFlag,
utils.DashboardRefreshFlag,
utils.EthashCacheDirFlag,
utils.EthashCachesInMemoryFlag,
utils.EthashCachesOnDiskFlag,
utils.EthashDatasetDirFlag,
utils.EthashDatasetsInMemoryFlag,
utils.EthashDatasetsOnDiskFlag,
//utils.NoUSBFlag,
//utils.DashboardEnabledFlag,
//utils.DashboardAddrFlag,
//utils.DashboardPortFlag,
//utils.DashboardRefreshFlag,
//utils.EthashCacheDirFlag,
//utils.EthashCachesInMemoryFlag,
//utils.EthashCachesOnDiskFlag,
//utils.EthashDatasetDirFlag,
//utils.EthashDatasetsInMemoryFlag,
//utils.EthashDatasetsOnDiskFlag,
utils.TxPoolNoLocalsFlag,
utils.TxPoolJournalFlag,
utils.TxPoolRejournalFlag,
@ -85,43 +84,47 @@ var (
utils.LightModeFlag,
utils.SyncModeFlag,
utils.GCModeFlag,
utils.LightServFlag,
utils.LightPeersFlag,
utils.LightKDFFlag,
utils.CacheFlag,
utils.CacheDatabaseFlag,
utils.CacheGCFlag,
utils.TrieCacheGenFlag,
//utils.LightServFlag,
//utils.LightPeersFlag,
//utils.LightKDFFlag,
//utils.CacheFlag,
//utils.CacheDatabaseFlag,
//utils.CacheGCFlag,
//utils.TrieCacheGenFlag,
utils.ListenPortFlag,
utils.MaxPeersFlag,
utils.MaxPendingPeersFlag,
utils.EtherbaseFlag,
utils.GasPriceFlag,
utils.MinerThreadsFlag,
utils.MiningEnabledFlag,
utils.StakerThreadsFlag,
utils.StakingEnabledFlag,
utils.TargetGasLimitFlag,
utils.NATFlag,
utils.NoDiscoverFlag,
utils.DiscoveryV5Flag,
utils.NetrestrictFlag,
//utils.DiscoveryV5Flag,
//utils.NetrestrictFlag,
utils.NodeKeyFileFlag,
utils.NodeKeyHexFlag,
utils.DeveloperFlag,
utils.DeveloperPeriodFlag,
utils.TestnetFlag,
utils.RinkebyFlag,
utils.VMEnableDebugFlag,
//utils.DeveloperFlag,
//utils.DeveloperPeriodFlag,
//utils.TestnetFlag,
//utils.RinkebyFlag,
//utils.VMEnableDebugFlag,
utils.XDCTestnetFlag,
utils.NetworkIdFlag,
utils.RPCCORSDomainFlag,
utils.RPCVirtualHostsFlag,
utils.EthStatsURLFlag,
utils.MetricsEnabledFlag,
utils.FakePoWFlag,
utils.NoCompactionFlag,
utils.GpoBlocksFlag,
utils.GpoPercentileFlag,
utils.ExtraDataFlag,
//utils.FakePoWFlag,
//utils.NoCompactionFlag,
//utils.GpoBlocksFlag,
//utils.GpoPercentileFlag,
//utils.ExtraDataFlag,
configFileFlag,
utils.AnnounceTxsFlag,
utils.StoreRewardFlag,
utils.RollbackFlag,
}
rpcFlags = []cli.Flag{
@ -146,22 +149,17 @@ var (
)
func init() {
// Initialize the CLI app and start Geth
app.Action = geth
// Initialize the CLI app and start XDC
app.Action = XDC
app.HideVersion = true // we have a command to print the version
app.Copyright = "Copyright 2013-2017 The go-ethereum Authors"
app.Copyright = "Copyright (c) 2018 XDCchain"
app.Commands = []cli.Command{
// See chaincmd.go:
initCommand,
importCommand,
exportCommand,
importPreimagesCommand,
exportPreimagesCommand,
copydbCommand,
removedbCommand,
dumpCommand,
// See monitorcmd.go:
monitorCommand,
// See accountcmd.go:
accountCommand,
walletCommand,
@ -170,11 +168,7 @@ func init() {
attachCommand,
javascriptCommand,
// See misccmd.go:
makecacheCommand,
makedagCommand,
versionCommand,
bugCommand,
licenseCommand,
// See config.go
dumpConfigCommand,
}
@ -184,7 +178,7 @@ func init() {
app.Flags = append(app.Flags, rpcFlags...)
app.Flags = append(app.Flags, consoleFlags...)
app.Flags = append(app.Flags, debug.Flags...)
app.Flags = append(app.Flags, whisperFlags...)
//app.Flags = append(app.Flags, whisperFlags...)
app.Before = func(ctx *cli.Context) error {
runtime.GOMAXPROCS(runtime.NumCPU())
@ -212,12 +206,12 @@ func main() {
}
}
// geth is the main entry point into the system if no special subcommand is ran.
// XDC is the main entry point into the system if no special subcommand is ran.
// It creates a default node based on the command line arguments and runs it in
// blocking mode, waiting for it to be shut down.
func geth(ctx *cli.Context) error {
node := makeFullNode(ctx)
startNode(ctx, node)
func XDC(ctx *cli.Context) error {
node, cfg := makeFullNode(ctx)
startNode(ctx, node, cfg)
node.Wait()
return nil
}
@ -225,18 +219,24 @@ func geth(ctx *cli.Context) error {
// startNode boots up the system node and all registered protocols, after which
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
func startNode(ctx *cli.Context, stack *node.Node) {
func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
// Start up the node itself
utils.StartNode(stack)
// Unlock any account specifically requested
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
passwords := utils.MakePasswordList(ctx)
unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
for i, account := range unlocks {
if ctx.GlobalIsSet(utils.UnlockedAccountFlag.Name) {
cfg.Account.Unlocks = strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
}
if ctx.GlobalIsSet(utils.PasswordFileFlag.Name) {
cfg.Account.Passwords = utils.MakePasswordList(ctx)
}
for i, account := range cfg.Account.Unlocks {
if trimmed := strings.TrimSpace(account); trimmed != "" {
unlockAccount(ctx, ks, trimmed, i, passwords)
unlockAccount(ctx, ks, trimmed, i, cfg.Account.Passwords)
}
}
// Register wallet event handlers to open and auto-derive wallets
@ -281,28 +281,91 @@ func startNode(ctx *cli.Context, stack *node.Node) {
}
}()
// Start auxiliary services if enabled
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
// Mining only makes sense if a full Ethereum node is running
if ctx.GlobalBool(utils.LightModeFlag.Name) || ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
}
var ethereum *eth.Ethereum
if err := stack.Service(&ethereum); err != nil {
utils.Fatalf("Ethereum service not running: %v", err)
}
// Use a reduced number of threads if requested
if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 {
type threaded interface {
SetThreads(threads int)
// Mining only makes sense if a full Ethereum node is running
if ctx.GlobalBool(utils.LightModeFlag.Name) || ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support staking")
}
var ethereum *eth.Ethereum
if err := stack.Service(&ethereum); err != nil {
utils.Fatalf("Ethereum service not running: %v", err)
}
if _, ok := ethereum.Engine().(*XDPoS.XDPoS); ok {
go func() {
started := false
ok := false
var err error
if common.IsTestnet {
ok, err = ethereum.ValidateMasternodeTestnet()
if err != nil {
utils.Fatalf("Can't verify masternode permission: %v", err)
}
} else {
ok, err = ethereum.ValidateMasternode()
if err != nil {
utils.Fatalf("Can't verify masternode permission: %v", err)
}
}
if th, ok := ethereum.Engine().(threaded); ok {
th.SetThreads(threads)
if ok {
log.Info("Masternode found. Enabling staking mode...")
// Use a reduced number of threads if requested
if threads := ctx.GlobalInt(utils.StakerThreadsFlag.Name); threads > 0 {
type threaded interface {
SetThreads(threads int)
}
if th, ok := ethereum.Engine().(threaded); ok {
th.SetThreads(threads)
}
}
// Set the gas price to the limits from the CLI and start mining
ethereum.TxPool().SetGasPrice(cfg.Eth.GasPrice)
if err := ethereum.StartStaking(true); err != nil {
utils.Fatalf("Failed to start staking: %v", err)
}
started = true
log.Info("Enabled staking node!!!")
}
}
// Set the gas price to the limits from the CLI and start mining
ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name))
if err := ethereum.StartMining(true); err != nil {
utils.Fatalf("Failed to start mining: %v", err)
}
defer close(core.CheckpointCh)
for range core.CheckpointCh {
log.Info("Checkpoint!!! It's time to reconcile node's state...")
if common.IsTestnet {
ok, err = ethereum.ValidateMasternodeTestnet()
if err != nil {
utils.Fatalf("Can't verify masternode permission: %v", err)
}
} else {
ok, err = ethereum.ValidateMasternode()
if err != nil {
utils.Fatalf("Can't verify masternode permission: %v", err)
}
}
if !ok {
if started {
log.Info("Only masternode can propose and verify blocks. Cancelling staking on this node...")
ethereum.StopStaking()
started = false
log.Info("Cancelled mining mode!!!")
}
} else if !started {
log.Info("Masternode found. Enabling staking mode...")
// Use a reduced number of threads if requested
if threads := ctx.GlobalInt(utils.StakerThreadsFlag.Name); threads > 0 {
type threaded interface {
SetThreads(threads int)
}
if th, ok := ethereum.Engine().(threaded); ok {
th.SetThreads(threads)
}
}
// Set the gas price to the limits from the CLI and start mining
ethereum.TxPool().SetGasPrice(cfg.Eth.GasPrice)
if err := ethereum.StartStaking(true); err != nil {
utils.Fatalf("Failed to start staking: %v", err)
}
started = true
log.Info("Enabled staking node!!!")
}
}
}()
}
}

View file

@ -80,7 +80,7 @@ The output of this command is supposed to be machine-readable.
func makecache(ctx *cli.Context) error {
args := ctx.Args()
if len(args) != 2 {
utils.Fatalf(`Usage: geth makecache <block number> <outputdir>`)
utils.Fatalf(`Usage: XDC makecache <block number> <outputdir>`)
}
block, err := strconv.ParseUint(args[0], 0, 64)
if err != nil {
@ -95,7 +95,7 @@ func makecache(ctx *cli.Context) error {
func makedag(ctx *cli.Context) error {
args := ctx.Args()
if len(args) != 2 {
utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`)
utils.Fatalf(`Usage: XDC makedag <block number> <outputdir>`)
}
block, err := strconv.ParseUint(args[0], 0, 64)
if err != nil {
@ -123,17 +123,17 @@ func version(ctx *cli.Context) error {
}
func license(_ *cli.Context) error {
fmt.Println(`Geth is free software: you can redistribute it and/or modify
fmt.Println(`XDC 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.
Geth is distributed in the hope that it will be useful,
XDC 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 geth. If not, see <http://www.gnu.org/licenses/>.`)
along with XDC. If not, see <http://www.gnu.org/licenses/>.`)
return nil
}

View file

@ -55,7 +55,7 @@ var (
ArgsUsage: " ",
Category: "MONITOR COMMANDS",
Description: `
The Geth monitor is a tool to collect and visualize various internal metrics
The XDC monitor is a tool to collect and visualize various internal metrics
gathered by the node, supporting different chart types as well as the capacity
to display multiple metrics simultaneously.
`,
@ -76,7 +76,7 @@ func monitor(ctx *cli.Context) error {
// Attach to an Ethereum node over IPC or RPC
endpoint := ctx.String(monitorCommandAttachFlag.Name)
if client, err = dialRPC(endpoint); err != nil {
utils.Fatalf("Unable to attach to geth node: %v", err)
utils.Fatalf("Unable to attach to XDC node: %v", err)
}
defer client.Close()
@ -93,7 +93,7 @@ func monitor(ctx *cli.Context) error {
if len(list) > 0 {
utils.Fatalf("No metrics specified.\n\nAvailable:\n - %s", strings.Join(list, "\n - "))
} else {
utils.Fatalf("No metrics collected by geth (--%s).\n", utils.MetricsEnabledFlag.Name)
utils.Fatalf("No metrics collected by XDC (--%s).\n", utils.MetricsEnabledFlag.Name)
}
}
sort.Strings(monitored)
@ -158,7 +158,7 @@ func monitor(ctx *cli.Context) error {
return nil
}
// retrieveMetrics contacts the attached geth node and retrieves the entire set
// retrieveMetrics contacts the attached XDC node and retrieves the entire set
// of collected system metrics.
func retrieveMetrics(client *rpc.Client) (map[string]interface{}, error) {
var metrics map[string]interface{}

View file

@ -27,14 +27,14 @@ import (
)
func tmpdir(t *testing.T) string {
dir, err := ioutil.TempDir("", "geth-test")
dir, err := ioutil.TempDir("", "XDC-test")
if err != nil {
t.Fatal(err)
}
return dir
}
type testgeth struct {
type testXDC struct {
*cmdtest.TestCmd
// template variables for expect
@ -43,8 +43,8 @@ type testgeth struct {
}
func init() {
// Run the app if we've been exec'd as "geth-test" in runGeth.
reexec.Register("geth-test", func() {
// Run the app if we've been exec'd as "XDC-test" in runGeth.
reexec.Register("XDC-test", func() {
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
@ -61,10 +61,10 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}
// spawns geth with the given command line args. If the args don't set --datadir, the
// spawns XDC with the given command line args. If the args don't set --datadir, the
// child g gets a temporary data directory.
func runGeth(t *testing.T, args ...string) *testgeth {
tt := &testgeth{}
func runXDC(t *testing.T, args ...string) *testXDC {
tt := &testXDC{}
tt.TestCmd = cmdtest.NewTestCmd(t, tt)
for i, arg := range args {
switch {
@ -90,9 +90,9 @@ func runGeth(t *testing.T, args ...string) *testgeth {
}()
}
// Boot "geth". This actually runs the test binary but the TestMain
// Boot "XDC". This actually runs the test binary but the TestMain
// function will prevent any tests from running.
tt.Run("geth-test", args...)
tt.Run("XDC-test", args...)
return tt
}

54
cmd/XDC/testdata/config.toml vendored Normal file
View file

@ -0,0 +1,54 @@
StakeEnable = true # flag --miner ( true : enable staker , false : disable )
Verbosity = 0 # flag --verbosity (0=Crit 1=Error 2=Warn 3=Info 4=Debug 5=Trace)
NAT = "" # flag --nat
[Eth]
NetworkId = 89 # flag --networkid
SyncMode = "full" # flag --syncmode
GasPrice = 1 # flag --gasprice
[Shh]
[Node]
DataDir = "node1/" # flag --datadir
HTTPPort = 8501 # flag --rpcport
HTTPHost = "localhost" # flags --rpcaddr & --rpc
# in 3 cases :
# HTTPHost is "" == --rpc & --rpcaddr is not set
# HTTPHost is "localhost" or "127.0.0.1" == only set --rpc
# HTTPHost is other IP (ex : 192.168.1.1) = set 2 flags --rpc & --rpcaddr
WSHost = "localhost" # flags --wsaddr & --ws . same option HTTPHost
WSPort = 8546 # flag --wsport
WSModules = ["eth","ssh"] #flag --wsapi
HTTPModules = ["personal","db","eth","net","web3","txpool","miner"] # flag --rpcapi
KeyStoreDir = "" # flag --keystore
UserIdent = "" # flag --identity
[Node.P2P]
ListenAddr = ":30311" # flag --port
MaxPeers = 200 # flag --maxpeers
BootstrapNodes = ["enode://a890c5762c406fe046fb93fd307577a8454d571b6bf789f7dbfbf3c559be751f5fa400bc10639691245a9b22be1cfce0bbf82b322a24d06c6dcf29bf7eeb930c@127.0.0.1:30310"] # flag --bootnodes
[Ethstats]
URL = "" # flag --ethstats
[Dashboard]
[Account]
Unlocks = ["0x12f90a417f41bedd4bbcc99d52971803fb4c3f8b"] # list account slipt in flag --unlock
Passwords = ["PWD_DEVNET"] # list password in environment variable (split by ',') : ex : export PWD_DEVNET=123456,123456789
[Bootnodes]
Mainnet =[]
Testnet =[]

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// Contains the geth command usage template and generator.
// Contains the XDC command usage template and generator.
package main
@ -33,7 +33,7 @@ import (
var AppHelpTemplate = `NAME:
{{.App.Name}} - {{.App.Usage}}
Copyright 2013-2017 The go-ethereum Authors
Copyright (c) 2018 XDCchain
USAGE:
{{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}}
@ -65,41 +65,41 @@ type flagGroup struct {
// AppHelpFlagGroups is the application flags, grouped by functionality.
var AppHelpFlagGroups = []flagGroup{
{
Name: "ETHEREUM",
Name: "XDCCHAIN",
Flags: []cli.Flag{
configFileFlag,
utils.DataDirFlag,
utils.KeyStoreDirFlag,
utils.NoUSBFlag,
//utils.NoUSBFlag,
utils.NetworkIdFlag,
utils.TestnetFlag,
utils.RinkebyFlag,
//utils.TestnetFlag,
//utils.RinkebyFlag,
utils.SyncModeFlag,
utils.GCModeFlag,
utils.EthStatsURLFlag,
utils.IdentityFlag,
utils.LightServFlag,
utils.LightPeersFlag,
utils.LightKDFFlag,
},
},
{Name: "DEVELOPER CHAIN",
Flags: []cli.Flag{
utils.DeveloperFlag,
utils.DeveloperPeriodFlag,
},
},
{
Name: "ETHASH",
Flags: []cli.Flag{
utils.EthashCacheDirFlag,
utils.EthashCachesInMemoryFlag,
utils.EthashCachesOnDiskFlag,
utils.EthashDatasetDirFlag,
utils.EthashDatasetsInMemoryFlag,
utils.EthashDatasetsOnDiskFlag,
//utils.LightServFlag,
//utils.LightPeersFlag,
//utils.LightKDFFlag,
},
},
//{Name: "DEVELOPER CHAIN",
// Flags: []cli.Flag{
// utils.DeveloperFlag,
// utils.DeveloperPeriodFlag,
// },
//},
//{
// Name: "ETHASH",
// Flags: []cli.Flag{
// utils.EthashCacheDirFlag,
// utils.EthashCachesInMemoryFlag,
// utils.EthashCachesOnDiskFlag,
// utils.EthashDatasetDirFlag,
// utils.EthashDatasetsInMemoryFlag,
// utils.EthashDatasetsOnDiskFlag,
// },
//},
//{
// Name: "DASHBOARD",
// Flags: []cli.Flag{
@ -110,30 +110,30 @@ var AppHelpFlagGroups = []flagGroup{
// utils.DashboardAssetsFlag,
// },
//},
{
Name: "TRANSACTION POOL",
Flags: []cli.Flag{
utils.TxPoolNoLocalsFlag,
utils.TxPoolJournalFlag,
utils.TxPoolRejournalFlag,
utils.TxPoolPriceLimitFlag,
utils.TxPoolPriceBumpFlag,
utils.TxPoolAccountSlotsFlag,
utils.TxPoolGlobalSlotsFlag,
utils.TxPoolAccountQueueFlag,
utils.TxPoolGlobalQueueFlag,
utils.TxPoolLifetimeFlag,
},
},
{
Name: "PERFORMANCE TUNING",
Flags: []cli.Flag{
utils.CacheFlag,
utils.CacheDatabaseFlag,
utils.CacheGCFlag,
utils.TrieCacheGenFlag,
},
},
//{
// Name: "TRANSACTION POOL",
// Flags: []cli.Flag{
// utils.TxPoolNoLocalsFlag,
// utils.TxPoolJournalFlag,
// utils.TxPoolRejournalFlag,
// utils.TxPoolPriceLimitFlag,
// utils.TxPoolPriceBumpFlag,
// utils.TxPoolAccountSlotsFlag,
// utils.TxPoolGlobalSlotsFlag,
// utils.TxPoolAccountQueueFlag,
// utils.TxPoolGlobalQueueFlag,
// utils.TxPoolLifetimeFlag,
// },
//},
//{
// Name: "PERFORMANCE TUNING",
// Flags: []cli.Flag{
// utils.CacheFlag,
// utils.CacheDatabaseFlag,
// utils.CacheGCFlag,
// utils.TrieCacheGenFlag,
// },
//},
{
Name: "ACCOUNT",
Flags: []cli.Flag{
@ -173,48 +173,48 @@ var AppHelpFlagGroups = []flagGroup{
utils.MaxPendingPeersFlag,
utils.NATFlag,
utils.NoDiscoverFlag,
utils.DiscoveryV5Flag,
utils.NetrestrictFlag,
//utils.DiscoveryV5Flag,
//utils.NetrestrictFlag,
utils.NodeKeyFileFlag,
utils.NodeKeyHexFlag,
},
},
{
Name: "MINER",
Name: "STAKER",
Flags: []cli.Flag{
utils.MiningEnabledFlag,
utils.MinerThreadsFlag,
utils.StakingEnabledFlag,
utils.StakerThreadsFlag,
utils.EtherbaseFlag,
utils.TargetGasLimitFlag,
utils.GasPriceFlag,
utils.ExtraDataFlag,
},
},
{
Name: "GAS PRICE ORACLE",
Flags: []cli.Flag{
utils.GpoBlocksFlag,
utils.GpoPercentileFlag,
},
},
{
Name: "VIRTUAL MACHINE",
Flags: []cli.Flag{
utils.VMEnableDebugFlag,
},
},
//{
// Name: "GAS PRICE ORACLE",
// Flags: []cli.Flag{
// utils.GpoBlocksFlag,
// utils.GpoPercentileFlag,
// },
//},
//{
// Name: "VIRTUAL MACHINE",
// Flags: []cli.Flag{
// utils.VMEnableDebugFlag,
// },
//},
{
Name: "LOGGING AND DEBUGGING",
Flags: append([]cli.Flag{
utils.MetricsEnabledFlag,
utils.FakePoWFlag,
utils.NoCompactionFlag,
//utils.FakePoWFlag,
//utils.NoCompactionFlag,
}, debug.Flags...),
},
{
Name: "WHISPER (EXPERIMENTAL)",
Flags: whisperFlags,
},
//{
// Name: "WHISPER (EXPERIMENTAL)",
// Flags: whisperFlags,
//},
{
Name: "DEPRECATED",
Flags: []cli.Flag{

270
cmd/XDCclean/main.go Normal file
View file

@ -0,0 +1,270 @@
package main
import (
"flag"
"fmt"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/hashicorp/golang-lru"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
"os"
"os/signal"
"runtime"
"sync"
"sync/atomic"
"time"
)
var (
dir = flag.String("dir", "", "dir to mainet chain data")
cacheSize = flag.Int("size", 1000000, "dir to mainet chain data")
)
type TrieRoot struct {
trie *trie.SecureTrie
number uint64
}
type StateNode struct {
node trie.Node
path []byte
}
type ResultProcessNode struct {
index int
number int
newNodes [17]*StateNode
keys [17]*[]byte
}
var sercureKey = []byte("secure-key-")
var nWorker = runtime.NumCPU() / 2
var cleanAddress = []common.Address{common.HexToAddress(common.BlockSigners)}
var cache *lru.Cache
var finish = int32(0)
var running = true
var stateRoots = make(chan TrieRoot)
func main() {
flag.Parse()
lddb, _ := ethdb.NewLDBDatabase(*dir, eth.DefaultConfig.DatabaseCache, utils.MakeDatabaseHandles())
head := core.GetHeadBlockHash(lddb)
currentHeader := core.GetHeader(lddb, head, core.GetBlockNumber(lddb, head))
tridb := trie.NewDatabase(lddb)
catchEventInterupt(lddb.LDB())
cache, _ = lru.New(*cacheSize)
go func() {
for i := uint64(1); i <= currentHeader.Number.Uint64(); i++ {
hash := core.GetCanonicalHash(lddb, i)
root := core.GetHeader(lddb, hash, i).Root
trieRoot, err := trie.NewSecure(root, tridb, 0)
if err != nil {
continue
}
if running {
stateRoots <- TrieRoot{trieRoot, i}
} else {
break
}
}
if running {
close(stateRoots)
}
}()
for trieRoot := range stateRoots {
atomic.StoreInt32(&finish, 1)
if running {
for _, address := range cleanAddress {
enc := trieRoot.trie.Get(address.Bytes())
var data state.Account
rlp.DecodeBytes(enc, &data)
fmt.Println(time.Now().Format(time.RFC3339), "Start clean state address ", address.Hex(), " at block ", trieRoot.number)
signerRoot, err := resolveHash(data.Root[:], lddb.LDB())
if err != nil {
fmt.Println(time.Now().Format(time.RFC3339), "Not found clean state address ", address.Hex(), " at block ", trieRoot.number)
continue
}
batch := new(leveldb.Batch)
count := 1
list := []*StateNode{{node: signerRoot}}
for len(list) > 0 {
newList, total := findNewNodes(list, lddb.LDB(), batch)
count = count + 17*len(newList)
list = removeNodesNil(newList, total)
}
fmt.Println(time.Now().Format(time.RFC3339), "Finish clean state address ", address.Hex(), " at block ", trieRoot.number, " keys ", count)
err = lddb.LDB().Write(batch, nil)
if err != nil {
fmt.Println(time.Now().Format(time.RFC3339), "Write batch leveldb error", err)
os.Exit(1)
}
}
} else {
break
}
atomic.StoreInt32(&finish, 0)
}
fmt.Println(time.Now(), "compact")
lddb.LDB().CompactRange(util.Range{})
lddb.Close()
fmt.Println(time.Now(), "end")
}
func removeNodesNil(list [][17]*StateNode, length int) []*StateNode {
results := make([]*StateNode, length)
index := 0
for _, nodes := range list {
for _, node := range nodes {
if node != nil {
results[index] = node
index++
}
}
}
return results
}
func catchEventInterupt(db *leveldb.DB) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
fmt.Println("catch event interrupt ", sig, running, finish)
running = false
if atomic.LoadInt32(&finish) == 0 {
close(stateRoots)
db.Close()
os.Exit(1)
}
}
}()
}
func resolveHash(n trie.HashNode, db *leveldb.DB) (trie.Node, error) {
if cache.Contains(common.BytesToHash(n)) {
return nil, &trie.MissingNodeError{}
}
enc, err := db.Get(n, nil)
if err != nil || enc == nil {
return nil, &trie.MissingNodeError{}
}
return trie.MustDecodeNode(n, enc, 0), nil
}
func getAllChilds(n StateNode, db *leveldb.DB) ([17]*StateNode, error) {
childs := [17]*StateNode{}
switch node := n.node.(type) {
case *trie.FullNode:
// Full Node, move to the first non-nil child.
for i := 0; i < len(node.Children); i++ {
child := node.Children[i]
if child != nil {
childNode := child
var err error = nil
if _, ok := child.(trie.HashNode); ok {
childNode, err = resolveHash(child.(trie.HashNode), db)
}
if err == nil {
childs[i] = &StateNode{node: childNode, path: append(n.path, byte(i))}
} else if err != nil {
_, ok := err.(*trie.MissingNodeError)
if !ok {
return childs, err
}
}
}
}
case *trie.ShortNode:
// Short Node, return the pointer singleton child
childNode := node.Val
var err error = nil
if _, ok := node.Val.(trie.HashNode); ok {
childNode, err = resolveHash(node.Val.(trie.HashNode), db)
}
if err == nil {
childs[0] = &StateNode{node: childNode, path: append(n.path, node.Key...)}
} else if err != nil {
_, ok := err.(*trie.MissingNodeError)
if !ok {
return childs, err
}
}
}
return childs, nil
}
func processNodes(node StateNode, db *leveldb.DB) ([17]*StateNode, [17]*[]byte, int) {
hash, _ := node.node.Cache()
commonHash := common.BytesToHash(hash)
newNodes := [17]*StateNode{}
keys := [17]*[]byte{}
number := 0
if !cache.Contains(commonHash) {
childNodes, err := getAllChilds(node, db)
if err != nil {
fmt.Println("Error when get all childs node : ", common.Bytes2Hex(node.path), err)
os.Exit(1)
}
for i, child := range childNodes {
if child != nil {
if _, ok := child.node.(trie.ValueNode); ok {
buf := append(sercureKey, child.path...)
keys[i] = &buf
} else {
hash, _ := child.node.Cache()
var bytes []byte = hash
keys[i] = &bytes
newNodes[i] = child
number++
}
}
}
cache.Add(commonHash, true)
}
return newNodes, keys, number
}
func findNewNodes(nodes []*StateNode, db *leveldb.DB, batchlvdb *leveldb.Batch) ([][17]*StateNode, int) {
length := len(nodes)
chunkSize := length / nWorker
if len(nodes)%nWorker != 0 {
chunkSize++
}
childNodes := make([][17]*StateNode, length)
results := make(chan ResultProcessNode)
wg := sync.WaitGroup{}
wg.Add(length)
for i := 0; i < nWorker; i++ {
from := i * chunkSize
to := from + chunkSize
if to > length {
to = length
}
go func(from int, to int) {
for j := from; j < to; j++ {
childs, keys, number := processNodes(*nodes[j], db)
go func(result ResultProcessNode) {
results <- result
}(ResultProcessNode{j, number, childs, keys})
}
}(from, to)
}
total := 0
go func() {
for result := range results {
childNodes[result.index] = result.newNodes
total = total + result.number
for _, key := range result.keys {
if key != nil {
batchlvdb.Delete(*key)
}
}
wg.Done()
}
}()
wg.Wait()
close(results)
return childNodes, total
}

View file

@ -215,7 +215,7 @@ type faucet struct {
func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte) (*faucet, error) {
// Assemble the raw devp2p protocol stack
stack, err := node.New(&node.Config{
Name: "geth",
Name: "XDC",
Version: params.Version,
DataDir: filepath.Join(os.Getenv("HOME"), ".faucet"),
P2P: p2p.Config{

View file

@ -1,110 +0,0 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// 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 (
"io/ioutil"
"os"
"path/filepath"
"testing"
)
var customGenesisTests = []struct {
genesis string
query string
result string
}{
// Plain genesis file without anything extra
{
genesis: `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
}`,
query: "eth.getBlock(0).nonce",
result: "0x0000000000000042",
},
// Genesis file with an empty chain configuration (ensure missing fields work)
{
genesis: `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config" : {}
}`,
query: "eth.getBlock(0).nonce",
result: "0x0000000000000042",
},
// Genesis file with specific chain configurations
{
genesis: `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config" : {
"homesteadBlock" : 314,
"daoForkBlock" : 141,
"daoForkSupport" : true
},
}`,
query: "eth.getBlock(0).nonce",
result: "0x0000000000000042",
},
}
// Tests that initializing Geth with a custom genesis block and chain definitions
// work properly.
func TestCustomGenesis(t *testing.T) {
for i, tt := range customGenesisTests {
// Create a temporary data directory to use and inspect later
datadir := tmpdir(t)
defer os.RemoveAll(datadir)
// Initialize the data directory with the custom genesis block
json := filepath.Join(datadir, "genesis.json")
if err := ioutil.WriteFile(json, []byte(tt.genesis), 0600); err != nil {
t.Fatalf("test %d: failed to write genesis file: %v", i, err)
}
runGeth(t, "--datadir", datadir, "init", json).WaitExit()
// Query the custom genesis block
geth := runGeth(t,
"--datadir", datadir, "--maxpeers", "0", "--port", "0",
"--nodiscover", "--nat", "none", "--ipcdisable",
"--exec", tt.query, "console")
geth.ExpectRegexp(tt.result)
geth.ExpectExit()
}
}

View file

@ -40,11 +40,11 @@ ADD genesis.json /genesis.json
ADD signer.pass /signer.pass
{{end}}
RUN \
echo 'geth --cache 512 init /genesis.json' > geth.sh && \{{if .Unlock}}
echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}}
echo $'geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--etherbase {{.Etherbase}} --mine --minerthreads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --targetgaslimit {{.GasTarget}} --gasprice {{.GasPrice}}' >> geth.sh
echo 'XDC --cache 512 init /genesis.json' > XDC.sh && \{{if .Unlock}}
echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> XDC.sh && \{{end}}
echo $'XDC --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--etherbase {{.Etherbase}} --mine --minerthreads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --targetgaslimit {{.GasTarget}} --gasprice {{.GasPrice}}' >> XDC.sh
ENTRYPOINT ["/bin/sh", "geth.sh"]
ENTRYPOINT ["/bin/sh", "XDC.sh"]
`
// nodeComposefile is the docker-compose.yml file required to deploy and maintain
@ -184,7 +184,7 @@ func (info *nodeInfos) Report() map[string]string {
report["Miner account"] = info.etherbase
}
if info.keyJSON != "" {
// Clique proof-of-authority signer
// XDPoS delegated-proof-of-stake signer
var key struct {
Address string `json:"address"`
}
@ -221,7 +221,7 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
// Container available, retrieve its node ID and its genesis json
var out []byte
if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 geth --exec admin.nodeInfo.id attach", network, kind)); err != nil {
if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 XDC --exec admin.nodeInfo.id attach", network, kind)); err != nil {
return nil, ErrServiceUnreachable
}
id := bytes.Trim(bytes.TrimSpace(out), "\"")

View file

@ -36,8 +36,8 @@ ADD genesis.json /genesis.json
RUN \
echo 'node server.js &' > wallet.sh && \
echo 'geth --cache 512 init /genesis.json' >> wallet.sh && \
echo $'geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*"' >> wallet.sh
echo 'XDC --cache 512 init /genesis.json' >> wallet.sh && \
echo $'XDC --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*"' >> wallet.sh
RUN \
sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \

View file

@ -244,7 +244,7 @@ func (w *wizard) readPassword() string {
func (w *wizard) readAddress() *common.Address {
for {
// Read the address from the user
fmt.Printf("> 0x")
fmt.Printf("> xdc")
text, err := w.in.ReadString('\n')
if err != nil {
log.Crit("Failed to read user input", "err", err)
@ -269,7 +269,7 @@ func (w *wizard) readAddress() *common.Address {
func (w *wizard) readDefaultAddress(def common.Address) common.Address {
for {
// Read the address from the user
fmt.Printf("> 0x")
fmt.Printf("> xdc")
text, err := w.in.ReadString('\n')
if err != nil {
log.Crit("Failed to read user input", "err", err)

View file

@ -21,7 +21,6 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"math/big"
"math/rand"
"time"
@ -29,6 +28,18 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"context"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
blockSignerContract "github.com/ethereum/go-ethereum/contracts/blocksigner"
multiSignWalletContract "github.com/ethereum/go-ethereum/contracts/multisigwallet"
randomizeContract "github.com/ethereum/go-ethereum/contracts/randomize"
validatorContract "github.com/ethereum/go-ethereum/contracts/validator"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
)
// makeGenesis creates a new genesis struct based on some user input.
@ -49,9 +60,10 @@ func (w *wizard) makeGenesis() {
}
// Figure out which consensus engine to choose
fmt.Println()
fmt.Println("Which consensus engine to use? (default = clique)")
fmt.Println("Which consensus engine to use? (default = XDPoS)")
fmt.Println(" 1. Ethash - proof-of-work")
fmt.Println(" 2. Clique - proof-of-authority")
fmt.Println(" 3. XDPoS - delegated-proof-of-stake")
choice := w.read()
switch {
@ -60,7 +72,7 @@ func (w *wizard) makeGenesis() {
genesis.Config.Ethash = new(params.EthashConfig)
genesis.ExtraData = make([]byte, 32)
case choice == "" || choice == "2":
case choice == "2":
// In the case of clique, configure the consensus parameters
genesis.Difficulty = big.NewInt(1)
genesis.Config.Clique = &params.CliqueConfig{
@ -98,6 +110,217 @@ func (w *wizard) makeGenesis() {
copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:])
}
case choice == "" || choice == "3":
genesis.Difficulty = big.NewInt(1)
genesis.Config.XDPoS = &params.XDPoSConfig{
Period: 15,
Epoch: 30000,
Reward: 0,
}
fmt.Println()
fmt.Println("How many seconds should blocks take? (default = 2)")
genesis.Config.XDPoS.Period = uint64(w.readDefaultInt(2))
fmt.Println()
fmt.Println("How many Ethers should be rewarded to masternode? (default = 10)")
genesis.Config.XDPoS.Reward = uint64(w.readDefaultInt(10))
fmt.Println()
fmt.Println("Who own the first masternodes? (mandatory)")
owner := *w.readAddress()
// We also need the initial list of signers
fmt.Println()
fmt.Println("Which accounts are allowed to seal (signers)? (mandatory at least one)")
var signers []common.Address
for {
if address := w.readAddress(); address != nil {
signers = append(signers, *address)
continue
}
if len(signers) > 0 {
break
}
}
// Sort the signers and embed into the extra-data section
for i := 0; i < len(signers); i++ {
for j := i + 1; j < len(signers); j++ {
if bytes.Compare(signers[i][:], signers[j][:]) > 0 {
signers[i], signers[j] = signers[j], signers[i]
}
}
}
validatorCap := new(big.Int)
validatorCap.SetString("50000000000000000000000", 10)
var validatorCaps []*big.Int
genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+65)
for i, signer := range signers {
validatorCaps = append(validatorCaps, validatorCap)
copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:])
}
fmt.Println()
fmt.Println("How many blocks per epoch? (default = 900)")
epochNumber := uint64(w.readDefaultInt(900))
genesis.Config.XDPoS.Epoch = epochNumber
genesis.Config.XDPoS.RewardCheckpoint = epochNumber
fmt.Println()
fmt.Println("How many blocks before checkpoint need to prepare new set of masternodes? (default = 450)")
genesis.Config.XDPoS.Gap = uint64(w.readDefaultInt(450))
fmt.Println()
fmt.Println("What is foundation wallet address? (default = xdc0000000000000000000000000000000000000068)")
genesis.Config.XDPoS.FoudationWalletAddr = w.readDefaultAddress(common.HexToAddress(common.FoudationAddr))
// Validator Smart Contract Code
pKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr := crypto.PubkeyToAddress(pKey.PublicKey)
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}})
transactOpts := bind.NewKeyedTransactor(pKey)
validatorAddress, _, err := validatorContract.DeployValidator(transactOpts, contractBackend, signers, validatorCaps, owner)
if err != nil {
fmt.Println("Can't deploy root registry")
}
contractBackend.Commit()
d := time.Now().Add(1000 * time.Millisecond)
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
code, _ := contractBackend.CodeAt(ctx, validatorAddress, nil)
storage := make(map[common.Hash]common.Hash)
f := func(key, val common.Hash) bool {
decode := []byte{}
trim := bytes.TrimLeft(val.Bytes(), "\x00")
rlp.DecodeBytes(trim, &decode)
storage[key] = common.BytesToHash(decode)
log.Info("DecodeBytes", "value", val.String(), "decode", storage[key].String())
return true
}
contractBackend.ForEachStorageAt(ctx, validatorAddress, nil, f)
genesis.Alloc[common.HexToAddress(common.MasternodeVotingSMC)] = core.GenesisAccount{
Balance: validatorCap.Mul(validatorCap, big.NewInt(int64(len(validatorCaps)))),
Code: code,
Storage: storage,
}
fmt.Println()
fmt.Println("Which accounts are allowed to confirm in Foudation MultiSignWallet?")
var owners []common.Address
for {
if address := w.readAddress(); address != nil {
owners = append(owners, *address)
continue
}
if len(owners) > 0 {
break
}
}
fmt.Println()
fmt.Println("How many require for confirm tx in Foudation MultiSignWallet? (default = 2)")
required := int64(w.readDefaultInt(2))
// MultiSigWallet.
multiSignWalletAddr, _, err := multiSignWalletContract.DeployMultiSigWallet(transactOpts, contractBackend, owners, big.NewInt(required))
if err != nil {
fmt.Println("Can't deploy MultiSignWallet SMC")
}
contractBackend.Commit()
code, _ = contractBackend.CodeAt(ctx, multiSignWalletAddr, nil)
storage = make(map[common.Hash]common.Hash)
contractBackend.ForEachStorageAt(ctx, multiSignWalletAddr, nil, f)
fBalance := big.NewInt(0) // 16m
fBalance.Add(fBalance, big.NewInt(16*1000*1000))
fBalance.Mul(fBalance, big.NewInt(1000000000000000000))
genesis.Alloc[common.HexToAddress(common.FoudationAddr)] = core.GenesisAccount{
Balance: fBalance,
Code: code,
Storage: storage,
}
// Block Signers Smart Contract
blockSignerAddress, _, err := blockSignerContract.DeployBlockSigner(transactOpts, contractBackend, big.NewInt(int64(epochNumber)))
if err != nil {
fmt.Println("Can't deploy root registry")
}
contractBackend.Commit()
code, _ = contractBackend.CodeAt(ctx, blockSignerAddress, nil)
storage = make(map[common.Hash]common.Hash)
contractBackend.ForEachStorageAt(ctx, blockSignerAddress, nil, f)
genesis.Alloc[common.HexToAddress(common.BlockSigners)] = core.GenesisAccount{
Balance: big.NewInt(0),
Code: code,
Storage: storage,
}
// Randomize Smart Contract Code
randomizeAddress, _, err := randomizeContract.DeployRandomize(transactOpts, contractBackend)
if err != nil {
fmt.Println("Can't deploy root registry")
}
contractBackend.Commit()
code, _ = contractBackend.CodeAt(ctx, randomizeAddress, nil)
storage = make(map[common.Hash]common.Hash)
contractBackend.ForEachStorageAt(ctx, randomizeAddress, nil, f)
genesis.Alloc[common.HexToAddress(common.RandomizeSMC)] = core.GenesisAccount{
Balance: big.NewInt(0),
Code: code,
Storage: storage,
}
fmt.Println()
fmt.Println("Which accounts are allowed to confirm in Team MultiSignWallet?")
var teams []common.Address
for {
if address := w.readAddress(); address != nil {
teams = append(teams, *address)
continue
}
if len(teams) > 0 {
break
}
}
fmt.Println()
fmt.Println("How many require for confirm tx in Team MultiSignWallet? (default = 2)")
required = int64(w.readDefaultInt(2))
// MultiSigWallet.
multiSignWalletTeamAddr, _, err := multiSignWalletContract.DeployMultiSigWallet(transactOpts, contractBackend, teams, big.NewInt(required))
if err != nil {
fmt.Println("Can't deploy MultiSignWallet SMC")
}
contractBackend.Commit()
code, _ = contractBackend.CodeAt(ctx, multiSignWalletTeamAddr, nil)
storage = make(map[common.Hash]common.Hash)
contractBackend.ForEachStorageAt(ctx, multiSignWalletTeamAddr, nil, f)
// Team balance.
balance := big.NewInt(0) // 12m
balance.Add(balance, big.NewInt(12*1000*1000))
balance.Mul(balance, big.NewInt(1000000000000000000))
subBalance := big.NewInt(0) // i * 50k
subBalance.Add(subBalance, big.NewInt(int64(len(signers))*50*1000))
subBalance.Mul(subBalance, big.NewInt(1000000000000000000))
balance.Sub(balance, subBalance) // 12m - i * 50k
genesis.Alloc[common.HexToAddress(common.TeamAddr)] = core.GenesisAccount{
Balance: balance,
Code: code,
Storage: storage,
}
fmt.Println()
fmt.Println("What is swap wallet address for fund 55m XDC?")
swapAddr := *w.readAddress()
baseBalance := big.NewInt(0) // 55m
baseBalance.Add(baseBalance, big.NewInt(55*1000*1000))
baseBalance.Mul(baseBalance, big.NewInt(1000000000000000000))
genesis.Alloc[swapAddr] = core.GenesisAccount{
Balance: baseBalance,
}
default:
log.Crit("Invalid consensus engine choice", "choice", choice)
}
@ -115,8 +338,8 @@ func (w *wizard) makeGenesis() {
break
}
// Add a batch of precompile balances to avoid them getting deleted
for i := int64(0); i < 256; i++ {
genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(1)}
for i := int64(0); i < 2; i++ {
genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(0)}
}
// Query the user for some custom extras
fmt.Println()

View file

@ -118,7 +118,7 @@ func (w *wizard) deployNode(boot bool) {
fmt.Printf("What address should the miner user? (default = %s)\n", infos.etherbase)
infos.etherbase = w.readDefaultAddress(common.HexToAddress(infos.etherbase)).Hex()
}
} else if w.conf.Genesis.Config.Clique != nil {
} else if w.conf.Genesis.Config.XDPoS != nil {
// If a previous signer was already set, offer to reuse it
if infos.keyJSON != "" {
if key, err := keystore.DecryptKey([]byte(infos.keyJSON), infos.keyPass); err != nil {
@ -131,7 +131,7 @@ func (w *wizard) deployNode(boot bool) {
}
}
}
// Clique based signers need a keyfile and unlock password, ask if unavailable
// XDPoS based signers need a keyfile and unlock password, ask if unavailable
if infos.keyJSON == "" {
fmt.Println()
fmt.Println("Please paste the signer's key JSON:")

View file

@ -70,7 +70,7 @@ const (
SWARM_ENV_ENS_ADDR = "SWARM_ENS_ADDR"
SWARM_ENV_CORS = "SWARM_CORS"
SWARM_ENV_BOOTNODES = "SWARM_BOOTNODES"
GETH_ENV_DATADIR = "GETH_DATADIR"
XDC_ENV_DATADIR = "XDC_DATADIR"
)
// These settings ensure that TOML keys use the same names as Go struct fields.
@ -116,7 +116,7 @@ func initSwarmNode(config *bzzapi.Config, stack *node.Node, ctx *cli.Context) {
//at this point, all vars should be set in the Config
//get the account for the provided swarm account
prvkey := getAccount(config.BzzAccount, ctx, stack)
//set the resolved config path (geth --datadir)
//set the resolved config path (XDC --datadir)
config.Path = stack.InstanceDir()
//finally, initialize the configuration
config.Init(prvkey)
@ -243,7 +243,7 @@ func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) {
}
}
if datadir := os.Getenv(GETH_ENV_DATADIR); datadir != "" {
if datadir := os.Getenv(XDC_ENV_DATADIR); datadir != "" {
currentConfig.Path = datadir
}

View file

@ -405,9 +405,9 @@ func bzzd(ctx *cli.Context) error {
}
cfg := defaultNodeConfig
//geth only supports --datadir via command line
//XDC only supports --datadir via command line
//in order to be consistent within swarm, if we pass --datadir via environment variable
//or via config file, we get the same directory for geth and swarm
//or via config file, we get the same directory for XDC and swarm
if _, err := os.Stat(bzzconfig.Path); err == nil {
cfg.DataDir = bzzconfig.Path
}

View file

@ -33,8 +33,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/clique"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/consensus/XDPoS"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
@ -112,7 +112,21 @@ func NewApp(gitCommit, usage string) *cli.App {
// are the same for all commands.
var (
// XDC flags.
RollbackFlag = cli.StringFlag{
Name: "rollback",
Usage: "Rollback chain at hash",
Value: "",
}
// General settings
AnnounceTxsFlag = cli.BoolFlag{
Name: "announce-txs",
Usage: "Always commit transactions",
}
StoreRewardFlag = cli.BoolFlag{
Name: "store-reward",
Usage: "Store reward to file",
}
DataDirFlag = DirectoryFlag{
Name: "datadir",
Usage: "Data directory for the databases and keystore",
@ -128,13 +142,17 @@ var (
}
NetworkIdFlag = cli.Uint64Flag{
Name: "networkid",
Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)",
Usage: "Network identifier (integer, 89=XDCchain)",
Value: eth.DefaultConfig.NetworkId,
}
TestnetFlag = cli.BoolFlag{
Name: "testnet",
Usage: "Ropsten network: pre-configured proof-of-work test network",
}
XDCTestnetFlag = cli.BoolFlag{
Name: "XDC-testnet",
Usage: "XDC test network",
}
RinkebyFlag = cli.BoolFlag{
Name: "rinkeby",
Usage: "Rinkeby network: pre-configured proof-of-authority test network",
@ -311,13 +329,13 @@ var (
Value: int(state.MaxTrieCacheGen),
}
// Miner settings
MiningEnabledFlag = cli.BoolFlag{
StakingEnabledFlag = cli.BoolFlag{
Name: "mine",
Usage: "Enable mining",
Usage: "Enable staking",
}
MinerThreadsFlag = cli.IntFlag{
StakerThreadsFlag = cli.IntFlag{
Name: "minerthreads",
Usage: "Number of CPU threads to use for mining",
Usage: "Number of CPU threads to use for staking",
Value: runtime.NumCPU(),
}
TargetGasLimitFlag = cli.Uint64Flag{
@ -587,7 +605,7 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
// setBootstrapNodes creates a list of bootstrap nodes from the command line
// flags, reverting to pre-configured ones if none have been specified.
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
urls := params.MainnetBootnodes
urls := []string{}
switch {
case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name):
if ctx.GlobalIsSet(BootnodesV4Flag.Name) {
@ -653,6 +671,7 @@ func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
// setNAT creates a port mapper from command line flags.
func setNAT(ctx *cli.Context, cfg *p2p.Config) {
if ctx.GlobalIsSet(NATFlag.Name) {
log.Info("NAT is setted", "value", ctx.GlobalString(NATFlag.Name))
natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name))
if err != nil {
Fatalf("Option %s: %v", NATFlag.Name, err)
@ -728,9 +747,9 @@ func setIPC(ctx *cli.Context, cfg *node.Config) {
}
}
// makeDatabaseHandles raises out the number of allowed file handles per process
// for Geth and returns half of the allowance to assign to the database.
func makeDatabaseHandles() int {
// MakeDatabaseHandles raises out the number of allowed file handles per process
// for XDC and returns half of the allowance to assign to the database.
func MakeDatabaseHandles() int {
limit, err := fdlimit.Current()
if err != nil {
Fatalf("Failed to retrieve file descriptor allowance: %v", err)
@ -761,7 +780,7 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error
log.Warn("-------------------------------------------------------------------")
log.Warn("Referring to accounts by order in the keystore folder is dangerous!")
log.Warn("This functionality is deprecated and will be removed in the future!")
log.Warn("Please use explicit addresses! (can search via `geth account list`)")
log.Warn("Please use explicit addresses! (can search via `XDC account list`)")
log.Warn("-------------------------------------------------------------------")
accs := ks.Accounts()
@ -896,6 +915,9 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
if ctx.GlobalIsSet(NoUSBFlag.Name) {
cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name)
}
if ctx.GlobalIsSet(AnnounceTxsFlag.Name) {
cfg.AnnounceTxs = ctx.GlobalBool(AnnounceTxsFlag.Name)
}
}
func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
@ -1044,7 +1066,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
}
cfg.DatabaseHandles = makeDatabaseHandles()
cfg.DatabaseHandles = MakeDatabaseHandles()
if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
@ -1054,8 +1076,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
cfg.TrieCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
}
if ctx.GlobalIsSet(MinerThreadsFlag.Name) {
cfg.MinerThreads = ctx.GlobalInt(MinerThreadsFlag.Name)
if ctx.GlobalIsSet(StakerThreadsFlag.Name) {
cfg.MinerThreads = ctx.GlobalInt(StakerThreadsFlag.Name)
}
if ctx.GlobalIsSet(DocRootFlag.Name) {
cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name)
@ -1070,7 +1092,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
// TODO(fjl): force-enable this in --dev mode
cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
}
if ctx.GlobalIsSet(StoreRewardFlag.Name) {
common.StoreRewardFolder = filepath.Join(stack.DataDir(), "XDC", "rewards")
if _, err := os.Stat(common.StoreRewardFolder); os.IsNotExist(err) {
os.Mkdir(common.StoreRewardFolder, os.ModePerm)
}
}
// Override any default configs for hard coded networks.
switch {
case ctx.GlobalBool(TestnetFlag.Name):
@ -1185,7 +1212,7 @@ func SetupNetwork(ctx *cli.Context) {
func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
var (
cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
handles = makeDatabaseHandles()
handles = MakeDatabaseHandles()
)
name := "chaindata"
if ctx.GlobalBool(LightModeFlag.Name) {
@ -1221,8 +1248,8 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
Fatalf("%v", err)
}
var engine consensus.Engine
if config.Clique != nil {
engine = clique.New(config.Clique, chainDb)
if config.XDPoS != nil {
engine = XDPoS.New(config.XDPoS, chainDb)
} else {
engine = ethash.NewFaker()
if !ctx.GlobalBool(FakePoWFlag.Name) {
@ -1235,6 +1262,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk,
})
}
Fatalf("Only support XDPoS consensus")
}
if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
@ -1276,11 +1304,11 @@ func MakeConsolePreloads(ctx *cli.Context) []string {
// This is a temporary function used for migrating old command/flags to the
// new format.
//
// e.g. geth account new --keystore /tmp/mykeystore --lightkdf
// e.g. XDC account new --keystore /tmp/mykeystore --lightkdf
//
// is equivalent after calling this method with:
//
// geth --keystore /tmp/mykeystore --lightkdf account new
// XDC --keystore /tmp/mykeystore --lightkdf account new
//
// This allows the use of the existing configuration functionality.
// When all flags are migrated this function can be removed and the existing

View file

@ -28,11 +28,16 @@ func ToHex(b []byte) string {
return "0x" + hex
}
// FromHex returns the bytes represented by the hexadecimal string s.
// s may be prefixed with "0x".
func FromHex(s string) []byte {
if len(s) > 1 {
if s[0:2] == "0x" || s[0:2] == "0X" {
s = s[2:]
}
if (s[0] == 'x' || s[0] == 'X') && (s[1] == 'd' || s[1] == 'D') && (s[2] == 'c' || s[2] == 'C') {
s = s[3:]
}
}
if len(s)%2 == 1 {
s = "0" + s
@ -53,6 +58,10 @@ func CopyBytes(b []byte) (copiedBytes []byte) {
return
}
func hasXDCPrefix(str string) bool {
return len(str) >= 3 && (str[0] == 'x' || str[0] == 'X') && (str[1] == 'd' || str[1] == 'D') && (str[2] == 'c' || str[2] == 'C')
}
func hasHexPrefix(str string) bool {
return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
}

30
common/constants.go Normal file
View file

@ -0,0 +1,30 @@
package common
import "math/big"
const (
RewardMasterPercent = 40
RewardVoterPercent = 50
RewardFoundationPercent = 10
HexSignMethod = "e341eaa4"
HexSetSecret = "34d38600"
HexSetOpening = "e11f5ba2"
EpocBlockSecret = 800
EpocBlockOpening = 850
EpocBlockRandomize = 900
MaxMasternodes = 150
LimitPenaltyEpoch = 4
BlocksPerYear = uint64(15768000)
LimitThresholdNonceInQueue = 10
DefaultMinGasPrice = 2500
MergeSignRange = 15
RangeReturnSigner = 150
MinimunMinerBlockPerEpoch = 1
)
var TIP2019Block = big.NewInt(1050000)
var TIPSigning = big.NewInt(3000000)
var IsTestnet bool = false
var StoreRewardFolder string
var RollbackHash Hash
var MinGasPrice int64

View file

@ -44,6 +44,14 @@ func (b Bytes) MarshalText() ([]byte, error) {
return result, nil
}
// MarshalXDCText implements encoding.TextMarshaler
func (b Bytes) MarshalXDCText() ([]byte, error) {
result := make([]byte, len(b)*2+3)
copy(result, `xdc`)
hex.Encode(result[3:], b)
return result, nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (b *Bytes) UnmarshalJSON(input []byte) error {
if !isString(input) {
@ -277,12 +285,18 @@ func bytesHave0xPrefix(input []byte) bool {
return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
}
func bytesHaveXDCPrefix(input []byte) bool {
return len(input) >= 3 && (input[0] == 'x' || input[0] == 'X') && (input[1] == 'd' || input[1] == 'D') && (input[2] == 'c' || input[2] == 'C')
}
func checkText(input []byte, wantPrefix bool) ([]byte, error) {
if len(input) == 0 {
return nil, nil // empty strings are allowed
}
if bytesHave0xPrefix(input) {
input = input[2:]
if bytesHaveXDCPrefix(input) {
input = input[3:]
} else if bytesHave0xPrefix(input) {
input = input[2:]
} else if wantPrefix {
return nil, ErrMissingPrefix
}

View file

@ -28,8 +28,18 @@ import (
)
const (
HashLength = 32
AddressLength = 20
HashLength = 32
AddressLength = 20
MasternodeVotingSMC = "xdc0000000000000000000000000000000000000088"
BlockSigners = "xdc0000000000000000000000000000000000000089"
RandomizeSMC = "xdc0000000000000000000000000000000000000090"
FoudationAddr = "xdc0000000000000000000000000000000000000068"
TeamAddr = "xdc0000000000000000000000000000000000000099"
VoteMethod = "0x6dd7d8ea"
UnvoteMethod = "0x02aa9be2"
ProposeMethod = "0x01267951"
ResignMethod = "0xae6e43f5"
SignMethod = "0xe341eaa4"
)
var (
@ -150,6 +160,9 @@ func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
// IsHexAddress verifies whether a string can represent a valid hex-encoded
// Ethereum address or not.
func IsHexAddress(s string) bool {
if hasXDCPrefix(s) {
s = s[3:]
}
if hasHexPrefix(s) {
s = s[2:]
}
@ -181,7 +194,7 @@ func (a Address) Hex() string {
result[i] -= 32
}
}
return "0x" + string(result)
return "xdc" + string(result)
}
// String implements the stringer interface and is used also by the logger.
@ -215,7 +228,7 @@ func (a *Address) Set(other Address) {
// MarshalText returns the hex representation of a.
func (a Address) MarshalText() ([]byte, error) {
return hexutil.Bytes(a[:]).MarshalText()
return hexutil.Bytes(a[:]).MarshalXDCText()
}
// UnmarshalText parses a hash in hex syntax.
@ -240,3 +253,40 @@ func (a *UnprefixedAddress) UnmarshalText(input []byte) error {
func (a UnprefixedAddress) MarshalText() ([]byte, error) {
return []byte(hex.EncodeToString(a[:])), nil
}
// Extract validators from byte array.
func RemoveItemFromArray(array []Address, items []Address) []Address {
if len(items) == 0 {
return array
}
for _, item := range items {
for i := len(array) - 1; i >= 0; i-- {
if array[i] == item {
array = append(array[:i], array[i+1:]...)
}
}
}
return array
}
// Extract validators from byte array.
func ExtractAddressToBytes(penalties []Address) []byte {
data := []byte{}
for _, signer := range penalties {
data = append(data, signer[:]...)
}
return data
}
func ExtractAddressFromBytes(bytePenalties []byte) []Address {
if bytePenalties != nil && len(bytePenalties) < AddressLength {
return []Address{}
}
penalties := make([]Address, len(bytePenalties)/AddressLength)
for i := 0; i < len(penalties); i++ {
copy(penalties[i][:], bytePenalties[i*AddressLength:])
}
return penalties
}

View file

@ -40,15 +40,15 @@ func TestIsHexAddress(t *testing.T) {
str string
exp bool
}{
{"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", true},
{"xdc5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", true},
{"5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", true},
{"0X5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", true},
{"0XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", true},
{"0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", true},
{"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed1", false},
{"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beae", false},
{"XDC5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", true},
{"XdcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", true},
{"xdcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", true},
{"xdc5aaeb6053f3e94c9b9a09f33669435e7ef1beaed1", false},
{"xdc5aaeb6053f3e94c9b9a09f33669435e7ef1beae", false},
{"5aaeb6053f3e94c9b9a09f33669435e7ef1beaed11", false},
{"0xxaaeb6053f3e94c9b9a09f33669435e7ef1beaed", false},
{"xdcxaaeb6053f3e94c9b9a09f33669435e7ef1beaed", false},
}
for _, test := range tests {
@ -101,6 +101,11 @@ func TestAddressUnmarshalJSON(t *testing.T) {
{`"0xG000000000000000000000000000000000000000"`, true, nil},
{`"0x0000000000000000000000000000000000000000"`, false, big.NewInt(0)},
{`"0x0000000000000000000000000000000000000010"`, false, big.NewInt(16)},
{`"xdc"`, true, nil},
{`"xdc00"`, true, nil},
{`"xdcG000000000000000000000000000000000000000"`, true, nil},
{`"xdc0000000000000000000000000000000000000000"`, false, big.NewInt(0)},
{`"xdc0000000000000000000000000000000000000010"`, false, big.NewInt(16)},
}
for i, test := range tests {
var v Address
@ -125,15 +130,15 @@ func TestAddressHexChecksum(t *testing.T) {
Output string
}{
// Test cases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md#specification
{"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"},
{"0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359", "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"},
{"0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb", "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"},
{"0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"},
{"xdc5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", "xdc5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"},
{"xdcfb6916095ca1df60bb79ce92ce3ea74c37c5d359", "xdcfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"},
{"xdcdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb", "xdcdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"},
{"xdcd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", "xdcD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"},
// Ensure that non-standard length input values are handled correctly
{"0xa", "0x000000000000000000000000000000000000000A"},
{"0x0a", "0x000000000000000000000000000000000000000A"},
{"0x00a", "0x000000000000000000000000000000000000000A"},
{"0x000000000000000000000000000000000000000a", "0x000000000000000000000000000000000000000A"},
{"0xa", "xdc000000000000000000000000000000000000000A"},
{"0x0a", "xdc000000000000000000000000000000000000000A"},
{"0x00a", "xdc000000000000000000000000000000000000000A"},
{"0x000000000000000000000000000000000000000a", "xdc000000000000000000000000000000000000000A"},
}
for i, test := range tests {
output := HexToAddress(test.Input).Hex()
@ -149,3 +154,12 @@ func BenchmarkAddressHex(b *testing.B) {
testAddr.Hex()
}
}
func TestRemoveItemInArray(t *testing.T) {
array := []Address{HexToAddress("0x0000003"), HexToAddress("0x0000001"), HexToAddress("0x0000002"), HexToAddress("0x0000003")}
remove := []Address{HexToAddress("0x0000002"), HexToAddress("0x0000004"), HexToAddress("0x0000003")}
array = RemoveItemFromArray(array, remove)
if len(array) != 1 {
t.Error("fail remove item from array address")
}
}

1168
consensus/XDPoS/XDPoS.go Normal file

File diff suppressed because it is too large Load diff

100
consensus/XDPoS/api.go Normal file
View file

@ -0,0 +1,100 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package XDPoS
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc"
)
// API is a user facing RPC API to allow controlling the signer and voting
// mechanisms of the proof-of-authority scheme.
type API struct {
chain consensus.ChainReader
XDPoS *XDPoS
}
// GetSnapshot retrieves the state snapshot at a given block.
func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
// Retrieve the requested block number (or current if none requested)
var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
// Ensure we have an actually valid block and return its snapshot
if header == nil {
return nil, errUnknownBlock
}
return api.XDPoS.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
}
// GetSnapshotAtHash retrieves the state snapshot at a given block.
func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
header := api.chain.GetHeaderByHash(hash)
if header == nil {
return nil, errUnknownBlock
}
return api.XDPoS.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
}
// GetSigners retrieves the list of authorized signers at the specified block.
func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
// Retrieve the requested block number (or current if none requested)
var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
// Ensure we have an actually valid block and return the signers from its snapshot
if header == nil {
return nil, errUnknownBlock
}
snap, err := api.XDPoS.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil {
return nil, err
}
return snap.GetSigners(), nil
}
// GetSignersAtHash retrieves the state snapshot at a given block.
func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
header := api.chain.GetHeaderByHash(hash)
if header == nil {
return nil, errUnknownBlock
}
snap, err := api.XDPoS.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil {
return nil, err
}
return snap.GetSigners(), nil
}
// Proposals returns the current proposals the node tries to uphold and vote on.
func (api *API) Proposals() map[common.Address]bool {
api.XDPoS.lock.RLock()
defer api.XDPoS.lock.RUnlock()
proposals := make(map[common.Address]bool)
for address, auth := range api.XDPoS.proposals {
proposals[address] = auth
}
return proposals
}

311
consensus/XDPoS/snapshot.go Normal file
View file

@ -0,0 +1,311 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package XDPoS
import (
"bytes"
"encoding/json"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/clique"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
lru "github.com/hashicorp/golang-lru"
)
// Vote represents a single vote that an authorized signer made to modify the
// list of authorizations.
//type Vote struct {
// Signer common.Address `json:"signer"` // Authorized signer that cast this vote
// Block uint64 `json:"block"` // Block number the vote was cast in (expire old votes)
// Address common.Address `json:"address"` // Account being voted on to change its authorization
// Authorize bool `json:"authorize"` // Whether to authorize or deauthorize the voted account
//}
// Tally is a simple vote tally to keep the current score of votes. Votes that
// go against the proposal aren't counted since it's equivalent to not voting.
//type Tally struct {
// Authorize bool `json:"authorize"` // Whether the vote is about authorizing or kicking someone
// Votes int `json:"votes"` // Number of votes until now wanting to pass the proposal
//}
// Snapshot is the state of the authorization voting at a given point in time.
type Snapshot struct {
config *params.XDPoSConfig // Consensus engine parameters to fine tune behavior
sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
Number uint64 `json:"number"` // Block number where the snapshot was created
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
Signers map[common.Address]struct{} `json:"signers"` // Set of authorized signers at this moment
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
Votes []*clique.Vote `json:"votes"` // List of votes cast in chronological order
Tally map[common.Address]clique.Tally `json:"tally"` // Current vote tally to avoid recalculating
}
// newSnapshot creates a new snapshot with the specified startup parameters. This
// method does not initialize the set of recent signers, so only ever use if for
// the genesis block.
func newSnapshot(config *params.XDPoSConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, signers []common.Address) *Snapshot {
snap := &Snapshot{
config: config,
sigcache: sigcache,
Number: number,
Hash: hash,
Signers: make(map[common.Address]struct{}),
Recents: make(map[uint64]common.Address),
Tally: make(map[common.Address]clique.Tally),
}
for _, signer := range signers {
snap.Signers[signer] = struct{}{}
}
return snap
}
// loadSnapshot loads an existing snapshot from the database.
func loadSnapshot(config *params.XDPoSConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
blob, err := db.Get(append([]byte("XDPoS-"), hash[:]...))
if err != nil {
return nil, err
}
snap := new(Snapshot)
if err := json.Unmarshal(blob, snap); err != nil {
return nil, err
}
snap.config = config
snap.sigcache = sigcache
return snap, nil
}
// store inserts the snapshot into the database.
func (s *Snapshot) store(db ethdb.Database) error {
blob, err := json.Marshal(s)
if err != nil {
return err
}
return db.Put(append([]byte("XDPoS-"), s.Hash[:]...), blob)
}
// copy creates a deep copy of the snapshot, though not the individual votes.
func (s *Snapshot) copy() *Snapshot {
cpy := &Snapshot{
config: s.config,
sigcache: s.sigcache,
Number: s.Number,
Hash: s.Hash,
Signers: make(map[common.Address]struct{}),
Recents: make(map[uint64]common.Address),
Votes: make([]*clique.Vote, len(s.Votes)),
Tally: make(map[common.Address]clique.Tally),
}
for signer := range s.Signers {
cpy.Signers[signer] = struct{}{}
}
for block, signer := range s.Recents {
cpy.Recents[block] = signer
}
for address, tally := range s.Tally {
cpy.Tally[address] = tally
}
copy(cpy.Votes, s.Votes)
return cpy
}
// validVote returns whether it makes sense to cast the specified vote in the
// given snapshot context (e.g. don't try to add an already authorized signer).
func (s *Snapshot) validVote(address common.Address, authorize bool) bool {
_, signer := s.Signers[address]
return (signer && !authorize) || (!signer && authorize)
}
// cast adds a new vote into the tally.
func (s *Snapshot) cast(address common.Address, authorize bool) bool {
// Ensure the vote is meaningful
if !s.validVote(address, authorize) {
return false
}
// Cast the vote into an existing or new tally
if old, ok := s.Tally[address]; ok {
old.Votes++
s.Tally[address] = old
} else {
s.Tally[address] = clique.Tally{Authorize: authorize, Votes: 1}
}
return true
}
// uncast removes a previously cast vote from the tally.
func (s *Snapshot) uncast(address common.Address, authorize bool) bool {
// If there's no tally, it's a dangling vote, just drop
tally, ok := s.Tally[address]
if !ok {
return false
}
// Ensure we only revert counted votes
if tally.Authorize != authorize {
return false
}
// Otherwise revert the vote
if tally.Votes > 1 {
tally.Votes--
s.Tally[address] = tally
} else {
delete(s.Tally, address)
}
return true
}
// apply creates a new authorization snapshot by applying the given headers to
// the original one.
func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
// Allow passing in no headers for cleaner code
if len(headers) == 0 {
return s, nil
}
// Sanity check that the headers can be applied
for i := 0; i < len(headers)-1; i++ {
if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
return nil, errInvalidVotingChain
}
}
if headers[0].Number.Uint64() != s.Number+1 {
return nil, errInvalidVotingChain
}
// Iterate through the headers and create a new snapshot
snap := s.copy()
for _, header := range headers {
// Remove any votes on checkpoint blocks
number := header.Number.Uint64()
if number%s.config.Epoch == 0 {
snap.Votes = nil
snap.Tally = make(map[common.Address]clique.Tally)
}
// Delete the oldest signer from the recent list to allow it signing again
if limit := uint64(len(snap.Signers)/2 + 1); number >= limit {
delete(snap.Recents, number-limit)
}
// Resolve the authorization key and check against signers
signer, err := ecrecover(header, s.sigcache)
if err != nil {
return nil, err
}
//FIXME: skip signer checking at this step until a good solution found
//if _, ok := snap.Signers[signer]; !ok {
// return nil, errUnauthorized
//}
//for _, recent := range snap.Recents {
// if recent == signer {
// return nil, errUnauthorized
// }
//}
snap.Recents[number] = signer
// Header authorized, discard any previous votes from the signer
for i, vote := range snap.Votes {
if vote.Signer == signer && vote.Address == header.Coinbase {
// Uncast the vote from the cached tally
snap.uncast(vote.Address, vote.Authorize)
// Uncast the vote from the chronological list
snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
break // only one vote allowed
}
}
// Tally up the new vote from the signer
var authorize bool
switch {
case bytes.Equal(header.Nonce[:], nonceAuthVote):
authorize = true
case bytes.Equal(header.Nonce[:], nonceDropVote):
authorize = false
default:
return nil, errInvalidVote
}
if snap.cast(header.Coinbase, authorize) {
snap.Votes = append(snap.Votes, &clique.Vote{
Signer: signer,
Block: number,
Address: header.Coinbase,
Authorize: authorize,
})
}
// If the vote passed, update the list of signers
if tally := snap.Tally[header.Coinbase]; tally.Votes > len(snap.Signers)/2 {
if tally.Authorize {
snap.Signers[header.Coinbase] = struct{}{}
} else {
delete(snap.Signers, header.Coinbase)
// Signer list shrunk, delete any leftover recent caches
if limit := uint64(len(snap.Signers)/2 + 1); number >= limit {
delete(snap.Recents, number-limit)
}
// Discard any previous votes the deauthorized signer cast
for i := 0; i < len(snap.Votes); i++ {
if snap.Votes[i].Signer == header.Coinbase {
// Uncast the vote from the cached tally
snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize)
// Uncast the vote from the chronological list
snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
i--
}
}
}
// Discard any previous votes around the just changed account
for i := 0; i < len(snap.Votes); i++ {
if snap.Votes[i].Address == header.Coinbase {
snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...)
i--
}
}
delete(snap.Tally, header.Coinbase)
}
}
snap.Number += uint64(len(headers))
snap.Hash = headers[len(headers)-1].Hash()
return snap, nil
}
// signers retrieves the list of authorized signers in ascending order.
func (s *Snapshot) GetSigners() []common.Address {
signers := make([]common.Address, 0, len(s.Signers))
for signer := range s.Signers {
signers = append(signers, signer)
}
for i := 0; i < len(signers); i++ {
for j := i + 1; j < len(signers); j++ {
if bytes.Compare(signers[i][:], signers[j][:]) > 0 {
signers[i], signers[j] = signers[j], signers[i]
}
}
}
return signers
}
// inturn returns if a signer at a given block height is in-turn or not.
func (s *Snapshot) inturn(number uint64, signer common.Address) bool {
signers, offset := s.GetSigners(), 0
for offset < len(signers) && signers[offset] != signer {
offset++
}
return (number % uint64(len(signers))) == uint64(offset)
}

View file

@ -612,6 +612,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, stop <-ch
if err != nil {
return nil, err
}
masternodes := []common.Address{}
if _, authorized := snap.Signers[signer]; !authorized {
return nil, errUnauthorized
}
@ -619,7 +620,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, stop <-ch
for seen, recent := range snap.Recents {
if recent == signer {
// Signer is among recents, only wait if the current block doesn't shift it out
if limit := uint64(len(snap.Signers)/2 + 1); number < limit || seen > number-limit {
if limit := uint64(len(masternodes)/2 + 1); number < limit || seen > number-limit {
log.Info("Signed recently, must wait for others")
<-stop
return nil, nil

View file

@ -1,405 +0,0 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package clique
import (
"bytes"
"crypto/ecdsa"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
type testerVote struct {
signer string
voted string
auth bool
}
// testerAccountPool is a pool to maintain currently active tester accounts,
// mapped from textual names used in the tests below to actual Ethereum private
// keys capable of signing transactions.
type testerAccountPool struct {
accounts map[string]*ecdsa.PrivateKey
}
func newTesterAccountPool() *testerAccountPool {
return &testerAccountPool{
accounts: make(map[string]*ecdsa.PrivateKey),
}
}
func (ap *testerAccountPool) sign(header *types.Header, signer string) {
// Ensure we have a persistent key for the signer
if ap.accounts[signer] == nil {
ap.accounts[signer], _ = crypto.GenerateKey()
}
// Sign the header and embed the signature in extra data
sig, _ := crypto.Sign(sigHash(header).Bytes(), ap.accounts[signer])
copy(header.Extra[len(header.Extra)-65:], sig)
}
func (ap *testerAccountPool) address(account string) common.Address {
// Ensure we have a persistent key for the account
if ap.accounts[account] == nil {
ap.accounts[account], _ = crypto.GenerateKey()
}
// Resolve and return the Ethereum address
return crypto.PubkeyToAddress(ap.accounts[account].PublicKey)
}
// testerChainReader implements consensus.ChainReader to access the genesis
// block. All other methods and requests will panic.
type testerChainReader struct {
db ethdb.Database
}
func (r *testerChainReader) Config() *params.ChainConfig { return params.AllCliqueProtocolChanges }
func (r *testerChainReader) CurrentHeader() *types.Header { panic("not supported") }
func (r *testerChainReader) GetHeader(common.Hash, uint64) *types.Header { panic("not supported") }
func (r *testerChainReader) GetBlock(common.Hash, uint64) *types.Block { panic("not supported") }
func (r *testerChainReader) GetHeaderByHash(common.Hash) *types.Header { panic("not supported") }
func (r *testerChainReader) GetHeaderByNumber(number uint64) *types.Header {
if number == 0 {
return core.GetHeader(r.db, core.GetCanonicalHash(r.db, 0), 0)
}
panic("not supported")
}
// Tests that voting is evaluated correctly for various simple and complex scenarios.
func TestVoting(t *testing.T) {
// Define the various voting scenarios to test
tests := []struct {
epoch uint64
signers []string
votes []testerVote
results []string
}{
{
// Single signer, no votes cast
signers: []string{"A"},
votes: []testerVote{{signer: "A"}},
results: []string{"A"},
}, {
// Single signer, voting to add two others (only accept first, second needs 2 votes)
signers: []string{"A"},
votes: []testerVote{
{signer: "A", voted: "B", auth: true},
{signer: "B"},
{signer: "A", voted: "C", auth: true},
},
results: []string{"A", "B"},
}, {
// Two signers, voting to add three others (only accept first two, third needs 3 votes already)
signers: []string{"A", "B"},
votes: []testerVote{
{signer: "A", voted: "C", auth: true},
{signer: "B", voted: "C", auth: true},
{signer: "A", voted: "D", auth: true},
{signer: "B", voted: "D", auth: true},
{signer: "C"},
{signer: "A", voted: "E", auth: true},
{signer: "B", voted: "E", auth: true},
},
results: []string{"A", "B", "C", "D"},
}, {
// Single signer, dropping itself (weird, but one less cornercase by explicitly allowing this)
signers: []string{"A"},
votes: []testerVote{
{signer: "A", voted: "A", auth: false},
},
results: []string{},
}, {
// Two signers, actually needing mutual consent to drop either of them (not fulfilled)
signers: []string{"A", "B"},
votes: []testerVote{
{signer: "A", voted: "B", auth: false},
},
results: []string{"A", "B"},
}, {
// Two signers, actually needing mutual consent to drop either of them (fulfilled)
signers: []string{"A", "B"},
votes: []testerVote{
{signer: "A", voted: "B", auth: false},
{signer: "B", voted: "B", auth: false},
},
results: []string{"A"},
}, {
// Three signers, two of them deciding to drop the third
signers: []string{"A", "B", "C"},
votes: []testerVote{
{signer: "A", voted: "C", auth: false},
{signer: "B", voted: "C", auth: false},
},
results: []string{"A", "B"},
}, {
// Four signers, consensus of two not being enough to drop anyone
signers: []string{"A", "B", "C", "D"},
votes: []testerVote{
{signer: "A", voted: "C", auth: false},
{signer: "B", voted: "C", auth: false},
},
results: []string{"A", "B", "C", "D"},
}, {
// Four signers, consensus of three already being enough to drop someone
signers: []string{"A", "B", "C", "D"},
votes: []testerVote{
{signer: "A", voted: "D", auth: false},
{signer: "B", voted: "D", auth: false},
{signer: "C", voted: "D", auth: false},
},
results: []string{"A", "B", "C"},
}, {
// Authorizations are counted once per signer per target
signers: []string{"A", "B"},
votes: []testerVote{
{signer: "A", voted: "C", auth: true},
{signer: "B"},
{signer: "A", voted: "C", auth: true},
{signer: "B"},
{signer: "A", voted: "C", auth: true},
},
results: []string{"A", "B"},
}, {
// Authorizing multiple accounts concurrently is permitted
signers: []string{"A", "B"},
votes: []testerVote{
{signer: "A", voted: "C", auth: true},
{signer: "B"},
{signer: "A", voted: "D", auth: true},
{signer: "B"},
{signer: "A"},
{signer: "B", voted: "D", auth: true},
{signer: "A"},
{signer: "B", voted: "C", auth: true},
},
results: []string{"A", "B", "C", "D"},
}, {
// Deauthorizations are counted once per signer per target
signers: []string{"A", "B"},
votes: []testerVote{
{signer: "A", voted: "B", auth: false},
{signer: "B"},
{signer: "A", voted: "B", auth: false},
{signer: "B"},
{signer: "A", voted: "B", auth: false},
},
results: []string{"A", "B"},
}, {
// Deauthorizing multiple accounts concurrently is permitted
signers: []string{"A", "B", "C", "D"},
votes: []testerVote{
{signer: "A", voted: "C", auth: false},
{signer: "B"},
{signer: "C"},
{signer: "A", voted: "D", auth: false},
{signer: "B"},
{signer: "C"},
{signer: "A"},
{signer: "B", voted: "D", auth: false},
{signer: "C", voted: "D", auth: false},
{signer: "A"},
{signer: "B", voted: "C", auth: false},
},
results: []string{"A", "B"},
}, {
// Votes from deauthorized signers are discarded immediately (deauth votes)
signers: []string{"A", "B", "C"},
votes: []testerVote{
{signer: "C", voted: "B", auth: false},
{signer: "A", voted: "C", auth: false},
{signer: "B", voted: "C", auth: false},
{signer: "A", voted: "B", auth: false},
},
results: []string{"A", "B"},
}, {
// Votes from deauthorized signers are discarded immediately (auth votes)
signers: []string{"A", "B", "C"},
votes: []testerVote{
{signer: "C", voted: "B", auth: false},
{signer: "A", voted: "C", auth: false},
{signer: "B", voted: "C", auth: false},
{signer: "A", voted: "B", auth: false},
},
results: []string{"A", "B"},
}, {
// Cascading changes are not allowed, only the account being voted on may change
signers: []string{"A", "B", "C", "D"},
votes: []testerVote{
{signer: "A", voted: "C", auth: false},
{signer: "B"},
{signer: "C"},
{signer: "A", voted: "D", auth: false},
{signer: "B", voted: "C", auth: false},
{signer: "C"},
{signer: "A"},
{signer: "B", voted: "D", auth: false},
{signer: "C", voted: "D", auth: false},
},
results: []string{"A", "B", "C"},
}, {
// Changes reaching consensus out of bounds (via a deauth) execute on touch
signers: []string{"A", "B", "C", "D"},
votes: []testerVote{
{signer: "A", voted: "C", auth: false},
{signer: "B"},
{signer: "C"},
{signer: "A", voted: "D", auth: false},
{signer: "B", voted: "C", auth: false},
{signer: "C"},
{signer: "A"},
{signer: "B", voted: "D", auth: false},
{signer: "C", voted: "D", auth: false},
{signer: "A"},
{signer: "C", voted: "C", auth: true},
},
results: []string{"A", "B"},
}, {
// Changes reaching consensus out of bounds (via a deauth) may go out of consensus on first touch
signers: []string{"A", "B", "C", "D"},
votes: []testerVote{
{signer: "A", voted: "C", auth: false},
{signer: "B"},
{signer: "C"},
{signer: "A", voted: "D", auth: false},
{signer: "B", voted: "C", auth: false},
{signer: "C"},
{signer: "A"},
{signer: "B", voted: "D", auth: false},
{signer: "C", voted: "D", auth: false},
{signer: "A"},
{signer: "B", voted: "C", auth: true},
},
results: []string{"A", "B", "C"},
}, {
// Ensure that pending votes don't survive authorization status changes. This
// corner case can only appear if a signer is quickly added, removed and then
// readded (or the inverse), while one of the original voters dropped. If a
// past vote is left cached in the system somewhere, this will interfere with
// the final signer outcome.
signers: []string{"A", "B", "C", "D", "E"},
votes: []testerVote{
{signer: "A", voted: "F", auth: true}, // Authorize F, 3 votes needed
{signer: "B", voted: "F", auth: true},
{signer: "C", voted: "F", auth: true},
{signer: "D", voted: "F", auth: false}, // Deauthorize F, 4 votes needed (leave A's previous vote "unchanged")
{signer: "E", voted: "F", auth: false},
{signer: "B", voted: "F", auth: false},
{signer: "C", voted: "F", auth: false},
{signer: "D", voted: "F", auth: true}, // Almost authorize F, 2/3 votes needed
{signer: "E", voted: "F", auth: true},
{signer: "B", voted: "A", auth: false}, // Deauthorize A, 3 votes needed
{signer: "C", voted: "A", auth: false},
{signer: "D", voted: "A", auth: false},
{signer: "B", voted: "F", auth: true}, // Finish authorizing F, 3/3 votes needed
},
results: []string{"B", "C", "D", "E", "F"},
}, {
// Epoch transitions reset all votes to allow chain checkpointing
epoch: 3,
signers: []string{"A", "B"},
votes: []testerVote{
{signer: "A", voted: "C", auth: true},
{signer: "B"},
{signer: "A"}, // Checkpoint block, (don't vote here, it's validated outside of snapshots)
{signer: "B", voted: "C", auth: true},
},
results: []string{"A", "B"},
},
}
// Run through the scenarios and test them
for i, tt := range tests {
// Create the account pool and generate the initial set of signers
accounts := newTesterAccountPool()
signers := make([]common.Address, len(tt.signers))
for j, signer := range tt.signers {
signers[j] = accounts.address(signer)
}
for j := 0; j < len(signers); j++ {
for k := j + 1; k < len(signers); k++ {
if bytes.Compare(signers[j][:], signers[k][:]) > 0 {
signers[j], signers[k] = signers[k], signers[j]
}
}
}
// Create the genesis block with the initial set of signers
genesis := &core.Genesis{
ExtraData: make([]byte, extraVanity+common.AddressLength*len(signers)+extraSeal),
}
for j, signer := range signers {
copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:])
}
// Create a pristine blockchain with the genesis injected
db, _ := ethdb.NewMemDatabase()
genesis.Commit(db)
// Assemble a chain of headers from the cast votes
headers := make([]*types.Header, len(tt.votes))
for j, vote := range tt.votes {
headers[j] = &types.Header{
Number: big.NewInt(int64(j) + 1),
Time: big.NewInt(int64(j) * int64(blockPeriod)),
Coinbase: accounts.address(vote.voted),
Extra: make([]byte, extraVanity+extraSeal),
}
if j > 0 {
headers[j].ParentHash = headers[j-1].Hash()
}
if vote.auth {
copy(headers[j].Nonce[:], nonceAuthVote)
}
accounts.sign(headers[j], vote.signer)
}
// Pass all the headers through clique and ensure tallying succeeds
head := headers[len(headers)-1]
snap, err := New(&params.CliqueConfig{Epoch: tt.epoch}, db).snapshot(&testerChainReader{db: db}, head.Number.Uint64(), head.Hash(), headers)
if err != nil {
t.Errorf("test %d: failed to create voting snapshot: %v", i, err)
continue
}
// Verify the final list of signers against the expected ones
signers = make([]common.Address, len(tt.results))
for j, signer := range tt.results {
signers[j] = accounts.address(signer)
}
for j := 0; j < len(signers); j++ {
for k := j + 1; k < len(signers); k++ {
if bytes.Compare(signers[j][:], signers[k][:]) > 0 {
signers[j], signers[k] = signers[k], signers[j]
}
}
}
result := snap.signers()
if len(result) != len(signers) {
t.Errorf("test %d: signers mismatch: have %x, want %x", i, result, signers)
continue
}
for j := 0; j < len(result); j++ {
if !bytes.Equal(result[j][:], signers[j][:]) {
t.Errorf("test %d, signer %d: signer mismatch: have %x, want %x", i, j, result[j], signers[j])
}
}
}
}

View file

@ -58,7 +58,7 @@ type Engine interface {
// VerifyHeader checks whether a header conforms to the consensus rules of a
// given engine. Verifying the seal may be done optionally here, or explicitly
// via the VerifySeal method.
VerifyHeader(chain ChainReader, header *types.Header, seal bool) error
VerifyHeader(chain ChainReader, header *types.Header, fullVerify bool) error
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
// concurrently. The method returns a quit channel to abort the operations and

View file

@ -34,4 +34,8 @@ var (
// ErrInvalidNumber is returned if a block's number doesn't equal it's parent's
// plus one.
ErrInvalidNumber = errors.New("invalid block number")
ErrFailValidatorSignature = errors.New("missing validator in header")
ErrNoValidatorSignature = errors.New("no validator in header")
)

View file

@ -272,8 +272,8 @@ func (c *Console) AutoCompleteInput(line string, pos int) (string, []string, str
// Welcome show summary of current Geth instance and some metadata about the
// console's available modules.
func (c *Console) Welcome() {
// Print some generic Geth metadata
fmt.Fprintf(c.printer, "Welcome to the Geth JavaScript console!\n\n")
// Print some generic XDC metadata
fmt.Fprintf(c.printer, "Welcome to the XDC JavaScript console!\n\n")
c.jsre.Run(`
console.log("instance: " + web3.version.node);
console.log("coinbase: " + eth.coinbase);

View file

@ -19,7 +19,6 @@ package console
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
@ -155,33 +154,6 @@ func (env *tester) Close(t *testing.T) {
os.RemoveAll(env.workspace)
}
// Tests that the node lists the correct welcome message, notably that it contains
// the instance name, coinbase account, block number, data directory and supported
// console modules.
func TestWelcome(t *testing.T) {
tester := newTester(t, nil)
defer tester.Close(t)
tester.console.Welcome()
output := tester.output.String()
if want := "Welcome"; !strings.Contains(output, want) {
t.Fatalf("console output missing welcome message: have\n%s\nwant also %s", output, want)
}
if want := fmt.Sprintf("instance: %s", testInstance); !strings.Contains(output, want) {
t.Fatalf("console output missing instance: have\n%s\nwant also %s", output, want)
}
if want := fmt.Sprintf("coinbase: %s", testAddress); !strings.Contains(output, want) {
t.Fatalf("console output missing coinbase: have\n%s\nwant also %s", output, want)
}
if want := "at block: 0"; !strings.Contains(output, want) {
t.Fatalf("console output missing sync status: have\n%s\nwant also %s", output, want)
}
if want := fmt.Sprintf("datadir: %s", tester.workspace); !strings.Contains(output, want) {
t.Fatalf("console output missing coinbase: have\n%s\nwant also %s", output, want)
}
}
// Tests that JavaScript statement evaluation works as intended.
func TestEvaluate(t *testing.T) {
tester := newTester(t, nil)

View file

@ -0,0 +1,33 @@
package contracts
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
)
var (
slotBlockSignerMapping = map[string]uint64{
"blockSigners": 0,
"blocks": 1,
}
)
func GetSigners(statedb *state.StateDB, block *types.Block) []common.Address {
slot := slotBlockSignerMapping["blockSigners"]
keys := []common.Hash{}
keyArrSlot := getLocMappingAtKey(block.Hash(), slot)
arrSlot := statedb.GetState(common.HexToAddress(common.BlockSigners), common.BigToHash(keyArrSlot))
arrLength := arrSlot.Big().Uint64()
for i := uint64(0); i < arrLength; i++ {
key := getLocDynamicArrAtElement(common.BigToHash(keyArrSlot), i, 1)
keys = append(keys, key)
}
rets := []common.Address{}
for _, key := range keys {
ret := statedb.GetState(common.HexToAddress(common.BlockSigners), key)
rets = append(rets, common.HexToAddress(ret.Hex()))
}
return rets
}

View file

@ -0,0 +1,57 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package blocksigner
import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/contracts/blocksigner/contract"
"math/big"
)
type BlockSigner struct {
*contract.BlockSignerSession
contractBackend bind.ContractBackend
}
func NewBlockSigner(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*BlockSigner, error) {
blockSigner, err := contract.NewBlockSigner(contractAddr, contractBackend)
if err != nil {
return nil, err
}
return &BlockSigner{
&contract.BlockSignerSession{
Contract: blockSigner,
TransactOpts: *transactOpts,
},
contractBackend,
}, nil
}
func DeployBlockSigner(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend, epochNumber *big.Int) (common.Address, *BlockSigner, error) {
blockSignerAddr, _, _, err := contract.DeployBlockSigner(transactOpts, contractBackend, epochNumber)
if err != nil {
return blockSignerAddr, nil, err
}
blockSigner, err := NewBlockSigner(transactOpts, blockSignerAddr, contractBackend)
if err != nil {
return blockSignerAddr, nil, err
}
return blockSignerAddr, blockSigner, nil
}

View file

@ -0,0 +1,86 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package blocksigner
import (
"context"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
"math/rand"
)
var (
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr = crypto.PubkeyToAddress(key.PublicKey)
)
func TestBlockSigner(t *testing.T) {
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}})
transactOpts := bind.NewKeyedTransactor(key)
blockSignerAddress, blockSigner, err := DeployBlockSigner(transactOpts, contractBackend, big.NewInt(99))
if err != nil {
t.Fatalf("can't deploy root registry: %v", err)
}
contractBackend.Commit()
d := time.Now().Add(1000 * time.Millisecond)
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
code, _ := contractBackend.CodeAt(ctx, blockSignerAddress, nil)
t.Log("contract code", common.ToHex(code))
f := func(key, val common.Hash) bool {
t.Log(key.Hex(), val.Hex())
return true
}
contractBackend.ForEachStorageAt(ctx, blockSignerAddress, nil, f)
byte0 := randomHash()
// Test sign.
tx, err := blockSigner.Sign(big.NewInt(2), byte0)
if err != nil {
t.Fatalf("can't sign: %v", err)
}
contractBackend.Commit()
t.Log("tx", tx)
signers, err := blockSigner.GetSigners(byte0)
if err != nil {
t.Fatalf("can't get candidates: %v", err)
}
for _, it := range signers {
t.Log("signer", it.String())
}
}
// Generate random string.
func randomHash() common.Hash {
letterBytes := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"
var b common.Hash
for i := range b {
rand.Seed(time.Now().UnixNano())
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return b
}

View file

@ -0,0 +1,31 @@
pragma solidity ^0.4.21;
import "./libs/SafeMath.sol";
contract BlockSigner {
using SafeMath for uint256;
event Sign(address _signer, uint256 _blockNumber, bytes32 _blockHash);
mapping(bytes32 => address[]) blockSigners;
mapping(uint256 => bytes32[]) blocks;
uint256 public epochNumber;
function BlockSigner(uint256 _epochNumber) public {
epochNumber = _epochNumber;
}
function sign(uint256 _blockNumber, bytes32 _blockHash) external {
// consensus should validate all senders are validators, gas = 0
require(block.number >= _blockNumber);
require(block.number <= _blockNumber.add(epochNumber * 2));
blocks[_blockNumber].push(_blockHash);
blockSigners[_blockHash].push(msg.sender);
emit Sign(msg.sender, _blockNumber, _blockHash);
}
function getSigners(bytes32 _blockHash) public view returns(address[]) {
return blockSigners[_blockHash];
}
}

View file

@ -0,0 +1,535 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package contract
import (
"math/big"
"strings"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)
// BlockSignerABI is the input ABI used to generate the binding from.
const BlockSignerABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_blockNumber\",\"type\":\"uint256\"},{\"name\":\"_blockHash\",\"type\":\"bytes32\"}],\"name\":\"sign\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_blockHash\",\"type\":\"bytes32\"}],\"name\":\"getSigners\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"epochNumber\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_epochNumber\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"_signer\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"_blockHash\",\"type\":\"bytes32\"}],\"name\":\"Sign\",\"type\":\"event\"}]"
// BlockSignerBin is the compiled bytecode used for deploying new contracts.
const BlockSignerBin = `0x6060604052341561000f57600080fd5b604051602080610386833981016040528080516002555050610350806100366000396000f3006060604052600436106100565763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663e341eaa4811461005b578063e7ec6aef14610076578063f4145a83146100df575b600080fd5b341561006657600080fd5b610074600435602435610104565b005b341561008157600080fd5b61008c600435610227565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156100cb5780820151838201526020016100b3565b505050509050019250505060405180910390f35b34156100ea57600080fd5b6100f26102ac565b60405190815260200160405180910390f35b438290101561011257600080fd5b600280546101289184910263ffffffff6102b216565b43111561013457600080fd5b600082815260016020819052604090912080549091810161015583826102c8565b5060009182526020808320919091018390558282528190526040902080546001810161018183826102c8565b506000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff19163373ffffffffffffffffffffffffffffffffffffffff8116919091179091557f62855fa22e051687c32ac285857751f6d3f2c100c72756d8d30cb7ecb1f64f5490838360405173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091526040808301919091526060909101905180910390a15050565b61022f6102f1565b600082815260208181526040918290208054909290918281020190519081016040528092919081815260200182805480156102a057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610275575b50505050509050919050565b60025481565b6000828201838110156102c157fe5b9392505050565b8154818355818115116102ec576000838152602090206102ec918101908301610303565b505050565b60206040519081016040526000815290565b61032191905b8082111561031d5760008155600101610309565b5090565b905600a165627a7a72305820a8ceddaea8e4ae00991e2ae81c8c88e160dd8770f255523282c24c2df4c30ec70029`
// DeployBlockSigner deploys a new Ethereum contract, binding an instance of BlockSigner to it.
func DeployBlockSigner(auth *bind.TransactOpts, backend bind.ContractBackend, _epochNumber *big.Int) (common.Address, *types.Transaction, *BlockSigner, error) {
parsed, err := abi.JSON(strings.NewReader(BlockSignerABI))
if err != nil {
return common.Address{}, nil, nil, err
}
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(BlockSignerBin), backend, _epochNumber)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &BlockSigner{BlockSignerCaller: BlockSignerCaller{contract: contract}, BlockSignerTransactor: BlockSignerTransactor{contract: contract}, BlockSignerFilterer: BlockSignerFilterer{contract: contract}}, nil
}
// BlockSigner is an auto generated Go binding around an Ethereum contract.
type BlockSigner struct {
BlockSignerCaller // Read-only binding to the contract
BlockSignerTransactor // Write-only binding to the contract
BlockSignerFilterer // Log filterer for contract events
}
// BlockSignerCaller is an auto generated read-only Go binding around an Ethereum contract.
type BlockSignerCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// BlockSignerTransactor is an auto generated write-only Go binding around an Ethereum contract.
type BlockSignerTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// BlockSignerFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type BlockSignerFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// BlockSignerSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type BlockSignerSession struct {
Contract *BlockSigner // Generic contract binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// BlockSignerCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type BlockSignerCallerSession struct {
Contract *BlockSignerCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// BlockSignerTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type BlockSignerTransactorSession struct {
Contract *BlockSignerTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// BlockSignerRaw is an auto generated low-level Go binding around an Ethereum contract.
type BlockSignerRaw struct {
Contract *BlockSigner // Generic contract binding to access the raw methods on
}
// BlockSignerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type BlockSignerCallerRaw struct {
Contract *BlockSignerCaller // Generic read-only contract binding to access the raw methods on
}
// BlockSignerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type BlockSignerTransactorRaw struct {
Contract *BlockSignerTransactor // Generic write-only contract binding to access the raw methods on
}
// NewBlockSigner creates a new instance of BlockSigner, bound to a specific deployed contract.
func NewBlockSigner(address common.Address, backend bind.ContractBackend) (*BlockSigner, error) {
contract, err := bindBlockSigner(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &BlockSigner{BlockSignerCaller: BlockSignerCaller{contract: contract}, BlockSignerTransactor: BlockSignerTransactor{contract: contract}, BlockSignerFilterer: BlockSignerFilterer{contract: contract}}, nil
}
// NewBlockSignerCaller creates a new read-only instance of BlockSigner, bound to a specific deployed contract.
func NewBlockSignerCaller(address common.Address, caller bind.ContractCaller) (*BlockSignerCaller, error) {
contract, err := bindBlockSigner(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &BlockSignerCaller{contract: contract}, nil
}
// NewBlockSignerTransactor creates a new write-only instance of BlockSigner, bound to a specific deployed contract.
func NewBlockSignerTransactor(address common.Address, transactor bind.ContractTransactor) (*BlockSignerTransactor, error) {
contract, err := bindBlockSigner(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &BlockSignerTransactor{contract: contract}, nil
}
// NewBlockSignerFilterer creates a new log filterer instance of BlockSigner, bound to a specific deployed contract.
func NewBlockSignerFilterer(address common.Address, filterer bind.ContractFilterer) (*BlockSignerFilterer, error) {
contract, err := bindBlockSigner(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &BlockSignerFilterer{contract: contract}, nil
}
// bindBlockSigner binds a generic wrapper to an already deployed contract.
func bindBlockSigner(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader(BlockSignerABI))
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_BlockSigner *BlockSignerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _BlockSigner.Contract.BlockSignerCaller.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_BlockSigner *BlockSignerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _BlockSigner.Contract.BlockSignerTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_BlockSigner *BlockSignerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _BlockSigner.Contract.BlockSignerTransactor.contract.Transact(opts, method, params...)
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_BlockSigner *BlockSignerCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _BlockSigner.Contract.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_BlockSigner *BlockSignerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _BlockSigner.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_BlockSigner *BlockSignerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _BlockSigner.Contract.contract.Transact(opts, method, params...)
}
// EpochNumber is a free data retrieval call binding the contract method 0xf4145a83.
//
// Solidity: function epochNumber() constant returns(uint256)
func (_BlockSigner *BlockSignerCaller) EpochNumber(opts *bind.CallOpts) (*big.Int, error) {
var (
ret0 = new(*big.Int)
)
out := ret0
err := _BlockSigner.contract.Call(opts, out, "epochNumber")
return *ret0, err
}
// EpochNumber is a free data retrieval call binding the contract method 0xf4145a83.
//
// Solidity: function epochNumber() constant returns(uint256)
func (_BlockSigner *BlockSignerSession) EpochNumber() (*big.Int, error) {
return _BlockSigner.Contract.EpochNumber(&_BlockSigner.CallOpts)
}
// EpochNumber is a free data retrieval call binding the contract method 0xf4145a83.
//
// Solidity: function epochNumber() constant returns(uint256)
func (_BlockSigner *BlockSignerCallerSession) EpochNumber() (*big.Int, error) {
return _BlockSigner.Contract.EpochNumber(&_BlockSigner.CallOpts)
}
// GetSigners is a free data retrieval call binding the contract method 0xe7ec6aef.
//
// Solidity: function getSigners(_blockHash bytes32) constant returns(address[])
func (_BlockSigner *BlockSignerCaller) GetSigners(opts *bind.CallOpts, _blockHash [32]byte) ([]common.Address, error) {
var (
ret0 = new([]common.Address)
)
out := ret0
err := _BlockSigner.contract.Call(opts, out, "getSigners", _blockHash)
return *ret0, err
}
// GetSigners is a free data retrieval call binding the contract method 0xe7ec6aef.
//
// Solidity: function getSigners(_blockHash bytes32) constant returns(address[])
func (_BlockSigner *BlockSignerSession) GetSigners(_blockHash [32]byte) ([]common.Address, error) {
return _BlockSigner.Contract.GetSigners(&_BlockSigner.CallOpts, _blockHash)
}
// GetSigners is a free data retrieval call binding the contract method 0xe7ec6aef.
//
// Solidity: function getSigners(_blockHash bytes32) constant returns(address[])
func (_BlockSigner *BlockSignerCallerSession) GetSigners(_blockHash [32]byte) ([]common.Address, error) {
return _BlockSigner.Contract.GetSigners(&_BlockSigner.CallOpts, _blockHash)
}
// Sign is a paid mutator transaction binding the contract method 0xe341eaa4.
//
// Solidity: function sign(_blockNumber uint256, _blockHash bytes32) returns()
func (_BlockSigner *BlockSignerTransactor) Sign(opts *bind.TransactOpts, _blockNumber *big.Int, _blockHash [32]byte) (*types.Transaction, error) {
return _BlockSigner.contract.Transact(opts, "sign", _blockNumber, _blockHash)
}
// Sign is a paid mutator transaction binding the contract method 0xe341eaa4.
//
// Solidity: function sign(_blockNumber uint256, _blockHash bytes32) returns()
func (_BlockSigner *BlockSignerSession) Sign(_blockNumber *big.Int, _blockHash [32]byte) (*types.Transaction, error) {
return _BlockSigner.Contract.Sign(&_BlockSigner.TransactOpts, _blockNumber, _blockHash)
}
// Sign is a paid mutator transaction binding the contract method 0xe341eaa4.
//
// Solidity: function sign(_blockNumber uint256, _blockHash bytes32) returns()
func (_BlockSigner *BlockSignerTransactorSession) Sign(_blockNumber *big.Int, _blockHash [32]byte) (*types.Transaction, error) {
return _BlockSigner.Contract.Sign(&_BlockSigner.TransactOpts, _blockNumber, _blockHash)
}
// BlockSignerSignIterator is returned from FilterSign and is used to iterate over the raw logs and unpacked data for Sign events raised by the BlockSigner contract.
type BlockSignerSignIterator struct {
Event *BlockSignerSign // Event containing the contract specifics and raw log
contract *bind.BoundContract // Generic contract to use for unpacking event data
event string // Event name to use for unpacking event data
logs chan types.Log // Log channel receiving the found contract events
sub ethereum.Subscription // Subscription for errors, completion and termination
done bool // Whether the subscription completed delivering logs
fail error // Occurred error to stop iteration
}
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *BlockSignerSignIterator) Next() bool {
// If the iterator failed, stop iterating
if it.fail != nil {
return false
}
// If the iterator completed, deliver directly whatever's available
if it.done {
select {
case log := <-it.logs:
it.Event = new(BlockSignerSign)
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
default:
return false
}
}
// Iterator still in progress, wait for either a data or an error event
select {
case log := <-it.logs:
it.Event = new(BlockSignerSign)
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
case err := <-it.sub.Err():
it.done = true
it.fail = err
return it.Next()
}
}
// Error returns any retrieval or parsing error occurred during filtering.
func (it *BlockSignerSignIterator) Error() error {
return it.fail
}
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *BlockSignerSignIterator) Close() error {
it.sub.Unsubscribe()
return nil
}
// BlockSignerSign represents a Sign event raised by the BlockSigner contract.
type BlockSignerSign struct {
Signer common.Address
BlockNumber *big.Int
BlockHash [32]byte
Raw types.Log // Blockchain specific contextual infos
}
// FilterSign is a free log retrieval operation binding the contract event 0x62855fa22e051687c32ac285857751f6d3f2c100c72756d8d30cb7ecb1f64f54.
//
// Solidity: event Sign(_signer address, _blockNumber uint256, _blockHash bytes32)
func (_BlockSigner *BlockSignerFilterer) FilterSign(opts *bind.FilterOpts) (*BlockSignerSignIterator, error) {
logs, sub, err := _BlockSigner.contract.FilterLogs(opts, "Sign")
if err != nil {
return nil, err
}
return &BlockSignerSignIterator{contract: _BlockSigner.contract, event: "Sign", logs: logs, sub: sub}, nil
}
// WatchSign is a free log subscription operation binding the contract event 0x62855fa22e051687c32ac285857751f6d3f2c100c72756d8d30cb7ecb1f64f54.
//
// Solidity: event Sign(_signer address, _blockNumber uint256, _blockHash bytes32)
func (_BlockSigner *BlockSignerFilterer) WatchSign(opts *bind.WatchOpts, sink chan<- *BlockSignerSign) (event.Subscription, error) {
logs, sub, err := _BlockSigner.contract.WatchLogs(opts, "Sign")
if err != nil {
return nil, err
}
return event.NewSubscription(func(quit <-chan struct{}) error {
defer sub.Unsubscribe()
for {
select {
case log := <-logs:
// New log arrived, parse the event and forward to the user
event := new(BlockSignerSign)
if err := _BlockSigner.contract.UnpackLog(event, "Sign", log); err != nil {
return err
}
event.Raw = log
select {
case sink <- event:
case err := <-sub.Err():
return err
case <-quit:
return nil
}
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
}), nil
}
// SafeMathABI is the input ABI used to generate the binding from.
const SafeMathABI = "[]"
// SafeMathBin is the compiled bytecode used for deploying new contracts.
const SafeMathBin = `0x604c602c600b82828239805160001a60731460008114601c57601e565bfe5b5030600052607381538281f30073000000000000000000000000000000000000000030146060604052600080fd00a165627a7a72305820b9407d48ebc7efee5c9f08b3b3a957df2939281f5913225e8c1291f069b900490029`
// DeploySafeMath deploys a new Ethereum contract, binding an instance of SafeMath to it.
func DeploySafeMath(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SafeMath, error) {
parsed, err := abi.JSON(strings.NewReader(SafeMathABI))
if err != nil {
return common.Address{}, nil, nil, err
}
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(SafeMathBin), backend)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &SafeMath{SafeMathCaller: SafeMathCaller{contract: contract}, SafeMathTransactor: SafeMathTransactor{contract: contract}, SafeMathFilterer: SafeMathFilterer{contract: contract}}, nil
}
// SafeMath is an auto generated Go binding around an Ethereum contract.
type SafeMath struct {
SafeMathCaller // Read-only binding to the contract
SafeMathTransactor // Write-only binding to the contract
SafeMathFilterer // Log filterer for contract events
}
// SafeMathCaller is an auto generated read-only Go binding around an Ethereum contract.
type SafeMathCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// SafeMathTransactor is an auto generated write-only Go binding around an Ethereum contract.
type SafeMathTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// SafeMathFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type SafeMathFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// SafeMathSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type SafeMathSession struct {
Contract *SafeMath // Generic contract binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// SafeMathCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type SafeMathCallerSession struct {
Contract *SafeMathCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// SafeMathTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type SafeMathTransactorSession struct {
Contract *SafeMathTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// SafeMathRaw is an auto generated low-level Go binding around an Ethereum contract.
type SafeMathRaw struct {
Contract *SafeMath // Generic contract binding to access the raw methods on
}
// SafeMathCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type SafeMathCallerRaw struct {
Contract *SafeMathCaller // Generic read-only contract binding to access the raw methods on
}
// SafeMathTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type SafeMathTransactorRaw struct {
Contract *SafeMathTransactor // Generic write-only contract binding to access the raw methods on
}
// NewSafeMath creates a new instance of SafeMath, bound to a specific deployed contract.
func NewSafeMath(address common.Address, backend bind.ContractBackend) (*SafeMath, error) {
contract, err := bindSafeMath(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &SafeMath{SafeMathCaller: SafeMathCaller{contract: contract}, SafeMathTransactor: SafeMathTransactor{contract: contract}, SafeMathFilterer: SafeMathFilterer{contract: contract}}, nil
}
// NewSafeMathCaller creates a new read-only instance of SafeMath, bound to a specific deployed contract.
func NewSafeMathCaller(address common.Address, caller bind.ContractCaller) (*SafeMathCaller, error) {
contract, err := bindSafeMath(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &SafeMathCaller{contract: contract}, nil
}
// NewSafeMathTransactor creates a new write-only instance of SafeMath, bound to a specific deployed contract.
func NewSafeMathTransactor(address common.Address, transactor bind.ContractTransactor) (*SafeMathTransactor, error) {
contract, err := bindSafeMath(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &SafeMathTransactor{contract: contract}, nil
}
// NewSafeMathFilterer creates a new log filterer instance of SafeMath, bound to a specific deployed contract.
func NewSafeMathFilterer(address common.Address, filterer bind.ContractFilterer) (*SafeMathFilterer, error) {
contract, err := bindSafeMath(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &SafeMathFilterer{contract: contract}, nil
}
// bindSafeMath binds a generic wrapper to an already deployed contract.
func bindSafeMath(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader(SafeMathABI))
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_SafeMath *SafeMathRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _SafeMath.Contract.SafeMathCaller.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_SafeMath *SafeMathRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _SafeMath.Contract.SafeMathTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_SafeMath *SafeMathRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _SafeMath.Contract.SafeMathTransactor.contract.Transact(opts, method, params...)
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_SafeMath *SafeMathCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _SafeMath.Contract.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_SafeMath *SafeMathTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _SafeMath.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_SafeMath *SafeMathTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _SafeMath.Contract.contract.Transact(opts, method, params...)
}

View file

@ -0,0 +1,47 @@
pragma solidity ^0.4.21;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}

View file

@ -0,0 +1,370 @@
pragma solidity ^0.4.21;
/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
/// @author Stefan George - <stefan.george@consensys.net>
contract MultiSigWallet {
/*
* Events
*/
event Confirmation(address indexed sender, uint indexed transactionId);
event Revocation(address indexed sender, uint indexed transactionId);
event Submission(uint indexed transactionId);
event Execution(uint indexed transactionId);
event ExecutionFailure(uint indexed transactionId);
event Deposit(address indexed sender, uint value);
event OwnerAddition(address indexed owner);
event OwnerRemoval(address indexed owner);
event RequirementChange(uint required);
/*
* Constants
*/
uint constant public MAX_OWNER_COUNT = 50;
/*
* Storage
*/
mapping (uint => Transaction) public transactions;
mapping (uint => mapping (address => bool)) public confirmations;
mapping (address => bool) public isOwner;
address[] public owners;
uint public required;
uint public transactionCount;
struct Transaction {
address destination;
uint value;
bytes data;
bool executed;
}
/*
* Modifiers
*/
modifier onlyWallet() {
require(msg.sender == address(this));
_;
}
modifier ownerDoesNotExist(address owner) {
require(!isOwner[owner]);
_;
}
modifier ownerExists(address owner) {
require(isOwner[owner]);
_;
}
modifier transactionExists(uint transactionId) {
require(transactions[transactionId].destination != 0);
_;
}
modifier confirmed(uint transactionId, address owner) {
require(confirmations[transactionId][owner]);
_;
}
modifier notConfirmed(uint transactionId, address owner) {
require(!confirmations[transactionId][owner]);
_;
}
modifier notExecuted(uint transactionId) {
require(!transactions[transactionId].executed);
_;
}
modifier notNull(address _address) {
require(_address != 0);
_;
}
modifier validRequirement(uint ownerCount, uint _required) {
require(ownerCount <= MAX_OWNER_COUNT
&& _required <= ownerCount
&& _required != 0
&& ownerCount != 0);
_;
}
/// @dev Fallback function allows to deposit ether.
function()
payable
{
if (msg.value > 0)
Deposit(msg.sender, msg.value);
}
/*
* Public functions
*/
/// @dev Contract constructor sets initial owners and required number of confirmations.
/// @param _owners List of initial owners.
/// @param _required Number of required confirmations.
function MultiSigWallet(address[] _owners, uint _required)
public
validRequirement(_owners.length, _required)
{
for (uint i=0; i<_owners.length; i++) {
require(!isOwner[_owners[i]] && _owners[i] != 0);
isOwner[_owners[i]] = true;
}
owners = _owners;
required = _required;
}
/// @dev Allows to add a new owner. Transaction has to be sent by wallet.
/// @param owner Address of new owner.
function addOwner(address owner)
public
onlyWallet
ownerDoesNotExist(owner)
notNull(owner)
validRequirement(owners.length + 1, required)
{
isOwner[owner] = true;
owners.push(owner);
OwnerAddition(owner);
}
/// @dev Allows to remove an owner. Transaction has to be sent by wallet.
/// @param owner Address of owner.
function removeOwner(address owner)
public
onlyWallet
ownerExists(owner)
{
isOwner[owner] = false;
for (uint i=0; i<owners.length - 1; i++)
if (owners[i] == owner) {
owners[i] = owners[owners.length - 1];
break;
}
owners.length -= 1;
if (required > owners.length)
changeRequirement(owners.length);
OwnerRemoval(owner);
}
/// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
/// @param owner Address of owner to be replaced.
/// @param newOwner Address of new owner.
function replaceOwner(address owner, address newOwner)
public
onlyWallet
ownerExists(owner)
ownerDoesNotExist(newOwner)
{
for (uint i=0; i<owners.length; i++)
if (owners[i] == owner) {
owners[i] = newOwner;
break;
}
isOwner[owner] = false;
isOwner[newOwner] = true;
OwnerRemoval(owner);
OwnerAddition(newOwner);
}
/// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
/// @param _required Number of required confirmations.
function changeRequirement(uint _required)
public
onlyWallet
validRequirement(owners.length, _required)
{
required = _required;
RequirementChange(_required);
}
/// @dev Allows an owner to submit and confirm a transaction.
/// @param destination Transaction target address.
/// @param value Transaction ether value.
/// @param data Transaction data payload.
/// @return Returns transaction ID.
function submitTransaction(address destination, uint value, bytes data)
public
returns (uint transactionId)
{
transactionId = addTransaction(destination, value, data);
confirmTransaction(transactionId);
}
/// @dev Allows an owner to confirm a transaction.
/// @param transactionId Transaction ID.
function confirmTransaction(uint transactionId)
public
ownerExists(msg.sender)
transactionExists(transactionId)
notConfirmed(transactionId, msg.sender)
{
confirmations[transactionId][msg.sender] = true;
Confirmation(msg.sender, transactionId);
executeTransaction(transactionId);
}
/// @dev Allows an owner to revoke a confirmation for a transaction.
/// @param transactionId Transaction ID.
function revokeConfirmation(uint transactionId)
public
ownerExists(msg.sender)
confirmed(transactionId, msg.sender)
notExecuted(transactionId)
{
confirmations[transactionId][msg.sender] = false;
Revocation(msg.sender, transactionId);
}
/// @dev Allows anyone to execute a confirmed transaction.
/// @param transactionId Transaction ID.
function executeTransaction(uint transactionId)
public
ownerExists(msg.sender)
confirmed(transactionId, msg.sender)
notExecuted(transactionId)
{
if (isConfirmed(transactionId)) {
Transaction storage txn = transactions[transactionId];
txn.executed = true;
if (txn.destination.call.value(txn.value)(txn.data))
Execution(transactionId);
else {
ExecutionFailure(transactionId);
txn.executed = false;
}
}
}
/// @dev Returns the confirmation status of a transaction.
/// @param transactionId Transaction ID.
/// @return Confirmation status.
function isConfirmed(uint transactionId)
public
constant
returns (bool)
{
uint count = 0;
for (uint i=0; i<owners.length; i++) {
if (confirmations[transactionId][owners[i]])
count += 1;
if (count == required)
return true;
}
}
/*
* Internal functions
*/
/// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
/// @param destination Transaction target address.
/// @param value Transaction ether value.
/// @param data Transaction data payload.
/// @return Returns transaction ID.
function addTransaction(address destination, uint value, bytes data)
internal
notNull(destination)
returns (uint transactionId)
{
transactionId = transactionCount;
transactions[transactionId] = Transaction({
destination: destination,
value: value,
data: data,
executed: false
});
transactionCount += 1;
Submission(transactionId);
}
/*
* Web3 call functions
*/
/// @dev Returns number of confirmations of a transaction.
/// @param transactionId Transaction ID.
/// @return Number of confirmations.
function getConfirmationCount(uint transactionId)
public
constant
returns (uint count)
{
for (uint i=0; i<owners.length; i++)
if (confirmations[transactionId][owners[i]])
count += 1;
}
/// @dev Returns total number of transactions after filers are applied.
/// @param pending Include pending transactions.
/// @param executed Include executed transactions.
/// @return Total number of transactions after filters are applied.
function getTransactionCount(bool pending, bool executed)
public
constant
returns (uint count)
{
for (uint i=0; i<transactionCount; i++)
if ( pending && !transactions[i].executed
|| executed && transactions[i].executed)
count += 1;
}
/// @dev Returns list of owners.
/// @return List of owner addresses.
function getOwners()
public
constant
returns (address[])
{
return owners;
}
/// @dev Returns array with owner addresses, which confirmed transaction.
/// @param transactionId Transaction ID.
/// @return Returns array of owner addresses.
function getConfirmations(uint transactionId)
public
constant
returns (address[] _confirmations)
{
address[] memory confirmationsTemp = new address[](owners.length);
uint count = 0;
uint i;
for (i=0; i<owners.length; i++)
if (confirmations[transactionId][owners[i]]) {
confirmationsTemp[count] = owners[i];
count += 1;
}
_confirmations = new address[](count);
for (i=0; i<count; i++)
_confirmations[i] = confirmationsTemp[i];
}
/// @dev Returns list of transaction IDs in defined range.
/// @param from Index start position of transaction array.
/// @param to Index end position of transaction array.
/// @param pending Include pending transactions.
/// @param executed Include executed transactions.
/// @return Returns array of transaction IDs.
function getTransactionIds(uint from, uint to, bool pending, bool executed)
public
constant
returns (uint[] _transactionIds)
{
uint[] memory transactionIdsTemp = new uint[](transactionCount);
uint count = 0;
uint i;
for (i=0; i<transactionCount; i++)
if ( pending && !transactions[i].executed
|| executed && transactions[i].executed)
{
transactionIdsTemp[count] = i;
count += 1;
}
_transactionIds = new uint[](to - from);
for (i=from; i<to; i++)
_transactionIds[i - from] = transactionIdsTemp[i];
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,57 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package multisigwallet
import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/contracts/multisigwallet/contract"
"math/big"
)
type MultiSigWallet struct {
*contract.MultiSigWalletSession
contractBackend bind.ContractBackend
}
func NewMultiSigWallet(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*MultiSigWallet, error) {
blockSigner, err := contract.NewMultiSigWallet(contractAddr, contractBackend)
if err != nil {
return nil, err
}
return &MultiSigWallet{
&contract.MultiSigWalletSession{
Contract: blockSigner,
TransactOpts: *transactOpts,
},
contractBackend,
}, nil
}
func DeployMultiSigWallet(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend, _owners []common.Address, _required *big.Int) (common.Address, *MultiSigWallet, error) {
blockSignerAddr, _, _, err := contract.DeployMultiSigWallet(transactOpts, contractBackend, _owners, _required)
if err != nil {
return blockSignerAddr, nil, err
}
blockSigner, err := NewMultiSigWallet(transactOpts, blockSignerAddr, contractBackend)
if err != nil {
return blockSignerAddr, nil, err
}
return blockSignerAddr, blockSigner, nil
}

View file

@ -0,0 +1,34 @@
pragma solidity ^0.4.21;
import "./libs/SafeMath.sol";
contract XDCRandomize {
using SafeMath for uint256;
mapping (address=>bytes32[]) randomSecret;
mapping (address=>bytes32) randomOpening;
function XDCRandomize () public {
}
function setSecret(bytes32[] _secret) public {
uint secretPoint = block.number % 900;
require(secretPoint >= 800);
require(secretPoint < 850);
randomSecret[msg.sender] = _secret;
}
function setOpening(bytes32 _opening) public {
uint openingPoint = block.number % 900;
require(openingPoint >= 850);
randomOpening[msg.sender] = _opening;
}
function getSecret(address _validator) public view returns(bytes32[]) {
return randomSecret[_validator];
}
function getOpening(address _validator) public view returns(bytes32) {
return randomOpening[_validator];
}
}

View file

@ -0,0 +1,47 @@
pragma solidity ^0.4.21;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}

View file

@ -0,0 +1,429 @@
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package contract
import (
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// SafeMathABI is the input ABI used to generate the binding from.
const SafeMathABI = "[]"
// SafeMathBin is the compiled bytecode used for deploying new contracts.
const SafeMathBin = `0x604c602c600b82828239805160001a60731460008114601c57601e565bfe5b5030600052607381538281f30073000000000000000000000000000000000000000030146060604052600080fd00a165627a7a72305820b9407d48ebc7efee5c9f08b3b3a957df2939281f5913225e8c1291f069b900490029`
// DeploySafeMath deploys a new Ethereum contract, binding an instance of SafeMath to it.
func DeploySafeMath(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SafeMath, error) {
parsed, err := abi.JSON(strings.NewReader(SafeMathABI))
if err != nil {
return common.Address{}, nil, nil, err
}
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(SafeMathBin), backend)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &SafeMath{SafeMathCaller: SafeMathCaller{contract: contract}, SafeMathTransactor: SafeMathTransactor{contract: contract}, SafeMathFilterer: SafeMathFilterer{contract: contract}}, nil
}
// SafeMath is an auto generated Go binding around an Ethereum contract.
type SafeMath struct {
SafeMathCaller // Read-only binding to the contract
SafeMathTransactor // Write-only binding to the contract
SafeMathFilterer // Log filterer for contract events
}
// SafeMathCaller is an auto generated read-only Go binding around an Ethereum contract.
type SafeMathCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// SafeMathTransactor is an auto generated write-only Go binding around an Ethereum contract.
type SafeMathTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// SafeMathFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type SafeMathFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// SafeMathSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type SafeMathSession struct {
Contract *SafeMath // Generic contract binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// SafeMathCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type SafeMathCallerSession struct {
Contract *SafeMathCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// SafeMathTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type SafeMathTransactorSession struct {
Contract *SafeMathTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// SafeMathRaw is an auto generated low-level Go binding around an Ethereum contract.
type SafeMathRaw struct {
Contract *SafeMath // Generic contract binding to access the raw methods on
}
// SafeMathCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type SafeMathCallerRaw struct {
Contract *SafeMathCaller // Generic read-only contract binding to access the raw methods on
}
// SafeMathTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type SafeMathTransactorRaw struct {
Contract *SafeMathTransactor // Generic write-only contract binding to access the raw methods on
}
// NewSafeMath creates a new instance of SafeMath, bound to a specific deployed contract.
func NewSafeMath(address common.Address, backend bind.ContractBackend) (*SafeMath, error) {
contract, err := bindSafeMath(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &SafeMath{SafeMathCaller: SafeMathCaller{contract: contract}, SafeMathTransactor: SafeMathTransactor{contract: contract}, SafeMathFilterer: SafeMathFilterer{contract: contract}}, nil
}
// NewSafeMathCaller creates a new read-only instance of SafeMath, bound to a specific deployed contract.
func NewSafeMathCaller(address common.Address, caller bind.ContractCaller) (*SafeMathCaller, error) {
contract, err := bindSafeMath(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &SafeMathCaller{contract: contract}, nil
}
// NewSafeMathTransactor creates a new write-only instance of SafeMath, bound to a specific deployed contract.
func NewSafeMathTransactor(address common.Address, transactor bind.ContractTransactor) (*SafeMathTransactor, error) {
contract, err := bindSafeMath(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &SafeMathTransactor{contract: contract}, nil
}
// NewSafeMathFilterer creates a new log filterer instance of SafeMath, bound to a specific deployed contract.
func NewSafeMathFilterer(address common.Address, filterer bind.ContractFilterer) (*SafeMathFilterer, error) {
contract, err := bindSafeMath(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &SafeMathFilterer{contract: contract}, nil
}
// bindSafeMath binds a generic wrapper to an already deployed contract.
func bindSafeMath(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader(SafeMathABI))
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_SafeMath *SafeMathRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _SafeMath.Contract.SafeMathCaller.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_SafeMath *SafeMathRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _SafeMath.Contract.SafeMathTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_SafeMath *SafeMathRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _SafeMath.Contract.SafeMathTransactor.contract.Transact(opts, method, params...)
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_SafeMath *SafeMathCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _SafeMath.Contract.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_SafeMath *SafeMathTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _SafeMath.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_SafeMath *SafeMathTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _SafeMath.Contract.contract.Transact(opts, method, params...)
}
// XDCRandomizeABI is the input ABI used to generate the binding from.
const XDCRandomizeABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"_validator\",\"type\":\"address\"}],\"name\":\"getSecret\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_secret\",\"type\":\"bytes32[]\"}],\"name\":\"setSecret\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_validator\",\"type\":\"address\"}],\"name\":\"getOpening\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_opening\",\"type\":\"bytes32\"}],\"name\":\"setOpening\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]"
// XDCRandomizeBin is the compiled bytecode used for deploying new contracts.
const XDCRandomizeBin = `0x6060604052341561000f57600080fd5b6103368061001e6000396000f3006060604052600436106100615763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663284180fc811461006657806334d38600146100d8578063d442d6cc14610129578063e11f5ba21461015a575b600080fd5b341561007157600080fd5b610085600160a060020a0360043516610170565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156100c45780820151838201526020016100ac565b505050509050019250505060405180910390f35b34156100e357600080fd5b61012760046024813581810190830135806020818102016040519081016040528093929190818152602001838360200280828437509496506101f395505050505050565b005b341561013457600080fd5b610148600160a060020a0360043516610243565b60405190815260200160405180910390f35b341561016557600080fd5b61012760043561025e565b61017861028e565b60008083600160a060020a0316600160a060020a031681526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156101e757602002820191906000526020600020905b815481526001909101906020018083116101d2575b50505050509050919050565b610384430661032081101561020757600080fd5b610352811061021557600080fd5b600160a060020a033316600090815260208190526040902082805161023e9291602001906102a0565b505050565b600160a060020a031660009081526001602052604090205490565b610384430661035281101561027257600080fd5b50600160a060020a033316600090815260016020526040902055565b60206040519081016040526000815290565b8280548282559060005260206000209081019282156102dd579160200282015b828111156102dd57825182556020909201916001909101906102c0565b506102e99291506102ed565b5090565b61030791905b808211156102e957600081556001016102f3565b905600a165627a7a7230582034991c8dc4001fc254f3ba2811c05d2e7d29bee3908946ca56d1545b2c852de20029`
// DeployXDCRandomize deploys a new Ethereum contract, binding an instance of XDCRandomize to it.
func DeployXDCRandomize(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *XDCRandomize, error) {
parsed, err := abi.JSON(strings.NewReader(XDCRandomizeABI))
if err != nil {
return common.Address{}, nil, nil, err
}
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(XDCRandomizeBin), backend)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &XDCRandomize{XDCRandomizeCaller: XDCRandomizeCaller{contract: contract}, XDCRandomizeTransactor: XDCRandomizeTransactor{contract: contract}, XDCRandomizeFilterer: XDCRandomizeFilterer{contract: contract}}, nil
}
// XDCRandomize is an auto generated Go binding around an Ethereum contract.
type XDCRandomize struct {
XDCRandomizeCaller // Read-only binding to the contract
XDCRandomizeTransactor // Write-only binding to the contract
XDCRandomizeFilterer // Log filterer for contract events
}
// XDCRandomizeCaller is an auto generated read-only Go binding around an Ethereum contract.
type XDCRandomizeCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// XDCRandomizeTransactor is an auto generated write-only Go binding around an Ethereum contract.
type XDCRandomizeTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// XDCRandomizeFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type XDCRandomizeFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// XDCRandomizeSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type XDCRandomizeSession struct {
Contract *XDCRandomize // Generic contract binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// XDCRandomizeCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type XDCRandomizeCallerSession struct {
Contract *XDCRandomizeCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// XDCRandomizeTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type XDCRandomizeTransactorSession struct {
Contract *XDCRandomizeTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// XDCRandomizeRaw is an auto generated low-level Go binding around an Ethereum contract.
type XDCRandomizeRaw struct {
Contract *XDCRandomize // Generic contract binding to access the raw methods on
}
// XDCRandomizeCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type XDCRandomizeCallerRaw struct {
Contract *XDCRandomizeCaller // Generic read-only contract binding to access the raw methods on
}
// XDCRandomizeTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type XDCRandomizeTransactorRaw struct {
Contract *XDCRandomizeTransactor // Generic write-only contract binding to access the raw methods on
}
// NewXDCRandomize creates a new instance of XDCRandomize, bound to a specific deployed contract.
func NewXDCRandomize(address common.Address, backend bind.ContractBackend) (*XDCRandomize, error) {
contract, err := bindXDCRandomize(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &XDCRandomize{XDCRandomizeCaller: XDCRandomizeCaller{contract: contract}, XDCRandomizeTransactor: XDCRandomizeTransactor{contract: contract}, XDCRandomizeFilterer: XDCRandomizeFilterer{contract: contract}}, nil
}
// NewXDCRandomizeCaller creates a new read-only instance of XDCRandomize, bound to a specific deployed contract.
func NewXDCRandomizeCaller(address common.Address, caller bind.ContractCaller) (*XDCRandomizeCaller, error) {
contract, err := bindXDCRandomize(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &XDCRandomizeCaller{contract: contract}, nil
}
// NewXDCRandomizeTransactor creates a new write-only instance of XDCRandomize, bound to a specific deployed contract.
func NewXDCRandomizeTransactor(address common.Address, transactor bind.ContractTransactor) (*XDCRandomizeTransactor, error) {
contract, err := bindXDCRandomize(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &XDCRandomizeTransactor{contract: contract}, nil
}
// NewXDCRandomizeFilterer creates a new log filterer instance of XDCRandomize, bound to a specific deployed contract.
func NewXDCRandomizeFilterer(address common.Address, filterer bind.ContractFilterer) (*XDCRandomizeFilterer, error) {
contract, err := bindXDCRandomize(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &XDCRandomizeFilterer{contract: contract}, nil
}
// bindXDCRandomize binds a generic wrapper to an already deployed contract.
func bindXDCRandomize(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader(XDCRandomizeABI))
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_XDCRandomize *XDCRandomizeRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _XDCRandomize.Contract.XDCRandomizeCaller.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_XDCRandomize *XDCRandomizeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _XDCRandomize.Contract.XDCRandomizeTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_XDCRandomize *XDCRandomizeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _XDCRandomize.Contract.XDCRandomizeTransactor.contract.Transact(opts, method, params...)
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_XDCRandomize *XDCRandomizeCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
return _XDCRandomize.Contract.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_XDCRandomize *XDCRandomizeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _XDCRandomize.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_XDCRandomize *XDCRandomizeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _XDCRandomize.Contract.contract.Transact(opts, method, params...)
}
// GetOpening is a free data retrieval call binding the contract method 0xd442d6cc.
//
// Solidity: function getOpening(_validator address) constant returns(bytes32)
func (_XDCRandomize *XDCRandomizeCaller) GetOpening(opts *bind.CallOpts, _validator common.Address) ([32]byte, error) {
var (
ret0 = new([32]byte)
)
out := ret0
err := _XDCRandomize.contract.Call(opts, out, "getOpening", _validator)
return *ret0, err
}
// GetOpening is a free data retrieval call binding the contract method 0xd442d6cc.
//
// Solidity: function getOpening(_validator address) constant returns(bytes32)
func (_XDCRandomize *XDCRandomizeSession) GetOpening(_validator common.Address) ([32]byte, error) {
return _XDCRandomize.Contract.GetOpening(&_XDCRandomize.CallOpts, _validator)
}
// GetOpening is a free data retrieval call binding the contract method 0xd442d6cc.
//
// Solidity: function getOpening(_validator address) constant returns(bytes32)
func (_XDCRandomize *XDCRandomizeCallerSession) GetOpening(_validator common.Address) ([32]byte, error) {
return _XDCRandomize.Contract.GetOpening(&_XDCRandomize.CallOpts, _validator)
}
// GetSecret is a free data retrieval call binding the contract method 0x284180fc.
//
// Solidity: function getSecret(_validator address) constant returns(bytes32[])
func (_XDCRandomize *XDCRandomizeCaller) GetSecret(opts *bind.CallOpts, _validator common.Address) ([][32]byte, error) {
var (
ret0 = new([][32]byte)
)
out := ret0
err := _XDCRandomize.contract.Call(opts, out, "getSecret", _validator)
return *ret0, err
}
// GetSecret is a free data retrieval call binding the contract method 0x284180fc.
//
// Solidity: function getSecret(_validator address) constant returns(bytes32[])
func (_XDCRandomize *XDCRandomizeSession) GetSecret(_validator common.Address) ([][32]byte, error) {
return _XDCRandomize.Contract.GetSecret(&_XDCRandomize.CallOpts, _validator)
}
// GetSecret is a free data retrieval call binding the contract method 0x284180fc.
//
// Solidity: function getSecret(_validator address) constant returns(bytes32[])
func (_XDCRandomize *XDCRandomizeCallerSession) GetSecret(_validator common.Address) ([][32]byte, error) {
return _XDCRandomize.Contract.GetSecret(&_XDCRandomize.CallOpts, _validator)
}
// SetOpening is a paid mutator transaction binding the contract method 0xe11f5ba2.
//
// Solidity: function setOpening(_opening bytes32) returns()
func (_XDCRandomize *XDCRandomizeTransactor) SetOpening(opts *bind.TransactOpts, _opening [32]byte) (*types.Transaction, error) {
return _XDCRandomize.contract.Transact(opts, "setOpening", _opening)
}
// SetOpening is a paid mutator transaction binding the contract method 0xe11f5ba2.
//
// Solidity: function setOpening(_opening bytes32) returns()
func (_XDCRandomize *XDCRandomizeSession) SetOpening(_opening [32]byte) (*types.Transaction, error) {
return _XDCRandomize.Contract.SetOpening(&_XDCRandomize.TransactOpts, _opening)
}
// SetOpening is a paid mutator transaction binding the contract method 0xe11f5ba2.
//
// Solidity: function setOpening(_opening bytes32) returns()
func (_XDCRandomize *XDCRandomizeTransactorSession) SetOpening(_opening [32]byte) (*types.Transaction, error) {
return _XDCRandomize.Contract.SetOpening(&_XDCRandomize.TransactOpts, _opening)
}
// SetSecret is a paid mutator transaction binding the contract method 0x34d38600.
//
// Solidity: function setSecret(_secret bytes32[]) returns()
func (_XDCRandomize *XDCRandomizeTransactor) SetSecret(opts *bind.TransactOpts, _secret [][32]byte) (*types.Transaction, error) {
return _XDCRandomize.contract.Transact(opts, "setSecret", _secret)
}
// SetSecret is a paid mutator transaction binding the contract method 0x34d38600.
//
// Solidity: function setSecret(_secret bytes32[]) returns()
func (_XDCRandomize *XDCRandomizeSession) SetSecret(_secret [][32]byte) (*types.Transaction, error) {
return _XDCRandomize.Contract.SetSecret(&_XDCRandomize.TransactOpts, _secret)
}
// SetSecret is a paid mutator transaction binding the contract method 0x34d38600.
//
// Solidity: function setSecret(_secret bytes32[]) returns()
func (_XDCRandomize *XDCRandomizeTransactorSession) SetSecret(_secret [][32]byte) (*types.Transaction, error) {
return _XDCRandomize.Contract.SetSecret(&_XDCRandomize.TransactOpts, _secret)
}

View file

@ -0,0 +1,56 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package randomize
import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/contracts/randomize/contract"
)
type Randomize struct {
*contract.XDCRandomizeSession
contractBackend bind.ContractBackend
}
func NewRandomize(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*Randomize, error) {
randomize, err := contract.NewXDCRandomize(contractAddr, contractBackend)
if err != nil {
return nil, err
}
return &Randomize{
&contract.XDCRandomizeSession{
Contract: randomize,
TransactOpts: *transactOpts,
},
contractBackend,
}, nil
}
func DeployRandomize(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend) (common.Address, *Randomize, error) {
randomizeAddr, _, _, err := contract.DeployXDCRandomize(transactOpts, contractBackend)
if err != nil {
return randomizeAddr, nil, err
}
randomize, err := NewRandomize(transactOpts, randomizeAddr, contractBackend)
if err != nil {
return randomizeAddr, nil, err
}
return randomizeAddr, randomize, nil
}

View file

@ -0,0 +1,152 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package randomize
import (
"context"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/contracts"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
)
var (
epocNumber = int64(12)
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr = crypto.PubkeyToAddress(key.PublicKey)
byte0 = make([][32]byte, epocNumber)
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey)
)
func TestRandomize(t *testing.T) {
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(100000000000000)}})
transactOpts := bind.NewKeyedTransactor(key)
transactOpts.GasLimit = 1000000
randomizeAddress, randomize, err := DeployRandomize(transactOpts, contractBackend)
t.Log("contract address", randomizeAddress.String())
if err != nil {
t.Fatalf("can't deploy root registry: %v", err)
}
contractBackend.Commit()
d := time.Now().Add(1000 * time.Millisecond)
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
code, _ := contractBackend.CodeAt(ctx, randomizeAddress, nil)
t.Log("contract code", common.ToHex(code))
f := func(key, val common.Hash) bool {
t.Log(key.Hex(), val.Hex())
return true
}
contractBackend.ForEachStorageAt(ctx, randomizeAddress, nil, f)
s, err := randomize.SetSecret(byte0)
if err != nil {
t.Fatalf("can't set secret: %v", err)
}
t.Log("tx data", s)
contractBackend.Commit()
}
func TestSendTxRandomizeSecretAndOpening(t *testing.T) {
genesis := core.GenesisAlloc{acc1Addr: {Balance: big.NewInt(1000000000000)}}
backend := backends.NewSimulatedBackend(genesis)
backend.Commit()
signer := types.HomesteadSigner{}
ctx := context.Background()
transactOpts := bind.NewKeyedTransactor(acc1Key)
transactOpts.GasLimit = 4200000
epocNumber := uint64(900)
randomizeAddr, randomizeContract, err := DeployRandomize(transactOpts, backend)
if err != nil {
t.Fatalf("Can't deploy randomize SC: %v", err)
}
backend.Commit()
randomizeKeyValue := contracts.RandStringByte(32)
for i := 1; i <= 900; i++ {
nonce := uint64(i)
switch i {
case 800:
tx, err := contracts.BuildTxSecretRandomize(nonce, randomizeAddr, epocNumber, randomizeKeyValue)
if err != nil {
t.Fatalf("Can't create tx randomize secret: %v", err)
}
tx, err = types.SignTx(tx, signer, acc1Key)
if err != nil {
t.Fatalf("Can't sign tx randomize secret: %v", err)
}
err = backend.SendTransaction(ctx, tx)
if err != nil {
t.Fatalf("Can't send tx for create randomize secret: %v", err)
}
case 850:
// Set opening.
tx, err := contracts.BuildTxOpeningRandomize(nonce, randomizeAddr, randomizeKeyValue)
if err != nil {
t.Fatalf("Can't create tx randomize opening: %v", err)
}
tx, err = types.SignTx(tx, signer, acc1Key)
if err != nil {
t.Fatalf("Can't sign tx randomize opening: %v", err)
}
err = backend.SendTransaction(ctx, tx)
if err != nil {
t.Fatalf("Can't send tx for create randomize opening: %v", err)
}
case 900:
// Get randomize secret from SC.
secrets, err := randomizeContract.GetSecret(acc1Addr)
if err != nil {
t.Error("Fail get secrets from randomize", err)
}
if len(secrets) <= 0 {
t.Error("Empty get secrets from SC", err)
}
// Decrypt randomize from SC.
opening, err := randomizeContract.GetOpening(acc1Addr)
if err != nil {
t.Fatalf("Can't get secret from SC: %v", err)
}
randomize, err := contracts.DecryptRandomizeFromSecretsAndOpening(secrets, opening)
t.Log("randomize", randomize)
if err != nil {
t.Error("Can't decrypt secret and opening", err)
}
default:
tx, err := types.SignTx(types.NewTransaction(nonce, common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, acc1Key)
if err != nil {
t.Fatalf("Can't sign tx randomize: %v", err)
}
err = backend.SendTransaction(ctx, tx)
if err != nil {
t.Fatalf("Can't send tx for create randomize: %v", err)
}
}
backend.Commit()
}
}

View file

@ -0,0 +1,37 @@
package contracts
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
)
var (
slotRandomizeMapping = map[string]uint64{
"randomSecret": 0,
"randomOpening": 1,
}
)
func GetSecret(statedb *state.StateDB, address common.Address) [][32]byte {
slot := slotRandomizeMapping["randomSecret"]
locSecret := getLocMappingAtKey(address.Hash(), slot)
arrLength := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locSecret))
keys := []common.Hash{}
for i := uint64(0); i < arrLength.Big().Uint64(); i++ {
key := getLocDynamicArrAtElement(common.BigToHash(locSecret), i, 1)
keys = append(keys, key)
}
rets := [][32]byte{}
for _, key := range keys {
ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), key)
rets = append(rets, ret)
}
return rets
}
func GetOpening(statedb *state.StateDB, address common.Address) [32]byte {
slot := slotRandomizeMapping["randomOpening"]
locOpening := getLocMappingAtKey(address.Hash(), slot)
ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locOpening))
return ret
}

34
contracts/smcUtils.go Normal file
View file

@ -0,0 +1,34 @@
package contracts
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
func getLocSimpleVariable(slot uint64) common.Hash {
slotHash := common.BigToHash(new(big.Int).SetUint64(slot))
return slotHash
}
func getLocMappingAtKey(key common.Hash, slot uint64) *big.Int {
slotHash := common.BigToHash(new(big.Int).SetUint64(slot))
retByte := crypto.Keccak256(key.Bytes(), slotHash.Bytes())
ret := new(big.Int)
ret.SetBytes(retByte)
return ret
}
func getLocDynamicArrAtElement(slotHash common.Hash, index uint64, elementSize uint64) common.Hash {
slotKecBig := crypto.Keccak256Hash(slotHash.Bytes()).Big()
//arrBig = slotKecBig + index * elementSize
arrBig := slotKecBig.Add(slotKecBig, new(big.Int).SetUint64(index*elementSize))
return common.BigToHash(arrBig)
}
func getLocFixedArrAtElement(slot uint64, index uint64, elementSize uint64) common.Hash {
slotBig := new(big.Int).SetUint64(slot)
arrBig := slotBig.Add(slotBig, new(big.Int).SetUint64(index*elementSize))
return common.BigToHash(arrBig)
}

282
contracts/test.go Normal file
View file

@ -0,0 +1,282 @@
package contracts
//
//import (
// "fmt"
// "math/big"
// "time"
//
// "github.com/ethereum/go-ethereum/common"
// "github.com/ethereum/go-ethereum/core"
// "github.com/ethereum/go-ethereum/core/state"
// "github.com/ethereum/go-ethereum/crypto"
// "github.com/ethereum/go-ethereum/ethdb"
// "github.com/ethereum/go-ethereum/core/types"
//)
//
//var (
// slotValidatorMapping = map[string]uint64{
// "withdrawsState": 0,
// "validatorsState": 1,
// "voters": 2,
// "candidates": 3,
// "candidateCount": 4,
// "minCandidateCap": 5,
// "minVoterCap": 6,
// "maxValidatorNumber": 7,
// "candidateWithdrawDelay": 8,
// "voterWithdrawDelay": 9,
// }
// slotBlockSignerMapping = map[string]uint64{
// "blockSigners": 0,
// "blocks": 1,
// }
// slotRandomizeMapping = map[string]uint64{
// "randomSecret": 0,
// "randomOpening": 1,
// }
// datadir = "/mnt/sgp1_tuna_chaindata3/data/XDCchaindata"
// candidate = "0xd6fa3e7a89bf8c84f0ccd204a15c0d259daf2091"
//)
//
//func main() {
// //Init
// chaindb, err := ethdb.NewLDBDatabase(datadir, 0, 0)
// if err != nil || chaindb == nil {
// fmt.Printf("Can't get chaindb: %v", err)
// return
// }
// headHash := core.GetHeadBlockHash(chaindb)
// blockNumber := core.GetBlockNumber(chaindb, headHash)
// block := core.GetBlock(chaindb, headHash, blockNumber)
// if block == nil {
// fmt.Println("Can't get head block")
// return
// }
// database := state.NewDatabase(chaindb)
// headerRootHash := block.Header().Root
// headHeaderHash := core.GetHeadHeaderHash(chaindb)
// statedb, _ := state.New(headHeaderHash, database)
// if statedb == nil {
// headHeaderHash = headerRootHash
// }
// candidateAddress := common.HexToAddress(candidate)
// fmt.Printf("Block head :%d, header root:%v\n", blockNumber, headerRootHash.Hex())
// statedb, _ = state.New(headHeaderHash, database)
// if statedb == nil {
// fmt.Println("Can't get state db")
// return
// }
//
// //GetCandidates
// _ = GetCandidates(statedb)
//
// //GetCandidateOwner
// _ = GetCandidateOwner(statedb, candidateAddress)
//
// //GetCandidateCap
// _ = GetCandidateCap(statedb, candidateAddress)
//
// //GetVoters
// voters := GetVoters(statedb, candidateAddress)
//
// start := time.Now()
// fmt.Printf("--------GetVoterCap---------\n")
// for _, voter := range voters {
// //GetVoterCap
// _ = GetVoterCap(statedb, candidateAddress, voter)
// }
// elapsed := time.Since(start)
// fmt.Printf("Execution time: %s\n", elapsed)
//
// //GetSigners
// blockInput := core.GetBlock(chaindb, common.HexToHash("0x632f2403ea19697082d794900275632eb3373f7a9943b1407461995bbbc2816a"), uint64(1800))
// _ = GetSigners(statedb, blockInput)
//
// //GetOpening
// _ = GetOpening(statedb, candidateAddress)
// //GetSecret
// _ = GetSecret(statedb, candidateAddress)
//}
//
//func GetCandidates(statedb *state.StateDB) []common.Address {
// start := time.Now()
// fmt.Printf("--------GetCandidates---------\n")
//
// slot := slotValidatorMapping["candidates"]
// slotHash := common.BigToHash(new(big.Int).SetUint64(slot))
// arrLength := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), slotHash)
// fmt.Printf("Candidates length: %v\n", arrLength.Hex())
// keys := []common.Hash{}
// for i := uint64(0); i < arrLength.Big().Uint64(); i++ {
// key := getLocDynamicArrAtElement(slotHash, i, 1)
// keys = append(keys, key)
// }
// rets := []common.Address{}
// for _, key := range keys {
// ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), key)
// rets = append(rets, common.HexToAddress(ret.Hex()))
// fmt.Printf("%v\n", common.HexToAddress(ret.Hex()).Hex())
// }
// elapsed := time.Since(start)
// fmt.Printf("Execution time: %s\n", elapsed)
// return rets
//}
//
//func GetCandidateOwner(statedb *state.StateDB, candidate common.Address) common.Address {
// start := time.Now()
// fmt.Printf("--------GetCandidateOwner---------\n")
//
// slot := slotValidatorMapping["validatorsState"]
// // validatorsState[_candidate].owner;
// locValidatorsState := getLocMappingAtKey(candidate.Hash(), slot)
// locCandidateOwner := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(0)))
// ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locCandidateOwner))
// fmt.Printf("ret: %v\n", common.HexToAddress(ret.Hex()).Hex())
//
// elapsed := time.Since(start)
// fmt.Printf("Execution time: %s\n", elapsed)
// return common.HexToAddress(ret.Hex())
//}
//
//func GetCandidateCap(statedb *state.StateDB, candidate common.Address) string {
// start := time.Now()
// fmt.Printf("--------GetCandidateCap---------\n")
//
// slot := slotValidatorMapping["validatorsState"]
// // validatorsState[_candidate].cap;
// locValidatorsState := getLocMappingAtKey(candidate.Hash(), slot)
// locCandidateCap := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(1)))
// ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locCandidateCap))
// fmt.Printf("cap: %v\n", ret.Big().String())
//
// elapsed := time.Since(start)
// fmt.Printf("Execution time: %s\n", elapsed)
// return ret.Hex()
//}
//
//func GetVoterCap(state *state.StateDB, candidate, voter common.Address) *big.Int {
// //validatorsState[_candidate].voters[_voter]
// slot := slotValidatorMapping["validatorsState"]
// locValidatorsState := getLocMappingAtKey(candidate.Hash(), slot)
// locCandidateVoters := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(2)))
// retByte := crypto.Keccak256(voter.Hash().Bytes(), common.BigToHash(locCandidateVoters).Bytes())
// ret := state.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BytesToHash(retByte))
// fmt.Printf("voter: %v - cap: %v\n", voter.Hex(), ret.Big().String())
// return ret.Big()
//}
//
//func GetVoters(statedb *state.StateDB, candidate common.Address) []common.Address {
// start := time.Now()
// fmt.Printf("--------GetVoters---------\n")
//
// //mapping(address => address[]) voters;
// slot := slotValidatorMapping["voters"]
// locVoters := getLocMappingAtKey(candidate.Hash(), slot)
// arrLength := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locVoters))
// fmt.Printf("Voters length: %v\n", arrLength.Hex())
// keys := []common.Hash{}
// for i := uint64(0); i < arrLength.Big().Uint64(); i++ {
// key := getLocDynamicArrAtElement(common.BigToHash(locVoters), i, 1)
// keys = append(keys, key)
// }
// rets := []common.Address{}
// for _, key := range keys {
// ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), key)
// rets = append(rets, common.HexToAddress(ret.Hex()))
// fmt.Printf("%v\n", common.HexToAddress(ret.Hex()).Hex())
// }
//
// elapsed := time.Since(start)
// fmt.Printf("Execution time: %s\n", elapsed)
// return rets
//}
//
//func GetSigners(statedb *state.StateDB, block *types.Block) []common.Address {
// methodName := "getSigners"
// fmt.Printf("---%s---\n", methodName)
// start := time.Now()
// slot := slotBlockSignerMapping["blockSigners"]
// keys := []common.Hash{}
// keyArrSlot := getLocMappingAtKey(block.Hash(), slot)
// arrSlot := statedb.GetState(common.HexToAddress(common.BlockSigners), common.BigToHash(keyArrSlot))
// arrLength := arrSlot.Big().Uint64()
// for i := uint64(0); i < arrLength; i++ {
// key := getLocDynamicArrAtElement(common.BigToHash(keyArrSlot), i, 1)
// keys = append(keys, key)
// }
// rets := []common.Address{}
// for _, key := range keys {
// ret := statedb.GetState(common.HexToAddress(common.BlockSigners), key)
// rets = append(rets, common.HexToAddress(ret.Hex()))
// fmt.Printf("%v\n", common.HexToAddress(ret.Hex()).Hex())
// }
//
// elapsed := time.Since(start)
// fmt.Printf("Execution time: %s\n", elapsed)
// return rets
//}
//
//func GetSecret(statedb *state.StateDB, address common.Address) [][32]byte {
// start := time.Now()
// fmt.Printf("--------GetSecret---------\n")
//
// slot := slotRandomizeMapping["randomSecret"]
// locSecret := getLocMappingAtKey(address.Hash(), slot)
// arrLength := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locSecret))
// fmt.Printf("Secret length: %v\n", arrLength.Hex())
// keys := []common.Hash{}
// for i := uint64(0); i < arrLength.Big().Uint64(); i++ {
// key := getLocDynamicArrAtElement(common.BigToHash(locSecret), i, 1)
// keys = append(keys, key)
// }
// rets := [][32]byte{}
// for _, key := range keys {
// ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), key)
// rets = append(rets, ret)
// fmt.Printf("ret hex: %v - ret byte: %v\n", ret.Hex(), ret.Bytes())
// }
// elapsed := time.Since(start)
//
// fmt.Printf("Execution time: %s\n", elapsed)
// return rets
//}
//
//func GetOpening(statedb *state.StateDB, address common.Address) [32]byte {
// start := time.Now()
// fmt.Printf("--------GetOpening---------\n")
//
// slot := slotRandomizeMapping["randomOpening"]
// locOpening := getLocMappingAtKey(address.Hash(), slot)
// ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locOpening))
// fmt.Printf("ret hex: %v - ret byte: %v\n", ret.Hex(), ret.Bytes())
// elapsed := time.Since(start)
// fmt.Printf("Execution time: %s\n", elapsed)
// return ret
//}
//
//
//////////////////////////////////////
///////////// Common lib /////////////
//////////////////////////////////////
//
//func getLocMappingAtKey(key common.Hash, slot uint64) *big.Int {
// slotHash := common.BigToHash(new(big.Int).SetUint64(slot))
// retByte := crypto.Keccak256(key.Bytes(), slotHash.Bytes())
// ret := new(big.Int)
// ret.SetBytes(retByte)
// return ret
//}
//
//func getLocDynamicArrAtElement(slotHash common.Hash, index uint64, elementSize uint64) common.Hash {
// slotKecBig := crypto.Keccak256Hash(slotHash.Bytes()).Big()
// //arrBig = slotKecBig + index * elementSize
// arrBig := slotKecBig.Add(slotKecBig, new(big.Int).SetUint64(index*elementSize))
// return common.BigToHash(arrBig)
//}
//
//func getLocFixedArrAtElement(slot uint64, index uint64, elementSize uint64) common.Hash {
// slotBig := new(big.Int).SetUint64(slot)
// arrBig := slotBig.Add(slotBig, new(big.Int).SetUint64(index*elementSize))
// return common.BigToHash(arrBig)
//}

567
contracts/utils.go Normal file
View file

@ -0,0 +1,567 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package contracts
import (
"bytes"
"crypto/aes"
"crypto/cipher"
cryptoRand "crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"math/big"
"math/rand"
"strconv"
"sync"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/XDPoS"
"github.com/ethereum/go-ethereum/contracts/blocksigner/contract"
randomizeContract "github.com/ethereum/go-ethereum/contracts/randomize/contract"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
const (
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
)
type rewardLog struct {
Sign uint64 `json:"sign"`
Reward *big.Int `json:"reward"`
}
var TxSignMu sync.RWMutex
// Send tx sign for block number to smart contract blockSigner.
func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, manager *accounts.Manager, block *types.Block, chainDb ethdb.Database) error {
TxSignMu.Lock()
defer TxSignMu.Unlock()
if chainConfig.XDPoS != nil {
// Find active account.
account := accounts.Account{}
var wallet accounts.Wallet
if wallets := manager.Wallets(); len(wallets) > 0 {
wallet = wallets[0]
if accts := wallets[0].Accounts(); len(accts) > 0 {
account = accts[0]
}
}
// Create and send tx to smart contract for sign validate block.
nonce := pool.State().GetNonce(account.Address)
tx := CreateTxSign(block.Number(), block.Hash(), nonce, common.HexToAddress(common.BlockSigners))
txSigned, err := wallet.SignTx(account, tx, chainConfig.ChainId)
if err != nil {
log.Error("Fail to create tx sign", "error", err)
return err
}
// Add tx signed to local tx pool.
err = pool.AddLocal(txSigned)
if err != nil {
log.Error("Fail to add tx sign to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce)
return err
}
// Create secret tx.
blockNumber := block.Number().Uint64()
checkNumber := blockNumber % chainConfig.XDPoS.Epoch
// Generate random private key and save into chaindb.
randomizeKeyName := []byte("randomizeKey")
exist, _ := chainDb.Has(randomizeKeyName)
// Set secret for randomize.
if !exist && checkNumber > 0 && common.EpocBlockSecret <= checkNumber && common.EpocBlockOpening > checkNumber {
// Only process when private key empty in state db.
// Save randomize key into state db.
randomizeKeyValue := RandStringByte(32)
tx, err := BuildTxSecretRandomize(nonce+1, common.HexToAddress(common.RandomizeSMC), chainConfig.XDPoS.Epoch, randomizeKeyValue)
if err != nil {
log.Error("Fail to get tx opening for randomize", "error", err)
return err
}
txSigned, err := wallet.SignTx(account, tx, chainConfig.ChainId)
if err != nil {
log.Error("Fail to create tx secret", "error", err)
return err
}
// Add tx signed to local tx pool.
err = pool.AddLocal(txSigned)
if err != nil {
log.Error("Fail to add tx secret to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce)
return err
}
// Put randomize key into chainDb.
chainDb.Put(randomizeKeyName, randomizeKeyValue)
}
// Set opening for randomize.
if exist && checkNumber > 0 && common.EpocBlockOpening <= checkNumber && common.EpocBlockRandomize >= checkNumber {
randomizeKeyValue, err := chainDb.Get(randomizeKeyName)
if err != nil {
log.Error("Fail to get randomize key from state db.", "error", err)
return err
}
tx, err := BuildTxOpeningRandomize(nonce+1, common.HexToAddress(common.RandomizeSMC), randomizeKeyValue)
if err != nil {
log.Error("Fail to get tx opening for randomize", "error", err)
return err
}
txSigned, err := wallet.SignTx(account, tx, chainConfig.ChainId)
if err != nil {
log.Error("Fail to create tx opening", "error", err)
return err
}
// Add tx to pool.
err = pool.AddLocal(txSigned)
if err != nil {
log.Error("Fail to add tx opening to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce)
return err
}
// Clear randomize key in state db.
chainDb.Delete(randomizeKeyName)
}
}
return nil
}
// Create tx sign.
func CreateTxSign(blockNumber *big.Int, blockHash common.Hash, nonce uint64, blockSigner common.Address) *types.Transaction {
data := common.Hex2Bytes(common.HexSignMethod)
inputData := append(data, common.LeftPadBytes(blockNumber.Bytes(), 32)...)
inputData = append(inputData, common.LeftPadBytes(blockHash.Bytes(), 32)...)
tx := types.NewTransaction(nonce, blockSigner, big.NewInt(0), 200000, big.NewInt(0), inputData)
return tx
}
// Send secret key into randomize smartcontract.
func BuildTxSecretRandomize(nonce uint64, randomizeAddr common.Address, epocNumber uint64, randomizeKey []byte) (*types.Transaction, error) {
data := common.Hex2Bytes(common.HexSetSecret)
rand.Seed(time.Now().UnixNano())
secretNumb := rand.Intn(int(epocNumber))
// Append randomize suffix in -1, 0, 1.
secrets := []int64{int64(secretNumb)}
sizeOfArray := int64(32)
// Build extra data for tx with first position is size of array byte and second position are length of array byte.
arrSizeOfSecrets := common.LeftPadBytes(new(big.Int).SetInt64(sizeOfArray).Bytes(), 32)
arrLengthOfSecrets := common.LeftPadBytes(new(big.Int).SetInt64(int64(len(secrets))).Bytes(), 32)
inputData := append(data, arrSizeOfSecrets...)
inputData = append(inputData, arrLengthOfSecrets...)
for _, secret := range secrets {
encryptSecret := Encrypt(randomizeKey, new(big.Int).SetInt64(secret).String())
inputData = append(inputData, common.LeftPadBytes([]byte(encryptSecret), int(sizeOfArray))...)
}
tx := types.NewTransaction(nonce, randomizeAddr, big.NewInt(0), 200000, big.NewInt(0), inputData)
return tx, nil
}
// Send opening to randomize SMC.
func BuildTxOpeningRandomize(nonce uint64, randomizeAddr common.Address, randomizeKey []byte) (*types.Transaction, error) {
data := common.Hex2Bytes(common.HexSetOpening)
inputData := append(data, randomizeKey...)
tx := types.NewTransaction(nonce, randomizeAddr, big.NewInt(0), 200000, big.NewInt(0), inputData)
return tx, nil
}
// Get signers signed for blockNumber from blockSigner contract.
func GetSignersFromContract(state *state.StateDB, block *types.Block) ([]common.Address, error) {
return GetSigners(state, block), nil
}
// Get signers signed for blockNumber from blockSigner contract.
func GetSignersByExecutingEVM(addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) {
blockSigner, err := contract.NewBlockSigner(addrBlockSigner, client)
if err != nil {
log.Error("Fail get instance of blockSigner", "error", err)
return nil, err
}
opts := new(bind.CallOpts)
addrs, err := blockSigner.GetSigners(opts, blockHash)
if err != nil {
log.Error("Fail get block signers", "error", err)
return nil, err
}
return addrs, nil
}
// Get random from randomize contract.
func GetRandomizeFromContract(client bind.ContractBackend, addrMasternode common.Address) (int64, error) {
randomize, err := randomizeContract.NewXDCRandomize(common.HexToAddress(common.RandomizeSMC), client)
if err != nil {
log.Error("Fail to get instance of randomize", "error", err)
}
opts := new(bind.CallOpts)
secrets, err := randomize.GetSecret(opts, addrMasternode)
if err != nil {
log.Error("Fail get secrets from randomize", "error", err)
}
opening, err := randomize.GetOpening(opts, addrMasternode)
if err != nil {
log.Error("Fail get opening from randomize", "error", err)
}
return DecryptRandomizeFromSecretsAndOpening(secrets, opening)
}
// Generate m2 listing from randomize array.
func GenM2FromRandomize(randomizes []int64, lenSigners int64) ([]int64, error) {
blockValidator := NewSlice(int64(0), lenSigners, 1)
randIndexs := make([]int64, lenSigners)
total := int64(0)
var temp int64 = 0
for _, j := range randomizes {
total += j
}
rand.Seed(total)
for i := len(blockValidator) - 1; i >= 0; i-- {
blockLength := len(blockValidator) - 1
if blockLength <= 1 {
blockLength = 1
}
randomIndex := int64(rand.Intn(blockLength))
temp = blockValidator[randomIndex]
blockValidator[randomIndex] = blockValidator[i]
blockValidator[i] = temp
blockValidator = append(blockValidator[:i], blockValidator[i+1:]...)
randIndexs[i] = temp
}
return randIndexs, nil
}
// Get validators from m2 array integer.
func BuildValidatorFromM2(listM2 []int64) []byte {
var validatorBytes []byte
for _, numberM2 := range listM2 {
// Convert number to byte.
m2Byte := common.LeftPadBytes([]byte(fmt.Sprintf("%d", numberM2)), XDPoS.M2ByteLength)
validatorBytes = append(validatorBytes, m2Byte...)
}
return validatorBytes
}
// Decode validator hex string.
func DecodeValidatorsHexData(validatorsStr string) ([]int64, error) {
validatorsByte, err := hexutil.Decode(validatorsStr)
if err != nil {
return nil, err
}
return XDPoS.ExtractValidatorsFromBytes(validatorsByte), nil
}
// Decrypt randomize from secrets and opening.
func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) (int64, error) {
var random int64
if len(secrets) > 0 {
for _, secret := range secrets {
trimSecret := bytes.TrimLeft(secret[:], "\x00")
decryptSecret := Decrypt(opening[:], string(trimSecret))
if isInt(decryptSecret) {
intNumber, err := strconv.Atoi(decryptSecret)
if err != nil {
log.Error("Can not convert string to integer", "error", err)
return -1, err
}
random = int64(intNumber)
}
}
}
return random, nil
}
// Calculate reward for reward checkpoint.
func GetRewardForCheckpoint(c *XDPoS.XDPoS, chain consensus.ChainReader, header *types.Header, rCheckpoint uint64, totalSigner *uint64) (map[common.Address]*rewardLog, error) {
// Not reward for singer of genesis block and only calculate reward at checkpoint block.
number := header.Number.Uint64()
prevCheckpoint := number - (rCheckpoint * 2)
startBlockNumber := prevCheckpoint + 1
endBlockNumber := startBlockNumber + rCheckpoint - 1
signers := make(map[common.Address]*rewardLog)
mapBlkHash := map[uint64]common.Hash{}
data := make(map[common.Hash][]common.Address)
for i := prevCheckpoint + (rCheckpoint * 2) - 1; i >= startBlockNumber; i-- {
header = chain.GetHeader(header.ParentHash, i)
mapBlkHash[i] = header.Hash()
signData, ok := c.BlockSigners.Get(header.Hash())
if !ok {
log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", i)
block := chain.GetBlock(header.Hash(), i)
txs := block.Transactions()
if !chain.Config().IsTIPSigning(header.Number) {
receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i)
signData = c.CacheData(header, txs, receipts)
} else {
signData = c.CacheSigner(header.Hash(), txs)
}
}
txs := signData.([]*types.Transaction)
for _, tx := range txs {
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
from := *tx.From()
data[blkHash] = append(data[blkHash], from)
}
}
header = chain.GetHeader(header.ParentHash, prevCheckpoint)
masternodes := XDPoS.GetMasternodesFromCheckpointHeader(header)
for i := startBlockNumber; i <= endBlockNumber; i++ {
if i%common.MergeSignRange == 0 || !chain.Config().IsTIP2019(big.NewInt(int64(i))) {
addrs := data[mapBlkHash[i]]
// Filter duplicate address.
if len(addrs) > 0 {
addrSigners := make(map[common.Address]bool)
for _, masternode := range masternodes {
for _, addr := range addrs {
if addr == masternode {
if _, ok := addrSigners[addr]; !ok {
addrSigners[addr] = true
}
break
}
}
}
for addr := range addrSigners {
_, exist := signers[addr]
if exist {
signers[addr].Sign++
} else {
signers[addr] = &rewardLog{1, new(big.Int)}
}
*totalSigner++
}
}
}
}
log.Info("Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber)
return signers, nil
}
// Calculate reward for signers.
func CalculateRewardForSigner(chainReward *big.Int, signers map[common.Address]*rewardLog, totalSigner uint64) (map[common.Address]*big.Int, error) {
resultSigners := make(map[common.Address]*big.Int)
// Add reward for signers.
if totalSigner > 0 {
for signer, rLog := range signers {
// Add reward for signer.
calcReward := new(big.Int)
calcReward.Div(chainReward, new(big.Int).SetUint64(totalSigner))
calcReward.Mul(calcReward, new(big.Int).SetUint64(rLog.Sign))
rLog.Reward = calcReward
resultSigners[signer] = calcReward
}
}
jsonSigners, err := json.Marshal(signers)
if err != nil {
log.Error("Fail to parse json signers", "error", err)
return nil, err
}
log.Info("Signers data", "signers", string(jsonSigners), "totalSigner", totalSigner, "totalReward", chainReward)
return resultSigners, nil
}
// Get candidate owner by address.
func GetCandidatesOwnerBySigner(state *state.StateDB, signerAddr common.Address) common.Address {
owner := GetCandidateOwner(state, signerAddr)
return owner
}
func CalculateRewardForHolders(foundationWalletAddr common.Address, state *state.StateDB, signer common.Address, calcReward *big.Int, blockNumber uint64) (error, map[common.Address]*big.Int) {
rewards, err := GetRewardBalancesRate(foundationWalletAddr, state, signer, calcReward, blockNumber)
if err != nil {
return err, nil
}
return nil, rewards
}
func GetRewardBalancesRate(foundationWalletAddr common.Address, state *state.StateDB, masterAddr common.Address, totalReward *big.Int, blockNumber uint64) (map[common.Address]*big.Int, error) {
owner := GetCandidatesOwnerBySigner(state, masterAddr)
balances := make(map[common.Address]*big.Int)
rewardMaster := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardMasterPercent))
rewardMaster = new(big.Int).Div(rewardMaster, new(big.Int).SetInt64(100))
balances[owner] = rewardMaster
// Get voters for masternode.
voters := GetVoters(state, masterAddr)
if len(voters) > 0 {
totalVoterReward := new(big.Int).Mul(totalReward, new(big.Int).SetUint64(common.RewardVoterPercent))
totalVoterReward = new(big.Int).Div(totalVoterReward, new(big.Int).SetUint64(100))
totalCap := new(big.Int)
// Get voters capacities.
voterCaps := make(map[common.Address]*big.Int)
for _, voteAddr := range voters {
if _, ok := voterCaps[voteAddr]; ok && common.TIP2019Block.Uint64() <= blockNumber {
continue
}
voterCap := GetVoterCap(state, masterAddr, voteAddr)
totalCap.Add(totalCap, voterCap)
voterCaps[voteAddr] = voterCap
}
if totalCap.Cmp(new(big.Int).SetInt64(0)) > 0 {
for addr, voteCap := range voterCaps {
// Only valid voter has cap > 0.
if voteCap.Cmp(new(big.Int).SetInt64(0)) > 0 {
rcap := new(big.Int).Mul(totalVoterReward, voteCap)
rcap = new(big.Int).Div(rcap, totalCap)
if balances[addr] != nil {
balances[addr].Add(balances[addr], rcap)
} else {
balances[addr] = rcap
}
}
}
}
}
foundationReward := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardFoundationPercent))
foundationReward = new(big.Int).Div(foundationReward, new(big.Int).SetInt64(100))
balances[foundationWalletAddr] = foundationReward
jsonHolders, err := json.Marshal(balances)
if err != nil {
log.Error("Fail to parse json holders", "error", err)
return nil, err
}
log.Info("Holders reward", "holders", string(jsonHolders), "master node", masterAddr.String())
return balances, nil
}
// Dynamic generate array sequence of numbers.
func NewSlice(start int64, end int64, step int64) []int64 {
s := make([]int64, end-start)
for i := range s {
s[i] = start
start += step
}
return s
}
// Shuffle array.
func Shuffle(slice []int64) []int64 {
newSlice := make([]int64, len(slice))
copy(newSlice, slice)
for i := 0; i < len(slice)-1; i++ {
rand.Seed(time.Now().UnixNano())
randIndex := rand.Intn(len(newSlice))
x := newSlice[i]
newSlice[i] = newSlice[randIndex]
newSlice[randIndex] = x
}
return newSlice
}
// encrypt string to base64 crypto using AES
func Encrypt(key []byte, text string) string {
// key := []byte(keyText)
plaintext := []byte(text)
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(cryptoRand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
// convert to base64
return base64.URLEncoding.EncodeToString(ciphertext)
}
// decrypt from base64 to decrypted string
func Decrypt(key []byte, cryptoText string) string {
ciphertext, _ := base64.URLEncoding.DecodeString(cryptoText)
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(ciphertext) < aes.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
// XORKeyStream can work in-place if the two arguments are the same.
stream.XORKeyStream(ciphertext, ciphertext)
return fmt.Sprintf("%s", ciphertext)
}
// Generate random string.
func RandStringByte(n int) []byte {
letterBytes := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"
b := make([]byte, n)
for i := range b {
rand.Seed(time.Now().UnixNano())
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return b
}
// Helper function check string is numeric.
func isInt(strNumber string) bool {
if _, err := strconv.Atoi(strNumber); err == nil {
return true
} else {
return false
}
}

211
contracts/utils_test.go Normal file
View file

@ -0,0 +1,211 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package contracts
import (
"bytes"
"context"
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/XDPoS"
"github.com/ethereum/go-ethereum/contracts/blocksigner"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"math/big"
"math/rand"
"testing"
"time"
)
var (
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
acc3Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
acc4Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee04aefe388d1e14474d32c45c72ce7b7a")
acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey)
acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey)
acc3Addr = crypto.PubkeyToAddress(acc3Key.PublicKey)
acc4Addr = crypto.PubkeyToAddress(acc4Key.PublicKey)
)
func getCommonBackend() *backends.SimulatedBackend {
genesis := core.GenesisAlloc{acc1Addr: {Balance: big.NewInt(1000000000000)}}
backend := backends.NewSimulatedBackend(genesis)
backend.Commit()
return backend
}
func TestSendTxSign(t *testing.T) {
accounts := []common.Address{acc2Addr, acc3Addr, acc4Addr}
keys := []*ecdsa.PrivateKey{acc2Key, acc3Key, acc4Key}
backend := getCommonBackend()
signer := types.HomesteadSigner{}
ctx := context.Background()
transactOpts := bind.NewKeyedTransactor(acc1Key)
blockSignerAddr, blockSigner, err := blocksigner.DeployBlockSigner(transactOpts, backend, big.NewInt(99))
if err != nil {
t.Fatalf("Can't get block signer: %v", err)
}
backend.Commit()
nonces := make(map[*ecdsa.PrivateKey]int)
oldBlocks := make(map[common.Hash]common.Address)
signTx := func(ctx context.Context, backend *backends.SimulatedBackend, signer types.HomesteadSigner, nonces map[*ecdsa.PrivateKey]int, accKey *ecdsa.PrivateKey, blockNumber *big.Int, blockHash common.Hash) *types.Transaction {
tx, _ := types.SignTx(CreateTxSign(blockNumber, blockHash, uint64(nonces[accKey]), blockSignerAddr), signer, accKey)
backend.SendTransaction(ctx, tx)
backend.Commit()
nonces[accKey]++
return tx
}
// Tx sign for signer.
signCount := int64(0)
blockHashes := make([]common.Hash, 10)
for i := int64(0); i < 10; i++ {
blockHash := randomHash()
blockHashes[i] = blockHash
randIndex := rand.Intn(len(keys))
accKey := keys[randIndex]
signTx(ctx, backend, signer, nonces, accKey, new(big.Int).SetInt64(i), blockHash)
oldBlocks[blockHash] = accounts[randIndex]
signCount++
// Tx sign for validators.
for _, key := range keys {
if key != accKey {
signTx(ctx, backend, signer, nonces, key, new(big.Int).SetInt64(i), blockHash)
signCount++
}
}
}
for _, blockHash := range blockHashes {
signers, err := blockSigner.GetSigners(blockHash)
if err != nil {
t.Fatalf("Can't get signers: %v", err)
}
if signers[0].String() != oldBlocks[blockHash].String() {
t.Errorf("Tx sign for block signer not match %v - %v", signers[0].String(), oldBlocks[blockHash].String())
}
if len(signers) != len(keys) {
t.Error("Tx sign for block validators not match")
}
}
}
// Generate random string.
func randomHash() common.Hash {
letterBytes := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"
var b common.Hash
for i := range b {
rand.Seed(time.Now().UnixNano())
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return b
}
// Unit test for get random position of masternodes.
func TestRandomMasterNode(t *testing.T) {
oldSlice := NewSlice(0, 10, 1)
newSlice := Shuffle(oldSlice)
for _, newNumber := range newSlice {
for i, oldNumber := range oldSlice {
if oldNumber == newNumber {
// Delete find element.
oldSlice = append(oldSlice[:i], oldSlice[i+1:]...)
}
}
}
if len(oldSlice) != 0 {
t.Errorf("Test generate random masternode fail %v - %v", oldSlice, newSlice)
}
}
func TestEncryptDecrypt(t *testing.T) {
//byteInteger := common.LeftPadBytes([]byte(new(big.Int).SetInt64(4).String()), 32)
randomByte := RandStringByte(32)
encrypt := Encrypt(randomByte, new(big.Int).SetInt64(4).String())
decrypt := Decrypt(randomByte, encrypt)
t.Log("Encrypt", encrypt, "Test", string(randomByte), "Decrypt", decrypt, "trim", string(bytes.TrimLeft([]byte(decrypt), "\x00")))
}
func isArrayEqual(a [][]int64, b [][]int64) bool {
if len(a) != len(b) {
return false
}
for i, vs := range a {
for j, v := range vs {
if v != b[i][j] {
return false
}
}
}
return true
}
// Unit test for
func TestGenM2FromRandomize(t *testing.T) {
var a []int64
for i := 0; i <= 10; i++ {
rand.Seed(time.Now().UTC().UnixNano())
a = append(a, int64(rand.Intn(9999)))
}
b, err := GenM2FromRandomize(a, common.MaxMasternodes)
t.Log("randomize", b, "len", len(b))
if err != nil {
t.Error("Fail to test gen m2 for randomize.", err)
}
// Test Permutation Without Fixed-point.
M1List := NewSlice(int64(0), common.MaxMasternodes, 1)
for i, m1 := range M1List {
if m1 == b[i] {
t.Errorf("Error check Permutation Without Fixed-point %v - %v - %v", i, b[i], a)
}
}
}
// Unit test for validator m2.
func TestBuildValidatorFromM2(t *testing.T) {
a := []int64{84, 58, 27, 96, 127, 60, 136, 20, 121, 31, 87, 85, 40, 120, 149, 109, 141, 145, 11, 110, 147, 35, 76, 46, 34, 108, 72, 103, 102, 12, 23, 47, 70, 86, 125, 112, 128, 13, 130, 98, 126, 62, 132, 111, 134, 6, 106, 67, 24, 91, 101, 50, 94, 43, 77, 73, 129, 71, 51, 10, 92, 29, 80, 95, 33, 100, 124, 75, 38, 133, 79, 83, 61, 36, 122, 99, 16, 28, 18, 116, 140, 97, 119, 82, 148, 48, 56, 32, 93, 107, 69, 68, 123, 81, 22, 137, 25, 115, 44, 8, 42, 131, 143, 17, 55, 89, 9, 15, 19, 59, 146, 54, 5, 30, 41, 144, 117, 1, 104, 49, 105, 45, 88, 78, 74, 135, 0, 21, 57, 3, 66, 52, 63, 138, 4, 114, 37, 118, 14, 2, 26, 7, 65, 139, 39, 64, 90, 142, 53, 113}
b := BuildValidatorFromM2(a)
c := XDPoS.ExtractValidatorsFromBytes(b)
if !isArrayEqual([][]int64{a}, [][]int64{c}) {
t.Errorf("Fail to get m2 result %v", b)
}
}
// Unit test for decode validator string data.
func TestDecodeValidatorsHexData(t *testing.T) {
a := "0x000000310000003000000032000000310000003000000032000000310000003000000032000000310000003000000031000000320000003000000031000000320000003000000031000000320000003000000030000000310000003200000030000000310000003200000030000000310000003200000030000000300000003100000032000000300000003100000032000000300000003100000032000000300000003200000030000000310000003200000030000000310000003200000030000000310000003000000030"
b, err := DecodeValidatorsHexData(a)
if err != nil {
t.Error("Fail to decode validator from hex string", err)
}
c := []int64{1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 2, 0, 1, 2, 0, 1, 2, 0, 1, 0, 0}
if !isArrayEqual([][]int64{b}, [][]int64{c}) {
t.Errorf("Fail to get m2 result %v", b)
}
t.Log("b", b)
}

View file

@ -0,0 +1,208 @@
pragma solidity ^0.4.21;
import "./libs/SafeMath.sol";
contract XDCalidator {
using SafeMath for uint256;
event Vote(address _voter, address _candidate, uint256 _cap);
event Unvote(address _voter, address _candidate, uint256 _cap);
event Propose(address _owner, address _candidate, uint256 _cap);
event Resign(address _owner, address _candidate);
event Withdraw(address _owner, uint256 _blockNumber, uint256 _cap);
struct ValidatorState {
address owner;
bool isCandidate;
uint256 cap;
mapping(address => uint256) voters;
}
struct WithdrawState {
mapping(uint256 => uint256) caps;
uint256[] blockNumbers;
}
mapping(address => WithdrawState) withdrawsState;
mapping(address => ValidatorState) validatorsState;
mapping(address => address[]) voters;
address[] public candidates;
uint256 public candidateCount = 0;
uint256 public minCandidateCap;
uint256 public minVoterCap;
uint256 public maxValidatorNumber;
uint256 public candidateWithdrawDelay;
uint256 public voterWithdrawDelay;
modifier onlyValidCandidateCap {
// anyone can deposit X XDCto become a candidate
require(msg.value >= minCandidateCap);
_;
}
modifier onlyValidVoterCap {
require(msg.value >= minVoterCap);
_;
}
modifier onlyOwner(address _candidate) {
require(validatorsState[_candidate].owner == msg.sender);
_;
}
modifier onlyCandidate(address _candidate) {
require(validatorsState[_candidate].isCandidate);
_;
}
modifier onlyValidCandidate (address _candidate) {
require(validatorsState[_candidate].isCandidate);
_;
}
modifier onlyNotCandidate (address _candidate) {
require(!validatorsState[_candidate].isCandidate);
_;
}
modifier onlyValidVote (address _candidate, uint256 _cap) {
require(validatorsState[_candidate].voters[msg.sender] >= _cap);
if (validatorsState[_candidate].owner == msg.sender) {
require(validatorsState[_candidate].voters[msg.sender].sub(_cap) >= minCandidateCap);
}
_;
}
modifier onlyValidWithdraw (uint256 _blockNumber, uint _index) {
require(_blockNumber > 0);
require(block.number >= _blockNumber);
require(withdrawsState[msg.sender].caps[_blockNumber] > 0);
require(withdrawsState[msg.sender].blockNumbers[_index] == _blockNumber);
_;
}
function XDCalidator (
address[] _candidates,
uint256[] _caps,
address _firstOwner,
uint256 _minCandidateCap,
uint256 _minVoterCap,
uint256 _maxValidatorNumber,
uint256 _candidateWithdrawDelay,
uint256 _voterWithdrawDelay
) public {
minCandidateCap = _minCandidateCap;
minVoterCap = _minVoterCap;
maxValidatorNumber = _maxValidatorNumber;
candidateWithdrawDelay = _candidateWithdrawDelay;
voterWithdrawDelay = _voterWithdrawDelay;
candidateCount = _candidates.length;
for (uint256 i = 0; i < _candidates.length; i++) {
candidates.push(_candidates[i]);
validatorsState[_candidates[i]] = ValidatorState({
owner: _firstOwner,
isCandidate: true,
cap: _caps[i]
});
voters[_candidates[i]].push(_firstOwner);
validatorsState[_candidates[i]].voters[_firstOwner] = minCandidateCap;
}
}
function propose(address _candidate) external payable onlyValidCandidateCap onlyNotCandidate(_candidate) {
uint256 cap = validatorsState[_candidate].cap.add(msg.value);
candidates.push(_candidate);
validatorsState[_candidate] = ValidatorState({
owner: msg.sender,
isCandidate: true,
cap: cap
});
validatorsState[_candidate].voters[msg.sender] = validatorsState[_candidate].voters[msg.sender].add(msg.value);
candidateCount = candidateCount.add(1);
voters[_candidate].push(msg.sender);
emit Propose(msg.sender, _candidate, msg.value);
}
function vote(address _candidate) external payable onlyValidVoterCap onlyValidCandidate(_candidate) {
validatorsState[_candidate].cap = validatorsState[_candidate].cap.add(msg.value);
if (validatorsState[_candidate].voters[msg.sender] == 0) {
voters[_candidate].push(msg.sender);
}
validatorsState[_candidate].voters[msg.sender] = validatorsState[_candidate].voters[msg.sender].add(msg.value);
emit Vote(msg.sender, _candidate, msg.value);
}
function getCandidates() public view returns(address[]) {
return candidates;
}
function getCandidateCap(address _candidate) public view returns(uint256) {
return validatorsState[_candidate].cap;
}
function getCandidateOwner(address _candidate) public view returns(address) {
return validatorsState[_candidate].owner;
}
function getVoterCap(address _candidate, address _voter) public view returns(uint256) {
return validatorsState[_candidate].voters[_voter];
}
function getVoters(address _candidate) public view returns(address[]) {
return voters[_candidate];
}
function isCandidate(address _candidate) public view returns(bool) {
return validatorsState[_candidate].isCandidate;
}
function getWithdrawBlockNumbers() public view returns(uint256[]) {
return withdrawsState[msg.sender].blockNumbers;
}
function getWithdrawCap(uint256 _blockNumber) public view returns(uint256) {
return withdrawsState[msg.sender].caps[_blockNumber];
}
function unvote(address _candidate, uint256 _cap) public onlyValidVote(_candidate, _cap) {
validatorsState[_candidate].cap = validatorsState[_candidate].cap.sub(_cap);
validatorsState[_candidate].voters[msg.sender] = validatorsState[_candidate].voters[msg.sender].sub(_cap);
// refund after delay X blocks
uint256 withdrawBlockNumber = voterWithdrawDelay.add(block.number);
withdrawsState[msg.sender].caps[withdrawBlockNumber] = withdrawsState[msg.sender].caps[withdrawBlockNumber].add(_cap);
withdrawsState[msg.sender].blockNumbers.push(withdrawBlockNumber);
emit Unvote(msg.sender, _candidate, _cap);
}
function resign(address _candidate) public onlyOwner(_candidate) onlyCandidate(_candidate) {
validatorsState[_candidate].isCandidate = false;
candidateCount = candidateCount.sub(1);
for (uint256 i = 0; i < candidates.length; i++) {
if (candidates[i] == _candidate) {
delete candidates[i];
break;
}
}
uint256 cap = validatorsState[_candidate].voters[msg.sender];
validatorsState[_candidate].cap = validatorsState[_candidate].cap.sub(cap);
validatorsState[_candidate].voters[msg.sender] = 0;
// refunding after resigning X blocks
uint256 withdrawBlockNumber = candidateWithdrawDelay.add(block.number);
withdrawsState[msg.sender].caps[withdrawBlockNumber] = withdrawsState[msg.sender].caps[withdrawBlockNumber].add(cap);
withdrawsState[msg.sender].blockNumbers.push(withdrawBlockNumber);
emit Resign(msg.sender, _candidate);
}
function withdraw(uint256 _blockNumber, uint _index) public onlyValidWithdraw(_blockNumber, _index) {
uint256 cap = withdrawsState[msg.sender].caps[_blockNumber];
delete withdrawsState[msg.sender].caps[_blockNumber];
delete withdrawsState[msg.sender].blockNumbers[_index];
msg.sender.transfer(cap);
emit Withdraw(msg.sender, _blockNumber, cap);
}
}

View file

@ -0,0 +1,47 @@
pragma solidity ^0.4.21;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,66 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package validator
import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/contracts/validator/contract"
"math/big"
)
type Validator struct {
*contract.XDCValidatorSession
contractBackend bind.ContractBackend
}
func NewValidator(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*Validator, error) {
validator, err := contract.NewXDCValidator(contractAddr, contractBackend)
if err != nil {
return nil, err
}
return &Validator{
&contract.XDCValidatorSession{
Contract: validator,
TransactOpts: *transactOpts,
},
contractBackend,
}, nil
}
func DeployValidator(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend, validatorAddress []common.Address, caps []*big.Int, ownerAddress common.Address) (common.Address, *Validator, error) {
minDeposit := new(big.Int)
minDeposit.SetString("50000000000000000000000", 10)
minVoterCap := new(big.Int)
minVoterCap.SetString("10000000000000000000", 10)
// Deposit 50K XDC
// Min Voter Cap 10 XDC
// 150 masternodes
// Candidate Delay Withdraw 30 days = 1296000 blocks
// Voter Delay Withdraw 2 days = 86400 blocks
validatorAddr, _, _, err := contract.DeployXDCValidator(transactOpts, contractBackend, validatorAddress, caps, ownerAddress, minDeposit, minVoterCap, big.NewInt(150), big.NewInt(1296000), big.NewInt(86400))
if err != nil {
return validatorAddr, nil, err
}
validator, err := NewValidator(transactOpts, validatorAddr, contractBackend)
if err != nil {
return validatorAddr, nil, err
}
return validatorAddr, validator, nil
}

View file

@ -0,0 +1,251 @@
// Copyright (c) 2018 XDCchain
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
package validator
import (
"context"
"encoding/json"
"math/big"
"math/rand"
"testing"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
contractValidator "github.com/ethereum/go-ethereum/contracts/validator/contract"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
)
var (
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr = crypto.PubkeyToAddress(key.PublicKey)
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
acc3Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
acc4Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee04aefe388d1e14474d32c45c72ce7b7a")
acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey)
acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey)
acc3Addr = crypto.PubkeyToAddress(acc3Key.PublicKey)
acc4Addr = crypto.PubkeyToAddress(acc4Key.PublicKey)
)
func TestValidator(t *testing.T) {
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}})
transactOpts := bind.NewKeyedTransactor(key)
validatorCap := new(big.Int)
validatorCap.SetString("50000000000000000000000", 10)
validatorAddress, validator, err := DeployValidator(transactOpts, contractBackend, []common.Address{addr}, []*big.Int{validatorCap}, addr)
if err != nil {
t.Fatalf("can't deploy root registry: %v", err)
}
contractBackend.Commit()
d := time.Now().Add(1000 * time.Millisecond)
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
code, _ := contractBackend.CodeAt(ctx, validatorAddress, nil)
t.Log("contract code", common.ToHex(code))
f := func(key, val common.Hash) bool {
t.Log(key.Hex(), val.Hex())
return true
}
contractBackend.ForEachStorageAt(ctx, validatorAddress, nil, f)
candidates, err := validator.GetCandidates()
if err != nil {
t.Fatalf("can't get candidates: %v", err)
}
for _, it := range candidates {
cap, _ := validator.GetCandidateCap(it)
t.Log("candidate", it.String(), "cap", cap)
owner, _ := validator.GetCandidateOwner(it)
t.Log("candidate", it.String(), "validator owner", owner.String())
}
contractBackend.Commit()
}
func TestRewardBalance(t *testing.T) {
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{
acc1Addr: {Balance: new(big.Int).SetUint64(10000000)},
acc2Addr: {Balance: new(big.Int).SetUint64(10000000)},
acc4Addr: {Balance: new(big.Int).SetUint64(10000000)},
})
acc1Opts := bind.NewKeyedTransactor(acc1Key)
acc2Opts := bind.NewKeyedTransactor(acc2Key)
accounts := []*bind.TransactOpts{acc1Opts, acc2Opts}
transactOpts := bind.NewKeyedTransactor(acc1Key)
// validatorAddr, _, baseValidator, err := contract.DeployXDCValidator(transactOpts, contractBackend, big.NewInt(50000), big.NewInt(99), big.NewInt(100), big.NewInt(100))
validatorCap := new(big.Int)
validatorCap.SetString("50000000000000000000000", 10)
validatorAddr, _, baseValidator, err := contractValidator.DeployXDCValidator(
transactOpts,
contractBackend,
[]common.Address{addr},
[]*big.Int{validatorCap},
addr,
big.NewInt(50000),
big.NewInt(1),
big.NewInt(99),
big.NewInt(100),
big.NewInt(100),
)
if err != nil {
t.Fatalf("can't deploy root registry: %v", err)
}
contractBackend.Commit()
// Propose master node acc3Addr.
opts := bind.NewKeyedTransactor(acc4Key)
opts.Value = new(big.Int).SetUint64(50000)
acc4Validator, _ := NewValidator(opts, validatorAddr, contractBackend)
acc4Validator.Propose(acc3Addr)
contractBackend.Commit()
totalVote := 0
type logCap struct {
Addr string
Balance int
}
logCaps := make(map[int]*logCap)
for i := 0; i <= 10; i++ {
rand.Seed(time.Now().UTC().UnixNano())
randIndex := rand.Intn(len(accounts))
randCap := rand.Intn(10) * 1000
if randCap <= 0 {
randCap = 1000
}
totalVote += randCap
accounts[randIndex].Value = new(big.Int).SetInt64(int64(randCap))
validator, err := NewValidator(accounts[randIndex], validatorAddr, contractBackend)
if err != nil {
t.Fatalf("can't get current validator: %v", err)
}
validator.Vote(acc3Addr)
contractBackend.Commit()
logCaps[i] = &logCap{accounts[randIndex].From.String(), randCap}
}
foundationAddr := common.HexToAddress(common.FoudationAddr)
totalReward := new(big.Int).SetInt64(15 * 1000)
rewards, err := GetRewardBalancesRate(foundationAddr, acc3Addr, totalReward, baseValidator)
if err != nil {
t.Error("Fail to get reward balances rate.", err)
}
afterReward := new(big.Int)
for _, value := range rewards {
afterReward = new(big.Int).Add(afterReward, value)
}
if totalReward.Int64()+5 < afterReward.Int64() || totalReward.Int64()-5 > afterReward.Int64() {
callOpts := new(bind.CallOpts)
voters, err := baseValidator.GetVoters(callOpts, acc3Addr)
if err != nil {
t.Fatal("Can not get voters in validator contract.", err)
}
for addr, capacity := range logCaps {
t.Errorf("from %v - %v", addr, capacity)
}
for _, voter := range voters {
voteCap, _ := baseValidator.GetVoterCap(callOpts, acc3Addr, voter)
t.Errorf("vote %v - %v", voter.String(), voteCap)
}
for addr, value := range rewards {
t.Errorf("reaward %v - %v", addr.String(), value)
}
t.Errorf("reward total %v - %v", totalReward, afterReward)
}
}
func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.XDCValidator) (map[common.Address]*big.Int, error) {
owner := GetCandidatesOwnerBySigner(validator, masterAddr)
balances := make(map[common.Address]*big.Int)
rewardMaster := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardMasterPercent))
rewardMaster = new(big.Int).Div(rewardMaster, new(big.Int).SetInt64(100))
balances[owner] = rewardMaster
// Get voters for masternode.
opts := new(bind.CallOpts)
voters, err := validator.GetVoters(opts, masterAddr)
if err != nil {
log.Crit("Fail to get voters", "error", err)
return nil, err
}
if len(voters) > 0 {
totalVoterReward := new(big.Int).Mul(totalReward, new(big.Int).SetUint64(common.RewardVoterPercent))
totalVoterReward = new(big.Int).Div(totalVoterReward, new(big.Int).SetUint64(100))
totalCap := new(big.Int)
// Get voters capacities.
voterCaps := make(map[common.Address]*big.Int)
for _, voteAddr := range voters {
var voterCap *big.Int
voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr)
if err != nil {
log.Crit("Fail to get vote capacity", "error", err)
}
totalCap.Add(totalCap, voterCap)
voterCaps[voteAddr] = voterCap
}
if totalCap.Cmp(new(big.Int).SetInt64(0)) > 0 {
for addr, voteCap := range voterCaps {
// Only valid voter has cap > 0.
if voteCap.Cmp(new(big.Int).SetInt64(0)) > 0 {
rcap := new(big.Int).Mul(totalVoterReward, voteCap)
rcap = new(big.Int).Div(rcap, totalCap)
if balances[addr] != nil {
balances[addr].Add(balances[addr], rcap)
} else {
balances[addr] = rcap
}
}
}
}
}
foudationReward := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardFoundationPercent))
foudationReward = new(big.Int).Div(foudationReward, new(big.Int).SetInt64(100))
balances[foudationWalletAddr] = foudationReward
jsonHolders, err := json.Marshal(balances)
if err != nil {
log.Error("Fail to parse json holders", "error", err)
return nil, err
}
log.Info("Holders reward", "holders", string(jsonHolders), "master node", masterAddr.String())
return balances, nil
}
func GetCandidatesOwnerBySigner(validator *contractValidator.XDCValidator, signerAddr common.Address) common.Address {
owner := signerAddr
opts := new(bind.CallOpts)
owner, err := validator.GetCandidateOwner(opts, signerAddr)
if err != nil {
log.Error("Fail get candidate owner", "error", err)
return owner
}
return owner
}

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