mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 06:06:44 +00:00
use go-ethereum for better forked-bor release
This commit is contained in:
parent
adf77d28e8
commit
1e56a697c0
826 changed files with 30446 additions and 26517 deletions
57
COPYING
57
COPYING
|
|
@ -1,7 +1,7 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
Copyright (C) 2014 The go-ethereum Authors.
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
@ -617,3 +617,58 @@ reviewing courts shall apply local law that most closely approximates
|
||||||
an absolute waiver of all civil liability in connection with the
|
an absolute waiver of all civil liability in connection with the
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
copy of the Program in return for a fee.
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program 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.
|
||||||
|
|
||||||
|
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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
|
|
|
||||||
13
Dockerfile
13
Dockerfile
|
|
@ -1,15 +1,16 @@
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.14-alpine as builder
|
FROM golang:1.15-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache make gcc musl-dev linux-headers git
|
RUN apk add --no-cache make gcc musl-dev linux-headers git
|
||||||
|
|
||||||
ADD . /bor
|
ADD . /go-ethereum
|
||||||
RUN cd /bor && make bor
|
RUN cd /go-ethereum && make geth
|
||||||
|
|
||||||
# Pull Bor into a second stage deploy alpine container
|
# Pull Geth into a second stage deploy alpine container
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates
|
RUN apk add --no-cache ca-certificates
|
||||||
COPY --from=builder /bor/build/bin/bor /usr/local/bin/
|
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
|
||||||
|
|
||||||
EXPOSE 8545 8546 8547 30303 30303/udp
|
EXPOSE 8545 8546 30303 30303/udp
|
||||||
|
ENTRYPOINT ["geth"]
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.14-alpine as builder
|
FROM golang:1.15-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache make gcc musl-dev linux-headers git
|
RUN apk add --no-cache make gcc musl-dev linux-headers git
|
||||||
|
|
||||||
ADD . /bor
|
ADD . /go-ethereum
|
||||||
RUN cd /bor && make all
|
RUN cd /go-ethereum && make all
|
||||||
|
|
||||||
# Pull all binaries into a second stage deploy alpine container
|
# Pull all binaries into a second stage deploy alpine container
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates
|
RUN apk add --no-cache ca-certificates
|
||||||
COPY --from=builder /bor/build/bin/* /usr/local/bin/
|
COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/
|
||||||
|
|
||||||
EXPOSE 8545 8546 8547 30303 30303/udp
|
EXPOSE 8545 8546 30303 30303/udp
|
||||||
|
|
|
||||||
141
Makefile
141
Makefile
|
|
@ -2,43 +2,38 @@
|
||||||
# with Go source code. If you know what GOPATH is then you probably
|
# with Go source code. If you know what GOPATH is then you probably
|
||||||
# don't need to bother with make.
|
# don't need to bother with make.
|
||||||
|
|
||||||
.PHONY: bor android ios bor-cross evm all test clean
|
.PHONY: geth android ios geth-cross evm all test clean
|
||||||
.PHONY: bor-linux bor-linux-386 bor-linux-amd64 bor-linux-mips64 bor-linux-mips64le
|
.PHONY: geth-linux geth-linux-386 geth-linux-amd64 geth-linux-mips64 geth-linux-mips64le
|
||||||
.PHONY: bor-linux-arm bor-linux-arm-5 bor-linux-arm-6 bor-linux-arm-7 bor-linux-arm64
|
.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
|
||||||
.PHONY: bor-darwin bor-darwin-386 bor-darwin-amd64
|
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
|
||||||
.PHONY: bor-windows bor-windows-386 bor-windows-amd64
|
.PHONY: geth-windows geth-windows-386 geth-windows-amd64
|
||||||
|
|
||||||
GOBIN = ./build/bin
|
GOBIN = ./build/bin
|
||||||
GO ?= latest
|
GO ?= latest
|
||||||
GORUN = go run
|
GORUN = env GO111MODULE=on go run
|
||||||
GOPATH = $(shell go env GOPATH)
|
|
||||||
|
|
||||||
bor:
|
geth:
|
||||||
$(GORUN) build/ci.go install ./cmd/bor
|
$(GORUN) build/ci.go install ./cmd/geth
|
||||||
mkdir -p $(GOPATH)/bin/
|
@echo "Done building."
|
||||||
cp $(GOBIN)/bor $(GOPATH)/bin/
|
@echo "Run \"$(GOBIN)/geth\" to launch geth."
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(GORUN) build/ci.go install
|
$(GORUN) build/ci.go install
|
||||||
mkdir -p $(GOPATH)/bin/
|
|
||||||
cp $(GOBIN)/* $(GOPATH)/bin/
|
|
||||||
|
|
||||||
android:
|
android:
|
||||||
$(GORUN) build/ci.go aar --local
|
$(GORUN) build/ci.go aar --local
|
||||||
@echo "Done building."
|
@echo "Done building."
|
||||||
@echo "Import \"$(GOBIN)/bor.aar\" to use the library."
|
@echo "Import \"$(GOBIN)/geth.aar\" to use the library."
|
||||||
|
@echo "Import \"$(GOBIN)/geth-sources.jar\" to add javadocs"
|
||||||
|
@echo "For more info see https://stackoverflow.com/questions/20994336/android-studio-how-to-attach-javadoc"
|
||||||
|
|
||||||
ios:
|
ios:
|
||||||
$(GORUN) build/ci.go xcode --local
|
$(GORUN) build/ci.go xcode --local
|
||||||
@echo "Done building."
|
@echo "Done building."
|
||||||
@echo "Import \"$(GOBIN)/bor.framework\" to use the library."
|
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
|
||||||
|
|
||||||
test: bor
|
test: all
|
||||||
go test github.com/maticnetwork/bor/consensus/bor
|
$(GORUN) build/ci.go test
|
||||||
go test github.com/maticnetwork/bor/tests/bor
|
|
||||||
|
|
||||||
# test: all
|
|
||||||
# $(GORUN) build/ci.go test
|
|
||||||
|
|
||||||
lint: ## Run linters.
|
lint: ## Run linters.
|
||||||
$(GORUN) build/ci.go lint
|
$(GORUN) build/ci.go lint
|
||||||
|
|
@ -62,92 +57,92 @@ devtools:
|
||||||
|
|
||||||
# Cross Compilation Targets (xgo)
|
# Cross Compilation Targets (xgo)
|
||||||
|
|
||||||
bor-cross: bor-linux bor-darwin bor-windows bor-android bor-ios
|
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
|
||||||
@echo "Full cross compilation done:"
|
@echo "Full cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-*
|
@ls -ld $(GOBIN)/geth-*
|
||||||
|
|
||||||
bor-linux: bor-linux-386 bor-linux-amd64 bor-linux-arm bor-linux-mips64 bor-linux-mips64le
|
geth-linux: geth-linux-386 geth-linux-amd64 geth-linux-arm geth-linux-mips64 geth-linux-mips64le
|
||||||
@echo "Linux cross compilation done:"
|
@echo "Linux cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-*
|
@ls -ld $(GOBIN)/geth-linux-*
|
||||||
|
|
||||||
bor-linux-386:
|
geth-linux-386:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/386 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/386 -v ./cmd/geth
|
||||||
@echo "Linux 386 cross compilation done:"
|
@echo "Linux 386 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep 386
|
@ls -ld $(GOBIN)/geth-linux-* | grep 386
|
||||||
|
|
||||||
bor-linux-amd64:
|
geth-linux-amd64:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/amd64 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/amd64 -v ./cmd/geth
|
||||||
@echo "Linux amd64 cross compilation done:"
|
@echo "Linux amd64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep amd64
|
@ls -ld $(GOBIN)/geth-linux-* | grep amd64
|
||||||
|
|
||||||
bor-linux-arm: bor-linux-arm-5 bor-linux-arm-6 bor-linux-arm-7 bor-linux-arm64
|
geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
|
||||||
@echo "Linux ARM cross compilation done:"
|
@echo "Linux ARM cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep arm
|
@ls -ld $(GOBIN)/geth-linux-* | grep arm
|
||||||
|
|
||||||
bor-linux-arm-5:
|
geth-linux-arm-5:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/arm-5 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/arm-5 -v ./cmd/geth
|
||||||
@echo "Linux ARMv5 cross compilation done:"
|
@echo "Linux ARMv5 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep arm-5
|
@ls -ld $(GOBIN)/geth-linux-* | grep arm-5
|
||||||
|
|
||||||
bor-linux-arm-6:
|
geth-linux-arm-6:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/arm-6 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/arm-6 -v ./cmd/geth
|
||||||
@echo "Linux ARMv6 cross compilation done:"
|
@echo "Linux ARMv6 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep arm-6
|
@ls -ld $(GOBIN)/geth-linux-* | grep arm-6
|
||||||
|
|
||||||
bor-linux-arm-7:
|
geth-linux-arm-7:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/arm-7 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/arm-7 -v ./cmd/geth
|
||||||
@echo "Linux ARMv7 cross compilation done:"
|
@echo "Linux ARMv7 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep arm-7
|
@ls -ld $(GOBIN)/geth-linux-* | grep arm-7
|
||||||
|
|
||||||
bor-linux-arm64:
|
geth-linux-arm64:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/arm64 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/arm64 -v ./cmd/geth
|
||||||
@echo "Linux ARM64 cross compilation done:"
|
@echo "Linux ARM64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep arm64
|
@ls -ld $(GOBIN)/geth-linux-* | grep arm64
|
||||||
|
|
||||||
bor-linux-mips:
|
geth-linux-mips:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/mips --ldflags '-extldflags "-static"' -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/mips --ldflags '-extldflags "-static"' -v ./cmd/geth
|
||||||
@echo "Linux MIPS cross compilation done:"
|
@echo "Linux MIPS cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep mips
|
@ls -ld $(GOBIN)/geth-linux-* | grep mips
|
||||||
|
|
||||||
bor-linux-mipsle:
|
geth-linux-mipsle:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/mipsle --ldflags '-extldflags "-static"' -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/mipsle --ldflags '-extldflags "-static"' -v ./cmd/geth
|
||||||
@echo "Linux MIPSle cross compilation done:"
|
@echo "Linux MIPSle cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep mipsle
|
@ls -ld $(GOBIN)/geth-linux-* | grep mipsle
|
||||||
|
|
||||||
bor-linux-mips64:
|
geth-linux-mips64:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/mips64 --ldflags '-extldflags "-static"' -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/mips64 --ldflags '-extldflags "-static"' -v ./cmd/geth
|
||||||
@echo "Linux MIPS64 cross compilation done:"
|
@echo "Linux MIPS64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep mips64
|
@ls -ld $(GOBIN)/geth-linux-* | grep mips64
|
||||||
|
|
||||||
bor-linux-mips64le:
|
geth-linux-mips64le:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/mips64le --ldflags '-extldflags "-static"' -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=linux/mips64le --ldflags '-extldflags "-static"' -v ./cmd/geth
|
||||||
@echo "Linux MIPS64le cross compilation done:"
|
@echo "Linux MIPS64le cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-linux-* | grep mips64le
|
@ls -ld $(GOBIN)/geth-linux-* | grep mips64le
|
||||||
|
|
||||||
bor-darwin: bor-darwin-386 bor-darwin-amd64
|
geth-darwin: geth-darwin-386 geth-darwin-amd64
|
||||||
@echo "Darwin cross compilation done:"
|
@echo "Darwin cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-darwin-*
|
@ls -ld $(GOBIN)/geth-darwin-*
|
||||||
|
|
||||||
bor-darwin-386:
|
geth-darwin-386:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=darwin/386 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=darwin/386 -v ./cmd/geth
|
||||||
@echo "Darwin 386 cross compilation done:"
|
@echo "Darwin 386 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-darwin-* | grep 386
|
@ls -ld $(GOBIN)/geth-darwin-* | grep 386
|
||||||
|
|
||||||
bor-darwin-amd64:
|
geth-darwin-amd64:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=darwin/amd64 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=darwin/amd64 -v ./cmd/geth
|
||||||
@echo "Darwin amd64 cross compilation done:"
|
@echo "Darwin amd64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-darwin-* | grep amd64
|
@ls -ld $(GOBIN)/geth-darwin-* | grep amd64
|
||||||
|
|
||||||
bor-windows: bor-windows-386 bor-windows-amd64
|
geth-windows: geth-windows-386 geth-windows-amd64
|
||||||
@echo "Windows cross compilation done:"
|
@echo "Windows cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-windows-*
|
@ls -ld $(GOBIN)/geth-windows-*
|
||||||
|
|
||||||
bor-windows-386:
|
geth-windows-386:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=windows/386 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=windows/386 -v ./cmd/geth
|
||||||
@echo "Windows 386 cross compilation done:"
|
@echo "Windows 386 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-windows-* | grep 386
|
@ls -ld $(GOBIN)/geth-windows-* | grep 386
|
||||||
|
|
||||||
bor-windows-amd64:
|
geth-windows-amd64:
|
||||||
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=windows/amd64 -v ./cmd/bor
|
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=windows/amd64 -v ./cmd/geth
|
||||||
@echo "Windows amd64 cross compilation done:"
|
@echo "Windows amd64 cross compilation done:"
|
||||||
@ls -ld $(GOBIN)/bor-windows-* | grep amd64
|
@ls -ld $(GOBIN)/geth-windows-* | grep amd64
|
||||||
|
|
|
||||||
339
README.md
339
README.md
|
|
@ -1,14 +1,26 @@
|
||||||
## Bor
|
## Go Ethereum
|
||||||
|
|
||||||
Official Golang implementation of the Matic protocol (fork of Go Ethereum - https://github.com/ethereum/go-ethereum)
|
Official Golang implementation of the Ethereum protocol.
|
||||||
|
|
||||||
|
[](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc)
|
||||||
|
[](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
|
||||||
|
[](https://travis-ci.org/ethereum/go-ethereum)
|
||||||
|
[](https://discord.gg/nthXNEv)
|
||||||
|
|
||||||
|
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
|
## Building the source
|
||||||
|
|
||||||
Building `bor` requires both a Go (version 1.13 or later) and a C compiler. You can install
|
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.13 or later) and a C compiler. You can install
|
||||||
them using your favourite package manager. Once the dependencies are installed, run
|
them using your favourite package manager. Once the dependencies are installed, run
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
make bor
|
make geth
|
||||||
```
|
```
|
||||||
|
|
||||||
or, to build the full suite of utilities:
|
or, to build the full suite of utilities:
|
||||||
|
|
@ -17,6 +29,325 @@ or, to build the full suite of utilities:
|
||||||
make all
|
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 run`). |
|
||||||
|
| `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`). |
|
||||||
|
| `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:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ 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 tool is optional and if you leave it out you can always attach to an already running
|
||||||
|
`geth` instance with `geth attach`.
|
||||||
|
|
||||||
|
### A Full node on the Görli 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.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ geth --goerli console
|
||||||
|
```
|
||||||
|
|
||||||
|
The `console` subcommand has 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 here.
|
||||||
|
|
||||||
|
Specifying the `--goerli` flag, however, will reconfigure your `geth` instance a bit:
|
||||||
|
|
||||||
|
* Instead of connecting the main Ethereum network, the client will connect to the Görli
|
||||||
|
test network, which uses different P2P bootnodes, different network IDs and genesis
|
||||||
|
states.
|
||||||
|
* Instead of using the default data directory (`~/.ethereum` on Linux for example), `geth`
|
||||||
|
will nest itself one level deeper into a `goerli` subfolder (`~/.ethereum/goerli` 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>/goerli/geth.ipc`. Windows users are not affected by
|
||||||
|
this.
|
||||||
|
|
||||||
|
*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
|
||||||
|
|
||||||
|
Go Ethereum also supports connecting to the older proof-of-authority based test network
|
||||||
|
called [*Rinkeby*](https://www.rinkeby.io) which is operated by members of the community.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ geth --rinkeby console
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full node on the Ropsten test network
|
||||||
|
|
||||||
|
In addition to Görli and Rinkeby, Geth also supports the ancient Ropsten testnet. The
|
||||||
|
Ropsten test network is 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.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ geth --ropsten console
|
||||||
|
```
|
||||||
|
|
||||||
|
*Note: Older Geth configurations store the Ropsten database in the `testnet` subdirectory.*
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
As an alternative to passing the numerous flags to the `geth` binary, you can also pass a
|
||||||
|
configuration file via:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ 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:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ 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:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
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 `--http.addr 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.
|
||||||
|
|
||||||
|
### Programmatically 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:
|
||||||
|
|
||||||
|
* `--http` Enable the HTTP-RPC server
|
||||||
|
* `--http.addr` HTTP-RPC server listening interface (default: `localhost`)
|
||||||
|
* `--http.port` HTTP-RPC server listening port (default: `8545`)
|
||||||
|
* `--http.api` API's offered over the HTTP-RPC interface (default: `eth,net,web3`)
|
||||||
|
* `--http.corsdomain` Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
||||||
|
* `--ws` Enable the WS-RPC server
|
||||||
|
* `--ws.addr` WS-RPC server listening interface (default: `localhost`)
|
||||||
|
* `--ws.port` WS-RPC server listening port (default: `8546`)
|
||||||
|
* `--ws.api` API's offered over the WS-RPC interface (default: `eth,net,web3`)
|
||||||
|
* `--ws.origins` 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](https://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 web servers, so malicious web pages 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": <arbitrary positive integer>,
|
||||||
|
"homesteadBlock": 0,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip155Block": 0,
|
||||||
|
"eip158Block": 0,
|
||||||
|
"byzantiumBlock": 0,
|
||||||
|
"constantinopleBlock": 0,
|
||||||
|
"petersburgBlock": 0,
|
||||||
|
"istanbulBlock": 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, create
|
||||||
|
the accounts and populate the `alloc` field with their addresses.
|
||||||
|
|
||||||
|
```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:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ 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:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ 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.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ 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 [ethminer](https://github.com/ethereum-mining/ethminer) 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:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ geth <usual-flags> --mine --miner.threads=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
|
## License
|
||||||
|
|
||||||
The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the
|
The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@ Please see Releases. We recommend to use the most recent released version.
|
||||||
|
|
||||||
## Audit reports
|
## Audit reports
|
||||||
|
|
||||||
Audit reports are published in the `docs` folder: https://github.com/maticnetwork/bor/tree/master/docs/audits
|
Audit reports are published in the `docs` folder: https://github.com/ethereum/go-ethereum/tree/master/docs/audits
|
||||||
|
|
||||||
|
|
||||||
| Scope | Date | Report Link |
|
| Scope | Date | Report Link |
|
||||||
| ------- | ------- | ----------- |
|
| ------- | ------- | ----------- |
|
||||||
| `geth` | 20170425 | [pdf](https://github.com/maticnetwork/bor/blob/master/docs/audits/2017-04-25_Geth-audit_Truesec.pdf) |
|
| `geth` | 20170425 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2017-04-25_Geth-audit_Truesec.pdf) |
|
||||||
| `clef` | 20180914 | [pdf](https://github.com/maticnetwork/bor/blob/master/docs/audits/2018-09-14_Clef-audit_NCC.pdf) |
|
| `clef` | 20180914 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2018-09-14_Clef-audit_NCC.pdf) |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The ABI holds information about a contract's context and available
|
// The ABI holds information about a contract's context and available
|
||||||
|
|
@ -80,39 +80,59 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
|
||||||
return append(method.ID, arguments...), nil
|
return append(method.ID, arguments...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpack output in v according to the abi specification
|
func (abi ABI) getArguments(name string, data []byte) (Arguments, error) {
|
||||||
func (abi ABI) Unpack(v interface{}, name string, data []byte) (err error) {
|
|
||||||
// since there can't be naming collisions with contracts and events,
|
// since there can't be naming collisions with contracts and events,
|
||||||
// we need to decide whether we're calling a method or an event
|
// we need to decide whether we're calling a method or an event
|
||||||
|
var args Arguments
|
||||||
if method, ok := abi.Methods[name]; ok {
|
if method, ok := abi.Methods[name]; ok {
|
||||||
if len(data)%32 != 0 {
|
if len(data)%32 != 0 {
|
||||||
return fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(data), data)
|
return nil, fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(data), data)
|
||||||
}
|
}
|
||||||
return method.Outputs.Unpack(v, data)
|
args = method.Outputs
|
||||||
}
|
}
|
||||||
if event, ok := abi.Events[name]; ok {
|
if event, ok := abi.Events[name]; ok {
|
||||||
return event.Inputs.Unpack(v, data)
|
args = event.Inputs
|
||||||
}
|
}
|
||||||
return fmt.Errorf("abi: could not locate named method or event")
|
if args == nil {
|
||||||
|
return nil, errors.New("abi: could not locate named method or event")
|
||||||
|
}
|
||||||
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnpackIntoMap unpacks a log into the provided map[string]interface{}
|
// Unpack unpacks the output according to the abi specification.
|
||||||
|
func (abi ABI) Unpack(name string, data []byte) ([]interface{}, error) {
|
||||||
|
args, err := abi.getArguments(name, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return args.Unpack(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnpackIntoInterface unpacks the output in v according to the abi specification.
|
||||||
|
// It performs an additional copy. Please only use, if you want to unpack into a
|
||||||
|
// structure that does not strictly conform to the abi structure (e.g. has additional arguments)
|
||||||
|
func (abi ABI) UnpackIntoInterface(v interface{}, name string, data []byte) error {
|
||||||
|
args, err := abi.getArguments(name, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
unpacked, err := args.Unpack(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return args.Copy(v, unpacked)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnpackIntoMap unpacks a log into the provided map[string]interface{}.
|
||||||
func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) (err error) {
|
func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) (err error) {
|
||||||
// since there can't be naming collisions with contracts and events,
|
args, err := abi.getArguments(name, data)
|
||||||
// we need to decide whether we're calling a method or an event
|
if err != nil {
|
||||||
if method, ok := abi.Methods[name]; ok {
|
return err
|
||||||
if len(data)%32 != 0 {
|
|
||||||
return fmt.Errorf("abi: improperly formatted output")
|
|
||||||
}
|
|
||||||
return method.Outputs.UnpackIntoMap(v, data)
|
|
||||||
}
|
}
|
||||||
if event, ok := abi.Events[name]; ok {
|
return args.UnpackIntoMap(v, data)
|
||||||
return event.Inputs.UnpackIntoMap(v, data)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("abi: could not locate named method or event")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler interface
|
// UnmarshalJSON implements json.Unmarshaler interface.
|
||||||
func (abi *ABI) UnmarshalJSON(data []byte) error {
|
func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||||
var fields []struct {
|
var fields []struct {
|
||||||
Type string
|
Type string
|
||||||
|
|
@ -201,8 +221,8 @@ func (abi *ABI) overloadedEventName(rawName string) string {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
// MethodById looks up a method by the 4-byte id
|
// MethodById looks up a method by the 4-byte id,
|
||||||
// returns nil if none found
|
// returns nil if none found.
|
||||||
func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
|
func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
|
||||||
if len(sigdata) < 4 {
|
if len(sigdata) < 4 {
|
||||||
return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata))
|
return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata))
|
||||||
|
|
@ -250,10 +270,10 @@ func UnpackRevert(data []byte) (string, error) {
|
||||||
if !bytes.Equal(data[:4], revertSelector) {
|
if !bytes.Equal(data[:4], revertSelector) {
|
||||||
return "", errors.New("invalid data for unpacking")
|
return "", errors.New("invalid data for unpacking")
|
||||||
}
|
}
|
||||||
var reason string
|
|
||||||
typ, _ := NewType("string", "", nil)
|
typ, _ := NewType("string", "", nil)
|
||||||
if err := (Arguments{{Type: typ}}).Unpack(&reason, data[4:]); err != nil {
|
unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
|
||||||
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return reason, nil
|
return unpacked[0].(string), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,14 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const jsondata = `
|
const jsondata = `
|
||||||
[
|
[
|
||||||
{ "type" : "function", "name" : "", "stateMutability" : "view" },
|
{ "type" : "function", "name" : ""},
|
||||||
{ "type" : "function", "name" : "balance", "stateMutability" : "view" },
|
{ "type" : "function", "name" : "balance", "stateMutability" : "view" },
|
||||||
{ "type" : "function", "name" : "send", "inputs" : [ { "name" : "amount", "type" : "uint256" } ] },
|
{ "type" : "function", "name" : "send", "inputs" : [ { "name" : "amount", "type" : "uint256" } ] },
|
||||||
{ "type" : "function", "name" : "test", "inputs" : [ { "name" : "number", "type" : "uint32" } ] },
|
{ "type" : "function", "name" : "test", "inputs" : [ { "name" : "number", "type" : "uint32" } ] },
|
||||||
|
|
@ -88,7 +88,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var methods = map[string]Method{
|
var methods = map[string]Method{
|
||||||
"": NewMethod("", "", Function, "view", false, false, nil, nil),
|
"": NewMethod("", "", Function, "", false, false, nil, nil),
|
||||||
"balance": NewMethod("balance", "balance", Function, "view", false, false, nil, nil),
|
"balance": NewMethod("balance", "balance", Function, "view", false, false, nil, nil),
|
||||||
"send": NewMethod("send", "send", Function, "", false, false, []Argument{{"amount", Uint256, false}}, nil),
|
"send": NewMethod("send", "send", Function, "", false, false, []Argument{{"amount", Uint256, false}}, nil),
|
||||||
"test": NewMethod("test", "test", Function, "", false, false, []Argument{{"number", Uint32, false}}, nil),
|
"test": NewMethod("test", "test", Function, "", false, false, []Argument{{"number", Uint32, false}}, nil),
|
||||||
|
|
@ -181,18 +181,15 @@ func TestConstructor(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
v := struct {
|
unpacked, err := abi.Constructor.Inputs.Unpack(packed)
|
||||||
A *big.Int
|
if err != nil {
|
||||||
B *big.Int
|
|
||||||
}{new(big.Int), new(big.Int)}
|
|
||||||
//abi.Unpack(&v, "", packed)
|
|
||||||
if err := abi.Constructor.Inputs.Unpack(&v, packed); err != nil {
|
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(v.A, big.NewInt(1)) {
|
|
||||||
|
if !reflect.DeepEqual(unpacked[0], big.NewInt(1)) {
|
||||||
t.Error("Unable to pack/unpack from constructor")
|
t.Error("Unable to pack/unpack from constructor")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(v.B, big.NewInt(2)) {
|
if !reflect.DeepEqual(unpacked[1], big.NewInt(2)) {
|
||||||
t.Error("Unable to pack/unpack from constructor")
|
t.Error("Unable to pack/unpack from constructor")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -743,7 +740,7 @@ func TestUnpackEvent(t *testing.T) {
|
||||||
}
|
}
|
||||||
var ev ReceivedEvent
|
var ev ReceivedEvent
|
||||||
|
|
||||||
err = abi.Unpack(&ev, "received", data)
|
err = abi.UnpackIntoInterface(&ev, "received", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -752,7 +749,7 @@ func TestUnpackEvent(t *testing.T) {
|
||||||
Sender common.Address
|
Sender common.Address
|
||||||
}
|
}
|
||||||
var receivedAddrEv ReceivedAddrEvent
|
var receivedAddrEv ReceivedAddrEvent
|
||||||
err = abi.Unpack(&receivedAddrEv, "receivedAddr", data)
|
err = abi.UnpackIntoInterface(&receivedAddrEv, "receivedAddr", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -1092,7 +1089,7 @@ func TestDoubleDuplicateEventNames(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestUnnamedEventParam checks that an event with unnamed parameters is
|
// TestUnnamedEventParam checks that an event with unnamed parameters is
|
||||||
// correctly handled
|
// correctly handled.
|
||||||
// The test runs the abi of the following contract.
|
// The test runs the abi of the following contract.
|
||||||
// contract TestEvent {
|
// contract TestEvent {
|
||||||
// event send(uint256, uint256);
|
// event send(uint256, uint256);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ type ArgumentMarshaling struct {
|
||||||
Indexed bool
|
Indexed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler interface
|
// UnmarshalJSON implements json.Unmarshaler interface.
|
||||||
func (argument *Argument) UnmarshalJSON(data []byte) error {
|
func (argument *Argument) UnmarshalJSON(data []byte) error {
|
||||||
var arg ArgumentMarshaling
|
var arg ArgumentMarshaling
|
||||||
err := json.Unmarshal(data, &arg)
|
err := json.Unmarshal(data, &arg)
|
||||||
|
|
@ -59,7 +59,7 @@ func (argument *Argument) UnmarshalJSON(data []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NonIndexed returns the arguments with indexed arguments filtered out
|
// NonIndexed returns the arguments with indexed arguments filtered out.
|
||||||
func (arguments Arguments) NonIndexed() Arguments {
|
func (arguments Arguments) NonIndexed() Arguments {
|
||||||
var ret []Argument
|
var ret []Argument
|
||||||
for _, arg := range arguments {
|
for _, arg := range arguments {
|
||||||
|
|
@ -70,37 +70,29 @@ func (arguments Arguments) NonIndexed() Arguments {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// isTuple returns true for non-atomic constructs, like (uint,uint) or uint[]
|
// isTuple returns true for non-atomic constructs, like (uint,uint) or uint[].
|
||||||
func (arguments Arguments) isTuple() bool {
|
func (arguments Arguments) isTuple() bool {
|
||||||
return len(arguments) > 1
|
return len(arguments) > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpack performs the operation hexdata -> Go format
|
// Unpack performs the operation hexdata -> Go format.
|
||||||
func (arguments Arguments) Unpack(v interface{}, data []byte) error {
|
func (arguments Arguments) Unpack(data []byte) ([]interface{}, error) {
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
if len(arguments) != 0 {
|
if len(arguments) != 0 {
|
||||||
return fmt.Errorf("abi: attempting to unmarshall an empty string while arguments are expected")
|
return nil, fmt.Errorf("abi: attempting to unmarshall an empty string while arguments are expected")
|
||||||
}
|
}
|
||||||
return nil // Nothing to unmarshal, return
|
// Nothing to unmarshal, return default variables
|
||||||
|
nonIndexedArgs := arguments.NonIndexed()
|
||||||
|
defaultVars := make([]interface{}, len(nonIndexedArgs))
|
||||||
|
for index, arg := range nonIndexedArgs {
|
||||||
|
defaultVars[index] = reflect.New(arg.Type.GetType())
|
||||||
|
}
|
||||||
|
return defaultVars, nil
|
||||||
}
|
}
|
||||||
// make sure the passed value is arguments pointer
|
return arguments.UnpackValues(data)
|
||||||
if reflect.Ptr != reflect.ValueOf(v).Kind() {
|
|
||||||
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
|
|
||||||
}
|
|
||||||
marshalledValues, err := arguments.UnpackValues(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(marshalledValues) == 0 {
|
|
||||||
return fmt.Errorf("abi: Unpack(no-values unmarshalled %T)", v)
|
|
||||||
}
|
|
||||||
if arguments.isTuple() {
|
|
||||||
return arguments.unpackTuple(v, marshalledValues)
|
|
||||||
}
|
|
||||||
return arguments.unpackAtomic(v, marshalledValues[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnpackIntoMap performs the operation hexdata -> mapping of argument name to argument value
|
// UnpackIntoMap performs the operation hexdata -> mapping of argument name to argument value.
|
||||||
func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte) error {
|
func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte) error {
|
||||||
// Make sure map is not nil
|
// Make sure map is not nil
|
||||||
if v == nil {
|
if v == nil {
|
||||||
|
|
@ -122,8 +114,26 @@ func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy performs the operation go format -> provided struct.
|
||||||
|
func (arguments Arguments) Copy(v interface{}, values []interface{}) error {
|
||||||
|
// make sure the passed value is arguments pointer
|
||||||
|
if reflect.Ptr != reflect.ValueOf(v).Kind() {
|
||||||
|
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
|
||||||
|
}
|
||||||
|
if len(values) == 0 {
|
||||||
|
if len(arguments) != 0 {
|
||||||
|
return fmt.Errorf("abi: attempting to copy no values while %d arguments are expected", len(arguments))
|
||||||
|
}
|
||||||
|
return nil // Nothing to copy, return
|
||||||
|
}
|
||||||
|
if arguments.isTuple() {
|
||||||
|
return arguments.copyTuple(v, values)
|
||||||
|
}
|
||||||
|
return arguments.copyAtomic(v, values[0])
|
||||||
|
}
|
||||||
|
|
||||||
// unpackAtomic unpacks ( hexdata -> go ) a single value
|
// unpackAtomic unpacks ( hexdata -> go ) a single value
|
||||||
func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interface{}) error {
|
func (arguments Arguments) copyAtomic(v interface{}, marshalledValues interface{}) error {
|
||||||
dst := reflect.ValueOf(v).Elem()
|
dst := reflect.ValueOf(v).Elem()
|
||||||
src := reflect.ValueOf(marshalledValues)
|
src := reflect.ValueOf(marshalledValues)
|
||||||
|
|
||||||
|
|
@ -133,8 +143,8 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interfac
|
||||||
return set(dst, src)
|
return set(dst, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
// unpackTuple unpacks ( hexdata -> go ) a batch of values.
|
// copyTuple copies a batch of values from marshalledValues to v.
|
||||||
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
|
func (arguments Arguments) copyTuple(v interface{}, marshalledValues []interface{}) error {
|
||||||
value := reflect.ValueOf(v).Elem()
|
value := reflect.ValueOf(v).Elem()
|
||||||
nonIndexedArgs := arguments.NonIndexed()
|
nonIndexedArgs := arguments.NonIndexed()
|
||||||
|
|
||||||
|
|
@ -207,13 +217,13 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
|
||||||
return retval, nil
|
return retval, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PackValues performs the operation Go format -> Hexdata
|
// PackValues performs the operation Go format -> Hexdata.
|
||||||
// It is the semantic opposite of UnpackValues
|
// It is the semantic opposite of UnpackValues.
|
||||||
func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) {
|
func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) {
|
||||||
return arguments.Pack(args...)
|
return arguments.Pack(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack performs the operation Go format -> Hexdata
|
// Pack performs the operation Go format -> Hexdata.
|
||||||
func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
|
func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
|
||||||
// Make sure arguments match up and pack them
|
// Make sure arguments match up and pack them
|
||||||
abiArgs := arguments
|
abiArgs := arguments
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,12 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/accounts/external"
|
"github.com/ethereum/go-ethereum/accounts/external"
|
||||||
"github.com/maticnetwork/bor/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewTransactor is a utility method to easily create a transaction signer from
|
// NewTransactor is a utility method to easily create a transaction signer from
|
||||||
|
|
@ -45,7 +45,7 @@ func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKeyStoreTransactor is a utility method to easily create a transaction signer from
|
// NewKeyStoreTransactor is a utility method to easily create a transaction signer from
|
||||||
// an decrypted key from a keystore
|
// a decrypted key from a keystore.
|
||||||
func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) {
|
func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) {
|
||||||
return &TransactOpts{
|
return &TransactOpts{
|
||||||
From: account.Address,
|
From: account.Address,
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
ethereum "github.com/maticnetwork/bor"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -41,7 +41,7 @@ var (
|
||||||
ErrNoCodeAfterDeploy = errors.New("no contract code after deployment")
|
ErrNoCodeAfterDeploy = errors.New("no contract code after deployment")
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContractCaller defines the methods needed to allow operating with contract on a read
|
// ContractCaller defines the methods needed to allow operating with a contract on a read
|
||||||
// only basis.
|
// only basis.
|
||||||
type ContractCaller interface {
|
type ContractCaller interface {
|
||||||
// CodeAt returns the code of the given account. This is needed to differentiate
|
// CodeAt returns the code of the given account. This is needed to differentiate
|
||||||
|
|
@ -62,8 +62,8 @@ type PendingContractCaller interface {
|
||||||
PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error)
|
PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractTransactor defines the methods needed to allow operating with contract
|
// ContractTransactor defines the methods needed to allow operating with a contract
|
||||||
// on a write only basis. Beside the transacting method, the remainder are helpers
|
// on a write only basis. Besides the transacting method, the remainder are helpers
|
||||||
// used when the user does not provide some needed values, but rather leaves it up
|
// used when the user does not provide some needed values, but rather leaves it up
|
||||||
// to the transactor to decide.
|
// to the transactor to decide.
|
||||||
type ContractTransactor interface {
|
type ContractTransactor interface {
|
||||||
|
|
|
||||||
|
|
@ -24,28 +24,28 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ethereum "github.com/maticnetwork/bor"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/maticnetwork/bor/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/maticnetwork/bor/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/maticnetwork/bor/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/maticnetwork/bor/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/maticnetwork/bor/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/maticnetwork/bor/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/maticnetwork/bor/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/maticnetwork/bor/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/maticnetwork/bor/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/maticnetwork/bor/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/maticnetwork/bor/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/maticnetwork/bor/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/maticnetwork/bor/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
|
// This nil assignment ensures at compile time that SimulatedBackend implements bind.ContractBackend.
|
||||||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -55,7 +55,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
|
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
|
||||||
// the background. Its main purpose is to allow easily testing contract bindings.
|
// the background. Its main purpose is to allow for easy testing of contract bindings.
|
||||||
// Simulated backend implements the following interfaces:
|
// Simulated backend implements the following interfaces:
|
||||||
// ChainReader, ChainStateReader, ContractBackend, ContractCaller, ContractFilterer, ContractTransactor,
|
// ChainReader, ChainStateReader, ContractBackend, ContractCaller, ContractFilterer, ContractTransactor,
|
||||||
// DeployBackend, GasEstimator, GasPricer, LogFilterer, PendingContractCaller, TransactionReader, and TransactionSender
|
// DeployBackend, GasEstimator, GasPricer, LogFilterer, PendingContractCaller, TransactionReader, and TransactionSender
|
||||||
|
|
@ -123,10 +123,10 @@ func (b *SimulatedBackend) Rollback() {
|
||||||
|
|
||||||
func (b *SimulatedBackend) rollback() {
|
func (b *SimulatedBackend) rollback() {
|
||||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
|
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
|
||||||
statedb, _ := b.blockchain.State()
|
stateDB, _ := b.blockchain.State()
|
||||||
|
|
||||||
b.pendingBlock = blocks[0]
|
b.pendingBlock = blocks[0]
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database(), nil)
|
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateByBlockNumber retrieves a state by a given blocknumber.
|
// stateByBlockNumber retrieves a state by a given blocknumber.
|
||||||
|
|
@ -146,12 +146,12 @@ func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address,
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
statedb, err := b.stateByBlockNumber(ctx, blockNumber)
|
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return statedb.GetCode(contract), nil
|
return stateDB.GetCode(contract), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BalanceAt returns the wei balance of a certain account in the blockchain.
|
// BalanceAt returns the wei balance of a certain account in the blockchain.
|
||||||
|
|
@ -159,12 +159,12 @@ func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Addres
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
statedb, err := b.stateByBlockNumber(ctx, blockNumber)
|
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return statedb.GetBalance(contract), nil
|
return stateDB.GetBalance(contract), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NonceAt returns the nonce of a certain account in the blockchain.
|
// NonceAt returns the nonce of a certain account in the blockchain.
|
||||||
|
|
@ -172,12 +172,12 @@ func (b *SimulatedBackend) NonceAt(ctx context.Context, contract common.Address,
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
statedb, err := b.stateByBlockNumber(ctx, blockNumber)
|
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return statedb.GetNonce(contract), nil
|
return stateDB.GetNonce(contract), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageAt returns the value of key in the storage of an account in the blockchain.
|
// StorageAt returns the value of key in the storage of an account in the blockchain.
|
||||||
|
|
@ -185,12 +185,12 @@ func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Addres
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
statedb, err := b.stateByBlockNumber(ctx, blockNumber)
|
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
val := statedb.GetState(contract, key)
|
val := stateDB.GetState(contract, key)
|
||||||
return val[:], nil
|
return val[:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,7 +222,7 @@ func (b *SimulatedBackend) TransactionByHash(ctx context.Context, txHash common.
|
||||||
return nil, false, ethereum.NotFound
|
return nil, false, ethereum.NotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockByHash retrieves a block based on the block hash
|
// BlockByHash retrieves a block based on the block hash.
|
||||||
func (b *SimulatedBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
func (b *SimulatedBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
@ -293,7 +293,7 @@ func (b *SimulatedBackend) HeaderByNumber(ctx context.Context, block *big.Int) (
|
||||||
return b.blockchain.GetHeaderByNumber(uint64(block.Int64())), nil
|
return b.blockchain.GetHeaderByNumber(uint64(block.Int64())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionCount returns the number of transactions in a given block
|
// TransactionCount returns the number of transactions in a given block.
|
||||||
func (b *SimulatedBackend) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) {
|
func (b *SimulatedBackend) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
@ -310,7 +310,7 @@ func (b *SimulatedBackend) TransactionCount(ctx context.Context, blockHash commo
|
||||||
return uint(block.Transactions().Len()), nil
|
return uint(block.Transactions().Len()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionInBlock returns the transaction for a specific block at a specific index
|
// TransactionInBlock returns the transaction for a specific block at a specific index.
|
||||||
func (b *SimulatedBackend) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
|
func (b *SimulatedBackend) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
@ -357,14 +357,14 @@ func newRevertError(result *core.ExecutionResult) *revertError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// revertError is an API error that encompassas an EVM revertal with JSON error
|
// revertError is an API error that encompasses an EVM revert with JSON error
|
||||||
// code and a binary data blob.
|
// code and a binary data blob.
|
||||||
type revertError struct {
|
type revertError struct {
|
||||||
error
|
error
|
||||||
reason string // revert reason hex encoded
|
reason string // revert reason hex encoded
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrorCode returns the JSON error code for a revertal.
|
// ErrorCode returns the JSON error code for a revert.
|
||||||
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
|
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
|
||||||
func (e *revertError) ErrorCode() int {
|
func (e *revertError) ErrorCode() int {
|
||||||
return 3
|
return 3
|
||||||
|
|
@ -383,11 +383,11 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM
|
||||||
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
||||||
return nil, errBlockNumberUnsupported
|
return nil, errBlockNumberUnsupported
|
||||||
}
|
}
|
||||||
state, err := b.blockchain.State()
|
stateDB, err := b.blockchain.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
|
res, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), stateDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -448,7 +448,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||||
hi = b.pendingBlock.GasLimit()
|
hi = b.pendingBlock.GasLimit()
|
||||||
}
|
}
|
||||||
// Recap the highest gas allowance with account's balance.
|
// Recap the highest gas allowance with account's balance.
|
||||||
if call.GasPrice != nil && call.GasPrice.Uint64() != 0 {
|
if call.GasPrice != nil && call.GasPrice.BitLen() != 0 {
|
||||||
balance := b.pendingState.GetBalance(call.From) // from can't be nil
|
balance := b.pendingState.GetBalance(call.From) // from can't be nil
|
||||||
available := new(big.Int).Set(balance)
|
available := new(big.Int).Set(balance)
|
||||||
if call.Value != nil {
|
if call.Value != nil {
|
||||||
|
|
@ -458,7 +458,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||||
available.Sub(available, call.Value)
|
available.Sub(available, call.Value)
|
||||||
}
|
}
|
||||||
allowance := new(big.Int).Div(available, call.GasPrice)
|
allowance := new(big.Int).Div(available, call.GasPrice)
|
||||||
if hi > allowance.Uint64() {
|
if allowance.IsUint64() && hi > allowance.Uint64() {
|
||||||
transfer := call.Value
|
transfer := call.Value
|
||||||
if transfer == nil {
|
if transfer == nil {
|
||||||
transfer = new(big.Int)
|
transfer = new(big.Int)
|
||||||
|
|
@ -525,7 +525,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||||
|
|
||||||
// callContract implements common code between normal and pending contract calls.
|
// callContract implements common code between normal and pending contract calls.
|
||||||
// state is modified during execution, make sure to copy it if necessary.
|
// state is modified during execution, make sure to copy it if necessary.
|
||||||
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) (*core.ExecutionResult, error) {
|
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, stateDB *state.StateDB) (*core.ExecutionResult, error) {
|
||||||
// Ensure message is initialized properly.
|
// Ensure message is initialized properly.
|
||||||
if call.GasPrice == nil {
|
if call.GasPrice == nil {
|
||||||
call.GasPrice = big.NewInt(1)
|
call.GasPrice = big.NewInt(1)
|
||||||
|
|
@ -537,18 +537,18 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
call.Value = new(big.Int)
|
call.Value = new(big.Int)
|
||||||
}
|
}
|
||||||
// Set infinite balance to the fake caller account.
|
// Set infinite balance to the fake caller account.
|
||||||
from := statedb.GetOrNewStateObject(call.From)
|
from := stateDB.GetOrNewStateObject(call.From)
|
||||||
from.SetBalance(math.MaxBig256)
|
from.SetBalance(math.MaxBig256)
|
||||||
// Execute the call.
|
// Execute the call.
|
||||||
msg := callmsg{call}
|
msg := callMsg{call}
|
||||||
|
|
||||||
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil)
|
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil)
|
||||||
// Create a new environment which holds all relevant information
|
// Create a new environment which holds all relevant information
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
|
vmEnv := vm.NewEVM(evmContext, stateDB, b.config, vm.Config{})
|
||||||
gaspool := new(core.GasPool).AddGas(math.MaxUint64)
|
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
|
|
||||||
return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTransaction updates the pending block to include the given transaction.
|
// SendTransaction updates the pending block to include the given transaction.
|
||||||
|
|
@ -572,10 +572,10 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
||||||
}
|
}
|
||||||
block.AddTxWithChain(b.blockchain, tx)
|
block.AddTxWithChain(b.blockchain, tx)
|
||||||
})
|
})
|
||||||
statedb, _ := b.blockchain.State()
|
stateDB, _ := b.blockchain.State()
|
||||||
|
|
||||||
b.pendingBlock = blocks[0]
|
b.pendingBlock = blocks[0]
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database(), nil)
|
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -589,7 +589,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter
|
||||||
// Block filter requested, construct a single-shot filter
|
// Block filter requested, construct a single-shot filter
|
||||||
filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics)
|
filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics)
|
||||||
} else {
|
} else {
|
||||||
// Initialize unset filter boundaried to run from genesis to chain head
|
// Initialize unset filter boundaries to run from genesis to chain head
|
||||||
from := int64(0)
|
from := int64(0)
|
||||||
if query.FromBlock != nil {
|
if query.FromBlock != nil {
|
||||||
from = query.FromBlock.Int64()
|
from = query.FromBlock.Int64()
|
||||||
|
|
@ -607,8 +607,8 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res := make([]types.Log, len(logs))
|
res := make([]types.Log, len(logs))
|
||||||
for i, log := range logs {
|
for i, nLog := range logs {
|
||||||
res[i] = *log
|
res[i] = *nLog
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
@ -629,9 +629,9 @@ func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethere
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case logs := <-sink:
|
case logs := <-sink:
|
||||||
for _, log := range logs {
|
for _, nlog := range logs {
|
||||||
select {
|
select {
|
||||||
case ch <- *log:
|
case ch <- *nlog:
|
||||||
case err := <-sub.Err():
|
case err := <-sub.Err():
|
||||||
return err
|
return err
|
||||||
case <-quit:
|
case <-quit:
|
||||||
|
|
@ -647,7 +647,7 @@ func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethere
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeNewHead returns an event subscription for a new header
|
// SubscribeNewHead returns an event subscription for a new header.
|
||||||
func (b *SimulatedBackend) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) {
|
func (b *SimulatedBackend) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) {
|
||||||
// subscribe to a new head
|
// subscribe to a new head
|
||||||
sink := make(chan *types.Header)
|
sink := make(chan *types.Header)
|
||||||
|
|
@ -675,20 +675,22 @@ func (b *SimulatedBackend) SubscribeNewHead(ctx context.Context, ch chan<- *type
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdjustTime adds a time shift to the simulated clock.
|
// AdjustTime adds a time shift to the simulated clock.
|
||||||
|
// It can only be called on empty blocks.
|
||||||
func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
|
func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
|
if len(b.pendingBlock.Transactions()) != 0 {
|
||||||
|
return errors.New("Could not adjust time on non-empty block")
|
||||||
|
}
|
||||||
|
|
||||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||||
for _, tx := range b.pendingBlock.Transactions() {
|
|
||||||
block.AddTx(tx)
|
|
||||||
}
|
|
||||||
block.OffsetTime(int64(adjustment.Seconds()))
|
block.OffsetTime(int64(adjustment.Seconds()))
|
||||||
})
|
})
|
||||||
statedb, _ := b.blockchain.State()
|
stateDB, _ := b.blockchain.State()
|
||||||
|
|
||||||
b.pendingBlock = blocks[0]
|
b.pendingBlock = blocks[0]
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database(), nil)
|
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -698,19 +700,19 @@ func (b *SimulatedBackend) Blockchain() *core.BlockChain {
|
||||||
return b.blockchain
|
return b.blockchain
|
||||||
}
|
}
|
||||||
|
|
||||||
// callmsg implements core.Message to allow passing it as a transaction simulator.
|
// callMsg implements core.Message to allow passing it as a transaction simulator.
|
||||||
type callmsg struct {
|
type callMsg struct {
|
||||||
ethereum.CallMsg
|
ethereum.CallMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m callmsg) From() common.Address { return m.CallMsg.From }
|
func (m callMsg) From() common.Address { return m.CallMsg.From }
|
||||||
func (m callmsg) Nonce() uint64 { return 0 }
|
func (m callMsg) Nonce() uint64 { return 0 }
|
||||||
func (m callmsg) CheckNonce() bool { return false }
|
func (m callMsg) CheckNonce() bool { return false }
|
||||||
func (m callmsg) To() *common.Address { return m.CallMsg.To }
|
func (m callMsg) To() *common.Address { return m.CallMsg.To }
|
||||||
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||||
func (m callmsg) Gas() uint64 { return m.CallMsg.Gas }
|
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
|
||||||
func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
|
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
|
||||||
func (m callmsg) Data() []byte { return m.CallMsg.Data }
|
func (m callMsg) Data() []byte { return m.CallMsg.Data }
|
||||||
|
|
||||||
// filterBackend implements filters.Backend to support filtering for logs without
|
// filterBackend implements filters.Backend to support filtering for logs without
|
||||||
// taking bloom-bits acceleration structures into account.
|
// taking bloom-bits acceleration structures into account.
|
||||||
|
|
@ -777,10 +779,6 @@ func (fb *filterBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event
|
||||||
return nullSubscription()
|
return nullSubscription()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fb *filterBackend) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription {
|
|
||||||
return fb.bc.SubscribeStateSyncEvent(ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 }
|
func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 }
|
||||||
|
|
||||||
func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) {
|
func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) {
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,14 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ethereum "github.com/maticnetwork/bor"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/maticnetwork/bor/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/maticnetwork/bor/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSimulatedBackend(t *testing.T) {
|
func TestSimulatedBackend(t *testing.T) {
|
||||||
|
|
@ -129,8 +129,8 @@ func TestNewSimulatedBackend(t *testing.T) {
|
||||||
t.Errorf("expected sim blockchain config to equal params.AllEthashProtocolChanges, got %v", sim.config)
|
t.Errorf("expected sim blockchain config to equal params.AllEthashProtocolChanges, got %v", sim.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
statedb, _ := sim.blockchain.State()
|
stateDB, _ := sim.blockchain.State()
|
||||||
bal := statedb.GetBalance(testAddr)
|
bal := stateDB.GetBalance(testAddr)
|
||||||
if bal.Cmp(expectedBal) != 0 {
|
if bal.Cmp(expectedBal) != 0 {
|
||||||
t.Errorf("expected balance for test address not received. expected: %v actual: %v", expectedBal, bal)
|
t.Errorf("expected balance for test address not received. expected: %v actual: %v", expectedBal, bal)
|
||||||
}
|
}
|
||||||
|
|
@ -143,8 +143,7 @@ func TestSimulatedBackend_AdjustTime(t *testing.T) {
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
prevTime := sim.pendingBlock.Time()
|
prevTime := sim.pendingBlock.Time()
|
||||||
err := sim.AdjustTime(time.Second)
|
if err := sim.AdjustTime(time.Second); err != nil {
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
newTime := sim.pendingBlock.Time()
|
newTime := sim.pendingBlock.Time()
|
||||||
|
|
@ -154,6 +153,44 @@ func TestSimulatedBackend_AdjustTime(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewSimulatedBackend_AdjustTimeFail(t *testing.T) {
|
||||||
|
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||||
|
sim := simTestBackend(testAddr)
|
||||||
|
// Create tx and send
|
||||||
|
tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil)
|
||||||
|
signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("could not sign tx: %v", err)
|
||||||
|
}
|
||||||
|
sim.SendTransaction(context.Background(), signedTx)
|
||||||
|
// AdjustTime should fail on non-empty block
|
||||||
|
if err := sim.AdjustTime(time.Second); err == nil {
|
||||||
|
t.Error("Expected adjust time to error on non-empty block")
|
||||||
|
}
|
||||||
|
sim.Commit()
|
||||||
|
|
||||||
|
prevTime := sim.pendingBlock.Time()
|
||||||
|
if err := sim.AdjustTime(time.Minute); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
newTime := sim.pendingBlock.Time()
|
||||||
|
if newTime-prevTime != uint64(time.Minute.Seconds()) {
|
||||||
|
t.Errorf("adjusted time not equal to a minute. prev: %v, new: %v", prevTime, newTime)
|
||||||
|
}
|
||||||
|
// Put a transaction after adjusting time
|
||||||
|
tx2 := types.NewTransaction(1, testAddr, big.NewInt(1000), params.TxGas, big.NewInt(1), nil)
|
||||||
|
signedTx2, err := types.SignTx(tx2, types.HomesteadSigner{}, testKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("could not sign tx: %v", err)
|
||||||
|
}
|
||||||
|
sim.SendTransaction(context.Background(), signedTx2)
|
||||||
|
sim.Commit()
|
||||||
|
newTime = sim.pendingBlock.Time()
|
||||||
|
if newTime-prevTime >= uint64(time.Minute.Seconds()) {
|
||||||
|
t.Errorf("time adjusted, but shouldn't be: prev: %v, new: %v", prevTime, newTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSimulatedBackend_BalanceAt(t *testing.T) {
|
func TestSimulatedBackend_BalanceAt(t *testing.T) {
|
||||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||||
expectedBal := big.NewInt(10000000000)
|
expectedBal := big.NewInt(10000000000)
|
||||||
|
|
@ -484,7 +521,7 @@ func TestSimulatedBackend_EstimateGasWithPrice(t *testing.T) {
|
||||||
sim := NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether*2 + 2e17)}}, 10000000)
|
sim := NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether*2 + 2e17)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
receipant := common.HexToAddress("deadbeef")
|
recipient := common.HexToAddress("deadbeef")
|
||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
name string
|
name string
|
||||||
message ethereum.CallMsg
|
message ethereum.CallMsg
|
||||||
|
|
@ -493,7 +530,7 @@ func TestSimulatedBackend_EstimateGasWithPrice(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{"EstimateWithoutPrice", ethereum.CallMsg{
|
{"EstimateWithoutPrice", ethereum.CallMsg{
|
||||||
From: addr,
|
From: addr,
|
||||||
To: &receipant,
|
To: &recipient,
|
||||||
Gas: 0,
|
Gas: 0,
|
||||||
GasPrice: big.NewInt(0),
|
GasPrice: big.NewInt(0),
|
||||||
Value: big.NewInt(1000),
|
Value: big.NewInt(1000),
|
||||||
|
|
@ -502,7 +539,7 @@ func TestSimulatedBackend_EstimateGasWithPrice(t *testing.T) {
|
||||||
|
|
||||||
{"EstimateWithPrice", ethereum.CallMsg{
|
{"EstimateWithPrice", ethereum.CallMsg{
|
||||||
From: addr,
|
From: addr,
|
||||||
To: &receipant,
|
To: &recipient,
|
||||||
Gas: 0,
|
Gas: 0,
|
||||||
GasPrice: big.NewInt(1000),
|
GasPrice: big.NewInt(1000),
|
||||||
Value: big.NewInt(1000),
|
Value: big.NewInt(1000),
|
||||||
|
|
@ -511,7 +548,7 @@ func TestSimulatedBackend_EstimateGasWithPrice(t *testing.T) {
|
||||||
|
|
||||||
{"EstimateWithVeryHighPrice", ethereum.CallMsg{
|
{"EstimateWithVeryHighPrice", ethereum.CallMsg{
|
||||||
From: addr,
|
From: addr,
|
||||||
To: &receipant,
|
To: &recipient,
|
||||||
Gas: 0,
|
Gas: 0,
|
||||||
GasPrice: big.NewInt(1e14), // gascost = 2.1ether
|
GasPrice: big.NewInt(1e14), // gascost = 2.1ether
|
||||||
Value: big.NewInt(1e17), // the remaining balance for fee is 2.1ether
|
Value: big.NewInt(1e17), // the remaining balance for fee is 2.1ether
|
||||||
|
|
@ -520,7 +557,7 @@ func TestSimulatedBackend_EstimateGasWithPrice(t *testing.T) {
|
||||||
|
|
||||||
{"EstimateWithSuperhighPrice", ethereum.CallMsg{
|
{"EstimateWithSuperhighPrice", ethereum.CallMsg{
|
||||||
From: addr,
|
From: addr,
|
||||||
To: &receipant,
|
To: &recipient,
|
||||||
Gas: 0,
|
Gas: 0,
|
||||||
GasPrice: big.NewInt(2e14), // gascost = 4.2ether
|
GasPrice: big.NewInt(2e14), // gascost = 4.2ether
|
||||||
Value: big.NewInt(1000),
|
Value: big.NewInt(1000),
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
ethereum "github.com/maticnetwork/bor"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/maticnetwork/bor/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignerFn is a signer function callback when a contract requires a method to
|
// SignerFn is a signer function callback when a contract requires a method to
|
||||||
|
|
@ -117,11 +117,14 @@ func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend Co
|
||||||
// sets the output to result. The result type might be a single field for simple
|
// 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, a slice of interfaces for anonymous returns and a struct for named
|
||||||
// returns.
|
// returns.
|
||||||
func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, params ...interface{}) error {
|
func (c *BoundContract) Call(opts *CallOpts, results *[]interface{}, method string, params ...interface{}) error {
|
||||||
// Don't crash on a lazy user
|
// Don't crash on a lazy user
|
||||||
if opts == nil {
|
if opts == nil {
|
||||||
opts = new(CallOpts)
|
opts = new(CallOpts)
|
||||||
}
|
}
|
||||||
|
if results == nil {
|
||||||
|
results = new([]interface{})
|
||||||
|
}
|
||||||
// Pack the input, call and unpack the results
|
// Pack the input, call and unpack the results
|
||||||
input, err := c.abi.Pack(method, params...)
|
input, err := c.abi.Pack(method, params...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -158,10 +161,14 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
|
if len(*results) == 0 {
|
||||||
|
res, err := c.abi.Unpack(method, output)
|
||||||
|
*results = res
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.abi.Unpack(result, method, output)
|
res := *results
|
||||||
|
return c.abi.UnpackIntoInterface(res[0], method, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transact invokes the (paid) contract method with params as input values.
|
// Transact invokes the (paid) contract method with params as input values.
|
||||||
|
|
@ -177,7 +184,7 @@ func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...in
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawTransact initiates a transaction with the given raw calldata as the input.
|
// RawTransact initiates a transaction with the given raw calldata as the input.
|
||||||
// It's usually used to initiates transaction for invoking **Fallback** function.
|
// It's usually used to initiate transactions for invoking **Fallback** function.
|
||||||
func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) {
|
func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) {
|
||||||
// todo(rjl493456442) check the method is payable or not,
|
// todo(rjl493456442) check the method is payable or not,
|
||||||
// reject invalid transaction at the first place
|
// reject invalid transaction at the first place
|
||||||
|
|
@ -339,7 +346,7 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter
|
||||||
// UnpackLog unpacks a retrieved log into the provided output structure.
|
// UnpackLog unpacks a retrieved log into the provided output structure.
|
||||||
func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error {
|
func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error {
|
||||||
if len(log.Data) > 0 {
|
if len(log.Data) > 0 {
|
||||||
if err := c.abi.Unpack(out, event, log.Data); err != nil {
|
if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,14 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
ethereum "github.com/maticnetwork/bor"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/maticnetwork/bor/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/maticnetwork/bor/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockCaller struct {
|
type mockCaller struct {
|
||||||
|
|
@ -71,11 +71,10 @@ func TestPassingBlockNumber(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, mc, nil, nil)
|
}, mc, nil, nil)
|
||||||
var ret string
|
|
||||||
|
|
||||||
blockNumber := big.NewInt(42)
|
blockNumber := big.NewInt(42)
|
||||||
|
|
||||||
bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, &ret, "something")
|
bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, nil, "something")
|
||||||
|
|
||||||
if mc.callContractBlockNumber != blockNumber {
|
if mc.callContractBlockNumber != blockNumber {
|
||||||
t.Fatalf("CallContract() was not passed the block number")
|
t.Fatalf("CallContract() was not passed the block number")
|
||||||
|
|
@ -85,7 +84,7 @@ func TestPassingBlockNumber(t *testing.T) {
|
||||||
t.Fatalf("CodeAt() was not passed the block number")
|
t.Fatalf("CodeAt() was not passed the block number")
|
||||||
}
|
}
|
||||||
|
|
||||||
bc.Call(&bind.CallOpts{}, &ret, "something")
|
bc.Call(&bind.CallOpts{}, nil, "something")
|
||||||
|
|
||||||
if mc.callContractBlockNumber != nil {
|
if mc.callContractBlockNumber != nil {
|
||||||
t.Fatalf("CallContract() was passed a block number when it should not have been")
|
t.Fatalf("CallContract() was passed a block number when it should not have been")
|
||||||
|
|
@ -95,7 +94,7 @@ func TestPassingBlockNumber(t *testing.T) {
|
||||||
t.Fatalf("CodeAt() was passed a block number when it should not have been")
|
t.Fatalf("CodeAt() was passed a block number when it should not have been")
|
||||||
}
|
}
|
||||||
|
|
||||||
bc.Call(&bind.CallOpts{BlockNumber: blockNumber, Pending: true}, &ret, "something")
|
bc.Call(&bind.CallOpts{BlockNumber: blockNumber, Pending: true}, nil, "something")
|
||||||
|
|
||||||
if !mc.pendingCallContractCalled {
|
if !mc.pendingCallContractCalled {
|
||||||
t.Fatalf("CallContract() was not passed the block number")
|
t.Fatalf("CallContract() was not passed the block number")
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Lang is a target programming language selector to generate bindings for.
|
// Lang is a target programming language selector to generate bindings for.
|
||||||
|
|
@ -52,7 +52,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
|
||||||
// contracts is the map of each individual contract requested binding
|
// contracts is the map of each individual contract requested binding
|
||||||
contracts = make(map[string]*tmplContract)
|
contracts = make(map[string]*tmplContract)
|
||||||
|
|
||||||
// structs is the map of all reclared structs shared by passed contracts.
|
// structs is the map of all redeclared structs shared by passed contracts.
|
||||||
structs = make(map[string]*tmplStruct)
|
structs = make(map[string]*tmplStruct)
|
||||||
|
|
||||||
// isLib is the map used to flag each encountered library as such
|
// isLib is the map used to flag each encountered library as such
|
||||||
|
|
@ -80,10 +80,10 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
|
||||||
fallback *tmplMethod
|
fallback *tmplMethod
|
||||||
receive *tmplMethod
|
receive *tmplMethod
|
||||||
|
|
||||||
// identifiers are used to detect duplicated identifier of function
|
// identifiers are used to detect duplicated identifiers of functions
|
||||||
// and event. For all calls, transacts and events, abigen will generate
|
// and events. For all calls, transacts and events, abigen will generate
|
||||||
// corresponding bindings. However we have to ensure there is no
|
// corresponding bindings. However we have to ensure there is no
|
||||||
// identifier coliision in the bindings of these categories.
|
// identifier collisions in the bindings of these categories.
|
||||||
callIdentifiers = make(map[string]bool)
|
callIdentifiers = make(map[string]bool)
|
||||||
transactIdentifiers = make(map[string]bool)
|
transactIdentifiers = make(map[string]bool)
|
||||||
eventIdentifiers = make(map[string]bool)
|
eventIdentifiers = make(map[string]bool)
|
||||||
|
|
@ -246,7 +246,7 @@ var bindType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) stri
|
||||||
LangJava: bindTypeJava,
|
LangJava: bindTypeJava,
|
||||||
}
|
}
|
||||||
|
|
||||||
// bindBasicTypeGo converts basic solidity types(except array, slice and tuple) to Go one.
|
// bindBasicTypeGo converts basic solidity types(except array, slice and tuple) to Go ones.
|
||||||
func bindBasicTypeGo(kind abi.Type) string {
|
func bindBasicTypeGo(kind abi.Type) string {
|
||||||
switch kind.T {
|
switch kind.T {
|
||||||
case abi.AddressTy:
|
case abi.AddressTy:
|
||||||
|
|
@ -286,7 +286,7 @@ func bindTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// bindBasicTypeJava converts basic solidity types(except array, slice and tuple) to Java one.
|
// bindBasicTypeJava converts basic solidity types(except array, slice and tuple) to Java ones.
|
||||||
func bindBasicTypeJava(kind abi.Type) string {
|
func bindBasicTypeJava(kind abi.Type) string {
|
||||||
switch kind.T {
|
switch kind.T {
|
||||||
case abi.AddressTy:
|
case abi.AddressTy:
|
||||||
|
|
@ -330,7 +330,7 @@ func bindBasicTypeJava(kind abi.Type) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// pluralizeJavaType explicitly converts multidimensional types to predefined
|
// pluralizeJavaType explicitly converts multidimensional types to predefined
|
||||||
// type in go side.
|
// types in go side.
|
||||||
func pluralizeJavaType(typ string) string {
|
func pluralizeJavaType(typ string) string {
|
||||||
switch typ {
|
switch typ {
|
||||||
case "boolean":
|
case "boolean":
|
||||||
|
|
@ -369,7 +369,7 @@ var bindTopicType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bindTopicTypeGo converts a Solidity topic type to a Go one. It is almost the same
|
// bindTopicTypeGo converts a Solidity topic type to a Go one. It is almost the same
|
||||||
// funcionality as for simple types, but dynamic types get converted to hashes.
|
// functionality as for simple types, but dynamic types get converted to hashes.
|
||||||
func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
|
func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
|
||||||
bound := bindTypeGo(kind, structs)
|
bound := bindTypeGo(kind, structs)
|
||||||
|
|
||||||
|
|
@ -386,7 +386,7 @@ func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// bindTopicTypeJava converts a Solidity topic type to a Java one. It is almost the same
|
// bindTopicTypeJava converts a Solidity topic type to a Java one. It is almost the same
|
||||||
// funcionality as for simple types, but dynamic types get converted to hashes.
|
// functionality as for simple types, but dynamic types get converted to hashes.
|
||||||
func bindTopicTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
|
func bindTopicTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
|
||||||
bound := bindTypeJava(kind, structs)
|
bound := bindTypeJava(kind, structs)
|
||||||
|
|
||||||
|
|
@ -394,7 +394,7 @@ func bindTopicTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
|
||||||
// parameters that are not value types i.e. arrays and structs are not
|
// parameters that are not value types i.e. arrays and structs are not
|
||||||
// stored directly but instead a keccak256-hash of an encoding is stored.
|
// stored directly but instead a keccak256-hash of an encoding is stored.
|
||||||
//
|
//
|
||||||
// We only convert stringS and bytes to hash, still need to deal with
|
// We only convert strings and bytes to hash, still need to deal with
|
||||||
// array(both fixed-size and dynamic-size) and struct.
|
// array(both fixed-size and dynamic-size) and struct.
|
||||||
if bound == "String" || bound == "byte[]" {
|
if bound == "String" || bound == "byte[]" {
|
||||||
bound = "Hash"
|
bound = "Hash"
|
||||||
|
|
@ -415,7 +415,7 @@ var bindStructType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct
|
||||||
func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
|
func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
|
||||||
switch kind.T {
|
switch kind.T {
|
||||||
case abi.TupleTy:
|
case abi.TupleTy:
|
||||||
// We compose raw struct name and canonical parameter expression
|
// We compose a raw struct name and a canonical parameter expression
|
||||||
// together here. The reason is before solidity v0.5.11, kind.TupleRawName
|
// together here. The reason is before solidity v0.5.11, kind.TupleRawName
|
||||||
// is empty, so we use canonical parameter expression to distinguish
|
// is empty, so we use canonical parameter expression to distinguish
|
||||||
// different struct definition. From the consideration of backward
|
// different struct definition. From the consideration of backward
|
||||||
|
|
@ -454,7 +454,7 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
|
||||||
func bindStructTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
|
func bindStructTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
|
||||||
switch kind.T {
|
switch kind.T {
|
||||||
case abi.TupleTy:
|
case abi.TupleTy:
|
||||||
// We compose raw struct name and canonical parameter expression
|
// We compose a raw struct name and a canonical parameter expression
|
||||||
// together here. The reason is before solidity v0.5.11, kind.TupleRawName
|
// together here. The reason is before solidity v0.5.11, kind.TupleRawName
|
||||||
// is empty, so we use canonical parameter expression to distinguish
|
// is empty, so we use canonical parameter expression to distinguish
|
||||||
// different struct definition. From the consideration of backward
|
// different struct definition. From the consideration of backward
|
||||||
|
|
@ -486,7 +486,7 @@ func bindStructTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// namedType is a set of functions that transform language specific types to
|
// namedType is a set of functions that transform language specific types to
|
||||||
// named versions that my be used inside method names.
|
// named versions that may be used inside method names.
|
||||||
var namedType = map[Lang]func(string, abi.Type) string{
|
var namedType = map[Lang]func(string, abi.Type) string{
|
||||||
LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") },
|
LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") },
|
||||||
LangJava: namedTypeJava,
|
LangJava: namedTypeJava,
|
||||||
|
|
@ -528,7 +528,7 @@ func alias(aliases map[string]string, n string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// methodNormalizer is a name transformer that modifies Solidity method names to
|
// methodNormalizer is a name transformer that modifies Solidity method names to
|
||||||
// conform to target language naming concentions.
|
// conform to target language naming conventions.
|
||||||
var methodNormalizer = map[Lang]func(string) string{
|
var methodNormalizer = map[Lang]func(string) string{
|
||||||
LangGo: abi.ToCamelCase,
|
LangGo: abi.ToCamelCase,
|
||||||
LangJava: decapitalise,
|
LangJava: decapitalise,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
package bind
|
package bind
|
||||||
|
|
||||||
import "github.com/maticnetwork/bor/accounts/abi"
|
import "github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
|
||||||
// tmplData is the data structure required to fill the binding template.
|
// tmplData is the data structure required to fill the binding template.
|
||||||
type tmplData struct {
|
type tmplData struct {
|
||||||
|
|
@ -30,7 +30,7 @@ type tmplData struct {
|
||||||
type tmplContract struct {
|
type tmplContract struct {
|
||||||
Type string // Type name of the main contract binding
|
Type string // Type name of the main contract binding
|
||||||
InputABI string // JSON ABI used as the input to generate the binding from
|
InputABI string // JSON ABI used as the input to generate the binding from
|
||||||
InputBin string // Optional EVM bytecode used to denetare deploy code from
|
InputBin string // Optional EVM bytecode used to generate deploy code from
|
||||||
FuncSigs map[string]string // Optional map: string signature -> 4-byte signature
|
FuncSigs map[string]string // Optional map: string signature -> 4-byte signature
|
||||||
Constructor abi.Method // Contract constructor for deploy parametrization
|
Constructor abi.Method // Contract constructor for deploy parametrization
|
||||||
Calls map[string]*tmplMethod // Contract calls that only read state data
|
Calls map[string]*tmplMethod // Contract calls that only read state data
|
||||||
|
|
@ -50,7 +50,8 @@ type tmplMethod struct {
|
||||||
Structured bool // Whether the returns should be accumulated into a struct
|
Structured bool // Whether the returns should be accumulated into a struct
|
||||||
}
|
}
|
||||||
|
|
||||||
// tmplEvent is a wrapper around an a
|
// tmplEvent is a wrapper around an abi.Event that contains a few preprocessed
|
||||||
|
// and cached data fields.
|
||||||
type tmplEvent struct {
|
type tmplEvent struct {
|
||||||
Original abi.Event // Original event as parsed by the abi package
|
Original abi.Event // Original event as parsed by the abi package
|
||||||
Normalized abi.Event // Normalized version of the parsed fields
|
Normalized abi.Event // Normalized version of the parsed fields
|
||||||
|
|
@ -64,7 +65,7 @@ type tmplField struct {
|
||||||
SolKind abi.Type // Raw abi type information
|
SolKind abi.Type // Raw abi type information
|
||||||
}
|
}
|
||||||
|
|
||||||
// tmplStruct is a wrapper around an abi.tuple contains an auto-generated
|
// tmplStruct is a wrapper around an abi.tuple and contains an auto-generated
|
||||||
// struct name.
|
// struct name.
|
||||||
type tmplStruct struct {
|
type tmplStruct struct {
|
||||||
Name string // Auto-generated struct name(before solidity v0.5.11) or raw name.
|
Name string // Auto-generated struct name(before solidity v0.5.11) or raw name.
|
||||||
|
|
@ -78,8 +79,8 @@ var tmplSource = map[Lang]string{
|
||||||
LangJava: tmplSourceJava,
|
LangJava: tmplSourceJava,
|
||||||
}
|
}
|
||||||
|
|
||||||
// tmplSourceGo is the Go source template use to generate the contract binding
|
// tmplSourceGo is the Go source template that the generated Go contract binding
|
||||||
// based on.
|
// is based on.
|
||||||
const tmplSourceGo = `
|
const tmplSourceGo = `
|
||||||
// Code generated - DO NOT EDIT.
|
// Code generated - DO NOT EDIT.
|
||||||
// This file is a generated binding and any manual changes will be lost.
|
// This file is a generated binding and any manual changes will be lost.
|
||||||
|
|
@ -90,12 +91,12 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
ethereum "github.com/maticnetwork/bor"
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
"github.com/maticnetwork/bor/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/maticnetwork/bor/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
|
@ -260,7 +261,7 @@ var (
|
||||||
// sets the output to result. The result type might be a single field for simple
|
// 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, a slice of interfaces for anonymous returns and a struct for named
|
||||||
// returns.
|
// returns.
|
||||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
|
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...)
|
return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,7 +280,7 @@ var (
|
||||||
// sets the output to result. The result type might be a single field for simple
|
// 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, a slice of interfaces for anonymous returns and a struct for named
|
||||||
// returns.
|
// returns.
|
||||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
|
func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||||
return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...)
|
return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -299,19 +300,23 @@ var (
|
||||||
//
|
//
|
||||||
// Solidity: {{.Original.String}}
|
// Solidity: {{.Original.String}}
|
||||||
func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) {
|
func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) {
|
||||||
{{if .Structured}}ret := new(struct{
|
var out []interface{}
|
||||||
{{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}}
|
err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||||
{{end}}
|
{{if .Structured}}
|
||||||
}){{else}}var (
|
outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} })
|
||||||
{{range $i, $_ := .Normalized.Outputs}}ret{{$i}} = new({{bindtype .Type $structs}})
|
{{range $i, $t := .Normalized.Outputs}}
|
||||||
{{end}}
|
outstruct.{{.Name}} = out[{{$i}}].({{bindtype .Type $structs}}){{end}}
|
||||||
){{end}}
|
|
||||||
out := {{if .Structured}}ret{{else}}{{if eq (len .Normalized.Outputs) 1}}ret0{{else}}&[]interface{}{
|
return *outstruct, err
|
||||||
{{range $i, $_ := .Normalized.Outputs}}ret{{$i}},
|
{{else}}
|
||||||
{{end}}
|
if err != nil {
|
||||||
}{{end}}{{end}}
|
return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err
|
||||||
err := _{{$contract.Type}}.contract.Call(opts, out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
}
|
||||||
return {{if .Structured}}*ret,{{else}}{{range $i, $_ := .Normalized.Outputs}}*ret{{$i}},{{end}}{{end}} err
|
{{range $i, $t := .Normalized.Outputs}}
|
||||||
|
out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||||
|
|
||||||
|
return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err
|
||||||
|
{{end}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||||
|
|
@ -543,8 +548,8 @@ var (
|
||||||
{{end}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
||||||
// tmplSourceJava is the Java source template use to generate the contract binding
|
// tmplSourceJava is the Java source template that the generated Java contract binding
|
||||||
// based on.
|
// is based on.
|
||||||
const tmplSourceJava = `
|
const tmplSourceJava = `
|
||||||
// This file is an automatically generated Java binding. Do not modify as any
|
// This file is an automatically generated Java binding. Do not modify as any
|
||||||
// change will likely be lost upon the next re-generation!
|
// change will likely be lost upon the next re-generation!
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WaitMined waits for tx to be mined on the blockchain.
|
// WaitMined waits for tx to be mined on the blockchain.
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/maticnetwork/bor/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func sliceTypeCheck(t Type, val reflect.Value) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if elemKind := val.Type().Elem().Kind(); elemKind != t.Elem.GetType().Kind() {
|
if val.Type().Elem().Kind() != t.Elem.GetType().Kind() {
|
||||||
return typeErr(formatSliceString(t.Elem.GetType().Kind(), t.Size), val.Type())
|
return typeErr(formatSliceString(t.Elem.GetType().Kind(), t.Size), val.Type())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Event is an event potentially triggered by the EVM's LOG mechanism. The Event
|
// Event is an event potentially triggered by the EVM's LOG mechanism. The Event
|
||||||
|
|
@ -32,7 +32,7 @@ type Event struct {
|
||||||
// the raw name and a suffix will be added in the case of a event overload.
|
// the raw name and a suffix will be added in the case of a event overload.
|
||||||
//
|
//
|
||||||
// e.g.
|
// e.g.
|
||||||
// There are two events have same name:
|
// These are two events that have the same name:
|
||||||
// * foo(int,int)
|
// * foo(int,int)
|
||||||
// * foo(uint,uint)
|
// * foo(uint,uint)
|
||||||
// The event name of the first one wll be resolved as foo while the second one
|
// The event name of the first one wll be resolved as foo while the second one
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
@ -147,10 +147,6 @@ func TestEventString(t *testing.T) {
|
||||||
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
|
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
|
||||||
func TestEventMultiValueWithArrayUnpack(t *testing.T) {
|
func TestEventMultiValueWithArrayUnpack(t *testing.T) {
|
||||||
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
|
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
|
||||||
type testStruct struct {
|
|
||||||
Value1 [2]uint8
|
|
||||||
Value2 uint8
|
|
||||||
}
|
|
||||||
abi, err := JSON(strings.NewReader(definition))
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
|
|
@ -158,10 +154,10 @@ func TestEventMultiValueWithArrayUnpack(t *testing.T) {
|
||||||
for ; i <= 3; i++ {
|
for ; i <= 3; i++ {
|
||||||
b.Write(packNum(reflect.ValueOf(i)))
|
b.Write(packNum(reflect.ValueOf(i)))
|
||||||
}
|
}
|
||||||
var rst testStruct
|
unpacked, err := abi.Unpack("test", b.Bytes())
|
||||||
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes()))
|
require.NoError(t, err)
|
||||||
require.Equal(t, [2]uint8{1, 2}, rst.Value1)
|
require.Equal(t, [2]uint8{1, 2}, unpacked[0])
|
||||||
require.Equal(t, uint8(3), rst.Value2)
|
require.Equal(t, uint8(3), unpacked[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEventTupleUnpack(t *testing.T) {
|
func TestEventTupleUnpack(t *testing.T) {
|
||||||
|
|
@ -351,14 +347,14 @@ func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, ass
|
||||||
var e Event
|
var e Event
|
||||||
assert.NoError(json.Unmarshal(jsonEvent, &e), "Should be able to unmarshal event ABI")
|
assert.NoError(json.Unmarshal(jsonEvent, &e), "Should be able to unmarshal event ABI")
|
||||||
a := ABI{Events: map[string]Event{"e": e}}
|
a := ABI{Events: map[string]Event{"e": e}}
|
||||||
return a.Unpack(dest, "e", data)
|
return a.UnpackIntoInterface(dest, "e", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
|
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
|
||||||
func TestEventUnpackIndexed(t *testing.T) {
|
func TestEventUnpackIndexed(t *testing.T) {
|
||||||
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
|
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
|
||||||
type testStruct struct {
|
type testStruct struct {
|
||||||
Value1 uint8
|
Value1 uint8 // indexed
|
||||||
Value2 uint8
|
Value2 uint8
|
||||||
}
|
}
|
||||||
abi, err := JSON(strings.NewReader(definition))
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
|
|
@ -366,16 +362,16 @@ func TestEventUnpackIndexed(t *testing.T) {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
b.Write(packNum(reflect.ValueOf(uint8(8))))
|
b.Write(packNum(reflect.ValueOf(uint8(8))))
|
||||||
var rst testStruct
|
var rst testStruct
|
||||||
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes()))
|
require.NoError(t, abi.UnpackIntoInterface(&rst, "test", b.Bytes()))
|
||||||
require.Equal(t, uint8(0), rst.Value1)
|
require.Equal(t, uint8(0), rst.Value1)
|
||||||
require.Equal(t, uint8(8), rst.Value2)
|
require.Equal(t, uint8(8), rst.Value2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEventIndexedWithArrayUnpack verifies that decoder will not overlow when static array is indexed input.
|
// TestEventIndexedWithArrayUnpack verifies that decoder will not overflow when static array is indexed input.
|
||||||
func TestEventIndexedWithArrayUnpack(t *testing.T) {
|
func TestEventIndexedWithArrayUnpack(t *testing.T) {
|
||||||
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]`
|
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]`
|
||||||
type testStruct struct {
|
type testStruct struct {
|
||||||
Value1 [2]uint8
|
Value1 [2]uint8 // indexed
|
||||||
Value2 string
|
Value2 string
|
||||||
}
|
}
|
||||||
abi, err := JSON(strings.NewReader(definition))
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
|
|
@ -388,7 +384,7 @@ func TestEventIndexedWithArrayUnpack(t *testing.T) {
|
||||||
b.Write(common.RightPadBytes([]byte(stringOut), 32))
|
b.Write(common.RightPadBytes([]byte(stringOut), 32))
|
||||||
|
|
||||||
var rst testStruct
|
var rst testStruct
|
||||||
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes()))
|
require.NoError(t, abi.UnpackIntoInterface(&rst, "test", b.Bytes()))
|
||||||
require.Equal(t, [2]uint8{0, 0}, rst.Value1)
|
require.Equal(t, [2]uint8{0, 0}, rst.Value1)
|
||||||
require.Equal(t, stringOut, rst.Value2)
|
require.Equal(t, stringOut, rst.Value2)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FunctionType represents different types of functions a contract might have.
|
// FunctionType represents different types of functions a contract might have.
|
||||||
|
|
@ -45,7 +45,7 @@ const (
|
||||||
// If the method is `Const` no transaction needs to be created for this
|
// If the method is `Const` no transaction needs to be created for this
|
||||||
// particular Method call. It can easily be simulated using a local VM.
|
// particular Method call. It can easily be simulated using a local VM.
|
||||||
// For example a `Balance()` method only needs to retrieve something
|
// For example a `Balance()` method only needs to retrieve something
|
||||||
// from the storage and therefore requires no Tx to be send to the
|
// from the storage and therefore requires no Tx to be sent to the
|
||||||
// network. A method such as `Transact` does require a Tx and thus will
|
// network. A method such as `Transact` does require a Tx and thus will
|
||||||
// be flagged `false`.
|
// be flagged `false`.
|
||||||
// Input specifies the required input parameters for this gives method.
|
// Input specifies the required input parameters for this gives method.
|
||||||
|
|
@ -54,7 +54,7 @@ type Method struct {
|
||||||
// the raw name and a suffix will be added in the case of a function overload.
|
// the raw name and a suffix will be added in the case of a function overload.
|
||||||
//
|
//
|
||||||
// e.g.
|
// e.g.
|
||||||
// There are two functions have same name:
|
// These are two functions that have the same name:
|
||||||
// * foo(int,int)
|
// * foo(int,int)
|
||||||
// * foo(uint,uint)
|
// * foo(uint,uint)
|
||||||
// The method name of the first one will be resolved as foo while the second one
|
// The method name of the first one will be resolved as foo while the second one
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,17 @@
|
||||||
package abi
|
package abi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
)
|
)
|
||||||
|
|
||||||
// packBytesSlice packs the given bytes as [L, V] as the canonical representation
|
// packBytesSlice packs the given bytes as [L, V] as the canonical representation
|
||||||
// bytes slice
|
// bytes slice.
|
||||||
func packBytesSlice(bytes []byte, l int) []byte {
|
func packBytesSlice(bytes []byte, l int) []byte {
|
||||||
len := packNum(reflect.ValueOf(l))
|
len := packNum(reflect.ValueOf(l))
|
||||||
return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...)
|
return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...)
|
||||||
|
|
@ -33,39 +35,42 @@ func packBytesSlice(bytes []byte, l int) []byte {
|
||||||
|
|
||||||
// packElement packs the given reflect value according to the abi specification in
|
// packElement packs the given reflect value according to the abi specification in
|
||||||
// t.
|
// t.
|
||||||
func packElement(t Type, reflectValue reflect.Value) []byte {
|
func packElement(t Type, reflectValue reflect.Value) ([]byte, error) {
|
||||||
switch t.T {
|
switch t.T {
|
||||||
case IntTy, UintTy:
|
case IntTy, UintTy:
|
||||||
return packNum(reflectValue)
|
return packNum(reflectValue), nil
|
||||||
case StringTy:
|
case StringTy:
|
||||||
return packBytesSlice([]byte(reflectValue.String()), reflectValue.Len())
|
return packBytesSlice([]byte(reflectValue.String()), reflectValue.Len()), nil
|
||||||
case AddressTy:
|
case AddressTy:
|
||||||
if reflectValue.Kind() == reflect.Array {
|
if reflectValue.Kind() == reflect.Array {
|
||||||
reflectValue = mustArrayToByteSlice(reflectValue)
|
reflectValue = mustArrayToByteSlice(reflectValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
return common.LeftPadBytes(reflectValue.Bytes(), 32)
|
return common.LeftPadBytes(reflectValue.Bytes(), 32), nil
|
||||||
case BoolTy:
|
case BoolTy:
|
||||||
if reflectValue.Bool() {
|
if reflectValue.Bool() {
|
||||||
return math.PaddedBigBytes(common.Big1, 32)
|
return math.PaddedBigBytes(common.Big1, 32), nil
|
||||||
}
|
}
|
||||||
return math.PaddedBigBytes(common.Big0, 32)
|
return math.PaddedBigBytes(common.Big0, 32), nil
|
||||||
case BytesTy:
|
case BytesTy:
|
||||||
if reflectValue.Kind() == reflect.Array {
|
if reflectValue.Kind() == reflect.Array {
|
||||||
reflectValue = mustArrayToByteSlice(reflectValue)
|
reflectValue = mustArrayToByteSlice(reflectValue)
|
||||||
}
|
}
|
||||||
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len())
|
if reflectValue.Type() != reflect.TypeOf([]byte{}) {
|
||||||
|
return []byte{}, errors.New("Bytes type is neither slice nor array")
|
||||||
|
}
|
||||||
|
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len()), nil
|
||||||
case FixedBytesTy, FunctionTy:
|
case FixedBytesTy, FunctionTy:
|
||||||
if reflectValue.Kind() == reflect.Array {
|
if reflectValue.Kind() == reflect.Array {
|
||||||
reflectValue = mustArrayToByteSlice(reflectValue)
|
reflectValue = mustArrayToByteSlice(reflectValue)
|
||||||
}
|
}
|
||||||
return common.RightPadBytes(reflectValue.Bytes(), 32)
|
return common.RightPadBytes(reflectValue.Bytes(), 32), nil
|
||||||
default:
|
default:
|
||||||
panic("abi: fatal error")
|
return []byte{}, fmt.Errorf("Could not pack element, unknown type: %v", t.T)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
|
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation.
|
||||||
func packNum(value reflect.Value) []byte {
|
func packNum(value reflect.Value) []byte {
|
||||||
switch kind := value.Kind(); kind {
|
switch kind := value.Kind(); kind {
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
|
@ -77,5 +82,4 @@ func packNum(value reflect.Value) []byte {
|
||||||
default:
|
default:
|
||||||
panic("abi: fatal error")
|
panic("abi: fatal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestPack tests the general pack/unpack tests in packing_test.go
|
// TestPack tests the general pack/unpack tests in packing_test.go
|
||||||
|
|
@ -44,18 +44,7 @@ func TestPack(t *testing.T) {
|
||||||
t.Fatalf("invalid ABI definition %s, %v", inDef, err)
|
t.Fatalf("invalid ABI definition %s, %v", inDef, err)
|
||||||
}
|
}
|
||||||
var packed []byte
|
var packed []byte
|
||||||
if reflect.TypeOf(test.unpacked).Kind() != reflect.Struct {
|
packed, err = inAbi.Pack("method", test.unpacked)
|
||||||
packed, err = inAbi.Pack("method", test.unpacked)
|
|
||||||
} else {
|
|
||||||
// if want is a struct we need to use the components.
|
|
||||||
elem := reflect.ValueOf(test.unpacked)
|
|
||||||
var values []interface{}
|
|
||||||
for i := 0; i < elem.NumField(); i++ {
|
|
||||||
field := elem.Field(i)
|
|
||||||
values = append(values, field.Interface())
|
|
||||||
}
|
|
||||||
packed, err = inAbi.Pack("method", values...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %d (%v) failed: %v", i, test.def, err)
|
t.Fatalf("test %d (%v) failed: %v", i, test.def, err)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ package abi
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type packUnpackTest struct {
|
type packUnpackTest struct {
|
||||||
|
|
@ -620,7 +620,7 @@ var packUnpackTests = []packUnpackTest{
|
||||||
|
|
||||||
{
|
{
|
||||||
def: `[{"type": "bytes32[]"}]`,
|
def: `[{"type": "bytes32[]"}]`,
|
||||||
unpacked: []common.Hash{{1}, {2}},
|
unpacked: [][32]byte{{1}, {2}},
|
||||||
packed: "0000000000000000000000000000000000000000000000000000000000000020" +
|
packed: "0000000000000000000000000000000000000000000000000000000000000020" +
|
||||||
"0000000000000000000000000000000000000000000000000000000000000002" +
|
"0000000000000000000000000000000000000000000000000000000000000002" +
|
||||||
"0100000000000000000000000000000000000000000000000000000000000000" +
|
"0100000000000000000000000000000000000000000000000000000000000000" +
|
||||||
|
|
@ -722,7 +722,7 @@ var packUnpackTests = []packUnpackTest{
|
||||||
},
|
},
|
||||||
// struct outputs
|
// struct outputs
|
||||||
{
|
{
|
||||||
def: `[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`,
|
def: `[{"components": [{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}], "type":"tuple"}]`,
|
||||||
packed: "0000000000000000000000000000000000000000000000000000000000000001" +
|
packed: "0000000000000000000000000000000000000000000000000000000000000001" +
|
||||||
"0000000000000000000000000000000000000000000000000000000000000002",
|
"0000000000000000000000000000000000000000000000000000000000000002",
|
||||||
unpacked: struct {
|
unpacked: struct {
|
||||||
|
|
@ -731,28 +731,28 @@ var packUnpackTests = []packUnpackTest{
|
||||||
}{big.NewInt(1), big.NewInt(2)},
|
}{big.NewInt(1), big.NewInt(2)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
def: `[{"name":"int_one","type":"int256"}]`,
|
def: `[{"components": [{"name":"int_one","type":"int256"}], "type":"tuple"}]`,
|
||||||
packed: "0000000000000000000000000000000000000000000000000000000000000001",
|
packed: "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
unpacked: struct {
|
unpacked: struct {
|
||||||
IntOne *big.Int
|
IntOne *big.Int
|
||||||
}{big.NewInt(1)},
|
}{big.NewInt(1)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
def: `[{"name":"int__one","type":"int256"}]`,
|
def: `[{"components": [{"name":"int__one","type":"int256"}], "type":"tuple"}]`,
|
||||||
packed: "0000000000000000000000000000000000000000000000000000000000000001",
|
packed: "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
unpacked: struct {
|
unpacked: struct {
|
||||||
IntOne *big.Int
|
IntOne *big.Int
|
||||||
}{big.NewInt(1)},
|
}{big.NewInt(1)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
def: `[{"name":"int_one_","type":"int256"}]`,
|
def: `[{"components": [{"name":"int_one_","type":"int256"}], "type":"tuple"}]`,
|
||||||
packed: "0000000000000000000000000000000000000000000000000000000000000001",
|
packed: "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
unpacked: struct {
|
unpacked: struct {
|
||||||
IntOne *big.Int
|
IntOne *big.Int
|
||||||
}{big.NewInt(1)},
|
}{big.NewInt(1)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`,
|
def: `[{"components": [{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}], "type":"tuple"}]`,
|
||||||
packed: "0000000000000000000000000000000000000000000000000000000000000001" +
|
packed: "0000000000000000000000000000000000000000000000000000000000000001" +
|
||||||
"0000000000000000000000000000000000000000000000000000000000000002",
|
"0000000000000000000000000000000000000000000000000000000000000002",
|
||||||
unpacked: struct {
|
unpacked: struct {
|
||||||
|
|
@ -831,11 +831,11 @@ var packUnpackTests = []packUnpackTest{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// static tuple
|
// static tuple
|
||||||
def: `[{"name":"a","type":"int64"},
|
def: `[{"components": [{"name":"a","type":"int64"},
|
||||||
{"name":"b","type":"int256"},
|
{"name":"b","type":"int256"},
|
||||||
{"name":"c","type":"int256"},
|
{"name":"c","type":"int256"},
|
||||||
{"name":"d","type":"bool"},
|
{"name":"d","type":"bool"},
|
||||||
{"name":"e","type":"bytes32[3][2]"}]`,
|
{"name":"e","type":"bytes32[3][2]"}], "type":"tuple"}]`,
|
||||||
unpacked: struct {
|
unpacked: struct {
|
||||||
A int64
|
A int64
|
||||||
B *big.Int
|
B *big.Int
|
||||||
|
|
@ -855,21 +855,22 @@ var packUnpackTests = []packUnpackTest{
|
||||||
"0500000000000000000000000000000000000000000000000000000000000000", // struct[e] array[1][2]
|
"0500000000000000000000000000000000000000000000000000000000000000", // struct[e] array[1][2]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
def: `[{"name":"a","type":"string"},
|
def: `[{"components": [{"name":"a","type":"string"},
|
||||||
{"name":"b","type":"int64"},
|
{"name":"b","type":"int64"},
|
||||||
{"name":"c","type":"bytes"},
|
{"name":"c","type":"bytes"},
|
||||||
{"name":"d","type":"string[]"},
|
{"name":"d","type":"string[]"},
|
||||||
{"name":"e","type":"int256[]"},
|
{"name":"e","type":"int256[]"},
|
||||||
{"name":"f","type":"address[]"}]`,
|
{"name":"f","type":"address[]"}], "type":"tuple"}]`,
|
||||||
unpacked: struct {
|
unpacked: struct {
|
||||||
FieldA string `abi:"a"` // Test whether abi tag works
|
A string
|
||||||
FieldB int64 `abi:"b"`
|
B int64
|
||||||
C []byte
|
C []byte
|
||||||
D []string
|
D []string
|
||||||
E []*big.Int
|
E []*big.Int
|
||||||
F []common.Address
|
F []common.Address
|
||||||
}{"foobar", 1, []byte{1}, []string{"foo", "bar"}, []*big.Int{big.NewInt(1), big.NewInt(-1)}, []common.Address{{1}, {2}}},
|
}{"foobar", 1, []byte{1}, []string{"foo", "bar"}, []*big.Int{big.NewInt(1), big.NewInt(-1)}, []common.Address{{1}, {2}}},
|
||||||
packed: "00000000000000000000000000000000000000000000000000000000000000c0" + // struct[a] offset
|
packed: "0000000000000000000000000000000000000000000000000000000000000020" + // struct a
|
||||||
|
"00000000000000000000000000000000000000000000000000000000000000c0" + // struct[a] offset
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
|
"0000000000000000000000000000000000000000000000000000000000000001" + // struct[b]
|
||||||
"0000000000000000000000000000000000000000000000000000000000000100" + // struct[c] offset
|
"0000000000000000000000000000000000000000000000000000000000000100" + // struct[c] offset
|
||||||
"0000000000000000000000000000000000000000000000000000000000000140" + // struct[d] offset
|
"0000000000000000000000000000000000000000000000000000000000000140" + // struct[d] offset
|
||||||
|
|
@ -894,23 +895,24 @@ var packUnpackTests = []packUnpackTest{
|
||||||
"0000000000000000000000000200000000000000000000000000000000000000", // common.Address{2}
|
"0000000000000000000000000200000000000000000000000000000000000000", // common.Address{2}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
def: `[{"components": [{"name": "a","type": "uint256"},
|
def: `[{"components": [{ "type": "tuple","components": [{"name": "a","type": "uint256"},
|
||||||
{"name": "b","type": "uint256[]"}],
|
{"name": "b","type": "uint256[]"}],
|
||||||
"name": "a","type": "tuple"},
|
"name": "a","type": "tuple"},
|
||||||
{"name": "b","type": "uint256[]"}]`,
|
{"name": "b","type": "uint256[]"}], "type": "tuple"}]`,
|
||||||
unpacked: struct {
|
unpacked: struct {
|
||||||
A struct {
|
A struct {
|
||||||
FieldA *big.Int `abi:"a"`
|
A *big.Int
|
||||||
B []*big.Int
|
B []*big.Int
|
||||||
}
|
}
|
||||||
B []*big.Int
|
B []*big.Int
|
||||||
}{
|
}{
|
||||||
A: struct {
|
A: struct {
|
||||||
FieldA *big.Int `abi:"a"` // Test whether abi tag works for nested tuple
|
A *big.Int
|
||||||
B []*big.Int
|
B []*big.Int
|
||||||
}{big.NewInt(1), []*big.Int{big.NewInt(1), big.NewInt(2)}},
|
}{big.NewInt(1), []*big.Int{big.NewInt(1), big.NewInt(2)}},
|
||||||
B: []*big.Int{big.NewInt(1), big.NewInt(2)}},
|
B: []*big.Int{big.NewInt(1), big.NewInt(2)}},
|
||||||
packed: "0000000000000000000000000000000000000000000000000000000000000040" + // a offset
|
packed: "0000000000000000000000000000000000000000000000000000000000000020" + // struct a
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000040" + // a offset
|
||||||
"00000000000000000000000000000000000000000000000000000000000000e0" + // b offset
|
"00000000000000000000000000000000000000000000000000000000000000e0" + // b offset
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001" + // a.a value
|
"0000000000000000000000000000000000000000000000000000000000000001" + // a.a value
|
||||||
"0000000000000000000000000000000000000000000000000000000000000040" + // a.b offset
|
"0000000000000000000000000000000000000000000000000000000000000040" + // a.b offset
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,29 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ConvertType converts an interface of a runtime type into a interface of the
|
||||||
|
// given type
|
||||||
|
// e.g. turn
|
||||||
|
// var fields []reflect.StructField
|
||||||
|
// fields = append(fields, reflect.StructField{
|
||||||
|
// Name: "X",
|
||||||
|
// Type: reflect.TypeOf(new(big.Int)),
|
||||||
|
// Tag: reflect.StructTag("json:\"" + "x" + "\""),
|
||||||
|
// }
|
||||||
|
// into
|
||||||
|
// type TupleT struct { X *big.Int }
|
||||||
|
func ConvertType(in interface{}, proto interface{}) interface{} {
|
||||||
|
protoType := reflect.TypeOf(proto)
|
||||||
|
if reflect.TypeOf(in).ConvertibleTo(protoType) {
|
||||||
|
return reflect.ValueOf(in).Convert(protoType).Interface()
|
||||||
|
}
|
||||||
|
// Use set as a last ditch effort
|
||||||
|
if err := set(reflect.ValueOf(proto), reflect.ValueOf(in)); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return proto
|
||||||
|
}
|
||||||
|
|
||||||
// indirect recursively dereferences the value until it either gets the value
|
// indirect recursively dereferences the value until it either gets the value
|
||||||
// or finds a big.Int
|
// or finds a big.Int
|
||||||
func indirect(v reflect.Value) reflect.Value {
|
func indirect(v reflect.Value) reflect.Value {
|
||||||
|
|
@ -61,7 +84,7 @@ func reflectIntType(unsigned bool, size int) reflect.Type {
|
||||||
return reflect.TypeOf(&big.Int{})
|
return reflect.TypeOf(&big.Int{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// mustArrayToBytesSlice creates a new byte slice with the exact same size as value
|
// mustArrayToByteSlice creates a new byte slice with the exact same size as value
|
||||||
// and copies the bytes in value to the new slice.
|
// and copies the bytes in value to the new slice.
|
||||||
func mustArrayToByteSlice(value reflect.Value) reflect.Value {
|
func mustArrayToByteSlice(value reflect.Value) reflect.Value {
|
||||||
slice := reflect.MakeSlice(reflect.TypeOf([]byte{}), value.Len(), value.Len())
|
slice := reflect.MakeSlice(reflect.TypeOf([]byte{}), value.Len(), value.Len())
|
||||||
|
|
@ -119,6 +142,9 @@ func setSlice(dst, src reflect.Value) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setArray(dst, src reflect.Value) error {
|
func setArray(dst, src reflect.Value) error {
|
||||||
|
if src.Kind() == reflect.Ptr {
|
||||||
|
return set(dst, indirect(src))
|
||||||
|
}
|
||||||
array := reflect.New(dst.Type()).Elem()
|
array := reflect.New(dst.Type()).Elem()
|
||||||
min := src.Len()
|
min := src.Len()
|
||||||
if src.Len() > dst.Len() {
|
if src.Len() > dst.Len() {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package abi
|
package abi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
@ -189,3 +190,72 @@ func TestReflectNameToStruct(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConvertType(t *testing.T) {
|
||||||
|
// Test Basic Struct
|
||||||
|
type T struct {
|
||||||
|
X *big.Int
|
||||||
|
Y *big.Int
|
||||||
|
}
|
||||||
|
// Create on-the-fly structure
|
||||||
|
var fields []reflect.StructField
|
||||||
|
fields = append(fields, reflect.StructField{
|
||||||
|
Name: "X",
|
||||||
|
Type: reflect.TypeOf(new(big.Int)),
|
||||||
|
Tag: reflect.StructTag("json:\"" + "x" + "\""),
|
||||||
|
})
|
||||||
|
fields = append(fields, reflect.StructField{
|
||||||
|
Name: "Y",
|
||||||
|
Type: reflect.TypeOf(new(big.Int)),
|
||||||
|
Tag: reflect.StructTag("json:\"" + "y" + "\""),
|
||||||
|
})
|
||||||
|
val := reflect.New(reflect.StructOf(fields))
|
||||||
|
val.Elem().Field(0).Set(reflect.ValueOf(big.NewInt(1)))
|
||||||
|
val.Elem().Field(1).Set(reflect.ValueOf(big.NewInt(2)))
|
||||||
|
// ConvertType
|
||||||
|
out := *ConvertType(val.Interface(), new(T)).(*T)
|
||||||
|
if out.X.Cmp(big.NewInt(1)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out.X, big.NewInt(1))
|
||||||
|
}
|
||||||
|
if out.Y.Cmp(big.NewInt(2)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out.Y, big.NewInt(2))
|
||||||
|
}
|
||||||
|
// Slice Type
|
||||||
|
val2 := reflect.MakeSlice(reflect.SliceOf(reflect.StructOf(fields)), 2, 2)
|
||||||
|
val2.Index(0).Field(0).Set(reflect.ValueOf(big.NewInt(1)))
|
||||||
|
val2.Index(0).Field(1).Set(reflect.ValueOf(big.NewInt(2)))
|
||||||
|
val2.Index(1).Field(0).Set(reflect.ValueOf(big.NewInt(3)))
|
||||||
|
val2.Index(1).Field(1).Set(reflect.ValueOf(big.NewInt(4)))
|
||||||
|
out2 := *ConvertType(val2.Interface(), new([]T)).(*[]T)
|
||||||
|
if out2[0].X.Cmp(big.NewInt(1)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out2[0].X, big.NewInt(1))
|
||||||
|
}
|
||||||
|
if out2[0].Y.Cmp(big.NewInt(2)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out2[1].Y, big.NewInt(2))
|
||||||
|
}
|
||||||
|
if out2[1].X.Cmp(big.NewInt(3)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out2[0].X, big.NewInt(1))
|
||||||
|
}
|
||||||
|
if out2[1].Y.Cmp(big.NewInt(4)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out2[1].Y, big.NewInt(2))
|
||||||
|
}
|
||||||
|
// Array Type
|
||||||
|
val3 := reflect.New(reflect.ArrayOf(2, reflect.StructOf(fields)))
|
||||||
|
val3.Elem().Index(0).Field(0).Set(reflect.ValueOf(big.NewInt(1)))
|
||||||
|
val3.Elem().Index(0).Field(1).Set(reflect.ValueOf(big.NewInt(2)))
|
||||||
|
val3.Elem().Index(1).Field(0).Set(reflect.ValueOf(big.NewInt(3)))
|
||||||
|
val3.Elem().Index(1).Field(1).Set(reflect.ValueOf(big.NewInt(4)))
|
||||||
|
out3 := *ConvertType(val3.Interface(), new([2]T)).(*[2]T)
|
||||||
|
if out3[0].X.Cmp(big.NewInt(1)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out3[0].X, big.NewInt(1))
|
||||||
|
}
|
||||||
|
if out3[0].Y.Cmp(big.NewInt(2)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out3[1].Y, big.NewInt(2))
|
||||||
|
}
|
||||||
|
if out3[1].X.Cmp(big.NewInt(3)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out3[0].X, big.NewInt(1))
|
||||||
|
}
|
||||||
|
if out3[1].Y.Cmp(big.NewInt(4)) != 0 {
|
||||||
|
t.Errorf("ConvertType failed, got %v want %v", out3[1].Y, big.NewInt(2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MakeTopics converts a filter query argument list into a filter topic set.
|
// MakeTopics converts a filter query argument list into a filter topic set.
|
||||||
|
|
@ -102,7 +102,7 @@ func genIntType(rule int64, size uint) []byte {
|
||||||
var topic [common.HashLength]byte
|
var topic [common.HashLength]byte
|
||||||
if rule < 0 {
|
if rule < 0 {
|
||||||
// if a rule is negative, we need to put it into two's complement.
|
// if a rule is negative, we need to put it into two's complement.
|
||||||
// extended to common.Hashlength bytes.
|
// extended to common.HashLength bytes.
|
||||||
topic = [common.HashLength]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
|
topic = [common.HashLength]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
|
||||||
}
|
}
|
||||||
for i := uint(0); i < size; i++ {
|
for i := uint(0); i < size; i++ {
|
||||||
|
|
@ -120,7 +120,7 @@ func ParseTopics(out interface{}, fields Arguments, topics []common.Hash) error
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseTopicsIntoMap converts the indexed topic field-value pairs into map key-value pairs
|
// ParseTopicsIntoMap converts the indexed topic field-value pairs into map key-value pairs.
|
||||||
func ParseTopicsIntoMap(out map[string]interface{}, fields Arguments, topics []common.Hash) error {
|
func ParseTopicsIntoMap(out map[string]interface{}, fields Arguments, topics []common.Hash) error {
|
||||||
return parseTopicWithSetter(fields, topics,
|
return parseTopicWithSetter(fields, topics,
|
||||||
func(arg Argument, reconstr interface{}) {
|
func(arg Argument, reconstr interface{}) {
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMakeTopics(t *testing.T) {
|
func TestMakeTopics(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type enumerator
|
// Type enumerator
|
||||||
|
|
@ -44,7 +44,7 @@ const (
|
||||||
FunctionTy
|
FunctionTy
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type is the reflection of the supported argument type
|
// Type is the reflection of the supported argument type.
|
||||||
type Type struct {
|
type Type struct {
|
||||||
Elem *Type
|
Elem *Type
|
||||||
Size int
|
Size int
|
||||||
|
|
@ -264,7 +264,7 @@ func overloadedArgName(rawName string, names map[string]string) (string, error)
|
||||||
return fieldName, nil
|
return fieldName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements Stringer
|
// String implements Stringer.
|
||||||
func (t Type) String() (out string) {
|
func (t Type) String() (out string) {
|
||||||
return t.stringKind
|
return t.stringKind
|
||||||
}
|
}
|
||||||
|
|
@ -346,7 +346,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
|
||||||
return append(ret, tail...), nil
|
return append(ret, tail...), nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return packElement(t, v), nil
|
return packElement(t, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -386,7 +386,7 @@ func isDynamicType(t Type) bool {
|
||||||
func getTypeSize(t Type) int {
|
func getTypeSize(t Type) int {
|
||||||
if t.T == ArrayTy && !isDynamicType(*t.Elem) {
|
if t.T == ArrayTy && !isDynamicType(*t.Elem) {
|
||||||
// Recursively calculate type size if it is a nested array
|
// Recursively calculate type size if it is a nested array
|
||||||
if t.Elem.T == ArrayTy {
|
if t.Elem.T == ArrayTy || t.Elem.T == TupleTy {
|
||||||
return t.Size * getTypeSize(*t.Elem)
|
return t.Size * getTypeSize(*t.Elem)
|
||||||
}
|
}
|
||||||
return t.Size * 32
|
return t.Size * 32
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// typeWithoutStringer is a alias for the Type type which simply doesn't implement
|
// typeWithoutStringer is a alias for the Type type which simply doesn't implement
|
||||||
|
|
@ -330,3 +330,39 @@ func TestInternalType(t *testing.T) {
|
||||||
t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s ", blob, spew.Sdump(typeWithoutStringer(typ)), spew.Sdump(typeWithoutStringer(kind)))
|
t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s ", blob, spew.Sdump(typeWithoutStringer(typ)), spew.Sdump(typeWithoutStringer(kind)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetTypeSize(t *testing.T) {
|
||||||
|
var testCases = []struct {
|
||||||
|
typ string
|
||||||
|
components []ArgumentMarshaling
|
||||||
|
typSize int
|
||||||
|
}{
|
||||||
|
// simple array
|
||||||
|
{"uint256[2]", nil, 32 * 2},
|
||||||
|
{"address[3]", nil, 32 * 3},
|
||||||
|
{"bytes32[4]", nil, 32 * 4},
|
||||||
|
// array array
|
||||||
|
{"uint256[2][3][4]", nil, 32 * (2 * 3 * 4)},
|
||||||
|
// array tuple
|
||||||
|
{"tuple[2]", []ArgumentMarshaling{{Name: "x", Type: "bytes32"}, {Name: "y", Type: "bytes32"}}, (32 * 2) * 2},
|
||||||
|
// simple tuple
|
||||||
|
{"tuple", []ArgumentMarshaling{{Name: "x", Type: "uint256"}, {Name: "y", Type: "uint256"}}, 32 * 2},
|
||||||
|
// tuple array
|
||||||
|
{"tuple", []ArgumentMarshaling{{Name: "x", Type: "bytes32[2]"}}, 32 * 2},
|
||||||
|
// tuple tuple
|
||||||
|
{"tuple", []ArgumentMarshaling{{Name: "x", Type: "tuple", Components: []ArgumentMarshaling{{Name: "x", Type: "bytes32"}}}}, 32},
|
||||||
|
{"tuple", []ArgumentMarshaling{{Name: "x", Type: "tuple", Components: []ArgumentMarshaling{{Name: "x", Type: "bytes32[2]"}, {Name: "y", Type: "uint256"}}}}, 32 * (2 + 1)},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, data := range testCases {
|
||||||
|
typ, err := NewType(data.typ, "", data.components)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("type %q: failed to parse type string: %v", data.typ, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := getTypeSize(typ)
|
||||||
|
if result != data.typSize {
|
||||||
|
t.Errorf("case %d type %q: get type size error: actual: %d expected: %d", i, data.typ, result, data.typSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,17 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// MaxUint256 is the maximum value that can be represented by a uint256
|
// MaxUint256 is the maximum value that can be represented by a uint256.
|
||||||
MaxUint256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1)
|
MaxUint256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1)
|
||||||
// MaxInt256 is the maximum value that can be represented by a int256
|
// MaxInt256 is the maximum value that can be represented by a int256.
|
||||||
MaxInt256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 255), common.Big1)
|
MaxInt256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 255), common.Big1)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadInteger reads the integer based on its kind and returns the appropriate value
|
// ReadInteger reads the integer based on its kind and returns the appropriate value.
|
||||||
func ReadInteger(typ Type, b []byte) interface{} {
|
func ReadInteger(typ Type, b []byte) interface{} {
|
||||||
if typ.T == UintTy {
|
if typ.T == UintTy {
|
||||||
switch typ.Size {
|
switch typ.Size {
|
||||||
|
|
@ -73,7 +73,7 @@ func ReadInteger(typ Type, b []byte) interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reads a bool
|
// readBool reads a bool.
|
||||||
func readBool(word []byte) (bool, error) {
|
func readBool(word []byte) (bool, error) {
|
||||||
for _, b := range word[:31] {
|
for _, b := range word[:31] {
|
||||||
if b != 0 {
|
if b != 0 {
|
||||||
|
|
@ -91,7 +91,8 @@ func readBool(word []byte) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A function type is simply the address with the function selection signature at the end.
|
// A function type is simply the address with the function selection signature at the end.
|
||||||
// This enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes)
|
//
|
||||||
|
// readFunctionType enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes)
|
||||||
func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
|
func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
|
||||||
if t.T != FunctionTy {
|
if t.T != FunctionTy {
|
||||||
return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array")
|
return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array")
|
||||||
|
|
@ -104,7 +105,7 @@ func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadFixedBytes uses reflection to create a fixed array to be read from
|
// ReadFixedBytes uses reflection to create a fixed array to be read from.
|
||||||
func ReadFixedBytes(t Type, word []byte) (interface{}, error) {
|
func ReadFixedBytes(t Type, word []byte) (interface{}, error) {
|
||||||
if t.T != FixedBytesTy {
|
if t.T != FixedBytesTy {
|
||||||
return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array")
|
return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array")
|
||||||
|
|
@ -117,7 +118,7 @@ func ReadFixedBytes(t Type, word []byte) (interface{}, error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// iteratively unpack elements
|
// forEachUnpack iteratively unpack elements.
|
||||||
func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
|
func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
|
||||||
if size < 0 {
|
if size < 0 {
|
||||||
return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size)
|
return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size)
|
||||||
|
|
@ -224,7 +225,10 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
|
||||||
return forEachUnpack(t, output[begin:], 0, length)
|
return forEachUnpack(t, output[begin:], 0, length)
|
||||||
case ArrayTy:
|
case ArrayTy:
|
||||||
if isDynamicType(*t.Elem) {
|
if isDynamicType(*t.Elem) {
|
||||||
offset := int64(binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:]))
|
offset := binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:])
|
||||||
|
if offset > uint64(len(output)) {
|
||||||
|
return nil, fmt.Errorf("abi: toGoType offset greater than output length: offset: %d, len(output): %d", offset, len(output))
|
||||||
|
}
|
||||||
return forEachUnpack(t, output[offset:], 0, t.Size)
|
return forEachUnpack(t, output[offset:], 0, t.Size)
|
||||||
}
|
}
|
||||||
return forEachUnpack(t, output[index:], 0, t.Size)
|
return forEachUnpack(t, output[index:], 0, t.Size)
|
||||||
|
|
@ -249,7 +253,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// interprets a 32 byte slice as an offset and then determines which indice to look to decode the type.
|
// lengthPrefixPointsTo interprets a 32 byte slice as an offset and then determines which indices to look to decode the type.
|
||||||
func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) {
|
func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) {
|
||||||
bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32])
|
bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32])
|
||||||
bigOffsetEnd.Add(bigOffsetEnd, common.Big32)
|
bigOffsetEnd.Add(bigOffsetEnd, common.Big32)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -44,15 +44,13 @@ func TestUnpack(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("invalid hex %s: %v", test.packed, err)
|
t.Fatalf("invalid hex %s: %v", test.packed, err)
|
||||||
}
|
}
|
||||||
outptr := reflect.New(reflect.TypeOf(test.unpacked))
|
out, err := abi.Unpack("method", encb)
|
||||||
err = abi.Unpack(outptr.Interface(), "method", encb)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("test %d (%v) failed: %v", i, test.def, err)
|
t.Errorf("test %d (%v) failed: %v", i, test.def, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
out := outptr.Elem().Interface()
|
if !reflect.DeepEqual(test.unpacked, ConvertType(out[0], test.unpacked)) {
|
||||||
if !reflect.DeepEqual(test.unpacked, out) {
|
t.Errorf("test %d (%v) failed: expected %v, got %v", i, test.def, test.unpacked, out[0])
|
||||||
t.Errorf("test %d (%v) failed: expected %v, got %v", i, test.def, test.unpacked, out)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -221,7 +219,7 @@ func TestLocalUnpackTests(t *testing.T) {
|
||||||
t.Fatalf("invalid hex %s: %v", test.enc, err)
|
t.Fatalf("invalid hex %s: %v", test.enc, err)
|
||||||
}
|
}
|
||||||
outptr := reflect.New(reflect.TypeOf(test.want))
|
outptr := reflect.New(reflect.TypeOf(test.want))
|
||||||
err = abi.Unpack(outptr.Interface(), "method", encb)
|
err = abi.UnpackIntoInterface(outptr.Interface(), "method", encb)
|
||||||
if err := test.checkError(err); err != nil {
|
if err := test.checkError(err); err != nil {
|
||||||
t.Errorf("test %d (%v) failed: %v", i, test.def, err)
|
t.Errorf("test %d (%v) failed: %v", i, test.def, err)
|
||||||
return
|
return
|
||||||
|
|
@ -234,7 +232,7 @@ func TestLocalUnpackTests(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackSetDynamicArrayOutput(t *testing.T) {
|
func TestUnpackIntoInterfaceSetDynamicArrayOutput(t *testing.T) {
|
||||||
abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`))
|
abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
@ -249,7 +247,7 @@ func TestUnpackSetDynamicArrayOutput(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
// test 32
|
// test 32
|
||||||
err = abi.Unpack(&out32, "testDynamicFixedBytes32", marshalledReturn32)
|
err = abi.UnpackIntoInterface(&out32, "testDynamicFixedBytes32", marshalledReturn32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -266,7 +264,7 @@ func TestUnpackSetDynamicArrayOutput(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// test 15
|
// test 15
|
||||||
err = abi.Unpack(&out15, "testDynamicFixedBytes32", marshalledReturn15)
|
err = abi.UnpackIntoInterface(&out15, "testDynamicFixedBytes32", marshalledReturn15)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -367,7 +365,7 @@ func TestMethodMultiReturn(t *testing.T) {
|
||||||
tc := tc
|
tc := tc
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
err := abi.Unpack(tc.dest, "multi", data)
|
err := abi.UnpackIntoInterface(tc.dest, "multi", data)
|
||||||
if tc.error == "" {
|
if tc.error == "" {
|
||||||
require.Nil(err, "Should be able to unpack method outputs.")
|
require.Nil(err, "Should be able to unpack method outputs.")
|
||||||
require.Equal(tc.expected, tc.dest)
|
require.Equal(tc.expected, tc.dest)
|
||||||
|
|
@ -390,7 +388,7 @@ func TestMultiReturnWithArray(t *testing.T) {
|
||||||
|
|
||||||
ret1, ret1Exp := new([3]uint64), [3]uint64{9, 9, 9}
|
ret1, ret1Exp := new([3]uint64), [3]uint64{9, 9, 9}
|
||||||
ret2, ret2Exp := new(uint64), uint64(8)
|
ret2, ret2Exp := new(uint64), uint64(8)
|
||||||
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
|
if err := abi.UnpackIntoInterface(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(*ret1, ret1Exp) {
|
if !reflect.DeepEqual(*ret1, ret1Exp) {
|
||||||
|
|
@ -414,7 +412,7 @@ func TestMultiReturnWithStringArray(t *testing.T) {
|
||||||
ret2, ret2Exp := new(common.Address), common.HexToAddress("ab1257528b3782fb40d7ed5f72e624b744dffb2f")
|
ret2, ret2Exp := new(common.Address), common.HexToAddress("ab1257528b3782fb40d7ed5f72e624b744dffb2f")
|
||||||
ret3, ret3Exp := new([2]string), [2]string{"Ethereum", "Hello, Ethereum!"}
|
ret3, ret3Exp := new([2]string), [2]string{"Ethereum", "Hello, Ethereum!"}
|
||||||
ret4, ret4Exp := new(bool), false
|
ret4, ret4Exp := new(bool), false
|
||||||
if err := abi.Unpack(&[]interface{}{ret1, ret2, ret3, ret4}, "multi", buff.Bytes()); err != nil {
|
if err := abi.UnpackIntoInterface(&[]interface{}{ret1, ret2, ret3, ret4}, "multi", buff.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(*ret1, ret1Exp) {
|
if !reflect.DeepEqual(*ret1, ret1Exp) {
|
||||||
|
|
@ -452,7 +450,7 @@ func TestMultiReturnWithStringSlice(t *testing.T) {
|
||||||
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000065")) // output[1][1] value
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000065")) // output[1][1] value
|
||||||
ret1, ret1Exp := new([]string), []string{"ethereum", "go-ethereum"}
|
ret1, ret1Exp := new([]string), []string{"ethereum", "go-ethereum"}
|
||||||
ret2, ret2Exp := new([]*big.Int), []*big.Int{big.NewInt(100), big.NewInt(101)}
|
ret2, ret2Exp := new([]*big.Int), []*big.Int{big.NewInt(100), big.NewInt(101)}
|
||||||
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
|
if err := abi.UnpackIntoInterface(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(*ret1, ret1Exp) {
|
if !reflect.DeepEqual(*ret1, ret1Exp) {
|
||||||
|
|
@ -492,7 +490,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
|
||||||
{{0x411, 0x412, 0x413}, {0x421, 0x422, 0x423}},
|
{{0x411, 0x412, 0x413}, {0x421, 0x422, 0x423}},
|
||||||
}
|
}
|
||||||
ret2, ret2Exp := new(uint64), uint64(0x9876)
|
ret2, ret2Exp := new(uint64), uint64(0x9876)
|
||||||
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
|
if err := abi.UnpackIntoInterface(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(*ret1, ret1Exp) {
|
if !reflect.DeepEqual(*ret1, ret1Exp) {
|
||||||
|
|
@ -531,7 +529,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000a"))
|
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000a"))
|
||||||
buff.Write(common.Hex2Bytes("0102000000000000000000000000000000000000000000000000000000000000"))
|
buff.Write(common.Hex2Bytes("0102000000000000000000000000000000000000000000000000000000000000"))
|
||||||
|
|
||||||
err = abi.Unpack(&mixedBytes, "mixedBytes", buff.Bytes())
|
err = abi.UnpackIntoInterface(&mixedBytes, "mixedBytes", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -546,7 +544,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
|
|
||||||
// marshal int
|
// marshal int
|
||||||
var Int *big.Int
|
var Int *big.Int
|
||||||
err = abi.Unpack(&Int, "int", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
err = abi.UnpackIntoInterface(&Int, "int", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -557,7 +555,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
|
|
||||||
// marshal bool
|
// marshal bool
|
||||||
var Bool bool
|
var Bool bool
|
||||||
err = abi.Unpack(&Bool, "bool", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
err = abi.UnpackIntoInterface(&Bool, "bool", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -574,7 +572,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
buff.Write(bytesOut)
|
buff.Write(bytesOut)
|
||||||
|
|
||||||
var Bytes []byte
|
var Bytes []byte
|
||||||
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
|
err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -590,7 +588,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
bytesOut = common.RightPadBytes([]byte("hello"), 64)
|
bytesOut = common.RightPadBytes([]byte("hello"), 64)
|
||||||
buff.Write(bytesOut)
|
buff.Write(bytesOut)
|
||||||
|
|
||||||
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
|
err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -606,7 +604,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
bytesOut = common.RightPadBytes([]byte("hello"), 64)
|
bytesOut = common.RightPadBytes([]byte("hello"), 64)
|
||||||
buff.Write(bytesOut)
|
buff.Write(bytesOut)
|
||||||
|
|
||||||
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
|
err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -616,7 +614,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// marshal dynamic bytes output empty
|
// marshal dynamic bytes output empty
|
||||||
err = abi.Unpack(&Bytes, "bytes", nil)
|
err = abi.UnpackIntoInterface(&Bytes, "bytes", nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("expected error")
|
t.Error("expected error")
|
||||||
}
|
}
|
||||||
|
|
@ -627,7 +625,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
|
||||||
buff.Write(common.RightPadBytes([]byte("hello"), 32))
|
buff.Write(common.RightPadBytes([]byte("hello"), 32))
|
||||||
|
|
||||||
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
|
err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -641,7 +639,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
buff.Write(common.RightPadBytes([]byte("hello"), 32))
|
buff.Write(common.RightPadBytes([]byte("hello"), 32))
|
||||||
|
|
||||||
var hash common.Hash
|
var hash common.Hash
|
||||||
err = abi.Unpack(&hash, "fixed", buff.Bytes())
|
err = abi.UnpackIntoInterface(&hash, "fixed", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -654,12 +652,12 @@ func TestUnmarshal(t *testing.T) {
|
||||||
// marshal error
|
// marshal error
|
||||||
buff.Reset()
|
buff.Reset()
|
||||||
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
|
||||||
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
|
err = abi.UnpackIntoInterface(&Bytes, "bytes", buff.Bytes())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("expected error")
|
t.Error("expected error")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = abi.Unpack(&Bytes, "multi", make([]byte, 64))
|
err = abi.UnpackIntoInterface(&Bytes, "multi", make([]byte, 64))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("expected error")
|
t.Error("expected error")
|
||||||
}
|
}
|
||||||
|
|
@ -670,7 +668,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000003"))
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000003"))
|
||||||
// marshal int array
|
// marshal int array
|
||||||
var intArray [3]*big.Int
|
var intArray [3]*big.Int
|
||||||
err = abi.Unpack(&intArray, "intArraySingle", buff.Bytes())
|
err = abi.UnpackIntoInterface(&intArray, "intArraySingle", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -691,7 +689,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000"))
|
buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000"))
|
||||||
|
|
||||||
var outAddr []common.Address
|
var outAddr []common.Address
|
||||||
err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes())
|
err = abi.UnpackIntoInterface(&outAddr, "addressSliceSingle", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("didn't expect error:", err)
|
t.Fatal("didn't expect error:", err)
|
||||||
}
|
}
|
||||||
|
|
@ -718,7 +716,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
A []common.Address
|
A []common.Address
|
||||||
B []common.Address
|
B []common.Address
|
||||||
}
|
}
|
||||||
err = abi.Unpack(&outAddrStruct, "addressSliceDouble", buff.Bytes())
|
err = abi.UnpackIntoInterface(&outAddrStruct, "addressSliceDouble", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("didn't expect error:", err)
|
t.Fatal("didn't expect error:", err)
|
||||||
}
|
}
|
||||||
|
|
@ -746,7 +744,7 @@ func TestUnmarshal(t *testing.T) {
|
||||||
buff.Reset()
|
buff.Reset()
|
||||||
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000100"))
|
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000100"))
|
||||||
|
|
||||||
err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes())
|
err = abi.UnpackIntoInterface(&outAddr, "addressSliceSingle", buff.Bytes())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected error:", err)
|
t.Fatal("expected error:", err)
|
||||||
}
|
}
|
||||||
|
|
@ -769,7 +767,7 @@ func TestUnpackTuple(t *testing.T) {
|
||||||
B *big.Int
|
B *big.Int
|
||||||
}{new(big.Int), new(big.Int)}
|
}{new(big.Int), new(big.Int)}
|
||||||
|
|
||||||
err = abi.Unpack(&v, "tuple", buff.Bytes())
|
err = abi.UnpackIntoInterface(&v, "tuple", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -841,7 +839,7 @@ func TestUnpackTuple(t *testing.T) {
|
||||||
A: big.NewInt(1),
|
A: big.NewInt(1),
|
||||||
}
|
}
|
||||||
|
|
||||||
err = abi.Unpack(&ret, "tuple", buff.Bytes())
|
err = abi.UnpackIntoInterface(&ret, "tuple", buff.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
ethereum "github.com/maticnetwork/bor"
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -39,7 +39,6 @@ const (
|
||||||
MimetypeDataWithValidator = "data/validator"
|
MimetypeDataWithValidator = "data/validator"
|
||||||
MimetypeTypedData = "data/typed"
|
MimetypeTypedData = "data/typed"
|
||||||
MimetypeClique = "application/x-clique-header"
|
MimetypeClique = "application/x-clique-header"
|
||||||
MimetypeBor = "application/x-bor-header"
|
|
||||||
MimetypeTextPlain = "text/plain"
|
MimetypeTextPlain = "text/plain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -89,7 +88,7 @@ type Wallet interface {
|
||||||
// to discover non zero accounts and automatically add them to list of tracked
|
// to discover non zero accounts and automatically add them to list of tracked
|
||||||
// accounts.
|
// accounts.
|
||||||
//
|
//
|
||||||
// Note, self derivaton will increment the last component of the specified path
|
// Note, self derivation will increment the last component of the specified path
|
||||||
// opposed to decending into a child path to allow discovering accounts starting
|
// opposed to decending into a child path to allow discovering accounts starting
|
||||||
// from non zero components.
|
// from non zero components.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTextHash(t *testing.T) {
|
func TestTextHash(t *testing.T) {
|
||||||
|
|
|
||||||
18
accounts/external/backend.go
vendored
18
accounts/external/backend.go
vendored
|
|
@ -21,15 +21,15 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
ethereum "github.com/maticnetwork/bor"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/maticnetwork/bor/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/maticnetwork/bor/signer/core"
|
"github.com/ethereum/go-ethereum/signer/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExternalBackend struct {
|
type ExternalBackend struct {
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mapset "github.com/deckarep/golang-set"
|
mapset "github.com/deckarep/golang-set"
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Minimum amount of time between cache reloads. This limit applies if the platform does
|
// Minimum amount of time between cache reloads. This limit applies if the platform does
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ import (
|
||||||
|
|
||||||
"github.com/cespare/cp"
|
"github.com/cespare/cp"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mapset "github.com/deckarep/golang-set"
|
mapset "github.com/deckarep/golang-set"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fileCache is a cache of files seen during scan of keystore.
|
// fileCache is a cache of files seen during scan of keystore.
|
||||||
type fileCache struct {
|
type fileCache struct {
|
||||||
all mapset.Set // Set of all files from the keystore folder
|
all mapset.Set // Set of all files from the keystore folder
|
||||||
lastMod time.Time // Last time instance when a file was modified
|
lastMod time.Time // Last time instance when a file was modified
|
||||||
mu sync.RWMutex
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// scan performs a new scan on the given directory, compares against the already
|
// scan performs a new scan on the given directory, compares against the already
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,11 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testSigData = make([]byte, 32)
|
var testSigData = make([]byte, 32)
|
||||||
|
|
@ -336,7 +336,9 @@ func TestWalletNotifications(t *testing.T) {
|
||||||
|
|
||||||
// Shut down the event collector and check events.
|
// Shut down the event collector and check events.
|
||||||
sub.Unsubscribe()
|
sub.Unsubscribe()
|
||||||
<-updates
|
for ev := range updates {
|
||||||
|
events = append(events, walletEvent{ev, ev.Wallet.Accounts()[0]})
|
||||||
|
}
|
||||||
checkAccounts(t, live, ks.Wallets())
|
checkAccounts(t, live, ks.Wallets())
|
||||||
checkEvents(t, wantEvents, events)
|
checkEvents(t, wantEvents, events)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,10 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
"golang.org/x/crypto/scrypt"
|
"golang.org/x/crypto/scrypt"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type keyStorePlain struct {
|
type keyStorePlain struct {
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func tmpKeyStoreIface(t *testing.T, encrypted bool) (dir string, ks keyStore) {
|
func tmpKeyStoreIface(t *testing.T, encrypted bool) (dir string, ks keyStore) {
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,10 @@ package keystore
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
ethereum "github.com/maticnetwork/bor"
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// keystoreWallet implements the accounts.Wallet interface for the original
|
// keystoreWallet implements the accounts.Wallet interface for the original
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ package keystore
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/rjeczalik/notify"
|
"github.com/rjeczalik/notify"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config contains the settings of the global account manager.
|
// Config contains the settings of the global account manager.
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,11 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
pcsc "github.com/gballet/go-libpcsclite"
|
pcsc "github.com/gballet/go-libpcsclite"
|
||||||
"github.com/maticnetwork/bor/accounts"
|
|
||||||
"github.com/maticnetwork/bor/common"
|
|
||||||
"github.com/maticnetwork/bor/event"
|
|
||||||
"github.com/maticnetwork/bor/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scheme is the URI prefix for smartcard wallets.
|
// Scheme is the URI prefix for smartcard wallets.
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import (
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
pcsc "github.com/gballet/go-libpcsclite"
|
pcsc "github.com/gballet/go-libpcsclite"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
|
||||||
"github.com/wsddn/go-ecdh"
|
"github.com/wsddn/go-ecdh"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
"golang.org/x/text/unicode/norm"
|
"golang.org/x/text/unicode/norm"
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,13 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
pcsc "github.com/gballet/go-libpcsclite"
|
pcsc "github.com/gballet/go-libpcsclite"
|
||||||
ethereum "github.com/maticnetwork/bor"
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
|
||||||
"github.com/maticnetwork/bor/common"
|
|
||||||
"github.com/maticnetwork/bor/core/types"
|
|
||||||
"github.com/maticnetwork/bor/crypto"
|
|
||||||
"github.com/maticnetwork/bor/log"
|
|
||||||
"github.com/status-im/keycard-go/derivationpath"
|
"github.com/status-im/keycard-go/derivationpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -637,7 +637,7 @@ func (w *Wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Accoun
|
||||||
// to discover non zero accounts and automatically add them to list of tracked
|
// to discover non zero accounts and automatically add them to list of tracked
|
||||||
// accounts.
|
// accounts.
|
||||||
//
|
//
|
||||||
// Note, self derivaton will increment the last component of the specified path
|
// Note, self derivation will increment the last component of the specified path
|
||||||
// opposed to decending into a child path to allow discovering accounts starting
|
// opposed to decending into a child path to allow discovering accounts starting
|
||||||
// from non zero components.
|
// from non zero components.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,10 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/karalabe/usb"
|
"github.com/karalabe/usb"
|
||||||
"github.com/maticnetwork/bor/accounts"
|
|
||||||
"github.com/maticnetwork/bor/event"
|
|
||||||
"github.com/maticnetwork/bor/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// LedgerScheme is the protocol scheme prefixing account and wallet URLs.
|
// LedgerScheme is the protocol scheme prefixing account and wallet URLs.
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,13 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/maticnetwork/bor/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ledgerOpcode is an enumeration encoding the supported Ledger opcodes.
|
// ledgerOpcode is an enumeration encoding the supported Ledger opcodes.
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,13 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/maticnetwork/bor/accounts"
|
|
||||||
"github.com/maticnetwork/bor/accounts/usbwallet/trezor"
|
|
||||||
"github.com/maticnetwork/bor/common"
|
|
||||||
"github.com/maticnetwork/bor/common/hexutil"
|
|
||||||
"github.com/maticnetwork/bor/core/types"
|
|
||||||
"github.com/maticnetwork/bor/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In
|
// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,13 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/karalabe/usb"
|
"github.com/karalabe/usb"
|
||||||
ethereum "github.com/maticnetwork/bor"
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
|
||||||
"github.com/maticnetwork/bor/common"
|
|
||||||
"github.com/maticnetwork/bor/core/types"
|
|
||||||
"github.com/maticnetwork/bor/crypto"
|
|
||||||
"github.com/maticnetwork/bor/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Maximum time between wallet health checks to detect USB unplugs.
|
// Maximum time between wallet health checks to detect USB unplugs.
|
||||||
|
|
@ -368,18 +368,22 @@ func (w *wallet) selfDerive() {
|
||||||
w.log.Warn("USB wallet nonce retrieval failed", "err", err)
|
w.log.Warn("USB wallet nonce retrieval failed", "err", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// If the next account is empty, stop self-derivation, but add for the last base path
|
// We've just self-derived a new account, start tracking it locally
|
||||||
|
// unless the account was empty.
|
||||||
|
path := make(accounts.DerivationPath, len(nextPaths[i]))
|
||||||
|
copy(path[:], nextPaths[i][:])
|
||||||
if balance.Sign() == 0 && nonce == 0 {
|
if balance.Sign() == 0 && nonce == 0 {
|
||||||
empty = true
|
empty = true
|
||||||
|
// If it indeed was empty, make a log output for it anyway. In the case
|
||||||
|
// of legacy-ledger, the first account on the legacy-path will
|
||||||
|
// be shown to the user, even if we don't actively track it
|
||||||
if i < len(nextAddrs)-1 {
|
if i < len(nextAddrs)-1 {
|
||||||
|
w.log.Info("Skipping trakcking first account on legacy path, use personal.deriveAccount(<url>,<path>, false) to track",
|
||||||
|
"path", path, "address", nextAddrs[i])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We've just self-derived a new account, start tracking it locally
|
|
||||||
path := make(accounts.DerivationPath, len(nextPaths[i]))
|
|
||||||
copy(path[:], nextPaths[i][:])
|
|
||||||
paths = append(paths, path)
|
paths = append(paths, path)
|
||||||
|
|
||||||
account := accounts.Account{
|
account := accounts.Account{
|
||||||
Address: nextAddrs[i],
|
Address: nextAddrs[i],
|
||||||
URL: accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
|
URL: accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
|
||||||
|
|
@ -489,7 +493,7 @@ func (w *wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Accoun
|
||||||
// to discover non zero accounts and automatically add them to list of tracked
|
// to discover non zero accounts and automatically add them to list of tracked
|
||||||
// accounts.
|
// accounts.
|
||||||
//
|
//
|
||||||
// Note, self derivaton will increment the last component of the specified path
|
// Note, self derivation will increment the last component of the specified path
|
||||||
// opposed to decending into a child path to allow discovering accounts starting
|
// opposed to decending into a child path to allow discovering accounts starting
|
||||||
// from non zero components.
|
// from non zero components.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ environment:
|
||||||
install:
|
install:
|
||||||
- git submodule update --init
|
- git submodule update --init
|
||||||
- rmdir C:\go /s /q
|
- rmdir C:\go /s /q
|
||||||
- appveyor DownloadFile https://dl.google.com/go/go1.14.2.windows-%GETH_ARCH%.zip
|
- appveyor DownloadFile https://dl.google.com/go/go1.15.windows-%GETH_ARCH%.zip
|
||||||
- 7z x go1.14.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
- 7z x go1.15.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||||
- go version
|
- go version
|
||||||
- gcc --version
|
- gcc --version
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# This file contains sha256 checksums of optional build dependencies.
|
# This file contains sha256 checksums of optional build dependencies.
|
||||||
|
|
||||||
98de84e69726a66da7b4e58eac41b99cbe274d7e8906eeb8a5b7eb0aadee7f7c go1.14.2.src.tar.gz
|
69438f7ed4f532154ffaf878f3dfd83747e7a00b70b3556eddabf7aaee28ac3a go1.15.src.tar.gz
|
||||||
|
|
||||||
d998a84eea42f2271aca792a7b027ca5c1edfcba229e8e5a844c9ac3f336df35 golangci-lint-1.27.0-linux-armv7.tar.gz
|
d998a84eea42f2271aca792a7b027ca5c1edfcba229e8e5a844c9ac3f336df35 golangci-lint-1.27.0-linux-armv7.tar.gz
|
||||||
bf781f05b0d393b4bf0a327d9e62926949a4f14d7774d950c4e009fc766ed1d4 golangci-lint.exe-1.27.0-windows-amd64.zip
|
bf781f05b0d393b4bf0a327d9e62926949a4f14d7774d950c4e009fc766ed1d4 golangci-lint.exe-1.27.0-windows-amd64.zip
|
||||||
|
|
|
||||||
28
build/ci.go
28
build/ci.go
|
|
@ -59,8 +59,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cespare/cp"
|
"github.com/cespare/cp"
|
||||||
"github.com/maticnetwork/bor/internal/build"
|
"github.com/ethereum/go-ethereum/internal/build"
|
||||||
"github.com/maticnetwork/bor/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -79,7 +79,6 @@ var (
|
||||||
executablePath("geth"),
|
executablePath("geth"),
|
||||||
executablePath("puppeth"),
|
executablePath("puppeth"),
|
||||||
executablePath("rlpdump"),
|
executablePath("rlpdump"),
|
||||||
executablePath("wnode"),
|
|
||||||
executablePath("clef"),
|
executablePath("clef"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,10 +108,6 @@ var (
|
||||||
BinaryName: "rlpdump",
|
BinaryName: "rlpdump",
|
||||||
Description: "Developer utility tool that prints RLP structures.",
|
Description: "Developer utility tool that prints RLP structures.",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
BinaryName: "wnode",
|
|
||||||
Description: "Ethereum Whisper diagnostic tool",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
BinaryName: "clef",
|
BinaryName: "clef",
|
||||||
Description: "Ethereum account management tool.",
|
Description: "Ethereum account management tool.",
|
||||||
|
|
@ -139,13 +134,14 @@ var (
|
||||||
// Note: zesty is unsupported because it was officially deprecated on Launchpad.
|
// Note: zesty is unsupported because it was officially deprecated on Launchpad.
|
||||||
// Note: artful is unsupported because it was officially deprecated on Launchpad.
|
// Note: artful is unsupported because it was officially deprecated on Launchpad.
|
||||||
// Note: cosmic is unsupported because it was officially deprecated on Launchpad.
|
// Note: cosmic is unsupported because it was officially deprecated on Launchpad.
|
||||||
|
// Note: disco is unsupported because it was officially deprecated on Launchpad.
|
||||||
debDistroGoBoots = map[string]string{
|
debDistroGoBoots = map[string]string{
|
||||||
"trusty": "golang-1.11",
|
"trusty": "golang-1.11",
|
||||||
"xenial": "golang-go",
|
"xenial": "golang-go",
|
||||||
"bionic": "golang-go",
|
"bionic": "golang-go",
|
||||||
"disco": "golang-go",
|
|
||||||
"eoan": "golang-go",
|
"eoan": "golang-go",
|
||||||
"focal": "golang-go",
|
"focal": "golang-go",
|
||||||
|
"groovy": "golang-go",
|
||||||
}
|
}
|
||||||
|
|
||||||
debGoBootPaths = map[string]string{
|
debGoBootPaths = map[string]string{
|
||||||
|
|
@ -215,9 +211,9 @@ func doInstall(cmdline []string) {
|
||||||
var minor int
|
var minor int
|
||||||
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
|
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
|
||||||
|
|
||||||
if minor < 11 {
|
if minor < 13 {
|
||||||
log.Println("You have Go version", runtime.Version())
|
log.Println("You have Go version", runtime.Version())
|
||||||
log.Println("go-ethereum requires at least Go version 1.11 and cannot")
|
log.Println("go-ethereum requires at least Go version 1.13 and cannot")
|
||||||
log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
|
log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
@ -233,6 +229,7 @@ func doInstall(cmdline []string) {
|
||||||
if runtime.GOARCH == "arm64" {
|
if runtime.GOARCH == "arm64" {
|
||||||
goinstall.Args = append(goinstall.Args, "-p", "1")
|
goinstall.Args = append(goinstall.Args, "-p", "1")
|
||||||
}
|
}
|
||||||
|
goinstall.Args = append(goinstall.Args, "-trimpath")
|
||||||
goinstall.Args = append(goinstall.Args, "-v")
|
goinstall.Args = append(goinstall.Args, "-v")
|
||||||
goinstall.Args = append(goinstall.Args, packages...)
|
goinstall.Args = append(goinstall.Args, packages...)
|
||||||
build.MustRun(goinstall)
|
build.MustRun(goinstall)
|
||||||
|
|
@ -241,6 +238,7 @@ func doInstall(cmdline []string) {
|
||||||
|
|
||||||
// Seems we are cross compiling, work around forbidden GOBIN
|
// Seems we are cross compiling, work around forbidden GOBIN
|
||||||
goinstall := goToolArch(*arch, *cc, "install", buildFlags(env)...)
|
goinstall := goToolArch(*arch, *cc, "install", buildFlags(env)...)
|
||||||
|
goinstall.Args = append(goinstall.Args, "-trimpath")
|
||||||
goinstall.Args = append(goinstall.Args, "-v")
|
goinstall.Args = append(goinstall.Args, "-v")
|
||||||
goinstall.Args = append(goinstall.Args, []string{"-buildmode", "archive"}...)
|
goinstall.Args = append(goinstall.Args, []string{"-buildmode", "archive"}...)
|
||||||
goinstall.Args = append(goinstall.Args, packages...)
|
goinstall.Args = append(goinstall.Args, packages...)
|
||||||
|
|
@ -833,11 +831,12 @@ func doAndroidArchive(cmdline []string) {
|
||||||
}
|
}
|
||||||
// Build the Android archive and Maven resources
|
// 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(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
|
||||||
build.MustRun(gomobileTool("bind", "-ldflags", "-s -w", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/maticnetwork/bor/mobile"))
|
build.MustRun(gomobileTool("bind", "-ldflags", "-s -w", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile"))
|
||||||
|
|
||||||
if *local {
|
if *local {
|
||||||
// If we're building locally, copy bundle to build dir and skip Maven
|
// If we're building locally, copy bundle to build dir and skip Maven
|
||||||
os.Rename("geth.aar", filepath.Join(GOBIN, "geth.aar"))
|
os.Rename("geth.aar", filepath.Join(GOBIN, "geth.aar"))
|
||||||
|
os.Rename("geth-sources.jar", filepath.Join(GOBIN, "geth-sources.jar"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
meta := newMavenMetadata(env)
|
meta := newMavenMetadata(env)
|
||||||
|
|
@ -884,11 +883,12 @@ func gomobileTool(subcmd string, args ...string) *exec.Cmd {
|
||||||
"PATH=" + GOBIN + string(os.PathListSeparator) + os.Getenv("PATH"),
|
"PATH=" + GOBIN + string(os.PathListSeparator) + os.Getenv("PATH"),
|
||||||
}
|
}
|
||||||
for _, e := range os.Environ() {
|
for _, e := range os.Environ() {
|
||||||
if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "PATH=") {
|
if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "PATH=") || strings.HasPrefix(e, "GOBIN=") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cmd.Env = append(cmd.Env, e)
|
cmd.Env = append(cmd.Env, e)
|
||||||
}
|
}
|
||||||
|
cmd.Env = append(cmd.Env, "GOBIN="+GOBIN)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -953,11 +953,11 @@ func doXCodeFramework(cmdline []string) {
|
||||||
// Build the iOS XCode framework
|
// Build the iOS XCode framework
|
||||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
|
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
|
||||||
build.MustRun(gomobileTool("init"))
|
build.MustRun(gomobileTool("init"))
|
||||||
bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "-v", "github.com/maticnetwork/bor/mobile")
|
bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||||
|
|
||||||
if *local {
|
if *local {
|
||||||
// If we're building locally, use the build folder and stop afterwards
|
// If we're building locally, use the build folder and stop afterwards
|
||||||
bind.Dir, _ = filepath.Abs(GOBIN)
|
bind.Dir = GOBIN
|
||||||
build.MustRun(bind)
|
build.MustRun(bind)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ Maintainer: {{.Author}}
|
||||||
Build-Depends: debhelper (>= 8.0.0), {{.GoBootPackage}}
|
Build-Depends: debhelper (>= 8.0.0), {{.GoBootPackage}}
|
||||||
Standards-Version: 3.9.5
|
Standards-Version: 3.9.5
|
||||||
Homepage: https://ethereum.org
|
Homepage: https://ethereum.org
|
||||||
Vcs-Git: git://github.com/maticnetwork/bor.git
|
Vcs-Git: git://github.com/ethereum/go-ethereum.git
|
||||||
Vcs-Browser: https://github.com/maticnetwork/bor
|
Vcs-Browser: https://github.com/ethereum/go-ethereum
|
||||||
|
|
||||||
Package: {{.Name}}
|
Package: {{.Name}}
|
||||||
Architecture: any
|
Architecture: any
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
<name>Android Ethereum Client</name>
|
<name>Android Ethereum Client</name>
|
||||||
<description>Android port of the go-ethereum libraries and node</description>
|
<description>Android port of the go-ethereum libraries and node</description>
|
||||||
<url>https://github.com/maticnetwork/bor</url>
|
<url>https://github.com/ethereum/go-ethereum</url>
|
||||||
<inceptionYear>2015</inceptionYear>
|
<inceptionYear>2015</inceptionYear>
|
||||||
|
|
||||||
<licenses>
|
<licenses>
|
||||||
|
|
@ -48,10 +48,10 @@
|
||||||
|
|
||||||
<issueManagement>
|
<issueManagement>
|
||||||
<system>GitHub Issues</system>
|
<system>GitHub Issues</system>
|
||||||
<url>https://github.com/maticnetwork/bor/issues/</url>
|
<url>https://github.com/ethereum/go-ethereum/issues/</url>
|
||||||
</issueManagement>
|
</issueManagement>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<url>https://github.com/maticnetwork/bor</url>
|
<url>https://github.com/ethereum/go-ethereum</url>
|
||||||
</scm>
|
</scm>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ InstallDir "$InstDir"
|
||||||
OutFile "${OUTPUTFILE}" # set through command line arguments
|
OutFile "${OUTPUTFILE}" # set through command line arguments
|
||||||
|
|
||||||
# Links for "Add/Remove Programs"
|
# Links for "Add/Remove Programs"
|
||||||
!define HELPURL "https://github.com/maticnetwork/bor/issues"
|
!define HELPURL "https://github.com/ethereum/go-ethereum/issues"
|
||||||
!define UPDATEURL "https://github.com/maticnetwork/bor/releases"
|
!define UPDATEURL "https://github.com/ethereum/go-ethereum/releases"
|
||||||
!define ABOUTURL "https://github.com/maticnetwork/bor#ethereum-go"
|
!define ABOUTURL "https://github.com/ethereum/go-ethereum#ethereum-go"
|
||||||
!define /date NOW "%Y%m%d"
|
!define /date NOW "%Y%m%d"
|
||||||
|
|
||||||
PageEx license
|
PageEx license
|
||||||
|
|
@ -34,8 +34,8 @@ Section "Geth" GETH_IDX
|
||||||
SimpleFC::AdvAddRule "Geth UDP discovery (UDP:30303)" "" 17 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)
|
# Set default IPC endpoint (https://github.com/ethereum/EIPs/issues/147)
|
||||||
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\bor.ipc"
|
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc"
|
||||||
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\bor.ipc"
|
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\geth.ipc"
|
||||||
|
|
||||||
# Add instdir to PATH
|
# Add instdir to PATH
|
||||||
Push "$INSTDIR"
|
Push "$INSTDIR"
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ Section "Uninstall"
|
||||||
SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)"
|
SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)"
|
||||||
|
|
||||||
# Remove IPC endpoint (https://github.com/ethereum/EIPs/issues/147)
|
# Remove IPC endpoint (https://github.com/ethereum/EIPs/issues/147)
|
||||||
${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\bor.ipc"
|
${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc"
|
||||||
|
|
||||||
# Remove install directory from PATH
|
# Remove install directory from PATH
|
||||||
Push "$INSTDIR"
|
Push "$INSTDIR"
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@ Pod::Spec.new do |spec|
|
||||||
spec.name = 'Geth'
|
spec.name = 'Geth'
|
||||||
spec.version = '{{.Version}}'
|
spec.version = '{{.Version}}'
|
||||||
spec.license = { :type => 'GNU Lesser General Public License, Version 3.0' }
|
spec.license = { :type => 'GNU Lesser General Public License, Version 3.0' }
|
||||||
spec.homepage = 'https://github.com/maticnetwork/bor'
|
spec.homepage = 'https://github.com/ethereum/go-ethereum'
|
||||||
spec.authors = { {{range .Contributors}}
|
spec.authors = { {{range .Contributors}}
|
||||||
'{{.Name}}' => '{{.Email}}',{{end}}
|
'{{.Name}}' => '{{.Email}}',{{end}}
|
||||||
}
|
}
|
||||||
spec.summary = 'iOS Ethereum Client'
|
spec.summary = 'iOS Ethereum Client'
|
||||||
spec.source = { :git => 'https://github.com/maticnetwork/bor.git', :commit => '{{.Commit}}' }
|
spec.source = { :git => 'https://github.com/ethereum/go-ethereum.git', :commit => '{{.Commit}}' }
|
||||||
|
|
||||||
spec.platform = :ios
|
spec.platform = :ios
|
||||||
spec.ios.deployment_target = '9.0'
|
spec.ios.deployment_target = '9.0'
|
||||||
|
|
|
||||||
32
circle.yml
Normal file
32
circle.yml
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
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
|
||||||
|
|
@ -23,8 +23,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/signer/core"
|
"github.com/ethereum/go-ethereum/signer/core"
|
||||||
"github.com/maticnetwork/bor/signer/fourbyte"
|
"github.com/ethereum/go-ethereum/signer/fourbyte"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,13 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/maticnetwork/bor/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/maticnetwork/bor/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/maticnetwork/bor/common/compiler"
|
"github.com/ethereum/go-ethereum/common/compiler"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -100,7 +101,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
app = utils.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool")
|
app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool")
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
abiFlag,
|
abiFlag,
|
||||||
binFlag,
|
binFlag,
|
||||||
|
|
@ -117,7 +118,7 @@ func init() {
|
||||||
aliasFlag,
|
aliasFlag,
|
||||||
}
|
}
|
||||||
app.Action = utils.MigrateFlags(abigen)
|
app.Action = utils.MigrateFlags(abigen)
|
||||||
cli.CommandHelpTemplate = utils.OriginCommandHelpTemplate
|
cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
func abigen(c *cli.Context) error {
|
func abigen(c *cli.Context) error {
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,14 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/maticnetwork/bor/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/maticnetwork/bor/p2p/discv5"
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/maticnetwork/bor/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/maticnetwork/bor/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
"github.com/maticnetwork/bor/p2p/netutil"
|
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
@ -44,7 +44,7 @@ func main() {
|
||||||
natdesc = flag.String("nat", "none", "port mapping mechanism (any|none|upnp|pmp|extip:<IP>)")
|
natdesc = flag.String("nat", "none", "port mapping mechanism (any|none|upnp|pmp|extip:<IP>)")
|
||||||
netrestrict = flag.String("netrestrict", "", "restrict network communication to the given IP networks (CIDR masks)")
|
netrestrict = flag.String("netrestrict", "", "restrict network communication to the given IP networks (CIDR masks)")
|
||||||
runv5 = flag.Bool("v5", false, "run a v5 topic discovery bootnode")
|
runv5 = flag.Bool("v5", false, "run a v5 topic discovery bootnode")
|
||||||
verbosity = flag.Int("verbosity", int(log.LvlInfo), "log verbosity (0-9)")
|
verbosity = flag.Int("verbosity", int(log.LvlInfo), "log verbosity (0-5)")
|
||||||
vmodule = flag.String("vmodule", "", "log verbosity pattern")
|
vmodule = flag.String("vmodule", "", "log verbosity pattern")
|
||||||
|
|
||||||
nodeKey *ecdsa.PrivateKey
|
nodeKey *ecdsa.PrivateKey
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,15 @@ package main
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/maticnetwork/bor/accounts/external"
|
"github.com/ethereum/go-ethereum/accounts/external"
|
||||||
"github.com/maticnetwork/bor/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/contracts/checkpointoracle"
|
"github.com/ethereum/go-ethereum/contracts/checkpointoracle"
|
||||||
"github.com/maticnetwork/bor/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
"github.com/maticnetwork/bor/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/maticnetwork/bor/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,17 +25,17 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/maticnetwork/bor/contracts/checkpointoracle"
|
"github.com/ethereum/go-ethereum/contracts/checkpointoracle"
|
||||||
"github.com/maticnetwork/bor/contracts/checkpointoracle/contract"
|
"github.com/ethereum/go-ethereum/contracts/checkpointoracle/contract"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/maticnetwork/bor/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/maticnetwork/bor/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/cmd/utils"
|
"github.com/ethereum/go-ethereum/common/fdlimit"
|
||||||
"github.com/maticnetwork/bor/common/fdlimit"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ var (
|
||||||
var app *cli.App
|
var app *cli.App
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
app = utils.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool")
|
app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool")
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []cli.Command{
|
||||||
commandStatus,
|
commandStatus,
|
||||||
commandDeploy,
|
commandDeploy,
|
||||||
|
|
@ -48,7 +48,7 @@ func init() {
|
||||||
oracleFlag,
|
oracleFlag,
|
||||||
nodeURLFlag,
|
nodeURLFlag,
|
||||||
}
|
}
|
||||||
cli.CommandHelpTemplate = utils.OriginCommandHelpTemplate
|
cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commonly used command line flags.
|
// Commonly used command line flags.
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,12 @@ GLOBAL OPTIONS:
|
||||||
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
|
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
|
||||||
--nousb Disables monitoring for and managing USB hardware wallets
|
--nousb Disables monitoring for and managing USB hardware wallets
|
||||||
--pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")
|
--pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")
|
||||||
--rpcaddr value HTTP-RPC server listening interface (default: "localhost")
|
--http.addr value HTTP-RPC server listening interface (default: "localhost")
|
||||||
--rpcvhosts value Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. (default: "localhost")
|
--http.vhosts value Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. (default: "localhost")
|
||||||
--ipcdisable Disable the IPC-RPC server
|
--ipcdisable Disable the IPC-RPC server
|
||||||
--ipcpath Filename for IPC socket/pipe within the datadir (explicit paths escape it)
|
--ipcpath Filename for IPC socket/pipe within the datadir (explicit paths escape it)
|
||||||
--rpc Enable the HTTP-RPC server
|
--http Enable the HTTP-RPC server
|
||||||
--rpcport value HTTP-RPC server listening port (default: 8550)
|
--http.port value HTTP-RPC server listening port (default: 8550)
|
||||||
--signersecret value A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash
|
--signersecret value A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash
|
||||||
--4bytedb-custom value File used for writing new 4byte-identifiers submitted via API (default: "./4byte-custom.json")
|
--4bytedb-custom value File used for writing new 4byte-identifiers submitted via API (default: "./4byte-custom.json")
|
||||||
--auditlog value File used to emit audit logs. Set to "" to disable (default: "audit.log")
|
--auditlog value File used to emit audit logs. Set to "" to disable (default: "audit.log")
|
||||||
|
|
@ -113,7 +113,7 @@ Some snags and todos
|
||||||
|
|
||||||
### External API
|
### External API
|
||||||
|
|
||||||
Clef listens to HTTP requests on `rpcaddr`:`rpcport` (or to IPC on `ipcpath`), with the same JSON-RPC standard as Geth. The messages are expected to be [JSON-RPC 2.0 standard](https://www.jsonrpc.org/specification).
|
Clef listens to HTTP requests on `http.addr`:`http.port` (or to IPC on `ipcpath`), with the same JSON-RPC standard as Geth. The messages are expected to be [JSON-RPC 2.0 standard](https://www.jsonrpc.org/specification).
|
||||||
|
|
||||||
Some of these calls can require user interaction. Clients must be aware that responses may be delayed significantly or may never be received if a user decides to ignore the confirmation request.
|
Some of these calls can require user interaction. Clients must be aware that responses may be delayed significantly or may never be received if a user decides to ignore the confirmation request.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ with minimal requirements.
|
||||||
On the `client` qube, we need to create a listener which will receive the request from the Dapp, and proxy it.
|
On the `client` qube, we need to create a listener which will receive the request from the Dapp, and proxy it.
|
||||||
|
|
||||||
|
|
||||||
[qubes-client.py](qubes/client/qubes-client.py):
|
[qubes-client.py](qubes/qubes-client.py):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,64 @@ TL;DR: Given a version number MAJOR.MINOR.PATCH, increment the:
|
||||||
|
|
||||||
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
|
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
|
||||||
|
|
||||||
|
### 6.1.0
|
||||||
|
|
||||||
|
The API-method `account_signGnosisSafeTx` was added. This method takes two parameters,
|
||||||
|
`[address, safeTx]`. The latter, `safeTx`, can be copy-pasted from the gnosis relay. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "account_signGnosisSafeTx",
|
||||||
|
"params": ["0xfd1c4226bfD1c436672092F4eCbfC270145b7256",
|
||||||
|
{
|
||||||
|
"safe": "0x25a6c4BBd32B2424A9c99aEB0584Ad12045382B3",
|
||||||
|
"to": "0xB372a646f7F05Cc1785018dBDA7EBc734a2A20E2",
|
||||||
|
"value": "20000000000000000",
|
||||||
|
"data": null,
|
||||||
|
"operation": 0,
|
||||||
|
"gasToken": "0x0000000000000000000000000000000000000000",
|
||||||
|
"safeTxGas": 27845,
|
||||||
|
"baseGas": 0,
|
||||||
|
"gasPrice": "0",
|
||||||
|
"refundReceiver": "0x0000000000000000000000000000000000000000",
|
||||||
|
"nonce": 2,
|
||||||
|
"executionDate": null,
|
||||||
|
"submissionDate": "2020-09-15T21:54:49.617634Z",
|
||||||
|
"modified": "2020-09-15T21:54:49.617634Z",
|
||||||
|
"blockNumber": null,
|
||||||
|
"transactionHash": null,
|
||||||
|
"safeTxHash": "0x2edfbd5bc113ff18c0631595db32eb17182872d88d9bf8ee4d8c2dd5db6d95e2",
|
||||||
|
"executor": null,
|
||||||
|
"isExecuted": false,
|
||||||
|
"isSuccessful": null,
|
||||||
|
"ethGasPrice": null,
|
||||||
|
"gasUsed": null,
|
||||||
|
"fee": null,
|
||||||
|
"origin": null,
|
||||||
|
"dataDecoded": null,
|
||||||
|
"confirmationsRequired": null,
|
||||||
|
"confirmations": [
|
||||||
|
{
|
||||||
|
"owner": "0xAd2e180019FCa9e55CADe76E4487F126Fd08DA34",
|
||||||
|
"submissionDate": "2020-09-15T21:54:49.663299Z",
|
||||||
|
"transactionHash": null,
|
||||||
|
"confirmationType": "CONFIRMATION",
|
||||||
|
"signature": "0x95a7250bb645f831c86defc847350e7faff815b2fb586282568e96cc859e39315876db20a2eed5f7a0412906ec5ab57652a6f645ad4833f345bda059b9da2b821c",
|
||||||
|
"signatureType": "EOA"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"signatures": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": 67
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Not all fields are required, though. This method is really just a UX helper, which massages the
|
||||||
|
input to conform to the `EIP-712` [specification](https://docs.gnosis.io/safe/docs/contracts_tx_execution/#transaction-hash)
|
||||||
|
for the Gnosis Safe, and making the output be directly importable to by a relay service.
|
||||||
|
|
||||||
|
|
||||||
### 6.0.0
|
### 6.0.0
|
||||||
|
|
||||||
|
|
|
||||||
154
cmd/clef/main.go
154
cmd/clef/main.go
|
|
@ -29,29 +29,31 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"os/user"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/maticnetwork/bor/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/maticnetwork/bor/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/maticnetwork/bor/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/maticnetwork/bor/node"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/maticnetwork/bor/params"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/maticnetwork/bor/rlp"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/maticnetwork/bor/rpc"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/maticnetwork/bor/signer/core"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/maticnetwork/bor/signer/fourbyte"
|
"github.com/ethereum/go-ethereum/signer/core"
|
||||||
"github.com/maticnetwork/bor/signer/rules"
|
"github.com/ethereum/go-ethereum/signer/fourbyte"
|
||||||
"github.com/maticnetwork/bor/signer/storage"
|
"github.com/ethereum/go-ethereum/signer/rules"
|
||||||
|
"github.com/ethereum/go-ethereum/signer/storage"
|
||||||
|
|
||||||
colorable "github.com/mattn/go-colorable"
|
colorable "github.com/mattn/go-colorable"
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
|
@ -101,10 +103,15 @@ var (
|
||||||
Usage: "Chain id to use for signing (1=mainnet, 3=Ropsten, 4=Rinkeby, 5=Goerli)",
|
Usage: "Chain id to use for signing (1=mainnet, 3=Ropsten, 4=Rinkeby, 5=Goerli)",
|
||||||
}
|
}
|
||||||
rpcPortFlag = cli.IntFlag{
|
rpcPortFlag = cli.IntFlag{
|
||||||
Name: "rpcport",
|
Name: "http.port",
|
||||||
Usage: "HTTP-RPC server listening port",
|
Usage: "HTTP-RPC server listening port",
|
||||||
Value: node.DefaultHTTPPort + 5,
|
Value: node.DefaultHTTPPort + 5,
|
||||||
}
|
}
|
||||||
|
legacyRPCPortFlag = cli.IntFlag{
|
||||||
|
Name: "rpcport",
|
||||||
|
Usage: "HTTP-RPC server listening port (Deprecated, please use --http.port).",
|
||||||
|
Value: node.DefaultHTTPPort + 5,
|
||||||
|
}
|
||||||
signerSecretFlag = cli.StringFlag{
|
signerSecretFlag = cli.StringFlag{
|
||||||
Name: "signersecret",
|
Name: "signersecret",
|
||||||
Usage: "A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash",
|
Usage: "A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash",
|
||||||
|
|
@ -215,6 +222,42 @@ The gendoc generates example structures of the json-rpc communication types.
|
||||||
`}
|
`}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AppHelpFlagGroups is the application flags, grouped by functionality.
|
||||||
|
var AppHelpFlagGroups = []flags.FlagGroup{
|
||||||
|
{
|
||||||
|
Name: "FLAGS",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
logLevelFlag,
|
||||||
|
keystoreFlag,
|
||||||
|
configdirFlag,
|
||||||
|
chainIdFlag,
|
||||||
|
utils.LightKDFFlag,
|
||||||
|
utils.NoUSBFlag,
|
||||||
|
utils.SmartCardDaemonPathFlag,
|
||||||
|
utils.HTTPListenAddrFlag,
|
||||||
|
utils.HTTPVirtualHostsFlag,
|
||||||
|
utils.IPCDisabledFlag,
|
||||||
|
utils.IPCPathFlag,
|
||||||
|
utils.HTTPEnabledFlag,
|
||||||
|
rpcPortFlag,
|
||||||
|
signerSecretFlag,
|
||||||
|
customDBFlag,
|
||||||
|
auditLogFlag,
|
||||||
|
ruleFlag,
|
||||||
|
stdiouiFlag,
|
||||||
|
testFlag,
|
||||||
|
advancedMode,
|
||||||
|
acceptFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ALIASED (deprecated)",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
legacyRPCPortFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
app.Name = "Clef"
|
app.Name = "Clef"
|
||||||
app.Usage = "Manage Ethereum account operations"
|
app.Usage = "Manage Ethereum account operations"
|
||||||
|
|
@ -240,6 +283,7 @@ func init() {
|
||||||
testFlag,
|
testFlag,
|
||||||
advancedMode,
|
advancedMode,
|
||||||
acceptFlag,
|
acceptFlag,
|
||||||
|
legacyRPCPortFlag,
|
||||||
}
|
}
|
||||||
app.Action = signer
|
app.Action = signer
|
||||||
app.Commands = []cli.Command{initCommand,
|
app.Commands = []cli.Command{initCommand,
|
||||||
|
|
@ -248,7 +292,41 @@ func init() {
|
||||||
delCredentialCommand,
|
delCredentialCommand,
|
||||||
newAccountCommand,
|
newAccountCommand,
|
||||||
gendocCommand}
|
gendocCommand}
|
||||||
cli.CommandHelpTemplate = utils.OriginCommandHelpTemplate
|
cli.CommandHelpTemplate = flags.CommandHelpTemplate
|
||||||
|
// Override the default app help template
|
||||||
|
cli.AppHelpTemplate = flags.ClefAppHelpTemplate
|
||||||
|
|
||||||
|
// Override the default app help printer, but only for the global app help
|
||||||
|
originalHelpPrinter := cli.HelpPrinter
|
||||||
|
cli.HelpPrinter = func(w io.Writer, tmpl string, data interface{}) {
|
||||||
|
if tmpl == flags.ClefAppHelpTemplate {
|
||||||
|
// Render out custom usage screen
|
||||||
|
originalHelpPrinter(w, tmpl, flags.HelpData{App: data, FlagGroups: AppHelpFlagGroups})
|
||||||
|
} else if tmpl == flags.CommandHelpTemplate {
|
||||||
|
// Iterate over all command specific flags and categorize them
|
||||||
|
categorized := make(map[string][]cli.Flag)
|
||||||
|
for _, flag := range data.(cli.Command).Flags {
|
||||||
|
if _, ok := categorized[flag.String()]; !ok {
|
||||||
|
categorized[flags.FlagCategory(flag, AppHelpFlagGroups)] = append(categorized[flags.FlagCategory(flag, AppHelpFlagGroups)], flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort to get a stable ordering
|
||||||
|
sorted := make([]flags.FlagGroup, 0, len(categorized))
|
||||||
|
for cat, flgs := range categorized {
|
||||||
|
sorted = append(sorted, flags.FlagGroup{Name: cat, Flags: flgs})
|
||||||
|
}
|
||||||
|
sort.Sort(flags.ByCategory(sorted))
|
||||||
|
|
||||||
|
// add sorted array to data and render with default printer
|
||||||
|
originalHelpPrinter(w, tmpl, map[string]interface{}{
|
||||||
|
"cmd": data,
|
||||||
|
"categorizedFlags": sorted,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
originalHelpPrinter(w, tmpl, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
@ -587,8 +665,8 @@ func signer(c *cli.Context) error {
|
||||||
Version: "1.0"},
|
Version: "1.0"},
|
||||||
}
|
}
|
||||||
if c.GlobalBool(utils.HTTPEnabledFlag.Name) {
|
if c.GlobalBool(utils.HTTPEnabledFlag.Name) {
|
||||||
vhosts := splitAndTrim(c.GlobalString(utils.HTTPVirtualHostsFlag.Name))
|
vhosts := utils.SplitAndTrim(c.GlobalString(utils.HTTPVirtualHostsFlag.Name))
|
||||||
cors := splitAndTrim(c.GlobalString(utils.HTTPCORSDomainFlag.Name))
|
cors := utils.SplitAndTrim(c.GlobalString(utils.HTTPCORSDomainFlag.Name))
|
||||||
|
|
||||||
srv := rpc.NewServer()
|
srv := rpc.NewServer()
|
||||||
err := node.RegisterApisFromWhitelist(rpcAPI, []string{"account"}, srv, false)
|
err := node.RegisterApisFromWhitelist(rpcAPI, []string{"account"}, srv, false)
|
||||||
|
|
@ -597,8 +675,17 @@ func signer(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
handler := node.NewHTTPHandlerStack(srv, cors, vhosts)
|
handler := node.NewHTTPHandlerStack(srv, cors, vhosts)
|
||||||
|
|
||||||
|
// set port
|
||||||
|
port := c.Int(rpcPortFlag.Name)
|
||||||
|
if c.GlobalIsSet(legacyRPCPortFlag.Name) {
|
||||||
|
if !c.GlobalIsSet(rpcPortFlag.Name) {
|
||||||
|
port = c.Int(legacyRPCPortFlag.Name)
|
||||||
|
}
|
||||||
|
log.Warn("The flag --rpcport is deprecated and will be removed in the future, please use --http.port")
|
||||||
|
}
|
||||||
|
|
||||||
// start http server
|
// start http server
|
||||||
httpEndpoint := fmt.Sprintf("%s:%d", c.GlobalString(utils.HTTPListenAddrFlag.Name), c.Int(rpcPortFlag.Name))
|
httpEndpoint := fmt.Sprintf("%s:%d", c.GlobalString(utils.HTTPListenAddrFlag.Name), port)
|
||||||
httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler)
|
httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Could not start RPC api: %v", err)
|
utils.Fatalf("Could not start RPC api: %v", err)
|
||||||
|
|
@ -648,21 +735,11 @@ func signer(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitAndTrim splits input separated by a comma
|
|
||||||
// and trims excessive white space from the substrings.
|
|
||||||
func splitAndTrim(input string) []string {
|
|
||||||
result := strings.Split(input, ",")
|
|
||||||
for i, r := range result {
|
|
||||||
result[i] = strings.TrimSpace(r)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultConfigDir is the default config directory to use for the vaults and other
|
// DefaultConfigDir is the default config directory to use for the vaults and other
|
||||||
// persistence requirements.
|
// persistence requirements.
|
||||||
func DefaultConfigDir() string {
|
func DefaultConfigDir() string {
|
||||||
// Try to place the data folder in the user's home dir
|
// Try to place the data folder in the user's home dir
|
||||||
home := homeDir()
|
home := utils.HomeDir()
|
||||||
if home != "" {
|
if home != "" {
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
return filepath.Join(home, "Library", "Signer")
|
return filepath.Join(home, "Library", "Signer")
|
||||||
|
|
@ -681,15 +758,6 @@ func DefaultConfigDir() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func homeDir() string {
|
|
||||||
if home := os.Getenv("HOME"); home != "" {
|
|
||||||
return home
|
|
||||||
}
|
|
||||||
if usr, err := user.Current(); err == nil {
|
|
||||||
return usr.HomeDir
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
func readMasterKey(ctx *cli.Context, ui core.UIClientAPI) ([]byte, error) {
|
func readMasterKey(ctx *cli.Context, ui core.UIClientAPI) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
file string
|
file string
|
||||||
|
|
|
||||||
86
cmd/devp2p/README.md
Normal file
86
cmd/devp2p/README.md
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
# The devp2p command
|
||||||
|
|
||||||
|
The devp2p command line tool is a utility for low-level peer-to-peer debugging and
|
||||||
|
protocol development purposes. It can do many things.
|
||||||
|
|
||||||
|
### ENR Decoding
|
||||||
|
|
||||||
|
Use `devp2p enrdump <base64>` to verify and display an Ethereum Node Record.
|
||||||
|
|
||||||
|
### Node Key Management
|
||||||
|
|
||||||
|
The `devp2p key ...` command family deals with node key files.
|
||||||
|
|
||||||
|
Run `devp2p key generate mynode.key` to create a new node key in the `mynode.key` file.
|
||||||
|
|
||||||
|
Run `devp2p key to-enode mynode.key -ip 127.0.0.1 -tcp 30303` to create an enode:// URL
|
||||||
|
corresponding to the given node key and address information.
|
||||||
|
|
||||||
|
### Maintaining DNS Discovery Node Lists
|
||||||
|
|
||||||
|
The devp2p command can create and publish DNS discovery node lists.
|
||||||
|
|
||||||
|
Run `devp2p dns sign <directory>` to update the signature of a DNS discovery tree.
|
||||||
|
|
||||||
|
Run `devp2p dns sync <enrtree-URL>` to download a complete DNS discovery tree.
|
||||||
|
|
||||||
|
Run `devp2p dns to-cloudflare <directory>` to publish a tree to CloudFlare DNS.
|
||||||
|
|
||||||
|
Run `devp2p dns to-route53 <directory>` to publish a tree to Amazon Route53.
|
||||||
|
|
||||||
|
You can find more information about these commands in the [DNS Discovery Setup Guide][dns-tutorial].
|
||||||
|
|
||||||
|
### Discovery v4 Utilities
|
||||||
|
|
||||||
|
The `devp2p discv4 ...` command family deals with the [Node Discovery v4][discv4]
|
||||||
|
protocol.
|
||||||
|
|
||||||
|
Run `devp2p discv4 ping <enode/ENR>` to ping a node.
|
||||||
|
|
||||||
|
Run `devp2p discv4 resolve <enode/ENR>` to find the most recent node record of a node in
|
||||||
|
the DHT.
|
||||||
|
|
||||||
|
Run `devp2p discv4 crawl <nodes.json path>` to create or update a JSON node set.
|
||||||
|
|
||||||
|
### Discovery v5 Utilities
|
||||||
|
|
||||||
|
The `devp2p discv5 ...` command family deals with the [Node Discovery v5][discv5]
|
||||||
|
protocol. This protocol is currently under active development.
|
||||||
|
|
||||||
|
Run `devp2p discv5 ping <ENR>` to ping a node.
|
||||||
|
|
||||||
|
Run `devp2p discv5 resolve <ENR>` to find the most recent node record of a node in
|
||||||
|
the discv5 DHT.
|
||||||
|
|
||||||
|
Run `devp2p discv5 listen` to run a Discovery v5 node.
|
||||||
|
|
||||||
|
Run `devp2p discv5 crawl <nodes.json path>` to create or update a JSON node set containing
|
||||||
|
discv5 nodes.
|
||||||
|
|
||||||
|
### Discovery Test Suites
|
||||||
|
|
||||||
|
The devp2p command also contains interactive test suites for Discovery v4 and Discovery
|
||||||
|
v5.
|
||||||
|
|
||||||
|
To run these tests against your implementation, you need to set up a networking
|
||||||
|
environment where two separate UDP listening addresses are available on the same machine.
|
||||||
|
The two listening addresses must also be routed such that they are able to reach the node
|
||||||
|
you want to test.
|
||||||
|
|
||||||
|
For example, if you want to run the test on your local host, and the node under test is
|
||||||
|
also on the local host, you need to assign two IP addresses (or a larger range) to your
|
||||||
|
loopback interface. On macOS, this can be done by executing the following command:
|
||||||
|
|
||||||
|
sudo ifconfig lo0 add 127.0.0.2
|
||||||
|
|
||||||
|
You can now run either test suite as follows: Start the node under test first, ensuring
|
||||||
|
that it won't talk to the Internet (i.e. disable bootstrapping). An easy way to prevent
|
||||||
|
unintended connections to the global DHT is listening on `127.0.0.1`.
|
||||||
|
|
||||||
|
Now get the ENR of your node and store it in the `NODE` environment variable.
|
||||||
|
|
||||||
|
Start the test by running `devp2p discv5 test -listen1 127.0.0.1 -listen2 127.0.0.2 $NODE`.
|
||||||
|
|
||||||
|
[dns-tutorial]: https://geth.ethereum.org/docs/developers/dns-discovery-setup
|
||||||
|
[discv4]: https://github.com/ethereum/devp2p/tree/master/discv4.md
|
||||||
|
[discv5]: https://github.com/ethereum/devp2p/tree/master/discv5/discv5.md
|
||||||
|
|
@ -19,8 +19,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/maticnetwork/bor/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type crawler struct {
|
type crawler struct {
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/cmd/devp2p/internal/v4test"
|
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/v4test"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/internal/utesting"
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
"github.com/maticnetwork/bor/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/maticnetwork/bor/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/maticnetwork/bor/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -286,7 +286,11 @@ func listen(ln *enode.LocalNode, addr string) *net.UDPConn {
|
||||||
}
|
}
|
||||||
usocket := socket.(*net.UDPConn)
|
usocket := socket.(*net.UDPConn)
|
||||||
uaddr := socket.LocalAddr().(*net.UDPAddr)
|
uaddr := socket.LocalAddr().(*net.UDPAddr)
|
||||||
ln.SetFallbackIP(net.IP{127, 0, 0, 1})
|
if uaddr.IP.IsUnspecified() {
|
||||||
|
ln.SetFallbackIP(net.IP{127, 0, 0, 1})
|
||||||
|
} else {
|
||||||
|
ln.SetFallbackIP(uaddr.IP)
|
||||||
|
}
|
||||||
ln.SetFallbackUDP(uaddr.Port)
|
ln.SetFallbackUDP(uaddr.Port)
|
||||||
return usocket
|
return usocket
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +298,11 @@ func listen(ln *enode.LocalNode, addr string) *net.UDPConn {
|
||||||
func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) {
|
func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) {
|
||||||
s := params.RinkebyBootnodes
|
s := params.RinkebyBootnodes
|
||||||
if ctx.IsSet(bootnodesFlag.Name) {
|
if ctx.IsSet(bootnodesFlag.Name) {
|
||||||
s = strings.Split(ctx.String(bootnodesFlag.Name), ",")
|
input := ctx.String(bootnodesFlag.Name)
|
||||||
|
if input == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
s = strings.Split(input, ",")
|
||||||
}
|
}
|
||||||
nodes := make([]*enode.Node, len(s))
|
nodes := make([]*enode.Node, len(s))
|
||||||
var err error
|
var err error
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,14 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/v5test"
|
||||||
"github.com/maticnetwork/bor/p2p/discover"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -33,6 +37,7 @@ var (
|
||||||
discv5PingCommand,
|
discv5PingCommand,
|
||||||
discv5ResolveCommand,
|
discv5ResolveCommand,
|
||||||
discv5CrawlCommand,
|
discv5CrawlCommand,
|
||||||
|
discv5TestCommand,
|
||||||
discv5ListenCommand,
|
discv5ListenCommand,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +58,12 @@ var (
|
||||||
Action: discv5Crawl,
|
Action: discv5Crawl,
|
||||||
Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag},
|
Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag},
|
||||||
}
|
}
|
||||||
|
discv5TestCommand = cli.Command{
|
||||||
|
Name: "test",
|
||||||
|
Usage: "Runs protocol tests against a node",
|
||||||
|
Action: discv5Test,
|
||||||
|
Flags: []cli.Flag{testPatternFlag, testListen1Flag, testListen2Flag},
|
||||||
|
}
|
||||||
discv5ListenCommand = cli.Command{
|
discv5ListenCommand = cli.Command{
|
||||||
Name: "listen",
|
Name: "listen",
|
||||||
Usage: "Runs a node",
|
Usage: "Runs a node",
|
||||||
|
|
@ -103,6 +114,30 @@ func discv5Crawl(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func discv5Test(ctx *cli.Context) error {
|
||||||
|
// Disable logging unless explicitly enabled.
|
||||||
|
if !ctx.GlobalIsSet("verbosity") && !ctx.GlobalIsSet("vmodule") {
|
||||||
|
log.Root().SetHandler(log.DiscardHandler())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter and run test cases.
|
||||||
|
suite := &v5test.Suite{
|
||||||
|
Dest: getNodeArg(ctx),
|
||||||
|
Listen1: ctx.String(testListen1Flag.Name),
|
||||||
|
Listen2: ctx.String(testListen2Flag.Name),
|
||||||
|
}
|
||||||
|
tests := suite.AllTests()
|
||||||
|
if ctx.IsSet(testPatternFlag.Name) {
|
||||||
|
tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name))
|
||||||
|
}
|
||||||
|
results := utesting.RunTests(tests, os.Stdout)
|
||||||
|
if fails := utesting.CountFailures(results); fails > 0 {
|
||||||
|
return fmt.Errorf("%v/%v tests passed.", len(tests)-fails, len(tests))
|
||||||
|
}
|
||||||
|
fmt.Printf("%v/%v passed\n", len(tests), len(tests))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func discv5Listen(ctx *cli.Context) error {
|
func discv5Listen(ctx *cli.Context) error {
|
||||||
disc := startV5(ctx)
|
disc := startV5(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflare-go"
|
"github.com/cloudflare/cloudflare-go"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/maticnetwork/bor/p2p/dnsdisc"
|
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
"github.com/aws/aws-sdk-go/service/route53"
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
"github.com/maticnetwork/bor/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/maticnetwork/bor/p2p/dnsdisc"
|
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,11 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/console/prompt"
|
"github.com/ethereum/go-ethereum/console/prompt"
|
||||||
"github.com/maticnetwork/bor/p2p/dnsdisc"
|
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
|
||||||
"github.com/maticnetwork/bor/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
cli "gopkg.in/urfave/cli.v1"
|
cli "gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,15 +21,16 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/maticnetwork/bor/p2p/enr"
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
"github.com/maticnetwork/bor/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -69,22 +70,30 @@ func enrdump(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("INVALID: %v", err)
|
return fmt.Errorf("INVALID: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Print(dumpRecord(r))
|
dumpRecord(os.Stdout, r)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// dumpRecord creates a human-readable description of the given node record.
|
// dumpRecord creates a human-readable description of the given node record.
|
||||||
func dumpRecord(r *enr.Record) string {
|
func dumpRecord(out io.Writer, r *enr.Record) {
|
||||||
out := new(bytes.Buffer)
|
n, err := enode.New(enode.ValidSchemes, r)
|
||||||
if n, err := enode.New(enode.ValidSchemes, r); err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(out, "INVALID: %v\n", err)
|
fmt.Fprintf(out, "INVALID: %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(out, "Node ID: %v\n", n.ID())
|
fmt.Fprintf(out, "Node ID: %v\n", n.ID())
|
||||||
|
dumpNodeURL(out, n)
|
||||||
}
|
}
|
||||||
kv := r.AppendElements(nil)[1:]
|
kv := r.AppendElements(nil)[1:]
|
||||||
fmt.Fprintf(out, "Record has sequence number %d and %d key/value pairs.\n", r.Seq(), len(kv)/2)
|
fmt.Fprintf(out, "Record has sequence number %d and %d key/value pairs.\n", r.Seq(), len(kv)/2)
|
||||||
fmt.Fprint(out, dumpRecordKV(kv, 2))
|
fmt.Fprint(out, dumpRecordKV(kv, 2))
|
||||||
return out.String()
|
}
|
||||||
|
|
||||||
|
func dumpNodeURL(out io.Writer, n *enode.Node) {
|
||||||
|
var key enode.Secp256k1
|
||||||
|
if n.Load(&key) != nil {
|
||||||
|
return // no secp256k1 public key
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, "URLv4: %s\n", n.URLv4())
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpRecordKV(kv []interface{}, indent int) string {
|
func dumpRecordKV(kv []interface{}, indent int) string {
|
||||||
|
|
|
||||||
166
cmd/devp2p/internal/ethtest/chain.go
Normal file
166
cmd/devp2p/internal/ethtest/chain.go
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
// Copyright 2020 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 ethtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/forkid"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Chain struct {
|
||||||
|
blocks []*types.Block
|
||||||
|
chainConfig *params.ChainConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Chain) WriteTo(writer io.Writer) error {
|
||||||
|
for _, block := range c.blocks {
|
||||||
|
if err := rlp.Encode(writer, block); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the length of the chain.
|
||||||
|
func (c *Chain) Len() int {
|
||||||
|
return len(c.blocks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TD calculates the total difficulty of the chain.
|
||||||
|
func (c *Chain) TD(height int) *big.Int { // TODO later on channge scheme so that the height is included in range
|
||||||
|
sum := big.NewInt(0)
|
||||||
|
for _, block := range c.blocks[:height] {
|
||||||
|
sum.Add(sum, block.Difficulty())
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForkID gets the fork id of the chain.
|
||||||
|
func (c *Chain) ForkID() forkid.ID {
|
||||||
|
return forkid.NewID(c.chainConfig, c.blocks[0].Hash(), uint64(c.Len()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shorten returns a copy chain of a desired height from the imported
|
||||||
|
func (c *Chain) Shorten(height int) *Chain {
|
||||||
|
blocks := make([]*types.Block, height)
|
||||||
|
copy(blocks, c.blocks[:height])
|
||||||
|
|
||||||
|
config := *c.chainConfig
|
||||||
|
return &Chain{
|
||||||
|
blocks: blocks,
|
||||||
|
chainConfig: &config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head returns the chain head.
|
||||||
|
func (c *Chain) Head() *types.Block {
|
||||||
|
return c.blocks[c.Len()-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Chain) GetHeaders(req GetBlockHeaders) (BlockHeaders, error) {
|
||||||
|
if req.Amount < 1 {
|
||||||
|
return nil, fmt.Errorf("no block headers requested")
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := make(BlockHeaders, req.Amount)
|
||||||
|
var blockNumber uint64
|
||||||
|
|
||||||
|
// range over blocks to check if our chain has the requested header
|
||||||
|
for _, block := range c.blocks {
|
||||||
|
if block.Hash() == req.Origin.Hash || block.Number().Uint64() == req.Origin.Number {
|
||||||
|
headers[0] = block.Header()
|
||||||
|
blockNumber = block.Number().Uint64()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if headers[0] == nil {
|
||||||
|
return nil, fmt.Errorf("no headers found for given origin number %v, hash %v", req.Origin.Number, req.Origin.Hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Reverse {
|
||||||
|
for i := 1; i < int(req.Amount); i++ {
|
||||||
|
blockNumber -= (1 - req.Skip)
|
||||||
|
headers[i] = c.blocks[blockNumber].Header()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < int(req.Amount); i++ {
|
||||||
|
blockNumber += (1 + req.Skip)
|
||||||
|
headers[i] = c.blocks[blockNumber].Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadChain takes the given chain.rlp file, and decodes and returns
|
||||||
|
// the blocks from the file.
|
||||||
|
func loadChain(chainfile string, genesis string) (*Chain, error) {
|
||||||
|
// Open the file handle and potentially unwrap the gzip stream
|
||||||
|
fh, err := os.Open(chainfile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
var reader io.Reader = fh
|
||||||
|
if strings.HasSuffix(chainfile, ".gz") {
|
||||||
|
if reader, err = gzip.NewReader(reader); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream := rlp.NewStream(reader, 0)
|
||||||
|
var blocks []*types.Block
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
var b types.Block
|
||||||
|
if err := stream.Decode(&b); err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, fmt.Errorf("at block %d: %v", i, err)
|
||||||
|
}
|
||||||
|
blocks = append(blocks, &b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the file handle and potentially unwrap the gzip stream
|
||||||
|
chainConfig, err := ioutil.ReadFile(genesis)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var gen core.Genesis
|
||||||
|
if err := json.Unmarshal(chainConfig, &gen); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Chain{
|
||||||
|
blocks: blocks,
|
||||||
|
chainConfig: gen.Config,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
150
cmd/devp2p/internal/ethtest/chain_test.go
Normal file
150
cmd/devp2p/internal/ethtest/chain_test.go
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
// Copyright 2020 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 ethtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestEthProtocolNegotiation tests whether the test suite
|
||||||
|
// can negotiate the highest eth protocol in a status message exchange
|
||||||
|
func TestEthProtocolNegotiation(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
conn *Conn
|
||||||
|
caps []p2p.Cap
|
||||||
|
expected uint32
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
conn: &Conn{},
|
||||||
|
caps: []p2p.Cap{
|
||||||
|
{Name: "eth", Version: 63},
|
||||||
|
{Name: "eth", Version: 64},
|
||||||
|
{Name: "eth", Version: 65},
|
||||||
|
},
|
||||||
|
expected: uint32(65),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn: &Conn{},
|
||||||
|
caps: []p2p.Cap{
|
||||||
|
{Name: "eth", Version: 0},
|
||||||
|
{Name: "eth", Version: 89},
|
||||||
|
{Name: "eth", Version: 65},
|
||||||
|
},
|
||||||
|
expected: uint32(65),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn: &Conn{},
|
||||||
|
caps: []p2p.Cap{
|
||||||
|
{Name: "eth", Version: 63},
|
||||||
|
{Name: "eth", Version: 64},
|
||||||
|
{Name: "wrongProto", Version: 65},
|
||||||
|
},
|
||||||
|
expected: uint32(64),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
tt.conn.negotiateEthProtocol(tt.caps)
|
||||||
|
assert.Equal(t, tt.expected, uint32(tt.conn.ethProtocolVersion))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestChain_GetHeaders tests whether the test suite can correctly
|
||||||
|
// respond to a GetBlockHeaders request from a node.
|
||||||
|
func TestChain_GetHeaders(t *testing.T) {
|
||||||
|
chainFile, err := filepath.Abs("./testdata/chain.rlp.gz")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
genesisFile, err := filepath.Abs("./testdata/genesis.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
chain, err := loadChain(chainFile, genesisFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
req GetBlockHeaders
|
||||||
|
expected BlockHeaders
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
req: GetBlockHeaders{
|
||||||
|
Origin: hashOrNumber{
|
||||||
|
Number: uint64(2),
|
||||||
|
},
|
||||||
|
Amount: uint64(5),
|
||||||
|
Skip: 1,
|
||||||
|
Reverse: false,
|
||||||
|
},
|
||||||
|
expected: BlockHeaders{
|
||||||
|
chain.blocks[2].Header(),
|
||||||
|
chain.blocks[4].Header(),
|
||||||
|
chain.blocks[6].Header(),
|
||||||
|
chain.blocks[8].Header(),
|
||||||
|
chain.blocks[10].Header(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
req: GetBlockHeaders{
|
||||||
|
Origin: hashOrNumber{
|
||||||
|
Number: uint64(chain.Len() - 1),
|
||||||
|
},
|
||||||
|
Amount: uint64(3),
|
||||||
|
Skip: 0,
|
||||||
|
Reverse: true,
|
||||||
|
},
|
||||||
|
expected: BlockHeaders{
|
||||||
|
chain.blocks[chain.Len()-1].Header(),
|
||||||
|
chain.blocks[chain.Len()-2].Header(),
|
||||||
|
chain.blocks[chain.Len()-3].Header(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
req: GetBlockHeaders{
|
||||||
|
Origin: hashOrNumber{
|
||||||
|
Hash: chain.Head().Hash(),
|
||||||
|
},
|
||||||
|
Amount: uint64(1),
|
||||||
|
Skip: 0,
|
||||||
|
Reverse: false,
|
||||||
|
},
|
||||||
|
expected: BlockHeaders{
|
||||||
|
chain.Head().Header(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
headers, err := chain.GetHeaders(tt.req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, headers, tt.expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
216
cmd/devp2p/internal/ethtest/suite.go
Normal file
216
cmd/devp2p/internal/ethtest/suite.go
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
// Copyright 2020 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 ethtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/rlpx"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Suite represents a structure used to test the eth
|
||||||
|
// protocol of a node(s).
|
||||||
|
type Suite struct {
|
||||||
|
Dest *enode.Node
|
||||||
|
|
||||||
|
chain *Chain
|
||||||
|
fullChain *Chain
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSuite creates and returns a new eth-test suite that can
|
||||||
|
// be used to test the given node against the given blockchain
|
||||||
|
// data.
|
||||||
|
func NewSuite(dest *enode.Node, chainfile string, genesisfile string) *Suite {
|
||||||
|
chain, err := loadChain(chainfile, genesisfile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return &Suite{
|
||||||
|
Dest: dest,
|
||||||
|
chain: chain.Shorten(1000),
|
||||||
|
fullChain: chain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Suite) AllTests() []utesting.Test {
|
||||||
|
return []utesting.Test{
|
||||||
|
{Name: "Status", Fn: s.TestStatus},
|
||||||
|
{Name: "GetBlockHeaders", Fn: s.TestGetBlockHeaders},
|
||||||
|
{Name: "Broadcast", Fn: s.TestBroadcast},
|
||||||
|
{Name: "GetBlockBodies", Fn: s.TestGetBlockBodies},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestStatus attempts to connect to the given node and exchange
|
||||||
|
// a status message with it, and then check to make sure
|
||||||
|
// the chain head is correct.
|
||||||
|
func (s *Suite) TestStatus(t *utesting.T) {
|
||||||
|
conn, err := s.dial()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not dial: %v", err)
|
||||||
|
}
|
||||||
|
// get protoHandshake
|
||||||
|
conn.handshake(t)
|
||||||
|
// get status
|
||||||
|
switch msg := conn.statusExchange(t, s.chain).(type) {
|
||||||
|
case *Status:
|
||||||
|
t.Logf("%+v\n", msg)
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected: %#v", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGetBlockHeaders tests whether the given node can respond to
|
||||||
|
// a `GetBlockHeaders` request and that the response is accurate.
|
||||||
|
func (s *Suite) TestGetBlockHeaders(t *utesting.T) {
|
||||||
|
conn, err := s.dial()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not dial: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.handshake(t)
|
||||||
|
conn.statusExchange(t, s.chain)
|
||||||
|
|
||||||
|
// get block headers
|
||||||
|
req := &GetBlockHeaders{
|
||||||
|
Origin: hashOrNumber{
|
||||||
|
Hash: s.chain.blocks[1].Hash(),
|
||||||
|
},
|
||||||
|
Amount: 2,
|
||||||
|
Skip: 1,
|
||||||
|
Reverse: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.Write(req); err != nil {
|
||||||
|
t.Fatalf("could not write to connection: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch msg := conn.ReadAndServe(s.chain).(type) {
|
||||||
|
case *BlockHeaders:
|
||||||
|
headers := msg
|
||||||
|
for _, header := range *headers {
|
||||||
|
num := header.Number.Uint64()
|
||||||
|
assert.Equal(t, s.chain.blocks[int(num)].Header(), header)
|
||||||
|
t.Logf("\nHEADER FOR BLOCK NUMBER %d: %+v\n", header.Number, header)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected: %#v", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGetBlockBodies tests whether the given node can respond to
|
||||||
|
// a `GetBlockBodies` request and that the response is accurate.
|
||||||
|
func (s *Suite) TestGetBlockBodies(t *utesting.T) {
|
||||||
|
conn, err := s.dial()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not dial: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.handshake(t)
|
||||||
|
conn.statusExchange(t, s.chain)
|
||||||
|
// create block bodies request
|
||||||
|
req := &GetBlockBodies{s.chain.blocks[54].Hash(), s.chain.blocks[75].Hash()}
|
||||||
|
if err := conn.Write(req); err != nil {
|
||||||
|
t.Fatalf("could not write to connection: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch msg := conn.ReadAndServe(s.chain).(type) {
|
||||||
|
case *BlockBodies:
|
||||||
|
bodies := msg
|
||||||
|
for _, body := range *bodies {
|
||||||
|
t.Logf("\nBODY: %+v\n", body)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected: %#v", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestBroadcast tests whether a block announcement is correctly
|
||||||
|
// propagated to the given node's peer(s).
|
||||||
|
func (s *Suite) TestBroadcast(t *utesting.T) {
|
||||||
|
// create conn to send block announcement
|
||||||
|
sendConn, err := s.dial()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not dial: %v", err)
|
||||||
|
}
|
||||||
|
// create conn to receive block announcement
|
||||||
|
receiveConn, err := s.dial()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not dial: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendConn.handshake(t)
|
||||||
|
receiveConn.handshake(t)
|
||||||
|
|
||||||
|
sendConn.statusExchange(t, s.chain)
|
||||||
|
receiveConn.statusExchange(t, s.chain)
|
||||||
|
|
||||||
|
// sendConn sends the block announcement
|
||||||
|
blockAnnouncement := &NewBlock{
|
||||||
|
Block: s.fullChain.blocks[1000],
|
||||||
|
TD: s.fullChain.TD(1001),
|
||||||
|
}
|
||||||
|
if err := sendConn.Write(blockAnnouncement); err != nil {
|
||||||
|
t.Fatalf("could not write to connection: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch msg := receiveConn.ReadAndServe(s.chain).(type) {
|
||||||
|
case *NewBlock:
|
||||||
|
assert.Equal(t, blockAnnouncement.Block.Header(), msg.Block.Header(),
|
||||||
|
"wrong block header in announcement")
|
||||||
|
assert.Equal(t, blockAnnouncement.TD, msg.TD,
|
||||||
|
"wrong TD in announcement")
|
||||||
|
case *NewBlockHashes:
|
||||||
|
hashes := *msg
|
||||||
|
assert.Equal(t, blockAnnouncement.Block.Hash(), hashes[0].Hash,
|
||||||
|
"wrong block hash in announcement")
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected: %#v", msg)
|
||||||
|
}
|
||||||
|
// update test suite chain
|
||||||
|
s.chain.blocks = append(s.chain.blocks, s.fullChain.blocks[1000])
|
||||||
|
// wait for client to update its chain
|
||||||
|
if err := receiveConn.waitForBlock(s.chain.Head()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dial attempts to dial the given node and perform a handshake,
|
||||||
|
// returning the created Conn if successful.
|
||||||
|
func (s *Suite) dial() (*Conn, error) {
|
||||||
|
var conn Conn
|
||||||
|
|
||||||
|
fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", s.Dest.IP(), s.Dest.TCP()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn.Conn = rlpx.NewConn(fd, s.Dest.Pubkey())
|
||||||
|
|
||||||
|
// do encHandshake
|
||||||
|
conn.ourKey, _ = crypto.GenerateKey()
|
||||||
|
_, err = conn.Handshake(conn.ourKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &conn, nil
|
||||||
|
}
|
||||||
BIN
cmd/devp2p/internal/ethtest/testdata/chain.rlp.gz
vendored
Executable file
BIN
cmd/devp2p/internal/ethtest/testdata/chain.rlp.gz
vendored
Executable file
Binary file not shown.
26
cmd/devp2p/internal/ethtest/testdata/genesis.json
vendored
Normal file
26
cmd/devp2p/internal/ethtest/testdata/genesis.json
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"chainId": 1,
|
||||||
|
"homesteadBlock": 0,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip155Block": 0,
|
||||||
|
"eip158Block": 0,
|
||||||
|
"byzantiumBlock": 0,
|
||||||
|
"ethash": {}
|
||||||
|
},
|
||||||
|
"nonce": "0xdeadbeefdeadbeef",
|
||||||
|
"timestamp": "0x0",
|
||||||
|
"extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"gasLimit": "0x8000000",
|
||||||
|
"difficulty": "0x10",
|
||||||
|
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"coinbase": "0x0000000000000000000000000000000000000000",
|
||||||
|
"alloc": {
|
||||||
|
"71562b71999873db5b286df957af199ec94617f7": {
|
||||||
|
"balance": "0xf4240"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"number": "0x0",
|
||||||
|
"gasUsed": "0x0",
|
||||||
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
366
cmd/devp2p/internal/ethtest/types.go
Normal file
366
cmd/devp2p/internal/ethtest/types.go
Normal file
|
|
@ -0,0 +1,366 @@
|
||||||
|
// Copyright 2020 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 ethtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/forkid"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/rlpx"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Message interface {
|
||||||
|
Code() int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Unwrap() error { return e.err }
|
||||||
|
func (e *Error) Error() string { return e.err.Error() }
|
||||||
|
func (e *Error) Code() int { return -1 }
|
||||||
|
func (e *Error) GoString() string { return e.Error() }
|
||||||
|
|
||||||
|
// Hello is the RLP structure of the protocol handshake.
|
||||||
|
type Hello struct {
|
||||||
|
Version uint64
|
||||||
|
Name string
|
||||||
|
Caps []p2p.Cap
|
||||||
|
ListenPort uint64
|
||||||
|
ID []byte // secp256k1 public key
|
||||||
|
|
||||||
|
// Ignore additional fields (for forward compatibility).
|
||||||
|
Rest []rlp.RawValue `rlp:"tail"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Hello) Code() int { return 0x00 }
|
||||||
|
|
||||||
|
// Disconnect is the RLP structure for a disconnect message.
|
||||||
|
type Disconnect struct {
|
||||||
|
Reason p2p.DiscReason
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Disconnect) Code() int { return 0x01 }
|
||||||
|
|
||||||
|
type Ping struct{}
|
||||||
|
|
||||||
|
func (p Ping) Code() int { return 0x02 }
|
||||||
|
|
||||||
|
type Pong struct{}
|
||||||
|
|
||||||
|
func (p Pong) Code() int { return 0x03 }
|
||||||
|
|
||||||
|
// Status is the network packet for the status message for eth/64 and later.
|
||||||
|
type Status struct {
|
||||||
|
ProtocolVersion uint32
|
||||||
|
NetworkID uint64
|
||||||
|
TD *big.Int
|
||||||
|
Head common.Hash
|
||||||
|
Genesis common.Hash
|
||||||
|
ForkID forkid.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Status) Code() int { return 16 }
|
||||||
|
|
||||||
|
// NewBlockHashes is the network packet for the block announcements.
|
||||||
|
type NewBlockHashes []struct {
|
||||||
|
Hash common.Hash // Hash of one particular block being announced
|
||||||
|
Number uint64 // Number of one particular block being announced
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nbh NewBlockHashes) Code() int { return 17 }
|
||||||
|
|
||||||
|
// NewBlock is the network packet for the block propagation message.
|
||||||
|
type NewBlock struct {
|
||||||
|
Block *types.Block
|
||||||
|
TD *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nb NewBlock) Code() int { return 23 }
|
||||||
|
|
||||||
|
// GetBlockHeaders represents a block header query.
|
||||||
|
type GetBlockHeaders struct {
|
||||||
|
Origin hashOrNumber // Block from which to retrieve headers
|
||||||
|
Amount uint64 // Maximum number of headers to retrieve
|
||||||
|
Skip uint64 // Blocks to skip between consecutive headers
|
||||||
|
Reverse bool // Query direction (false = rising towards latest, true = falling towards genesis)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GetBlockHeaders) Code() int { return 19 }
|
||||||
|
|
||||||
|
type BlockHeaders []*types.Header
|
||||||
|
|
||||||
|
func (bh BlockHeaders) Code() int { return 20 }
|
||||||
|
|
||||||
|
// HashOrNumber is a combined field for specifying an origin block.
|
||||||
|
type hashOrNumber struct {
|
||||||
|
Hash common.Hash // Block hash from which to retrieve headers (excludes Number)
|
||||||
|
Number uint64 // Block hash from which to retrieve headers (excludes Hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeRLP is a specialized encoder for hashOrNumber to encode only one of the
|
||||||
|
// two contained union fields.
|
||||||
|
func (hn *hashOrNumber) EncodeRLP(w io.Writer) error {
|
||||||
|
if hn.Hash == (common.Hash{}) {
|
||||||
|
return rlp.Encode(w, hn.Number)
|
||||||
|
}
|
||||||
|
if hn.Number != 0 {
|
||||||
|
return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number)
|
||||||
|
}
|
||||||
|
return rlp.Encode(w, hn.Hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeRLP is a specialized decoder for hashOrNumber to decode the contents
|
||||||
|
// into either a block hash or a block number.
|
||||||
|
func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error {
|
||||||
|
_, size, _ := s.Kind()
|
||||||
|
origin, err := s.Raw()
|
||||||
|
if err == nil {
|
||||||
|
switch {
|
||||||
|
case size == 32:
|
||||||
|
err = rlp.DecodeBytes(origin, &hn.Hash)
|
||||||
|
case size <= 8:
|
||||||
|
err = rlp.DecodeBytes(origin, &hn.Number)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("invalid input size %d for origin", size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockBodies represents a GetBlockBodies request
|
||||||
|
type GetBlockBodies []common.Hash
|
||||||
|
|
||||||
|
func (gbb GetBlockBodies) Code() int { return 21 }
|
||||||
|
|
||||||
|
// BlockBodies is the network packet for block content distribution.
|
||||||
|
type BlockBodies []*types.Body
|
||||||
|
|
||||||
|
func (bb BlockBodies) Code() int { return 22 }
|
||||||
|
|
||||||
|
// Conn represents an individual connection with a peer
|
||||||
|
type Conn struct {
|
||||||
|
*rlpx.Conn
|
||||||
|
ourKey *ecdsa.PrivateKey
|
||||||
|
ethProtocolVersion uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) Read() Message {
|
||||||
|
code, rawData, _, err := c.Conn.Read()
|
||||||
|
if err != nil {
|
||||||
|
return &Error{fmt.Errorf("could not read from connection: %v", err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg Message
|
||||||
|
switch int(code) {
|
||||||
|
case (Hello{}).Code():
|
||||||
|
msg = new(Hello)
|
||||||
|
case (Ping{}).Code():
|
||||||
|
msg = new(Ping)
|
||||||
|
case (Pong{}).Code():
|
||||||
|
msg = new(Pong)
|
||||||
|
case (Disconnect{}).Code():
|
||||||
|
msg = new(Disconnect)
|
||||||
|
case (Status{}).Code():
|
||||||
|
msg = new(Status)
|
||||||
|
case (GetBlockHeaders{}).Code():
|
||||||
|
msg = new(GetBlockHeaders)
|
||||||
|
case (BlockHeaders{}).Code():
|
||||||
|
msg = new(BlockHeaders)
|
||||||
|
case (GetBlockBodies{}).Code():
|
||||||
|
msg = new(GetBlockBodies)
|
||||||
|
case (BlockBodies{}).Code():
|
||||||
|
msg = new(BlockBodies)
|
||||||
|
case (NewBlock{}).Code():
|
||||||
|
msg = new(NewBlock)
|
||||||
|
case (NewBlockHashes{}).Code():
|
||||||
|
msg = new(NewBlockHashes)
|
||||||
|
default:
|
||||||
|
return &Error{fmt.Errorf("invalid message code: %d", code)}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rlp.DecodeBytes(rawData, msg); err != nil {
|
||||||
|
return &Error{fmt.Errorf("could not rlp decode message: %v", err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadAndServe serves GetBlockHeaders requests while waiting
|
||||||
|
// on another message from the node.
|
||||||
|
func (c *Conn) ReadAndServe(chain *Chain) Message {
|
||||||
|
for {
|
||||||
|
switch msg := c.Read().(type) {
|
||||||
|
case *Ping:
|
||||||
|
c.Write(&Pong{})
|
||||||
|
case *GetBlockHeaders:
|
||||||
|
req := *msg
|
||||||
|
headers, err := chain.GetHeaders(req)
|
||||||
|
if err != nil {
|
||||||
|
return &Error{fmt.Errorf("could not get headers for inbound header request: %v", err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Write(headers); err != nil {
|
||||||
|
return &Error{fmt.Errorf("could not write to connection: %v", err)}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) Write(msg Message) error {
|
||||||
|
payload, err := rlp.EncodeToBytes(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = c.Conn.Write(uint64(msg.Code()), payload)
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// handshake checks to make sure a `HELLO` is received.
|
||||||
|
func (c *Conn) handshake(t *utesting.T) Message {
|
||||||
|
// write protoHandshake to client
|
||||||
|
pub0 := crypto.FromECDSAPub(&c.ourKey.PublicKey)[1:]
|
||||||
|
ourHandshake := &Hello{
|
||||||
|
Version: 5,
|
||||||
|
Caps: []p2p.Cap{
|
||||||
|
{Name: "eth", Version: 64},
|
||||||
|
{Name: "eth", Version: 65},
|
||||||
|
},
|
||||||
|
ID: pub0,
|
||||||
|
}
|
||||||
|
if err := c.Write(ourHandshake); err != nil {
|
||||||
|
t.Fatalf("could not write to connection: %v", err)
|
||||||
|
}
|
||||||
|
// read protoHandshake from client
|
||||||
|
switch msg := c.Read().(type) {
|
||||||
|
case *Hello:
|
||||||
|
// set snappy if version is at least 5
|
||||||
|
if msg.Version >= 5 {
|
||||||
|
c.SetSnappy(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.negotiateEthProtocol(msg.Caps)
|
||||||
|
if c.ethProtocolVersion == 0 {
|
||||||
|
t.Fatalf("unexpected eth protocol version")
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
default:
|
||||||
|
t.Fatalf("bad handshake: %#v", msg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// negotiateEthProtocol sets the Conn's eth protocol version
|
||||||
|
// to highest advertised capability from peer
|
||||||
|
func (c *Conn) negotiateEthProtocol(caps []p2p.Cap) {
|
||||||
|
var highestEthVersion uint
|
||||||
|
for _, capability := range caps {
|
||||||
|
if capability.Name != "eth" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if capability.Version > highestEthVersion && capability.Version <= 65 {
|
||||||
|
highestEthVersion = capability.Version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.ethProtocolVersion = highestEthVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// statusExchange performs a `Status` message exchange with the given
|
||||||
|
// node.
|
||||||
|
func (c *Conn) statusExchange(t *utesting.T, chain *Chain) Message {
|
||||||
|
// read status message from client
|
||||||
|
var message Message
|
||||||
|
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
switch msg := c.Read().(type) {
|
||||||
|
case *Status:
|
||||||
|
if msg.Head != chain.blocks[chain.Len()-1].Hash() {
|
||||||
|
t.Fatalf("wrong head in status: %v", msg.Head)
|
||||||
|
}
|
||||||
|
if msg.TD.Cmp(chain.TD(chain.Len())) != 0 {
|
||||||
|
t.Fatalf("wrong TD in status: %v", msg.TD)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(msg.ForkID, chain.ForkID()) {
|
||||||
|
t.Fatalf("wrong fork ID in status: %v", msg.ForkID)
|
||||||
|
}
|
||||||
|
message = msg
|
||||||
|
break loop
|
||||||
|
case *Disconnect:
|
||||||
|
t.Fatalf("disconnect received: %v", msg.Reason)
|
||||||
|
case *Ping:
|
||||||
|
c.Write(&Pong{}) // TODO (renaynay): in the future, this should be an error
|
||||||
|
// (PINGs should not be a response upon fresh connection)
|
||||||
|
default:
|
||||||
|
t.Fatalf("bad status message: %#v", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// make sure eth protocol version is set for negotiation
|
||||||
|
if c.ethProtocolVersion == 0 {
|
||||||
|
t.Fatalf("eth protocol version must be set in Conn")
|
||||||
|
}
|
||||||
|
// write status message to client
|
||||||
|
status := Status{
|
||||||
|
ProtocolVersion: uint32(c.ethProtocolVersion),
|
||||||
|
NetworkID: 1,
|
||||||
|
TD: chain.TD(chain.Len()),
|
||||||
|
Head: chain.blocks[chain.Len()-1].Hash(),
|
||||||
|
Genesis: chain.blocks[0].Hash(),
|
||||||
|
ForkID: chain.ForkID(),
|
||||||
|
}
|
||||||
|
if err := c.Write(status); err != nil {
|
||||||
|
t.Fatalf("could not write to connection: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitForBlock waits for confirmation from the client that it has
|
||||||
|
// imported the given block.
|
||||||
|
func (c *Conn) waitForBlock(block *types.Block) error {
|
||||||
|
for {
|
||||||
|
req := &GetBlockHeaders{Origin: hashOrNumber{Hash: block.Hash()}, Amount: 1}
|
||||||
|
if err := c.Write(req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch msg := c.Read().(type) {
|
||||||
|
case *BlockHeaders:
|
||||||
|
if len(*msg) > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid message: %v", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,9 +24,9 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/internal/utesting"
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
"github.com/maticnetwork/bor/p2p/discover/v4wire"
|
"github.com/ethereum/go-ethereum/p2p/discover/v4wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/p2p/discover/v4wire"
|
"github.com/ethereum/go-ethereum/p2p/discover/v4wire"
|
||||||
"github.com/maticnetwork/bor/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
)
|
)
|
||||||
|
|
||||||
const waitTime = 300 * time.Millisecond
|
const waitTime = 300 * time.Millisecond
|
||||||
|
|
|
||||||
377
cmd/devp2p/internal/v5test/discv5tests.go
Normal file
377
cmd/devp2p/internal/v5test/discv5tests.go
Normal file
|
|
@ -0,0 +1,377 @@
|
||||||
|
// Copyright 2020 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 v5test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discover/v5wire"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Suite is the discv5 test suite.
|
||||||
|
type Suite struct {
|
||||||
|
Dest *enode.Node
|
||||||
|
Listen1, Listen2 string // listening addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Suite) listen1(log logger) (*conn, net.PacketConn) {
|
||||||
|
c := newConn(s.Dest, log)
|
||||||
|
l := c.listen(s.Listen1)
|
||||||
|
return c, l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Suite) listen2(log logger) (*conn, net.PacketConn, net.PacketConn) {
|
||||||
|
c := newConn(s.Dest, log)
|
||||||
|
l1, l2 := c.listen(s.Listen1), c.listen(s.Listen2)
|
||||||
|
return c, l1, l2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Suite) AllTests() []utesting.Test {
|
||||||
|
return []utesting.Test{
|
||||||
|
{Name: "Ping", Fn: s.TestPing},
|
||||||
|
{Name: "PingLargeRequestID", Fn: s.TestPingLargeRequestID},
|
||||||
|
{Name: "PingMultiIP", Fn: s.TestPingMultiIP},
|
||||||
|
{Name: "PingHandshakeInterrupted", Fn: s.TestPingHandshakeInterrupted},
|
||||||
|
{Name: "TalkRequest", Fn: s.TestTalkRequest},
|
||||||
|
{Name: "FindnodeZeroDistance", Fn: s.TestFindnodeZeroDistance},
|
||||||
|
{Name: "FindnodeResults", Fn: s.TestFindnodeResults},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test sends PING and expects a PONG response.
|
||||||
|
func (s *Suite) TestPing(t *utesting.T) {
|
||||||
|
conn, l1 := s.listen1(t)
|
||||||
|
defer conn.close()
|
||||||
|
|
||||||
|
ping := &v5wire.Ping{ReqID: conn.nextReqID()}
|
||||||
|
switch resp := conn.reqresp(l1, ping).(type) {
|
||||||
|
case *v5wire.Pong:
|
||||||
|
checkPong(t, resp, ping, l1)
|
||||||
|
default:
|
||||||
|
t.Fatal("expected PONG, got", resp.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPong(t *utesting.T, pong *v5wire.Pong, ping *v5wire.Ping, c net.PacketConn) {
|
||||||
|
if !bytes.Equal(pong.ReqID, ping.ReqID) {
|
||||||
|
t.Fatalf("wrong request ID %x in PONG, want %x", pong.ReqID, ping.ReqID)
|
||||||
|
}
|
||||||
|
if !pong.ToIP.Equal(laddr(c).IP) {
|
||||||
|
t.Fatalf("wrong destination IP %v in PONG, want %v", pong.ToIP, laddr(c).IP)
|
||||||
|
}
|
||||||
|
if int(pong.ToPort) != laddr(c).Port {
|
||||||
|
t.Fatalf("wrong destination port %v in PONG, want %v", pong.ToPort, laddr(c).Port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test sends PING with a 9-byte request ID, which isn't allowed by the spec.
|
||||||
|
// The remote node should not respond.
|
||||||
|
func (s *Suite) TestPingLargeRequestID(t *utesting.T) {
|
||||||
|
conn, l1 := s.listen1(t)
|
||||||
|
defer conn.close()
|
||||||
|
|
||||||
|
ping := &v5wire.Ping{ReqID: make([]byte, 9)}
|
||||||
|
switch resp := conn.reqresp(l1, ping).(type) {
|
||||||
|
case *v5wire.Pong:
|
||||||
|
t.Errorf("PONG response with unknown request ID %x", resp.ReqID)
|
||||||
|
case *readError:
|
||||||
|
if resp.err == v5wire.ErrInvalidReqID {
|
||||||
|
t.Error("response with oversized request ID")
|
||||||
|
} else if !netutil.IsTimeout(resp.err) {
|
||||||
|
t.Error(resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In this test, a session is established from one IP as usual. The session is then reused
|
||||||
|
// on another IP, which shouldn't work. The remote node should respond with WHOAREYOU for
|
||||||
|
// the attempt from a different IP.
|
||||||
|
func (s *Suite) TestPingMultiIP(t *utesting.T) {
|
||||||
|
conn, l1, l2 := s.listen2(t)
|
||||||
|
defer conn.close()
|
||||||
|
|
||||||
|
// Create the session on l1.
|
||||||
|
ping := &v5wire.Ping{ReqID: conn.nextReqID()}
|
||||||
|
resp := conn.reqresp(l1, ping)
|
||||||
|
if resp.Kind() != v5wire.PongMsg {
|
||||||
|
t.Fatal("expected PONG, got", resp)
|
||||||
|
}
|
||||||
|
checkPong(t, resp.(*v5wire.Pong), ping, l1)
|
||||||
|
|
||||||
|
// Send on l2. This reuses the session because there is only one codec.
|
||||||
|
ping2 := &v5wire.Ping{ReqID: conn.nextReqID()}
|
||||||
|
conn.write(l2, ping2, nil)
|
||||||
|
switch resp := conn.read(l2).(type) {
|
||||||
|
case *v5wire.Pong:
|
||||||
|
t.Fatalf("remote responded to PING from %v for session on IP %v", laddr(l2).IP, laddr(l1).IP)
|
||||||
|
case *v5wire.Whoareyou:
|
||||||
|
t.Logf("got WHOAREYOU for new session as expected")
|
||||||
|
resp.Node = s.Dest
|
||||||
|
conn.write(l2, ping2, resp)
|
||||||
|
default:
|
||||||
|
t.Fatal("expected WHOAREYOU, got", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catch the PONG on l2.
|
||||||
|
switch resp := conn.read(l2).(type) {
|
||||||
|
case *v5wire.Pong:
|
||||||
|
checkPong(t, resp, ping2, l2)
|
||||||
|
default:
|
||||||
|
t.Fatal("expected PONG, got", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try on l1 again.
|
||||||
|
ping3 := &v5wire.Ping{ReqID: conn.nextReqID()}
|
||||||
|
conn.write(l1, ping3, nil)
|
||||||
|
switch resp := conn.read(l1).(type) {
|
||||||
|
case *v5wire.Pong:
|
||||||
|
t.Fatalf("remote responded to PING from %v for session on IP %v", laddr(l1).IP, laddr(l2).IP)
|
||||||
|
case *v5wire.Whoareyou:
|
||||||
|
t.Logf("got WHOAREYOU for new session as expected")
|
||||||
|
default:
|
||||||
|
t.Fatal("expected WHOAREYOU, got", resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test starts a handshake, but doesn't finish it and sends a second ordinary message
|
||||||
|
// packet instead of a handshake message packet. The remote node should respond with
|
||||||
|
// another WHOAREYOU challenge for the second packet.
|
||||||
|
func (s *Suite) TestPingHandshakeInterrupted(t *utesting.T) {
|
||||||
|
conn, l1 := s.listen1(t)
|
||||||
|
defer conn.close()
|
||||||
|
|
||||||
|
// First PING triggers challenge.
|
||||||
|
ping := &v5wire.Ping{ReqID: conn.nextReqID()}
|
||||||
|
conn.write(l1, ping, nil)
|
||||||
|
switch resp := conn.read(l1).(type) {
|
||||||
|
case *v5wire.Whoareyou:
|
||||||
|
t.Logf("got WHOAREYOU for PING")
|
||||||
|
default:
|
||||||
|
t.Fatal("expected WHOAREYOU, got", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send second PING.
|
||||||
|
ping2 := &v5wire.Ping{ReqID: conn.nextReqID()}
|
||||||
|
switch resp := conn.reqresp(l1, ping2).(type) {
|
||||||
|
case *v5wire.Pong:
|
||||||
|
checkPong(t, resp, ping2, l1)
|
||||||
|
default:
|
||||||
|
t.Fatal("expected WHOAREYOU, got", resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test sends TALKREQ and expects an empty TALKRESP response.
|
||||||
|
func (s *Suite) TestTalkRequest(t *utesting.T) {
|
||||||
|
conn, l1 := s.listen1(t)
|
||||||
|
defer conn.close()
|
||||||
|
|
||||||
|
// Non-empty request ID.
|
||||||
|
id := conn.nextReqID()
|
||||||
|
resp := conn.reqresp(l1, &v5wire.TalkRequest{ReqID: id, Protocol: "test-protocol"})
|
||||||
|
switch resp := resp.(type) {
|
||||||
|
case *v5wire.TalkResponse:
|
||||||
|
if !bytes.Equal(resp.ReqID, id) {
|
||||||
|
t.Fatalf("wrong request ID %x in TALKRESP, want %x", resp.ReqID, id)
|
||||||
|
}
|
||||||
|
if len(resp.Message) > 0 {
|
||||||
|
t.Fatalf("non-empty message %x in TALKRESP", resp.Message)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("expected TALKRESP, got", resp.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty request ID.
|
||||||
|
resp = conn.reqresp(l1, &v5wire.TalkRequest{Protocol: "test-protocol"})
|
||||||
|
switch resp := resp.(type) {
|
||||||
|
case *v5wire.TalkResponse:
|
||||||
|
if len(resp.ReqID) > 0 {
|
||||||
|
t.Fatalf("wrong request ID %x in TALKRESP, want empty byte array", resp.ReqID)
|
||||||
|
}
|
||||||
|
if len(resp.Message) > 0 {
|
||||||
|
t.Fatalf("non-empty message %x in TALKRESP", resp.Message)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("expected TALKRESP, got", resp.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test checks that the remote node returns itself for FINDNODE with distance zero.
|
||||||
|
func (s *Suite) TestFindnodeZeroDistance(t *utesting.T) {
|
||||||
|
conn, l1 := s.listen1(t)
|
||||||
|
defer conn.close()
|
||||||
|
|
||||||
|
nodes, err := conn.findnode(l1, []uint{0})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(nodes) != 1 {
|
||||||
|
t.Fatalf("remote returned more than one node for FINDNODE [0]")
|
||||||
|
}
|
||||||
|
if nodes[0].ID() != conn.remote.ID() {
|
||||||
|
t.Errorf("ID of response node is %v, want %v", nodes[0].ID(), conn.remote.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In this test, multiple nodes ping the node under test. After waiting for them to be
|
||||||
|
// accepted into the remote table, the test checks that they are returned by FINDNODE.
|
||||||
|
func (s *Suite) TestFindnodeResults(t *utesting.T) {
|
||||||
|
// Create bystanders.
|
||||||
|
nodes := make([]*bystander, 5)
|
||||||
|
added := make(chan enode.ID, len(nodes))
|
||||||
|
for i := range nodes {
|
||||||
|
nodes[i] = newBystander(t, s, added)
|
||||||
|
defer nodes[i].close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get them added to the remote table.
|
||||||
|
timeout := 60 * time.Second
|
||||||
|
timeoutCh := time.After(timeout)
|
||||||
|
for count := 0; count < len(nodes); {
|
||||||
|
select {
|
||||||
|
case id := <-added:
|
||||||
|
t.Logf("bystander node %v added to remote table", id)
|
||||||
|
count++
|
||||||
|
case <-timeoutCh:
|
||||||
|
t.Errorf("remote added %d bystander nodes in %v, need %d to continue", count, timeout, len(nodes))
|
||||||
|
t.Logf("this can happen if the node has a non-empty table from previous runs")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("all %d bystander nodes were added", len(nodes))
|
||||||
|
|
||||||
|
// Collect our nodes by distance.
|
||||||
|
var dists []uint
|
||||||
|
expect := make(map[enode.ID]*enode.Node)
|
||||||
|
for _, bn := range nodes {
|
||||||
|
n := bn.conn.localNode.Node()
|
||||||
|
expect[n.ID()] = n
|
||||||
|
d := uint(enode.LogDist(n.ID(), s.Dest.ID()))
|
||||||
|
if !containsUint(dists, d) {
|
||||||
|
dists = append(dists, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send FINDNODE for all distances.
|
||||||
|
conn, l1 := s.listen1(t)
|
||||||
|
defer conn.close()
|
||||||
|
foundNodes, err := conn.findnode(l1, dists)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("remote returned %d nodes for distance list %v", len(foundNodes), dists)
|
||||||
|
for _, n := range foundNodes {
|
||||||
|
delete(expect, n.ID())
|
||||||
|
}
|
||||||
|
if len(expect) > 0 {
|
||||||
|
t.Errorf("missing %d nodes in FINDNODE result", len(expect))
|
||||||
|
t.Logf("this can happen if the test is run multiple times in quick succession")
|
||||||
|
t.Logf("and the remote node hasn't removed dead nodes from previous runs yet")
|
||||||
|
} else {
|
||||||
|
t.Logf("all %d expected nodes were returned", len(nodes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A bystander is a node whose only purpose is filling a spot in the remote table.
|
||||||
|
type bystander struct {
|
||||||
|
dest *enode.Node
|
||||||
|
conn *conn
|
||||||
|
l net.PacketConn
|
||||||
|
|
||||||
|
addedCh chan enode.ID
|
||||||
|
done sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBystander(t *utesting.T, s *Suite, added chan enode.ID) *bystander {
|
||||||
|
conn, l := s.listen1(t)
|
||||||
|
conn.setEndpoint(l) // bystander nodes need IP/port to get pinged
|
||||||
|
bn := &bystander{
|
||||||
|
conn: conn,
|
||||||
|
l: l,
|
||||||
|
dest: s.Dest,
|
||||||
|
addedCh: added,
|
||||||
|
}
|
||||||
|
bn.done.Add(1)
|
||||||
|
go bn.loop()
|
||||||
|
return bn
|
||||||
|
}
|
||||||
|
|
||||||
|
// id returns the node ID of the bystander.
|
||||||
|
func (bn *bystander) id() enode.ID {
|
||||||
|
return bn.conn.localNode.ID()
|
||||||
|
}
|
||||||
|
|
||||||
|
// close shuts down loop.
|
||||||
|
func (bn *bystander) close() {
|
||||||
|
bn.conn.close()
|
||||||
|
bn.done.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop answers packets from the remote node until quit.
|
||||||
|
func (bn *bystander) loop() {
|
||||||
|
defer bn.done.Done()
|
||||||
|
|
||||||
|
var (
|
||||||
|
lastPing time.Time
|
||||||
|
wasAdded bool
|
||||||
|
)
|
||||||
|
for {
|
||||||
|
// Ping the remote node.
|
||||||
|
if !wasAdded && time.Since(lastPing) > 10*time.Second {
|
||||||
|
bn.conn.reqresp(bn.l, &v5wire.Ping{
|
||||||
|
ReqID: bn.conn.nextReqID(),
|
||||||
|
ENRSeq: bn.dest.Seq(),
|
||||||
|
})
|
||||||
|
lastPing = time.Now()
|
||||||
|
}
|
||||||
|
// Answer packets.
|
||||||
|
switch p := bn.conn.read(bn.l).(type) {
|
||||||
|
case *v5wire.Ping:
|
||||||
|
bn.conn.write(bn.l, &v5wire.Pong{
|
||||||
|
ReqID: p.ReqID,
|
||||||
|
ENRSeq: bn.conn.localNode.Seq(),
|
||||||
|
ToIP: bn.dest.IP(),
|
||||||
|
ToPort: uint16(bn.dest.UDP()),
|
||||||
|
}, nil)
|
||||||
|
wasAdded = true
|
||||||
|
bn.notifyAdded()
|
||||||
|
case *v5wire.Findnode:
|
||||||
|
bn.conn.write(bn.l, &v5wire.Nodes{ReqID: p.ReqID, Total: 1}, nil)
|
||||||
|
wasAdded = true
|
||||||
|
bn.notifyAdded()
|
||||||
|
case *v5wire.TalkRequest:
|
||||||
|
bn.conn.write(bn.l, &v5wire.TalkResponse{ReqID: p.ReqID}, nil)
|
||||||
|
case *readError:
|
||||||
|
if !netutil.IsTemporaryError(p.err) {
|
||||||
|
bn.conn.logf("shutting down: %v", p.err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bn *bystander) notifyAdded() {
|
||||||
|
if bn.addedCh != nil {
|
||||||
|
bn.addedCh <- bn.id()
|
||||||
|
bn.addedCh = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
263
cmd/devp2p/internal/v5test/framework.go
Normal file
263
cmd/devp2p/internal/v5test/framework.go
Normal file
|
|
@ -0,0 +1,263 @@
|
||||||
|
// Copyright 2020 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 v5test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discover/v5wire"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// readError represents an error during packet reading.
|
||||||
|
// This exists to facilitate type-switching on the result of conn.read.
|
||||||
|
type readError struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *readError) Kind() byte { return 99 }
|
||||||
|
func (p *readError) Name() string { return fmt.Sprintf("error: %v", p.err) }
|
||||||
|
func (p *readError) Error() string { return p.err.Error() }
|
||||||
|
func (p *readError) Unwrap() error { return p.err }
|
||||||
|
func (p *readError) RequestID() []byte { return nil }
|
||||||
|
func (p *readError) SetRequestID([]byte) {}
|
||||||
|
|
||||||
|
// readErrorf creates a readError with the given text.
|
||||||
|
func readErrorf(format string, args ...interface{}) *readError {
|
||||||
|
return &readError{fmt.Errorf(format, args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the response timeout used in tests.
|
||||||
|
const waitTime = 300 * time.Millisecond
|
||||||
|
|
||||||
|
// conn is a connection to the node under test.
|
||||||
|
type conn struct {
|
||||||
|
localNode *enode.LocalNode
|
||||||
|
localKey *ecdsa.PrivateKey
|
||||||
|
remote *enode.Node
|
||||||
|
remoteAddr *net.UDPAddr
|
||||||
|
listeners []net.PacketConn
|
||||||
|
|
||||||
|
log logger
|
||||||
|
codec *v5wire.Codec
|
||||||
|
lastRequest v5wire.Packet
|
||||||
|
lastChallenge *v5wire.Whoareyou
|
||||||
|
idCounter uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type logger interface {
|
||||||
|
Logf(string, ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// newConn sets up a connection to the given node.
|
||||||
|
func newConn(dest *enode.Node, log logger) *conn {
|
||||||
|
key, err := crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
db, err := enode.OpenDB("")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ln := enode.NewLocalNode(db, key)
|
||||||
|
|
||||||
|
return &conn{
|
||||||
|
localKey: key,
|
||||||
|
localNode: ln,
|
||||||
|
remote: dest,
|
||||||
|
remoteAddr: &net.UDPAddr{IP: dest.IP(), Port: dest.UDP()},
|
||||||
|
codec: v5wire.NewCodec(ln, key, mclock.System{}),
|
||||||
|
log: log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *conn) setEndpoint(c net.PacketConn) {
|
||||||
|
tc.localNode.SetStaticIP(laddr(c).IP)
|
||||||
|
tc.localNode.SetFallbackUDP(laddr(c).Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc *conn) listen(ip string) net.PacketConn {
|
||||||
|
l, err := net.ListenPacket("udp", fmt.Sprintf("%v:0", ip))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
tc.listeners = append(tc.listeners, l)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// close shuts down all listeners and the local node.
|
||||||
|
func (tc *conn) close() {
|
||||||
|
for _, l := range tc.listeners {
|
||||||
|
l.Close()
|
||||||
|
}
|
||||||
|
tc.localNode.Database().Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// nextReqID creates a request id.
|
||||||
|
func (tc *conn) nextReqID() []byte {
|
||||||
|
id := make([]byte, 4)
|
||||||
|
tc.idCounter++
|
||||||
|
binary.BigEndian.PutUint32(id, tc.idCounter)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// reqresp performs a request/response interaction on the given connection.
|
||||||
|
// The request is retried if a handshake is requested.
|
||||||
|
func (tc *conn) reqresp(c net.PacketConn, req v5wire.Packet) v5wire.Packet {
|
||||||
|
reqnonce := tc.write(c, req, nil)
|
||||||
|
switch resp := tc.read(c).(type) {
|
||||||
|
case *v5wire.Whoareyou:
|
||||||
|
if resp.Nonce != reqnonce {
|
||||||
|
return readErrorf("wrong nonce %x in WHOAREYOU (want %x)", resp.Nonce[:], reqnonce[:])
|
||||||
|
}
|
||||||
|
resp.Node = tc.remote
|
||||||
|
tc.write(c, req, resp)
|
||||||
|
return tc.read(c)
|
||||||
|
default:
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// findnode sends a FINDNODE request and waits for its responses.
|
||||||
|
func (tc *conn) findnode(c net.PacketConn, dists []uint) ([]*enode.Node, error) {
|
||||||
|
var (
|
||||||
|
findnode = &v5wire.Findnode{ReqID: tc.nextReqID(), Distances: dists}
|
||||||
|
reqnonce = tc.write(c, findnode, nil)
|
||||||
|
first = true
|
||||||
|
total uint8
|
||||||
|
results []*enode.Node
|
||||||
|
)
|
||||||
|
for n := 1; n > 0; {
|
||||||
|
switch resp := tc.read(c).(type) {
|
||||||
|
case *v5wire.Whoareyou:
|
||||||
|
// Handle handshake.
|
||||||
|
if resp.Nonce == reqnonce {
|
||||||
|
resp.Node = tc.remote
|
||||||
|
tc.write(c, findnode, resp)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("unexpected WHOAREYOU (nonce %x), waiting for NODES", resp.Nonce[:])
|
||||||
|
}
|
||||||
|
case *v5wire.Ping:
|
||||||
|
// Handle ping from remote.
|
||||||
|
tc.write(c, &v5wire.Pong{
|
||||||
|
ReqID: resp.ReqID,
|
||||||
|
ENRSeq: tc.localNode.Seq(),
|
||||||
|
}, nil)
|
||||||
|
case *v5wire.Nodes:
|
||||||
|
// Got NODES! Check request ID.
|
||||||
|
if !bytes.Equal(resp.ReqID, findnode.ReqID) {
|
||||||
|
return nil, fmt.Errorf("NODES response has wrong request id %x", resp.ReqID)
|
||||||
|
}
|
||||||
|
// Check total count. It should be greater than one
|
||||||
|
// and needs to be the same across all responses.
|
||||||
|
if first {
|
||||||
|
if resp.Total == 0 || resp.Total > 6 {
|
||||||
|
return nil, fmt.Errorf("invalid NODES response 'total' %d (not in (0,7))", resp.Total)
|
||||||
|
}
|
||||||
|
total = resp.Total
|
||||||
|
n = int(total) - 1
|
||||||
|
first = false
|
||||||
|
} else {
|
||||||
|
n--
|
||||||
|
if resp.Total != total {
|
||||||
|
return nil, fmt.Errorf("invalid NODES response 'total' %d (!= %d)", resp.Total, total)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check nodes.
|
||||||
|
nodes, err := checkRecords(resp.Nodes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid node in NODES response: %v", err)
|
||||||
|
}
|
||||||
|
results = append(results, nodes...)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("expected NODES, got %v", resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// write sends a packet on the given connection.
|
||||||
|
func (tc *conn) write(c net.PacketConn, p v5wire.Packet, challenge *v5wire.Whoareyou) v5wire.Nonce {
|
||||||
|
packet, nonce, err := tc.codec.Encode(tc.remote.ID(), tc.remoteAddr.String(), p, challenge)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("can't encode %v packet: %v", p.Name(), err))
|
||||||
|
}
|
||||||
|
if _, err := c.WriteTo(packet, tc.remoteAddr); err != nil {
|
||||||
|
tc.logf("Can't send %s: %v", p.Name(), err)
|
||||||
|
} else {
|
||||||
|
tc.logf(">> %s", p.Name())
|
||||||
|
}
|
||||||
|
return nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
// read waits for an incoming packet on the given connection.
|
||||||
|
func (tc *conn) read(c net.PacketConn) v5wire.Packet {
|
||||||
|
buf := make([]byte, 1280)
|
||||||
|
if err := c.SetReadDeadline(time.Now().Add(waitTime)); err != nil {
|
||||||
|
return &readError{err}
|
||||||
|
}
|
||||||
|
n, fromAddr, err := c.ReadFrom(buf)
|
||||||
|
if err != nil {
|
||||||
|
return &readError{err}
|
||||||
|
}
|
||||||
|
_, _, p, err := tc.codec.Decode(buf[:n], fromAddr.String())
|
||||||
|
if err != nil {
|
||||||
|
return &readError{err}
|
||||||
|
}
|
||||||
|
tc.logf("<< %s", p.Name())
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// logf prints to the test log.
|
||||||
|
func (tc *conn) logf(format string, args ...interface{}) {
|
||||||
|
if tc.log != nil {
|
||||||
|
tc.log.Logf("(%s) %s", tc.localNode.ID().TerminalString(), fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func laddr(c net.PacketConn) *net.UDPAddr {
|
||||||
|
return c.LocalAddr().(*net.UDPAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRecords(records []*enr.Record) ([]*enode.Node, error) {
|
||||||
|
nodes := make([]*enode.Node, len(records))
|
||||||
|
for i := range records {
|
||||||
|
n, err := enode.New(enode.ValidSchemes, records[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nodes[i] = n
|
||||||
|
}
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsUint(ints []uint, x uint) bool {
|
||||||
|
for i := range ints {
|
||||||
|
if ints[i] == x {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
@ -20,8 +20,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/maticnetwork/bor/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/internal/debug"
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
"github.com/maticnetwork/bor/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/maticnetwork/bor/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -63,6 +63,7 @@ func init() {
|
||||||
discv5Command,
|
discv5Command,
|
||||||
dnsCommand,
|
dnsCommand,
|
||||||
nodesetCommand,
|
nodesetCommand,
|
||||||
|
rlpxCommand,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,7 +81,7 @@ func commandHasFlag(ctx *cli.Context, flag cli.Flag) bool {
|
||||||
|
|
||||||
// getNodeArg handles the common case of a single node descriptor argument.
|
// getNodeArg handles the common case of a single node descriptor argument.
|
||||||
func getNodeArg(ctx *cli.Context) *enode.Node {
|
func getNodeArg(ctx *cli.Context) *enode.Node {
|
||||||
if ctx.NArg() != 1 {
|
if ctx.NArg() < 1 {
|
||||||
exit("missing node as command-line argument")
|
exit("missing node as command-line argument")
|
||||||
}
|
}
|
||||||
n, err := parseNode(ctx.Args()[0])
|
n, err := parseNode(ctx.Args()[0])
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/maticnetwork/bor/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/maticnetwork/bor/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
)
|
)
|
||||||
|
|
||||||
const jsonIndent = " "
|
const jsonIndent = " "
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue