mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Merge remote-tracking branch 'origin/feature/update-smart-contracts' into refactore/rollupUpdateBuckets
# Conflicts: # eth/contracts/hermez/Hermez.go
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -0,0 +1 @@
|
|||||||
|
bin/
|
||||||
135
Makefile
Normal file
135
Makefile
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
#! /usr/bin/make -f
|
||||||
|
|
||||||
|
# Project variables.
|
||||||
|
PACKAGE := github.com/hermeznetwork/hermez-node
|
||||||
|
VERSION := $(shell git describe --tags --always)
|
||||||
|
BUILD := $(shell git rev-parse --short HEAD)
|
||||||
|
BUILD_DATE := $(shell date +%Y-%m-%dT%H:%M:%S%z)
|
||||||
|
PROJECT_NAME := $(shell basename "$(PWD)")
|
||||||
|
|
||||||
|
# Go related variables.
|
||||||
|
GO_FILES ?= $$(find . -name '*.go' | grep -v vendor)
|
||||||
|
GOBASE := $(shell pwd)
|
||||||
|
GOBIN := $(GOBASE)/bin
|
||||||
|
GOPKG := $(.)
|
||||||
|
GOENVVARS := GOBIN=$(GOBIN)
|
||||||
|
GOCMD := $(GOBASE)/cli/node
|
||||||
|
GOPROOF := $(GOBASE)/test/proofserver/cli
|
||||||
|
GOBINARY := node
|
||||||
|
|
||||||
|
# Project configs.
|
||||||
|
MODE ?= sync
|
||||||
|
CONFIG ?= $(GOBASE)/cli/node/cfg.buidler.toml
|
||||||
|
POSTGRES_PASS ?= yourpasswordhere
|
||||||
|
|
||||||
|
# Use linker flags to provide version/build settings.
|
||||||
|
LDFLAGS=-ldflags "-X=main.Version=$(VERSION) -X=main.Build=$(BUILD) -X=main.Date=$(BUILD_DATE)"
|
||||||
|
|
||||||
|
# PID file will keep the process id of the server.
|
||||||
|
PID_PROOF_MOCK := /tmp/.$(PROJECT_NAME).proof.pid
|
||||||
|
|
||||||
|
# Make is verbose in Linux. Make it silent.
|
||||||
|
MAKEFLAGS += --silent
|
||||||
|
|
||||||
|
.PHONY: help
|
||||||
|
help: Makefile
|
||||||
|
@echo
|
||||||
|
@echo " Choose a command run in "$(PROJECT_NAME)":"
|
||||||
|
@echo
|
||||||
|
@sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /'
|
||||||
|
@echo
|
||||||
|
|
||||||
|
## test: Run the application check and all tests.
|
||||||
|
test: govet gocilint test-unit
|
||||||
|
|
||||||
|
## test-unit: Run all unit tests.
|
||||||
|
test-unit:
|
||||||
|
@echo " > Running unit tests"
|
||||||
|
$(GOENVVARS) go test -race -p 1 -failfast -timeout 300s -v ./...
|
||||||
|
|
||||||
|
## test-api-server: Run the API server using the Go tests.
|
||||||
|
test-api-server:
|
||||||
|
@echo " > Running unit tests"
|
||||||
|
$(GOENVVARS) FAKE_SERVER=yes go test -timeout 0 ./api -p 1 -count 1 -v
|
||||||
|
|
||||||
|
## gofmt: Run `go fmt` for all go files.
|
||||||
|
gofmt:
|
||||||
|
@echo " > Format all go files"
|
||||||
|
$(GOENVVARS) gofmt -w ${GO_FILES}
|
||||||
|
|
||||||
|
## govet: Run go vet.
|
||||||
|
govet:
|
||||||
|
@echo " > Running go vet"
|
||||||
|
$(GOENVVARS) go vet ./...
|
||||||
|
|
||||||
|
## golint: Run default golint.
|
||||||
|
golint:
|
||||||
|
@echo " > Running golint"
|
||||||
|
$(GOENVVARS) golint -set_exit_status ./...
|
||||||
|
|
||||||
|
## gocilint: Run Golang CI Lint.
|
||||||
|
gocilint:
|
||||||
|
@echo " > Running Golang CI Lint"
|
||||||
|
$-golangci-lint run --timeout=5m -E whitespace -E gosec -E gci -E misspell -E gomnd -E gofmt -E goimports -E golint --exclude-use-default=false --max-same-issues 0
|
||||||
|
|
||||||
|
## exec: Run given command. e.g; make exec run="go test ./..."
|
||||||
|
exec:
|
||||||
|
GOBIN=$(GOBIN) $(run)
|
||||||
|
|
||||||
|
## clean: Clean build files. Runs `go clean` internally.
|
||||||
|
clean:
|
||||||
|
@-rm $(GOBIN)/ 2> /dev/null
|
||||||
|
@echo " > Cleaning build cache"
|
||||||
|
$(GOENVVARS) go clean
|
||||||
|
|
||||||
|
## build: Build the project.
|
||||||
|
build: install
|
||||||
|
@echo " > Building Hermez binary..."
|
||||||
|
@bash -c "$(MAKE) migration-pack"
|
||||||
|
$(GOENVVARS) go build $(LDFLAGS) -o $(GOBIN)/$(GOBINARY) $(GOCMD)
|
||||||
|
@bash -c "$(MAKE) migration-clean"
|
||||||
|
|
||||||
|
## install: Install missing dependencies. Runs `go get` internally. e.g; make install get=github.com/foo/bar
|
||||||
|
install:
|
||||||
|
@echo " > Checking if there is any missing dependencies..."
|
||||||
|
$(GOENVVARS) go get $(GOCMD)/... $(get)
|
||||||
|
|
||||||
|
## run: Run Hermez node.
|
||||||
|
run:
|
||||||
|
@bash -c "$(MAKE) clean build"
|
||||||
|
@echo " > Running $(PROJECT_NAME)"
|
||||||
|
@$(GOBIN)/$(GOBINARY) --mode $(MODE) --cfg $(CONFIG) run
|
||||||
|
|
||||||
|
## run-proof-mock: Run proof server mock API.
|
||||||
|
run-proof-mock: stop-proof-mock
|
||||||
|
@echo " > Running Proof Server Mock"
|
||||||
|
$(GOENVVARS) go build -o $(GOBIN)/proof $(GOPROOF)
|
||||||
|
@$(GOBIN)/proof 2>&1 & echo $$! > $(PID_PROOF_MOCK)
|
||||||
|
@cat $(PID_PROOF_MOCK) | sed "/^/s/^/ \> Proof Server Mock PID: /"
|
||||||
|
|
||||||
|
## stop-proof-mock: Stop proof server mock API.
|
||||||
|
stop-proof-mock:
|
||||||
|
@-touch $(PID_PROOF_MOCK)
|
||||||
|
@-kill -s INT `cat $(PID_PROOF_MOCK)` 2> /dev/null || true
|
||||||
|
@-rm $(PID_PROOF_MOCK) $(GOBIN)/proof 2> /dev/null || true
|
||||||
|
|
||||||
|
## migration-pack: Pack the database migrations into the binary.
|
||||||
|
migration-pack:
|
||||||
|
@echo " > Packing the migrations..."
|
||||||
|
@cd /tmp && go get -u github.com/gobuffalo/packr/v2/packr2 && cd -
|
||||||
|
@cd $(GOBASE)/db && packr2 && cd -
|
||||||
|
|
||||||
|
## migration-clean: Clean the database migrations pack.
|
||||||
|
migration-clean:
|
||||||
|
@echo " > Cleaning the migrations..."
|
||||||
|
@cd $(GOBASE)/db && packr2 clean && cd -
|
||||||
|
|
||||||
|
## run-database-container: Run the Postgres container
|
||||||
|
run-database-container:
|
||||||
|
@echo " > Running the postgreSQL DB..."
|
||||||
|
@-docker run --rm --name hermez-db -p 5432:5432 -e POSTGRES_DB=hermez -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD="$(POSTGRES_PASS)" -d postgres
|
||||||
|
|
||||||
|
## stop-database-container: Stop the Postgres container
|
||||||
|
stop-database-container:
|
||||||
|
@echo " > Stopping the postgreSQL DB..."
|
||||||
|
@-docker stop hermez-db
|
||||||
83
README.md
83
README.md
@@ -8,42 +8,75 @@ Go implementation of the Hermez node.
|
|||||||
|
|
||||||
The `hermez-node` has been tested with go version 1.14
|
The `hermez-node` has been tested with go version 1.14
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
Build the binary and check the current version:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ make build
|
||||||
|
$ bin/node version
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run
|
||||||
|
|
||||||
|
First you must edit the default/template config file into [cli/node/cfg.buidler.toml](cli/node/cfg.buidler.toml),
|
||||||
|
there are more information about the config file into [cli/node/README.md](cli/node/README.md)
|
||||||
|
|
||||||
|
After setting the config, you can build and run the Hermez Node as a synchronizer:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ make run
|
||||||
|
```
|
||||||
|
|
||||||
|
Or build and run as a coordinator, and also passing the config file from other location:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ MODE=sync CONFIG=cli/node/cfg.buidler.toml make run
|
||||||
|
```
|
||||||
|
|
||||||
|
To check the useful make commands:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ make help
|
||||||
|
```
|
||||||
|
|
||||||
### Unit testing
|
### Unit testing
|
||||||
|
|
||||||
Running the unit tests requires a connection to a PostgreSQL database. You can
|
Running the unit tests requires a connection to a PostgreSQL database. You can
|
||||||
start PostgreSQL with docker easily this way (where `yourpasswordhere` should
|
run PostgreSQL with docker easily this way (where `yourpasswordhere` should
|
||||||
be your password):
|
be your password):
|
||||||
|
|
||||||
```
|
```shell
|
||||||
POSTGRES_PASS=yourpasswordhere; sudo docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=hermez -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD="$POSTGRES_PASS" -d postgres
|
$ POSTGRES_PASS="yourpasswordhere" make run-database-container
|
||||||
```
|
```
|
||||||
|
|
||||||
Afterwards, run the tests with the password as env var:
|
Afterward, run the tests with the password as env var:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
POSTGRES_PASS=yourpasswordhere go test -p 1 ./...
|
$ POSTGRES_PASS="yourpasswordhere" make test
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE: `-p 1` forces execution of package test in serial. Otherwise they may be
|
NOTE: `-p 1` forces execution of package test in serial. Otherwise, they may be
|
||||||
executed in paralel and the test may find unexpected entries in the SQL databse
|
executed in parallel, and the test may find unexpected entries in the SQL database
|
||||||
because it's shared among all tests.
|
because it's shared among all tests.
|
||||||
|
|
||||||
There is an extra temporary option that allows you to run the API server using
|
There is an extra temporary option that allows you to run the API server using the
|
||||||
the Go tests. This will be removed once the API can be properly initialized,
|
Go tests. It will be removed once the API can be properly initialized with data
|
||||||
with data from the synchronizer and so on. To use this, run:
|
from the synchronizer. To use this, run:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
FAKE_SERVER=yes POSTGRES_PASS=yourpasswordhere go test -timeout 0 ./api -p 1 -count 1 -v`
|
$ POSTGRES_PASS="yourpasswordhere" make test-api-server
|
||||||
```
|
```
|
||||||
|
|
||||||
### Lint
|
### Lint
|
||||||
|
|
||||||
All Pull Requests need to pass the configured linter.
|
All Pull Requests need to pass the configured linter.
|
||||||
|
|
||||||
To run the linter locally, first install [golangci-lint](https://golangci-lint.run). Afterwards you can check the lints with this command:
|
To run the linter locally, first, install [golangci-lint](https://golangci-lint.run).
|
||||||
|
Afterward, you can check the lints with this command:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
golangci-lint run --timeout=5m -E whitespace -E gosec -E gci -E misspell -E gomnd -E gofmt -E goimports -E golint --exclude-use-default=false --max-same-issues 0
|
$ make gocilint
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -54,13 +87,13 @@ See [cli/node/README.md](cli/node/README.md)
|
|||||||
|
|
||||||
### Proof Server
|
### Proof Server
|
||||||
|
|
||||||
The node in mode coordinator requires a proof server (a server that is capable
|
The node in mode coordinator requires a proof server (a server capable of
|
||||||
of calculating proofs from the zkInputs). For testing purposes there is a mock
|
calculating proofs from the zkInputs). There is a mock proof server CLI
|
||||||
proof server cli at `test/proofserver/cli`.
|
at `test/proofserver/cli` for testing purposes.
|
||||||
|
|
||||||
Usage of `test/proofserver/cli`:
|
Usage of `test/proofserver/cli`:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
USAGE:
|
USAGE:
|
||||||
go run ./test/proofserver/cli OPTIONS
|
go run ./test/proofserver/cli OPTIONS
|
||||||
|
|
||||||
@@ -71,11 +104,19 @@ OPTIONS:
|
|||||||
proving time duration (default 2s)
|
proving time duration (default 2s)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Also, the Makefile commands can be used to run and stop the proof server
|
||||||
|
in the background:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ make run-proof-mock
|
||||||
|
$ make stop-proof-mock
|
||||||
|
```
|
||||||
|
|
||||||
### `/tmp` as tmpfs
|
### `/tmp` as tmpfs
|
||||||
|
|
||||||
For every processed batch, the node builds a temporary exit tree in a key-value
|
For every processed batch, the node builds a temporary exit tree in a key-value
|
||||||
DB stored in `/tmp`. It is highly recommended that `/tmp` is mounted as a RAM
|
DB stored in `/tmp`. It is highly recommended that `/tmp` is mounted as a RAM
|
||||||
file system in production to avoid unecessary reads an writes to disk. This
|
file system in production to avoid unnecessary reads a writes to disk. This
|
||||||
can be done by mounting `/tmp` as tmpfs; for example, by having this line in
|
can be done by mounting `/tmp` as tmpfs; for example, by having this line in
|
||||||
`/etc/fstab`:
|
`/etc/fstab`:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ import (
|
|||||||
|
|
||||||
// BigIntStr is used to scan/value *big.Int directly into strings from/to sql DBs.
|
// BigIntStr is used to scan/value *big.Int directly into strings from/to sql DBs.
|
||||||
// It assumes that *big.Int are inserted/fetched to/from the DB using the BigIntMeddler meddler
|
// It assumes that *big.Int are inserted/fetched to/from the DB using the BigIntMeddler meddler
|
||||||
// defined at github.com/hermeznetwork/hermez-node/db
|
// defined at github.com/hermeznetwork/hermez-node/db. Since *big.Int is
|
||||||
|
// stored as DECIMAL in SQL, there's no need to implement Scan()/Value()
|
||||||
|
// because DECIMALS are encoded/decoded as strings by the sql driver, and
|
||||||
|
// BigIntStr is already a string.
|
||||||
type BigIntStr string
|
type BigIntStr string
|
||||||
|
|
||||||
// NewBigIntStr creates a *BigIntStr from a *big.Int.
|
// NewBigIntStr creates a *BigIntStr from a *big.Int.
|
||||||
@@ -31,34 +34,6 @@ func NewBigIntStr(bigInt *big.Int) *BigIntStr {
|
|||||||
return &bigIntStr
|
return &bigIntStr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan implements Scanner for database/sql
|
|
||||||
func (b *BigIntStr) Scan(src interface{}) error {
|
|
||||||
srcBytes, ok := src.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return tracerr.Wrap(fmt.Errorf("can't scan %T into apitypes.BigIntStr", src))
|
|
||||||
}
|
|
||||||
// bytes to *big.Int
|
|
||||||
bigInt := new(big.Int).SetBytes(srcBytes)
|
|
||||||
// *big.Int to BigIntStr
|
|
||||||
bigIntStr := NewBigIntStr(bigInt)
|
|
||||||
if bigIntStr == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
*b = *bigIntStr
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value implements valuer for database/sql
|
|
||||||
func (b BigIntStr) Value() (driver.Value, error) {
|
|
||||||
// string to *big.Int
|
|
||||||
bigInt, ok := new(big.Int).SetString(string(b), 10)
|
|
||||||
if !ok || bigInt == nil {
|
|
||||||
return nil, tracerr.Wrap(errors.New("invalid representation of a *big.Int"))
|
|
||||||
}
|
|
||||||
// *big.Int to bytes
|
|
||||||
return bigInt.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StrBigInt is used to unmarshal BigIntStr directly into an alias of big.Int
|
// StrBigInt is used to unmarshal BigIntStr directly into an alias of big.Int
|
||||||
type StrBigInt big.Int
|
type StrBigInt big.Int
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ The `hermez-node` has been tested with go version 1.14
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```shell
|
||||||
NAME:
|
NAME:
|
||||||
hermez-node - A new cli application
|
hermez-node - A new cli application
|
||||||
|
|
||||||
@@ -16,18 +16,18 @@ USAGE:
|
|||||||
node [global options] command [command options] [arguments...]
|
node [global options] command [command options] [arguments...]
|
||||||
|
|
||||||
VERSION:
|
VERSION:
|
||||||
0.1.0-alpha
|
v0.1.0-6-gd8a50c5
|
||||||
|
|
||||||
COMMANDS:
|
COMMANDS:
|
||||||
|
version Show the application version
|
||||||
importkey Import ethereum private key
|
importkey Import ethereum private key
|
||||||
genbjj Generate a new BabyJubJub key
|
genbjj Generate a new BabyJubJub key
|
||||||
wipesql Wipe the SQL DB (HistoryDB and L2DB), leaving the DB in a clean state
|
wipesql Wipe the SQL DB (HistoryDB and L2DB) and the StateDBs, leaving the DB in a clean state
|
||||||
run Run the hermez-node in the indicated mode
|
run Run the hermez-node in the indicated mode
|
||||||
|
discard Discard blocks up to a specified block number
|
||||||
help, h Shows a list of commands or help for one command
|
help, h Shows a list of commands or help for one command
|
||||||
|
|
||||||
GLOBAL OPTIONS:
|
GLOBAL OPTIONS:
|
||||||
--mode MODE Set node MODE (can be "sync" or "coord")
|
|
||||||
--cfg FILE Node configuration FILE
|
|
||||||
--help, -h show help (default: false)
|
--help, -h show help (default: false)
|
||||||
--version, -v print the version (default: false)
|
--version, -v print the version (default: false)
|
||||||
```
|
```
|
||||||
@@ -75,7 +75,7 @@ when running the coordinator in sync mode
|
|||||||
|
|
||||||
Building the node requires using the packr utility to bundle the database
|
Building the node requires using the packr utility to bundle the database
|
||||||
migrations inside the resulting binary. Install the packr utility with:
|
migrations inside the resulting binary. Install the packr utility with:
|
||||||
```
|
```shell
|
||||||
cd /tmp && go get -u github.com/gobuffalo/packr/v2/packr2 && cd -
|
cd /tmp && go get -u github.com/gobuffalo/packr/v2/packr2 && cd -
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ Make sure your `$PATH` contains `$GOPATH/bin`, otherwise the packr utility will
|
|||||||
not be found.
|
not be found.
|
||||||
|
|
||||||
Now build the node executable:
|
Now build the node executable:
|
||||||
```
|
```shell
|
||||||
cd ../../db && packr2 && cd -
|
cd ../../db && packr2 && cd -
|
||||||
go build .
|
go build .
|
||||||
cd ../../db && packr2 clean && cd -
|
cd ../../db && packr2 clean && cd -
|
||||||
@@ -98,35 +98,40 @@ run the following examples by replacing `./node` with `go run .` and executing
|
|||||||
them in the `cli/node` directory to build from source and run at the same time.
|
them in the `cli/node` directory to build from source and run at the same time.
|
||||||
|
|
||||||
Run the node in mode synchronizer:
|
Run the node in mode synchronizer:
|
||||||
```
|
```shell
|
||||||
./node --mode sync --cfg cfg.buidler.toml run
|
./node run --mode sync --cfg cfg.buidler.toml
|
||||||
```
|
```
|
||||||
|
|
||||||
Run the node in mode coordinator:
|
Run the node in mode coordinator:
|
||||||
```
|
```shell
|
||||||
./node --mode coord --cfg cfg.buidler.toml run
|
./node run --mode coord --cfg cfg.buidler.toml
|
||||||
```
|
```
|
||||||
|
|
||||||
Import an ethereum private key into the keystore:
|
Import an ethereum private key into the keystore:
|
||||||
```
|
```shell
|
||||||
./node --mode coord --cfg cfg.buidler.toml importkey --privatekey 0x618b35096c477aab18b11a752be619f0023a539bb02dd6c813477a6211916cde
|
./node importkey --mode coord --cfg cfg.buidler.toml --privatekey 0x618b35096c477aab18b11a752be619f0023a539bb02dd6c813477a6211916cde
|
||||||
```
|
```
|
||||||
|
|
||||||
Generate a new BabyJubJub key pair:
|
Generate a new BabyJubJub key pair:
|
||||||
|
```shell
|
||||||
|
./node genbjj
|
||||||
```
|
```
|
||||||
./node --mode coord --cfg cfg.buidler.toml genbjj
|
|
||||||
|
Check the binary version:
|
||||||
|
```shell
|
||||||
|
./node version
|
||||||
```
|
```
|
||||||
|
|
||||||
Wipe the entier SQL database (this will destroy all synchronized and pool
|
Wipe the entier SQL database (this will destroy all synchronized and pool
|
||||||
data):
|
data):
|
||||||
```
|
```shell
|
||||||
./node --mode coord --cfg cfg.buidler.toml wipesql
|
./node wipesql --mode coord --cfg cfg.buidler.toml
|
||||||
```
|
```
|
||||||
|
|
||||||
Discard all synchronized blocks and associated state up to a given block
|
Discard all synchronized blocks and associated state up to a given block
|
||||||
number. This command is useful in case the synchronizer reaches an invalid
|
number. This command is useful in case the synchronizer reaches an invalid
|
||||||
state and you want to roll back a few blocks and try again (maybe with some
|
state and you want to roll back a few blocks and try again (maybe with some
|
||||||
fixes in the code).
|
fixes in the code).
|
||||||
```
|
```shell
|
||||||
./node --mode coord --cfg cfg.buidler.toml discard --block 8061330
|
./node discard --mode coord --cfg cfg.buidler.toml --block 8061330
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -34,6 +34,22 @@ const (
|
|||||||
modeCoord = "coord"
|
modeCoord = "coord"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Version represents the program based on the git tag
|
||||||
|
Version = "v0.1.0"
|
||||||
|
// Build represents the program based on the git commit
|
||||||
|
Build = "dev"
|
||||||
|
// Date represents the date of application was built
|
||||||
|
Date = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdVersion(c *cli.Context) error {
|
||||||
|
fmt.Printf("Version = \"%v\"\n", Version)
|
||||||
|
fmt.Printf("Build = \"%v\"\n", Build)
|
||||||
|
fmt.Printf("Date = \"%v\"\n", Date)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func cmdGenBJJ(c *cli.Context) error {
|
func cmdGenBJJ(c *cli.Context) error {
|
||||||
sk := babyjub.NewRandPrivKey()
|
sk := babyjub.NewRandPrivKey()
|
||||||
skBuf := [32]byte(sk)
|
skBuf := [32]byte(sk)
|
||||||
@@ -404,8 +420,8 @@ func getConfigAPIServer(c *cli.Context) (*ConfigAPIServer, error) {
|
|||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "hermez-node"
|
app.Name = "hermez-node"
|
||||||
app.Version = "0.1.0-alpha"
|
app.Version = Version
|
||||||
app.Flags = []cli.Flag{
|
flags := []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: flagMode,
|
Name: flagMode,
|
||||||
Usage: fmt.Sprintf("Set node `MODE` (can be \"%v\" or \"%v\")", modeSync, modeCoord),
|
Usage: fmt.Sprintf("Set node `MODE` (can be \"%v\" or \"%v\")", modeSync, modeCoord),
|
||||||
@@ -419,17 +435,23 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.Commands = []*cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "version",
|
||||||
|
Aliases: []string{},
|
||||||
|
Usage: "Show the application version and build",
|
||||||
|
Action: cmdVersion,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "importkey",
|
Name: "importkey",
|
||||||
Aliases: []string{},
|
Aliases: []string{},
|
||||||
Usage: "Import ethereum private key",
|
Usage: "Import ethereum private key",
|
||||||
Action: cmdImportKey,
|
Action: cmdImportKey,
|
||||||
Flags: []cli.Flag{
|
Flags: append(flags,
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: flagSK,
|
Name: flagSK,
|
||||||
Usage: "ethereum `PRIVATE_KEY` in hex",
|
Usage: "ethereum `PRIVATE_KEY` in hex",
|
||||||
Required: true,
|
Required: true,
|
||||||
}},
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "genbjj",
|
Name: "genbjj",
|
||||||
@@ -443,18 +465,19 @@ func main() {
|
|||||||
Usage: "Wipe the SQL DB (HistoryDB and L2DB) and the StateDBs, " +
|
Usage: "Wipe the SQL DB (HistoryDB and L2DB) and the StateDBs, " +
|
||||||
"leaving the DB in a clean state",
|
"leaving the DB in a clean state",
|
||||||
Action: cmdWipeSQL,
|
Action: cmdWipeSQL,
|
||||||
Flags: []cli.Flag{
|
Flags: append(flags,
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: flagYes,
|
Name: flagYes,
|
||||||
Usage: "automatic yes to the prompt",
|
Usage: "automatic yes to the prompt",
|
||||||
Required: false,
|
Required: false,
|
||||||
}},
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "run",
|
Name: "run",
|
||||||
Aliases: []string{},
|
Aliases: []string{},
|
||||||
Usage: "Run the hermez-node in the indicated mode",
|
Usage: "Run the hermez-node in the indicated mode",
|
||||||
Action: cmdRun,
|
Action: cmdRun,
|
||||||
|
Flags: flags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "serveapi",
|
Name: "serveapi",
|
||||||
@@ -467,12 +490,12 @@ func main() {
|
|||||||
Aliases: []string{},
|
Aliases: []string{},
|
||||||
Usage: "Discard blocks up to a specified block number",
|
Usage: "Discard blocks up to a specified block number",
|
||||||
Action: cmdDiscard,
|
Action: cmdDiscard,
|
||||||
Flags: []cli.Flag{
|
Flags: append(flags,
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
Name: flagBlock,
|
Name: flagBlock,
|
||||||
Usage: "last block number to keep",
|
Usage: "last block number to keep",
|
||||||
Required: false,
|
Required: false,
|
||||||
}},
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,11 +112,17 @@ type Coordinator struct {
|
|||||||
// MustForgeAtSlotDeadline enables the coordinator to forge slots if
|
// MustForgeAtSlotDeadline enables the coordinator to forge slots if
|
||||||
// the empty slots reach the slot deadline.
|
// the empty slots reach the slot deadline.
|
||||||
MustForgeAtSlotDeadline bool
|
MustForgeAtSlotDeadline bool
|
||||||
// IgnoreSlotCommitment IgnoreSlotCommitment disables forcing the
|
// IgnoreSlotCommitment disables forcing the coordinator to forge a
|
||||||
// coordinator to forge a slot immediately when the slot is not
|
// slot immediately when the slot is not committed. If set to false,
|
||||||
// committed. If set to false, the coordinator will immediately forge
|
// the coordinator will immediately forge a batch at the beginning of a
|
||||||
// a batch at the beginning of a slot if it's the slot winner.
|
// slot if it's the slot winner.
|
||||||
IgnoreSlotCommitment bool
|
IgnoreSlotCommitment bool
|
||||||
|
// ForgeOncePerSlotIfTxs will make the coordinator forge at most one
|
||||||
|
// batch per slot, only if there are included txs in that batch, or
|
||||||
|
// pending l1UserTxs in the smart contract. Setting this parameter
|
||||||
|
// overrides `ForgeDelay`, `ForgeNoTxsDelay`, `MustForgeAtSlotDeadline`
|
||||||
|
// and `IgnoreSlotCommitment`.
|
||||||
|
ForgeOncePerSlotIfTxs bool
|
||||||
// SyncRetryInterval is the waiting interval between calls to the main
|
// SyncRetryInterval is the waiting interval between calls to the main
|
||||||
// handler of a synced block after an error
|
// handler of a synced block after an error
|
||||||
SyncRetryInterval Duration `validate:"required"`
|
SyncRetryInterval Duration `validate:"required"`
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ type BatchInfo struct {
|
|||||||
PublicInputs []*big.Int
|
PublicInputs []*big.Int
|
||||||
L1Batch bool
|
L1Batch bool
|
||||||
VerifierIdx uint8
|
VerifierIdx uint8
|
||||||
L1UserTxsExtra []common.L1Tx
|
L1UserTxs []common.L1Tx
|
||||||
L1CoordTxs []common.L1Tx
|
L1CoordTxs []common.L1Tx
|
||||||
L1CoordinatorTxsAuths [][]byte
|
L1CoordinatorTxsAuths [][]byte
|
||||||
L2Txs []common.L2Tx
|
L2Txs []common.L2Tx
|
||||||
|
|||||||
@@ -24,10 +24,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errLastL1BatchNotSynced = fmt.Errorf("last L1Batch not synced yet")
|
errLastL1BatchNotSynced = fmt.Errorf("last L1Batch not synced yet")
|
||||||
errForgeNoTxsBeforeDelay = fmt.Errorf(
|
errSkipBatchByPolicy = fmt.Errorf("skip batch by policy")
|
||||||
"no txs to forge and we haven't reached the forge no txs delay")
|
|
||||||
errForgeBeforeDelay = fmt.Errorf("we haven't reached the forge delay")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -92,6 +90,12 @@ type Config struct {
|
|||||||
// the coordinator will immediately forge a batch at the beginning of
|
// the coordinator will immediately forge a batch at the beginning of
|
||||||
// a slot if it's the slot winner.
|
// a slot if it's the slot winner.
|
||||||
IgnoreSlotCommitment bool
|
IgnoreSlotCommitment bool
|
||||||
|
// ForgeOncePerSlotIfTxs will make the coordinator forge at most one
|
||||||
|
// batch per slot, only if there are included txs in that batch, or
|
||||||
|
// pending l1UserTxs in the smart contract. Setting this parameter
|
||||||
|
// overrides `ForgeDelay`, `ForgeNoTxsDelay`, `MustForgeAtSlotDeadline`
|
||||||
|
// and `IgnoreSlotCommitment`.
|
||||||
|
ForgeOncePerSlotIfTxs bool
|
||||||
// SyncRetryInterval is the waiting interval between calls to the main
|
// SyncRetryInterval is the waiting interval between calls to the main
|
||||||
// handler of a synced block after an error
|
// handler of a synced block after an error
|
||||||
SyncRetryInterval time.Duration
|
SyncRetryInterval time.Duration
|
||||||
|
|||||||
@@ -224,8 +224,9 @@ func (p *Pipeline) handleForgeBatch(ctx context.Context,
|
|||||||
|
|
||||||
// 2. Forge the batch internally (make a selection of txs and prepare
|
// 2. Forge the batch internally (make a selection of txs and prepare
|
||||||
// all the smart contract arguments)
|
// all the smart contract arguments)
|
||||||
|
var skipReason *string
|
||||||
p.mutexL2DBUpdateDelete.Lock()
|
p.mutexL2DBUpdateDelete.Lock()
|
||||||
batchInfo, err = p.forgeBatch(batchNum)
|
batchInfo, skipReason, err = p.forgeBatch(batchNum)
|
||||||
p.mutexL2DBUpdateDelete.Unlock()
|
p.mutexL2DBUpdateDelete.Unlock()
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
@@ -234,13 +235,13 @@ func (p *Pipeline) handleForgeBatch(ctx context.Context,
|
|||||||
log.Warnw("forgeBatch: scheduled L1Batch too early", "err", err,
|
log.Warnw("forgeBatch: scheduled L1Batch too early", "err", err,
|
||||||
"lastForgeL1TxsNum", p.state.lastForgeL1TxsNum,
|
"lastForgeL1TxsNum", p.state.lastForgeL1TxsNum,
|
||||||
"syncLastForgeL1TxsNum", p.stats.Sync.LastForgeL1TxsNum)
|
"syncLastForgeL1TxsNum", p.stats.Sync.LastForgeL1TxsNum)
|
||||||
} else if tracerr.Unwrap(err) == errForgeNoTxsBeforeDelay ||
|
|
||||||
tracerr.Unwrap(err) == errForgeBeforeDelay {
|
|
||||||
// no log
|
|
||||||
} else {
|
} else {
|
||||||
log.Errorw("forgeBatch", "err", err)
|
log.Errorw("forgeBatch", "err", err)
|
||||||
}
|
}
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, tracerr.Wrap(err)
|
||||||
|
} else if skipReason != nil {
|
||||||
|
log.Debugw("skipping batch", "batch", batchNum, "reason", *skipReason)
|
||||||
|
return nil, tracerr.Wrap(errSkipBatchByPolicy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Send the ZKInputs to the proof server
|
// 3. Send the ZKInputs to the proof server
|
||||||
@@ -295,8 +296,7 @@ func (p *Pipeline) Start(batchNum common.BatchNum,
|
|||||||
if p.ctx.Err() != nil {
|
if p.ctx.Err() != nil {
|
||||||
continue
|
continue
|
||||||
} else if tracerr.Unwrap(err) == errLastL1BatchNotSynced ||
|
} else if tracerr.Unwrap(err) == errLastL1BatchNotSynced ||
|
||||||
tracerr.Unwrap(err) == errForgeNoTxsBeforeDelay ||
|
tracerr.Unwrap(err) == errSkipBatchByPolicy {
|
||||||
tracerr.Unwrap(err) == errForgeBeforeDelay {
|
|
||||||
continue
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
p.setErrAtBatchNum(batchNum)
|
p.setErrAtBatchNum(batchNum)
|
||||||
@@ -389,25 +389,109 @@ func (p *Pipeline) sendServerProof(ctx context.Context, batchInfo *BatchInfo) er
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we reach the ForgeDelay or not before batch forging
|
// slotCommitted returns true if the current slot has already been committed
|
||||||
func (p *Pipeline) preForgeBatchCheck(slotCommitted bool, now time.Time) error {
|
func (p *Pipeline) slotCommitted() bool {
|
||||||
if slotCommitted && now.Sub(p.lastForgeTime) < p.cfg.ForgeDelay {
|
// Synchronizer has synchronized a batch in the current slot (setting
|
||||||
return errForgeBeforeDelay
|
// CurrentSlot.ForgerCommitment) or the pipeline has already
|
||||||
|
// internally-forged a batch in the current slot
|
||||||
|
return p.stats.Sync.Auction.CurrentSlot.ForgerCommitment ||
|
||||||
|
p.stats.Sync.Auction.CurrentSlot.SlotNum == p.state.lastSlotForged
|
||||||
|
}
|
||||||
|
|
||||||
|
// forgePolicySkipPreSelection is called before doing a tx selection in a batch to
|
||||||
|
// determine by policy if we should forge the batch or not. Returns true and
|
||||||
|
// the reason when the forging of the batch must be skipped.
|
||||||
|
func (p *Pipeline) forgePolicySkipPreSelection(now time.Time) (bool, string) {
|
||||||
|
// Check if the slot is not yet fulfilled
|
||||||
|
slotCommitted := p.slotCommitted()
|
||||||
|
if p.cfg.ForgeOncePerSlotIfTxs {
|
||||||
|
if slotCommitted {
|
||||||
|
return true, "cfg.ForgeOncePerSlotIfTxs = true and slot already committed"
|
||||||
|
}
|
||||||
|
return false, ""
|
||||||
}
|
}
|
||||||
return nil
|
// Determine if we must commit the slot
|
||||||
|
if !p.cfg.IgnoreSlotCommitment && !slotCommitted {
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we haven't reached the ForgeDelay, skip forging the batch
|
||||||
|
if now.Sub(p.lastForgeTime) < p.cfg.ForgeDelay {
|
||||||
|
return true, "we haven't reached the forge delay"
|
||||||
|
}
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// forgePolicySkipPostSelection is called after doing a tx selection in a batch to
|
||||||
|
// determine by policy if we should forge the batch or not. Returns true and
|
||||||
|
// the reason when the forging of the batch must be skipped.
|
||||||
|
func (p *Pipeline) forgePolicySkipPostSelection(now time.Time, l1UserTxsExtra, l1CoordTxs []common.L1Tx,
|
||||||
|
poolL2Txs []common.PoolL2Tx, batchInfo *BatchInfo) (bool, string, error) {
|
||||||
|
// Check if the slot is not yet fulfilled
|
||||||
|
slotCommitted := p.slotCommitted()
|
||||||
|
|
||||||
|
pendingTxs := true
|
||||||
|
if len(l1UserTxsExtra) == 0 && len(l1CoordTxs) == 0 && len(poolL2Txs) == 0 {
|
||||||
|
if batchInfo.L1Batch {
|
||||||
|
// Query the number of unforged L1UserTxs
|
||||||
|
// (either in a open queue or in a frozen
|
||||||
|
// not-yet-forged queue).
|
||||||
|
count, err := p.historyDB.GetUnforgedL1UserTxsCount()
|
||||||
|
if err != nil {
|
||||||
|
return false, "", err
|
||||||
|
}
|
||||||
|
// If there are future L1UserTxs, we forge a
|
||||||
|
// batch to advance the queues to be able to
|
||||||
|
// forge the L1UserTxs in the future.
|
||||||
|
// Otherwise, skip.
|
||||||
|
if count == 0 {
|
||||||
|
pendingTxs = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pendingTxs = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.cfg.ForgeOncePerSlotIfTxs {
|
||||||
|
if slotCommitted {
|
||||||
|
return true, "cfg.ForgeOncePerSlotIfTxs = true and slot already committed",
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
if pendingTxs {
|
||||||
|
return false, "", nil
|
||||||
|
}
|
||||||
|
return true, "cfg.ForgeOncePerSlotIfTxs = true and no pending txs",
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if we must commit the slot
|
||||||
|
if !p.cfg.IgnoreSlotCommitment && !slotCommitted {
|
||||||
|
return false, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if there is no txs to forge, no l1UserTxs in the open queue to
|
||||||
|
// freeze and we haven't reached the ForgeNoTxsDelay
|
||||||
|
if now.Sub(p.lastForgeTime) < p.cfg.ForgeNoTxsDelay {
|
||||||
|
if !pendingTxs {
|
||||||
|
return true, "no txs to forge and we haven't reached the forge no txs delay",
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// forgeBatch forges the batchNum batch.
|
// forgeBatch forges the batchNum batch.
|
||||||
func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, err error) {
|
func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo,
|
||||||
|
skipReason *string, err error) {
|
||||||
// remove transactions from the pool that have been there for too long
|
// remove transactions from the pool that have been there for too long
|
||||||
_, err = p.purger.InvalidateMaybe(p.l2DB, p.txSelector.LocalAccountsDB(),
|
_, err = p.purger.InvalidateMaybe(p.l2DB, p.txSelector.LocalAccountsDB(),
|
||||||
p.stats.Sync.LastBlock.Num, int64(batchNum))
|
p.stats.Sync.LastBlock.Num, int64(batchNum))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
_, err = p.purger.PurgeMaybe(p.l2DB, p.stats.Sync.LastBlock.Num, int64(batchNum))
|
_, err = p.purger.PurgeMaybe(p.l2DB, p.stats.Sync.LastBlock.Num, int64(batchNum))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
// Structure to accumulate data and metadata of the batch
|
// Structure to accumulate data and metadata of the batch
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -417,53 +501,48 @@ func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, e
|
|||||||
|
|
||||||
var poolL2Txs []common.PoolL2Tx
|
var poolL2Txs []common.PoolL2Tx
|
||||||
var discardedL2Txs []common.PoolL2Tx
|
var discardedL2Txs []common.PoolL2Tx
|
||||||
var l1UserTxsExtra, l1CoordTxs []common.L1Tx
|
var l1UserTxs, l1CoordTxs []common.L1Tx
|
||||||
var auths [][]byte
|
var auths [][]byte
|
||||||
var coordIdxs []common.Idx
|
var coordIdxs []common.Idx
|
||||||
|
|
||||||
// Check if the slot is not yet fulfilled
|
if skip, reason := p.forgePolicySkipPreSelection(now); skip {
|
||||||
slotCommitted := p.cfg.IgnoreSlotCommitment
|
return nil, &reason, nil
|
||||||
if p.stats.Sync.Auction.CurrentSlot.ForgerCommitment ||
|
|
||||||
p.stats.Sync.Auction.CurrentSlot.SlotNum == p.state.lastSlotForged {
|
|
||||||
slotCommitted = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we haven't reached the ForgeDelay, skip forging the batch
|
|
||||||
if err = p.preForgeBatchCheck(slotCommitted, now); err != nil {
|
|
||||||
return nil, tracerr.Wrap(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Decide if we forge L2Tx or L1+L2Tx
|
// 1. Decide if we forge L2Tx or L1+L2Tx
|
||||||
if p.shouldL1L2Batch(batchInfo) {
|
if p.shouldL1L2Batch(batchInfo) {
|
||||||
batchInfo.L1Batch = true
|
batchInfo.L1Batch = true
|
||||||
if p.state.lastForgeL1TxsNum != p.stats.Sync.LastForgeL1TxsNum {
|
if p.state.lastForgeL1TxsNum != p.stats.Sync.LastForgeL1TxsNum {
|
||||||
return nil, tracerr.Wrap(errLastL1BatchNotSynced)
|
return nil, nil, tracerr.Wrap(errLastL1BatchNotSynced)
|
||||||
}
|
}
|
||||||
// 2a: L1+L2 txs
|
// 2a: L1+L2 txs
|
||||||
l1UserTxs, err := p.historyDB.GetUnforgedL1UserTxs(p.state.lastForgeL1TxsNum + 1)
|
_l1UserTxs, err := p.historyDB.GetUnforgedL1UserTxs(p.state.lastForgeL1TxsNum + 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
coordIdxs, auths, l1UserTxsExtra, l1CoordTxs, poolL2Txs, discardedL2Txs, err =
|
coordIdxs, auths, l1UserTxs, l1CoordTxs, poolL2Txs, discardedL2Txs, err =
|
||||||
p.txSelector.GetL1L2TxSelection(p.cfg.TxProcessorConfig, l1UserTxs)
|
p.txSelector.GetL1L2TxSelection(p.cfg.TxProcessorConfig, _l1UserTxs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 2b: only L2 txs
|
// 2b: only L2 txs
|
||||||
coordIdxs, auths, l1CoordTxs, poolL2Txs, discardedL2Txs, err =
|
coordIdxs, auths, l1CoordTxs, poolL2Txs, discardedL2Txs, err =
|
||||||
p.txSelector.GetL2TxSelection(p.cfg.TxProcessorConfig)
|
p.txSelector.GetL2TxSelection(p.cfg.TxProcessorConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
l1UserTxsExtra = nil
|
l1UserTxs = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no txs to forge, no l1UserTxs in the open queue to
|
if skip, reason, err := p.forgePolicySkipPostSelection(now,
|
||||||
// freeze, and we haven't reached the ForgeNoTxsDelay, skip forging the
|
l1UserTxs, l1CoordTxs, poolL2Txs, batchInfo); err != nil {
|
||||||
// batch.
|
return nil, nil, tracerr.Wrap(err)
|
||||||
if err = p.postForgeBatchCheck(slotCommitted, now, l1UserTxsExtra, l1CoordTxs, poolL2Txs, batchInfo); err != nil {
|
} else if skip {
|
||||||
return nil, tracerr.Wrap(err)
|
if err := p.txSelector.Reset(batchInfo.BatchNum-1, false); err != nil {
|
||||||
|
return nil, nil, tracerr.Wrap(err)
|
||||||
|
}
|
||||||
|
return nil, &reason, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if batchInfo.L1Batch {
|
if batchInfo.L1Batch {
|
||||||
@@ -472,7 +551,7 @@ func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. Save metadata from TxSelector output for BatchNum
|
// 3. Save metadata from TxSelector output for BatchNum
|
||||||
batchInfo.L1UserTxsExtra = l1UserTxsExtra
|
batchInfo.L1UserTxs = l1UserTxs
|
||||||
batchInfo.L1CoordTxs = l1CoordTxs
|
batchInfo.L1CoordTxs = l1CoordTxs
|
||||||
batchInfo.L1CoordinatorTxsAuths = auths
|
batchInfo.L1CoordinatorTxsAuths = auths
|
||||||
batchInfo.CoordIdxs = coordIdxs
|
batchInfo.CoordIdxs = coordIdxs
|
||||||
@@ -480,10 +559,10 @@ func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, e
|
|||||||
|
|
||||||
if err := p.l2DB.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs),
|
if err := p.l2DB.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs),
|
||||||
batchInfo.BatchNum); err != nil {
|
batchInfo.BatchNum); err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
if err := p.l2DB.UpdateTxsInfo(discardedL2Txs); err != nil {
|
if err := p.l2DB.UpdateTxsInfo(discardedL2Txs); err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalidate transactions that become invalid because of
|
// Invalidate transactions that become invalid because of
|
||||||
@@ -492,21 +571,21 @@ func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, e
|
|||||||
// all the nonces smaller than the current one)
|
// all the nonces smaller than the current one)
|
||||||
err = p.l2DB.InvalidateOldNonces(idxsNonceFromPoolL2Txs(poolL2Txs), batchInfo.BatchNum)
|
err = p.l2DB.InvalidateOldNonces(idxsNonceFromPoolL2Txs(poolL2Txs), batchInfo.BatchNum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Call BatchBuilder with TxSelector output
|
// 4. Call BatchBuilder with TxSelector output
|
||||||
configBatch := &batchbuilder.ConfigBatch{
|
configBatch := &batchbuilder.ConfigBatch{
|
||||||
TxProcessorConfig: p.cfg.TxProcessorConfig,
|
TxProcessorConfig: p.cfg.TxProcessorConfig,
|
||||||
}
|
}
|
||||||
zkInputs, err := p.batchBuilder.BuildBatch(coordIdxs, configBatch, l1UserTxsExtra,
|
zkInputs, err := p.batchBuilder.BuildBatch(coordIdxs, configBatch, l1UserTxs,
|
||||||
l1CoordTxs, poolL2Txs)
|
l1CoordTxs, poolL2Txs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
l2Txs, err := common.PoolL2TxsToL2Txs(poolL2Txs) // NOTE: This is a big uggly, find a better way
|
l2Txs, err := common.PoolL2TxsToL2Txs(poolL2Txs) // NOTE: This is a big uggly, find a better way
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, tracerr.Wrap(err)
|
return nil, nil, tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
batchInfo.L2Txs = l2Txs
|
batchInfo.L2Txs = l2Txs
|
||||||
|
|
||||||
@@ -518,42 +597,7 @@ func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, e
|
|||||||
|
|
||||||
p.state.lastSlotForged = p.stats.Sync.Auction.CurrentSlot.SlotNum
|
p.state.lastSlotForged = p.stats.Sync.Auction.CurrentSlot.SlotNum
|
||||||
|
|
||||||
return batchInfo, nil
|
return batchInfo, nil, nil
|
||||||
}
|
|
||||||
|
|
||||||
// check if there is no txs to forge, no l1UserTxs in the open queue to freeze and we haven't reached the ForgeNoTxsDelay
|
|
||||||
func (p *Pipeline) postForgeBatchCheck(slotCommitted bool, now time.Time, l1UserTxsExtra, l1CoordTxs []common.L1Tx,
|
|
||||||
poolL2Txs []common.PoolL2Tx, batchInfo *BatchInfo) error {
|
|
||||||
if slotCommitted && now.Sub(p.lastForgeTime) < p.cfg.ForgeNoTxsDelay {
|
|
||||||
noTxs := false
|
|
||||||
if len(l1UserTxsExtra) == 0 && len(l1CoordTxs) == 0 && len(poolL2Txs) == 0 {
|
|
||||||
if batchInfo.L1Batch {
|
|
||||||
// Query the number of unforged L1UserTxs
|
|
||||||
// (either in a open queue or in a frozen
|
|
||||||
// not-yet-forged queue).
|
|
||||||
count, err := p.historyDB.GetUnforgedL1UserTxsCount()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// If there are future L1UserTxs, we forge a
|
|
||||||
// batch to advance the queues to be able to
|
|
||||||
// forge the L1UserTxs in the future.
|
|
||||||
// Otherwise, skip.
|
|
||||||
if count == 0 {
|
|
||||||
noTxs = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
noTxs = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if noTxs {
|
|
||||||
if err := p.txSelector.Reset(batchInfo.BatchNum-1, false); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return errForgeNoTxsBeforeDelay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// waitServerProof gets the generated zkProof & sends it to the SmartContract
|
// waitServerProof gets the generated zkProof & sends it to the SmartContract
|
||||||
@@ -598,7 +642,7 @@ func prepareForgeBatchArgs(batchInfo *BatchInfo) *eth.RollupForgeBatchArgs {
|
|||||||
NewLastIdx: int64(zki.Metadata.NewLastIdxRaw),
|
NewLastIdx: int64(zki.Metadata.NewLastIdxRaw),
|
||||||
NewStRoot: zki.Metadata.NewStateRootRaw.BigInt(),
|
NewStRoot: zki.Metadata.NewStateRootRaw.BigInt(),
|
||||||
NewExitRoot: zki.Metadata.NewExitRootRaw.BigInt(),
|
NewExitRoot: zki.Metadata.NewExitRootRaw.BigInt(),
|
||||||
L1UserTxs: batchInfo.L1UserTxsExtra,
|
L1UserTxs: batchInfo.L1UserTxs,
|
||||||
L1CoordinatorTxs: batchInfo.L1CoordTxs,
|
L1CoordinatorTxs: batchInfo.L1CoordTxs,
|
||||||
L1CoordinatorTxsAuths: batchInfo.L1CoordinatorTxsAuths,
|
L1CoordinatorTxsAuths: batchInfo.L1CoordinatorTxsAuths,
|
||||||
L2TxsData: batchInfo.L2Txs,
|
L2TxsData: batchInfo.L2Txs,
|
||||||
|
|||||||
@@ -224,12 +224,12 @@ PoolTransfer(0) User2-User3: 300 (126)
|
|||||||
|
|
||||||
batchNum++
|
batchNum++
|
||||||
|
|
||||||
batchInfo, err := pipeline.forgeBatch(batchNum)
|
batchInfo, _, err := pipeline.forgeBatch(batchNum)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, 3, len(batchInfo.L2Txs))
|
assert.Equal(t, 3, len(batchInfo.L2Txs))
|
||||||
|
|
||||||
batchNum++
|
batchNum++
|
||||||
batchInfo, err = pipeline.forgeBatch(batchNum)
|
batchInfo, _, err = pipeline.forgeBatch(batchNum)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, 0, len(batchInfo.L2Txs))
|
assert.Equal(t, 0, len(batchInfo.L2Txs))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ func (t *TxManager) NewAuth(ctx context.Context, batchInfo *BatchInfo) (*bind.Tr
|
|||||||
auth.Value = big.NewInt(0) // in wei
|
auth.Value = big.NewInt(0) // in wei
|
||||||
|
|
||||||
gasLimit := t.cfg.ForgeBatchGasCost.Fixed +
|
gasLimit := t.cfg.ForgeBatchGasCost.Fixed +
|
||||||
uint64(len(batchInfo.L1UserTxsExtra))*t.cfg.ForgeBatchGasCost.L1UserTx +
|
uint64(len(batchInfo.L1UserTxs))*t.cfg.ForgeBatchGasCost.L1UserTx +
|
||||||
uint64(len(batchInfo.L1CoordTxs))*t.cfg.ForgeBatchGasCost.L1CoordTx +
|
uint64(len(batchInfo.L1CoordTxs))*t.cfg.ForgeBatchGasCost.L1CoordTx +
|
||||||
uint64(len(batchInfo.L2Txs))*t.cfg.ForgeBatchGasCost.L2Tx
|
uint64(len(batchInfo.L2Txs))*t.cfg.ForgeBatchGasCost.L2Tx
|
||||||
auth.GasLimit = gasLimit
|
auth.GasLimit = gasLimit
|
||||||
|
|||||||
@@ -693,11 +693,11 @@ func (hdb *HistoryDB) GetAllExits() ([]common.ExitInfo, error) {
|
|||||||
func (hdb *HistoryDB) GetAllL1UserTxs() ([]common.L1Tx, error) {
|
func (hdb *HistoryDB) GetAllL1UserTxs() ([]common.L1Tx, error) {
|
||||||
var txs []*common.L1Tx
|
var txs []*common.L1Tx
|
||||||
err := meddler.QueryAll(
|
err := meddler.QueryAll(
|
||||||
hdb.dbRead, &txs, // Note that '\x' gets parsed as a big.Int with value = 0
|
hdb.dbRead, &txs,
|
||||||
`SELECT tx.id, tx.to_forge_l1_txs_num, tx.position, tx.user_origin,
|
`SELECT tx.id, tx.to_forge_l1_txs_num, tx.position, tx.user_origin,
|
||||||
tx.from_idx, tx.effective_from_idx, tx.from_eth_addr, tx.from_bjj, tx.to_idx, tx.token_id,
|
tx.from_idx, tx.effective_from_idx, tx.from_eth_addr, tx.from_bjj, tx.to_idx, tx.token_id,
|
||||||
tx.amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.amount_success THEN tx.amount ELSE '\x' END) AS effective_amount,
|
tx.amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.amount_success THEN tx.amount ELSE 0 END) AS effective_amount,
|
||||||
tx.deposit_amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.deposit_amount_success THEN tx.deposit_amount ELSE '\x' END) AS effective_deposit_amount,
|
tx.deposit_amount, (CASE WHEN tx.batch_num IS NULL THEN NULL WHEN tx.deposit_amount_success THEN tx.deposit_amount ELSE 0 END) AS effective_deposit_amount,
|
||||||
tx.eth_block_num, tx.type, tx.batch_num
|
tx.eth_block_num, tx.type, tx.batch_num
|
||||||
FROM tx WHERE is_l1 = TRUE AND user_origin = TRUE ORDER BY item_id;`,
|
FROM tx WHERE is_l1 = TRUE AND user_origin = TRUE ORDER BY item_id;`,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
-- +migrate Up
|
-- +migrate Up
|
||||||
|
|
||||||
|
-- NOTE: We use "DECIMAL(78,0)" to encode go *big.Int types. All the *big.Int
|
||||||
|
-- that we deal with represent a value in the SNARK field, which is an integer
|
||||||
|
-- of 256 bits. `log(2**256, 10) = 77.06`: that is, a 256 bit number can have
|
||||||
|
-- at most 78 digits, so we use this value to specify the precision in the
|
||||||
|
-- PostgreSQL DECIMAL guaranteeing that we will never lose precision.
|
||||||
|
|
||||||
-- History
|
-- History
|
||||||
CREATE TABLE block (
|
CREATE TABLE block (
|
||||||
eth_block_num BIGINT PRIMARY KEY,
|
eth_block_num BIGINT PRIMARY KEY,
|
||||||
@@ -22,10 +28,10 @@ CREATE TABLE batch (
|
|||||||
forger_addr BYTEA NOT NULL, -- fake foreign key for coordinator
|
forger_addr BYTEA NOT NULL, -- fake foreign key for coordinator
|
||||||
fees_collected BYTEA NOT NULL,
|
fees_collected BYTEA NOT NULL,
|
||||||
fee_idxs_coordinator BYTEA NOT NULL,
|
fee_idxs_coordinator BYTEA NOT NULL,
|
||||||
state_root BYTEA NOT NULL,
|
state_root DECIMAL(78,0) NOT NULL,
|
||||||
num_accounts BIGINT NOT NULL,
|
num_accounts BIGINT NOT NULL,
|
||||||
last_idx BIGINT NOT NULL,
|
last_idx BIGINT NOT NULL,
|
||||||
exit_root BYTEA NOT NULL,
|
exit_root DECIMAL(78,0) NOT NULL,
|
||||||
forge_l1_txs_num BIGINT,
|
forge_l1_txs_num BIGINT,
|
||||||
slot_num BIGINT NOT NULL,
|
slot_num BIGINT NOT NULL,
|
||||||
total_fees_usd NUMERIC
|
total_fees_usd NUMERIC
|
||||||
@@ -34,7 +40,7 @@ CREATE TABLE batch (
|
|||||||
CREATE TABLE bid (
|
CREATE TABLE bid (
|
||||||
item_id SERIAL PRIMARY KEY,
|
item_id SERIAL PRIMARY KEY,
|
||||||
slot_num BIGINT NOT NULL,
|
slot_num BIGINT NOT NULL,
|
||||||
bid_value BYTEA NOT NULL,
|
bid_value DECIMAL(78,0) NOT NULL,
|
||||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||||
bidder_addr BYTEA NOT NULL -- fake foreign key for coordinator
|
bidder_addr BYTEA NOT NULL -- fake foreign key for coordinator
|
||||||
);
|
);
|
||||||
@@ -106,7 +112,7 @@ CREATE TABLE account_update (
|
|||||||
batch_num BIGINT NOT NULL REFERENCES batch (batch_num) ON DELETE CASCADE,
|
batch_num BIGINT NOT NULL REFERENCES batch (batch_num) ON DELETE CASCADE,
|
||||||
idx BIGINT NOT NULL REFERENCES account (idx) ON DELETE CASCADE,
|
idx BIGINT NOT NULL REFERENCES account (idx) ON DELETE CASCADE,
|
||||||
nonce BIGINT NOT NULL,
|
nonce BIGINT NOT NULL,
|
||||||
balance BYTEA NOT NULL
|
balance DECIMAL(78,0) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE exit_tree (
|
CREATE TABLE exit_tree (
|
||||||
@@ -114,7 +120,7 @@ CREATE TABLE exit_tree (
|
|||||||
batch_num BIGINT REFERENCES batch (batch_num) ON DELETE CASCADE,
|
batch_num BIGINT REFERENCES batch (batch_num) ON DELETE CASCADE,
|
||||||
account_idx BIGINT REFERENCES account (idx) ON DELETE CASCADE,
|
account_idx BIGINT REFERENCES account (idx) ON DELETE CASCADE,
|
||||||
merkle_proof BYTEA NOT NULL,
|
merkle_proof BYTEA NOT NULL,
|
||||||
balance BYTEA NOT NULL,
|
balance DECIMAL(78,0) NOT NULL,
|
||||||
instant_withdrawn BIGINT REFERENCES block (eth_block_num) ON DELETE SET NULL,
|
instant_withdrawn BIGINT REFERENCES block (eth_block_num) ON DELETE SET NULL,
|
||||||
delayed_withdraw_request BIGINT REFERENCES block (eth_block_num) ON DELETE SET NULL,
|
delayed_withdraw_request BIGINT REFERENCES block (eth_block_num) ON DELETE SET NULL,
|
||||||
owner BYTEA,
|
owner BYTEA,
|
||||||
@@ -164,7 +170,7 @@ CREATE TABLE tx (
|
|||||||
to_idx BIGINT NOT NULL,
|
to_idx BIGINT NOT NULL,
|
||||||
to_eth_addr BYTEA,
|
to_eth_addr BYTEA,
|
||||||
to_bjj BYTEA,
|
to_bjj BYTEA,
|
||||||
amount BYTEA NOT NULL,
|
amount DECIMAL(78,0) NOT NULL,
|
||||||
amount_success BOOLEAN NOT NULL DEFAULT true,
|
amount_success BOOLEAN NOT NULL DEFAULT true,
|
||||||
amount_f NUMERIC NOT NULL,
|
amount_f NUMERIC NOT NULL,
|
||||||
token_id INT NOT NULL REFERENCES token (token_id),
|
token_id INT NOT NULL REFERENCES token (token_id),
|
||||||
@@ -174,7 +180,7 @@ CREATE TABLE tx (
|
|||||||
-- L1
|
-- L1
|
||||||
to_forge_l1_txs_num BIGINT,
|
to_forge_l1_txs_num BIGINT,
|
||||||
user_origin BOOLEAN,
|
user_origin BOOLEAN,
|
||||||
deposit_amount BYTEA,
|
deposit_amount DECIMAL(78,0),
|
||||||
deposit_amount_success BOOLEAN NOT NULL DEFAULT true,
|
deposit_amount_success BOOLEAN NOT NULL DEFAULT true,
|
||||||
deposit_amount_f NUMERIC,
|
deposit_amount_f NUMERIC,
|
||||||
deposit_amount_usd NUMERIC,
|
deposit_amount_usd NUMERIC,
|
||||||
@@ -544,7 +550,7 @@ FOR EACH ROW EXECUTE PROCEDURE forge_l1_user_txs();
|
|||||||
|
|
||||||
CREATE TABLE rollup_vars (
|
CREATE TABLE rollup_vars (
|
||||||
eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||||
fee_add_token BYTEA NOT NULL,
|
fee_add_token DECIMAL(78,0) NOT NULL,
|
||||||
forge_l1_timeout BIGINT NOT NULL,
|
forge_l1_timeout BIGINT NOT NULL,
|
||||||
withdrawal_delay BIGINT NOT NULL,
|
withdrawal_delay BIGINT NOT NULL,
|
||||||
buckets BYTEA NOT NULL,
|
buckets BYTEA NOT NULL,
|
||||||
@@ -556,7 +562,7 @@ CREATE TABLE bucket_update (
|
|||||||
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
eth_block_num BIGINT NOT NULL REFERENCES block (eth_block_num) ON DELETE CASCADE,
|
||||||
num_bucket BIGINT NOT NULL,
|
num_bucket BIGINT NOT NULL,
|
||||||
block_stamp BIGINT NOT NULL,
|
block_stamp BIGINT NOT NULL,
|
||||||
withdrawals BYTEA NOT NULL
|
withdrawals DECIMAL(78,0) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE token_exchange (
|
CREATE TABLE token_exchange (
|
||||||
@@ -572,7 +578,7 @@ CREATE TABLE escape_hatch_withdrawal (
|
|||||||
who_addr BYTEA NOT NULL,
|
who_addr BYTEA NOT NULL,
|
||||||
to_addr BYTEA NOT NULL,
|
to_addr BYTEA NOT NULL,
|
||||||
token_addr BYTEA NOT NULL,
|
token_addr BYTEA NOT NULL,
|
||||||
amount BYTEA NOT NULL
|
amount DECIMAL(78,0) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auction_vars (
|
CREATE TABLE auction_vars (
|
||||||
@@ -610,7 +616,7 @@ CREATE TABLE tx_pool (
|
|||||||
effective_to_eth_addr BYTEA,
|
effective_to_eth_addr BYTEA,
|
||||||
effective_to_bjj BYTEA,
|
effective_to_bjj BYTEA,
|
||||||
token_id INT NOT NULL REFERENCES token (token_id) ON DELETE CASCADE,
|
token_id INT NOT NULL REFERENCES token (token_id) ON DELETE CASCADE,
|
||||||
amount BYTEA NOT NULL,
|
amount DECIMAL(78,0) NOT NULL,
|
||||||
amount_f NUMERIC NOT NULL,
|
amount_f NUMERIC NOT NULL,
|
||||||
fee SMALLINT NOT NULL,
|
fee SMALLINT NOT NULL,
|
||||||
nonce BIGINT NOT NULL,
|
nonce BIGINT NOT NULL,
|
||||||
@@ -624,7 +630,7 @@ CREATE TABLE tx_pool (
|
|||||||
rq_to_eth_addr BYTEA,
|
rq_to_eth_addr BYTEA,
|
||||||
rq_to_bjj BYTEA,
|
rq_to_bjj BYTEA,
|
||||||
rq_token_id INT,
|
rq_token_id INT,
|
||||||
rq_amount BYTEA,
|
rq_amount DECIMAL(78,0),
|
||||||
rq_fee SMALLINT,
|
rq_fee SMALLINT,
|
||||||
rq_nonce BIGINT,
|
rq_nonce BIGINT,
|
||||||
tx_type VARCHAR(40) NOT NULL,
|
tx_type VARCHAR(40) NOT NULL,
|
||||||
|
|||||||
20
db/utils.go
20
db/utils.go
@@ -13,6 +13,9 @@ import (
|
|||||||
"github.com/hermeznetwork/hermez-node/log"
|
"github.com/hermeznetwork/hermez-node/log"
|
||||||
"github.com/hermeznetwork/tracerr"
|
"github.com/hermeznetwork/tracerr"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
|
//nolint:errcheck // driver for postgres DB
|
||||||
|
_ "github.com/lib/pq"
|
||||||
migrate "github.com/rubenv/sql-migrate"
|
migrate "github.com/rubenv/sql-migrate"
|
||||||
"github.com/russross/meddler"
|
"github.com/russross/meddler"
|
||||||
"golang.org/x/sync/semaphore"
|
"golang.org/x/sync/semaphore"
|
||||||
@@ -165,7 +168,11 @@ func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error {
|
|||||||
return tracerr.Wrap(fmt.Errorf("BigIntMeddler.PostRead: nil pointer"))
|
return tracerr.Wrap(fmt.Errorf("BigIntMeddler.PostRead: nil pointer"))
|
||||||
}
|
}
|
||||||
field := fieldPtr.(**big.Int)
|
field := fieldPtr.(**big.Int)
|
||||||
*field = new(big.Int).SetBytes([]byte(*ptr))
|
var ok bool
|
||||||
|
*field, ok = new(big.Int).SetString(*ptr, 10)
|
||||||
|
if !ok {
|
||||||
|
return tracerr.Wrap(fmt.Errorf("big.Int.SetString failed on \"%v\"", *ptr))
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +180,7 @@ func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error {
|
|||||||
func (b BigIntMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) {
|
func (b BigIntMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) {
|
||||||
field := fieldPtr.(*big.Int)
|
field := fieldPtr.(*big.Int)
|
||||||
|
|
||||||
return field.Bytes(), nil
|
return field.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BigIntNullMeddler encodes or decodes the field value to or from JSON
|
// BigIntNullMeddler encodes or decodes the field value to or from JSON
|
||||||
@@ -198,7 +205,12 @@ func (b BigIntNullMeddler) PostRead(fieldPtr, scanTarget interface{}) error {
|
|||||||
if ptr == nil {
|
if ptr == nil {
|
||||||
return tracerr.Wrap(fmt.Errorf("BigIntMeddler.PostRead: nil pointer"))
|
return tracerr.Wrap(fmt.Errorf("BigIntMeddler.PostRead: nil pointer"))
|
||||||
}
|
}
|
||||||
*field = new(big.Int).SetBytes(ptr)
|
var ok bool
|
||||||
|
*field, ok = new(big.Int).SetString(string(ptr), 10)
|
||||||
|
if !ok {
|
||||||
|
return tracerr.Wrap(fmt.Errorf("big.Int.SetString failed on \"%v\"", string(ptr)))
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +220,7 @@ func (b BigIntNullMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}
|
|||||||
if field == nil {
|
if field == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return field.Bytes(), nil
|
return field.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SliceToSlicePtrs converts any []Foo to []*Foo
|
// SliceToSlicePtrs converts any []Foo to []*Foo
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/russross/meddler"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
type foo struct {
|
type foo struct {
|
||||||
@@ -33,3 +37,42 @@ func TestSlicePtrsToSlice(t *testing.T) {
|
|||||||
assert.Equal(t, *a[i], b[i])
|
assert.Equal(t, *a[i], b[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBigInt(t *testing.T) {
|
||||||
|
pass := os.Getenv("POSTGRES_PASS")
|
||||||
|
db, err := InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
_, err := db.Exec("DROP TABLE IF EXISTS test_big_int;")
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = db.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = db.Exec("DROP TABLE IF EXISTS test_big_int;")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = db.Exec(`CREATE TABLE test_big_int (
|
||||||
|
item_id SERIAL PRIMARY KEY,
|
||||||
|
value1 DECIMAL(78, 0) NOT NULL,
|
||||||
|
value2 DECIMAL(78, 0),
|
||||||
|
value3 DECIMAL(78, 0)
|
||||||
|
);`)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
type Entry struct {
|
||||||
|
ItemID int `meddler:"item_id"`
|
||||||
|
Value1 *big.Int `meddler:"value1,bigint"`
|
||||||
|
Value2 *big.Int `meddler:"value2,bigintnull"`
|
||||||
|
Value3 *big.Int `meddler:"value3,bigintnull"`
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := Entry{ItemID: 1, Value1: big.NewInt(1234567890), Value2: big.NewInt(9876543210), Value3: nil}
|
||||||
|
err = meddler.Insert(db, "test_big_int", &entry)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var dbEntry Entry
|
||||||
|
err = meddler.QueryRow(db, &dbEntry, "SELECT * FROM test_big_int WHERE item_id = 1;")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, entry, dbEntry)
|
||||||
|
}
|
||||||
|
|||||||
@@ -309,9 +309,12 @@ func (_HermezAuctionProtocol *HermezAuctionProtocolCaller) Coordinators(opts *bi
|
|||||||
Forger common.Address
|
Forger common.Address
|
||||||
CoordinatorURL string
|
CoordinatorURL string
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return *outstruct, err
|
||||||
|
}
|
||||||
|
|
||||||
outstruct.Forger = out[0].(common.Address)
|
outstruct.Forger = *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
|
||||||
outstruct.CoordinatorURL = out[1].(string)
|
outstruct.CoordinatorURL = *abi.ConvertType(out[1], new(string)).(*string)
|
||||||
|
|
||||||
return *outstruct, err
|
return *outstruct, err
|
||||||
|
|
||||||
@@ -884,12 +887,15 @@ func (_HermezAuctionProtocol *HermezAuctionProtocolCaller) Slots(opts *bind.Call
|
|||||||
BidAmount *big.Int
|
BidAmount *big.Int
|
||||||
ClosedMinBid *big.Int
|
ClosedMinBid *big.Int
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return *outstruct, err
|
||||||
|
}
|
||||||
|
|
||||||
outstruct.Bidder = out[0].(common.Address)
|
outstruct.Bidder = *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
|
||||||
outstruct.Fulfilled = out[1].(bool)
|
outstruct.Fulfilled = *abi.ConvertType(out[1], new(bool)).(*bool)
|
||||||
outstruct.ForgerCommitment = out[2].(bool)
|
outstruct.ForgerCommitment = *abi.ConvertType(out[2], new(bool)).(*bool)
|
||||||
outstruct.BidAmount = out[3].(*big.Int)
|
outstruct.BidAmount = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int)
|
||||||
outstruct.ClosedMinBid = out[4].(*big.Int)
|
outstruct.ClosedMinBid = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int)
|
||||||
|
|
||||||
return *outstruct, err
|
return *outstruct, err
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -367,6 +367,7 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) {
|
|||||||
ForgeDelay: cfg.Coordinator.ForgeDelay.Duration,
|
ForgeDelay: cfg.Coordinator.ForgeDelay.Duration,
|
||||||
MustForgeAtSlotDeadline: cfg.Coordinator.MustForgeAtSlotDeadline,
|
MustForgeAtSlotDeadline: cfg.Coordinator.MustForgeAtSlotDeadline,
|
||||||
IgnoreSlotCommitment: cfg.Coordinator.IgnoreSlotCommitment,
|
IgnoreSlotCommitment: cfg.Coordinator.IgnoreSlotCommitment,
|
||||||
|
ForgeOncePerSlotIfTxs: cfg.Coordinator.ForgeOncePerSlotIfTxs,
|
||||||
ForgeNoTxsDelay: cfg.Coordinator.ForgeNoTxsDelay.Duration,
|
ForgeNoTxsDelay: cfg.Coordinator.ForgeNoTxsDelay.Duration,
|
||||||
SyncRetryInterval: cfg.Coordinator.SyncRetryInterval.Duration,
|
SyncRetryInterval: cfg.Coordinator.SyncRetryInterval.Duration,
|
||||||
PurgeByExtDelInterval: cfg.Coordinator.PurgeByExtDelInterval.Duration,
|
PurgeByExtDelInterval: cfg.Coordinator.PurgeByExtDelInterval.Duration,
|
||||||
|
|||||||
Reference in New Issue
Block a user