use go-ethereum for better forked-bor release

This commit is contained in:
Jaynti Kanani 2020-11-13 09:21:48 +05:30
parent adf77d28e8
commit 1e56a697c0
No known key found for this signature in database
GPG key ID: 4396982C976BAE5E
826 changed files with 30446 additions and 26517 deletions

57
COPYING
View file

@ -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>.

View file

@ -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"]

View file

@ -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
View file

@ -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
View file

@ -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.
[![API Reference](
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
)](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc)
[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
[![Travis](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum)
[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](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

View file

@ -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) |

View file

@ -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) return args.UnpackIntoMap(v, data)
}
if event, ok := abi.Events[name]; ok {
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
} }

View file

@ -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);

View file

@ -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())
} }
// make sure the passed value is arguments pointer return defaultVars, nil
if reflect.Ptr != reflect.ValueOf(v).Kind() {
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
} }
marshalledValues, err := arguments.UnpackValues(data) return 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

View file

@ -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,

View file

@ -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 {

View file

@ -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()
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { if len(b.pendingBlock.Transactions()) != 0 {
for _, tx := range b.pendingBlock.Transactions() { return errors.New("Could not adjust time on non-empty block")
block.AddTx(tx)
} }
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
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) {

View file

@ -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),

View file

@ -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
} }
} }

View file

@ -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")

View file

@ -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

View file

@ -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}})
{{if .Structured}}
outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} })
{{range $i, $t := .Normalized.Outputs}}
outstruct.{{.Name}} = out[{{$i}}].({{bindtype .Type $structs}}){{end}}
return *outstruct, err
{{else}}
if err != nil {
return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{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}} {{end}}
}){{else}}var (
{{range $i, $_ := .Normalized.Outputs}}ret{{$i}} = new({{bindtype .Type $structs}})
{{end}}
){{end}}
out := {{if .Structured}}ret{{else}}{{if eq (len .Normalized.Outputs) 1}}ret0{{else}}&[]interface{}{
{{range $i, $_ := .Normalized.Outputs}}ret{{$i}},
{{end}}
}{{end}}{{end}}
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
} }
// {{.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!

View file

@ -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.

View file

@ -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")

View file

@ -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

View file

@ -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

View file

@ -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)
} }

View file

@ -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

View file

@ -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")
} }
} }

View file

@ -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)

View file

@ -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

View file

@ -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() {

View file

@ -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))
}
}

View file

@ -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{}) {

View file

@ -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) {

View file

@ -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

View file

@ -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)
}
}
}

View file

@ -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)

View file

@ -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)
} }

View file

@ -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.
// //

View file

@ -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) {

View file

@ -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 {

View file

@ -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

View file

@ -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 (

View file

@ -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

View file

@ -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"
) )

View file

@ -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 (

View file

@ -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)
} }

View file

@ -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"

View file

@ -20,7 +20,7 @@ import (
"io/ioutil" "io/ioutil"
"testing" "testing"
"github.com/maticnetwork/bor/common" "github.com/ethereum/go-ethereum/common"
) )
const ( const (

View file

@ -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 {

View file

@ -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) {

View file

@ -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"
) )

View file

@ -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

View file

@ -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"
) )

View file

@ -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.

View file

@ -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.

View file

@ -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"

View file

@ -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.
// //

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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.
// //

View file

@ -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

View file

@ -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

View file

@ -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
} }

View file

@ -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

View file

@ -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>

View file

@ -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"

View file

@ -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"

View file

@ -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
View 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

View file

@ -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() {

View file

@ -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 {

View file

@ -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

View file

@ -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"
) )

View file

@ -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"
) )

View file

@ -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.

View file

@ -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"
) )

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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
View 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

View file

@ -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 {

View file

@ -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)
if uaddr.IP.IsUnspecified() {
ln.SetFallbackIP(net.IP{127, 0, 0, 1}) 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

View file

@ -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()

View file

@ -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"
) )

View file

@ -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"
) )

View file

@ -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"
) )

View file

@ -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 {

View 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
}

View 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)
})
}
}

View 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
}

Binary file not shown.

View 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"
}

View 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)
}
}
}

View file

@ -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 (

View file

@ -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

View 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
}
}

View 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
}

View file

@ -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"
) )

View file

@ -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])

View file

@ -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