good morning!!!!

Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • github/maticnetwork/bor
  • open/bor
2 results
Show changes
Commits on Source (264)
Showing
with 596 additions and 240 deletions
......@@ -6,10 +6,15 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Install Go
uses: actions/setup-go@v2.1.3
uses: actions/setup-go@v2
with:
go-version: 1.15.5
go-version: 1.17
- name: "Build binaries"
run: make all
- name: "Run tests"
run: make test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
file: ./cover.out
name: Docker Images For Latest Branches
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build docker image
env:
DOCKERHUB: ${{ secrets.DOCKERHUB }}
DOCKERHUB_KEY: ${{ secrets.DOCKERHUB_KEY }}
run: |
set -x
ls -l
echo "Docker login"
docker login -u $DOCKERHUB -p $DOCKERHUB_KEY
echo "Running build"
docker build -t maticnetwork/bor:${GITHUB_REF/refs\/heads\//} .
echo "Pushing image"
docker push maticnetwork/bor:${GITHUB_REF/refs\/heads\//}
echo "Done"
......@@ -2,8 +2,12 @@ name: Bor Docker Image CI
on:
push:
branches-ignore:
- '**'
tags:
- 'v*.*.*'
# to be used by fork patch-releases ^^
- 'v*.*.*-*'
jobs:
build:
......@@ -19,7 +23,7 @@ jobs:
echo "Docker login"
docker login -u $DOCKERHUB -p $DOCKERHUB_KEY
echo "running build"
docker build -t maticnetwork/bor:${GITHUB_REF/refs\/tags\//} .
docker build -f Dockerfile.classic -t maticnetwork/bor:${GITHUB_REF/refs\/tags\//} .
echo "pushing image"
docker push maticnetwork/bor:${GITHUB_REF/refs\/tags\//}
echo "DONE!"
name: Linux package
on:
push:
tags:
- "v*.*.*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Go
uses: actions/setup-go@v1
with:
go-version: 1.15.5
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6
- name: Retrieve release version
run: |
echo "RELEASE_VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV
- name: Build package
run: |
set -x
echo "Release version: ${{ env.RELEASE_VERSION }}"
sudo apt-get -yqq install libpq-dev build-essential
gem install --no-document fpm
fpm --version
make bor-all
fpm -s dir -t deb --deb-user root --deb-group root -n matic-bor -v ${{ env.RELEASE_VERSION }} \
build/bin/bor=/usr/bin/ \
build/bin/bootnode=/usr/bin/
mkdir packages-v${{ env.RELEASE_VERSION }}
mv matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb packages-v${{ env.RELEASE_VERSION }}/
ls packages-v${{ env.RELEASE_VERSION }}/
- name: S3 upload
uses: jakejarvis/s3-sync-action@master
with:
args: --acl public-read
env:
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: "us-east-1" # optional: defaults to us-east-1
SOURCE_DIR: "packages-v${{ env.RELEASE_VERSION }}"
DEST_DIR: "v${{ env.RELEASE_VERSION }}"
- name: Slack Notification
uses: rtCamp/action-slack-notify@v2.0.0
env:
SLACK_CHANNEL: code-releases
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_TITLE: "New linux package for Bor v${{ env.RELEASE_VERSION }} just got released"
SLACK_MESSAGE: "Package has been uploaded to S3 bucket for public use and available at https://matic-public.s3.amazonaws.com/v${{ env.RELEASE_VERSION }}/matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb"
name: Release
on:
push:
branches-ignore:
- '**'
tags:
- 'v*.*.*'
# to be used by fork patch-releases ^^
- 'v*.*.*-*'
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@master
with:
go-version: 1.17.x
- name: Prepare
id: prepare
run: |
TAG=${GITHUB_REF#refs/tags/}
echo ::set-output name=tag_name::${TAG}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Run GoReleaser
run: |
make release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.prepare.outputs.tag_name }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
DOCKER_USERNAME: ${{ secrets.DOCKERHUB }}
DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_KEY }}
......@@ -47,3 +47,7 @@ profile.cov
/dashboard/assets/package-lock.json
**/yarn-error.log
./test
./bor-debug-*
dist
# This file configures github.com/golangci/golangci-lint.
run:
timeout: 3m
timeout: 5m
tests: true
# default is true. Enables skipping of directories:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
......
project_name: bor
release:
disable: false
draft: true
prerelease: auto
builds:
- id: darwin-amd64
main: ./cmd/geth
binary: bor
goos:
- darwin
goarch:
- amd64
env:
- CC=o64-clang
- CXX=o64-clang++
tags:
- netgo
ldflags:
-s -w
- id: darwin-arm64
main: ./cmd/geth
binary: bor
goos:
- darwin
goarch:
- arm64
env:
- CC=oa64-clang
- CXX=oa64-clang++
tags:
- netgo
ldflags:
-s -w
- id: linux-amd64
main: ./cmd/geth
binary: bor
goos:
- linux
goarch:
- amd64
env:
- CC=gcc
- CXX=g++
tags:
- netgo
ldflags:
# We need to build a static binary because we are building in a glibc based system and running in a musl container
-s -w -extldflags "-static"
- id: linux-arm64
main: ./cmd/geth
binary: bor
goos:
- linux
goarch:
- arm64
env:
- CC=aarch64-linux-gnu-gcc
- CXX=aarch64-linux-gnu-g++
tags:
- netgo
ldflags:
# We need to build a static binary because we are building in a glibc based system and running in a musl container
-s -w -extldflags "-static"
nfpms:
- vendor: 0xPolygon
homepage: https://polygon.technology
maintainer: Polygon Team <team@polygon.technology>
description: Polygon Blockchain
license: GPLv3 LGPLv3
formats:
- apk
- deb
- rpm
contents:
- src: builder/files/bor.service
dst: /lib/systemd/system/bor.service
type: config
- src: builder/files/genesis-mainnet-v1.json
dst: /etc/bor/genesis-mainnet-v1.json
type: config
- src: builder/files/genesis-testnet-v4.json
dst: /etc/bor/genesis-testnet-v4.json
type: config
overrides:
rpm:
replacements:
amd64: x86_64
snapshot:
name_template: "{{ .Tag }}.next"
dockers:
- image_templates:
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-amd64
dockerfile: Dockerfile.release
use: buildx
goarch: amd64
ids:
- linux-amd64
build_flag_templates:
- --platform=linux/amd64
extra_files:
- builder/files/genesis-mainnet-v1.json
- builder/files/genesis-testnet-v4.json
- image_templates:
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-arm64
dockerfile: Dockerfile.release
use: buildx
goarch: arm64
ids:
- linux-arm64
build_flag_templates:
- --platform=linux/arm64/v8
extra_files:
- builder/files/genesis-mainnet-v1.json
- builder/files/genesis-testnet-v4.json
docker_manifests:
- name_template: 0xpolygon/{{ .ProjectName }}:{{ .Version }}
image_templates:
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-amd64
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-arm64
- name_template: 0xpolygon/{{ .ProjectName }}:latest
image_templates:
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-amd64
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-arm64
announce:
slack:
enabled: true
# The name of the channel that the user selected as a destination for webhook messages.
channel: '#code-releases'
......@@ -263,3 +263,15 @@ jobs:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go purge -store gethstore/builds -days 14
# This builder executes race tests
- stage: build
if: type = cron
os: linux
dist: bionic
go: 1.17.x
env:
- GO111MODULE=on
script:
- go run build/ci.go test -race -coverage $TEST_PACKAGES
# Build Geth in a stock Go builder container
FROM golang:1.17-alpine as builder
FROM golang:latest
RUN apk add --no-cache make gcc musl-dev linux-headers git bash
ARG BOR_DIR=/bor
ENV BOR_DIR=$BOR_DIR
ADD . /bor
RUN cd /bor && make bor-all
RUN apt-get update -y && apt-get upgrade -y \
&& apt install build-essential git -y \
&& mkdir -p /bor
CMD ["/bin/bash"]
WORKDIR ${BOR_DIR}
COPY . .
RUN make bor-all
# Pull Bor into a second stage deploy alpine container
FROM alpine:latest
ENV SHELL /bin/bash
EXPOSE 8545 8546 8547 30303 30303/udp
RUN apk add --no-cache ca-certificates
COPY --from=builder /bor/build/bin/bor /usr/local/bin/
COPY --from=builder /bor/build/bin/bootnode /usr/local/bin/
EXPOSE 8545 8546 8547 30303 30303/udp
\ No newline at end of file
ENTRYPOINT ["bor"]
......@@ -9,7 +9,10 @@ RUN cd /bor && make bor-all
# Pull all binaries into a second stage deploy alpine container
FROM alpine:latest
RUN apk add --no-cache ca-certificates
RUN set -x \
&& apk add --update --no-cache \
ca-certificates \
&& rm -rf /var/cache/apk/*
COPY --from=builder /bor/build/bin/* /usr/local/bin/
EXPOSE 8545 8546 30303 30303/udp
\ No newline at end of file
EXPOSE 8545 8546 30303 30303/udp
# Build Geth in a stock Go builder container
FROM golang:1.17-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git bash
ADD . /bor
RUN cd /bor && make bor-all
CMD ["/bin/bash"]
# Pull Bor into a second stage deploy alpine container
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=builder /bor/build/bin/bor /usr/local/bin/
COPY --from=builder /bor/build/bin/bootnode /usr/local/bin/
EXPOSE 8545 8546 8547 30303 30303/udp
FROM alpine:3.14
RUN apk add --no-cache ca-certificates && \
mkdir -p /etc/bor
COPY bor /usr/local/bin/
COPY builder/files/genesis-mainnet-v1.json /etc/bor/
COPY builder/files/genesis-testnet-v4.json /etc/bor/
EXPOSE 8545 8546 8547 30303 30303/udp
ENTRYPOINT ["bor"]
......@@ -25,6 +25,9 @@ bor-all:
cp $(GOBIN)/geth $(GOBIN)/bor
cp $(GOBIN)/* $(GOPATH)/bin/
protoc:
protoc --go_out=. --go-grpc_out=. ./command/server/proto/*.proto
geth:
$(GORUN) build/ci.go install ./cmd/geth
@echo "Done building."
......@@ -45,10 +48,9 @@ ios:
@echo "Done building."
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
test: all
# $(GORUN) build/ci.go test
go test github.com/ethereum/go-ethereum/consensus/bor
go test github.com/ethereum/go-ethereum/tests/bor
test:
# Skip mobile and cmd tests since they are being deprecated
go test -v $$(go list ./... | grep -v go-ethereum/cmd/) -cover -coverprofile=cover.out
lint: ## Run linters.
$(GORUN) build/ci.go lint
......@@ -160,3 +162,37 @@ geth-windows-amd64:
$(GORUN) build/ci.go xgo -- --go=$(GO) --targets=windows/amd64 -v ./cmd/geth
@echo "Windows amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep amd64
PACKAGE_NAME := github.com/maticnetwork/bor
GOLANG_CROSS_VERSION ?= v1.17.2
.PHONY: release-dry-run
release-dry-run:
@docker run \
--rm \
--privileged \
-e CGO_ENABLED=1 \
-e GITHUB_TOKEN \
-e DOCKER_USERNAME \
-e DOCKER_PASSWORD \
-v /var/run/docker.sock:/var/run/docker.sock \
-v `pwd`:/go/src/$(PACKAGE_NAME) \
-w /go/src/$(PACKAGE_NAME) \
ghcr.io/troian/golang-cross:${GOLANG_CROSS_VERSION} \
--rm-dist --skip-validate --skip-publish
.PHONY: release
release:
@docker run \
--rm \
--privileged \
-e CGO_ENABLED=1 \
-e GITHUB_TOKEN \
-e DOCKER_USERNAME \
-e DOCKER_PASSWORD \
-e SLACK_WEBHOOK \
-v /var/run/docker.sock:/var/run/docker.sock \
-v `pwd`:/go/src/$(PACKAGE_NAME) \
-w /go/src/$(PACKAGE_NAME) \
ghcr.io/troian/golang-cross:${GOLANG_CROSS_VERSION} \
--rm-dist --skip-validate
## Bor
# Bor Overview
Bor is the Official Golang implementation of the Matic protocol. It is a fork of Go Ethereum - https://github.com/ethereum/go-ethereum and EVM compabile.
Official Golang implementation of the Matic protocol (fork of Go Ethereum - https://github.com/ethereum/go-ethereum)
![Forks](https://img.shields.io/github/forks/maticnetwork/bor?style=social)
![Stars](https://img.shields.io/github/stars/maticnetwork/bor?style=social)
![Languages](https://img.shields.io/github/languages/count/maticnetwork/bor)
![Issues](https://img.shields.io/github/issues/maticnetwork/bor)
![PRs](https://img.shields.io/github/issues-pr-raw/maticnetwork/bor)
![MIT License](https://img.shields.io/github/license/maticnetwork/bor)
![contributors](https://img.shields.io/github/contributors-anon/maticnetwork/bor)
![size](https://img.shields.io/github/languages/code-size/maticnetwork/bor)
![lines](https://img.shields.io/tokei/lines/github/maticnetwork/bor)
[![Discord](https://img.shields.io/discord/714888181740339261?color=1C1CE1&label=Polygon%20%7C%20Discord%20%F0%9F%91%8B%20&style=flat-square)](https://discord.gg/zdwkdvMNY2)
[![Twitter Follow](https://img.shields.io/twitter/follow/0xPolygon.svg?style=social)](https://twitter.com/0xPolygon)
## Building the source
## How to contribute
Building `bor` requires both a Go (version 1.14 or later) and a C compiler. You can install
### Contribution Guidelines
We believe one of the things that makes Polygon special is its coherent design and we seek to retain this defining characteristic. From the outset we defined some guidelines to ensure new contributions only ever enhance the project:
* Quality: Code in the Polygon project should meet the style guidelines, with sufficient test-cases, descriptive commit messages, evidence that the contribution does not break any compatibility commitments or cause adverse feature interactions, and evidence of high-quality peer-review
* Size: The Polygon project’s culture is one of small pull-requests, regularly submitted. The larger a pull-request, the more likely it is that you will be asked to resubmit as a series of self-contained and individually reviewable smaller PRs
* Maintainability: If the feature will require ongoing maintenance (eg support for a particular brand of database), we may ask you to accept responsibility for maintaining this feature
### Submit an issue
- Create a [new issue](https://github.com/maticnetwork/bor/issues/new/choose)
- Comment on the issue (if you'd like to be assigned to it) - that way [our team can assign the issue to you](https://github.blog/2019-06-25-assign-issues-to-issue-commenters/).
- If you do not have a specific contribution in mind, you can also browse the issues labelled as `help wanted`
- Issues that additionally have the `good first issue` label are considered ideal for first-timers
### Fork the repository (repo)
- If you're not sure, here's how to [fork the repo](https://help.github.com/en/articles/fork-a-repo)
- If this is your first time forking our repo, this is all you need to do for this step:
```
$ git clone git@github.com:[your_github_handle]/bor
```
- If you've already forked the repo, you'll want to ensure your fork is configured and that it's up to date. This will save you the headache of potential merge conflicts.
- To [configure your fork](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork):
```
$ git remote add upstream https://github.com/maticnetwork/bor
```
- To [sync your fork with the latest changes](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork):
```
$ git checkout master
$ git fetch upstream
$ git merge upstream/master
```
### Building the source
- Building `bor` requires both a Go (version 1.14 or later) and a C compiler. You can install
them using your favourite package manager. Once the dependencies are installed, run
```shell
make bor
```
```shell
$ make bor
```
- or, to build the full suite of utilities:
```shell
$ make bor-all
```
### Make awesome changes!
1. Create new branch for your changes
or, to build the full suite of utilities:
```
$ git checkout -b new_branch_name
```
2. Commit and prepare for pull request (PR). In your PR commit message, reference the issue it resolves (see [how to link a commit message to an issue using a keyword](https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword).
Checkout our [Git-Rules](https://docs.polygon.technology/docs/contribute/orientation#git-rules)
```
$ git commit -m "brief description of changes [Fixes #1234]"
```
3. Push to your GitHub account
```
$ git push
```
### Submit your PR
- After your changes are commited to your GitHub fork, submit a pull request (PR) to the `master` branch of the `maticnetwork/bor` repo
- In your PR description, reference the issue it resolves (see [linking a pull request to an issue using a keyword](https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword))
- ex. `Updates out of date content [Fixes #1234]`
- Why not say hi and draw attention to your PR in [our discord server](https://discord.gg/zdwkdvMNY2)?
### Wait for review
- The team reviews every PR
- Acceptable PRs will be approved & merged into the `master` branch
<hr style="margin-top: 3em; margin-bottom: 3em;">
## Release
- You can [view the history of releases](https://github.com/maticnetwork/bor/releases), which include PR highlights
<hr style="margin-top: 3em; margin-bottom: 3em;">
Build the beta client:
```shell
make bor-all
go build -o bor-beta command/*.go
```
## License
......@@ -25,4 +127,10 @@ also included in our repository in the `COPYING.LESSER` file.
The go-ethereum binaries (i.e. all code inside of the `cmd` directory) is licensed under the
[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), also
included in our repository in the `COPYING` file.
\ No newline at end of file
included in our repository in the `COPYING` file.
<hr style="margin-top: 3em; margin-bottom: 3em;">
## Join our Discord server
Join Polygon community – share your ideas or just say hi over [on Discord](https://discord.gg/zdwkdvMNY2).
......@@ -12,6 +12,8 @@ Audit reports are published in the `docs` folder: https://github.com/ethereum/go
| ------- | ------- | ----------- |
| `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/ethereum/go-ethereum/blob/master/docs/audits/2018-09-14_Clef-audit_NCC.pdf) |
| `Discv5` | 20191015 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2019-10-15_Discv5_audit_LeastAuthority.pdf) |
| `Discv5` | 20200124 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2020-01-24_DiscV5_audit_Cure53.pdf) |
## Reporting a Vulnerability
......
......@@ -34,6 +34,7 @@ type ABI struct {
Constructor Method
Methods map[string]Method
Events map[string]Event
Errors map[string]Error
// Additional "special" functions introduced in solidity v0.6.0.
// It's separated from the original default fallback. Each contract
......@@ -157,12 +158,13 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
}
abi.Methods = make(map[string]Method)
abi.Events = make(map[string]Event)
abi.Errors = make(map[string]Error)
for _, field := range fields {
switch field.Type {
case "constructor":
abi.Constructor = NewMethod("", "", Constructor, field.StateMutability, field.Constant, field.Payable, field.Inputs, nil)
case "function":
name := abi.overloadedMethodName(field.Name)
name := overloadedName(field.Name, func(s string) bool { _, ok := abi.Methods[s]; return ok })
abi.Methods[name] = NewMethod(name, field.Name, Function, field.StateMutability, field.Constant, field.Payable, field.Inputs, field.Outputs)
case "fallback":
// New introduced function type in v0.6.0, check more detail
......@@ -182,8 +184,10 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
}
abi.Receive = NewMethod("", "", Receive, field.StateMutability, field.Constant, field.Payable, nil, nil)
case "event":
name := abi.overloadedEventName(field.Name)
name := overloadedName(field.Name, func(s string) bool { _, ok := abi.Events[s]; return ok })
abi.Events[name] = NewEvent(name, field.Name, field.Anonymous, field.Inputs)
case "error":
abi.Errors[field.Name] = NewError(field.Name, field.Inputs)
default:
return fmt.Errorf("abi: could not recognize type %v of field %v", field.Type, field.Name)
}
......@@ -191,36 +195,6 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
return nil
}
// overloadedMethodName returns the next available name for a given function.
// Needed since solidity allows for function overload.
//
// e.g. if the abi contains Methods send, send1
// overloadedMethodName would return send2 for input send.
func (abi *ABI) overloadedMethodName(rawName string) string {
name := rawName
_, ok := abi.Methods[name]
for idx := 0; ok; idx++ {
name = fmt.Sprintf("%s%d", rawName, idx)
_, ok = abi.Methods[name]
}
return name
}
// overloadedEventName returns the next available name for a given event.
// Needed since solidity allows for event overload.
//
// e.g. if the abi contains events received, received1
// overloadedEventName would return received2 for input received.
func (abi *ABI) overloadedEventName(rawName string) string {
name := rawName
_, ok := abi.Events[name]
for idx := 0; ok; idx++ {
name = fmt.Sprintf("%s%d", rawName, idx)
_, ok = abi.Events[name]
}
return name
}
// MethodById looks up a method by the 4-byte id,
// returns nil if none found.
func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
......@@ -277,3 +251,20 @@ func UnpackRevert(data []byte) (string, error) {
}
return unpacked[0].(string), nil
}
// overloadedName returns the next available name for a given thing.
// Needed since solidity allows for overloading.
//
// e.g. if the abi contains Methods send, send1
// overloadedName would return send2 for input send.
//
// overloadedName works for methods, events and errors.
func overloadedName(rawName string, isAvail func(string) bool) string {
name := rawName
ok := isAvail(name)
for idx := 0; ok; idx++ {
name = fmt.Sprintf("%s%d", rawName, idx)
ok = isAvail(name)
}
return name
}
......@@ -295,6 +295,20 @@ func TestOverloadedMethodSignature(t *testing.T) {
check("bar0", "bar(uint256,uint256)", false)
}
func TestCustomErrors(t *testing.T) {
json := `[{ "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ],"name": "MyError", "type": "error"} ]`
abi, err := JSON(strings.NewReader(json))
if err != nil {
t.Fatal(err)
}
check := func(name string, expect string) {
if abi.Errors[name].Sig != expect {
t.Fatalf("The signature of overloaded method mismatch, want %s, have %s", expect, abi.Methods[name].Sig)
}
}
check("MyError", "MyError(uint256)")
}
func TestMultiPack(t *testing.T) {
abi, err := JSON(strings.NewReader(jsondata))
if err != nil {
......
......@@ -137,7 +137,7 @@ func (arguments Arguments) copyAtomic(v interface{}, marshalledValues interface{
dst := reflect.ValueOf(v).Elem()
src := reflect.ValueOf(marshalledValues)
if dst.Kind() == reflect.Struct && src.Kind() != reflect.Struct {
if dst.Kind() == reflect.Struct {
return set(dst.Field(0), src)
}
return set(dst, src)
......
......@@ -231,108 +231,158 @@ func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error)
return c.transact(opts, &c.address, nil)
}
// transact executes an actual transaction invocation, first deriving any missing
// authorization fields, and then scheduling the transaction for execution.
func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
var err error
// Ensure a valid value field and resolve the account nonce
func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Address, input []byte, head *types.Header) (*types.Transaction, error) {
// Normalize value
value := opts.Value
if value == nil {
value = new(big.Int)
}
var nonce uint64
if opts.Nonce == nil {
nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From)
// Estimate TipCap
gasTipCap := opts.GasTipCap
if gasTipCap == nil {
tip, err := c.transactor.SuggestGasTipCap(ensureContext(opts.Context))
if err != nil {
return nil, fmt.Errorf("failed to retrieve account nonce: %v", err)
return nil, err
}
} else {
nonce = opts.Nonce.Uint64()
gasTipCap = tip
}
// Figure out reasonable gas price values
if opts.GasPrice != nil && (opts.GasFeeCap != nil || opts.GasTipCap != nil) {
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
// Estimate FeeCap
gasFeeCap := opts.GasFeeCap
if gasFeeCap == nil {
gasFeeCap = new(big.Int).Add(
gasTipCap,
new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
)
}
head, err := c.transactor.HeaderByNumber(ensureContext(opts.Context), nil)
if gasFeeCap.Cmp(gasTipCap) < 0 {
return nil, fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", gasFeeCap, gasTipCap)
}
// Estimate GasLimit
gasLimit := opts.GasLimit
if opts.GasLimit == 0 {
var err error
gasLimit, err = c.estimateGasLimit(opts, contract, input, nil, gasTipCap, gasFeeCap, value)
if err != nil {
return nil, err
}
}
// create the transaction
nonce, err := c.getNonce(opts)
if err != nil {
return nil, err
}
if head.BaseFee != nil && opts.GasPrice == nil {
if opts.GasTipCap == nil {
tip, err := c.transactor.SuggestGasTipCap(ensureContext(opts.Context))
if err != nil {
return nil, err
}
opts.GasTipCap = tip
}
if opts.GasFeeCap == nil {
gasFeeCap := new(big.Int).Add(
opts.GasTipCap,
new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
)
opts.GasFeeCap = gasFeeCap
}
if opts.GasFeeCap.Cmp(opts.GasTipCap) < 0 {
return nil, fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", opts.GasFeeCap, opts.GasTipCap)
}
} else {
if opts.GasFeeCap != nil || opts.GasTipCap != nil {
return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet")
}
if opts.GasPrice == nil {
price, err := c.transactor.SuggestGasPrice(ensureContext(opts.Context))
if err != nil {
return nil, err
}
opts.GasPrice = price
baseTx := &types.DynamicFeeTx{
To: contract,
Nonce: nonce,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
Gas: gasLimit,
Value: value,
Data: input,
}
return types.NewTx(baseTx), nil
}
func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
if opts.GasFeeCap != nil || opts.GasTipCap != nil {
return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet")
}
// Normalize value
value := opts.Value
if value == nil {
value = new(big.Int)
}
// Estimate GasPrice
gasPrice := opts.GasPrice
if gasPrice == nil {
price, err := c.transactor.SuggestGasPrice(ensureContext(opts.Context))
if err != nil {
return nil, err
}
gasPrice = price
}
// Estimate GasLimit
gasLimit := opts.GasLimit
if gasLimit == 0 {
// Gas estimation cannot succeed without code for method invocations
if contract != nil {
if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil {
return nil, err
} else if len(code) == 0 {
return nil, ErrNoCode
}
}
// If the contract surely has code (or code is not needed), estimate the transaction
msg := ethereum.CallMsg{From: opts.From, To: contract, GasPrice: opts.GasPrice, GasTipCap: opts.GasTipCap, GasFeeCap: opts.GasFeeCap, Value: value, Data: input}
gasLimit, err = c.transactor.EstimateGas(ensureContext(opts.Context), msg)
if opts.GasLimit == 0 {
var err error
gasLimit, err = c.estimateGasLimit(opts, contract, input, gasPrice, nil, nil, value)
if err != nil {
return nil, fmt.Errorf("failed to estimate gas needed: %v", err)
return nil, err
}
}
// Create the transaction, sign it and schedule it for execution
var rawTx *types.Transaction
if opts.GasFeeCap == nil {
baseTx := &types.LegacyTx{
Nonce: nonce,
GasPrice: opts.GasPrice,
Gas: gasLimit,
Value: value,
Data: input,
}
if contract != nil {
baseTx.To = &c.address
// create the transaction
nonce, err := c.getNonce(opts)
if err != nil {
return nil, err
}
baseTx := &types.LegacyTx{
To: contract,
Nonce: nonce,
GasPrice: gasPrice,
Gas: gasLimit,
Value: value,
Data: input,
}
return types.NewTx(baseTx), nil
}
func (c *BoundContract) estimateGasLimit(opts *TransactOpts, contract *common.Address, input []byte, gasPrice, gasTipCap, gasFeeCap, value *big.Int) (uint64, error) {
if contract != nil {
// Gas estimation cannot succeed without code for method invocations.
if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil {
return 0, err
} else if len(code) == 0 {
return 0, ErrNoCode
}
rawTx = types.NewTx(baseTx)
}
msg := ethereum.CallMsg{
From: opts.From,
To: contract,
GasPrice: gasPrice,
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Value: value,
Data: input,
}
return c.transactor.EstimateGas(ensureContext(opts.Context), msg)
}
func (c *BoundContract) getNonce(opts *TransactOpts) (uint64, error) {
if opts.Nonce == nil {
return c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From)
} else {
baseTx := &types.DynamicFeeTx{
Nonce: nonce,
GasFeeCap: opts.GasFeeCap,
GasTipCap: opts.GasTipCap,
Gas: gasLimit,
Value: value,
Data: input,
}
if contract != nil {
baseTx.To = &c.address
return opts.Nonce.Uint64(), nil
}
}
// transact executes an actual transaction invocation, first deriving any missing
// authorization fields, and then scheduling the transaction for execution.
func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
if opts.GasPrice != nil && (opts.GasFeeCap != nil || opts.GasTipCap != nil) {
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
}
// Create the transaction
var (
rawTx *types.Transaction
err error
)
if opts.GasPrice != nil {
rawTx, err = c.createLegacyTx(opts, contract, input)
} else {
// Only query for basefee if gasPrice not specified
if head, errHead := c.transactor.HeaderByNumber(ensureContext(opts.Context), nil); err != nil {
return nil, errHead
} else if head.BaseFee != nil {
rawTx, err = c.createDynamicTx(opts, contract, input, head)
} else {
// Chain is not London ready -> use legacy transaction
rawTx, err = c.createLegacyTx(opts, contract, input)
}
rawTx = types.NewTx(baseTx)
}
if err != nil {
return nil, err
}
// Sign the transaction and schedule it for execution
if opts.Signer == nil {
return nil, errors.New("no signer to authorize the transaction with")
}
......@@ -431,6 +481,9 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter
// UnpackLog unpacks a retrieved log into the provided output structure.
func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error {
if log.Topics[0] != c.abi.Events[event].ID {
return fmt.Errorf("event signature mismatch")
}
if len(log.Data) > 0 {
if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil {
return err
......@@ -447,6 +500,9 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log)
// UnpackLogIntoMap unpacks a retrieved log into the provided map.
func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error {
if log.Topics[0] != c.abi.Events[event].ID {
return fmt.Errorf("event signature mismatch")
}
if len(log.Data) > 0 {
if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil {
return err
......