From 604808543f9ff90cc3e0940d0b079c2c4e25af6d Mon Sep 17 00:00:00 2001 From: a_bennassar Date: Mon, 13 Sep 2021 12:32:47 +0200 Subject: [PATCH] Release/v1.7.0 (#1140) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Backup old config file if exits * Backup old config file if exits * Ignore new config file if exits * Avoid rewrite the service config file * Use SuggestGasTipCap to get GasPrice * Add base fee * Fix typo * Add log, fix typos * Fix imports for linter * Adjust log * Add common.nonce package * Fix nonce import in tests * Fix imports * Linter fixes * Remove use of interface * Linter fixes * bump gin version (#1046) * Reference endpoints with filter options (#1039) Reference endpoints with filter options * Turn the structs public * Linter fixes * Use 2 structures for Token * Use 2 structures for Token * Test if solve the stack overflow issue * Fix types * Revert marshal method * Move api types to common, to avoid ciclic import error * Fix structure types * Fix types * Add json tags to PoolL2TxAPI * Turn the poolTxAPIView private * Fix TxL2 name and refactor * Update swagger * Add nullable to field * fixed verifyPoolL2Tx error (#1045) * code owners (#998) * code owners * Suggestion * suggestion * suggestion * Fix the use of multi proof servers * Update example toml * Adding new request for updating transactions in tx-pool (#1044) * added on conflict condition to checkPoolIsFull * added const to onConflictQuery var * deleted rqfromidx test in txspool * adding update for txs in the pool * added correct test to atomicpool_test.go and additional fields to update for updateTx function * fixed lint errors * deleted checking for null in updateTx function * added more tests for update txpool * added info for transactions-pool put request in swagger.yml * moved UpdateTxAPI function from l2db.go file to the apiqueries.go * atomic: fix error message at invalid group * Feature/update tx by idx and nonce (#1070) * adding update transaction by idx and nonce function * merged with develop * Feature/#711 default config (#1037) * Configuration * ApiServer and logs fix * Readme * Config as library * Config error messages * Fix env variable names * Fix paths in default config * library name changed * Readme improved * fix array with env variables * linter * Default values and readme improved * Adapt #1068 PR * linter * cfg not required * Readme * New lib version and env bug fixed * test: remove debug log * tests: remove unecessary comments * Feature/tx selector sort txs by profitability (#1072) * make tx selector to sort txs by profitability * remove unused file * trigger checks * added guide to run integration tests (#1065) * added guide to run integration tests * added more info to guide * fixed pr comments * added possibility to update tx with invl status (#1075) * txselector: use PR suggestion Co-authored-by: a_bennassar * remove not necessary TODO messages (#1093) * remove TODOs from code since we created issues to address them (#1094) * Remove priceupdater (#1053) * remove priceupdater * remove update and create fiat * remove config price updater Co-authored-by: Marcelo Castellani Co-authored-by: Marcelo Castellani Co-authored-by: Mikhail Wall Co-authored-by: Alonso Rodriguez Co-authored-by: Mário Idival Co-authored-by: Thiago Coimbra Lemos --- .github/CODEOWNERS | 32 +- Makefile | 20 +- SETUP_NODE.md | 3 - api/account_test.go | 5 +- api/accountcreationauths.go | 2 +- api/api.go | 4 +- api/api_test.go | 3 +- api/atomicpool_test.go | 15 + api/batch_test.go | 2 +- api/errors.go | 5 + api/exits_test.go | 2 +- api/fiat_test.go | 5 +- api/noroute_test.go | 4 +- api/parsers/txpool.go | 22 + api/state_test.go | 5 +- api/stateapiupdater/stateapiupdater.go | 4 +- api/swagger.yml | 102 +++- api/txshistory_test.go | 7 +- api/txspool.go | 144 +++++- api/txspool_test.go | 202 +++++++- cmd/heznode/cfg.builder.toml | 303 +++++++----- cmd/heznode/main.go | 2 +- common/account.go | 54 +-- common/account_test.go | 33 +- {api => common}/apitypes/apitypes.go | 0 {api => common}/apitypes/apitypes_test.go | 0 common/apitypes/txl2.go | 150 ++++++ common/batch.go | 2 +- common/errors.go | 3 - common/l2tx.go | 7 +- common/nonce/errors.go | 6 + common/nonce/nonce.go | 43 ++ common/pooll2tx.go | 18 +- common/tx.go | 3 +- config/README.md | 211 ++++++++ config/config.go | 231 ++++----- config/default.go | 112 +++++ coordinator/coordinator_test.go | 8 +- coordinator/pipeline.go | 1 - coordinator/purger.go | 5 +- coordinator/purger_test.go | 17 +- coordinator/txmanager.go | 3 - db/historydb/apiqueries.go | 5 +- db/historydb/historydb.go | 25 - db/historydb/historydb_test.go | 13 +- db/historydb/nodeinfo.go | 2 +- db/historydb/views.go | 13 +- db/l2db/apiqueries.go | 91 +++- db/l2db/l2db.go | 111 ++++- db/l2db/l2db_test.go | 13 +- db/l2db/views.go | 127 +++-- db/migrations/0008_test.go | 4 +- db/migrations/0009.sql | 20 + db/migrations/0009_test.go | 180 +++++++ db/statedb/statedb_test.go | 11 +- ...fo-to-run-integration-tests-hermez-node.md | 40 ++ eth/ethereum.go | 23 +- eth/rollup.go | 2 - go.mod | 6 +- go.sum | 124 ++--- node/node.go | 44 +- priceupdater/priceupdater.go | 453 ------------------ priceupdater/priceupdater_test.go | 160 ------- prover/prover_test.go | 1 - synchronizer/synchronizer.go | 12 - test/debugapi/debugapi_test.go | 3 +- test/ethclient.go | 26 - test/historydb.go | 3 +- test/l2db.go | 4 +- test/til/txs.go | 11 +- test/til/txs_test.go | 31 +- txprocessor/txprocessor.go | 6 +- txprocessor/txprocessor_test.go | 13 +- txselector/txselector.go | 55 ++- txselector/txselector_test.go | 63 ++- 75 files changed, 2063 insertions(+), 1432 deletions(-) rename {api => common}/apitypes/apitypes.go (100%) rename {api => common}/apitypes/apitypes_test.go (100%) create mode 100644 common/apitypes/txl2.go create mode 100644 common/nonce/errors.go create mode 100644 common/nonce/nonce.go create mode 100644 config/README.md create mode 100644 config/default.go create mode 100644 db/migrations/0009.sql create mode 100644 db/migrations/0009_test.go create mode 100644 doc/info-to-run-integration-tests-hermez-node.md delete mode 100644 priceupdater/priceupdater.go delete mode 100644 priceupdater/priceupdater_test.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6fb5ad0ac..326776dc5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,9 +1,25 @@ -*.md @jeffprestes -api/ @arnaubennassar -db/*.go @arnaubennassar -db/historydb @arnaubennassar -db/migrations @arnaubennassar -db/l2db @arnaubennassar -txselector/ @arnaubennassar +*.md @jeffprestes @arnaubennassar +api/ @Mikelle @ARR552 +db/*.go @Mikelle @tclemos +db/historydb @Mikelle @tclemos +db/migrations @Mikelle @arnaubennassar +db/l2db @Mikelle @marioidival +db/kvdb @Mikelle @marioidival +db/statedb @Mikelle @marioidival +txselector/ @mfcastellani @tclemos @arnaubennassar etherscan/ @ARR552 -priceupdater/ @ARR552 +priceupdater/ @marioidival @ARR552 +common/ @Mikelle @mfcastellani +config/ @ARR552 @marioidival +coordinator/ @mfcastellani @marioidival +node/ @Mikelle @ARR552 +eth/ @ARR552 @arnaubennassar +cmd/ @mfcastellani +txprocessor/ @mfcastellani @tclemos @arnaubennassar +health/ @Mikelle @ARR552 +log/ @mfcastellani +metric/ @mfcastellani +test/ @arnaubennassar @mfcastellani +prover/ @mfcastellani @marioidival +synchronizer/ @ARR552 @arnaubennassar +batchbuilder/ @mfcastellani @marioidival diff --git a/Makefile b/Makefile index 5e936a4c6..f6be9e70a 100644 --- a/Makefile +++ b/Makefile @@ -187,25 +187,28 @@ exec: install: echo " > Installing heznode as a service" echo " > Checking requirements" -ifneq ("$(wildcard $(dist/heznode))","") +ifneq ("$(wildcard ./dist/heznode)","") echo " - heznode file found!" else echo " - heznode file not found!" echo " - please, run make build before make install!" test -f ./dist/heznode endif -ifneq ("$(wildcard $(cmd/heznode/cfg.builder.toml))","") +ifneq ("$(wildcard ./cmd/heznode/cfg.builder.toml)","") echo " - config template found!" else echo " - config template not found!" - echo " - please, check the !" + echo " - please, check the ./cmd/heznode/cfg.builder.toml!" test -f ./cmd/heznode/cfg.builder.toml endif - echo " > Copying hez binary to /usr/local/bin" - cp dist/heznode /usr/local/bin/heznode +ifneq ("$(wildcard /etc/hermez/config.toml)","") + echo " > Config file already exists - ignored." +else echo " > Copying config file to /etc/hermez" mkdir -p /etc/hermez cp cmd/heznode/cfg.builder.toml /etc/hermez/config.toml +endif +ifeq ("$(wildcard /etc/systemd/system/heznode.service)", "") echo " > Registering as a service" touch /etc/systemd/system/heznode.service echo "[Unit]" | tee -a /etc/systemd/system/heznode.service > /dev/null @@ -227,6 +230,13 @@ endif echo "WantedBy=multi-user.target" | tee -a /etc/systemd/system/heznode.service > /dev/null echo "" | tee -a /etc/systemd/system/heznode.service > /dev/null systemctl daemon-reload +else + echo " > Service is already registered. Will be stoped!" + service heznode stop + rm /usr/local/bin/heznode +endif + echo " > Copying hez binary to /usr/local/bin" + cp dist/heznode /usr/local/bin/heznode echo " > Service is ready. Please update the configs at /etc/hermez/config.toml" echo " > You can use the service with service heznode status|start|stop" echo " Bye." diff --git a/SETUP_NODE.md b/SETUP_NODE.md index 174a44d33..2d1c14b71 100644 --- a/SETUP_NODE.md +++ b/SETUP_NODE.md @@ -213,9 +213,6 @@ folder. Is so that the API can be accessed by users outside the host. - - [ ] Add APIKey to `PriceUpdater.Fiat` section. - Get a key [here](https://exchangeratesapi.io/) - - [ ] Change PostgreSQL section with the values of user created before. - HostWrite: Use the IP from server instead of localhost diff --git a/api/account_test.go b/api/account_test.go index 1ab9b8acd..5b2bb9ea7 100644 --- a/api/account_test.go +++ b/api/account_test.go @@ -5,8 +5,9 @@ import ( "strconv" "testing" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/mitchellh/copystructure" @@ -20,7 +21,7 @@ type testAccount struct { BatchNum common.BatchNum `json:"batchNum"` PublicKey apitypes.HezBJJ `json:"bjj"` EthAddr apitypes.HezEthAddr `json:"hezEthereumAddress"` - Nonce common.Nonce `json:"nonce"` + Nonce nonce.Nonce `json:"nonce"` Balance *apitypes.BigIntStr `json:"balance"` Token historydb.TokenWithUSD `json:"token"` } diff --git a/api/accountcreationauths.go b/api/accountcreationauths.go index 8901aa91f..85667e688 100644 --- a/api/accountcreationauths.go +++ b/api/accountcreationauths.go @@ -7,9 +7,9 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/gin-gonic/gin" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/api/parsers" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" "github.com/iden3/go-iden3-crypto/babyjub" ) diff --git a/api/api.go b/api/api.go index 10730e44d..b059579d8 100644 --- a/api/api.go +++ b/api/api.go @@ -106,9 +106,11 @@ func NewAPI( v1.GET("/account-creation-authorization/:hezEthereumAddress", a.getAccountCreationAuth) // Transaction v1.POST("/transactions-pool", a.postPoolTx) - v1.POST("/atomic-pool", a.postAtomicPool) + v1.PUT("/transactions-pool/:id", a.putPoolTx) + v1.PUT("/transactions-pool/accounts/:accountIndex/nonces/:nonce", a.putPoolTxByIdxAndNonce) v1.GET("/transactions-pool/:id", a.getPoolTx) v1.GET("/transactions-pool", a.getPoolTxs) + v1.POST("/atomic-pool", a.postAtomicPool) v1.GET("/atomic-pool/:id", a.getAtomicGroup) } diff --git a/api/api_test.go b/api/api_test.go index 4dad03478..2b665103b 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -21,6 +21,7 @@ import ( "github.com/gin-gonic/gin" "github.com/hermeznetwork/hermez-node/api/stateapiupdater" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/hermeznetwork/hermez-node/db/l2db" @@ -361,7 +362,7 @@ func TestMain(m *testing.M) { for _, batch := range block.Rollup.Batches { commonL2Txs = append(commonL2Txs, batch.L2Txs...) for i := range batch.CreatedAccounts { - batch.CreatedAccounts[i].Nonce = common.Nonce(i) + batch.CreatedAccounts[i].Nonce = nonce.Nonce(i) commonAccounts = append(commonAccounts, batch.CreatedAccounts[i]) } commonBatches = append(commonBatches, batch.Batch) diff --git a/api/atomicpool_test.go b/api/atomicpool_test.go index 277f2884c..89faa0dc8 100644 --- a/api/atomicpool_test.go +++ b/api/atomicpool_test.go @@ -153,6 +153,21 @@ func TestAtomicPool(t *testing.T) { // Check txs in the DB assertTxs(txsToReceive, atomicGroup.ID) + // test that we can't update atomic tx + // this test is checking, that this request will return error + // bcs of bad signature. Bad signature returned, bcs Rq* fields + // are part of the signature, but they are not part of json, which was sent + // we need to keep this test in case Rq* fields will be part of the PoolL2Tx json + txRepeated1 := atomicGroup.Txs[1] + jsonTxBytes, err = json.Marshal(txRepeated1) + require.NoError(t, err) + jsonTxReader = bytes.NewReader(jsonTxBytes) + fetchedTxID := common.TxID{} + require.Error(t, doGoodReq( + "PUT", + apiURL+"transactions-pool/"+txRepeated1.TxID.String(), + jsonTxReader, &fetchedTxID)) + // Test only one tx with fee // Generate txs txs = []common.PoolL2Tx{} diff --git a/api/batch_test.go b/api/batch_test.go index 383e2fe8d..0c106673a 100644 --- a/api/batch_test.go +++ b/api/batch_test.go @@ -7,8 +7,8 @@ import ( "time" ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" "github.com/hermeznetwork/hermez-node/db" "github.com/mitchellh/copystructure" "github.com/stretchr/testify/assert" diff --git a/api/errors.go b/api/errors.go index beac53e50..e96311c38 100644 --- a/api/errors.go +++ b/api/errors.go @@ -147,6 +147,11 @@ const ( // ErrFeeTooBigType type for fee too big error ErrFeeTooBigType apiErrorType = "ErrFeeTooBig" + // ErrNothingToUpdateCode code for nothing to update error + ErrNothingToUpdateCode apiErrorCode = 25 + // ErrNothingToUpdateType type for nothing to update type + ErrNothingToUpdateType apiErrorType = "ErrNothingToUpdate" + // ErrUnsupportedMaxNumBatch error message returned when tx.MaxNumBatch != 0 until the feature is fully implemented ErrUnsupportedMaxNumBatch = "currently only supported value for maxNumBatch is 0, this will change soon when the feature is fully implemented" diff --git a/api/exits_test.go b/api/exits_test.go index db89c6dcb..babc8eb86 100644 --- a/api/exits_test.go +++ b/api/exits_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/mitchellh/copystructure" diff --git a/api/fiat_test.go b/api/fiat_test.go index fcfb0ffe6..48b148e52 100644 --- a/api/fiat_test.go +++ b/api/fiat_test.go @@ -13,7 +13,10 @@ import ( ) func genFiatPrices(db *historydb.HistoryDB) error { - err := db.CreateFiatPrice("EUR", "USD", 0.82) + _, err := db.DB().Exec( + "INSERT INTO fiat(currency, base_currency, price) VALUES ($1, $2, $3);", + "EUR", "USD", 0.82, + ) if err != nil { return err } diff --git a/api/noroute_test.go b/api/noroute_test.go index 08223c1a6..463e6ad71 100644 --- a/api/noroute_test.go +++ b/api/noroute_test.go @@ -13,7 +13,7 @@ func TestNoRouteVersionNotProvided(t *testing.T) { resp, err := doSimpleReq("GET", endpoint) assert.NoError(t, err) assert.Equal(t, - "{\"error\":\"Version not provided, please provide a valid version in the path such as v1\"}\n", + "{\"error\":\"Version not provided, please provide a valid version in the path such as v1\"}", resp) } @@ -24,6 +24,6 @@ func TestNoRoute(t *testing.T) { resp, err := doSimpleReq("GET", endpoint) assert.NoError(t, err) assert.Equal(t, - "{\"error\":\"404 page not found\"}\n", + "{\"error\":\"404 page not found\"}", resp) } diff --git a/api/parsers/txpool.go b/api/parsers/txpool.go index a5c79a6c9..11029334c 100644 --- a/api/parsers/txpool.go +++ b/api/parsers/txpool.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db/l2db" "github.com/hermeznetwork/tracerr" "gopkg.in/go-playground/validator.v9" @@ -28,6 +29,27 @@ func ParsePoolTxFilter(c *gin.Context) (common.TxID, error) { return txID, nil } +// PoolTxUpdateByIdxAndNonceFilter struct to get uri param from /transactions-pool/accounts/:accountIndex/nonces/:nonce request +type PoolTxUpdateByIdxAndNonceFilter struct { + AccountIndex string `uri:"accountIndex" binding:"required"` + Nonce *uint `uri:"nonce" binding:"required"` +} + +// ParsePoolTxUpdateByIdxAndNonceFilter func for parsing pool tx update by idx and nonce filter to the account index and nonce +func ParsePoolTxUpdateByIdxAndNonceFilter(c *gin.Context) (common.Idx, nonce.Nonce, error) { + var poolTxUpdateByIdxAndNonceFilter PoolTxUpdateByIdxAndNonceFilter + if err := c.ShouldBindUri(&poolTxUpdateByIdxAndNonceFilter); err != nil { + return common.Idx(0), 0, tracerr.Wrap(err) + } + queryAccount, err := common.StringToIdx(poolTxUpdateByIdxAndNonceFilter.AccountIndex, "accountIndex") + if err != nil { + return common.Idx(0), 0, tracerr.Wrap(err) + } + + queryNonce := nonce.Nonce(*poolTxUpdateByIdxAndNonceFilter.Nonce) + return *queryAccount.AccountIndex, queryNonce, nil +} + // PoolTxsFilters struct for holding query params from /transactions-pool request type PoolTxsFilters struct { TokenID *uint `form:"tokenId"` diff --git a/api/state_test.go b/api/state_test.go index 303c6ed2f..aa92979cd 100644 --- a/api/state_test.go +++ b/api/state_test.go @@ -4,8 +4,8 @@ import ( "math/big" "testing" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -203,12 +203,10 @@ func TestGetState(t *testing.T) { // Network assert.Equal(t, lastBlock.Num, status.Network.LastEthBlock) assert.Equal(t, lastBlock.Num, status.Network.LastSyncBlock) - // TODO: assert all the batch, not just the batch num assert.Equal(t, lastBatchNum, status.Network.LastBatch.BatchNum) assert.Equal(t, currentSlotNum, status.Network.CurrentSlot) assertNextForgers(t, tc.nextForgers, status.Network.NextForgers) // Metrics - // TODO: perform real asserts (not just greater than 0) assert.Greater(t, status.Metrics.TransactionsPerBatch, float64(0)) assert.Greater(t, status.Metrics.BatchFrequency, float64(0)) assert.Greater(t, status.Metrics.TransactionsPerSecond, float64(0)) @@ -216,7 +214,6 @@ func TestGetState(t *testing.T) { assert.Greater(t, status.Metrics.Wallets, int64(0)) assert.Greater(t, status.Metrics.AvgTransactionFee, float64(0)) // Recommended fee - // TODO: perform real asserts (not just greater than 0) assert.Greater(t, status.RecommendedFee.ExistingAccount, float64(0)) assert.Equal(t, status.RecommendedFee.CreatesAccount, status.RecommendedFee.ExistingAccount* diff --git a/api/stateapiupdater/stateapiupdater.go b/api/stateapiupdater/stateapiupdater.go index d64a1cd54..495ed67ca 100644 --- a/api/stateapiupdater/stateapiupdater.go +++ b/api/stateapiupdater/stateapiupdater.go @@ -31,8 +31,8 @@ type Updater struct { // RecommendedFeePolicy describes how the recommended fee is calculated type RecommendedFeePolicy struct { - PolicyType RecommendedFeePolicyType `validate:"required"` - StaticValue float64 + PolicyType RecommendedFeePolicyType `validate:"required" env:"HEZNODE_RECOMMENDEDFEEPOLICY_POLICYTYPE"` + StaticValue float64 `env:"HEZNODE_RECOMMENDEDFEEPOLICY_STATICVALUE"` } // RecommendedFeePolicyType describes the different available recommended fee strategies diff --git a/api/swagger.yml b/api/swagger.yml index 093befc3f..6d996ba6a 100644 --- a/api/swagger.yml +++ b/api/swagger.yml @@ -32,9 +32,10 @@ info: ### Signatures - There are two endpoints that require signatures: + There are three endpoints that require signatures: * POST /account-creation-authorization: signed using an Ethereum key. * POST /transactions-pool: signed using BJJ key. + * PUT /transactions-pool: signed using BJJ key. It's recommended to use the official SDKs for [Go](https://github.com/hermeznetwork/hermez-go-sdk), [JS](https://github.com/hermeznetwork/hermezjs) and [Flutter](https://github.com/hermeznetwork/hermez_flutter_sdk). If for some reason the previous options doesn't suit your usecase, you can implement the signatures following the spec for [account creation authorizations](https://docs.hermez.io/#/developers/protocol/hermez-protocol/protocol?id=regular-rollup-account) and [L2 transactions](https://docs.hermez.io/#/developers/protocol/hermez-protocol/protocol?id=l2) @@ -630,6 +631,46 @@ paths: schema: $ref: '#/components/schemas/Error500' '/transactions-pool/{id}': + put: + tags: + - Coordinator + summary: Update an L2 transaction in the coordinator's pool. Only regular transactions can be updated. Fields, that can be updated - toAccountIndex, toHezEthereumAddress, toBjj, maxNumBatch, signature, type + description: >- + Update L2 transaction + operationId: putTx + parameters: + - name: id + in: path + description: Transaction identifier. + required: true + schema: + $ref: '#/components/schemas/TransactionId' + requestBody: + description: Signed transaction + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PostPoolL2Transaction' + responses: + '200': + description: Successful operation. + content: + application/json: + schema: + $ref: '#/components/schemas/TransactionId' + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '500': + description: Internal server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' get: tags: - Coordinator @@ -637,6 +678,7 @@ paths: description: >- Get transaction from the pool by its ID. This endpoint is specially useful for tracking the status of a transaction that may not be forged yet. Only transactions from the pool will be returned. + There are other options to filter transactions using query string parameters. Please check for more details below. Note that the transaction pool is different for each coordinator and therefore only a coordinator that has received a specific transaction will be able to provide information about that transaction. operationId: getPoolTx @@ -672,6 +714,54 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + '/transactions-pool/accounts/{idx}/nonces/{nonce}': + put: + tags: + - Coordinator + summary: Update transaction by from account idx and nonce. + description: >- + Updates regular transactions by account idx and nonce. This endpoint is useful, when user want to update fee or amount, that was sent in the transaction, + but user can't use regular update transaction request, bcs transaction id is also changing. Delete previous transaction and inserts new one + operationId: updateTxByIdxAndNonce + parameters: + - name: idx + in: path + description: From account idx + required: true + schema: + $ref: '#/components/schemas/AccountIndex' + - name: nonce + in: path + description: trasnaction nonce + required: true + schema: + $ref: '#/components/schemas/Nonce' + requestBody: + description: Signed transaction + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PostPoolL2Transaction' + responses: + '200': + description: Successful operation. + content: + application/json: + schema: + $ref: '#/components/schemas/TransactionId' + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '500': + description: Internal server error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' '/transactions-history': get: tags: @@ -811,9 +901,10 @@ paths: get: tags: - Explorer - summary: Get details and status of a historical transaction. + summary: Get details and status of a specific historical transaction. description: >- - Get transaction by its ID. This endpoint will return all the different types of transactions except those that are still in the pool of any coordinator. + Get transaction by its ID. There are other options to filter transactions using query string parameters. Please check for more details below. + This endpoint will return all the different types of transactions except those that are still in the pool of any coordinator. operationId: getHistoryTx parameters: - name: id @@ -1649,6 +1740,11 @@ components: $ref: '#/components/schemas/Nonce' state: $ref: '#/components/schemas/PoolL2TransactionState' + batchNum: + type: integer + description: Batch num for transaction. + example: 0 + nullable: true maxNumBatch: type: integer description: Batch until the transaction can be forged. If the transaction isn't forged before batch `maxNumBatch`, it will never be forged. 0 means no restriction. diff --git a/api/txshistory_test.go b/api/txshistory_test.go index d23109d8f..5a2e07a81 100644 --- a/api/txshistory_test.go +++ b/api/txshistory_test.go @@ -8,8 +8,9 @@ import ( "testing" "time" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/hermeznetwork/hermez-node/test" @@ -31,7 +32,7 @@ type testL1Info struct { type testL2Info struct { Fee common.FeeSelector `json:"fee"` HistoricFeeUSD *float64 `json:"historicFeeUSD"` - Nonce common.Nonce `json:"nonce"` + Nonce nonce.Nonce `json:"nonce"` } type testTx struct { @@ -369,7 +370,7 @@ func TestGetHistoryTxs(t *testing.T) { continue } } - toQueryAccount, err := common.StringToIdx((tc.txs[i].ToIdx), "") + toQueryAccount, err := common.StringToIdx(tc.txs[i].ToIdx, "") assert.NoError(t, err) if *toQueryAccount.AccountIndex == *queryAccount.AccountIndex { idxTxs = append(idxTxs, tc.txs[i]) diff --git a/api/txspool.go b/api/txspool.go index 4aa511cbe..c636f99e2 100644 --- a/api/txspool.go +++ b/api/txspool.go @@ -10,7 +10,7 @@ import ( "github.com/gin-gonic/gin" "github.com/hermeznetwork/hermez-node/api/parsers" "github.com/hermeznetwork/hermez-node/common" - "github.com/hermeznetwork/hermez-node/db/l2db" + "github.com/hermeznetwork/hermez-node/common/apitypes" "github.com/hermeznetwork/tracerr" ) @@ -34,7 +34,39 @@ func (a *API) postPoolTx(c *gin.Context) { return } // Check that tx is valid - if err := a.verifyPoolL2Tx(receivedTx); err != nil { + if apiErr := a.verifyPoolL2Tx(receivedTx); apiErr != nil { + retBadReq(apiErr, c) + return + } + receivedTx.ClientIP = c.ClientIP() + receivedTx.Info = "" + // Insert to DB + if err := a.l2.AddTxAPI(&receivedTx); err != nil { + if strings.Contains(err.Error(), "< minFeeUSD") { + retBadReq(&apiError{ + Err: err, + Code: ErrFeeTooLowCode, + Type: ErrFeeTooLowType, + }, c) + return + } else if strings.Contains(err.Error(), "> maxFeeUSD") { + retBadReq(&apiError{ + Err: err, + Code: ErrFeeTooBigCode, + Type: ErrFeeTooBigType, + }, c) + return + } + retSQLErr(err, c) + return + } + // Return TxID + c.JSON(http.StatusOK, receivedTx.TxID.String()) +} + +func (a *API) putPoolTxByIdxAndNonce(c *gin.Context) { + idx, nonce, err := parsers.ParsePoolTxUpdateByIdxAndNonceFilter(c) + if err != nil { retBadReq(&apiError{ Err: err, Code: ErrParamValidationFailedCode, @@ -42,10 +74,42 @@ func (a *API) postPoolTx(c *gin.Context) { }, c) return } + var receivedTx common.PoolL2Tx + if err = c.ShouldBindJSON(&receivedTx); err != nil { + retBadReq(&apiError{ + Err: err, + Code: ErrParamValidationFailedCode, + Type: ErrParamValidationFailedType, + }, c) + return + } + + if isAtomic(receivedTx) { + retBadReq(&apiError{ + Err: errors.New(ErrNotAtomicTxsInPostPoolTx), + Code: ErrNotAtomicTxsInPostPoolTxCode, + Type: ErrNotAtomicTxsInPostPoolTxType, + }, c) + return + } + if receivedTx.State != common.PoolL2TxStatePending || receivedTx.FromIdx != idx || receivedTx.Nonce != nonce { + retBadReq(&apiError{ + Err: errors.New("tx state is not pend or invl or fromIdx or nonce in request body not equal request uri params"), + Code: ErrParamValidationFailedCode, + Type: ErrParamValidationFailedType, + }, c) + return + } + + if apiErr := a.verifyPoolL2Tx(receivedTx); apiErr != nil { + retBadReq(apiErr, c) + return + } + receivedTx.ClientIP = c.ClientIP() receivedTx.Info = "" - // Insert to DB - if err := a.l2.AddTxAPI(&receivedTx); err != nil { + + if err := a.l2.UpdateTxByIdxAndNonceAPI(idx, nonce, &receivedTx); err != nil { if strings.Contains(err.Error(), "< minFeeUSD") { retBadReq(&apiError{ Err: err, @@ -64,6 +128,72 @@ func (a *API) postPoolTx(c *gin.Context) { retSQLErr(err, c) return } + + c.JSON(http.StatusOK, receivedTx.TxID.String()) +} + +func (a *API) putPoolTx(c *gin.Context) { + txID, err := parsers.ParsePoolTxFilter(c) + if err != nil { + retBadReq(&apiError{ + Err: err, + Code: ErrParamValidationFailedCode, + Type: ErrParamValidationFailedType, + }, c) + return + } + var receivedTx common.PoolL2Tx + if err := c.ShouldBindJSON(&receivedTx); err != nil { + retBadReq(&apiError{ + Err: err, + Code: ErrParamValidationFailedCode, + Type: ErrParamValidationFailedType, + }, c) + return + } + + receivedTx.TxID = txID + + if isAtomic(receivedTx) { + retBadReq(&apiError{ + Err: errors.New(ErrNotAtomicTxsInPostPoolTx), + Code: ErrNotAtomicTxsInPostPoolTxCode, + Type: ErrNotAtomicTxsInPostPoolTxType, + }, c) + return + } + if apiErr := a.verifyPoolL2Tx(receivedTx); apiErr != nil { + retBadReq(apiErr, c) + return + } + receivedTx.ClientIP = c.ClientIP() + receivedTx.Info = "" + + if err := a.l2.UpdateTxAPI(&receivedTx); err != nil { + if strings.Contains(err.Error(), "< minFeeUSD") { + retBadReq(&apiError{ + Err: err, + Code: ErrFeeTooLowCode, + Type: ErrFeeTooLowType, + }, c) + return + } else if strings.Contains(err.Error(), "> maxFeeUSD") { + retBadReq(&apiError{ + Err: err, + Code: ErrFeeTooBigCode, + Type: ErrFeeTooBigType, + }, c) + return + } else if strings.Contains(err.Error(), "nothing to update") { + retBadReq(&apiError{ + Err: err, + Code: ErrNothingToUpdateCode, + Type: ErrNothingToUpdateType, + }, c) + } + retSQLErr(err, c) + return + } // Return TxID c.JSON(http.StatusOK, receivedTx.TxID.String()) } @@ -108,8 +238,8 @@ func (a *API) getPoolTxs(c *gin.Context) { // Build successful response type txsResponse struct { - Txs []l2db.PoolTxAPI `json:"transactions"` - PendingItems uint64 `json:"pendingItems"` + Txs []apitypes.TxL2 `json:"transactions"` + PendingItems uint64 `json:"pendingItems"` } c.JSON(http.StatusOK, &txsResponse{ Txs: txs, @@ -117,7 +247,7 @@ func (a *API) getPoolTxs(c *gin.Context) { }) } -func (a *API) verifyPoolL2Tx(tx common.PoolL2Tx) error { +func (a *API) verifyPoolL2Tx(tx common.PoolL2Tx) *apiError { // Check type and id _, err := common.NewPoolL2Tx(&tx) if err != nil { diff --git a/api/txspool_test.go b/api/txspool_test.go index f7980f2e3..440a5cc45 100644 --- a/api/txspool_test.go +++ b/api/txspool_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/iden3/go-iden3-crypto/babyjub" @@ -32,7 +33,7 @@ type testPoolTxReceive struct { ToBJJ *string `json:"toBjj"` Amount string `json:"amount"` Fee common.FeeSelector `json:"fee"` - Nonce common.Nonce `json:"nonce"` + Nonce nonce.Nonce `json:"nonce"` State common.PoolL2TxState `json:"state"` Signature babyjub.SignatureComp `json:"signature"` RqFromIdx *string `json:"requestFromAccountIndex"` @@ -42,7 +43,7 @@ type testPoolTxReceive struct { RqTokenID *common.TokenID `json:"requestTokenId"` RqAmount *string `json:"requestAmount"` RqFee *common.FeeSelector `json:"requestFee"` - RqNonce *common.Nonce `json:"requestNonce"` + RqNonce *nonce.Nonce `json:"requestNonce"` BatchNum *common.BatchNum `json:"batchNum"` Timestamp time.Time `json:"timestamp"` Token historydb.TokenWithUSD `json:"token"` @@ -193,14 +194,6 @@ func TestPoolTxs(t *testing.T) { jsonTxReader = bytes.NewReader(jsonTxBytes) err = doBadReq("POST", endpoint, jsonTxReader, 400) require.NoError(t, err) - // Wrong rq - badTx = tc.poolTxsToSend[0] - badTx.RqFromIdx = 30 - jsonTxBytes, err = json.Marshal(badTx) - require.NoError(t, err) - jsonTxReader = bytes.NewReader(jsonTxBytes) - err = doBadReq("POST", endpoint, jsonTxReader, 409) - require.NoError(t, err) // Wrong maxNumBatch badTx = tc.poolTxsToSend[0] badTx.MaxNumBatch = 30 @@ -420,6 +413,195 @@ func TestPoolTxs(t *testing.T) { ) assertPoolTx(t, tx, fetchedTx) } + // PUT + // Change toEthAddr + tx := tc.poolTxsToSend[1] + txToReceive := tc.poolTxsToReceive[1] + fetchedTx := testPoolTxReceive{} + require.NoError(t, doGoodReq( + "GET", + endpoint+tx.TxID.String(), + nil, &fetchedTx)) + assertPoolTx(t, txToReceive, fetchedTx) + + tx.ToIdx = common.Idx(0) + tx.ToBJJ = common.EmptyBJJComp + ethAddrStr := "hez:0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf" + ethAddr, err := common.HezStringToEthAddr(ethAddrStr, "ethAddr") + require.NoError(t, err) + tx.ToEthAddr = *ethAddr + signStr := "5a4627d4bfc9414cee1454c7788b03101a938e880328dcd8ecaf4ed97c530a1f9a7a4cc593216280033639d1b110b0e7fea7bcd9b59b8a6c7945ce3f00879a01" + sign := babyjub.SignatureComp{} + err = sign.UnmarshalText([]byte(signStr)) + require.NoError(t, err) + tx.Signature = sign + jsonTxBytes, err = json.Marshal(tx) + require.NoError(t, err) + jsonTxReader = bytes.NewReader(jsonTxBytes) + require.NoError(t, doGoodReq( + "PUT", + endpoint+tx.TxID.String(), + jsonTxReader, &fetchedTxID)) + + assert.Equal(t, tx.TxID, fetchedTxID) + fetchedTx = testPoolTxReceive{} + require.NoError(t, doGoodReq( + "GET", + endpoint+tx.TxID.String(), + nil, &fetchedTx)) + assert.Equal(t, ethAddrStr, *fetchedTx.ToEthAddr) + + // change type from transfer to transferToEthAddr + tx = tc.poolTxsToSend[0] + txToReceive = tc.poolTxsToReceive[0] + fetchedTx = testPoolTxReceive{} + require.NoError(t, doGoodReq( + "GET", + endpoint+tx.TxID.String(), + nil, &fetchedTx)) + assertPoolTx(t, txToReceive, fetchedTx) + + tx.Type = common.TxTypeTransferToEthAddr + tx.ToIdx = common.Idx(0) + ethAddrStr = "hez:0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF" + ethAddr, err = common.HezStringToEthAddr(ethAddrStr, "ethAddr") + require.NoError(t, err) + tx.ToEthAddr = *ethAddr + signStr = "ea16b8d0ebe1680700faad197f30232fe3d13b57b9d96e2037c0fb3e8597d7afd99ea7b6171c6b1dab6707b714845d20661b23b4a401efb866646e4e36370401" + sign = babyjub.SignatureComp{} + err = sign.UnmarshalText([]byte(signStr)) + require.NoError(t, err) + tx.Signature = sign + jsonTxBytes, err = json.Marshal(tx) + require.NoError(t, err) + jsonTxReader = bytes.NewReader(jsonTxBytes) + require.NoError(t, doGoodReq( + "PUT", + endpoint+tx.TxID.String(), + jsonTxReader, &fetchedTxID)) + assert.Equal(t, tx.TxID, fetchedTxID) + fetchedTx = testPoolTxReceive{} + require.NoError(t, doGoodReq( + "GET", + endpoint+tx.TxID.String(), + nil, &fetchedTx)) + assert.Equal(t, ethAddrStr, *fetchedTx.ToEthAddr) + assert.Equal(t, "hez:ETH:0", *fetchedTx.ToIdx) + + // change type from transferToEthAddr to transfer back + tx = tc.poolTxsToSend[0] + fetchedTx = testPoolTxReceive{} + require.NoError(t, doGoodReq( + "GET", + endpoint+tx.TxID.String(), + nil, &fetchedTx)) + + tx.Type = common.TxTypeTransfer + tx.ToIdx = common.Idx(262) + tx.ToEthAddr = common.EmptyAddr + signStr = "9f76205e4c69776f8174db8e0961aa94d37ceb5c1de06a95cca80821ee093d885812c3f7cfad61e00027ee56de0d3f573ff6cc88a13780abd12e5f61a622f103" + sign = babyjub.SignatureComp{} + err = sign.UnmarshalText([]byte(signStr)) + require.NoError(t, err) + tx.Signature = sign + jsonTxBytes, err = json.Marshal(tx) + require.NoError(t, err) + jsonTxReader = bytes.NewReader(jsonTxBytes) + require.NoError(t, doGoodReq( + "PUT", + endpoint+tx.TxID.String(), + jsonTxReader, &fetchedTxID)) + + assert.Equal(t, tx.TxID, fetchedTxID) + fetchedTx = testPoolTxReceive{} + require.NoError(t, doGoodReq( + "GET", + endpoint+tx.TxID.String(), + nil, &fetchedTx)) + assert.Equal(t, "hez:0x0000000000000000000000000000000000000000", *fetchedTx.ToEthAddr) + assert.Equal(t, "hez:ETH:262", *fetchedTx.ToIdx) + + // test positive case + tx = tc.poolTxsToSend[0] + fetchedTx = testPoolTxReceive{} + require.NoError(t, doGoodReq( + "GET", + endpoint+tx.TxID.String(), + nil, &fetchedTx)) + prevTxID := tx.TxID + tx.TxID, err = common.NewTxIDFromString("0x0270c069af9f5ae54b837ee12a404d026b583bcfa4b2380d48c7156c3bb5a8b30a") + assert.NoError(t, err) + signStr = "a0ddfec6c15c657f06e99a41d7a0bae0fc31f73799028a615a69214889c0831bb304ac547ca1e5a1b5ac1c7b45bbd95bbe4a17b10a46e069ed8c5ac154434a00" + sign = babyjub.SignatureComp{} + err = sign.UnmarshalText([]byte(signStr)) + require.NoError(t, err) + tx.Signature = sign + tx.Amount = big.NewInt(110) + jsonTxBytes, err = json.Marshal(tx) + require.NoError(t, err) + jsonTxReader = bytes.NewReader(jsonTxBytes) + require.NoError(t, doGoodReq( + "PUT", + endpoint+"accounts/"+idx+"/nonces/"+tx.Nonce.BigInt().String(), + jsonTxReader, &fetchedTxID)) + assert.Equal(t, tx.TxID, fetchedTxID) + require.NoError(t, doGoodReq( + "GET", + endpoint+tx.TxID.String(), + nil, &fetchedTx)) + assert.Equal(t, tx.Amount.String(), fetchedTx.Amount) + err = doBadReq("GET", endpoint+prevTxID.String(), nil, 404) + require.NoError(t, err) + + // test not existing tx + oldTx := tx + oldIdx := idx + idx = "hez:ETH:265" + tx.FromIdx = common.Idx(265) + tx.Nonce = nonce.Nonce(0) + tx.TxID, err = common.NewTxIDFromString("0x0293ed7291a26bc0ccd01b696f95c8618690d04d028d2af04087831f874235b217") + require.NoError(t, err) + signStr = "e14165987818b09194dc0eb348bf0d30250bac6005d8a4c3d43f8021c6bee3937781ea69ced553cbbdacd09992f88f6a41bf8e17e0341aa2e53d0bfa80d03b05" + sign = babyjub.SignatureComp{} + err = sign.UnmarshalText([]byte(signStr)) + require.NoError(t, err) + tx.Signature = sign + jsonTxBytes, err = json.Marshal(tx) + require.NoError(t, err) + jsonTxReader = bytes.NewReader(jsonTxBytes) + require.NoError(t, doBadReq( + "PUT", + endpoint+"accounts/"+idx+"/nonces/"+tx.Nonce.BigInt().String(), + jsonTxReader, 404)) + tx = oldTx + idx = oldIdx + + // test wrong nonce + oldNonce := tx.Nonce + tx.Nonce = nonce.Nonce(5) + jsonTxBytes, err = json.Marshal(tx) + require.NoError(t, err) + jsonTxReader = bytes.NewReader(jsonTxBytes) + + require.NoError(t, doBadReq( + "PUT", + endpoint+"accounts/"+idx+"/nonces/"+oldNonce.BigInt().String(), + jsonTxReader, 400)) + tx.Nonce = oldNonce + + // test wrong account idx + oldAccountIdx := tx.FromIdx + tx.FromIdx = common.Idx(250) + jsonTxBytes, err = json.Marshal(tx) + require.NoError(t, err) + jsonTxReader = bytes.NewReader(jsonTxBytes) + + require.NoError(t, doBadReq( + "PUT", + endpoint+"accounts/"+idx+"/nonces/"+oldNonce.BigInt().String(), + jsonTxReader, 400)) + tx.FromIdx = oldAccountIdx + // 400, due invalid TxID err = doBadReq("GET", endpoint+"0xG2241b6f2b1dd772dba391f4a1a3407c7c21f598d86e2585a14e616fb4a255f823", nil, 400) require.NoError(t, err) diff --git a/cmd/heznode/cfg.builder.toml b/cmd/heznode/cfg.builder.toml index cde577ee3..5773a58b5 100644 --- a/cmd/heznode/cfg.builder.toml +++ b/cmd/heznode/cfg.builder.toml @@ -1,164 +1,205 @@ -[API] -Address = "localhost:8086" -Explorer = true -UpdateMetricsInterval = "10s" -UpdateRecommendedFeeInterval = "10s" -MaxSQLConnections = 100 -SQLConnectionTimeout = "2s" - -[PriceUpdater] -Interval = "5s" -Priority = "bitfinexV2,CoinGeckoV3" -Statictokens="3=1.31,4=1.01" # =,= - -[PriceUpdater.Fiat] -APIKey="" -URL="https://api.exchangeratesapi.io/v1/" -BaseCurrency="USD" -Currencies="CNY,EUR,JPY,GBP" - -[[PriceUpdater.Provider]] -Provider = "bitfinexV2" -BASEURL = "https://api-pub.bitfinex.com/v2/" -URL = "ticker/t" -URLExtraParams = "USD" -# token order ETH,HEZ,USDT,USDC,DAI,WBTC,WETH,XAUt,UNI,SUSHI,COMP,BAL,AAVE,YFI,LINK. Order based in tokenId. -# Available update methods: -# - ignore method don't update the price leave it as it is on the DB. Type ignore or leave the field empty -# - static method is performed writting the price in Statictokens. -# Example: Symbols = "0=ETH,1=HEZ,2=ignore,4=DAI,5=WBT,6=static,7=XAUT:,8=UNI,9=SUSHI:,10=COMP:,11=,12=AAVE:,13=YFI,14=LINK:" -Symbols = "0=ETH,2=UST,8=ignore,9=SUSHI:,5=WBT,14=LINK:,12=AAVE:,7=XAUT:,10=COMP:,6=ETH" - -[[PriceUpdater.Provider]] -Provider = "CoinGeckoV3" -BASEURL = "https://api.coingecko.com/api/v3/" -URL = "simple/token_price/ethereum?contract_addresses=" -URLExtraParams = "&vs_currencies=usd" -# token order ETH,HEZ,USDT,USDC,DAI,WBTC,WETH,XAUt,UNI,SUSHI,COMP,BAL,AAVE,YFI,LINK. Order based in tokenId. -# Available update methods: -# - ignore method don't update the price leave it as it is on the DB. Type ignore or leave the field empty -# - static method is performed writting the price in Statictokens. -# Example: Addresses="0=0x00,1=0x12,2=0x12,4=0x12,5=0x12,6=,7=0x12,8=,9=0x12,10=0x12,11=ignore,12=0x12,13=0x12,14=0x12" -Addresses="0=0x0000000000000000000000000000000000000000,2=0xdac17f958d2ee523a2206206994597c13d831ec7,8=ignore" - -[Debug] -APIAddress = "0.0.0.0:12345" -MeddlerLogs = true -GinDebugMode = true - -[StateDB] -Path = "/tmp/iden3-test/hermez/statedb" -Keep = 256 +#[API] +### Url and port where the API will listen +#Address = "0.0.0.0:8086" +### Enables the Explorer API endpoints +#Explorer = true +### Interval between updates of the API metrics +#UpdateMetricsInterval = "10s" +### Interval between updates of the recommended fees +#UpdateRecommendedFeeInterval = "10s" +### Maximum concurrent connections allowed between API and SQL +#MaxSQLConnections = 100 +### Maximum amount of time that an API request can wait to establish a SQL connection +#SQLConnectionTimeout = "2s" + +#[Debug] +### If it is set, the debug api will listen in this address and port +#APIAddress = "0.0.0.0:12345" +### Enables meddler debug mode, where unused columns and struct fields will be logged +#MeddlerLogs = true +### Sets the web framework Gin-Gonic to run in debug mode +#GinDebugMode = false + +#[StateDB] +### Path where the synchronizer StateDB is stored +#Path = "/var/hermez/statedb" +### Number of checkpoints to keep +#Keep = 256 [PostgreSQL] +## Port of the PostgreSQL write server PortWrite = 5432 +## Host of the PostgreSQL write server HostWrite = "localhost" +## User of the PostgreSQL write server UserWrite = "hermez" +## Password of the PostgreSQL write server PasswordWrite = "yourpasswordhere" +## Name of the PostgreSQL write server database NameWrite = "hermez" +## Port of the PostgreSQL read server. If it is not set, the hermez node will use the postgresql write server configuration # PortRead = 5432 +## Host of the PostgreSQL read server. If it is not set, the hermez node will use the postgresql write server configuration # HostRead = "localhost" +## User of the PostgreSQL read server. If it is not set, the hermez node will use the postgresql write server configuration # UserRead = "hermez" +## Password of the PostgreSQL read server. If it is not set, the hermez node will use the postgresql write server configuration # PasswordRead = "yourpasswordhere" +## Name of the PostgreSQL read server database. If it is not set, the hermez node will use the postgresql write server configuration # NameRead = "hermez" [Web3] +## Url of the web3 ethereum-node RPC server. Only geth is officially supported URL = "http://localhost:8545" -[Synchronizer] -SyncLoopInterval = "1s" -StatsUpdateBlockNumDiffThreshold = 100 -StatsUpdateFrequencyDivider = 100 +#[Synchronizer] +### Interval between attempts to synchronize a new block from an ethereum node +#SyncLoopInterval = "1s" +### Threshold of a number of Ethereum blocks left to synchronize, such that if there are more blocks to sync than the defined value synchronizer can aggressively skip calling UpdateEth to save network bandwidth and time. After reaching the threshold UpdateEth is called on each block. This value only affects the reported % of synchronization of blocks and batches, nothing else. +#StatsUpdateBlockNumDiffThreshold = 100 +### While having more blocks to sync than updateEthBlockNumThreshold, UpdateEth will be called once in a defined number of blocks. This value only affects the reported % of synchronization of blocks and batches, nothing else +#StatsUpdateFrequencyDivider = 100 [SmartContracts] -Rollup = "0x8EEaea23686c319133a7cC110b840d1591d9AeE0" +## Smart contract address of the rollup Hermez.sol +Rollup = "0xA68D85dF56E733A06443306A095646317B5Fa633" [Coordinator] -ForgerAddress = "0x05c23b938a85ab26A36E6314a0D02080E9ca6BeD" # Non-Boot Coordinator -# ForgerAddressPrivateKey = "0x30f5fddb34cd4166adb2c6003fa6b18f380fd2341376be42cf1c7937004ac7a3" -# ForgerAddress = "0xb4124ceb3451635dacedd11767f004d8a28c6ee7" # Boot Coordinator -# ForgerAddressPrivateKey = "0xa8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563" -MinimumForgeAddressBalance = "0" -ConfirmBlocks = 10 -L1BatchTimeoutPerc = 0.6 -StartSlotBlocksDelay = 2 -ScheduleBatchBlocksAheadCheck = 3 -SendBatchBlocksMarginCheck = 1 -ProofServerPollInterval = "1s" -ForgeRetryInterval = "500ms" -SyncRetryInterval = "1s" -ForgeDelay = "10s" -ForgeNoTxsDelay = "0s" -PurgeByExtDelInterval = "1m" -MustForgeAtSlotDeadline = true -IgnoreSlotCommitment = false +## Ethereum address that the coordinator is using to forge batches +ForgerAddress = "0x05c23b938a85ab26A36E6314a0D02080E9ca6BeD" +### Minimum balance the forger address needs to start the coordinator in wei. If It is set to 0, the coordinator will not check the balance +#MinimumForgeAddressBalance = "0" +### Number of confirmation blocks to be sure that the tx has been mined correctly +#ConfirmBlocks = 5 +### Portion of the range before the L1Batch timeout that will trigger a schedule to forge an L1Batch +#L1BatchTimeoutPerc = 0.00001 +### Number of delay blocks to wait before starting the pipeline when a slot in which the coordinator can forge is reached +#StartSlotBlocksDelay = 0 +### Number of blocks ahead used to decide when to stop scheduling new batches +#ScheduleBatchBlocksAheadCheck = 0 +### Number of marging blocks used to decide when to stop sending batches to the smart contract +#SendBatchBlocksMarginCheck = 0 +### Interval between calls to the ProofServer to check the status +#ProofServerPollInterval = "1s" +### Interval between forge retries after an error +#ForgeRetryInterval = "10s" +### Interval between calls to the main handler of a synced block after an error +#SyncRetryInterval = "1s" +#Delay after which a batch is forged if the slot is already committed. If It is set to "0s", the coordinator will continuously forge at the maximum rate +#ForgeDelay = "600s" +### Delay after a forged batch if there are no txs to forge. If It is set to 0s, the coordinator will continuously forge even if the batches are empty +#ForgeNoTxsDelay = "86400s" +### Interval between calls to the PurgeByExternalDelete function of the l2db which deletes pending txs externally marked by the column `external_delete` +#PurgeByExtDelInterval = "1m" +### Enables the coordinator to forge in slots if the empty slots reach the slot deadline +#MustForgeAtSlotDeadline = true +### It 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`. +#IgnoreSlotCommitment = true +### This parameter 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 = false [Coordinator.FeeAccount] +## Ethereum address of the account that will receive the fees Address = "0x56232B1c5B10038125Bc7345664B4AFD745bcF8E" -# PrivateKey = "0x3a9270c020e169097808da4b02e8d9100be0f8a38cfad3dcfc0b398076381fdd" +## BJJ is the baby jub jub public key of the account that will receive the fees BJJ = "0x130c5c7f294792559f469220274f3d3b2dca6e89f4c5ec88d3a08bf73262171b" -# BJJPrivateKey = "0xb556862fb60e7cf4c0a8a7f44baf2ab06a4c90ac39decc4eef363b6142d07a34" -[Coordinator.L2DB] -SafetyPeriod = 10 -MaxTxs = 512 -MinFeeUSD = 0.0 -MaxFeeUSD = 50.0 -TTL = "24h" -PurgeBatchDelay = 10 -InvalidateBatchDelay = 20 -PurgeBlockDelay = 10 -InvalidateBlockDelay = 20 - -[Coordinator.TxSelector] -Path = "/tmp/iden3-test/hermez/txselector" - -[Coordinator.BatchBuilder] -Path = "/tmp/iden3-test/hermez/batchbuilder" - -[[Coordinator.ServerProofs]] -URL = "http://localhost:3000/api" +#[Coordinator.L2DB] +### Number of batches after which non-pending L2Txs are deleted from the pool +#SafetyPeriod = 10 +### Maximum number of pending L2Txs that can be stored in the pool +#MaxTxs = 1000000 +### Minimum fee in USD that a tx must pay in order to be accepted into the pool +#MinFeeUSD = 0.10 +### Maximum fee in USD that a tx must pay in order to be accepted into the pool +#MaxFeeUSD = 10.00 +### Time To Live for L2Txs in the pool. L2Txs older than TTL will be deleted. +#TTL = "24h" +### Delay between batches to purge outdated transactions. Outdated L2Txs are those that have been forged or marked as invalid for longer than the SafetyPeriod and pending L2Txs that have been in the pool for longer than TTL once there are MaxTxs +#PurgeBatchDelay = 10 +### Delay between batches to mark invalid transactions due to nonce lower than the account nonce +#InvalidateBatchDelay = 20 +### Delay between blocks to purge outdated transactions. Outdated L2Txs are those that have been forged or marked as invalid for longer than the SafetyPeriod and pending L2Txs that have been in the pool for longer than TTL once there are MaxTxs. +#PurgeBlockDelay = 10 +### Delay between blocks to mark invalid transactions due to nonce lower than the account nonce +#InvalidateBlockDelay = 20 + +#[Coordinator.TxSelector] +### Path where the TxSelector StateDB is stored +#Path = "/var/hermez/txselector" + +#[Coordinator.BatchBuilder] +### Path where the BatchBuilder StateDB is stored +#Path = "/var/hermez/batchbuilder" + +[Coordinator.ServerProofs] +## Server proof API URLs +URLs = ["http://localhost:3000"] [Coordinator.Circuit] -MaxTx = 512 +## Maximum number of txs supported by the circuit +MaxTx = 2048 +## Maximum number of merkle tree levels supported by the circuit NLevels = 32 -[Coordinator.EthClient] -CheckLoopInterval = "500ms" -Attempts = 4 -AttemptsDelay = "500ms" -TxResendTimeout = "2m" -NoReuseNonce = false -MaxGasPrice = 2000 -MinGasPrice = 5 -GasPriceIncPerc = 10 +#[Coordinator.EthClient] +### Interval between receipt checks of ethereum transactions in the TxManager +#CheckLoopInterval = "500ms" +### Number of attempts to do an eth client RPC call before giving up +#Attempts = 4 +### Delay between attempts do do an eth client RPC call +#AttemptsDelay = "500ms" +### Timeout after which a non-mined ethereum transaction will be resent (reusing the nonce) with a newly calculated gas price +#TxResendTimeout = "2m" +### Disables reusing nonces of pending transactions for new replacement transactions +#NoReuseNonce = false +### Maximum gas price allowed for ethereum transactions in gwei +#MaxGasPrice = 500 +### Minimum gas price allowed for ethereum transactions in gwei +#MinGasPrice = 5 +### Percentage increased of gas price set in an ethereum transaction from the suggested gas price by the ethereum node +#GasPriceIncPerc = 5 [Coordinator.EthClient.Keystore] -Path = "/tmp/iden3-test/hermez/ethkeystore" +### Path where the keystore is stored +#Path = "/var/hermez/ethkeystore" +## Password used to decrypt the keys in the keystore Password = "yourpasswordhere" -[Coordinator.EthClient.ForgeBatchGasCost] -Fixed = 600000 -L1UserTx = 15000 -L1CoordTx = 8000 -L2Tx = 250 - -[Coordinator.API] -Coordinator = true - -[Coordinator.Debug] -BatchPath = "/tmp/iden3-test/hermez/batchesdebug" -LightScrypt = true -# RollupVerifierIndex = 0 - -[Coordinator.Etherscan] -URL = "https://api.etherscan.io" -APIKey = "" - -[RecommendedFeePolicy] -# Strategy used to calculate the recommended fee that the API will expose. -# Available options: -# - Static: always return the same value (StaticValue) in USD -# - AvgLastHour: calculate using the average fee of the forged transactions during the last hour -PolicyType = "Static" -StaticValue = 0.99 \ No newline at end of file +#[Coordinator.EthClient.ForgeBatchGasCost] +### Gas needed to forge an empty batch +#Fixed = 900000 +### Gas needed per L1 tx +#L1UserTx = 15000 +### Gas needed for a coordinator L1 tx +#L1CoordTx = 7000 +### Gas needed for an L2 tx +#L2Tx = 600 + +#[Coordinator.API] +### Enables coordinator API endpoints +#Coordinator = true + +#[Coordinator.Debug] +### If this parameter is set, specifies the path where batchInfo is stored in JSON in every step/update of the pipeline +#BatchPath = "/var/hermez/batchesdebug" +### If lightScrypt is set, uses light parameters for the ethereum keystore encryption algorithm +#LightScrypt = false +### RollupVerifierIndex is the index of the verifier to use in the Rollup smart contract. The verifier chosen by index must match with the Circuit parameters +#RollupVerifierIndex = 0 + +#[Coordinator.Etherscan] +### If this parameter is set, specifies the etherscan endpoint to get the gas estimations for that momment +#URL = "https://api.etherscan.io" +### APIKey parameter allows access to etherscan services +#APIKey = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + +#[RecommendedFeePolicy] +### Strategy used to calculate the recommended fee that the API will expose. +### Available options: +### - Static: always return the same value (StaticValue) in USD +### - AvgLastHour: calculate using the average fee of the forged transactions during the last hour +### Selects the mode. "Static" or "AvgLastHour" +#PolicyType = "Static" +### If PolicyType is "static" defines the recommended fee value +#StaticValue = 0.10 diff --git a/cmd/heznode/main.go b/cmd/heznode/main.go index 07e9a5907..7ace3be5a 100644 --- a/cmd/heznode/main.go +++ b/cmd/heznode/main.go @@ -530,7 +530,7 @@ func main() { &cli.StringFlag{ Name: flagCfg, Usage: "Node configuration `FILE`", - Required: true, + Required: false, }, } diff --git a/common/account.go b/common/account.go index 7a44b98d1..8e7d4bc3a 100644 --- a/common/account.go +++ b/common/account.go @@ -8,6 +8,7 @@ import ( "strconv" ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" "github.com/iden3/go-iden3-crypto/poseidon" @@ -17,9 +18,7 @@ import ( const ( // NLeafElems is the number of elements for a leaf NLeafElems = 4 - // maxNonceValue is the maximum value that the Account.Nonce can have - // (40 bits: maxNonceValue=2**40-1) - maxNonceValue = 0xffffffffff + // maxBalanceBytes is the maximum bytes that can use the // Account.Balance *big.Int maxBalanceBytes = 24 @@ -89,35 +88,6 @@ func IdxFromBigInt(b *big.Int) (Idx, error) { return Idx(uint64(b.Int64())), nil } -// Nonce represents the nonce value in a uint64, which has the method Bytes -// that returns a byte array of length 5 (40 bits). -type Nonce uint64 - -// Bytes returns a byte array of length 5 representing the Nonce -func (n Nonce) Bytes() ([5]byte, error) { - if n > maxNonceValue { - return [5]byte{}, tracerr.Wrap(ErrNonceOverflow) - } - var nonceBytes [8]byte - binary.BigEndian.PutUint64(nonceBytes[:], uint64(n)) - var b [5]byte - copy(b[:], nonceBytes[3:]) - return b, nil -} - -// BigInt returns the *big.Int representation of the Nonce value -func (n Nonce) BigInt() *big.Int { - return big.NewInt(int64(n)) -} - -// NonceFromBytes returns Nonce from a [5]byte -func NonceFromBytes(b [5]byte) Nonce { - var nonceBytes [8]byte - copy(nonceBytes[3:], b[:]) - nonce := binary.BigEndian.Uint64(nonceBytes[:]) - return Nonce(nonce) -} - // Account is a struct that gives information of the holdings of an address and // a specific token. Is the data structure that generates the Value stored in // the leaf of the MerkleTree @@ -127,7 +97,7 @@ type Account struct { BatchNum BatchNum `meddler:"batch_num"` BJJ babyjub.PublicKeyComp `meddler:"bjj"` EthAddr ethCommon.Address `meddler:"eth_addr"` - Nonce Nonce `meddler:"-"` // max of 40 bits used + Nonce nonce.Nonce `meddler:"-"` // max of 40 bits used Balance *big.Int `meddler:"-"` // max of 192 bits used } @@ -150,7 +120,7 @@ func (a *Account) String() string { func (a *Account) Bytes() ([32 * NLeafElems]byte, error) { var b [32 * NLeafElems]byte - if a.Nonce > maxNonceValue { + if a.Nonce > nonce.MaxNonceValue { return b, tracerr.Wrap(fmt.Errorf("%s Nonce", ErrNumOverflow)) } if len(a.Balance.Bytes()) > maxBalanceBytes { @@ -231,7 +201,7 @@ func AccountFromBytes(b [32 * NLeafElems]byte) (*Account, error) { } var nonceBytes5 [5]byte copy(nonceBytes5[:], b[23:28]) - nonce := NonceFromBytes(nonceBytes5) + nonce := nonce.FromBytes(nonceBytes5) sign := b[22] == 1 balance := new(big.Int).SetBytes(b[40:64]) @@ -262,16 +232,16 @@ func AccountFromBytes(b [32 * NLeafElems]byte) (*Account, error) { // IdxNonce is a pair of Idx and Nonce representing an account type IdxNonce struct { - Idx Idx `db:"idx"` - Nonce Nonce `db:"nonce"` + Idx Idx `db:"idx"` + Nonce nonce.Nonce `db:"nonce"` } // AccountUpdate represents an account balance and/or nonce update after a // processed batch type AccountUpdate struct { - EthBlockNum int64 `meddler:"eth_block_num"` - BatchNum BatchNum `meddler:"batch_num"` - Idx Idx `meddler:"idx"` - Nonce Nonce `meddler:"nonce"` - Balance *big.Int `meddler:"balance,bigint"` + EthBlockNum int64 `meddler:"eth_block_num"` + BatchNum BatchNum `meddler:"batch_num"` + Idx Idx `meddler:"idx"` + Nonce nonce.Nonce `meddler:"nonce"` + Balance *big.Int `meddler:"balance,bigint"` } diff --git a/common/account_test.go b/common/account_test.go index 020758531..ba2aaf79f 100644 --- a/common/account_test.go +++ b/common/account_test.go @@ -10,6 +10,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" ethCrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" cryptoConstants "github.com/iden3/go-iden3-crypto/constants" @@ -50,28 +51,28 @@ func TestIdxParser(t *testing.T) { } func TestNonceParser(t *testing.T) { - n := Nonce(1) + n := nonce.Nonce(1) nBytes, err := n.Bytes() assert.NoError(t, err) assert.Equal(t, 5, len(nBytes)) assert.Equal(t, "0000000001", hex.EncodeToString(nBytes[:])) - n2 := NonceFromBytes(nBytes) + n2 := nonce.FromBytes(nBytes) assert.Equal(t, n, n2) // value before overflow - n = Nonce(1099511627775) + n = nonce.Nonce(1099511627775) nBytes, err = n.Bytes() assert.NoError(t, err) assert.Equal(t, 5, len(nBytes)) assert.Equal(t, "ffffffffff", hex.EncodeToString(nBytes[:])) - n2 = NonceFromBytes(nBytes) + n2 = nonce.FromBytes(nBytes) assert.Equal(t, n, n2) // expect value overflow - n = Nonce(1099511627776) + n = nonce.Nonce(1099511627776) nBytes, err = n.Bytes() assert.NotNil(t, err) - assert.Equal(t, ErrNonceOverflow, tracerr.Unwrap(err)) + assert.Equal(t, nonce.ErrNonceOverflow, tracerr.Unwrap(err)) } func TestAccount(t *testing.T) { @@ -83,7 +84,7 @@ func TestAccount(t *testing.T) { account := &Account{ TokenID: TokenID(1), - Nonce: Nonce(1234), + Nonce: nonce.Nonce(1234), Balance: big.NewInt(1000), BJJ: pk.Compress(), EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), @@ -127,7 +128,7 @@ func TestAccountLoop(t *testing.T) { account := &Account{ TokenID: TokenID(i), - Nonce: Nonce(i), + Nonce: nonce.Nonce(i), Balance: big.NewInt(1000), BJJ: pk.Compress(), EthAddr: address, @@ -164,7 +165,7 @@ func TestAccountLoopRandom(t *testing.T) { account := &Account{ TokenID: TokenID(i), - Nonce: Nonce(i), + Nonce: nonce.Nonce(i), Balance: big.NewInt(1000), BJJ: pk.Compress(), EthAddr: address, @@ -208,7 +209,7 @@ func TestAccountHashValue(t *testing.T) { account := &Account{ TokenID: TokenID(1), - Nonce: Nonce(1234), + Nonce: nonce.Nonce(1234), Balance: big.NewInt(1000), BJJ: pk.Compress(), EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), @@ -234,7 +235,7 @@ func TestAccountHashValueTestVectors(t *testing.T) { TokenID: 0xFFFFFFFF, BJJ: bjj.Compress(), EthAddr: ethCommon.HexToAddress("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), - Nonce: Nonce(0xFFFFFFFFFF), + Nonce: nonce.Nonce(0xFFFFFFFFFF), Balance: bigFromStr("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16), } @@ -268,7 +269,7 @@ func TestAccountHashValueTestVectors(t *testing.T) { TokenID: 0, BJJ: bjj.Compress(), EthAddr: ethCommon.HexToAddress("0x00"), - Nonce: Nonce(0), + Nonce: nonce.Nonce(0), Balance: big.NewInt(0), } v, err = account.HashValue() @@ -286,7 +287,7 @@ func TestAccountHashValueTestVectors(t *testing.T) { TokenID: 3, BJJ: bjj.Compress(), EthAddr: ethCommon.HexToAddress("0xA3C88ac39A76789437AED31B9608da72e1bbfBF9"), - Nonce: Nonce(129), + Nonce: nonce.Nonce(129), Balance: bigFromStr("42000000000000000000", 10), } e, err = account.BigInts() @@ -338,7 +339,7 @@ func TestAccountErrNumOverflowNonce(t *testing.T) { // check limit account := &Account{ TokenID: TokenID(1), - Nonce: Nonce(math.Pow(2, 40) - 1), + Nonce: nonce.Nonce(math.Pow(2, 40) - 1), Balance: big.NewInt(1000), BJJ: pk.Compress(), EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), @@ -347,7 +348,7 @@ func TestAccountErrNumOverflowNonce(t *testing.T) { assert.NoError(t, err) // force value overflow - account.Nonce = Nonce(math.Pow(2, 40)) + account.Nonce = nonce.Nonce(math.Pow(2, 40)) b, err := account.Bytes() assert.NotNil(t, err) assert.Equal(t, fmt.Errorf("%s Nonce", ErrNumOverflow), tracerr.Unwrap(err)) @@ -366,7 +367,7 @@ func TestAccountErrNumOverflowBalance(t *testing.T) { // check limit account := &Account{ TokenID: TokenID(1), - Nonce: Nonce(math.Pow(2, 40) - 1), + Nonce: nonce.Nonce(math.Pow(2, 40) - 1), Balance: new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(192), nil), big.NewInt(1)), BJJ: pk.Compress(), EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), diff --git a/api/apitypes/apitypes.go b/common/apitypes/apitypes.go similarity index 100% rename from api/apitypes/apitypes.go rename to common/apitypes/apitypes.go diff --git a/api/apitypes/apitypes_test.go b/common/apitypes/apitypes_test.go similarity index 100% rename from api/apitypes/apitypes_test.go rename to common/apitypes/apitypes_test.go diff --git a/common/apitypes/txl2.go b/common/apitypes/txl2.go new file mode 100644 index 000000000..006f10ae4 --- /dev/null +++ b/common/apitypes/txl2.go @@ -0,0 +1,150 @@ +package apitypes + +import ( + "encoding/json" + "time" + + ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" + "github.com/iden3/go-iden3-crypto/babyjub" +) + +// TxL2 represents a L2 Tx pool with extra metadata used by the API +type TxL2 struct { + ItemID uint64 `json:"itemId"` + TxID common.TxID `json:"id"` + Type common.TxType `json:"type"` + FromIdx HezIdx `json:"fromAccountIndex"` + EffectiveFromEthAddr *HezEthAddr `json:"fromHezEthereumAddress"` + EffectiveFromBJJ *HezBJJ `json:"fromBJJ"` + ToIdx *HezIdx `json:"toAccountIndex"` + EffectiveToEthAddr *HezEthAddr `json:"toHezEthereumAddress"` + EffectiveToBJJ *HezBJJ `json:"toBJJ"` + Amount BigIntStr `json:"amount"` + Fee common.FeeSelector `json:"fee"` + Nonce nonce.Nonce `json:"nonce"` + State common.PoolL2TxState `json:"state"` + BatchNum *common.BatchNum `json:"batchNum"` + MaxNumBatch uint32 `json:"maxNumBatch"` + Info *string `json:"info"` + ErrorCode *int `json:"errorCode"` + ErrorType *string `json:"errorType"` + Signature babyjub.SignatureComp `json:"signature"` + Timestamp time.Time `json:"timestamp"` + RqFromIdx *HezIdx `json:"requestFromAccountIndex"` + RqToIdx *HezIdx `json:"requestToAccountIndex"` + RqToEthAddr *HezEthAddr `json:"requestToHezEthereumAddress"` + RqToBJJ *HezBJJ `json:"requestToBJJ"` + RqTokenID *common.TokenID `json:"requestTokenId"` + RqAmount *BigIntStr `json:"requestAmount"` + RqFee *common.FeeSelector `json:"requestFee"` + RqNonce *nonce.Nonce `json:"requestNonce"` + Token struct { + TokenID common.TokenID `json:"id"` + TokenItemID uint64 `json:"itemId"` + TokenEthBlockNum int64 `json:"ethereumBlockNum"` + TokenEthAddr ethCommon.Address `json:"ethereumAddress"` + TokenName string `json:"name"` + TokenSymbol string `json:"symbol"` + TokenDecimals uint64 `json:"decimals"` + TokenUSD *float64 `json:"USD"` + TokenUSDUpdate *time.Time `json:"fiatUpdate"` + } `json:"token"` +} + +// MarshalJSON is used to convert TxL2 in JSON +func (tx TxL2) MarshalJSON() ([]byte, error) { + type jsonToken struct { + TokenID common.TokenID `json:"id"` + TokenItemID uint64 `json:"itemId"` + TokenEthBlockNum int64 `json:"ethereumBlockNum"` + TokenEthAddr ethCommon.Address `json:"ethereumAddress"` + TokenName string `json:"name"` + TokenSymbol string `json:"symbol"` + TokenDecimals uint64 `json:"decimals"` + TokenUSD *float64 `json:"USD"` + TokenUSDUpdate *time.Time `json:"fiatUpdate"` + } + type jsonFormat struct { + ItemID uint64 `json:"itemId"` + TxID common.TxID `json:"id"` + Type common.TxType `json:"type"` + FromIdx HezIdx `json:"fromAccountIndex"` + EffectiveFromEthAddr *HezEthAddr `json:"fromHezEthereumAddress"` + EffectiveFromBJJ *HezBJJ `json:"fromBJJ"` + ToIdx *HezIdx `json:"toAccountIndex"` + EffectiveToEthAddr *HezEthAddr `json:"toHezEthereumAddress"` + EffectiveToBJJ *HezBJJ `json:"toBJJ"` + Amount BigIntStr `json:"amount"` + Fee common.FeeSelector `json:"fee"` + Nonce nonce.Nonce `json:"nonce"` + State common.PoolL2TxState `json:"state"` + BatchNum *common.BatchNum `json:"batchNum"` + MaxNumBatch uint32 `json:"maxNumBatch"` + Info *string `json:"info"` + ErrorCode *int `json:"errorCode"` + ErrorType *string `json:"errorType"` + Signature babyjub.SignatureComp `json:"signature"` + Timestamp time.Time `json:"timestamp"` + RqFromIdx *HezIdx `json:"requestFromAccountIndex"` + RqToIdx *HezIdx `json:"requestToAccountIndex"` + RqToEthAddr *HezEthAddr `json:"requestToHezEthereumAddress"` + RqToBJJ *HezBJJ `json:"requestToBJJ"` + RqTokenID *common.TokenID `json:"requestTokenId"` + RqAmount *BigIntStr `json:"requestAmount"` + RqFee *common.FeeSelector `json:"requestFee"` + RqNonce *nonce.Nonce `json:"requestNonce"` + Token jsonToken `json:"token"` + } + toMarshal := jsonFormat{ + ItemID: tx.ItemID, + TxID: tx.TxID, + Type: tx.Type, + FromIdx: tx.FromIdx, + EffectiveFromEthAddr: tx.EffectiveFromEthAddr, + EffectiveFromBJJ: tx.EffectiveFromBJJ, + ToIdx: tx.ToIdx, + EffectiveToEthAddr: tx.EffectiveToEthAddr, + EffectiveToBJJ: tx.EffectiveToBJJ, + Amount: tx.Amount, + Fee: tx.Fee, + Nonce: tx.Nonce, + State: tx.State, + MaxNumBatch: tx.MaxNumBatch, + Info: tx.Info, + ErrorCode: tx.ErrorCode, + ErrorType: tx.ErrorType, + Signature: tx.Signature, + Timestamp: tx.Timestamp, + RqFromIdx: tx.RqFromIdx, + RqToIdx: tx.RqToIdx, + RqToEthAddr: tx.RqToEthAddr, + RqToBJJ: tx.RqToBJJ, + RqTokenID: tx.RqTokenID, + RqAmount: tx.RqAmount, + RqFee: tx.RqFee, + RqNonce: tx.RqNonce, + Token: jsonToken{ + TokenID: tx.Token.TokenID, + TokenItemID: tx.Token.TokenItemID, + TokenEthBlockNum: tx.Token.TokenEthBlockNum, + TokenEthAddr: tx.Token.TokenEthAddr, + TokenName: tx.Token.TokenName, + TokenSymbol: tx.Token.TokenSymbol, + TokenDecimals: tx.Token.TokenDecimals, + TokenUSD: tx.Token.TokenUSD, + TokenUSDUpdate: tx.Token.TokenUSDUpdate, + }, + } + return json.Marshal(toMarshal) +} + +// UnmarshalJSON is used to create a TxL2 from JSON data +func (tx *TxL2) UnmarshalJSON(data []byte) error { + err := json.Unmarshal(data, tx) + if err != nil { + return err + } + return nil +} diff --git a/common/batch.go b/common/batch.go index 6ea929c12..f1886bb23 100644 --- a/common/batch.go +++ b/common/batch.go @@ -77,7 +77,7 @@ func BatchNumFromBytes(b []byte) (BatchNum, error) { // BatchData contains the information of a Batch type BatchData struct { - L1Batch bool // TODO: Remove once Batch.ForgeL1TxsNum is a pointer + L1Batch bool // L1UserTxs that were forged in the batch L1UserTxs []L1Tx L1CoordinatorTxs []L1Tx diff --git a/common/errors.go b/common/errors.go index 2ad2da0dd..6fe85120b 100644 --- a/common/errors.go +++ b/common/errors.go @@ -12,9 +12,6 @@ var ErrNotInFF = errors.New("BigInt not inside the Finite Field") // ErrNumOverflow is used when a given value overflows the maximum capacity of the parameter var ErrNumOverflow = errors.New("Value overflows the type") -// ErrNonceOverflow is used when a given nonce overflows the maximum capacity of the Nonce (2**40-1) -var ErrNonceOverflow = errors.New("Nonce overflow, max value: 2**40 -1") - // ErrIdxOverflow is used when a given nonce overflows the maximum capacity of the Idx (2**48-1) var ErrIdxOverflow = errors.New("Idx overflow, max value: 2**48 -1") diff --git a/common/l2tx.go b/common/l2tx.go index 966b37d90..9c9e56a90 100644 --- a/common/l2tx.go +++ b/common/l2tx.go @@ -5,6 +5,7 @@ import ( "math/big" ethCrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/tracerr" ) @@ -21,8 +22,8 @@ type L2Tx struct { Amount *big.Int `meddler:"amount,bigint"` Fee FeeSelector `meddler:"fee"` // Nonce is filled by the TxProcessor - Nonce Nonce `meddler:"nonce"` - Type TxType `meddler:"type"` + Nonce nonce.Nonce `meddler:"nonce"` + Type TxType `meddler:"type"` // EthBlockNum in which this L2Tx was added to the queue EthBlockNum int64 `meddler:"eth_block_num"` } @@ -122,7 +123,7 @@ func (tx *L2Tx) Tx() *Tx { *batchNum = tx.BatchNum fee := new(FeeSelector) *fee = tx.Fee - nonce := new(Nonce) + nonce := new(nonce.Nonce) *nonce = tx.Nonce return &Tx{ IsL1: false, diff --git a/common/nonce/errors.go b/common/nonce/errors.go new file mode 100644 index 000000000..c4512362d --- /dev/null +++ b/common/nonce/errors.go @@ -0,0 +1,6 @@ +package nonce + +import "errors" + +// ErrNonceOverflow is used when a given nonce overflows the maximum capacity of the Nonce (2**40-1) +var ErrNonceOverflow = errors.New("Nonce overflow, max value: 2**40 -1") diff --git a/common/nonce/nonce.go b/common/nonce/nonce.go new file mode 100644 index 000000000..fc2fc7df9 --- /dev/null +++ b/common/nonce/nonce.go @@ -0,0 +1,43 @@ +package nonce + +import ( + "encoding/binary" + "math/big" + + "github.com/hermeznetwork/tracerr" +) + +const ( + // MaxNonceValue is the maximum value that the Account.Nonce can have + // (40 bits: MaxNonceValue=2**40-1) + MaxNonceValue = 0xffffffffff +) + +// Nonce represents the nonce value in a uint64, which has the method Bytes +// that returns a byte array of length 5 (40 bits). +type Nonce uint64 + +// Bytes returns a byte array of length 5 representing the Nonce +func (n Nonce) Bytes() ([5]byte, error) { + if n > MaxNonceValue { + return [5]byte{}, tracerr.Wrap(ErrNonceOverflow) + } + var nonceBytes [8]byte + binary.BigEndian.PutUint64(nonceBytes[:], uint64(n)) + var b [5]byte + copy(b[:], nonceBytes[3:]) + return b, nil +} + +// BigInt returns the *big.Int representation of the Nonce value +func (n Nonce) BigInt() *big.Int { + return big.NewInt(int64(n)) +} + +// FromBytes returns Nonce from a [5]byte +func FromBytes(b [5]byte) Nonce { + var nonceBytes [8]byte + copy(nonceBytes[3:], b[:]) + nonce := binary.BigEndian.Uint64(nonceBytes[:]) + return Nonce(nonce) +} diff --git a/common/pooll2tx.go b/common/pooll2tx.go index d93f63512..ce69a594e 100644 --- a/common/pooll2tx.go +++ b/common/pooll2tx.go @@ -9,6 +9,7 @@ import ( "time" ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" "github.com/iden3/go-iden3-crypto/poseidon" @@ -23,7 +24,7 @@ var EmptyBJJComp = babyjub.PublicKeyComp([32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // PoolL2Tx is a struct that represents a L2Tx sent by an account to the // coordinator that is waiting to be forged type PoolL2Tx struct { - // Stored in DB: mandatory fileds + // Stored in DB: mandatory fields // TxID (12 bytes) for L2Tx is: // bytes: | 1 | 6 | 5 | @@ -40,7 +41,7 @@ type PoolL2Tx struct { TokenID TokenID `meddler:"token_id"` Amount *big.Int `meddler:"amount,bigint"` Fee FeeSelector `meddler:"fee"` - Nonce Nonce `meddler:"nonce"` // effective 40 bits used + Nonce nonce.Nonce `meddler:"nonce"` // effective 40 bits used State PoolL2TxState `meddler:"state"` MaxNumBatch uint32 `meddler:"max_num_batch,zeroisnull"` // Info contains information about the status & State of the @@ -52,7 +53,7 @@ type PoolL2Tx struct { ErrorType string `meddler:"error_type,zeroisnull"` Signature babyjub.SignatureComp `meddler:"signature"` // tx signature Timestamp time.Time `meddler:"timestamp,utctime"` // time when added to the tx pool - // Stored in DB: optional fileds, may be uninitialized + // Stored in DB: optional fields, may be uninitialized AtomicGroupID AtomicGroupID `meddler:"atomic_group_id,zeroisnull"` RqFromIdx Idx `meddler:"rq_from_idx,zeroisnull"` RqToIdx Idx `meddler:"rq_to_idx,zeroisnull"` @@ -61,7 +62,7 @@ type PoolL2Tx struct { RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"` RqAmount *big.Int `meddler:"rq_amount,bigintnull"` RqFee FeeSelector `meddler:"rq_fee,zeroisnull"` - RqNonce Nonce `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used + RqNonce nonce.Nonce `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used AbsoluteFee float64 `meddler:"fee_usd,zeroisnull"` AbsoluteFeeUpdate time.Time `meddler:"usd_update,utctimez"` Type TxType `meddler:"tx_type"` @@ -463,7 +464,7 @@ func (tx PoolL2Tx) MarshalJSON() ([]byte, error) { ToBJJ *string `json:"toBjj"` Amount string `json:"amount"` Fee FeeSelector `json:"fee"` - Nonce Nonce `json:"nonce"` + Nonce nonce.Nonce `json:"nonce"` MaxNumBatch uint32 `json:"maxNumBatch"` Signature babyjub.SignatureComp `json:"signature"` RqOffset *uint8 `json:"requestOffset"` @@ -500,9 +501,10 @@ func (tx PoolL2Tx) MarshalJSON() ([]byte, error) { return json.Marshal(toMarshal) } -// UnmarshalJSON unmarshals a PoolL2Tx that has been formated in json as specified in `api/swagger.yml:schemas/PostPoolL2Transaction`. +// UnmarshalJSON unmarshal a PoolL2Tx that has been formatted in json as specified +// in `api/swagger.yml:schemas/PostPoolL2Transaction`. // Note that ClientIP is not included as part of the json and will be set to "". -// If State is not setted (State == ""), it will be set to PoolL2TxStatePending. +// If State is not defined (State == ""), it will be set to PoolL2TxStatePending. func (tx *PoolL2Tx) UnmarshalJSON(data []byte) error { receivedJSON := struct { TxID TxID `json:"id" binding:"required"` @@ -514,7 +516,7 @@ func (tx *PoolL2Tx) UnmarshalJSON(data []byte) error { ToBJJ StrHezBJJ `json:"toBjj"` Amount *StrBigInt `json:"amount" binding:"required"` Fee FeeSelector `json:"fee"` - Nonce Nonce `json:"nonce"` + Nonce nonce.Nonce `json:"nonce"` MaxNumBatch uint32 `json:"maxNumBatch"` Signature babyjub.SignatureComp `json:"signature" binding:"required"` State string `json:"state"` diff --git a/common/tx.go b/common/tx.go index 449c7be57..8068bef1b 100644 --- a/common/tx.go +++ b/common/tx.go @@ -10,6 +10,7 @@ import ( "strings" ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" ) @@ -164,7 +165,7 @@ type Tx struct { // L2 Fee *FeeSelector `meddler:"fee"` FeeUSD *float64 `meddler:"fee_usd"` - Nonce *Nonce `meddler:"nonce"` + Nonce *nonce.Nonce `meddler:"nonce"` } func (tx *Tx) String() string { diff --git a/config/README.md b/config/README.md new file mode 100644 index 000000000..99be667c5 --- /dev/null +++ b/config/README.md @@ -0,0 +1,211 @@ +# Configuration + +This is an example of the env variable equivalations and the toml file: + +``` +[API] +Address = HEZNODE_API_ADDRESS +Explorer = HEZNODE_API_EXPLORER +UpdateMetricsInterval = HEZNODE_API_UPDATEMETRICSINTERVAL +UpdateRecommendedFeeInterval = HEZNODE_API_UPDATERECOMMENDEDFEEINTERVAL +MaxSQLConnections = HEZNODE_API_MAXSQLCONNECTIONS +SQLConnectionTimeout = HEZNODE_API_SQLCONNECTIONTIMEOUT + +[Debug] +APIAddress = HEZNODE_DEBUG_APIADDRESS +MeddlerLogs = HEZNODE_DEBUG_MEDDLERLOGS +GinDebugMode = HEZNODE_DEBUG_GINDEBUGMODE + +[StateDB] +Path = HEZNODE_STATEDB_PATH +Keep = HEZNODE_STATEDB_KEEP + +[PostgreSQL] +PortWrite = HEZNODE_POSTGRESQL_PORTWRITE +HostWrite = HEZNODE_POSTGRESQL_HOSTWRITE +UserWrite = HEZNODE_POSTGRESQL_USERWRITE +PasswordWrite = HEZNODE_POSTGRESQL_PASSWORDWRITE +NameWrite = HEZNODE_POSTGRESQL_NAMEWRITE +PortRead = HEZNODE_POSTGRESQL_PORTREAD +HostRead = HEZNODE_POSTGRESQL_HOSTREAD +UserRead = HEZNODE_POSTGRESQL_USERREAD +PasswordRead = HEZNODE_POSTGRESQL_PASSWORDREAD +NameRead = HEZNODE_POSTGRESQL_NAMEREAD + +[Web3] +URL = HEZNODE_WEB3_URL + +[Synchronizer] +SyncLoopInterval = HEZNODE_SYNCHRONIZER_SYNCLOOPINTERVAL +StatsUpdateBlockNumDiffThreshold = HEZNODE_SYNCHRONIZER_STATSUPDATEBLOCKSNUMDIFFTHRESHOLD +StatsUpdateFrequencyDivider = HEZNODE_SYNCHRONIZER_STATSUPDATEFREQUENCYDIVIDER + +[SmartContracts] +Rollup = HEZNODE_SMARTCONTRACTS_ROLLUP + +[Coordinator] +ForgerAddress = HEZNODE_COORDINATOR_FORGERADDRESS +MinimumForgeAddressBalance = HEZNODE_COORDINATOR_MINIMUMFORGEADDRESSBALANCE +ConfirmBlocks = HEZNODE_COORDINATOR_CONFIRMBLOCKS +L1BatchTimeoutPerc = HEZNODE_COORDINATOR_L1BATCHTIMEOUTPERC +StartSlotBlocksDelay = HEZNODE_COORDINATOR_STARTSLOTBLOCKSDELAY +ScheduleBatchBlocksAheadCheck = HEZNODE_COORDINATOR_SCHEDULEBATCHBLOCKSAHEADCHECK +SendBatchBlocksMarginCheck = HEZNODE_COORDINATOR_SENDBATCHBLOCKSMARGINCHECK +ProofServerPollInterval = HEZNODE_COORDINATOR_PROOFSERVERPOLLINTERVAL +ForgeRetryInterval = HEZNODE_COORDINATOR_FORGERETRYINTERVAL +SyncRetryInterval = HEZNODE_COORDINATOR_SYNCRETRYINTERVAL +ForgeDelay = HEZNODE_COORDINATOR_FORGEDELAY +ForgeNoTxsDelay = HEZNODE_COORDINATOR_FORGENOTXSDELAY +PurgeByExtDelInterval = HEZNODE_COORDINATOR_PURGEBYEXTDELINTERVAL +MustForgeAtSlotDeadline = HEZNODE_COORDINATOR_MUSTFORGEATSLOTDEADLINE +IgnoreSlotCommitment = HEZNODE_COORDINATOR_IGNORESLOTCOMMITMENT + +[Coordinator.FeeAccount] +Address = HEZNODE_FEEACCOUNT_ADDRESS +BJJ = HEZNODE_FEEACCOUNT_BJJ + + +[Coordinator.L2DB] +SafetyPeriod = HEZNODE_L2DB_SAFETYPERIOD +MaxTxs = HEZNODE_L2DB_MAXTXS +MinFeeUSD = HEZNODE_L2DB_MINFEEUSD +MaxFeeUSD = HEZNODE_L2DB_MAXFEEUSD +TTL = HEZNODE_L2DB_TTL +PurgeBatchDelay = HEZNODE_L2DB_PURGEBATCHDELAY +InvalidateBatchDelay = HEZNODE_L2DB_INVALIDATEBATCHDELAY +PurgeBlockDelay = HEZNODE_L2DB_PURGEBLOCKDELAY +InvalidateBlockDelay = HEZNODE_L2DB_INVALIDATEBLOCKDELAY + +[Coordinator.TxSelector] +Path = HEZNODE_TXSELECTOR_PATH + +[Coordinator.BatchBuilder] +Path = HEZNODE_BATCHBUILDER_PATH + +[Coordinator.ServerProofs] +URLs = HEZNODE_SERVERPROOF_URLS + +[Coordinator.Circuit] +MaxTx = HEZNODE_CIRCUIT_MAXTX +NLevels = HEZNODE_CIRCUIT_NLEVELS + +[Coordinator.EthClient] +CheckLoopInterval = HEZNODE_ETHCLIENT_CHECKLOOPINTERVAL +Attempts = HEZNODE_ETHCLIENT_ATTEMPTS +AttemptsDelay = HEZNODE_ETHCLIENT_ATTEMPTSDELAY +TxResendTimeout = HEZNODE_ETHCLIENT_TXRESENDTIMEOUT +NoReuseNonce = HEZNODE_ETHCLIENT_NOREUSENONCE +MaxGasPrice = HEZNODE_ETHCLIENT_MAXGASPRICE +MinGasPrice = HEZNODE_ETHCLIENT_MINGASPRICE +GasPriceIncPerc = HEZNODE_ETHCLIENT_GASPRICEINCPERC + +[Coordinator.EthClient.Keystore] +Path = HEZNODE_KEYSTORE_PATH +Password = HEZNODE_KEYSTORE_PASSWORD + +[Coordinator.EthClient.ForgeBatchGasCost] +Fixed = HEZNODE_FORGEBATCHGASCOST_FIXED +L1UserTx = HEZNODE_FORGEBATCHGASCOST_L1USERTX +L1CoordTx = HEZNODE_FORGEBATCHGASCOST_L1COORDTX +L2Tx = HEZNODE_FORGEBATCHGASCOST_L2TX + +[Coordinator.API] +Coordinator = HEZNODE_COORDINATORAPI_COORDINATOR + +[Coordinator.Debug] +BatchPath = HEZNODE_COORDINATORDEBUG_BATCHPATH +LightScrypt = HEZNODE_COORDINATORDEBUG_LIGHTSCRYPT + +[Coordinator.Etherscan] +URL = HEZNODE_ETHERSCAN_URL +APIKey = HEZNODE_ETHERSCAN_APIKEY + +[RecommendedFeePolicy] +PolicyType = HEZNODE_RECOMMENDEDFEEPOLICY_POLICYTYPE +StaticValue = HEZNODE_RECOMMENDEDFEEPOLICY_STATICVALUE +``` + +## Table: + +|Section |Parameter Name |Env name | Required/Optional|Default value |Description | +--- | --- | --- | --- | --- | --- | +|API|Address|HEZNODE_API_ADDRESS|Optional|"0.0.0.0:9086"|Url and port where the API will listen +|API|Explorer|HEZNODE_API_EXPLORER|Optional|true|Enables the Explorer API endpoints +|API|UpdateMetricsInterval|HEZNODE_API_UPDATEMETRICSINTERVAL|Optional|"10s"|Interval between updates of the API metrics +|API|UpdateRecommendedFeeInterval|HEZNODE_API_UPDATERECOMMENDEDFEEINTERVAL|Optional|"10s"|Interval between updates of the recommended fees +|API|MaxSQLConnections|HEZNODE_API_MAXSQLCONNECTIONS|Optional|100|Maximum concurrent connections allowed between API and SQL +|API|SQLConnectionTimeout|HEZNODE_API_SQLCONNECTIONTIMEOUT|Optional|"2s"|Maximum amount of time that an API request can wait to establish a SQL connection +|Debug|APIAddress|HEZNODE_DEBUG_APIADDRESS|Optional|"0.0.0.0:12345"|If it is set, the debug api will listen in this address and port +|Debug|MeddlerLogs|HEZNODE_DEBUG_MEDDLERLOGS|Optional|true|Enables meddler debug mode, where unused columns and struct fields will be logged +|Debug|GinDebugMode|HEZNODE_DEBUG_GINDEBUGMODE|Optional|false|Sets the web framework Gin-Gonic to run in debug mode +|StateDB|Path|HEZNODE_STATEDB_PATH|Optional|"/var/hermez/statedb"|Path where the synchronizer StateDB is stored +|StateDB|Keep|HEZNODE_STATEDB_KEEP|Optional|256|Number of checkpoints to keep +|PostgreSQL|PortWrite|HEZNODE_POSTGRESQL_PORTWRITE|**Required**|5432|Port of the PostgreSQL write server +|PostgreSQL|HostWrite|HEZNODE_POSTGRESQL_HOSTWRITE|**Required**|"localhost"|Host of the PostgreSQL write server +|PostgreSQL|UserWrite|HEZNODE_POSTGRESQL_USERWRITE|**Required**|"hermez"|User of the PostgreSQL write server +|PostgreSQL|PasswordWrite|HEZNODE_POSTGRESQL_PASSWORDWRITE|**Required**|"yourpasswordhere"|Password of the PostgreSQL write server +|PostgreSQL|NameWrite|HEZNODE_POSTGRESQL_NAMEWRITE|**Required**|"hermez"|Name of the PostgreSQL write server database +|PostgreSQL|PortRead|HEZNODE_POSTGRESQL_PORTREAD|Optional|5432|Port of the PostgreSQL read server. If it is not set, the hermez node will use the postgresql write server configuration +|PostgreSQL|HostRead|HEZNODE_POSTGRESQL_HOSTREAD|Optional|"localhost"|Host of the PostgreSQL read server. If it is not set, the hermez node will use the postgresql write server configuration +|PostgreSQL|UserRead|HEZNODE_POSTGRESQL_USERREAD|Optional|"hermez"|User of the PostgreSQL read server. If it is not set, the hermez node will use the postgresql write server configuration +|PostgreSQL|PasswordRead|HEZNODE_POSTGRESQL_PASSWORDREAD|Optional|"yourpasswordhere"|Password of the PostgreSQL read server. If it is not set, the hermez node will use the postgresql write server configuration +|PostgreSQL|NameRead|HEZNODE_POSTGRESQL_NAMEREAD|Optional|"hermez"|Name of the PostgreSQL read server database. If it is not set, the hermez node will use the postgresql write server configuration +|Web3|URL|HEZNODE_WEB3_URL|**Required**|"http://localhost:8545"|Url of the web3 ethereum-node RPC server. Only geth is officially supported +|Synchronizer|SyncLoopInterval|HEZNODE_SYNCHRONIZER_SYNCLOOPINTERVAL|Optional|"1s"|Interval between attempts to synchronize a new block from an ethereum node +|Synchronizer|StatsUpdateBlockNumDiffThreshold|HEZNODE_SYNCHRONIZER_STATSUPDATEBLOCKSNUMDIFFTHRESHOLD|Optional|100|Threshold of a number of Ethereum blocks left to synchronize, such that if there are more blocks to sync than the defined value synchronizer can aggressively skip calling UpdateEth to save network bandwidth and time. After reaching the threshold UpdateEth is called on each block. This value only affects the reported % of synchronization of blocks and batches, nothing else. +|Synchronizer|StatsUpdateFrequencyDivider|HEZNODE_SYNCHRONIZER_STATSUPDATEFREQUENCYDIVIDER|Optional|100|While having more blocks to sync than updateEthBlockNumThreshold, UpdateEth will be called once in a defined number of blocks. This value only affects the reported % of synchronization of blocks and batches, nothing else +|SmartContracts|Rollup|HEZNODE_SMARTCONTRACTS_ROLLUP|**Required**|"0xA68D85dF56E733A06443306A095646317B5Fa633"|Smart contract address of the rollup Hermez.sol +|Coordinator|ForgerAddress|HEZNODE_COORDINATOR_FORGERADDRESS|**Required**|"0x05c23b938a85ab26A36E6314a0D02080E9ca6BeD"|Ethereum address that the coordinator is using to forge batches +|Coordinator|MinimumForgeAddressBalance|HEZNODE_COORDINATOR_MINIMUMFORGEADDRESSBALANCE|Optional|"0"|Minimum balance the forger address needs to start the coordinator in wei. If It is set to 0, the coordinator will not check the balance +|Coordinator|ConfirmBlocks|HEZNODE_COORDINATOR_CONFIRMBLOCKS|Optional|5|Number of confirmation blocks to be sure that the tx has been mined correctly +|Coordinator|L1BatchTimeoutPerc|HEZNODE_COORDINATOR_L1BATCHTIMEOUTPERC|Optional|0.00001|Portion of the range before the L1Batch timeout that will trigger a schedule to forge an L1Batch +|Coordinator|StartSlotBlocksDelay|HEZNODE_COORDINATOR_STARTSLOTBLOCKSDELAY|Optional|0|Number of delay blocks to wait before starting the pipeline when a slot in which the coordinator can forge is reached +|Coordinator|ScheduleBatchBlocksAheadCheck|HEZNODE_COORDINATOR_SCHEDULEBATCHBLOCKSAHEADCHECK|Optional|0|Number of blocks ahead used to decide when to stop scheduling new batches +|Coordinator|SendBatchBlocksMarginCheck|HEZNODE_COORDINATOR_SENDBATCHBLOCKSMARGINCHECK|Optional|0|Number of marging blocks used to decide when to stop sending batches to the smart contract +|Coordinator|ProofServerPollInterval|HEZNODE_COORDINATOR_PROOFSERVERPOLLINTERVAL|Optional|"1s"|Interval between calls to the ProofServer to check the status +|Coordinator|ForgeRetryInterval|HEZNODE_COORDINATOR_FORGERETRYINTERVAL|Optional|"10s"|Interval between forge retries after an error +|Coordinator|SyncRetryInterval|HEZNODE_COORDINATOR_SYNCRETRYINTERVAL|Optional|"1s"|Interval between calls to the main handler of a synced block after an error +|Coordinator|ForgeDelay|HEZNODE_COORDINATOR_FORGEDELAY|Optional|"600s"|Delay after which a batch is forged if the slot is already committed. If It is set to "0s", the coordinator will continuously forge at the maximum rate +|Coordinator|ForgeNoTxsDelay|HEZNODE_COORDINATOR_FORGENOTXSDELAY|Optional|"86400s"|Delay after a forged batch if there are no txs to forge. If It is set to 0s, the coordinator will continuously forge even if the batches are empty +|Coordinator|PurgeByExtDelInterval|HEZNODE_COORDINATOR_PURGEBYEXTDELINTERVAL|Optional|"1m"|Interval between calls to the PurgeByExternalDelete function of the l2db which deletes pending txs externally marked by the column `external_delete` +|Coordinator|MustForgeAtSlotDeadline|HEZNODE_COORDINATOR_MUSTFORGEATSLOTDEADLINE|Optional|true|Enables the coordinator to forge in slots if the empty slots reach the slot deadline. +|Coordinator|IgnoreSlotCommitment|HEZNODE_COORDINATOR_IGNORESLOTCOMMITMENT|Optional|true|It 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`. +|Coordinator|ForgeOncePerSlotIfTxs|HEZNODE_COORDINATOR_FORGEONCEPERSLOTIFTXS|Optional|false|This parameter 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`. +|Coordinator.FeeAccount|Address|HEZNODE_FEEACCOUNT_ADDRESS|**Required**|"0x56232B1c5B10038125Bc7345664B4AFD745bcF8E"|Ethereum address of the account that will receive the fees +|Coordinator.FeeAccount|BJJ|HEZNODE_FEEACCOUNT_BJJ|**Required**|"0x130c5c7f294792559f469220274f3d3b2dca6e89f4c5ec88d3a08bf73262171b"|BJJ is the baby jub jub public key of the account that will receive the fees +|Coordinator.L2DB|SafetyPeriod|HEZNODE_L2DB_SAFETYPERIOD|Optional|10|Number of batches after which non-pending L2Txs are deleted from the pool +|Coordinator.L2DB|MaxTxs|HEZNODE_L2DB_MAXTXS|Optional|1000000|Maximum number of pending L2Txs that can be stored in the pool +|Coordinator.L2DB|MinFeeUSD|HEZNODE_L2DB_MINFEEUSD|Optional|0.10|Minimum fee in USD that a tx must pay in order to be accepted into the pool +|Coordinator.L2DB|MaxFeeUSD|HEZNODE_L2DB_MAXFEEUSD|Optional|10.0|Maximum fee in USD that a tx must pay in order to be accepted into the pool +|Coordinator.L2DB|TTL|HEZNODE_L2DB_TTL|Optional|"24h"|Time To Live for L2Txs in the pool. L2Txs older than TTL will be deleted. +|Coordinator.L2DB|PurgeBatchDelay|HEZNODE_L2DB_PURGEBATCHDELAY|Optional|10|Delay between batches to purge outdated transactions. Outdated L2Txs are those that have been forged or marked as invalid for longer than the SafetyPeriod and pending L2Txs that have been in the pool for longer than TTL once there are MaxTxs +|Coordinator.L2DB|InvalidateBatchDelay|HEZNODE_L2DB_INVALIDATEBATCHDELAY|Optional|20|Delay between batches to mark invalid transactions due to nonce lower than the account nonce +|Coordinator.L2DB|PurgeBlockDelay|HEZNODE_L2DB_PURGEBLOCKDELAY|Optional|10|Delay between blocks to purge outdated transactions. Outdated L2Txs are those that have been forged or marked as invalid for longer than the SafetyPeriod and pending L2Txs that have been in the pool for longer than TTL once there are MaxTxs. +|Coordinator.L2DB|InvalidateBlockDelay|HEZNODE_L2DB_INVALIDATEBLOCKDELAY|Optional|20|Delay between blocks to mark invalid transactions due to nonce lower than the account nonce +|Coordinator.TxSelector|Path|HEZNODE_TXSELECTOR_PATH|Optional|"/var/hermez/txselector"|Path where the TxSelector StateDB is stored +|Coordinator.BatchBuilder|Path|HEZNODE_BATCHBUILDER_PATH|Optional|"/var/hermez/batchbuilder"|Path where the BatchBuilder StateDB is stored +|Coordinator.ServerProofs|URLs|HEZNODE_SERVERPROOF_URLS (comma separator ",")|**Required**|`["http://localhost:3000"]`|Server proof API URL +|Coordinator.Circuit|MaxTx|HEZNODE_CIRCUIT_MAXTX|**Required**|2048|Maximum number of txs supported by the circuit +|Coordinator.Circuit|NLevels|HEZNODE_CIRCUIT_NLEVELS|**Required**|32|Maximum number of merkle tree levels supported by the circuit +|Coordinator.EthClient|CheckLoopInterval|HEZNODE_ETHCLIENT_CHECKLOOPINTERVAL|Optional|"500ms"|Interval between receipt checks of ethereum transactions in the TxManager +|Coordinator.EthClient|Attempts|HEZNODE_ETHCLIENT_ATTEMPTS|Optional|4|Number of attempts to do an eth client RPC call before giving up +|Coordinator.EthClient|AttemptsDelay|HEZNODE_ETHCLIENT_ATTEMPTSDELAY|Optional|"500ms"|Delay between attempts do do an eth client RPC call +|Coordinator.EthClient|TxResendTimeout|HEZNODE_ETHCLIENT_TXRESENDTIMEOUT|Optional|"2m"|Timeout after which a non-mined ethereum transaction will be resent (reusing the nonce) with a newly calculated gas price +|Coordinator.EthClient|NoReuseNonce|HEZNODE_ETHCLIENT_NOREUSENONCE|Optional|false|Disables reusing nonces of pending transactions for new replacement transactions +|Coordinator.EthClient|MaxGasPrice|HEZNODE_ETHCLIENT_MAXGASPRICE|Optional|500|Maximum gas price allowed for ethereum transactions in gwei +|Coordinator.EthClient|MinGasPrice|HEZNODE_ETHCLIENT_MINGASPRICE|Optional|5|Minimum gas price allowed for ethereum transactions in gwei +|Coordinator.EthClient|GasPriceIncPerc|HEZNODE_ETHCLIENT_GASPRICEINCPERC|Optional|5|Percentage increased of gas price set in an ethereum transaction from the suggested gas price by the ethereum node +|Coordinator.EthClient.Keystore|Path|HEZNODE_KEYSTORE_PATH|Optional|"/var/hermez/ethkeystore"|Path where the keystore is stored +|Coordinator.EthClient.Keystore|Password|HEZNODE_KEYSTORE_PASSWORD|**Required**|"yourpasswordhere"|Password used to decrypt the keys in the keystore +|Coordinator.EthClient.ForgeBatchGasCost|Fixed|HEZNODE_FORGEBATCHGASCOST_FIXED|Optional|900000|Gas needed to forge an empty batch +|Coordinator.EthClient.ForgeBatchGasCost|L1UserTx|HEZNODE_FORGEBATCHGASCOST_L1USERTX|Optional|15000|Gas needed per L1 tx +|Coordinator.EthClient.ForgeBatchGasCost|L1CoordTx|HEZNODE_FORGEBATCHGASCOST_L1COORDTX|Optional|7000|Gas needed for a coordinator L1 tx +|Coordinator.EthClient.ForgeBatchGasCost|L2Tx|HEZNODE_FORGEBATCHGASCOST_L2TX|Optional|600|Gas needed for an L2 tx +|Coordinator.API|Coordinator|HEZNODE_COORDINATORAPI_COORDINATOR|Optional|true|Enables coordinator API endpoints +|Coordinator.Debug|BatchPath|HEZNODE_COORDINATORDEBUG_BATCHPATH|Optional|""|If this parameter is set, specifies the path where batchInfo is stored in JSON in every step/update of the pipeline +|Coordinator.Debug|LightScrypt|HEZNODE_COORDINATORDEBUG_LIGHTSCRYPT|Optional|false|If lightScrypt is set, uses light parameters for the ethereum keystore encryption algorithm +|Coordinator.Debug|RollupVerifierIndex||Optional|nil|RollupVerifierIndex is the index of the verifier to use in the Rollup smart contract. The verifier chosen by index must match with the Circuit parameters. Only for debug purposes. It can't be used as env variable +|Coordinator.Etherscan|URL|HEZNODE_ETHERSCAN_URL|Optional|""|If this parameter is set, specifies the etherscan endpoint to get the gas estimations for that momment +|Coordinator.Etherscan|APIKey|HEZNODE_ETHERSCAN_APIKEY|Optional|""|This parameter allow access to etherscan services +|RecommendedFeePolicy|PolicyType|HEZNODE_RECOMMENDEDFEEPOLICY_POLICYTYPE|Optional|"Static"|Selects the mode. "Static" or "AvgLastHour" +|RecommendedFeePolicy|StaticValue|HEZNODE_RECOMMENDEDFEEPOLICY_STATICVALUE|Optional|0.10|If PolicyType is "static" defines the recommended fee value diff --git a/config/config.go b/config/config.go index 5448c17ca..5e8e5776d 100644 --- a/config/config.go +++ b/config/config.go @@ -2,15 +2,15 @@ package config import ( "fmt" - "io/ioutil" "math/big" + "strings" "time" - "github.com/BurntSushi/toml" ethCommon "github.com/ethereum/go-ethereum/common" + configLibrary "github.com/hermeznetwork/go-hermez-config" "github.com/hermeznetwork/hermez-node/api/stateapiupdater" "github.com/hermeznetwork/hermez-node/common" - "github.com/hermeznetwork/hermez-node/priceupdater" + "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" "gopkg.in/go-playground/validator.v9" @@ -31,52 +31,46 @@ func (d *Duration) UnmarshalText(data []byte) error { return nil } -// ServerProof is the server proof configuration data. -type ServerProof struct { - // URL is the server proof API URL - URL string `validate:"required,url"` -} - // ForgeBatchGasCost is the costs associated to a ForgeBatch transaction, split // into different parts to be used in a formula. type ForgeBatchGasCost struct { - Fixed uint64 `validate:"required"` - L1UserTx uint64 `validate:"required"` - L1CoordTx uint64 `validate:"required"` - L2Tx uint64 `validate:"required"` + Fixed uint64 `validate:"required" env:"HEZNODE_FORGEBATCHGASCOST_FIXED"` + L1UserTx uint64 `validate:"required" env:"HEZNODE_FORGEBATCHGASCOST_L1USERTX"` + L1CoordTx uint64 `validate:"required" env:"HEZNODE_FORGEBATCHGASCOST_L1COORDTX"` + L2Tx uint64 `validate:"required" env:"HEZNODE_FORGEBATCHGASCOST_L2TX"` } // CoordinatorAPI specifies the configuration parameters of the API in mode // coordinator type CoordinatorAPI struct { // Coordinator enables the coordinator API endpoints - Coordinator bool + Coordinator bool `env:"HEZNODE_COORDINATORAPI_COORDINATOR"` } // Coordinator is the coordinator specific configuration. type Coordinator struct { // ForgerAddress is the address under which this coordinator is forging - ForgerAddress ethCommon.Address `validate:"required"` + ForgerAddress ethCommon.Address `validate:"required" env:"HEZNODE_COORDINATOR_FORGERADDRESS"` // MinimumForgeAddressBalance is the minimum balance the forger address // needs to start the coordinator in wei. Of set to 0, the coordinator // will not check the balance before starting. - MinimumForgeAddressBalance *big.Int + MinimumForgeAddressBalance *big.Int `env:"HEZNODE_COORDINATOR_MINIMUMFORGEADDRESSBALANCE"` // FeeAccount is the Hermez account that the coordinator uses to receive fees FeeAccount struct { // Address is the ethereum address of the account to receive fees - Address ethCommon.Address `validate:"required"` + Address ethCommon.Address `validate:"required" env:"HEZNODE_FEEACCOUNT_ADDRESS"` // BJJ is the baby jub jub public key of the account to receive fees - BJJ babyjub.PublicKeyComp `validate:"required"` + BJJ babyjub.PublicKeyComp `validate:"required" env:"HEZNODE_FEEACCOUNT_BJJ"` } `validate:"required"` // ConfirmBlocks is the number of confirmation blocks to wait for sent // ethereum transactions before forgetting about them - ConfirmBlocks int64 `validate:"required,gte=0"` + ConfirmBlocks int64 `validate:"required,gte=0" env:"HEZNODE_COORDINATOR_CONFIRMBLOCKS"` // L1BatchTimeoutPerc is the portion of the range before the L1Batch // timeout that will trigger a schedule to forge an L1Batch - L1BatchTimeoutPerc float64 `validate:"required,lte=1.0,gte=0.0"` + L1BatchTimeoutPerc float64 `validate:"required,lte=1.0,gte=0.0" env:"HEZNODE_COORDINATOR_L1BATCHTIMEOUTPERC"` // StartSlotBlocksDelay is the number of blocks of delay to wait before // starting the pipeline when we reach a slot in which we can forge. - StartSlotBlocksDelay int64 `validate:"gte=0"` + StartSlotBlocksDelay int64 `validate:"gte=0" env:"HEZNODE_COORDINATOR_STARTSLOTBLOCKSDELAY"` // ScheduleBatchBlocksAheadCheck is the number of blocks ahead in which // the forger address is checked to be allowed to forge (apart from // checking the next block), used to decide when to stop scheduling new @@ -86,7 +80,7 @@ type Coordinator struct { // stopped if we can't forge at block 15. // This value should be the expected number of blocks it takes between // scheduling a batch and having it mined. - ScheduleBatchBlocksAheadCheck int64 `validate:"gte=0"` + ScheduleBatchBlocksAheadCheck int64 `validate:"gte=0" env:"HEZNODE_COORDINATOR_SCHEDULEBATCHBLOCKSAHEADCHECK"` // SendBatchBlocksMarginCheck is the number of margin blocks ahead in // which the coordinator is also checked to be allowed to forge, apart // from the next block; used to decide when to stop sending batches to @@ -94,133 +88,135 @@ type Coordinator struct { // For example, if we are at block 10 and SendBatchBlocksMarginCheck is // 5, even though at block 11 we canForge, the batch will be discarded // if we can't forge at block 15. - SendBatchBlocksMarginCheck int64 `validate:"gte=0"` + SendBatchBlocksMarginCheck int64 `validate:"gte=0" env:"HEZNODE_COORDINATOR_SENDBATCHBLOCKSMARGINCHECK"` // ProofServerPollInterval is the waiting interval between polling the // ProofServer while waiting for a particular status - ProofServerPollInterval Duration `validate:"required"` + ProofServerPollInterval Duration `validate:"required" env:"HEZNODE_COORDINATOR_PROOFSERVERPOLLINTERVAL"` // ForgeRetryInterval is the waiting interval between calls forge a // batch after an error - ForgeRetryInterval Duration `validate:"required"` + ForgeRetryInterval Duration `validate:"required" env:"HEZNODE_COORDINATOR_FORGERETRYINTERVAL"` // ForgeDelay is the delay after which a batch is forged if the slot is // already committed. If set to 0s, the coordinator will continuously // forge at the maximum rate. - ForgeDelay Duration `validate:"-"` + ForgeDelay Duration `validate:"-" env:"HEZNODE_COORDINATOR_FORGEDELAY"` // ForgeNoTxsDelay is the delay after which a batch is forged even if // there are no txs to forge if the slot is already committed. If set // to 0s, the coordinator will continuously forge even if the batches // are empty. - ForgeNoTxsDelay Duration `validate:"-"` + ForgeNoTxsDelay Duration `validate:"-" env:"HEZNODE_COORDINATOR_FORGENOTXSDELAY"` // MustForgeAtSlotDeadline enables the coordinator to forge slots if // the empty slots reach the slot deadline. - MustForgeAtSlotDeadline bool + MustForgeAtSlotDeadline bool `env:"HEZNODE_COORDINATOR_MUSTFORGEATSLOTDEADLINE"` // IgnoreSlotCommitment disables forcing the coordinator to forge a // slot immediately when the slot is not committed. If set to false, // the coordinator will immediately forge a batch at the beginning of a // slot if it's the slot winner. - IgnoreSlotCommitment bool + IgnoreSlotCommitment bool `env:"HEZNODE_COORDINATOR_IGNORESLOTCOMMITMENT"` // 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 + ForgeOncePerSlotIfTxs bool `env:"HEZNODE_COORDINATOR_FORGEONCEPERSLOTIFTXS"` // SyncRetryInterval is the waiting interval between calls to the main // handler of a synced block after an error - SyncRetryInterval Duration `validate:"required"` + SyncRetryInterval Duration `validate:"required" env:"HEZNODE_COORDINATOR_SYNCRETRYINTERVAL"` // PurgeByExtDelInterval is the waiting interval between calls // to the PurgeByExternalDelete function of the l2db which deletes // pending txs externally marked by the column `external_delete` - PurgeByExtDelInterval Duration `validate:"required"` + PurgeByExtDelInterval Duration `validate:"required" env:"HEZNODE_COORDINATOR_PURGEBYEXTDELINTERVAL"` // L2DB is the DB that holds the pool of L2Txs L2DB struct { // SafetyPeriod is the number of batches after which // non-pending L2Txs are deleted from the pool - SafetyPeriod common.BatchNum `validate:"required"` + SafetyPeriod common.BatchNum `validate:"required" env:"HEZNODE_L2DB_SAFETYPERIOD"` // MaxTxs is the maximum number of pending L2Txs that can be // stored in the pool. Once this number of pending L2Txs is // reached, inserts to the pool will be denied until some of // the pending txs are forged. - MaxTxs uint32 `validate:"required"` + MaxTxs uint32 `validate:"required" env:"HEZNODE_L2DB_MAXTXS"` // MinFeeUSD is the minimum fee in USD that a tx must pay in // order to be accepted into the pool. Txs with lower than // minimum fee will be rejected at the API level. - MinFeeUSD float64 `validate:"gte=0"` + MinFeeUSD float64 `validate:"gte=0" env:"HEZNODE_L2DB_MINFEEUSD"` // MaxFeeUSD is the maximum fee in USD that a tx must pay in // order to be accepted into the pool. Txs with greater than // maximum fee will be rejected at the API level. - MaxFeeUSD float64 `validate:"required,gte=0"` + MaxFeeUSD float64 `validate:"required,gte=0" env:"HEZNODE_L2DB_MAXFEEUSD"` // TTL is the Time To Live for L2Txs in the pool. L2Txs older // than TTL will be deleted. - TTL Duration `validate:"required"` + TTL Duration `validate:"required" env:"HEZNODE_L2DB_TTL"` // PurgeBatchDelay is the delay between batches to purge // outdated transactions. Outdated L2Txs are those that have // been forged or marked as invalid for longer than the // SafetyPeriod and pending L2Txs that have been in the pool // for longer than TTL once there are MaxTxs. - PurgeBatchDelay int64 `validate:"required,gte=0"` + PurgeBatchDelay int64 `validate:"required,gte=0" env:"HEZNODE_L2DB_PURGEBATCHDELAY"` // InvalidateBatchDelay is the delay between batches to mark // invalid transactions due to nonce lower than the account // nonce. - InvalidateBatchDelay int64 `validate:"required"` + InvalidateBatchDelay int64 `validate:"required" env:"HEZNODE_L2DB_INVALIDATEBATCHDELAY"` // PurgeBlockDelay is the delay between blocks to purge // outdated transactions. Outdated L2Txs are those that have // been forged or marked as invalid for longer than the // SafetyPeriod and pending L2Txs that have been in the pool // for longer than TTL once there are MaxTxs. - PurgeBlockDelay int64 `validate:"required,gte=0"` + PurgeBlockDelay int64 `validate:"required,gte=0" env:"HEZNODE_L2DB_PURGEBLOCKDELAY"` // InvalidateBlockDelay is the delay between blocks to mark // invalid transactions due to nonce lower than the account // nonce. - InvalidateBlockDelay int64 `validate:"required,gte=0"` + InvalidateBlockDelay int64 `validate:"required,gte=0" env:"HEZNODE_L2DB_INVALIDATEBLOCKDELAY"` } `validate:"required"` TxSelector struct { // Path where the TxSelector StateDB is stored - Path string `validate:"required"` + Path string `validate:"required" env:"HEZNODE_TXSELECTOR_PATH"` } `validate:"required"` BatchBuilder struct { // Path where the BatchBuilder StateDB is stored - Path string `validate:"required"` + Path string `validate:"required" env:"HEZNODE_BATCHBUILDER_PATH"` } `validate:"required"` - ServerProofs []ServerProof `validate:"required"` - Circuit struct { + ServerProofs struct { + URLs []string `validate:"required" env:"HEZNODE_SERVERPROOF_URLS" envSeparator:","` + } `validate:"required"` + Circuit struct { // MaxTx is the maximum number of txs supported by the circuit - MaxTx int64 `validate:"required,gte=0"` + MaxTx int64 `validate:"required,gte=0" env:"HEZNODE_CIRCUIT_MAXTX"` // NLevels is the maximum number of merkle tree levels // supported by the circuit - NLevels int64 `validate:"required,gte=0"` + NLevels int64 `validate:"required,gte=0" env:"HEZNODE_CIRCUIT_NLEVELS"` } `validate:"required"` EthClient struct { // MaxGasPrice is the maximum gas price allowed for ethereum // transactions - MaxGasPrice int64 `validate:"required"` + MaxGasPrice int64 `validate:"required" env:"HEZNODE_ETHCLIENT_MAXGASPRICE"` // MinGasPrice is the minimum gas price in gwei allowed for ethereum - MinGasPrice int64 `validate:"required"` + MinGasPrice int64 `validate:"required" env:"HEZNODE_ETHCLIENT_MINGASPRICE"` // GasPriceIncPerc is the percentage increase of gas price set // in an ethereum transaction from the suggested gas price by // the ethereum node - GasPriceIncPerc int64 `validate:"gte=0"` + GasPriceIncPerc int64 `validate:"gte=0" env:"HEZNODE_ETHCLIENT_GASPRICEINCPERC"` // CheckLoopInterval is the waiting interval between receipt // checks of ethereum transactions in the TxManager - CheckLoopInterval Duration `validate:"required"` + CheckLoopInterval Duration `validate:"required" env:"HEZNODE_ETHCLIENT_CHECKLOOPINTERVAL"` // Attempts is the number of attempts to do an eth client RPC // call before giving up - Attempts int `validate:"required,gte=1"` + Attempts int `validate:"required,gte=1" env:"HEZNODE_ETHCLIENT_ATTEMPTS"` // AttemptsDelay is delay between attempts do do an eth client // RPC call - AttemptsDelay Duration `validate:"required"` + AttemptsDelay Duration `validate:"required" env:"HEZNODE_ETHCLIENT_ATTEMPTSDELAY"` // TxResendTimeout is the timeout after which a non-mined // ethereum transaction will be resent (reusing the nonce) with // a newly calculated gas price - TxResendTimeout Duration `validate:"required"` + TxResendTimeout Duration `validate:"required" env:"HEZNODE_ETHCLIENT_TXRESENDTIMEOUT"` // NoReuseNonce disables reusing nonces of pending transactions for // new replacement transactions - NoReuseNonce bool + NoReuseNonce bool `env:"HEZNODE_ETHCLIENT_NOREUSENONCE"` // Keystore is the ethereum keystore where private keys are kept Keystore struct { // Path to the keystore - Path string `validate:"required"` + Path string `validate:"required" env:"HEZNODE_KEYSTORE_PATH"` // Password used to decrypt the keys in the keystore - Password string `validate:"required"` + Password string `validate:"required" env:"HEZNODE_KEYSTORE_PASSWORD"` } `validate:"required"` // ForgeBatchGasCost contains the cost of each action in the // ForgeBatch transaction. @@ -230,10 +226,10 @@ type Coordinator struct { Debug struct { // BatchPath if set, specifies the path where batchInfo is stored // in JSON in every step/update of the pipeline - BatchPath string + BatchPath string `env:"HEZNODE_COORDINATORDEBUG_BATCHPATH"` // LightScrypt if set, uses light parameters for the ethereum // keystore encryption algorithm. - LightScrypt bool + LightScrypt bool `env:"HEZNODE_COORDINATORDEBUG_LIGHTSCRYPT"` // RollupVerifierIndex is the index of the verifier to use in // the Rollup smart contract. The verifier chosen by index // must match with the Circuit parameters. @@ -242,9 +238,9 @@ type Coordinator struct { Etherscan struct { // URL if set, specifies the etherscan endpoint to get // the gas estimations for that moment. - URL string + URL string `env:"HEZNODE_ETHERSCAN_URL"` // APIKey allow access to etherscan services - APIKey string + APIKey string `env:"HEZNODE_ETHERSCAN_APIKEY"` } } @@ -253,70 +249,58 @@ type Coordinator struct { // not provided, the write one it's going to be used for both reads and writes type PostgreSQL struct { // Port of the PostgreSQL write server - PortWrite int `validate:"required"` + PortWrite int `validate:"required" env:"HEZNODE_POSTGRESQL_PORTWRITE"` // Host of the PostgreSQL write server - HostWrite string `validate:"required"` + HostWrite string `validate:"required" env:"HEZNODE_POSTGRESQL_HOSTWRITE"` // User of the PostgreSQL write server - UserWrite string `validate:"required"` + UserWrite string `validate:"required" env:"HEZNODE_POSTGRESQL_USERWRITE"` // Password of the PostgreSQL write server - PasswordWrite string `validate:"required"` + PasswordWrite string `validate:"required" env:"HEZNODE_POSTGRESQL_PASSWORDWRITE"` // Name of the PostgreSQL write server database - NameWrite string `validate:"required"` + NameWrite string `validate:"required" env:"HEZNODE_POSTGRESQL_NAMEWRITE"` // Port of the PostgreSQL read server - PortRead int + PortRead int `env:"HEZNODE_POSTGRESQL_PORTREAD"` // Host of the PostgreSQL read server - HostRead string `validate:"nefield=HostWrite"` + HostRead string `validate:"nefield=HostWrite" env:"HEZNODE_POSTGRESQL_HOSTREAD"` // User of the PostgreSQL read server - UserRead string + UserRead string `env:"HEZNODE_POSTGRESQL_USERREAD"` // Password of the PostgreSQL read server - PasswordRead string + PasswordRead string `env:"HEZNODE_POSTGRESQL_PASSWORDREAD"` // Name of the PostgreSQL read server database - NameRead string + NameRead string `env:"HEZNODE_POSTGRESQL_NAMEREAD"` } // NodeDebug specifies debug configuration parameters type NodeDebug struct { // APIAddress is the address where the debugAPI will listen if // set - APIAddress string + APIAddress string `env:"HEZNODE_DEBUG_APIADDRESS"` // MeddlerLogs enables meddler debug mode, where unused columns and struct // fields will be logged - MeddlerLogs bool + MeddlerLogs bool `env:"HEZNODE_DEBUG_MEDDLERLOGS"` // GinDebugMode sets Gin-Gonic (the web framework) to run in // debug mode - GinDebugMode bool + GinDebugMode bool `env:"HEZNODE_DEBUG_GINDEBUGMODE"` } // Node is the hermez node configuration. type Node struct { - PriceUpdater struct { - // Interval between price updater calls - Interval Duration `validate:"required"` - // Priority option defines the priority provider - Priority string `validate:"required"` - // TokensConfig to specify how each token get it's price updated - Provider []priceupdater.Provider - // Statictokens defines the static prices for tokens - Statictokens string - // Fiat defines the prices for fiat currencies - Fiat priceupdater.Fiat - } `validate:"required"` StateDB struct { // Path where the synchronizer StateDB is stored - Path string `validate:"required"` + Path string `validate:"required" env:"HEZNODE_STATEDB_PATH"` // Keep is the number of checkpoints to keep - Keep int `validate:"required,gte=128"` + Keep int `validate:"required,gte=128" env:"HEZNODE_STATEDB_KEEP"` } `validate:"required"` PostgreSQL PostgreSQL `validate:"required"` Web3 struct { // URL is the URL of the web3 ethereum-node RPC server. Only // geth is officially supported. - URL string `validate:"required,url"` + URL string `validate:"required,url" env:"HEZNODE_WEB3_URL"` } `validate:"required"` Synchronizer struct { // SyncLoopInterval is the interval between attempts to // synchronize a new block from an ethereum node - SyncLoopInterval Duration `validate:"required"` + SyncLoopInterval Duration `validate:"required" env:"HEZNODE_SYNCHRONIZER_SYNCLOOPINTERVAL"` // StatsUpdateBlockNumDiffThreshold is a threshold of a number of // Ethereum blocks left to synchronize, such that if there are more // blocks to sync than the defined value synchronizer can aggressively @@ -324,34 +308,34 @@ type Node struct { // After reaching the threshold UpdateEth is called on each block. // This value only affects the reported % of synchronization of // blocks and batches, nothing else. - StatsUpdateBlockNumDiffThreshold uint16 `validate:"required,gt=32"` + StatsUpdateBlockNumDiffThreshold uint16 `validate:"required,gt=32" env:"HEZNODE_SYNCHRONIZER_STATSUPDATEBLOCKSNUMDIFFTHRESHOLD"` // StatsUpdateFrequencyDivider - While having more blocks to sync than // updateEthBlockNumThreshold, UpdateEth will be called once in a // defined number of blocks. This value only affects the reported % of // synchronization of blocks and batches, nothing else. - StatsUpdateFrequencyDivider uint16 `validate:"required,gt=1"` + StatsUpdateFrequencyDivider uint16 `validate:"required,gt=1" env:"HEZNODE_SYNCHRONIZER_STATSUPDATEFREQUENCYDIVIDER"` } `validate:"required"` SmartContracts struct { // Rollup is the address of the Hermez.sol smart contract - Rollup ethCommon.Address `validate:"required"` + Rollup ethCommon.Address `validate:"required" env:"HEZNODE_SMARTCONTRACTS_ROLLUP"` } `validate:"required"` // API specifies the configuration parameters of the API API struct { // Address where the API will listen if set - Address string + Address string `env:"HEZNODE_API_ADDRESS"` // Explorer enables the Explorer API endpoints - Explorer bool + Explorer bool `env:"HEZNODE_API_EXPLORER"` // UpdateMetricsInterval is the interval between updates of the // API metrics - UpdateMetricsInterval Duration `validate:"required"` + UpdateMetricsInterval Duration `validate:"required" env:"HEZNODE_API_UPDATEMETRICSINTERVAL"` // UpdateRecommendedFeeInterval is the interval between updates of the // recommended fees - UpdateRecommendedFeeInterval Duration `validate:"required"` + UpdateRecommendedFeeInterval Duration `validate:"required" env:"HEZNODE_API_UPDATERECOMMENDEDFEEINTERVAL"` // Maximum concurrent connections allowed between API and SQL - MaxSQLConnections int `validate:"required,gte=1"` + MaxSQLConnections int `validate:"required,gte=1" env:"HEZNODE_API_MAXSQLCONNECTIONS"` // SQLConnectionTimeout is the maximum amount of time that an API request // can wait to establish a SQL connection - SQLConnectionTimeout Duration + SQLConnectionTimeout Duration `env:"HEZNODE_API_SQLCONNECTIONTIMEOUT"` } `validate:"required"` RecommendedFeePolicy stateapiupdater.RecommendedFeePolicy `validate:"required"` Debug NodeDebug `validate:"required"` @@ -363,61 +347,52 @@ type APIServer struct { // NodeAPI specifies the configuration parameters of the API API struct { // Address where the API will listen if set - Address string `validate:"required"` + Address string `validate:"required" env:"HEZNODE_API_ADDRESS"` // Explorer enables the Explorer API endpoints - Explorer bool + Explorer bool `env:"HEZNODE_API_EXPLORER"` // Maximum concurrent connections allowed between API and SQL - MaxSQLConnections int `validate:"required,gte=1"` + MaxSQLConnections int `validate:"required,gte=1" env:"HEZNODE_API_MAXSQLCONNECTIONS"` // SQLConnectionTimeout is the maximum amount of time that an API request // can wait to establish a SQL connection - SQLConnectionTimeout Duration + SQLConnectionTimeout Duration `env:"HEZNODE_API_SQLCONNECTIONTIMEOUT"` } `validate:"required"` PostgreSQL PostgreSQL `validate:"required"` Coordinator struct { API struct { // Coordinator enables the coordinator API endpoints - Coordinator bool + Coordinator bool `env:"HEZNODE_COORDINATORAPI_COORDINATOR"` } `validate:"required"` L2DB struct { // MaxTxs is the maximum number of pending L2Txs that can be // stored in the pool. Once this number of pending L2Txs is // reached, inserts to the pool will be denied until some of // the pending txs are forged. - MaxTxs uint32 `validate:"required"` + MaxTxs uint32 `validate:"required" env:"HEZNODE_L2DB_MAXTXS"` // MinFeeUSD is the minimum fee in USD that a tx must pay in // order to be accepted into the pool. Txs with lower than // minimum fee will be rejected at the API level. - MinFeeUSD float64 `validate:"gte=0"` + MinFeeUSD float64 `validate:"gte=0" env:"HEZNODE_L2DB_MINFEEUSD"` // MaxFeeUSD is the maximum fee in USD that a tx must pay in // order to be accepted into the pool. Txs with greater than // maximum fee will be rejected at the API level. - MaxFeeUSD float64 `validate:"required,gte=0"` + MaxFeeUSD float64 `validate:"required,gte=0" env:"HEZNODE_L2DB_MAXFEEUSD"` } `validate:"required"` } Debug NodeDebug `validate:"required"` } -// Load loads a generic config. -func Load(path string, cfg interface{}) error { - bs, err := ioutil.ReadFile(path) //nolint:gosec - if err != nil { - return tracerr.Wrap(err) - } - cfgToml := string(bs) - if _, err := toml.Decode(cfgToml, cfg); err != nil { - return tracerr.Wrap(err) - } - return nil -} - // LoadNode loads the Node configuration from path. func LoadNode(path string, coordinator bool) (*Node, error) { var cfg Node - if err := Load(path, &cfg); err != nil { - return nil, tracerr.Wrap(fmt.Errorf("error loading node configuration file: %w", err)) + err := configLibrary.LoadConfig(path, DefaultValues, &cfg) + if err != nil { + //Split errors depending on if there is a file error, a env error or a default error + if strings.Contains(err.Error(), "default") { + return nil, err + } + log.Warn(err.Error()) } validate := validator.New() - validate.RegisterStructValidation(priceupdater.ProviderValidation, priceupdater.Provider{}) if err := validate.Struct(cfg); err != nil { return nil, tracerr.Wrap(fmt.Errorf("error validating configuration file: %w", err)) } @@ -432,11 +407,15 @@ func LoadNode(path string, coordinator bool) (*Node, error) { // LoadAPIServer loads the APIServer configuration from path. func LoadAPIServer(path string, coordinator bool) (*APIServer, error) { var cfg APIServer - if err := Load(path, &cfg); err != nil { - return nil, tracerr.Wrap(fmt.Errorf("error loading apiServer configuration file: %w", err)) + err := configLibrary.LoadConfig(path, DefaultValues, &cfg) + if err != nil { + //Split errors depending on if there is a file error, a env error or a default error + if strings.Contains(err.Error(), "default") { + return nil, err + } + log.Warn(err.Error()) } validate := validator.New() - validate.RegisterStructValidation(priceupdater.ProviderValidation, priceupdater.Provider{}) if err := validate.Struct(cfg); err != nil { return nil, tracerr.Wrap(fmt.Errorf("error validating configuration file: %w", err)) } diff --git a/config/default.go b/config/default.go new file mode 100644 index 000000000..e6d478a4b --- /dev/null +++ b/config/default.go @@ -0,0 +1,112 @@ +package config + +// DefaultValues is the default fonfigurations for the hermez node +const DefaultValues = ` +[API] +Address = "0.0.0.0:8086" +Explorer = true +UpdateMetricsInterval = "10s" +UpdateRecommendedFeeInterval = "10s" +MaxSQLConnections = 100 +SQLConnectionTimeout = "2s" + +[StateDB] +Path = "/var/hermez/statedb" +Keep = 256 + +[PostgreSQL] +PortWrite = 5432 +HostWrite = "localhost" +UserWrite = "hermez" +PasswordWrite = "yourpasswordhere" +NameWrite = "hermez" +# PortRead = 5432 +# HostRead = "localhost" +# UserRead = "hermez" +# PasswordRead = "yourpasswordhere" +# NameRead = "hermez" + +[Web3] +URL = "http://localhost:8545" + +[Synchronizer] +SyncLoopInterval = "1s" +StatsUpdateBlockNumDiffThreshold = 100 +StatsUpdateFrequencyDivider = 100 + +[SmartContracts] +Rollup = "0xA68D85dF56E733A06443306A095646317B5Fa633" + +[Coordinator] +ForgerAddress = "0x05c23b938a85ab26A36E6314a0D02080E9ca6BeD" # Non-Boot Coordinator +MinimumForgeAddressBalance = "0" +ConfirmBlocks = 5 +L1BatchTimeoutPerc = 0.00001 +StartSlotBlocksDelay = 0 +ScheduleBatchBlocksAheadCheck = 0 +SendBatchBlocksMarginCheck = 0 +ProofServerPollInterval = "1s" +ForgeRetryInterval = "10s" +SyncRetryInterval = "1s" +ForgeDelay = "600s" +ForgeNoTxsDelay = "86400s" +PurgeByExtDelInterval = "1m" +MustForgeAtSlotDeadline = true +IgnoreSlotCommitment = true +ForgeOncePerSlotIfTxs = false + +[Coordinator.FeeAccount] +Address = "0x56232B1c5B10038125Bc7345664B4AFD745bcF8E" +BJJ = "0x130c5c7f294792559f469220274f3d3b2dca6e89f4c5ec88d3a08bf73262171b" + +[Coordinator.L2DB] +SafetyPeriod = 10 +MaxTxs = 1000000 +MinFeeUSD = 0.10 +MaxFeeUSD = 10.00 +TTL = "24h" +PurgeBatchDelay = 10 +InvalidateBatchDelay = 20 +PurgeBlockDelay = 10 +InvalidateBlockDelay = 20 + +[Coordinator.TxSelector] +Path = "/var/hermez/txselector" + +[Coordinator.BatchBuilder] +Path = "/var/hermez/batchbuilder" + +[Coordinator.ServerProofs] +URLs = ["http://localhost:3000"] + +[Coordinator.Circuit] +MaxTx = 2048 +NLevels = 32 + +[Coordinator.EthClient] +CheckLoopInterval = "500ms" +Attempts = 4 +AttemptsDelay = "500ms" +TxResendTimeout = "2m" +NoReuseNonce = false +MaxGasPrice = 500 +MinGasPrice = 5 +GasPriceIncPerc = 5 + +[Coordinator.EthClient.Keystore] +Path = "/var/hermez/ethkeystore" +Password = "yourpasswordhere" + +[Coordinator.EthClient.ForgeBatchGasCost] +Fixed = 900000 +L1UserTx = 15000 +L1CoordTx = 7000 +L2Tx = 600 + +[Coordinator.API] +Coordinator = true + +[RecommendedFeePolicy] +PolicyType = "Static" +StaticValue = 0.10 +` diff --git a/coordinator/coordinator_test.go b/coordinator/coordinator_test.go index 7f6de58c1..a14f7e07d 100644 --- a/coordinator/coordinator_test.go +++ b/coordinator/coordinator_test.go @@ -115,7 +115,7 @@ func newTestModules(t *testing.T) modules { var bjj babyjub.PublicKeyComp err = bjj.UnmarshalText([]byte("c433f7a696b7aa3a5224efb3993baf0ccd9e92eecee0c29a3f6c8208a9e81d9e")) require.NoError(t, err) - coordAccount := txselector.CoordAccount{ // TODO TMP + coordAccount := txselector.CoordAccount{ Addr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), BJJ: bjj, AccountCreationAuth: nil, @@ -590,9 +590,3 @@ func TestCoordinatorStress(t *testing.T) { closeTestModules(t, modules) } - -// TODO: Test Reorg -// TODO: Test TxMonitor -// TODO: Test forgeBatch -// TODO: Test waitServerProof -// TODO: Test handleReorg diff --git a/coordinator/pipeline.go b/coordinator/pipeline.go index 8ab880749..ff86c53ce 100644 --- a/coordinator/pipeline.go +++ b/coordinator/pipeline.go @@ -22,7 +22,6 @@ import ( "github.com/hermeznetwork/tracerr" ) -// TODO: add this timeout to config file? const proverWaitReadyTimeout = 20 * time.Second type statsVars struct { diff --git a/coordinator/purger.go b/coordinator/purger.go index bf748a11d..938794cb5 100644 --- a/coordinator/purger.go +++ b/coordinator/purger.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db/l2db" "github.com/hermeznetwork/hermez-node/db/statedb" "github.com/hermeznetwork/hermez-node/log" @@ -93,7 +94,7 @@ func (p *Purger) InvalidateMaybe(l2DB *l2db.L2DB, stateDB *statedb.LocalStateDB, //nolint:unused,deadcode func idxsNonceFromL2Txs(txs []common.L2Tx) []common.IdxNonce { - idxNonceMap := map[common.Idx]common.Nonce{} + idxNonceMap := map[common.Idx]nonce.Nonce{} for _, tx := range txs { if nonce, ok := idxNonceMap[tx.FromIdx]; !ok { idxNonceMap[tx.FromIdx] = tx.Nonce @@ -109,7 +110,7 @@ func idxsNonceFromL2Txs(txs []common.L2Tx) []common.IdxNonce { } func idxsNonceFromPoolL2Txs(txs []common.PoolL2Tx) []common.IdxNonce { - idxNonceMap := map[common.Idx]common.Nonce{} + idxNonceMap := map[common.Idx]nonce.Nonce{} for _, tx := range txs { if nonce, ok := idxNonceMap[tx.FromIdx]; !ok { idxNonceMap[tx.FromIdx] = tx.Nonce diff --git a/coordinator/purger_test.go b/coordinator/purger_test.go index b255464aa..885d4b01e 100644 --- a/coordinator/purger_test.go +++ b/coordinator/purger_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" dbUtils "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db/l2db" "github.com/hermeznetwork/hermez-node/db/statedb" @@ -151,10 +152,10 @@ func TestIdxsNonce(t *testing.T) { {Idx: 258, Nonce: 5}, {Idx: 258, Nonce: 2}, } - expectedIdxsNonce := map[common.Idx]common.Nonce{ - common.Idx(256): common.Nonce(2), - common.Idx(257): common.Nonce(3), - common.Idx(258): common.Nonce(5), + expectedIdxsNonce := map[common.Idx]nonce.Nonce{ + common.Idx(256): nonce.Nonce(2), + common.Idx(257): nonce.Nonce(3), + common.Idx(258): nonce.Nonce(5), } l2txs := make([]common.L2Tx, len(inputIdxsNonce)) @@ -236,10 +237,10 @@ func TestPoolMarkInvalidOldNonces(t *testing.T) { // invalid for name, user := range tc.Users { for _, _acc := range user.Accounts { - require.Equal(t, common.Nonce(nonces0[name]), _acc.Nonce) // sanity check + require.Equal(t, nonce.Nonce(nonces0[name]), _acc.Nonce) // sanity check acc, err := stateDB.GetAccount(_acc.Idx) require.NoError(t, err) - require.Equal(t, common.Nonce(0), acc.Nonce) // sanity check + require.Equal(t, nonce.Nonce(0), acc.Nonce) // sanity check acc.Nonce = _acc.Nonce _, err = stateDB.UpdateAccount(acc.Idx, acc) require.NoError(t, err) @@ -266,10 +267,10 @@ func TestPoolMarkInvalidOldNonces(t *testing.T) { for name, user := range tc.Users { for _, _acc := range user.Accounts { - require.Equal(t, common.Nonce(nonces1[name]), _acc.Nonce) // sanity check + require.Equal(t, nonce.Nonce(nonces1[name]), _acc.Nonce) // sanity check acc, err := stateDB.GetAccount(_acc.Idx) require.NoError(t, err) - require.Equal(t, common.Nonce(nonces0[name]), acc.Nonce) // sanity check + require.Equal(t, nonce.Nonce(nonces0[name]), acc.Nonce) // sanity check } } diff --git a/coordinator/txmanager.go b/coordinator/txmanager.go index 7aba96482..cb83b3548 100644 --- a/coordinator/txmanager.go +++ b/coordinator/txmanager.go @@ -424,9 +424,6 @@ func (t *TxManager) handleReceipt(ctx context.Context, batchInfo *BatchInfo) (*i return nil, nil } -// TODO: -// - After sending a message: CancelPipeline, stop all consecutive pending Batches (transactions) - // Queue of BatchInfos type Queue struct { list []*BatchInfo diff --git a/db/historydb/apiqueries.go b/db/historydb/apiqueries.go index dc53c04d1..115aaa418 100644 --- a/db/historydb/apiqueries.go +++ b/db/historydb/apiqueries.go @@ -8,8 +8,9 @@ import ( "time" ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" @@ -1137,7 +1138,7 @@ func (hdb *HistoryDB) GetCommonAccountAPI(idx common.Idx) (*common.Account, erro BatchNum common.BatchNum `meddler:"batch_num"` BJJ babyjub.PublicKeyComp `meddler:"bjj"` EthAddr ethCommon.Address `meddler:"eth_addr"` - Nonce common.Nonce `meddler:"nonce"` + Nonce nonce.Nonce `meddler:"nonce"` Balance *big.Int `meddler:"balance,bigint"` // max of 192 bits used } account := &fullAccount{} diff --git a/db/historydb/historydb.go b/db/historydb/historydb.go index e468b39a1..66af84233 100644 --- a/db/historydb/historydb.go +++ b/db/historydb/historydb.go @@ -37,8 +37,6 @@ import ( "github.com/russross/meddler" ) -// TODO(Edu): Document here how HistoryDB is kept consistent - // HistoryDB persist the historic of the rollup type HistoryDB struct { dbRead *sqlx.DB @@ -288,7 +286,6 @@ func (hdb *HistoryDB) addBids(d meddler.DB, bids []common.Bid) error { if len(bids) == 0 { return nil } - // TODO: check the coordinator info return tracerr.Wrap(db.BulkInsert( d, "INSERT INTO bid (slot_num, bid_value, eth_block_num, bidder_addr) VALUES %s;", @@ -489,26 +486,6 @@ func (hdb *HistoryDB) UpdateTokenValueByTokenID(tokenID uint, value float64) err return tracerr.Wrap(err) } -// UpdateFiatPrice updates the USD value per currency -func (hdb *HistoryDB) UpdateFiatPrice(currency string, baseCurrency string, price float64) error { - // last_update field is gonna be updated automatically by the trigger trigger_fiat_price_update - _, err := hdb.dbWrite.Exec( - "UPDATE fiat SET price = $1 WHERE currency = $2 AND base_currency = $3;", - price, currency, baseCurrency, - ) - return tracerr.Wrap(err) -} - -// CreateFiatPrice creates a new entry for a new currency or pair currency/baseCurrency -func (hdb *HistoryDB) CreateFiatPrice(currency string, baseCurrency string, price float64) error { - // last_update field is gonna be filled automatically by the trigger trigger_fiat_price_update - _, err := hdb.dbWrite.Exec( - "INSERT INTO fiat(currency, base_currency, price) VALUES ($1, $2, $3);", - currency, baseCurrency, price, - ) - return tracerr.Wrap(err) -} - // GetFiatPrice recover the price for a currency func (hdb *HistoryDB) GetFiatPrice(currency, baseCurrency string) (FiatCurrency, error) { var currencyPrice = &FiatCurrency{} @@ -844,8 +821,6 @@ func (hdb *HistoryDB) GetUnforgedL1UserTxsCount() (int, error) { return count, tracerr.Wrap(row.Scan(&count)) } -// TODO: Think about chaning all the queries that return a last value, to queries that return the next valid value. - // GetLastTxsPosition for a given to_forge_l1_txs_num func (hdb *HistoryDB) GetLastTxsPosition(toForgeL1TxsNum int64) (int, error) { row := hdb.dbRead.QueryRow( diff --git a/db/historydb/historydb_test.go b/db/historydb/historydb_test.go index 19e1f6bd7..95d3ebffa 100644 --- a/db/historydb/historydb_test.go +++ b/db/historydb/historydb_test.go @@ -11,8 +11,9 @@ import ( "time" ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" + "github.com/hermeznetwork/hermez-node/common/nonce" dbUtils "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/test" @@ -376,7 +377,7 @@ func TestAccounts(t *testing.T) { EthBlockNum: batches[acc.BatchNum-1].EthBlockNum, BatchNum: acc.BatchNum, Idx: acc.Idx, - Nonce: common.Nonce(i), + Nonce: nonce.Nonce(i), Balance: big.NewInt(int64(i)), } } @@ -547,7 +548,7 @@ func TestTxs(t *testing.T) { assert.Equal(t, common.TokenID(2), dbL1Txs[9].TokenID) // Batch Number - var bn common.BatchNum = common.BatchNum(2) + var bn = common.BatchNum(2) assert.Equal(t, &bn, dbL1Txs[0].BatchNum) assert.Equal(t, &bn, dbL1Txs[1].BatchNum) @@ -1246,7 +1247,7 @@ func TestGetMetricsAPIMoreThan24Hours(t *testing.T) { err = tc.FillBlocksExtra(blocks, &tilCfgExtra) require.NoError(t, err) - const numBatches int = 2 + numBlocks + const numBatches = 2 + numBlocks const blockNum = 4 + numBlocks // Sanity check @@ -1254,7 +1255,7 @@ func TestGetMetricsAPIMoreThan24Hours(t *testing.T) { // Adding one batch per block // batch frequency can be chosen - const blockTime time.Duration = 3600 * time.Second + const blockTime = 3600 * time.Second now := time.Now() require.NoError(t, err) @@ -1489,7 +1490,7 @@ func TestNodeInfo(t *testing.T) { require.NoError(t, err) // Test parameters - var f64 float64 = 1.2 + var f64 = 1.2 var i64 int64 = 8888 addr := ethCommon.HexToAddress("0x1234") hash := ethCommon.HexToHash("0x5678") diff --git a/db/historydb/nodeinfo.go b/db/historydb/nodeinfo.go index 06ecfc708..dd40ef665 100644 --- a/db/historydb/nodeinfo.go +++ b/db/historydb/nodeinfo.go @@ -4,8 +4,8 @@ import ( "time" ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" "github.com/hermeznetwork/tracerr" "github.com/russross/meddler" ) diff --git a/db/historydb/views.go b/db/historydb/views.go index b78563146..efdbc7c13 100644 --- a/db/historydb/views.go +++ b/db/historydb/views.go @@ -6,8 +6,9 @@ import ( "time" ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/iden3/go-iden3-crypto/babyjub" "github.com/iden3/go-merkletree" ) @@ -47,7 +48,7 @@ type ExitAPIJSON struct { type AccountAPIJSON struct { ItemID uint64 `json:"itemId"` AccountIndex apitypes.HezIdx `json:"accountIndex"` - Nonce common.Nonce `json:"nonce"` + Nonce nonce.Nonce `json:"nonce"` Balance *apitypes.BigIntStr `json:"balance"` Bjj apitypes.HezBJJ `json:"bjj"` HezEthereumAddress apitypes.HezEthAddr `json:"hezEthereumAddress"` @@ -94,7 +95,7 @@ type L1infoJSON struct { type L2infoJSON struct { Fee *common.FeeSelector `json:"fee"` HistoricFeeUSD *float64 `json:"historicFeeUSD"` - Nonce *common.Nonce `json:"nonce"` + Nonce *nonce.Nonce `json:"nonce"` } // TxAPI is a representation of a generic Tx with additional information @@ -126,7 +127,7 @@ type TxAPI struct { // L2 Fee *common.FeeSelector `meddler:"fee"` HistoricFeeUSD *float64 `meddler:"fee_usd"` - Nonce *common.Nonce `meddler:"nonce"` + Nonce *nonce.Nonce `meddler:"nonce"` // API extras Timestamp time.Time `meddler:"timestamp,utctime"` TotalItems uint64 `meddler:"total_items"` @@ -230,7 +231,7 @@ type txWrite struct { DepositAmountFloat *float64 `meddler:"deposit_amount_f"` // L2 Fee *common.FeeSelector `meddler:"fee"` - Nonce *common.Nonce `meddler:"nonce"` + Nonce *nonce.Nonce `meddler:"nonce"` } // TokenSymbolAndAddr token representation with only Eth addr and symbol @@ -342,7 +343,7 @@ type AccountAPI struct { BatchNum common.BatchNum `meddler:"batch_num"` PublicKey apitypes.HezBJJ `meddler:"bjj"` EthAddr apitypes.HezEthAddr `meddler:"eth_addr"` - Nonce common.Nonce `meddler:"nonce"` // max of 40 bits used + Nonce nonce.Nonce `meddler:"nonce"` // max of 40 bits used Balance *apitypes.BigIntStr `meddler:"balance"` // max of 192 bits used TotalItems uint64 `meddler:"total_items"` FirstItem uint64 `meddler:"first_item"` diff --git a/db/l2db/apiqueries.go b/db/l2db/apiqueries.go index 7d84c740f..c0fb89a0a 100644 --- a/db/l2db/apiqueries.go +++ b/db/l2db/apiqueries.go @@ -6,6 +6,8 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" @@ -53,6 +55,16 @@ func (l2db *L2DB) AddTxAPI(tx *common.PoolL2Tx) error { } defer l2db.apiConnCon.Release() // Check fee is in range + if err = l2db.checkFeeIsInRange(tx); err != nil { + return tracerr.Wrap(err) + } + // Add tx if pool is not full + return tracerr.Wrap( + l2db.addTxs([]common.PoolL2Tx{*tx}, true), + ) +} + +func (l2db *L2DB) checkFeeIsInRange(tx *common.PoolL2Tx) error { row := l2db.dbRead.QueryRow(`SELECT ($1::NUMERIC * COALESCE(token.usd, 0) * fee_percentage($2::NUMERIC)) / (10.0 ^ token.decimals::NUMERIC) @@ -63,17 +75,39 @@ func (l2db *L2DB) AddTxAPI(tx *common.PoolL2Tx) error { return tracerr.Wrap(err) } if feeUSD < l2db.minFeeUSD { - return tracerr.Wrap(fmt.Errorf("tx.feeUSD (%v) < minFeeUSD (%v)", - feeUSD, l2db.minFeeUSD)) + return fmt.Errorf("tx.feeUSD (%v) < minFeeUSD (%v)", + feeUSD, l2db.minFeeUSD) } if feeUSD > l2db.maxFeeUSD { - return tracerr.Wrap(fmt.Errorf("tx.feeUSD (%v) > maxFeeUSD (%v)", - feeUSD, l2db.maxFeeUSD)) + return fmt.Errorf("tx.feeUSD (%v) > maxFeeUSD (%v)", + feeUSD, l2db.maxFeeUSD) } - // Add tx if pool is not full - return tracerr.Wrap( - l2db.addTxs([]common.PoolL2Tx{*tx}, true), - ) + return nil +} + +// UpdateTxByIdxAndNonceAPI upadte PoolL2Tx regular transaction in the pool by account idx and nonce +func (l2db *L2DB) UpdateTxByIdxAndNonceAPI(idx common.Idx, nonce nonce.Nonce, tx *common.PoolL2Tx) error { + cancel, err := l2db.apiConnCon.Acquire() + defer cancel() + if err != nil { + return tracerr.Wrap(err) + } + defer l2db.apiConnCon.Release() + if err = l2db.checkFeeIsInRange(tx); err != nil { + return tracerr.Wrap(err) + } + return tracerr.Wrap(l2db.updateTxByIdxAndNonce(idx, nonce, tx)) +} + +// UpdateTxAPI Update PoolL2Tx regular transactions in the pool. +func (l2db *L2DB) UpdateTxAPI(tx *common.PoolL2Tx) error { + cancel, err := l2db.apiConnCon.Acquire() + defer cancel() + if err != nil { + return tracerr.Wrap(err) + } + defer l2db.apiConnCon.Release() + return tracerr.Wrap(l2db.updateTx(*tx)) } // AddAtomicTxsAPI inserts transactions into the pool @@ -170,20 +204,21 @@ token.item_id AS token_item_id, token.eth_block_num, token.eth_addr, token.name, count(*) OVER() AS total_items FROM tx_pool INNER JOIN token ON tx_pool.token_id = token.token_id ` -// GetTxAPI return the specified Tx in PoolTxAPI format -func (l2db *L2DB) GetTxAPI(txID common.TxID) (*PoolTxAPI, error) { +// GetTxAPI return the specified Tx in TxL2 format +func (l2db *L2DB) GetTxAPI(txID common.TxID) (apitypes.TxL2, error) { cancel, err := l2db.apiConnCon.Acquire() defer cancel() + tx := new(poolTxAPIView) if err != nil { - return nil, tracerr.Wrap(err) + return tx.ToAPI(), tracerr.Wrap(err) } defer l2db.apiConnCon.Release() - tx := new(PoolTxAPI) - return tx, tracerr.Wrap(meddler.QueryRow( + err = tracerr.Wrap(meddler.QueryRow( l2db.dbRead, tx, selectPoolTxAPI+"WHERE tx_id = $1;", txID, )) + return tx.ToAPI(), err } // GetPoolTxsAPIRequest is an API request struct for getting txs from the pool @@ -207,7 +242,7 @@ type GetPoolTxsAPIRequest struct { } // GetPoolTxsAPI return Txs from the pool -func (l2db *L2DB) GetPoolTxsAPI(request GetPoolTxsAPIRequest) ([]PoolTxAPI, uint64, error) { +func (l2db *L2DB) GetPoolTxsAPI(request GetPoolTxsAPIRequest) ([]apitypes.TxL2, uint64, error) { cancel, err := l2db.apiConnCon.Acquire() defer cancel() if err != nil { @@ -359,22 +394,26 @@ func (l2db *L2DB) GetPoolTxsAPI(request GetPoolTxsAPIRequest) ([]PoolTxAPI, uint queryStr += fmt.Sprintf("LIMIT %d;", *request.Limit) query := l2db.dbRead.Rebind(queryStr) - txsPtrs := []*PoolTxAPI{} + txsPtrs := []*poolTxAPIView{} if err = meddler.QueryAll( l2db.dbRead, &txsPtrs, query, args...); err != nil { return nil, 0, tracerr.Wrap(err) } - txs := db.SlicePtrsToSlice(txsPtrs).([]PoolTxAPI) - if len(txs) == 0 { - return txs, 0, nil + txs := db.SlicePtrsToSlice(txsPtrs).([]poolTxAPIView) + retTxs := []apitypes.TxL2{} + for _, currentTx := range txs { + retTxs = append(retTxs, currentTx.ToAPI()) } - return txs, txs[0].TotalItems - uint64(len(txs)), tracerr.Wrap(err) + if len(retTxs) == 0 { + return retTxs, 0, nil + } + return retTxs, txs[0].TotalItems - uint64(len(txs)), tracerr.Wrap(err) } // GetPoolTxsByAtomicGroupIDAPI return Txs from the pool that belong to the given atomicGroupID -func (l2db *L2DB) GetPoolTxsByAtomicGroupIDAPI(atomicGroupID common.AtomicGroupID) ([]PoolTxAPI, error) { +func (l2db *L2DB) GetPoolTxsByAtomicGroupIDAPI(atomicGroupID common.AtomicGroupID) ([]apitypes.TxL2, error) { cancel, err := l2db.apiConnCon.Acquire() defer cancel() if err != nil { @@ -382,7 +421,7 @@ func (l2db *L2DB) GetPoolTxsByAtomicGroupIDAPI(atomicGroupID common.AtomicGroupI } defer l2db.apiConnCon.Release() - txsPtrs := []*PoolTxAPI{} + txsPtrs := []*poolTxAPIView{} if err := meddler.QueryAll( l2db.dbRead, &txsPtrs, selectPoolTxsAPI+" WHERE atomic_group_id = $1;", @@ -390,9 +429,13 @@ func (l2db *L2DB) GetPoolTxsByAtomicGroupIDAPI(atomicGroupID common.AtomicGroupI ); err != nil { return nil, tracerr.Wrap(err) } - txs := db.SlicePtrsToSlice(txsPtrs).([]PoolTxAPI) + txs := db.SlicePtrsToSlice(txsPtrs).([]poolTxAPIView) + retTxs := []apitypes.TxL2{} + for _, currentTx := range txs { + retTxs = append(retTxs, currentTx.ToAPI()) + } if len(txs) == 0 { - return txs, nil + return retTxs, nil } - return txs, nil + return retTxs, nil } diff --git a/db/l2db/l2db.go b/db/l2db/l2db.go index c3105ac7a..b492d9f95 100644 --- a/db/l2db/l2db.go +++ b/db/l2db/l2db.go @@ -18,6 +18,8 @@ In some cases, some of the structs defined in this file also include custom Mars package l2db import ( + "database/sql" + "errors" "fmt" "math/big" "strconv" @@ -25,6 +27,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" @@ -35,8 +38,6 @@ import ( "github.com/russross/meddler" ) -// TODO(Edu): Check DB consistency while there's concurrent use from Coordinator/TxSelector & API - // L2DB stores L2 txs and authorization registers received by the coordinator and keeps them until they are no longer relevant // due to them being forged or invalid after a safety period type L2DB struct { @@ -194,7 +195,7 @@ func (l2db *L2DB) addTxs(txs []common.PoolL2Tx, checkPoolIsFull bool) error { rqTokenID *common.TokenID rqAmount *string rqFee *common.FeeSelector - rqNonce *common.Nonce + rqNonce *nonce.Nonce rqOffset *uint8 atomicGroupID *common.AtomicGroupID maxNumBatch *uint32 @@ -274,13 +275,7 @@ func (l2db *L2DB) addTxs(txs []common.PoolL2Tx, checkPoolIsFull bool) error { " WHERE (SELECT COUNT (*) FROM tx_pool WHERE state = ? AND NOT external_delete) < ?;" // Check if the pool is full queryVars = append(queryVars, common.PoolL2TxStatePending, l2db.maxTxs) } else { - query += " VALUES " + queryVarsPart + " ON CONFLICT ON CONSTRAINT tx_id_unique DO UPDATE SET " + - "from_idx = excluded.from_idx, to_idx = excluded.to_idx, to_eth_addr = excluded.to_eth_addr, to_bjj = excluded.to_bjj," + - " token_id = excluded.token_id, amount = excluded.amount, fee = excluded.fee, nonce = excluded.nonce, state = excluded.state," + - "info = excluded.info, signature = excluded.signature, rq_from_idx = excluded.rq_from_idx, rq_to_idx = excluded.rq_to_idx, " + - "rq_to_bjj = excluded.rq_to_bjj, rq_token_id = excluded.rq_token_id, rq_amount = excluded.rq_amount, rq_fee = excluded.rq_fee, rq_nonce = excluded.rq_nonce," + - " tx_type = excluded.tx_type, amount_f = excluded.amount_f, client_ip = excluded.client_ip, " + - "rq_offset = excluded.rq_offset, max_num_batch = excluded.max_num_batch WHERE tx_pool.atomic_group_id IS NULL;" + query += " VALUES " + queryVarsPart + ";" } // Replace "?, ?, ... ?" ==> "$1, $2, ..., $(len(queryVars))" query = l2db.dbRead.Rebind(query) @@ -296,6 +291,102 @@ func (l2db *L2DB) addTxs(txs []common.PoolL2Tx, checkPoolIsFull bool) error { return tracerr.Wrap(err) } +// Update PoolL2Tx transaction in the pool +func (l2db *L2DB) updateTx(tx common.PoolL2Tx) error { + const queryUpdate = `UPDATE tx_pool SET to_idx = ?, to_eth_addr = ?, to_bjj = ?, max_num_batch = ?, + signature = ?, client_ip = ?, tx_type = ? WHERE tx_id = ? AND tx_pool.atomic_group_id IS NULL;` + + if tx.ToIdx == 0 && tx.ToEthAddr == common.EmptyAddr && tx.ToBJJ == common.EmptyBJJComp && tx.MaxNumBatch == 0 { + return tracerr.Wrap(errors.New("nothing to update")) + } + + queryVars := []interface{}{tx.ToIdx, tx.ToEthAddr, tx.ToBJJ, tx.MaxNumBatch, tx.Signature, tx.ClientIP, tx.Type, tx.TxID} + + query, args, err := sqlx.In(queryUpdate, queryVars...) + if err != nil { + return tracerr.Wrap(err) + } + + query = l2db.dbWrite.Rebind(query) + _, err = l2db.dbWrite.Exec(query, args...) + return tracerr.Wrap(err) +} + +func (l2db *L2DB) updateTxByIdxAndNonce(idx common.Idx, nonce nonce.Nonce, tx *common.PoolL2Tx) error { + txn, err := l2db.dbWrite.Beginx() + if err != nil { + return tracerr.Wrap(err) + } + defer func() { + if err != nil { + db.Rollback(txn) + } + }() + var ( + res sql.Result + queryVars []interface{} + rowsAffected int64 + ) + + const queryDelete = `DELETE FROM tx_pool WHERE from_idx = $1 AND nonce = $2 AND (state = $3 OR state = $4) AND atomic_group_id IS NULL AND NOT external_delete;` + if res, err = txn.Exec(queryDelete, idx, nonce, common.PoolL2TxStatePending, common.PoolL2TxStateInvalid); err != nil { + return tracerr.Wrap(err) + } + + if rowsAffected, err = res.RowsAffected(); err != nil || rowsAffected == 0 { + return tracerr.Wrap(sql.ErrNoRows) + } + + const queryInsertPart = `INSERT INTO tx_pool ( + tx_id, from_idx, to_idx, to_eth_addr, to_bjj, token_id, + amount, fee, nonce, state, info, signature, + tx_type, amount_f, client_ip, max_num_batch + )` + + var ( + toEthAddr *ethCommon.Address + toBJJ *babyjub.PublicKeyComp + info *string + maxNumBatch *uint32 + ) + + // AmountFloat + f := new(big.Float).SetInt(tx.Amount) + amountF, _ := f.Float64() + // ToEthAddr + if tx.ToEthAddr != common.EmptyAddr { + toEthAddr = &tx.ToEthAddr + } + // ToBJJ + if tx.ToBJJ != common.EmptyBJJComp { + toBJJ = &tx.ToBJJ + } + // MAxNumBatch + if tx.MaxNumBatch != 0 { + maxNumBatch = &tx.MaxNumBatch + } + + queryVarsPart := `(?::BYTEA, ?::BIGINT, ?::BIGINT, ?::BYTEA, ?::BYTEA, ?::INT, + ?::NUMERIC, ?::SMALLINT, ?::BIGINT, ?::CHAR(4), ?::VARCHAR, ?::BYTEA, + ?::VARCHAR(40), ?::NUMERIC, ?::VARCHAR, ?::BIGINT)` + + queryVars = append(queryVars, + tx.TxID, tx.FromIdx, tx.ToIdx, toEthAddr, toBJJ, tx.TokenID, + tx.Amount.String(), tx.Fee, tx.Nonce, tx.State, info, tx.Signature, + tx.Type, amountF, tx.ClientIP, maxNumBatch) + + query := queryInsertPart + " VALUES " + queryVarsPart + ";" + query = txn.Rebind(query) + res, err = txn.Exec(query, queryVars...) + if err != nil { + return tracerr.Wrap(err) + } + if rowsAffected, err = res.RowsAffected(); err != nil || rowsAffected == 0 { + return tracerr.Wrap(sql.ErrNoRows) + } + return tracerr.Wrap(txn.Commit()) +} + // selectPoolTxCommon select part of queries to get common.PoolL2Tx const selectPoolTxCommon = `SELECT tx_pool.tx_id, from_idx, to_idx, tx_pool.to_eth_addr, tx_pool.to_bjj, tx_pool.token_id, tx_pool.amount, tx_pool.fee, tx_pool.nonce, diff --git a/db/l2db/l2db_test.go b/db/l2db/l2db_test.go index f278d3c30..ce46ec1bb 100644 --- a/db/l2db/l2db_test.go +++ b/db/l2db/l2db_test.go @@ -10,6 +10,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" dbUtils "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/hermeznetwork/hermez-node/log" @@ -178,13 +179,13 @@ func TestAddTxTest(t *testing.T) { tx := &poolL2Txs[1] fetchedTx, err := l2DB.GetTx(tx.TxID) require.NoError(t, err) - assert.Equal(t, fetchedTx.TokenID, common.TokenID(2)) - tx.TokenID = common.TokenID(1) - err = l2DBWithACC.AddTxTest(tx) + assert.Equal(t, fetchedTx.ToIdx, tx.ToIdx) + tx.ToIdx = common.Idx(1) + err = l2DBWithACC.UpdateTxAPI(tx) require.NoError(t, err) fetchedTx, err = l2DB.GetTx(tx.TxID) require.NoError(t, err) - assert.Equal(t, fetchedTx.TokenID, common.TokenID(1)) + assert.Equal(t, fetchedTx.ToIdx, common.Idx(1)) } func TestAddTxAPI(t *testing.T) { @@ -482,11 +483,11 @@ func TestInvalidateOldNonces(t *testing.T) { require.NoError(t, err) // Update Accounts currentNonce var updateAccounts []common.IdxNonce - var currentNonce = common.Nonce(1) + var currentNonce = nonce.Nonce(1) for i := range accs { updateAccounts = append(updateAccounts, common.IdxNonce{ Idx: accs[i].Idx, - Nonce: common.Nonce(currentNonce), + Nonce: nonce.Nonce(currentNonce), }) } // Add txs to DB diff --git a/db/l2db/views.go b/db/l2db/views.go index d18060537..7cbec0eed 100644 --- a/db/l2db/views.go +++ b/db/l2db/views.go @@ -1,17 +1,17 @@ package l2db import ( - "encoding/json" "time" ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/hermeznetwork/hermez-node/api/apitypes" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/apitypes" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/iden3/go-iden3-crypto/babyjub" ) -// PoolTxAPI represents a L2 Tx pool with extra metadata used by the API -type PoolTxAPI struct { +// poolTxAPIView represents a L2 Tx pool with extra metadata used by the API +type poolTxAPIView struct { ItemID uint64 `meddler:"item_id"` TxID common.TxID `meddler:"tx_id"` FromIdx apitypes.HezIdx `meddler:"from_idx"` @@ -22,7 +22,7 @@ type PoolTxAPI struct { EffectiveToBJJ *apitypes.HezBJJ `meddler:"effective_to_bjj"` Amount apitypes.BigIntStr `meddler:"amount"` Fee common.FeeSelector `meddler:"fee"` - Nonce common.Nonce `meddler:"nonce"` + Nonce nonce.Nonce `meddler:"nonce"` State common.PoolL2TxState `meddler:"state"` MaxNumBatch uint32 `meddler:"max_num_batch,zeroisnull"` Info *string `meddler:"info"` @@ -36,66 +36,20 @@ type PoolTxAPI struct { RqTokenID *common.TokenID `meddler:"rq_token_id"` RqAmount *apitypes.BigIntStr `meddler:"rq_amount"` RqFee *common.FeeSelector `meddler:"rq_fee"` - RqNonce *common.Nonce `meddler:"rq_nonce"` + RqNonce *nonce.Nonce `meddler:"rq_nonce"` Type common.TxType `meddler:"tx_type"` - // Extra read fileds - BatchNum *common.BatchNum `meddler:"batch_num"` - Timestamp time.Time `meddler:"timestamp,utctime"` - TotalItems uint64 `meddler:"total_items"` - TokenID common.TokenID `meddler:"token_id"` - TokenItemID uint64 `meddler:"token_item_id"` - TokenEthBlockNum int64 `meddler:"eth_block_num"` - TokenEthAddr ethCommon.Address `meddler:"eth_addr"` - TokenName string `meddler:"name"` - TokenSymbol string `meddler:"symbol"` - TokenDecimals uint64 `meddler:"decimals"` - TokenUSD *float64 `meddler:"usd"` - TokenUSDUpdate *time.Time `meddler:"usd_update"` -} - -// MarshalJSON is used to neast some of the fields of PoolTxAPI -// without the need of auxiliar structs -func (tx PoolTxAPI) MarshalJSON() ([]byte, error) { - return json.Marshal(map[string]interface{}{ - "itemId": tx.ItemID, - "id": tx.TxID, - "type": tx.Type, - "fromAccountIndex": tx.FromIdx, - "fromHezEthereumAddress": tx.EffectiveFromEthAddr, - "fromBJJ": tx.EffectiveFromBJJ, - "toAccountIndex": tx.ToIdx, - "toHezEthereumAddress": tx.EffectiveToEthAddr, - "toBJJ": tx.EffectiveToBJJ, - "amount": tx.Amount, - "fee": tx.Fee, - "nonce": tx.Nonce, - "state": tx.State, - "maxNumBatch": tx.MaxNumBatch, - "info": tx.Info, - "errorCode": tx.ErrorCode, - "errorType": tx.ErrorType, - "signature": tx.Signature, - "timestamp": tx.Timestamp, - "requestFromAccountIndex": tx.RqFromIdx, - "requestToAccountIndex": tx.RqToIdx, - "requestToHezEthereumAddress": tx.RqToEthAddr, - "requestToBJJ": tx.RqToBJJ, - "requestTokenId": tx.RqTokenID, - "requestAmount": tx.RqAmount, - "requestFee": tx.RqFee, - "requestNonce": tx.RqNonce, - "token": map[string]interface{}{ - "id": tx.TokenID, - "itemId": tx.TokenItemID, - "ethereumBlockNum": tx.TokenEthBlockNum, - "ethereumAddress": tx.TokenEthAddr, - "name": tx.TokenName, - "symbol": tx.TokenSymbol, - "decimals": tx.TokenDecimals, - "USD": tx.TokenUSD, - "fiatUpdate": tx.TokenUSDUpdate, - }, - }) + BatchNum *common.BatchNum `meddler:"batch_num"` + Timestamp time.Time `meddler:"timestamp,utctime"` + TotalItems uint64 `meddler:"total_items"` + TokenID common.TokenID `meddler:"token_id"` + TokenItemID uint64 `meddler:"token_item_id"` + TokenEthBlockNum int64 `meddler:"eth_block_num"` + TokenEthAddr ethCommon.Address `meddler:"eth_addr"` + TokenName string `meddler:"name"` + TokenSymbol string `meddler:"symbol"` + TokenDecimals uint64 `meddler:"decimals"` + TokenUSD *float64 `meddler:"usd"` + TokenUSDUpdate *time.Time `meddler:"usd_update"` } // AccountCreationAuthAPI represents an account creation auth in the expected format by the API @@ -105,3 +59,48 @@ type AccountCreationAuthAPI struct { Signature apitypes.EthSignature `json:"signature" meddler:"signature" ` Timestamp time.Time `json:"timestamp" meddler:"timestamp,utctime"` } + +// ToAPI converts a poolTxAPIView into TxL2 +func (tx *poolTxAPIView) ToAPI() apitypes.TxL2 { + pooll2apilocal := apitypes.TxL2{ + ItemID: tx.ItemID, + TxID: tx.TxID, + Type: tx.Type, + FromIdx: tx.FromIdx, + EffectiveFromEthAddr: tx.EffectiveFromEthAddr, + EffectiveFromBJJ: tx.EffectiveFromBJJ, + ToIdx: tx.ToIdx, + EffectiveToEthAddr: tx.EffectiveToEthAddr, + EffectiveToBJJ: tx.EffectiveToBJJ, + Amount: tx.Amount, + Fee: tx.Fee, + Nonce: tx.Nonce, + State: tx.State, + MaxNumBatch: tx.MaxNumBatch, + BatchNum: tx.BatchNum, + Info: tx.Info, + ErrorCode: tx.ErrorCode, + ErrorType: tx.ErrorType, + Signature: tx.Signature, + Timestamp: tx.Timestamp, + RqFromIdx: tx.RqFromIdx, + RqToIdx: tx.RqToIdx, + RqToEthAddr: tx.RqToEthAddr, + RqToBJJ: tx.RqToBJJ, + RqTokenID: tx.RqTokenID, + RqAmount: tx.RqAmount, + RqFee: tx.RqFee, + RqNonce: tx.RqNonce, + } + pooll2apilocal.Token.TokenID = tx.TokenID + pooll2apilocal.Token.TokenItemID = tx.TokenItemID + pooll2apilocal.Token.TokenEthBlockNum = tx.TokenEthBlockNum + pooll2apilocal.Token.TokenEthAddr = tx.TokenEthAddr + pooll2apilocal.Token.TokenName = tx.TokenName + pooll2apilocal.Token.TokenSymbol = tx.TokenSymbol + pooll2apilocal.Token.TokenDecimals = tx.TokenDecimals + pooll2apilocal.Token.TokenUSD = tx.TokenUSD + pooll2apilocal.Token.TokenUSDUpdate = tx.TokenUSDUpdate + + return pooll2apilocal +} diff --git a/db/migrations/0008_test.go b/db/migrations/0008_test.go index 8490d1449..df4dd5e3a 100644 --- a/db/migrations/0008_test.go +++ b/db/migrations/0008_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" ) -// This migration creates the fiat table +// This migration updates the tx_pool table type migrationTest0008 struct{} @@ -86,7 +86,7 @@ func (m migrationTest0008) RunAssertsAfterMigrationUp(t *testing.T, db *sqlx.DB) } func (m migrationTest0008) RunAssertsAfterMigrationDown(t *testing.T, db *sqlx.DB) { - // check that the fiat table is not created and I can't insert data + // check that the new fields can't be inserted in tx_pool table const queryInsert = `INSERT INTO tx_pool (tx_id, from_idx, effective_from_eth_addr, diff --git a/db/migrations/0009.sql b/db/migrations/0009.sql new file mode 100644 index 000000000..1137bb6d6 --- /dev/null +++ b/db/migrations/0009.sql @@ -0,0 +1,20 @@ +-- +migrate Up +-- +migrate StatementBegin +CREATE OR REPLACE FUNCTION update_pool_tx() + RETURNS TRIGGER +AS +$BODY$ +BEGIN + NEW."effective_to_eth_addr" = NEW."to_eth_addr"; + NEW."effective_to_bjj" = NEW."to_bjj"; + RETURN NEW; +END; +$BODY$ +LANGUAGE plpgsql; +-- +migrate StatementEnd +CREATE TRIGGER trigger_update_pool_tx BEFORE UPDATE ON tx_pool +FOR EACH ROW EXECUTE PROCEDURE update_pool_tx(); + +-- +migrate Down +DROP TRIGGER IF EXISTS trigger_update_pool_tx ON tx_pool; +DROP FUNCTION IF EXISTS update_pool_tx(); \ No newline at end of file diff --git a/db/migrations/0009_test.go b/db/migrations/0009_test.go new file mode 100644 index 000000000..51a9d6c31 --- /dev/null +++ b/db/migrations/0009_test.go @@ -0,0 +1,180 @@ +package migrations_test + +import ( + "testing" + + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" +) + +type migrationTest0009 struct{} + +func (m migrationTest0009) InsertData(db *sqlx.DB) error { + return nil +} + +func (m migrationTest0009) RunAssertsAfterMigrationUp(t *testing.T, db *sqlx.DB) { + // Test that update to_eth_addr on tx_pool also affects effective_to_eth_addr + //Insert data in the tx_pool table + const queryInsert = `INSERT INTO tx_pool (tx_id, + from_idx, + effective_from_eth_addr, + effective_from_bjj, + to_idx, + to_eth_addr, + to_bjj, + effective_to_eth_addr, + effective_to_bjj, + token_id, + amount, + amount_f, + fee, + nonce, + state, + info, + signature, + "timestamp", + batch_num, + rq_from_idx, + rq_to_idx, + rq_to_eth_addr, + rq_to_bjj, + rq_token_id, + rq_amount, + rq_fee, + rq_nonce, + tx_type, + client_ip, + external_delete, + item_id, + error_code, + error_type) VALUES(decode('03A193BC53932580F2EF91B5DA038AF611D9F1D896D518CDD65B1D766CBD835E30','hex'), + 3142, + decode('380ED8BD696C78395FB1961BDA42739D2F5242A1','hex'), + decode('CA780AF6B4C6164157DF737CE3E1E0A29EC9523F5B2CB4ADC26560379BFD5080','hex'), + NULL, + decode('15868E0C2DFC14A47FFC7360A93ADDC994386B11','hex'), + NULL, + decode('15868E0C2DFC14A47FFC7360A93ADDC994386B11','hex'), + NULL, + 0, + 34565432000000, + 34565432000000, + 20, + 28, + 'fged', + NULL, + decode('226B72179B58EC2D2106EAF40D828DF31F1FA92F2ED7DAC263E04259BDCE3085C803B7EC7F57E44E0C63234E52BFD28404332204B2F53A4589CB0B83531B0B05','hex'), + '2021-07-16 10:19:15.671', + 6164, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'TransferToEthAddr', + '95.127.153.55', + false, + 28494, + 15, + 'ErrToIdxNotFound'); + ` + _, err := db.Exec(queryInsert) + assert.NoError(t, err) + const queryGetNumberItems = `select count(*) from tx_pool;` + row := db.QueryRow(queryGetNumberItems) + var result int + assert.NoError(t, row.Scan(&result)) + assert.Equal(t, 1, result) + const queryUpdate = `UPDATE tx_pool SET to_eth_addr = 'hez:0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf' WHERE tx_id = decode('03A193BC53932580F2EF91B5DA038AF611D9F1D896D518CDD65B1D766CBD835E30','hex')` + _, err = db.Exec(queryUpdate) + assert.NoError(t, err) + const getQuery = `SELECT COUNT(*) FROM tx_pool WHERE effective_to_eth_addr = 'hez:0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf'` + row = db.QueryRow(getQuery) + assert.NoError(t, row.Scan(&result)) + assert.Equal(t, 1, result) + const queryDelete = `DELETE FROM tx_pool WHERE tx_id = decode('03A193BC53932580F2EF91B5DA038AF611D9F1D896D518CDD65B1D766CBD835E30','hex')` + _, err = db.Exec(queryDelete) + assert.NoError(t, err) + row = db.QueryRow(getQuery) + assert.NoError(t, row.Scan(&result)) + assert.Equal(t, 0, result) +} + +func (m migrationTest0009) RunAssertsAfterMigrationDown(t *testing.T, db *sqlx.DB) { + // Test that update on tx_pool doesn't affect effective_to_eth_addr + // Insert data in the tx_pool table + const queryInsert = `INSERT INTO tx_pool (tx_id, + from_idx, + effective_from_eth_addr, + effective_from_bjj, + to_idx, + to_eth_addr, + to_bjj, + effective_to_eth_addr, + effective_to_bjj, + token_id, + amount, + amount_f, + fee, + nonce, + state, + info, + signature, + "timestamp", + batch_num, + rq_from_idx, + rq_to_idx, + rq_to_eth_addr, + rq_to_bjj, + rq_token_id, + rq_amount, + rq_fee, + rq_nonce, + tx_type, + client_ip, + external_delete, + item_id, + error_code, + error_type) VALUES(decode('03A193BC53932580F2EF91B5DA038AF611D9F1D896D518CDD65B1D766CBD835E30','hex'), + 3142, + decode('380ED8BD696C78395FB1961BDA42739D2F5242A1','hex'), + decode('CA780AF6B4C6164157DF737CE3E1E0A29EC9523F5B2CB4ADC26560379BFD5080','hex'), + NULL, + decode('15868E0C2DFC14A47FFC7360A93ADDC994386B11','hex'), + NULL, + decode('15868E0C2DFC14A47FFC7360A93ADDC994386B11','hex'), + NULL, + 0, + 34565432000000, + 34565432000000, + 20, + 28, + 'fged', + NULL, + decode('226B72179B58EC2D2106EAF40D828DF31F1FA92F2ED7DAC263E04259BDCE3085C803B7EC7F57E44E0C63234E52BFD28404332204B2F53A4589CB0B83531B0B05','hex'), + '2021-07-16 10:19:15.671', + 6164, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + 'TransferToEthAddr', + '95.127.153.55', + false, + 28494, + 15, + 'ErrToIdxNotFound'); + ` + _, err := db.Exec(queryInsert) + assert.NoError(t, err) + const queryGetNumberItems = `select count(*) from tx_pool;` + row := db.QueryRow(queryGetNumberItems) + var result int + assert.NoError(t, row.Scan(&result)) + assert.Equal(t, 1, result) + const queryUpdate = `UPDATE tx_pool SET to_eth_addr = 'hez:0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf' WHERE tx_id = decode('03A193BC53932580F2EF91B5DA038AF611D9F1D896D518CDD65B1D766CBD835E30','hex')` + _, err = db.Exec(queryUpdate) + assert.NoError(t, err) + const getQuery = `SELECT COUNT(*) FROM tx_pool WHERE effective_to_eth_addr = 'hez:0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf'` + row = db.QueryRow(getQuery) + assert.NoError(t, row.Scan(&result)) + assert.Equal(t, 0, result) +} + +func TestMigration0009(t *testing.T) { + runMigrationTest(t, 9, migrationTest0009{}) +} diff --git a/db/statedb/statedb_test.go b/db/statedb/statedb_test.go index 3b89509dc..684320e51 100644 --- a/db/statedb/statedb_test.go +++ b/db/statedb/statedb_test.go @@ -13,6 +13,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" ethCrypto "github.com/ethereum/go-ethereum/crypto" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" @@ -48,7 +49,7 @@ func newAccount(t *testing.T, i int) *common.Account { return &common.Account{ Idx: common.Idx(256 + i), TokenID: common.TokenID(i), - Nonce: common.Nonce(i), + Nonce: nonce.Nonce(i), Balance: big.NewInt(1000), BJJ: pk.Compress(), EthAddr: address, @@ -523,7 +524,7 @@ func TestCheckAccountsTreeTestVectors(t *testing.T) { TokenID: 0xFFFFFFFF, BJJ: bjj0, EthAddr: ethCommon.HexToAddress("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), - Nonce: common.Nonce(0xFFFFFFFFFF), + Nonce: nonce.Nonce(0xFFFFFFFFFF), Balance: bigFromStr("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16), }, { @@ -531,7 +532,7 @@ func TestCheckAccountsTreeTestVectors(t *testing.T) { TokenID: 0, BJJ: bjj1, EthAddr: ethCommon.HexToAddress("0x00"), - Nonce: common.Nonce(0), + Nonce: nonce.Nonce(0), Balance: bigFromStr("0", 10), }, { @@ -539,7 +540,7 @@ func TestCheckAccountsTreeTestVectors(t *testing.T) { TokenID: 3, BJJ: bjj2, EthAddr: ethCommon.HexToAddress("0xA3C88ac39A76789437AED31B9608da72e1bbfBF9"), - Nonce: common.Nonce(129), + Nonce: nonce.Nonce(129), Balance: bigFromStr("42000000000000000000", 10), }, { @@ -547,7 +548,7 @@ func TestCheckAccountsTreeTestVectors(t *testing.T) { TokenID: 1000, BJJ: bjj3, EthAddr: ethCommon.HexToAddress("0x64"), - Nonce: common.Nonce(1900), + Nonce: nonce.Nonce(1900), Balance: bigFromStr("14000000000000000000", 10), }, } diff --git a/doc/info-to-run-integration-tests-hermez-node.md b/doc/info-to-run-integration-tests-hermez-node.md new file mode 100644 index 000000000..b679a60b2 --- /dev/null +++ b/doc/info-to-run-integration-tests-hermez-node.md @@ -0,0 +1,40 @@ +## Notes +- Access to AWS to download docker containers + - https://www.notion.so/AWS-info-0f116600256c4370b8d9f2be47f961ba +- The very first time to run it, it takes a while since docker is downloading all proper docker images + - **IMPORTANT NOTICE**: there is the line in the script, that deletes every docker image, container and network on the machine. + If you don't want it, delete or comment this line in the script - https://github.com/hermeznetwork/integration-testing/blob/main/scripts/it_local_launcher.sh#L60 +- Ports that should available + - https://github.com/hermeznetwork/integration-testing#issues + - careful with docker and VPN, database port could also break if you have automatically running postgresDb on your machine +- See docker containers running in your machine: + - `docker ps` +- See docker container logs in runtime: + - `docker logs -f #docker_name` + - Example: `docker logs -f docker_hermez-node_1` +- See logs file generated in: https://github.com/hermeznetwork/integration-testing/tree/main/test#logs-tests + +# Run specific hermez-node on integration-testing + +#### Requirements + +- Tools: docker, docker-compose, npm v7.0+, nodejs v14.0+, aws cli 2.0+, git, jq +- Set up as env vars AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY with vars +from paragraph *To push/pull images (hermez-docker user)* +from there https://www.notion.so/AWS-info-0f116600256c4370b8d9f2be47f961ba +- Make sure you have all requirements set up, including AWS variables + +##### Run those commands to launch integration test: +``` +git clone git@github.com:hermeznetwork/integration-testing.git +cd integration-testing +npm i +make build-hermezjs +npm run pretest + +// change commit hermez-node in https://github.com/hermeznetwork/integration-testing/blob/main/Makefile#L8 + +make build-hermez-node +mkdir log +DEV_PERIOD=3 MODE=coord npx mocha ./test/**/*.mochatest.js --exit > "log/report.txt" 2>&1 +``` \ No newline at end of file diff --git a/eth/ethereum.go b/eth/ethereum.go index 04995368c..6ae169fbe 100644 --- a/eth/ethereum.go +++ b/eth/ethereum.go @@ -14,7 +14,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/hermeznetwork/hermez-node/common" - tokenhez "github.com/hermeznetwork/hermez-node/eth/contracts/tokenhez" + "github.com/hermeznetwork/hermez-node/eth/contracts/tokenhez" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/tracerr" ) @@ -48,7 +48,7 @@ var ( // ErrAccountNil is used when the calls can not be made because the account is nil ErrAccountNil = fmt.Errorf("Authorized calls can't be made when the account is nil") // ErrBlockHashMismatchEvent is used when there's a block hash mismatch - // beetween different events of the same block + // between different events of the same block ErrBlockHashMismatchEvent = fmt.Errorf("block hash mismatch in event log") ) @@ -129,8 +129,23 @@ func (c *EthereumClient) EthAddress() (*ethCommon.Address, error) { // EthSuggestGasPrice retrieves the currently suggested gas price to allow a // timely execution of a transaction. -func (c *EthereumClient) EthSuggestGasPrice(ctx context.Context) (*big.Int, error) { - return c.client.SuggestGasPrice(ctx) +func (c *EthereumClient) EthSuggestGasPrice(ctx context.Context) (gasPrice *big.Int, err error) { + var head *types.Header + head, err = c.client.HeaderByNumber(ctx, nil) + if err != nil { + err = fmt.Errorf("[EthSuggestGasPrice]. Error getting head: %s", err.Error()) + return + } + var tip *big.Int + tip, err = c.client.SuggestGasTipCap(ctx) + if err != nil { + err = fmt.Errorf("[EthSuggestGasPrice]. Error getting tip: %s", err.Error()) + return + } + baseFee := head.BaseFee + gasPrice = new(big.Int).Add(baseFee, tip) + log.Debugw("Suggested Gas Price:", "tip", tip, "baseFee", baseFee, "gasPrice", gasPrice) + return } // EthKeyStore returns the keystore in the EthereumClient diff --git a/eth/rollup.go b/eth/rollup.go index 27d760ed9..a4b6ebcc2 100644 --- a/eth/rollup.go +++ b/eth/rollup.go @@ -1037,8 +1037,6 @@ func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash, numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes for i := 0; i < numFeeIdxCoordinator; i++ { var paddedFeeIdx [6]byte - // TODO: This check is not necessary: the first case will always work. Test it - // before removing the if. if lenFeeIdxCoordinatorBytes < common.IdxBytesLen { copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes]) diff --git a/go.mod b/go.mod index 46b008fab..38334b9cb 100644 --- a/go.mod +++ b/go.mod @@ -5,14 +5,15 @@ go 1.14 require ( github.com/BurntSushi/toml v0.3.1 github.com/btcsuite/btcd v0.22.0-beta // indirect + github.com/caarlos0/env/v6 v6.6.2 github.com/dghubble/sling v1.3.0 github.com/dimiro1/health v0.0.0-20191019130555-c5cbb4d46ffc github.com/ethereum/go-ethereum v1.10.4 github.com/getkin/kin-openapi v0.22.0 github.com/gin-contrib/cors v1.3.1 - github.com/gin-gonic/gin v1.5.0 + github.com/gin-gonic/gin v1.7.2 github.com/gobuffalo/packr/v2 v2.8.1 - github.com/hermeznetwork/hermez-go-sdk v0.1.1 + github.com/hermeznetwork/go-hermez-config v0.0.0-20210811071123-bf147fbf457c github.com/hermeznetwork/tracerr v0.3.1-0.20210120162744-5da60b576169 github.com/iden3/go-iden3-crypto v0.0.6-0.20210308142348-8f85683b2cef github.com/iden3/go-merkletree v0.0.0-20210308143313-8b63ca866189 @@ -25,6 +26,7 @@ require ( github.com/mitchellh/copystructure v1.0.0 github.com/mitchellh/mapstructure v1.3.0 github.com/prometheus/client_golang v1.3.0 + github.com/rjeczalik/notify v0.9.2 // indirect github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 github.com/russross/meddler v1.0.1 github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum index febdfad0a..307e8fb08 100644 --- a/go.sum +++ b/go.sum @@ -12,7 +12,6 @@ cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbf cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= @@ -40,7 +39,6 @@ github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EF github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= @@ -48,12 +46,10 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE= -github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -72,11 +68,7 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= -github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= -github.com/aristanetworks/goarista v0.0.0-20190912214011-b54698eaaca6/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= -github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -101,11 +93,9 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= -github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= @@ -123,6 +113,9 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= +github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs= +github.com/caarlos0/env/v6 v6.6.2 h1:BypLXDWQTA32rS4UM7pBz+/0BOuvs6C7LSeQAxMwyvI= +github.com/caarlos0/env/v6 v6.6.2/go.mod h1:P0BVSgU9zfkxfSpFUs6KsO3uWR4k3Ac0P66ibAGTybM= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -156,17 +149,12 @@ github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeS github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= -github.com/consensys/bavard v0.1.8-0.20210105233146-c16790d2aa8b/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= -github.com/consensys/goff v0.3.10/go.mod h1:xTldOBEHmFiYS0gPXd3NsaEqZWlnmeWcRLWgD3ba3xc= -github.com/consensys/gurvy v0.3.8/go.mod h1:sN75xnsiD593XnhbhvG2PkOy194pZBzqShWF/kwuW/g= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -203,7 +191,6 @@ github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbT github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -213,17 +200,13 @@ github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= -github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/go-ethereum v1.9.5/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= github.com/ethereum/go-ethereum v1.9.12/go.mod h1:PvsVkQmhZFx92Y+h2ylythYlheEDt/uBgFbl61Js/jo= -github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= -github.com/ethereum/go-ethereum v1.10.2/go.mod h1:YmSRTZNqAvVUg3BIG8uhT/BOkFk9+R2iCbxw5zOlnWY= github.com/ethereum/go-ethereum v1.10.4 h1:JPZPL2MHbegfFStcaOrrggMVIcf57OQHQ0J3UhjQ+xQ= github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= @@ -241,7 +224,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/garyburd/redigo v0.0.0-20160302234602-4ed1111375cb/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= @@ -258,6 +240,8 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= +github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA= +github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= @@ -277,10 +261,18 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -339,7 +331,6 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= @@ -384,9 +375,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -403,8 +392,6 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -412,20 +399,21 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hermeznetwork/hermez-go-sdk v0.1.1 h1:rXdjnekVOD26hkNTUwU7yr4rlj5hk5i0xoXJOtL3Z9s= -github.com/hermeznetwork/hermez-go-sdk v0.1.1/go.mod h1:IJUcE8mSHTAX0aucz0CxNwatWglvwmqh77fyvFqnEuw= -github.com/hermeznetwork/hermez-node v1.1.0/go.mod h1:cq4UzG6AqY+KTzgsIyU2/LggAYhUB/DHI7B+FGvg4nw= +github.com/hermeznetwork/go-hermez-config v0.0.0-20210728095630-35cecfa18aae h1:f+ZaDjB4tarcK1hOWqiRqxJzsVGBys03CUk2A3MBJe0= +github.com/hermeznetwork/go-hermez-config v0.0.0-20210728095630-35cecfa18aae/go.mod h1:oP5l93YlYArOFlp9t65C8+zDijAyDAurMY4gkkjFkwY= +github.com/hermeznetwork/go-hermez-config v0.0.0-20210811071123-bf147fbf457c h1:K5hE6gUsc+Yt76lzaiPIE4Wm0CXj+aIrPlKHTeFA5PY= +github.com/hermeznetwork/go-hermez-config v0.0.0-20210811071123-bf147fbf457c/go.mod h1:oP5l93YlYArOFlp9t65C8+zDijAyDAurMY4gkkjFkwY= +github.com/hermeznetwork/go-hermez-config v0.0.0-20210811083017-293d54cc5c47 h1:Y9/fFEZZ1yuZKfBnT4zNkmx7vBKpnNhQy6NuKw4K6MI= +github.com/hermeznetwork/go-hermez-config v0.0.0-20210811083017-293d54cc5c47/go.mod h1:oP5l93YlYArOFlp9t65C8+zDijAyDAurMY4gkkjFkwY= github.com/hermeznetwork/tracerr v0.3.1-0.20210120162744-5da60b576169 h1:I7zgVVlOgf+26yrrKKY9UT+9f73qqlNBGX6C9MPXnk4= github.com/hermeznetwork/tracerr v0.3.1-0.20210120162744-5da60b576169/go.mod h1:nsWC1+tc4qUEbUGRv4DcPJJTjLsedlPajlFmpJoohK4= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88 h1:bcAj8KroPf552TScjFPIakjH2/tdIrIH8F+cc4v4SRo= github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= @@ -440,7 +428,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= -github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= @@ -452,10 +439,8 @@ github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbk github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= -github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -474,6 +459,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= @@ -486,7 +473,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/karrick/godirwalk v1.15.8 h1:7+rWAZPn9zuRxaIqqT8Ohs2Q2Ac0msBqwRdxNCr2VVs= @@ -495,7 +481,6 @@ github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4 github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= -github.com/kilic/bls12-381 v0.0.0-20201226121925-69dacb279461/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -507,7 +492,6 @@ github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM52 github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -520,10 +504,11 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/leanovate/gopter v0.2.8/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= @@ -534,13 +519,13 @@ github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSD github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= @@ -554,6 +539,8 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -574,7 +561,6 @@ github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go. github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miguelmota/go-ethereum-hdwallet v0.0.0-20200123000308-a60dcd172b4c/go.mod h1:Z4zI+CdJB1fyrZ1jfevFH6flNV9izrLZnQAeuD6Wkjk= github.com/miguelmota/go-ethereum-hdwallet v0.0.0-20210626002539-518b14aa39c0 h1:4IKN6/Hdn2/8YZGWc9SXRpmbRpesMViHqRnxGiaI69I= github.com/miguelmota/go-ethereum-hdwallet v0.0.0-20210626002539-518b14aa39c0/go.mod h1:f9m9uXokAHA6WNoYOPjj4AqjJS5pquQRiYYj/XSyPYc= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -624,20 +610,16 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= -github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -659,7 +641,6 @@ github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHu github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= @@ -677,7 +658,6 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -697,7 +677,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -726,20 +705,17 @@ github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNue github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/meddler v1.0.0/go.mod h1:j75NzzcOL4CGy+pPKykxZoT/At5Qj4ZnRRs1PXxweZI= github.com/russross/meddler v1.0.1 h1:JLR7Z4M4iGm1nr7DIURBq18UW8cTrm+qArUFgOhELo8= github.com/russross/meddler v1.0.1/go.mod h1:GzGDChbFHuzxlFwt8gnJMRRNyFSQDSudmy2kHh7GYnQ= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -758,14 +734,11 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= @@ -783,23 +756,16 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/goleveldb v0.0.0-20180621010148-0d5a0ceb10cf/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= -github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= -github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tyler-smith/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= @@ -812,7 +778,6 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= @@ -822,16 +787,12 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= -github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yourbasic/graph v0.0.0-20210606180040-8ecfec1c2869 h1:7v7L5lsfw4w8iqBBXETukHo4IPltmD+mWoLRYUmeGN8= github.com/yourbasic/graph v0.0.0-20210606180040-8ecfec1c2869/go.mod h1:Rfzr+sqaDreiCaoQbFCu3sTXxeFq/9kXRuyOoSlGQHE= @@ -871,20 +832,17 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -894,7 +852,6 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= @@ -915,12 +872,10 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNT golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= @@ -949,14 +904,11 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= @@ -989,7 +941,6 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -999,38 +950,30 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1067,12 +1010,10 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1081,7 +1022,6 @@ golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= @@ -1148,14 +1088,12 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fatih/set.v0 v0.2.1/go.mod h1:5eLWEndGL4zGGemXWrKuts+wTJR0y+w+auqUJZbmyBg= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= @@ -1165,19 +1103,11 @@ gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvR gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= -gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= -gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= -gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= -gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= -gopkg.in/karalabe/cookiejar.v2 v2.0.0-20150724131613-8dcd6a7f4951/go.mod h1:owOxCRGGeAx1uugABik6K9oeNu1cgxP/R9ItzLDxNWA= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190213234257-ec84240a7772/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/node/node.go b/node/node.go index 8ca527d39..3b8cab6d6 100644 --- a/node/node.go +++ b/node/node.go @@ -44,7 +44,6 @@ import ( "github.com/hermeznetwork/hermez-node/eth" "github.com/hermeznetwork/hermez-node/etherscan" "github.com/hermeznetwork/hermez-node/log" - "github.com/hermeznetwork/hermez-node/priceupdater" "github.com/hermeznetwork/hermez-node/prover" "github.com/hermeznetwork/hermez-node/synchronizer" "github.com/hermeznetwork/hermez-node/test/debugapi" @@ -76,7 +75,6 @@ type Node struct { nodeAPI *NodeAPI stateAPIUpdater *stateapiupdater.Updater debugAPI *debugapi.DebugAPI - priceUpdater *priceupdater.PriceUpdater // Coordinator coord *coordinator.Coordinator @@ -348,9 +346,9 @@ func NewNode(mode Mode, cfg *config.Node, version string) (*Node, error) { log.Info("EtherScan method not configured in config file") etherScanService = nil } - serverProofs := make([]prover.Client, len(cfg.Coordinator.ServerProofs)) - for i, serverProofCfg := range cfg.Coordinator.ServerProofs { - serverProofs[i] = prover.NewProofServerClient(serverProofCfg.URL, + serverProofs := make([]prover.Client, len(cfg.Coordinator.ServerProofs.URLs)) + for i, serverProofCfg := range cfg.Coordinator.ServerProofs.URLs { + serverProofs[i] = prover.NewProofServerClient(serverProofCfg, cfg.Coordinator.ProofServerPollInterval.Duration) } @@ -471,22 +469,11 @@ func NewNode(mode Mode, cfg *config.Node, version string) (*Node, error) { if cfg.Debug.APIAddress != "" { debugAPI = debugapi.NewDebugAPI(cfg.Debug.APIAddress, stateDB, sync) } - priceUpdater, err := priceupdater.NewPriceUpdater( - cfg.PriceUpdater.Priority, - cfg.PriceUpdater.Provider, - cfg.PriceUpdater.Statictokens, - cfg.PriceUpdater.Fiat, - historyDB, - ) - if err != nil { - return nil, tracerr.Wrap(err) - } ctx, cancel := context.WithCancel(context.Background()) return &Node{ stateAPIUpdater: stateAPIUpdater, nodeAPI: nodeAPI, debugAPI: debugAPI, - priceUpdater: priceUpdater, coord: coord, sync: sync, cfg: cfg, @@ -661,8 +648,7 @@ func NewNodeAPI( // with cancellation. func (a *NodeAPI) Run(ctx context.Context) error { server := &http.Server{ - Handler: a.engine, - // TODO: Figure out best parameters for production + Handler: a.engine, ReadTimeout: 30 * time.Second, //nolint:gomnd WriteTimeout: 30 * time.Second, //nolint:gomnd MaxHeaderBytes: 1 << 20, //nolint:gomnd @@ -737,8 +723,6 @@ func (n *Node) handleReorg(ctx context.Context, stats *synchronizer.Stats, return nil } -// TODO(Edu): Consider keeping the `lastBlock` inside synchronizer so that we -// don't have to pass it around. func (n *Node) syncLoopFn(ctx context.Context, lastBlock *common.Block) (*common.Block, time.Duration, error) { blockData, discarded, err := n.sync.Sync(ctx, lastBlock) @@ -814,26 +798,6 @@ func (n *Node) StartSynchronizer() { } } }() - - n.wg.Add(1) - go func() { - for { - select { - case <-n.ctx.Done(): - log.Info("PriceUpdater done") - n.wg.Done() - return - case <-time.After(n.cfg.PriceUpdater.Interval.Duration): - if err := n.priceUpdater.UpdateFiatPrices(n.ctx); err != nil { - log.Errorw("PriceUpdater.UpdateFiatPrices()", "err", err) - } - if err := n.priceUpdater.UpdateTokenList(); err != nil { - log.Errorw("PriceUpdater.UpdateTokenList()", "err", err) - } - n.priceUpdater.UpdatePrices(n.ctx) - } - } - }() } // StartDebugAPI starts the DebugAPI diff --git a/priceupdater/priceupdater.go b/priceupdater/priceupdater.go deleted file mode 100644 index f5713cc4a..000000000 --- a/priceupdater/priceupdater.go +++ /dev/null @@ -1,453 +0,0 @@ -package priceupdater - -import ( - "context" - "fmt" - "net/http" - "strconv" - "strings" - "time" - - "github.com/dghubble/sling" - ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/hermeznetwork/hermez-node/common" - "github.com/hermeznetwork/hermez-node/db/historydb" - "github.com/hermeznetwork/hermez-node/log" - "github.com/hermeznetwork/tracerr" - "gopkg.in/go-playground/validator.v9" -) - -const ( - defaultMaxIdleConns = 10 - defaultIdleConnTimeout = 2 * time.Second -) - -const ( - // UpdateMethodTypeBitFinexV2 is the http API used by bitfinex V2 - UpdateMethodTypeBitFinexV2 string = "bitfinexV2" - // UpdateMethodTypeCoingeckoV3 is the http API used by copingecko V3 - UpdateMethodTypeCoingeckoV3 string = "CoinGeckoV3" - // UpdateMethodTypeIgnore indicates to not update the value, to set value 0 - // it's better to use UpdateMethodTypeStatic - UpdateMethodTypeIgnore string = "ignore" -) - -// Fiat definition -type Fiat struct { - APIKey string - URL string - BaseCurrency string - Currencies string -} - -// Provider definition -type Provider struct { - Provider string - BaseURL string - URL string - URLExtraParams string - SymbolsMap symbolsMap - AddressesMap addressesMap - Symbols string - Addresses string -} - -type staticMap struct { - Statictokens map[uint]float64 -} - -// strToStaticTokensMap converts Statictokens mapping from text. -func (d *staticMap) strToStaticTokensMap(str string) error { - var lastErr error - if str != "" { - mapping := make(map[uint]float64) - elements := strings.Split(str, ",") - for i := 0; i < len(elements); i++ { - values := strings.Split(elements[i], "=") - tokenID, err := strconv.Atoi(values[0]) - if err != nil { - log.Error("Error converting string to int. Avoiding element: ", elements[i]) - lastErr = err - continue - } - if price, err := strconv.ParseFloat(values[1], 64); err != nil { - log.Error("function strToStaticTokensMap. Error converting string to float64. Avoiding element: ", - elements[i], " Error: ", err) - lastErr = err - continue - } else { - mapping[uint(tokenID)] = price - } - } - d.Statictokens = mapping - log.Debug("StaticToken mapping from config file: ", mapping) - } - return lastErr -} - -type symbolsMap struct { - Symbols map[uint]string -} - -// strToMapSymbol converts Symbols mapping from text. -func (d *symbolsMap) strToMapSymbol(str string) error { - var lastErr error - if str != "" { - mapping := make(map[uint]string) - elements := strings.Split(str, ",") - for i := 0; i < len(elements); i++ { - values := strings.Split(elements[i], "=") - tokenID, err := strconv.Atoi(values[0]) - if err != nil { - log.Error("function strToMapSymbol. Error converting string to int. Avoiding element: ", elements[i]) - lastErr = err - continue - } - if values[1] == UpdateMethodTypeIgnore || values[1] == "" { - mapping[uint(tokenID)] = UpdateMethodTypeIgnore - } else { - mapping[uint(tokenID)] = values[1] - } - } - d.Symbols = mapping - log.Debug("Symbol mapping from config file: ", mapping) - } else { - d.Symbols = make(map[uint]string) - } - return lastErr -} - -type addressesMap struct { - Addresses map[uint]ethCommon.Address -} - -// strToMapAddress converts addresses mapping from text. -func (d *addressesMap) strToMapAddress(str string) error { - var lastErr error - if str != "" { - mapping := make(map[uint]ethCommon.Address) - elements := strings.Split(str, ",") - for i := 0; i < len(elements); i++ { - values := strings.Split(elements[i], "=") - tokenID, err := strconv.Atoi(values[0]) - if err != nil { - log.Error("function strToMapAddress. Error converting string to int. Avoiding element: ", elements[i]) - lastErr = err - continue - } - if values[1] == UpdateMethodTypeIgnore || values[1] == "" { - mapping[uint(tokenID)] = common.FFAddr - } else { - mapping[uint(tokenID)] = ethCommon.HexToAddress(values[1]) - } - } - d.Addresses = mapping - log.Debug("Address mapping from config file: ", mapping) - } else { - d.Addresses = make(map[uint]ethCommon.Address) - } - return lastErr -} - -// ProviderValidation method is for validation of Provider struct -func ProviderValidation(sl validator.StructLevel) { - Provider := sl.Current().Interface().(Provider) - if Provider.Symbols == "" && Provider.Addresses != "" { - sl.ReportError(Provider.Addresses, "Addresses", "Addresses", "notokens", "") - sl.ReportError(Provider.Symbols, "Symbols", "Symbols", "notokens", "") - return - } -} - -// PriceUpdater definition -type PriceUpdater struct { - db *historydb.HistoryDB - updateMethodsPriority []string - tokensList map[uint]historydb.TokenSymbolAndAddr - providers map[string]Provider - statictokensMap staticMap - fiat Fiat - clientProviders map[string]*sling.Sling -} - -// NewPriceUpdater is the constructor for the updater -func NewPriceUpdater( - updateMethodTypesPriority string, - providers []Provider, - staticTokens string, - fiat Fiat, - db *historydb.HistoryDB, -) (*PriceUpdater, error) { - priorityArr := strings.Split(string(updateMethodTypesPriority), ",") - var staticTokensMap staticMap - err := staticTokensMap.strToStaticTokensMap(staticTokens) - if err != nil { - return nil, tracerr.Wrap(err) - } - clientProviders := make(map[string]*sling.Sling) - // Init - tr := &http.Transport{ - MaxIdleConns: defaultMaxIdleConns, - IdleConnTimeout: defaultIdleConnTimeout, - DisableCompression: true, - } - httpClient := &http.Client{Transport: tr} - providersMap := make(map[string]Provider) - for i := 0; i < len(providers); i++ { - // create mappings - err := providers[i].SymbolsMap.strToMapSymbol(providers[i].Symbols) - if err != nil { - return nil, tracerr.Wrap(err) - } - err = providers[i].AddressesMap.strToMapAddress(providers[i].Addresses) - if err != nil { - return nil, tracerr.Wrap(err) - } - // Create Client providers for each provider - clientProviders[providers[i].Provider] = sling.New().Base(providers[i].BaseURL).Client(httpClient) - clientProviders["fiat"] = sling.New().Base(fiat.URL).Client(httpClient) - // Add provider to providersMap - providersMap[providers[i].Provider] = providers[i] - } - return &PriceUpdater{ - db: db, - updateMethodsPriority: priorityArr, - tokensList: map[uint]historydb.TokenSymbolAndAddr{}, - providers: providersMap, - statictokensMap: staticTokensMap, - fiat: fiat, - clientProviders: clientProviders, - }, nil -} - -func (p *PriceUpdater) getTokenPriceFromProvider(ctx context.Context, tokenID uint) (float64, error) { - for i := 0; i < len(p.updateMethodsPriority); i++ { - provider := p.providers[p.updateMethodsPriority[i]] - var url string - if _, ok := provider.AddressesMap.Addresses[tokenID]; ok { - if provider.AddressesMap.Addresses[tokenID] == common.EmptyAddr { - url = "simple/price?ids=ethereum" + provider.URLExtraParams - } else { - url = provider.URL + provider.AddressesMap.Addresses[tokenID].String() + provider.URLExtraParams - } - } else { - url = provider.URL + provider.SymbolsMap.Symbols[tokenID] + provider.URLExtraParams - } - req, err := p.clientProviders[provider.Provider].New().Get(url).Request() - if err != nil { - return 0, tracerr.Wrap(err) - } - var ( - res *http.Response - result float64 - isEmptyResult bool - ) - switch provider.Provider { - case UpdateMethodTypeBitFinexV2: - var data interface{} - res, err = p.clientProviders[provider.Provider].Do(req.WithContext(ctx), &data, nil) - if data != nil { - // The token price is received inside an array in the sixth position - result = data.([]interface{})[6].(float64) - } else { - isEmptyResult = true - } - case UpdateMethodTypeCoingeckoV3: - if provider.AddressesMap.Addresses[tokenID] == common.EmptyAddr { - var data map[string]map[string]float64 - res, err = p.clientProviders[provider.Provider].Do(req.WithContext(ctx), &data, nil) - result = data["ethereum"]["usd"] - if len(data) == 0 { - isEmptyResult = true - } - } else { - var data map[ethCommon.Address]map[string]float64 - res, err = p.clientProviders[provider.Provider].Do(req.WithContext(ctx), &data, nil) - result = data[provider.AddressesMap.Addresses[tokenID]]["usd"] - if len(data) == 0 { - isEmptyResult = true - } - } - default: - log.Error("Unknown price provider: ", provider.Provider) - return 0, tracerr.Wrap(fmt.Errorf("Error: Unknown price provider: " + provider.Provider)) - } - if err != nil || isEmptyResult || res.StatusCode != http.StatusOK { - var errMsg strings.Builder - errMsg.WriteString("Trying another price provider if it's possible.") - if err != nil { - errMsg.WriteString(" - Error: " + err.Error()) - } - if res != nil { - errMsg.WriteString(fmt.Sprintf(" - HTTP Error: %d %s", res.StatusCode, res.Status)) - } - errMsg.WriteString(fmt.Sprintf(" - TokenID: %d - URL: %s", tokenID, url)) - log.Warn(errMsg.String()) - continue - } else { - return result, nil - } - } - return 0, tracerr.Wrap(fmt.Errorf("Error getting price. All providers have failed")) -} - -// UpdatePrices is triggered by the Coordinator, and internally will update the -// token prices in the db -func (p *PriceUpdater) UpdatePrices(ctx context.Context) { - // Update static prices - for tokenID, price := range p.statictokensMap.Statictokens { - if err := p.db.UpdateTokenValueByTokenID(tokenID, price); err != nil { - log.Errorw("token price not updated (db error)", - "err", err) - } - } - // Update token prices but ignore ones - for _, token := range p.tokensList { - if p.providers[p.updateMethodsPriority[0]].AddressesMap.Addresses[token.TokenID] != common.FFAddr || - p.providers[p.updateMethodsPriority[0]].SymbolsMap.Symbols[token.TokenID] == UpdateMethodTypeIgnore { - tokenPrice, err := p.getTokenPriceFromProvider(ctx, token.TokenID) - if err != nil { - log.Errorw("token price from provider error", "err", err, "token", token.Symbol) - } else if err := p.db.UpdateTokenValueByTokenID(token.TokenID, tokenPrice); err != nil { - log.Errorw("token price not updated (db error)", - "err", err, "token", token.Symbol) - } - } - } -} - -// UpdateTokenList get the registered token symbols from HistoryDB -func (p *PriceUpdater) UpdateTokenList() error { - dbTokens, err := p.db.GetTokenSymbolsAndAddrs() - if err != nil { - return tracerr.Wrap(err) - } - // For each token from the DB - for _, dbToken := range dbTokens { - // If the token doesn't exists in the config list, - // add it with default update method - if _, ok := p.statictokensMap.Statictokens[dbToken.TokenID]; ok { - continue - } else { - if !(p.providers[p.updateMethodsPriority[0]].SymbolsMap.Symbols[dbToken.TokenID] == UpdateMethodTypeIgnore || - p.providers[p.updateMethodsPriority[0]].AddressesMap.Addresses[dbToken.TokenID] == common.FFAddr) { - p.tokensList[dbToken.TokenID] = dbToken - } - } - for _, provider := range p.providers { - switch provider.Provider { - case UpdateMethodTypeBitFinexV2: - if _, ok := provider.SymbolsMap.Symbols[dbToken.TokenID]; !ok { - provider.SymbolsMap.Symbols[dbToken.TokenID] = dbToken.Symbol - } - case UpdateMethodTypeCoingeckoV3: - if _, ok := provider.AddressesMap.Addresses[dbToken.TokenID]; !ok { - provider.AddressesMap.Addresses[dbToken.TokenID] = dbToken.Addr - } - default: - log.Warn("This price provider is not supported: ", provider.Provider) - return tracerr.Wrap(fmt.Errorf("Error: Unknown price provider: " + provider.Provider)) - } - } - } - return nil -} - -type fiatExchangeAPI struct { - Base string - Rates interface{} -} - -func (p *PriceUpdater) getFiatPrices(ctx context.Context) (map[string]interface{}, error) { - url := "latest?base=" + p.fiat.BaseCurrency + "&symbols=" + p.fiat.Currencies + "&access_key=" + p.fiat.APIKey - req, err := p.clientProviders["fiat"].New().Get(url).Request() - if err != nil { - return make(map[string]interface{}), tracerr.Wrap(err) - } - var ( - res *http.Response - result map[string]interface{} - data *fiatExchangeAPI - ) - res, err = p.clientProviders["fiat"].Do(req.WithContext(ctx), &data, nil) - if err != nil { - return make(map[string]interface{}), tracerr.Wrap(err) - } - if data != nil { - result = data.Rates.(map[string]interface{}) - } else { - log.Error("Error: data got are empty. Http code: ", res.StatusCode, ". URL: ", url) - return make(map[string]interface{}), tracerr.Wrap(fmt.Errorf("Empty data received from the fiat provider")) - } - return result, nil -} - -// UpdateFiatPrices updates the fiat prices -func (p *PriceUpdater) UpdateFiatPrices(ctx context.Context) error { - log.Debug("Updating fiat prices") - // Retrieve fiat prices - prices, err := p.getFiatPrices(ctx) - if err != nil { - return tracerr.Wrap(err) - } - // Getting all price from database with baseCurrency USD - currencies, err := p.db.GetAllFiatPrice("USD") - if err != nil { - return tracerr.Wrap(err) - } - for token, pr := range prices { - price := pr.(float64) - var exist bool - for i := 0; i < len(currencies); i++ { - if token == currencies[i].Currency { - exist = true - } - } - if exist { - if err = p.db.UpdateFiatPrice(token, "USD", price); err != nil { - log.Error("DB error updating fiat currency price: ", token, ", ", price, " Error: ", err) - } - } else { - if err = p.db.CreateFiatPrice(token, "USD", price); err != nil { - log.Error("DB error creating fiat currency price: ", token, ", ", price, " Error: ", err) - } - } - } - return err -} - -// UpdateFiatPricesMock updates the fiat prices -func (p *PriceUpdater) UpdateFiatPricesMock(ctx context.Context) error { - log.Debug("Updating fiat prices") - // Retrieve fiat prices - prices := make(map[string]interface{}) - prices["CNY"] = 6.4306 - prices["EUR"] = 0.817675 - prices["JPY"] = 108.709503 - prices["GBP"] = 0.70335 - - // Getting all price from database with baseCurrency USD - currencies, err := p.db.GetAllFiatPrice("USD") - if err != nil { - return tracerr.Wrap(err) - } - for token, pr := range prices { - price := pr.(float64) - var exist bool - for i := 0; i < len(currencies); i++ { - if token == currencies[i].Currency { - exist = true - } - } - if exist { - if err = p.db.UpdateFiatPrice(token, "USD", price); err != nil { - log.Error("DB error updating fiat currency price: ", token, ", ", price, " Error: ", err) - } - } else { - if err = p.db.CreateFiatPrice(token, "USD", price); err != nil { - log.Error("DB error creating fiat currency price: ", token, ", ", price, " Error: ", err) - } - } - } - return err -} diff --git a/priceupdater/priceupdater_test.go b/priceupdater/priceupdater_test.go deleted file mode 100644 index 6e5a66621..000000000 --- a/priceupdater/priceupdater_test.go +++ /dev/null @@ -1,160 +0,0 @@ -package priceupdater - -import ( - "context" - "testing" - - ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/hermeznetwork/hermez-node/common" - dbUtils "github.com/hermeznetwork/hermez-node/db" - "github.com/hermeznetwork/hermez-node/db/historydb" - "github.com/hermeznetwork/hermez-node/test" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var historyDB *historydb.HistoryDB - -const usdtAddr = "0xdac17f958d2ee523a2206206994597c13d831ec7" -const daiAddr = "0x6b175474e89094c44da98b954eedeac495271d0f" - -func TestPriceUpdater(t *testing.T) { - // Init DB - db, err := dbUtils.InitTestSQLDB() - if err != nil { - panic(err) - } - historyDB = historydb.NewHistoryDB(db, db, nil) - // Clean DB - test.WipeDB(historyDB.DB()) - // Populate DB - // Gen blocks and add them to DB - blocks := test.GenBlocks(1, 2) - require.NoError(t, historyDB.AddBlocks(blocks)) - // Gen tokens and add them to DB - tokens := []common.Token{ - { - TokenID: 1, - EthBlockNum: blocks[0].Num, - EthAddr: ethCommon.HexToAddress(daiAddr), - Name: "DAI", - Symbol: "DAI", - Decimals: 18, - }, // Used to test get by token symbol - { - TokenID: 2, - EthBlockNum: blocks[0].Num, - EthAddr: ethCommon.HexToAddress(usdtAddr), - Name: "Tether", - Symbol: "USDT", - Decimals: 18, - }, // Used to test get by SC addr - { - TokenID: 3, - EthBlockNum: blocks[0].Num, - EthAddr: ethCommon.HexToAddress("0x2"), - Name: "FOO", - Symbol: "FOO", - Decimals: 18, - }, // Used to test ignore - { - TokenID: 4, - EthBlockNum: blocks[0].Num, - EthAddr: ethCommon.HexToAddress("0x3"), - Name: "BAR", - Symbol: "BAR", - Decimals: 18, - }, // Used to test static - { - TokenID: 5, - EthBlockNum: blocks[0].Num, - EthAddr: ethCommon.HexToAddress("0x1f9840a85d5af5bf1d1762f925bdaddc4201f984"), - Name: "Uniswap", - Symbol: "UNI", - Decimals: 18, - }, // Used to test default - } - require.NoError(t, historyDB.AddTokens(tokens)) // ETH token exist in DB by default - // Update token price used to test ignore - ignoreValue := 44.44 - require.NoError(t, historyDB.UpdateTokenValue(tokens[2].EthAddr, ignoreValue)) - - // Prepare token config - tc := []Provider{ - { - Provider: "bitfinexV2", - BaseURL: "https://api-pub.bitfinex.com/v2/", - URL: "ticker/t", - URLExtraParams: "USD", - Symbols: "1=DAI,2=USDT,3=ignore,5=UNI", - }, - { - Provider: "CoinGeckoV3", - BaseURL: "https://api.coingecko.com/api/v3/", - URL: "simple/token_price/ethereum?contract_addresses=", - URLExtraParams: "&vs_currencies=usd", - Addresses: "1=" + daiAddr + ",2=" + usdtAddr + ",3=ignore,5=0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", - }, - } - var priority string = "bitfinexV2,CoinGeckoV3" - var staticTokens = "4=30.02" - var fiat = Fiat{ - APIKey: "FFFFFFFFFF", - URL: "https://api.exchangeratesapi.io/v1/", - BaseCurrency: "USD", - Currencies: "CNY,EUR,JPY,GBP", - } - - // Init price updater - pu, err := NewPriceUpdater( - priority, - tc, - staticTokens, - fiat, - historyDB, - ) - require.NoError(t, err) - - // Update token list - require.NoError(t, pu.UpdateTokenList()) - - // Update prices - pu.UpdatePrices(context.Background()) - - // Check results: get tokens from DB - fetchedTokens, err := historyDB.GetTokensTest() - require.NoError(t, err) - // Check that tokens that are updated via API have value: - // ETH - require.NotNil(t, fetchedTokens[0].USDUpdate) - assert.Greater(t, *fetchedTokens[0].USD, 0.0) - // DAI - require.NotNil(t, fetchedTokens[1].USDUpdate) - assert.Greater(t, *fetchedTokens[1].USD, 0.0) - // USDT - require.NotNil(t, fetchedTokens[2].USDUpdate) - assert.Greater(t, *fetchedTokens[2].USD, 0.0) - // UNI - require.NotNil(t, fetchedTokens[5].USDUpdate) - assert.Greater(t, *fetchedTokens[5].USD, 0.0) - // Check ignored token - assert.Equal(t, ignoreValue, *fetchedTokens[3].USD) - // Check static value - assert.Equal(t, 30.02, *fetchedTokens[4].USD) - - // Get fiat currencies: get currencies from DB - fetchedcurrencies, err := historyDB.GetAllFiatPrice("USD") - require.NoError(t, err) - assert.Equal(t, 0, len(fetchedcurrencies)) - //Update fiat currencies - err = pu.UpdateFiatPricesMock(context.Background()) - require.NoError(t, err) - - // Check results: get fiat currencies from DB - fetchedcurrencies, err = historyDB.GetAllFiatPrice("USD") - require.NoError(t, err) - assert.Greater(t, fetchedcurrencies[0].Price, 0.0) - assert.Greater(t, fetchedcurrencies[1].Price, 0.0) - assert.Greater(t, fetchedcurrencies[2].Price, 0.0) - assert.Greater(t, fetchedcurrencies[3].Price, 0.0) -} diff --git a/prover/prover_test.go b/prover/prover_test.go index 6547229ce..54fb8e441 100644 --- a/prover/prover_test.go +++ b/prover/prover_test.go @@ -74,7 +74,6 @@ func testCancel(t *testing.T) { zkInputs := common.NewZKInputs(0, 100, 24, 512, 32, big.NewInt(1)) err := proofServerClient.CalculateProof(context.Background(), zkInputs) require.NoError(t, err) - // TODO: remove sleep when the server has been reviewed time.Sleep(time.Second / 4) err = proofServerClient.Cancel(context.Background()) require.NoError(t, err) diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index 3e582ac1c..5c4f2b258 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -94,11 +94,6 @@ func (s *Stats) Synced() bool { return s.Eth.LastBlock.Num == s.Sync.LastBlock.Num } -// TODO(Edu): Consider removing all the mutexes from StatsHolder, make -// Synchronizer.Stats not thread-safe, don't pass the synchronizer to the -// debugAPI, and have a copy of the Stats in the DebugAPI that the node passes -// when the Sync updates. - // StatsHolder stores stats and that allows reading and writing them // concurrently type StatsHolder struct { @@ -389,8 +384,6 @@ func (s *Synchronizer) updateCurrentSlot(slot *common.Slot, reset bool, hasBatch return tracerr.Wrap(err) } - // TODO: Remove this SANITY CHECK once this code is tested enough - // BEGIN SANITY CHECK canForge, err := s.ethClient.AuctionCanForge(slot.Forger, blockNum) if err != nil { return tracerr.Wrap(fmt.Errorf("AuctionCanForge: %w", err)) @@ -399,7 +392,6 @@ func (s *Synchronizer) updateCurrentSlot(slot *common.Slot, reset bool, hasBatch return tracerr.Wrap(fmt.Errorf("Synchronized value of forger address for closed slot "+ "differs from smart contract: %+v", slot)) } - // END SANITY CHECK } return nil } @@ -420,8 +412,6 @@ func (s *Synchronizer) updateNextSlot(slot *common.Slot) error { return tracerr.Wrap(err) } - // TODO: Remove this SANITY CHECK once this code is tested enough - // BEGIN SANITY CHECK canForge, err := s.ethClient.AuctionCanForge(slot.Forger, slot.StartBlock) if err != nil { return tracerr.Wrap(fmt.Errorf("AuctionCanForge: %w", err)) @@ -430,7 +420,6 @@ func (s *Synchronizer) updateNextSlot(slot *common.Slot) error { return tracerr.Wrap(fmt.Errorf("Synchronized value of forger address for closed slot "+ "differs from smart contract: %+v", slot)) } - // END SANITY CHECK } return nil } @@ -513,7 +502,6 @@ func (s *Synchronizer) resetIntermediateState() error { // If a block is synced, it will be returned and also stored in the DB. If a // reorg is detected, the number of discarded blocks will be returned and no // synchronization will be made. -// TODO: Be smart about locking: only lock during the read/write operations func (s *Synchronizer) Sync(ctx context.Context, lastSavedBlock *common.Block) (blockData *common.BlockData, discarded *int64, err error) { if s.resetStateFailed { diff --git a/test/debugapi/debugapi_test.go b/test/debugapi/debugapi_test.go index 5476fd7b5..5064f17ff 100644 --- a/test/debugapi/debugapi_test.go +++ b/test/debugapi/debugapi_test.go @@ -13,6 +13,7 @@ import ( "github.com/dghubble/sling" ethCrypto "github.com/ethereum/go-ethereum/crypto" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db/statedb" "github.com/iden3/go-iden3-crypto/babyjub" "github.com/stretchr/testify/assert" @@ -34,7 +35,7 @@ func newAccount(t *testing.T, i int) *common.Account { return &common.Account{ Idx: common.Idx(256 + i), TokenID: common.TokenID(i), - Nonce: common.Nonce(i), + Nonce: nonce.Nonce(i), Balance: big.NewInt(1000), BJJ: pk.Compress(), EthAddr: address, diff --git a/test/ethclient.go b/test/ethclient.go index 456fdfd81..ede3ee0b0 100644 --- a/test/ethclient.go +++ b/test/ethclient.go @@ -34,7 +34,6 @@ func init() { // WDelayerBlock stores all the data related to the WDelayer SC from an ethereum block type WDelayerBlock struct { - // State eth.WDelayerState // TODO Vars common.WDelayerVariables Events eth.WDelayerEvents Txs map[ethCommon.Hash]*types.Transaction @@ -964,19 +963,12 @@ func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs, return nil, tracerr.Wrap(fmt.Errorf(common.AuctionErrMsgCannotForge)) } - // TODO: Verify proof - // Auction err = a.forge(*c.addr) if err != nil { return nil, tracerr.Wrap(err) } - // TODO: If successful, store the tx in a successful array. - // TODO: If failed, store the tx in a failed array. - // TODO: Add method to move the tx to another block, reapply it there, and possibly go from - // successful to failed. - return c.addBatch(args) } @@ -1099,24 +1091,6 @@ func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Tra return nil, tracerr.Wrap(errTODO) } -// RollupUpdateTokensHEZ is the interface to call the smart contract function -// func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (tx *types.Transaction, -// err error) { -// c.rw.Lock() -// defer c.rw.Unlock() -// cpy := c.nextBlock().copy() -// defer func() { c.revertIfErr(err, cpy) }() -// -// log.Error("TODO") -// return nil, errTODO -// } - -// RollupUpdateGovernance is the interface to call the smart contract function -// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { -// // TODO (Not defined in Hermez.sol) -// return nil, errTODO -// } - // RollupConstants returns the Constants of the Rollup Smart Contract func (c *Client) RollupConstants() (*common.RollupConstants, error) { c.rw.RLock() diff --git a/test/historydb.go b/test/historydb.go index bbc970268..ba2724684 100644 --- a/test/historydb.go +++ b/test/historydb.go @@ -8,6 +8,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" "github.com/iden3/go-merkletree" @@ -297,7 +298,7 @@ func GenL2Txs( Position: i - fromIdx, Amount: amount, Fee: fee, - Nonce: common.Nonce(i + 1), + Nonce: nonce.Nonce(i + 1), EthBlockNum: blocks[i%len(blocks)].Num, Type: randomTxType(i), } diff --git a/test/l2db.go b/test/l2db.go index b1ade1f05..9536b4040 100644 --- a/test/l2db.go +++ b/test/l2db.go @@ -40,7 +40,7 @@ func GenPoolTxs(n int, tokens []common.Token) []*common.PoolL2Tx { TokenID: token.TokenID, Amount: big.NewInt(int64(i)), Fee: fee, - Nonce: common.Nonce(i), + Nonce: nonce.Nonce(i), State: state, Signature: privK.SignPoseidon(big.NewInt(int64(i))).Compress(), } @@ -57,7 +57,7 @@ func GenPoolTxs(n int, tokens []common.Token) []*common.PoolL2Tx { tx.RqTokenID = common.TokenID(i) tx.RqAmount = big.NewInt(int64(i)) tx.RqFee = common.FeeSelector(i) - tx.RqNonce = common.Nonce(i) + tx.RqNonce = nonce.Nonce(i) } txs = append(txs, tx) } diff --git a/test/til/txs.go b/test/til/txs.go index 52bdf5ddb..a735a4076 100644 --- a/test/til/txs.go +++ b/test/til/txs.go @@ -11,6 +11,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" ethCrypto "github.com/ethereum/go-ethereum/crypto" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" @@ -43,7 +44,7 @@ func newBlock(blockNum int64) common.BlockData { type contextExtra struct { openToForge int64 toForgeL1TxsNum int64 - nonces map[common.Idx]common.Nonce + nonces map[common.Idx]nonce.Nonce idx int idxByTxID map[common.TxID]common.Idx } @@ -106,7 +107,7 @@ func NewContext(chainID uint16, rollupConstMaxL1UserTx int) *Context { extra: contextExtra{ openToForge: 0, toForgeL1TxsNum: 0, - nonces: make(map[common.Idx]common.Nonce), + nonces: make(map[common.Idx]nonce.Nonce), idx: common.UserThreshold, idxByTxID: make(map[common.TxID]common.Idx), }, @@ -117,7 +118,7 @@ func NewContext(chainID uint16, rollupConstMaxL1UserTx int) *Context { type Account struct { Idx common.Idx TokenID common.TokenID - Nonce common.Nonce + Nonce nonce.Nonce BatchNum int } @@ -434,7 +435,7 @@ func (tc *Context) calculateIdxForL1Txs(isCoordinatorTxs bool, txs []L1Tx) error tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] = &Account{ Idx: common.Idx(tc.idx), TokenID: tx.L1Tx.TokenID, - Nonce: common.Nonce(0), + Nonce: nonce.Nonce(0), BatchNum: tc.currBatchNum, } tc.l1CreatedAccounts[idxTokenIDToString(tx.fromIdxName, tx.L1Tx.TokenID)] = @@ -707,7 +708,7 @@ func (tc *Context) generatePoolL2Txs() ([]common.PoolL2Tx, error) { func (tc *Context) RestartNonces() { for name, user := range tc.Users { for tokenID := range user.Accounts { - tc.Users[name].Accounts[tokenID].Nonce = common.Nonce(0) + tc.Users[name].Accounts[tokenID].Nonce = nonce.Nonce(0) } } } diff --git a/test/til/txs_test.go b/test/til/txs_test.go index 3e69e68a6..079d5caec 100644 --- a/test/til/txs_test.go +++ b/test/til/txs_test.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -256,16 +257,16 @@ func TestGeneratePoolL2Txs(t *testing.T) { assert.Equal(t, common.EmptyAddr.Hex(), poolL2Txs[5].ToEthAddr.Hex()) assert.Equal(t, common.EmptyBJJComp.String(), poolL2Txs[5].ToBJJ.String()) - assert.Equal(t, common.Nonce(0), poolL2Txs[0].Nonce) - assert.Equal(t, common.Nonce(0), poolL2Txs[1].Nonce) - assert.Equal(t, common.Nonce(0), poolL2Txs[2].Nonce) - assert.Equal(t, common.Nonce(1), poolL2Txs[3].Nonce) - assert.Equal(t, common.Nonce(0), poolL2Txs[4].Nonce) - assert.Equal(t, common.Nonce(0), poolL2Txs[5].Nonce) - assert.Equal(t, common.Nonce(0), poolL2Txs[6].Nonce) - assert.Equal(t, common.Nonce(0), poolL2Txs[7].Nonce) - assert.Equal(t, common.Nonce(2), poolL2Txs[8].Nonce) - assert.Equal(t, common.Nonce(3), poolL2Txs[9].Nonce) + assert.Equal(t, nonce.Nonce(0), poolL2Txs[0].Nonce) + assert.Equal(t, nonce.Nonce(0), poolL2Txs[1].Nonce) + assert.Equal(t, nonce.Nonce(0), poolL2Txs[2].Nonce) + assert.Equal(t, nonce.Nonce(1), poolL2Txs[3].Nonce) + assert.Equal(t, nonce.Nonce(0), poolL2Txs[4].Nonce) + assert.Equal(t, nonce.Nonce(0), poolL2Txs[5].Nonce) + assert.Equal(t, nonce.Nonce(0), poolL2Txs[6].Nonce) + assert.Equal(t, nonce.Nonce(0), poolL2Txs[7].Nonce) + assert.Equal(t, nonce.Nonce(2), poolL2Txs[8].Nonce) + assert.Equal(t, nonce.Nonce(3), poolL2Txs[9].Nonce) assert.Equal(t, tc.Users["B"].Addr.Hex(), poolL2Txs[9].ToEthAddr.Hex()) assert.Equal(t, common.EmptyBJJComp, poolL2Txs[9].ToBJJ) @@ -283,9 +284,9 @@ func TestGeneratePoolL2Txs(t *testing.T) { ` poolL2Txs, err = tc.GeneratePoolL2Txs(set) require.NoError(t, err) - assert.Equal(t, common.Nonce(5), poolL2Txs[0].Nonce) - assert.Equal(t, common.Nonce(1), poolL2Txs[1].Nonce) - assert.Equal(t, common.Nonce(6), poolL2Txs[2].Nonce) + assert.Equal(t, nonce.Nonce(5), poolL2Txs[0].Nonce) + assert.Equal(t, nonce.Nonce(1), poolL2Txs[1].Nonce) + assert.Equal(t, nonce.Nonce(6), poolL2Txs[2].Nonce) // check that a PoolL2Tx can be done to a non existing ToIdx set = ` @@ -466,9 +467,9 @@ func TestGenerateErrors(t *testing.T) { tc = NewContext(0, common.RollupConstMaxL1UserTx) _, err = tc.GenerateBlocks(set) require.NoError(t, err) - assert.Equal(t, common.Nonce(3), tc.Users["A"].Accounts[common.TokenID(1)].Nonce) + assert.Equal(t, nonce.Nonce(3), tc.Users["A"].Accounts[common.TokenID(1)].Nonce) assert.Equal(t, common.Idx(256), tc.Users["A"].Accounts[common.TokenID(1)].Idx) - assert.Equal(t, common.Nonce(1), tc.Users["B"].Accounts[common.TokenID(1)].Nonce) + assert.Equal(t, nonce.Nonce(1), tc.Users["B"].Accounts[common.TokenID(1)].Nonce) assert.Equal(t, common.Idx(257), tc.Users["B"].Accounts[common.TokenID(1)].Idx) } diff --git a/txprocessor/txprocessor.go b/txprocessor/txprocessor.go index ff8e8afc2..028e7148b 100644 --- a/txprocessor/txprocessor.go +++ b/txprocessor/txprocessor.go @@ -87,6 +87,7 @@ import ( "os" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db/statedb" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/tracerr" @@ -668,9 +669,6 @@ func (txProcessor *TxProcessor) ProcessL1Tx(exitTree *merkletree.MerkleTree, tx log.Error(err) return nil, nil, false, nil, tracerr.Wrap(err) } - // TODO applyCreateAccount will return the created account, - // which in the case type==TypeSynchronizer will be added to an - // array of created accounts that will be returned case common.TxTypeDeposit: txProcessor.computeEffectiveAmounts(tx) @@ -1323,7 +1321,7 @@ func (txProcessor *TxProcessor) applyExit(coordIdxsMap map[common.TokenID]common // exitAmount (exitAmount=tx.Amount) exitAccount := &common.Account{ TokenID: acc.TokenID, - Nonce: common.Nonce(0), + Nonce: nonce.Nonce(0), // as is a common.Tx, the tx.Amount is already an // EffectiveAmount Balance: tx.Amount, diff --git a/txprocessor/txprocessor_test.go b/txprocessor/txprocessor_test.go index 6ce859ae0..9b8df7dd1 100644 --- a/txprocessor/txprocessor_test.go +++ b/txprocessor/txprocessor_test.go @@ -9,6 +9,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" "github.com/hermeznetwork/hermez-node/db/statedb" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/test/til" @@ -469,9 +470,9 @@ func TestProcessTxsSynchronizer(t *testing.T) { log.Debug("block:1 batch:1") l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs) // before processing expect l2Txs[0:2].Nonce==0 - assert.Equal(t, common.Nonce(0), l2Txs[0].Nonce) - assert.Equal(t, common.Nonce(0), l2Txs[1].Nonce) - assert.Equal(t, common.Nonce(0), l2Txs[2].Nonce) + assert.Equal(t, nonce.Nonce(0), l2Txs[0].Nonce) + assert.Equal(t, nonce.Nonce(0), l2Txs[1].Nonce) + assert.Equal(t, nonce.Nonce(0), l2Txs[2].Nonce) // Idx of user 'X' idxX1 := tc.Users["X"].Accounts[common.TokenID(1)].Idx @@ -493,9 +494,9 @@ func TestProcessTxsSynchronizer(t *testing.T) { require.NoError(t, err) // after processing expect l2Txs[0:2].Nonce!=0 and has expected value - assert.Equal(t, common.Nonce(5), l2Txs[0].Nonce) - assert.Equal(t, common.Nonce(6), l2Txs[1].Nonce) - assert.Equal(t, common.Nonce(7), l2Txs[2].Nonce) + assert.Equal(t, nonce.Nonce(5), l2Txs[0].Nonce) + assert.Equal(t, nonce.Nonce(6), l2Txs[1].Nonce) + assert.Equal(t, nonce.Nonce(7), l2Txs[2].Nonce) // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs assert.Equal(t, 4, len(ptOut.ExitInfos)) assert.Equal(t, 1, len(ptOut.CreatedAccounts)) diff --git a/txselector/txselector.go b/txselector/txselector.go index 4b6701f04..c8d0b23b6 100644 --- a/txselector/txselector.go +++ b/txselector/txselector.go @@ -442,8 +442,6 @@ func (txsel *TxSelector) processL2Txs( ) { const failedGroupErrMsg = "Failed forging atomic tx from Group %s." + " Restarting selection process without txs from this group" - // TODO: differentiate between nonSelectedL2Txs and unforjableL2Txs - // (right now all fall into nonSelectedL2Txs, which is safe but non optimal) positionL1 := nAlreadyProcessedL1Txs nextBatchNum := uint32(txsel.localAccountsDB.CurrentBatch()) + 1 // Iterate over l2Txs @@ -730,7 +728,7 @@ func (txsel *TxSelector) processL2Txs( nAlreadyProcessedL1Txs++ } if validL2Tx == nil { - // TODO: Missing info on why this tx is not selected? Check l2Txs.Info at this point! + // Missing info on why this tx is not selected? Check l2Txs.Info at this point! // If tx is atomic, restart process without txs from the atomic group if l2Txs[i].AtomicGroupID != common.EmptyAtomicGroupID { obj := common.TxSelectorError{ @@ -1023,18 +1021,27 @@ func sortL2Txs( atomicGroupsFee[atomicGroups[j][0].AtomicGroupID] }) - // Sort non atomic txs by absolute fee with SliceStable, so that txs with same - // AbsoluteFee are not rearranged and nonce order is kept in such case - sort.SliceStable(nonAtomicTxs, func(i, j int) bool { - return nonAtomicTxs[i].AbsoluteFee > nonAtomicTxs[j].AbsoluteFee - }) + // Sort non atomic txs by AbsoluteFee DESC, then by FromIdx ASC and then + // by Nonce ASC. + // + // This sorting sequence allows us to select firstly the most profitable + // txs, even though this can mess with the Nonce sequence, but since the + // Nonce sequence is only one of the rules in order to a txs be selected + // and we have a txs reprocessing strategy, the tx selector will try to + // select the `wrong nonce` txs in the next interation until it identifies + // there is no more txs to be selected at this moment, when this situation + // happens we can assume the tx selector selected all the most profitable + // txs that can be processed at this moment. - // sort non atomic txs by Nonce. This can be done in many different ways, what - // is needed is to output the l2Txs where the Nonce of l2Txs for each - // Account is sorted, but the l2Txs can not be grouped by sender Account - // neither by Fee. This is because later on the Nonces will need to be - // sequential for the zkproof generation. sort.Slice(nonAtomicTxs, func(i, j int) bool { + if nonAtomicTxs[i].AbsoluteFee != nonAtomicTxs[j].AbsoluteFee { + return nonAtomicTxs[i].AbsoluteFee > nonAtomicTxs[j].AbsoluteFee + } + + if nonAtomicTxs[i].FromIdx != nonAtomicTxs[j].FromIdx { + return nonAtomicTxs[i].FromIdx < nonAtomicTxs[j].FromIdx + } + return nonAtomicTxs[i].Nonce < nonAtomicTxs[j].Nonce }) @@ -1072,6 +1079,7 @@ func sortL2Txs( sortedL2Txs = append(sortedL2Txs, nonAtomicTxs[i]) } } + return sortedL2Txs } @@ -1189,7 +1197,6 @@ func isAtomicGroupValid(atomicGroup common.AtomicGroup) bool { atomicGroup.Txs[i].RqTokenID != requestedTx.TokenID || atomicGroup.Txs[i].RqFee != requestedTx.Fee || atomicGroup.Txs[i].RqNonce != requestedTx.Nonce { - // TODO: err should be compliant with txSelectorError return false } // Check amount @@ -1243,15 +1250,19 @@ func setInfoForFailedAtomicTx( ) common.TxSelectorError { if isOriginOfFailure { obj := common.TxSelectorError{ - Message: fmt.Sprintf("unselectable atomic group"+" %s, tx %s failed due to: %s", - failedAtomicGroupID, - failedTxID, - failMessage.Message, - ), - Code: failMessage.Code, - Type: failMessage.Type, + Message: failMessage.Message, + Code: failMessage.Code, + Type: failMessage.Type, } return obj } - return common.TxSelectorError{} + return common.TxSelectorError{ + Message: fmt.Sprintf("unselectable atomic group"+" %s, tx %s failed due to: %s", + failedAtomicGroupID, + failedTxID, + failMessage.Message, + ), + Code: ErrInvalidAtomicGroupCode, + Type: ErrInvalidAtomicGroupType, + } } diff --git a/txselector/txselector_test.go b/txselector/txselector_test.go index 3b7bf5ef7..3d29195c0 100644 --- a/txselector/txselector_test.go +++ b/txselector/txselector_test.go @@ -12,6 +12,7 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" ethCrypto "github.com/ethereum/go-ethereum/crypto" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/common/nonce" dbUtils "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/hermeznetwork/hermez-node/db/l2db" @@ -151,7 +152,7 @@ func checkBalanceByIdx(t *testing.T, txsel *TxSelector, idx common.Idx, expected // checkSortedByNonce takes as input testAccNonces map, and the array of // common.PoolL2Txs, and checks if the nonces correspond to the accumulated // values of the map. Also increases the Nonces computed on the map. -func checkSortedByNonce(t *testing.T, testAccNonces map[common.Idx]common.Nonce, +func checkSortedByNonce(t *testing.T, testAccNonces map[common.Idx]nonce.Nonce, txs []common.PoolL2Tx) { for _, tx := range txs { assert.True(t, testAccNonces[tx.FromIdx] == tx.Nonce, @@ -176,7 +177,7 @@ func TestGetL2TxSelectionMinimumFlow0(t *testing.T) { // restart nonces of TilContext, as will be set by generating directly // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs tc.RestartNonces() - testAccNonces := make(map[common.Idx]common.Nonce) + testAccNonces := make(map[common.Idx]nonce.Nonce) // add tokens to HistoryDB to avoid breaking FK constrains addTokens(t, tc, txsel.l2db.DB()) @@ -812,9 +813,9 @@ func TestProcessL2Selection(t *testing.T) { // (due the 2nd txs not being accepted) assert.Equal(t, 1, len(oL2Txs)) assert.Equal(t, 2, len(discardedL2Txs)) - assert.Equal(t, common.Nonce(0), oL2Txs[0].Nonce) - assert.Equal(t, common.Nonce(1), discardedL2Txs[0].Nonce) - assert.Equal(t, common.Nonce(2), discardedL2Txs[1].Nonce) + assert.Equal(t, nonce.Nonce(0), oL2Txs[0].Nonce) + assert.Equal(t, nonce.Nonce(1), discardedL2Txs[0].Nonce) + assert.Equal(t, nonce.Nonce(2), discardedL2Txs[1].Nonce) assert.Equal(t, "Tx not selected due to not enough Balance at the sender. "+ "Current sender account Balance: 7, Amount+Fee: 11", discardedL2Txs[0].Info) assert.Equal(t, 11, discardedL2Txs[0].ErrorCode) @@ -905,18 +906,6 @@ func TestValidTxsWithLowFeeAndInvalidTxsWithHighFee(t *testing.T) { txsel.localAccountsDB.CurrentBatch()) require.NoError(t, err) - // batch 3. The A-B txs have lower fee, but are the only ones possible - // with the current Accounts Balances, as the B-A tx of amount 40 will - // not be included as will be processed first when there is not enough - // balance at B (processed first as the TxSelector sorts by Fee and then - // by Nonce). - // TODO: The explanation of the test just above is outdated, as the new itereation of txselector - // is capable of detecting more complicated situations. Before merging to develop the explanation - // should be updated. Leaving like this to remember that we have altered the original test, since the - // code is not stable yet, is good to remember of this test modification. The correctness of the result - // has been checked by forging more batches in the original code, and ensuring that the order of the L2Tx - // is the same, but contained in less batches. Also the limits in terms of MaxTxs and MaxL1Tx can be checked by - // comparing the configuration and the asserts batchPoolL2 := ` Type: PoolL2 PoolTransfer(0) B-A: 40 (130) // B-A txs are only possible once A-B txs are processed @@ -1300,7 +1289,7 @@ func TestFailingAtomicTx(t *testing.T) { TokenID: 0, Amount: big.NewInt(50), // Ok Fee: 0, - Nonce: 0, + Nonce: 1, RqOffset: 1, // Request tx bellow (position +1) AtomicGroupID: agid, RqFromIdx: 258, // account B @@ -1333,7 +1322,7 @@ func TestFailingAtomicTx(t *testing.T) { RqTokenID: 0, RqAmount: big.NewInt(50), // OK RqFee: 0, - RqNonce: 0, + RqNonce: 1, State: common.PoolL2TxStatePending, } // Tx2 signature @@ -1372,6 +1361,17 @@ func TestFailingAtomicTx(t *testing.T) { assert.Equal(t, 0, len(oL1CoordTxs)) assert.Equal(t, 1, len(oL2Txs)) assert.Equal(t, 2, len(discardedL2Txs)) + + for _, tx := range discardedL2Txs { + if tx1.TxID == tx.TxID { + assert.Equal(t, ErrNoCurrentNonceType, tx.ErrorType) + } else if tx2.TxID == tx.TxID { + assert.Equal(t, ErrInvalidAtomicGroupType, tx.ErrorType) + } else { + assert.Fail(t, "unexpected transaction") + } + } + assert.Equal(t, common.BatchNum(4), txsel.localAccountsDB.CurrentBatch()) assert.Equal(t, common.Idx(259), txsel.localAccountsDB.CurrentIdx()) checkBalance(t, tc, txsel, "Coord", 0, "1010") // 1000 + 10 @@ -1679,6 +1679,15 @@ func TestSortL2Txs(t *testing.T) { assert.Equal(t, expected[i], a.TxID) } } + + //Idxs + idx1 := common.Idx(256) + idx2 := common.Idx(257) + idx3 := common.Idx(258) + idx4 := common.Idx(259) + idx5 := common.Idx(260) + idx6 := common.Idx(261) + // TxIDs id1 := common.TxID([common.TxIDLen]byte{1}) id2 := common.TxID([common.TxIDLen]byte{2}) @@ -1695,18 +1704,21 @@ func TestSortL2Txs(t *testing.T) { txs := []common.PoolL2Tx{ { TxID: id1, + FromIdx: idx1, AtomicGroupID: common.EmptyAtomicGroupID, AbsoluteFee: 3, Nonce: 2, }, { TxID: id2, + FromIdx: idx1, AtomicGroupID: common.EmptyAtomicGroupID, AbsoluteFee: 3, Nonce: 1, }, { TxID: id3, + FromIdx: idx2, AtomicGroupID: common.EmptyAtomicGroupID, AbsoluteFee: 7, Nonce: 2, @@ -1714,29 +1726,33 @@ func TestSortL2Txs(t *testing.T) { } fees := calculateAtomicGroupsAverageFee(txs) actual := sortL2Txs(txs, fees) - assertResult(t, []common.TxID{id2, id3, id1}, actual) + assertResult(t, []common.TxID{id3, id2, id1}, actual) // Case only atomic txs = []common.PoolL2Tx{ { TxID: id1, + FromIdx: idx1, AtomicGroupID: agid2, AbsoluteFee: 3, Nonce: 2220, }, { TxID: id2, + FromIdx: idx2, AtomicGroupID: agid2, AbsoluteFee: 3, Nonce: 1, }, { TxID: id3, + FromIdx: idx3, AtomicGroupID: agid1, AbsoluteFee: 7, Nonce: 300, }, { TxID: id4, + FromIdx: idx2, AtomicGroupID: agid1, AbsoluteFee: 700, Nonce: 2, @@ -1749,42 +1765,49 @@ func TestSortL2Txs(t *testing.T) { txs = []common.PoolL2Tx{ { TxID: id1, + FromIdx: idx1, AtomicGroupID: agid2, AbsoluteFee: 20, Nonce: 2220, }, { TxID: id2, + FromIdx: idx2, AtomicGroupID: agid2, AbsoluteFee: 20, Nonce: 1, }, { TxID: id3, + FromIdx: idx3, AtomicGroupID: agid1, AbsoluteFee: 30, Nonce: 300, }, { TxID: id4, + FromIdx: idx2, AtomicGroupID: agid1, AbsoluteFee: 30, Nonce: 2, }, { TxID: id5, + FromIdx: idx4, AtomicGroupID: common.EmptyAtomicGroupID, AbsoluteFee: 25, Nonce: 2, }, { TxID: id6, + FromIdx: idx5, AtomicGroupID: common.EmptyAtomicGroupID, AbsoluteFee: 10, Nonce: 2, }, { TxID: id7, + FromIdx: idx6, AtomicGroupID: common.EmptyAtomicGroupID, AbsoluteFee: 35, Nonce: 2,