diff --git a/db/historydb/nodeinfo.go b/db/historydb/nodeinfo.go index d2c051c..b29eba8 100644 --- a/db/historydb/nodeinfo.go +++ b/db/historydb/nodeinfo.go @@ -11,9 +11,9 @@ import ( "github.com/hermeznetwork/hermez-node/apitypes" "github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/db" + "github.com/hermeznetwork/tracerr" "github.com/jmoiron/sqlx" "github.com/russross/meddler" - "github.com/ztrue/tracerr" ) const ( @@ -484,7 +484,7 @@ func (hdb *HistoryDB) UpdateRecommendedFee() error { } func (hdb *HistoryDB) updateNodeInfo(setUpdatedNodeInfo func(*sqlx.Tx, *NodeInfo) error) error { - // Create a SQL transaction o read and update atomicaly + // Create a SQL transaction or read and update atomicaly txn, err := hdb.dbWrite.Beginx() if err != nil { return tracerr.Wrap(err) diff --git a/foobar b/foobar deleted file mode 100644 index 20d60a5..0000000 --- a/foobar +++ /dev/null @@ -1,1326 +0,0 @@ -diff --git a/api/api.go b/api/api.go -index 631d76e..5afa8a8 100644 ---- a/api/api.go -+++ b/api/api.go -@@ -2,40 +2,19 @@ package api - - import ( - "errors" -- "sync" - - ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/gin-gonic/gin" -- "github.com/hermeznetwork/hermez-node/common" - "github.com/hermeznetwork/hermez-node/db/historydb" - "github.com/hermeznetwork/hermez-node/db/l2db" - "github.com/hermeznetwork/tracerr" - ) - --// TODO: Add correct values to constants --const ( -- createAccountExtraFeePercentage float64 = 2 -- createAccountInternalExtraFeePercentage float64 = 2.5 --) -- --// Status define status of the network --type Status struct { -- sync.RWMutex -- NodeConfig NodeConfig `json:"nodeConfig"` -- Network Network `json:"network"` -- Metrics historydb.Metrics `json:"metrics"` -- Rollup historydb.RollupVariablesAPI `json:"rollup"` -- Auction historydb.AuctionVariablesAPI `json:"auction"` -- WithdrawalDelayer common.WDelayerVariables `json:"withdrawalDelayer"` -- RecommendedFee common.RecommendedFee `json:"recommendedFee"` --} -- - // API serves HTTP requests to allow external interaction with the Hermez node - type API struct { - h *historydb.HistoryDB - cg *configAPI - l2 *l2db.L2DB -- status Status - chainID uint16 - hermezAddress ethCommon.Address - } -@@ -46,8 +25,6 @@ func NewAPI( - server *gin.Engine, - hdb *historydb.HistoryDB, - l2db *l2db.L2DB, -- config *Config, -- nodeConfig *NodeConfig, - ) (*API, error) { - // Check input - // TODO: is stateDB only needed for explorer endpoints or for both? -@@ -57,20 +34,20 @@ func NewAPI( - if explorerEndpoints && hdb == nil { - return nil, tracerr.Wrap(errors.New("cannot serve Explorer endpoints without HistoryDB")) - } -- -+ ni, err := hdb.GetNodeInfo() -+ if err != nil { -+ return nil, err -+ } - a := &API{ - h: hdb, - cg: &configAPI{ -- RollupConstants: *newRollupConstants(config.RollupConstants), -- AuctionConstants: config.AuctionConstants, -- WDelayerConstants: config.WDelayerConstants, -- }, -- l2: l2db, -- status: Status{ -- NodeConfig: *nodeConfig, -+ RollupConstants: *newRollupConstants(ni.Constants.RollupConstants), -+ AuctionConstants: ni.Constants.AuctionConstants, -+ WDelayerConstants: ni.Constants.WDelayerConstants, - }, -- chainID: config.ChainID, -- hermezAddress: config.HermezAddress, -+ l2: l2db, -+ chainID: ni.Constants.ChainID, -+ hermezAddress: ni.Constants.HermezAddress, - } - - // Add coordinator endpoints -diff --git a/api/state.go b/api/state.go -index eecdd77..ebb0a3c 100644 ---- a/api/state.go -+++ b/api/state.go -@@ -1,320 +1,16 @@ - package api - - import ( -- "database/sql" -- "fmt" -- "math" -- "math/big" - "net/http" -- "time" - - "github.com/gin-gonic/gin" -- "github.com/hermeznetwork/hermez-node/apitypes" -- "github.com/hermeznetwork/hermez-node/common" -- "github.com/hermeznetwork/hermez-node/db/historydb" -- "github.com/hermeznetwork/tracerr" - ) - --// Network define status of the network --type Network struct { -- LastEthBlock int64 `json:"lastEthereumBlock"` -- LastSyncBlock int64 `json:"lastSynchedBlock"` -- LastBatch *historydb.BatchAPI `json:"lastBatch"` -- CurrentSlot int64 `json:"currentSlot"` -- NextForgers []NextForger `json:"nextForgers"` --} -- --// NodeConfig is the configuration of the node that is exposed via API --type NodeConfig struct { -- // ForgeDelay in seconds -- ForgeDelay float64 `json:"forgeDelay"` --} -- --// NextForger is a representation of the information of a coordinator and the period will forge --type NextForger struct { -- Coordinator historydb.CoordinatorAPI `json:"coordinator"` -- Period Period `json:"period"` --} -- --// Period is a representation of a period --type Period struct { -- SlotNum int64 `json:"slotNum"` -- FromBlock int64 `json:"fromBlock"` -- ToBlock int64 `json:"toBlock"` -- FromTimestamp time.Time `json:"fromTimestamp"` -- ToTimestamp time.Time `json:"toTimestamp"` --} -- - func (a *API) getState(c *gin.Context) { -- // TODO: There are no events for the buckets information, so now this information will be 0 -- a.status.RLock() -- status := a.status //nolint -- a.status.RUnlock() -- c.JSON(http.StatusOK, status) //nolint --} -- --// SC Vars -- --// SetRollupVariables set Status.Rollup variables --func (a *API) SetRollupVariables(rollupVariables common.RollupVariables) { -- a.status.Lock() -- var rollupVAPI historydb.RollupVariablesAPI -- rollupVAPI.EthBlockNum = rollupVariables.EthBlockNum -- rollupVAPI.FeeAddToken = apitypes.NewBigIntStr(rollupVariables.FeeAddToken) -- rollupVAPI.ForgeL1L2BatchTimeout = rollupVariables.ForgeL1L2BatchTimeout -- rollupVAPI.WithdrawalDelay = rollupVariables.WithdrawalDelay -- -- for i, bucket := range rollupVariables.Buckets { -- var apiBucket historydb.BucketParamsAPI -- apiBucket.CeilUSD = apitypes.NewBigIntStr(bucket.CeilUSD) -- apiBucket.Withdrawals = apitypes.NewBigIntStr(bucket.Withdrawals) -- apiBucket.BlockWithdrawalRate = apitypes.NewBigIntStr(bucket.BlockWithdrawalRate) -- apiBucket.MaxWithdrawals = apitypes.NewBigIntStr(bucket.MaxWithdrawals) -- rollupVAPI.Buckets[i] = apiBucket -- } -- -- rollupVAPI.SafeMode = rollupVariables.SafeMode -- a.status.Rollup = rollupVAPI -- a.status.Unlock() --} -- --// SetWDelayerVariables set Status.WithdrawalDelayer variables --func (a *API) SetWDelayerVariables(wDelayerVariables common.WDelayerVariables) { -- a.status.Lock() -- a.status.WithdrawalDelayer = wDelayerVariables -- a.status.Unlock() --} -- --// SetAuctionVariables set Status.Auction variables --func (a *API) SetAuctionVariables(auctionVariables common.AuctionVariables) { -- a.status.Lock() -- var auctionAPI historydb.AuctionVariablesAPI -- -- auctionAPI.EthBlockNum = auctionVariables.EthBlockNum -- auctionAPI.DonationAddress = auctionVariables.DonationAddress -- auctionAPI.BootCoordinator = auctionVariables.BootCoordinator -- auctionAPI.BootCoordinatorURL = auctionVariables.BootCoordinatorURL -- auctionAPI.DefaultSlotSetBidSlotNum = auctionVariables.DefaultSlotSetBidSlotNum -- auctionAPI.ClosedAuctionSlots = auctionVariables.ClosedAuctionSlots -- auctionAPI.OpenAuctionSlots = auctionVariables.OpenAuctionSlots -- auctionAPI.Outbidding = auctionVariables.Outbidding -- auctionAPI.SlotDeadline = auctionVariables.SlotDeadline -- -- for i, slot := range auctionVariables.DefaultSlotSetBid { -- auctionAPI.DefaultSlotSetBid[i] = apitypes.NewBigIntStr(slot) -- } -- -- for i, ratio := range auctionVariables.AllocationRatio { -- auctionAPI.AllocationRatio[i] = ratio -- } -- -- a.status.Auction = auctionAPI -- a.status.Unlock() --} -- --// Network -- --// UpdateNetworkInfoBlock update Status.Network block related information --func (a *API) UpdateNetworkInfoBlock( -- lastEthBlock, lastSyncBlock common.Block, --) { -- a.status.Network.LastSyncBlock = lastSyncBlock.Num -- a.status.Network.LastEthBlock = lastEthBlock.Num --} -- --// UpdateNetworkInfo update Status.Network information --func (a *API) UpdateNetworkInfo( -- lastEthBlock, lastSyncBlock common.Block, -- lastBatchNum common.BatchNum, currentSlot int64, --) error { -- lastBatch, err := a.h.GetBatchAPI(lastBatchNum) -- if tracerr.Unwrap(err) == sql.ErrNoRows { -- lastBatch = nil -- } else if err != nil { -- return tracerr.Wrap(err) -- } -- lastClosedSlot := currentSlot + int64(a.status.Auction.ClosedAuctionSlots) -- nextForgers, err := a.getNextForgers(lastSyncBlock, currentSlot, lastClosedSlot) -- if tracerr.Unwrap(err) == sql.ErrNoRows { -- nextForgers = nil -- } else if err != nil { -- return tracerr.Wrap(err) -- } -- a.status.Lock() -- a.status.Network.LastSyncBlock = lastSyncBlock.Num -- a.status.Network.LastEthBlock = lastEthBlock.Num -- a.status.Network.LastBatch = lastBatch -- a.status.Network.CurrentSlot = currentSlot -- a.status.Network.NextForgers = nextForgers -- -- // Update buckets withdrawals -- bucketsUpdate, err := a.h.GetBucketUpdatesAPI() -- if tracerr.Unwrap(err) == sql.ErrNoRows { -- bucketsUpdate = nil -- } else if err != nil { -- return tracerr.Wrap(err) -- } -- -- for i, bucketParams := range a.status.Rollup.Buckets { -- for _, bucketUpdate := range bucketsUpdate { -- if bucketUpdate.NumBucket == i { -- bucketParams.Withdrawals = bucketUpdate.Withdrawals -- a.status.Rollup.Buckets[i] = bucketParams -- break -- } -- } -- } -- a.status.Unlock() -- return nil --} -- --// apiSlotToBigInts converts from [6]*apitypes.BigIntStr to [6]*big.Int --func apiSlotToBigInts(defaultSlotSetBid [6]*apitypes.BigIntStr) ([6]*big.Int, error) { -- var slots [6]*big.Int -- -- for i, slot := range defaultSlotSetBid { -- bigInt, ok := new(big.Int).SetString(string(*slot), 10) -- if !ok { -- return slots, tracerr.Wrap(fmt.Errorf("can't convert %T into big.Int", slot)) -- } -- slots[i] = bigInt -- } -- -- return slots, nil --} -- --// getNextForgers returns next forgers --func (a *API) getNextForgers(lastBlock common.Block, currentSlot, lastClosedSlot int64) ([]NextForger, error) { -- secondsPerBlock := int64(15) //nolint:gomnd -- // currentSlot and lastClosedSlot included -- limit := uint(lastClosedSlot - currentSlot + 1) -- bids, _, err := a.h.GetBestBidsAPI(¤tSlot, &lastClosedSlot, nil, &limit, "ASC") -- if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows { -- return nil, tracerr.Wrap(err) -- } -- nextForgers := []NextForger{} -- // Get min bid info -- var minBidInfo []historydb.MinBidInfo -- if currentSlot >= a.status.Auction.DefaultSlotSetBidSlotNum { -- // All min bids can be calculated with the last update of AuctionVariables -- bigIntSlots, err := apiSlotToBigInts(a.status.Auction.DefaultSlotSetBid) -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- -- minBidInfo = []historydb.MinBidInfo{{ -- DefaultSlotSetBid: bigIntSlots, -- DefaultSlotSetBidSlotNum: a.status.Auction.DefaultSlotSetBidSlotNum, -- }} -- } else { -- // Get all the relevant updates from the DB -- minBidInfo, err = a.h.GetAuctionVarsUntilSetSlotNumAPI(lastClosedSlot, int(lastClosedSlot-currentSlot)+1) -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- } -- // Create nextForger for each slot -- for i := currentSlot; i <= lastClosedSlot; i++ { -- fromBlock := i*int64(a.cg.AuctionConstants.BlocksPerSlot) + a.cg.AuctionConstants.GenesisBlockNum -- toBlock := (i+1)*int64(a.cg.AuctionConstants.BlocksPerSlot) + a.cg.AuctionConstants.GenesisBlockNum - 1 -- nextForger := NextForger{ -- Period: Period{ -- SlotNum: i, -- FromBlock: fromBlock, -- ToBlock: toBlock, -- FromTimestamp: lastBlock.Timestamp.Add(time.Second * time.Duration(secondsPerBlock*(fromBlock-lastBlock.Num))), -- ToTimestamp: lastBlock.Timestamp.Add(time.Second * time.Duration(secondsPerBlock*(toBlock-lastBlock.Num))), -- }, -- } -- foundForger := false -- // If there is a bid for a slot, get forger (coordinator) -- for j := range bids { -- slotNum := bids[j].SlotNum -- if slotNum == i { -- // There's a bid for the slot -- // Check if the bid is greater than the minimum required -- for i := 0; i < len(minBidInfo); i++ { -- // Find the most recent update -- if slotNum >= minBidInfo[i].DefaultSlotSetBidSlotNum { -- // Get min bid -- minBidSelector := slotNum % int64(len(a.status.Auction.DefaultSlotSetBid)) -- minBid := minBidInfo[i].DefaultSlotSetBid[minBidSelector] -- // Check if the bid has beaten the minimum -- bid, ok := new(big.Int).SetString(string(bids[j].BidValue), 10) -- if !ok { -- return nil, tracerr.New("Wrong bid value, error parsing it as big.Int") -- } -- if minBid.Cmp(bid) == 1 { -- // Min bid is greater than bid, the slot will be forged by boot coordinator -- break -- } -- foundForger = true -- break -- } -- } -- if !foundForger { // There is no bid or it's smaller than the minimum -- break -- } -- coordinator, err := a.h.GetCoordinatorAPI(bids[j].Bidder) -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- nextForger.Coordinator = *coordinator -- break -- } -- } -- // If there is no bid, the coordinator that will forge is boot coordinator -- if !foundForger { -- nextForger.Coordinator = historydb.CoordinatorAPI{ -- Forger: a.status.Auction.BootCoordinator, -- URL: a.status.Auction.BootCoordinatorURL, -- } -- } -- nextForgers = append(nextForgers, nextForger) -- } -- return nextForgers, nil --} -- --// Metrics -- --// UpdateMetrics update Status.Metrics information --func (a *API) UpdateMetrics() error { -- a.status.RLock() -- if a.status.Network.LastBatch == nil { -- a.status.RUnlock() -- return nil -- } -- batchNum := a.status.Network.LastBatch.BatchNum -- a.status.RUnlock() -- metrics, err := a.h.GetMetricsAPI(batchNum) -+ ni, err := a.h.GetNodeInfo() - if err != nil { -- return tracerr.Wrap(err) -- } -- a.status.Lock() -- a.status.Metrics = *metrics -- a.status.Unlock() -- return nil --} -- --// Recommended fee -- --// UpdateRecommendedFee update Status.RecommendedFee information --func (a *API) UpdateRecommendedFee() error { -- feeExistingAccount, err := a.h.GetAvgTxFeeAPI() -- if err != nil { -- return tracerr.Wrap(err) -- } -- var minFeeUSD float64 -- if a.l2 != nil { -- minFeeUSD = a.l2.MinFeeUSD() -+ retBadReq(err, c) -+ return - } -- a.status.Lock() -- a.status.RecommendedFee.ExistingAccount = -- math.Max(feeExistingAccount, minFeeUSD) -- a.status.RecommendedFee.CreatesAccount = -- math.Max(createAccountExtraFeePercentage*feeExistingAccount, minFeeUSD) -- a.status.RecommendedFee.CreatesAccountAndRegister = -- math.Max(createAccountInternalExtraFeePercentage*feeExistingAccount, minFeeUSD) -- a.status.Unlock() -- return nil -+ c.JSON(http.StatusOK, ni.StateAPI) - } -diff --git a/cli/node/main.go b/cli/node/main.go -index 0138640..d7bf69d 100644 ---- a/cli/node/main.go -+++ b/cli/node/main.go -@@ -143,6 +143,47 @@ func cmdRun(c *cli.Context) error { - return nil - } - -+func cmdServeAPI(c *cli.Context) error { -+ cfgPath := c.String(flagCfg) -+ cfg, err := config.LoadAPIServer(cfgPath) -+ if err != nil { -+ if err := cli.ShowAppHelp(c); err != nil { -+ panic(err) -+ } -+ return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err)) -+ } -+ -+ node, err := node.NewNode(cfg.mode, cfg.node) -+ if err != nil { -+ return tracerr.Wrap(fmt.Errorf("error starting node: %w", err)) -+ } -+ node.Start() -+ -+ stopCh := make(chan interface{}) -+ -+ // catch ^C to send the stop signal -+ ossig := make(chan os.Signal, 1) -+ signal.Notify(ossig, os.Interrupt) -+ const forceStopCount = 3 -+ go func() { -+ n := 0 -+ for sig := range ossig { -+ if sig == os.Interrupt { -+ log.Info("Received Interrupt Signal") -+ stopCh <- nil -+ n++ -+ if n == forceStopCount { -+ log.Fatalf("Received %v Interrupt Signals", forceStopCount) -+ } -+ } -+ } -+ }() -+ <-stopCh -+ node.Stop() -+ -+ return nil -+} -+ - func cmdDiscard(c *cli.Context) error { - _cfg, err := parseCli(c) - if err != nil { -@@ -225,9 +266,6 @@ func getConfig(c *cli.Context) (*Config, error) { - var cfg Config - mode := c.String(flagMode) - nodeCfgPath := c.String(flagCfg) -- if nodeCfgPath == "" { -- return nil, tracerr.Wrap(fmt.Errorf("required flag \"%v\" not set", flagCfg)) -- } - var err error - switch mode { - case modeSync: -@@ -304,6 +342,12 @@ func main() { - Usage: "Run the hermez-node in the indicated mode", - Action: cmdRun, - }, -+ { -+ Name: "serveapi", -+ Aliases: []string{}, -+ Usage: "Serve the API only", -+ Action: cmdServeAPI, -+ }, - { - Name: "discard", - Aliases: []string{}, -diff --git a/config/config.go b/config/config.go -index a9f495f..f517497 100644 ---- a/config/config.go -+++ b/config/config.go -@@ -44,6 +44,13 @@ type ForgeBatchGasCost struct { - L2Tx uint64 `validate:"required"` - } - -+// CoordinatorAPI specifies the configuration parameters of the API in mode -+// coordinator -+type CoordinatorAPI struct { -+ // Coordinator enables the coordinator API endpoints -+ Coordinator bool -+} -+ - // Coordinator is the coordinator specific configuration. - type Coordinator struct { - // ForgerAddress is the address under which this coordinator is forging -@@ -197,10 +204,7 @@ type Coordinator struct { - // ForgeBatch transaction. - ForgeBatchGasCost ForgeBatchGasCost `validate:"required"` - } `validate:"required"` -- API struct { -- // Coordinator enables the coordinator API endpoints -- Coordinator bool -- } `validate:"required"` -+ API CoordinatorAPI `validate:"required"` - Debug struct { - // BatchPath if set, specifies the path where batchInfo is stored - // in JSON in every step/update of the pipeline -@@ -215,6 +219,64 @@ type Coordinator struct { - } - } - -+// NodeAPI specifies the configuration parameters of the API -+type NodeAPI struct { -+ // Address where the API will listen if set -+ Address string -+ // Explorer enables the Explorer API endpoints -+ Explorer bool -+ // UpdateMetricsInterval is the interval between updates of the -+ // API metrics -+ UpdateMetricsInterval Duration -+ // UpdateRecommendedFeeInterval is the interval between updates of the -+ // recommended fees -+ UpdateRecommendedFeeInterval Duration -+ // Maximum concurrent connections allowed between API and SQL -+ MaxSQLConnections int `validate:"required"` -+ // SQLConnectionTimeout is the maximum amount of time that an API request -+ // can wait to stablish a SQL connection -+ SQLConnectionTimeout Duration -+} -+ -+// It's possible to use diferentiated SQL connections for read/write. -+// If the read configuration is 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"` -+ // Host of the PostgreSQL write server -+ HostWrite string `validate:"required"` -+ // User of the PostgreSQL write server -+ UserWrite string `validate:"required"` -+ // Password of the PostgreSQL write server -+ PasswordWrite string `validate:"required"` -+ // Name of the PostgreSQL write server database -+ NameWrite string `validate:"required"` -+ // Port of the PostgreSQL read server -+ PortRead int -+ // Host of the PostgreSQL read server -+ HostRead string -+ // User of the PostgreSQL read server -+ UserRead string -+ // Password of the PostgreSQL read server -+ PasswordRead string -+ // Name of the PostgreSQL read server database -+ NameRead string -+} -+ -+// NodeDebug specifies debug configuration parameters -+type NodeDebug struct { -+ // APIAddress is the address where the debugAPI will listen if -+ // set -+ APIAddress string -+ // MeddlerLogs enables meddler debug mode, where unused columns and struct -+ // fields will be logged -+ MeddlerLogs bool -+ // GinDebugMode sets Gin-Gonic (the web framework) to run in -+ // debug mode -+ GinDebugMode bool -+} -+ - // Node is the hermez node configuration. - type Node struct { - PriceUpdater struct { -@@ -231,32 +293,8 @@ type Node struct { - // Keep is the number of checkpoints to keep - Keep int `validate:"required"` - } `validate:"required"` -- // It's possible to use diferentiated SQL connections for read/write. -- // If the read configuration is not provided, the write one it's going to be used -- // for both reads and writes -- PostgreSQL struct { -- // Port of the PostgreSQL write server -- PortWrite int `validate:"required"` -- // Host of the PostgreSQL write server -- HostWrite string `validate:"required"` -- // User of the PostgreSQL write server -- UserWrite string `validate:"required"` -- // Password of the PostgreSQL write server -- PasswordWrite string `validate:"required"` -- // Name of the PostgreSQL write server database -- NameWrite string `validate:"required"` -- // Port of the PostgreSQL read server -- PortRead int -- // Host of the PostgreSQL read server -- HostRead string -- // User of the PostgreSQL read server -- UserRead string -- // Password of the PostgreSQL read server -- PasswordRead string -- // Name of the PostgreSQL read server database -- NameRead string -- } `validate:"required"` -- Web3 struct { -+ PostgreSQL PostgreSQL `validate:"required"` -+ Web3 struct { - // URL is the URL of the web3 ethereum-node RPC server - URL string `validate:"required"` - } `validate:"required"` -@@ -286,37 +324,34 @@ type Node struct { - // TokenHEZ address - TokenHEZName string `validate:"required"` - } `validate:"required"` -- API struct { -- // Address where the API will listen if set -- Address string -- // Explorer enables the Explorer API endpoints -- Explorer bool -- // UpdateMetricsInterval is the interval between updates of the -- // API metrics -- UpdateMetricsInterval Duration -- // UpdateRecommendedFeeInterval is the interval between updates of the -- // recommended fees -- UpdateRecommendedFeeInterval Duration -- // Maximum concurrent connections allowed between API and SQL -- MaxSQLConnections int `validate:"required"` -- // SQLConnectionTimeout is the maximum amount of time that an API request -- // can wait to stablish a SQL connection -- SQLConnectionTimeout Duration -- } `validate:"required"` -- Debug struct { -- // APIAddress is the address where the debugAPI will listen if -- // set -- APIAddress string -- // MeddlerLogs enables meddler debug mode, where unused columns and struct -- // fields will be logged -- MeddlerLogs bool -- // GinDebugMode sets Gin-Gonic (the web framework) to run in -- // debug mode -- GinDebugMode bool -- } -+ API NodeAPI `validate:"required"` -+ Debug NodeDebug `validate:"required"` - Coordinator Coordinator `validate:"-"` - } - -+type APIServer struct { -+ API NodeAPI `validate:"required"` -+ PostgreSQL PostgreSQL `validate:"required"` -+ Coordinator struct { -+ API struct { -+ // Coordinator enables the coordinator API endpoints -+ Coordinator bool -+ } `validate:"required"` -+ } `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"` -+ // 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:"required"` -+ Debug NodeDebug `validate:"required"` -+} -+ - // Load loads a generic config. - func Load(path string, cfg interface{}) error { - bs, err := ioutil.ReadFile(path) //nolint:gosec -@@ -358,3 +393,16 @@ func LoadNode(path string) (*Node, error) { - } - return &cfg, nil - } -+ -+// LoadAPIServer loads the APIServer configuration from path. -+func LoadAPIServer(path string) (*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)) -+ } -+ validate := validator.New() -+ if err := validate.Struct(cfg); err != nil { -+ return nil, tracerr.Wrap(fmt.Errorf("error validating configuration file: %w", err)) -+ } -+ return &cfg, nil -+} -diff --git a/db/historydb/apiqueries.go b/db/historydb/apiqueries.go -index 073608c..e187448 100644 ---- a/db/historydb/apiqueries.go -+++ b/db/historydb/apiqueries.go -@@ -32,9 +32,12 @@ func (hdb *HistoryDB) GetBatchAPI(batchNum common.BatchNum) (*BatchAPI, error) { - return nil, tracerr.Wrap(err) - } - defer hdb.apiConnCon.Release() -+ return hdb.getBatchAPI(hdb.dbRead, batchNum) -+} -+func (hdb *HistoryDB) getBatchAPI(d meddler.DB, batchNum common.BatchNum) (*BatchAPI, error) { - batch := &BatchAPI{} - return batch, tracerr.Wrap(meddler.QueryRow( -- hdb.dbRead, batch, -+ d, batch, - `SELECT batch.item_id, batch.batch_num, batch.eth_block_num, - batch.forger_addr, batch.fees_collected, batch.total_fees_usd, batch.state_root, - batch.num_accounts, batch.exit_root, batch.forge_l1_txs_num, batch.slot_num, -@@ -180,6 +183,14 @@ func (hdb *HistoryDB) GetBestBidsAPI( - return nil, 0, tracerr.Wrap(err) - } - defer hdb.apiConnCon.Release() -+ return hdb.getBestBidsAPI(hdb.dbRead, minSlotNum, maxSlotNum, bidderAddr, limit, order) -+} -+func (hdb *HistoryDB) getBestBidsAPI( -+ d meddler.DB, -+ minSlotNum, maxSlotNum *int64, -+ bidderAddr *ethCommon.Address, -+ limit *uint, order string, -+) ([]BidAPI, uint64, error) { - var query string - var args []interface{} - // JOIN the best bid of each slot with the latest update of each coordinator -@@ -214,7 +225,7 @@ func (hdb *HistoryDB) GetBestBidsAPI( - } - query = hdb.dbRead.Rebind(queryStr) - bidPtrs := []*BidAPI{} -- if err := meddler.QueryAll(hdb.dbRead, &bidPtrs, query, args...); err != nil { -+ if err := meddler.QueryAll(d, &bidPtrs, query, args...); err != nil { - return nil, 0, tracerr.Wrap(err) - } - // log.Debug(query) -@@ -697,25 +708,6 @@ func (hdb *HistoryDB) GetExitsAPI( - return db.SlicePtrsToSlice(exits).([]ExitAPI), exits[0].TotalItems - uint64(len(exits)), nil - } - --// GetBucketUpdatesAPI retrieves latest values for each bucket --func (hdb *HistoryDB) GetBucketUpdatesAPI() ([]BucketUpdateAPI, error) { -- cancel, err := hdb.apiConnCon.Acquire() -- defer cancel() -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- defer hdb.apiConnCon.Release() -- var bucketUpdates []*BucketUpdateAPI -- err = meddler.QueryAll( -- hdb.dbRead, &bucketUpdates, -- `SELECT num_bucket, withdrawals FROM bucket_update -- WHERE item_id in(SELECT max(item_id) FROM bucket_update -- group by num_bucket) -- ORDER BY num_bucket ASC;`, -- ) -- return db.SlicePtrsToSlice(bucketUpdates).([]BucketUpdateAPI), tracerr.Wrap(err) --} -- - // GetCoordinatorsAPI returns a list of coordinators from the DB and pagination info - func (hdb *HistoryDB) GetCoordinatorsAPI( - bidderAddr, forgerAddr *ethCommon.Address, -@@ -800,29 +792,6 @@ func (hdb *HistoryDB) GetAuctionVarsAPI() (*common.AuctionVariables, error) { - return auctionVars, tracerr.Wrap(err) - } - --// GetAuctionVarsUntilSetSlotNumAPI returns all the updates of the auction vars --// from the last entry in which DefaultSlotSetBidSlotNum <= slotNum --func (hdb *HistoryDB) GetAuctionVarsUntilSetSlotNumAPI(slotNum int64, maxItems int) ([]MinBidInfo, error) { -- cancel, err := hdb.apiConnCon.Acquire() -- defer cancel() -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- defer hdb.apiConnCon.Release() -- auctionVars := []*MinBidInfo{} -- query := ` -- SELECT DISTINCT default_slot_set_bid, default_slot_set_bid_slot_num FROM auction_vars -- WHERE default_slot_set_bid_slot_num < $1 -- ORDER BY default_slot_set_bid_slot_num DESC -- LIMIT $2; -- ` -- err = meddler.QueryAll(hdb.dbRead, &auctionVars, query, slotNum, maxItems) -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- return db.SlicePtrsToSlice(auctionVars).([]MinBidInfo), nil --} -- - // GetAccountAPI returns an account by its index - func (hdb *HistoryDB) GetAccountAPI(idx common.Idx) (*AccountAPI, error) { - cancel, err := hdb.apiConnCon.Acquire() -@@ -941,135 +910,47 @@ func (hdb *HistoryDB) GetAccountsAPI( - accounts[0].TotalItems - uint64(len(accounts)), nil - } - --// GetMetricsAPI returns metrics --func (hdb *HistoryDB) GetMetricsAPI(lastBatchNum common.BatchNum) (*Metrics, error) { -+// GetCommonAccountAPI returns the account associated to an account idx -+func (hdb *HistoryDB) GetCommonAccountAPI(idx common.Idx) (*common.Account, error) { - cancel, err := hdb.apiConnCon.Acquire() - defer cancel() - if err != nil { - return nil, tracerr.Wrap(err) - } - defer hdb.apiConnCon.Release() -- metricsTotals := &MetricsTotals{} -- metrics := &Metrics{} -- err = meddler.QueryRow( -- hdb.dbRead, metricsTotals, `SELECT -- COALESCE (MIN(batch.batch_num), 0) as batch_num, -- COALESCE (MIN(block.timestamp), NOW()) AS min_timestamp, -- COALESCE (MAX(block.timestamp), NOW()) AS max_timestamp -- FROM batch INNER JOIN block ON batch.eth_block_num = block.eth_block_num -- WHERE block.timestamp >= NOW() - INTERVAL '24 HOURS' and batch.batch_num <= $1;`, lastBatchNum) -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- -- err = meddler.QueryRow( -- hdb.dbRead, metricsTotals, `SELECT COUNT(*) as total_txs -- FROM tx WHERE tx.batch_num between $1 AND $2;`, metricsTotals.FirstBatchNum, lastBatchNum) -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- -- seconds := metricsTotals.MaxTimestamp.Sub(metricsTotals.MinTimestamp).Seconds() -- // Avoid dividing by 0 -- if seconds == 0 { -- seconds++ -- } -- -- metrics.TransactionsPerSecond = float64(metricsTotals.TotalTransactions) / seconds -- -- if (lastBatchNum - metricsTotals.FirstBatchNum) > 0 { -- metrics.TransactionsPerBatch = float64(metricsTotals.TotalTransactions) / -- float64(lastBatchNum-metricsTotals.FirstBatchNum+1) -- } else { -- metrics.TransactionsPerBatch = float64(0) -- } -- -- err = meddler.QueryRow( -- hdb.dbRead, metricsTotals, `SELECT COUNT(*) AS total_batches, -- COALESCE (SUM(total_fees_usd), 0) AS total_fees FROM batch -- WHERE batch_num between $1 and $2;`, metricsTotals.FirstBatchNum, lastBatchNum) -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- -- if metricsTotals.TotalBatches > 0 { -- metrics.BatchFrequency = seconds / float64(metricsTotals.TotalBatches) -- } else { -- metrics.BatchFrequency = 0 -- } -- if metricsTotals.TotalTransactions > 0 { -- metrics.AvgTransactionFee = metricsTotals.TotalFeesUSD / float64(metricsTotals.TotalTransactions) -- } else { -- metrics.AvgTransactionFee = 0 -- } -- err = meddler.QueryRow( -- hdb.dbRead, metrics, -- `SELECT COUNT(*) AS total_bjjs, COUNT(DISTINCT(bjj)) AS total_accounts FROM account;`) -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -+ account := &common.Account{} - err = meddler.QueryRow( -- hdb.dbRead, metrics, -- `SELECT COALESCE (AVG(EXTRACT(EPOCH FROM (forged.timestamp - added.timestamp))), 0) AS estimatedTimeToForgeL1 FROM tx -- INNER JOIN block AS added ON tx.eth_block_num = added.eth_block_num -- INNER JOIN batch AS forged_batch ON tx.batch_num = forged_batch.batch_num -- INNER JOIN block AS forged ON forged_batch.eth_block_num = forged.eth_block_num -- WHERE tx.batch_num between $1 and $2 AND tx.is_l1 AND tx.user_origin;`, -- metricsTotals.FirstBatchNum, lastBatchNum, -+ hdb.dbRead, account, `SELECT * FROM account WHERE idx = $1;`, idx, - ) -- if err != nil { -- return nil, tracerr.Wrap(err) -- } -- -- return metrics, nil -+ return account, tracerr.Wrap(err) - } - --// GetAvgTxFeeAPI returns average transaction fee of the last 1h --func (hdb *HistoryDB) GetAvgTxFeeAPI() (float64, error) { -+// GetCoordinatorAPI returns a coordinator by its bidderAddr -+func (hdb *HistoryDB) GetCoordinatorAPI(bidderAddr ethCommon.Address) (*CoordinatorAPI, error) { - cancel, err := hdb.apiConnCon.Acquire() - defer cancel() - if err != nil { -- return 0, tracerr.Wrap(err) -+ return nil, tracerr.Wrap(err) - } - defer hdb.apiConnCon.Release() -- metricsTotals := &MetricsTotals{} -- err = meddler.QueryRow( -- hdb.dbRead, metricsTotals, `SELECT COUNT(tx.*) as total_txs, -- COALESCE (MIN(tx.batch_num), 0) as batch_num -- FROM tx INNER JOIN block ON tx.eth_block_num = block.eth_block_num -- WHERE block.timestamp >= NOW() - INTERVAL '1 HOURS';`) -- if err != nil { -- return 0, tracerr.Wrap(err) -- } -- err = meddler.QueryRow( -- hdb.dbRead, metricsTotals, `SELECT COUNT(*) AS total_batches, -- COALESCE (SUM(total_fees_usd), 0) AS total_fees FROM batch -- WHERE batch_num > $1;`, metricsTotals.FirstBatchNum) -- if err != nil { -- return 0, tracerr.Wrap(err) -- } -- -- var avgTransactionFee float64 -- if metricsTotals.TotalTransactions > 0 { -- avgTransactionFee = metricsTotals.TotalFeesUSD / float64(metricsTotals.TotalTransactions) -- } else { -- avgTransactionFee = 0 -- } -- -- return avgTransactionFee, nil -+ return hdb.getCoordinatorAPI(hdb.dbRead, bidderAddr) -+} -+func (hdb *HistoryDB) getCoordinatorAPI(d meddler.DB, bidderAddr ethCommon.Address) (*CoordinatorAPI, error) { -+ coordinator := &CoordinatorAPI{} -+ err := meddler.QueryRow( -+ d, coordinator, -+ "SELECT * FROM coordinator WHERE bidder_addr = $1 ORDER BY item_id DESC LIMIT 1;", -+ bidderAddr, -+ ) -+ return coordinator, tracerr.Wrap(err) - } - --// GetCommonAccountAPI returns the account associated to an account idx --func (hdb *HistoryDB) GetCommonAccountAPI(idx common.Idx) (*common.Account, error) { -+func (hdb *HistoryDB) GetNodeInfoAPI() (*NodeInfo, error) { - cancel, err := hdb.apiConnCon.Acquire() - defer cancel() - if err != nil { - return nil, tracerr.Wrap(err) - } - defer hdb.apiConnCon.Release() -- account := &common.Account{} -- err = meddler.QueryRow( -- hdb.dbRead, account, `SELECT * FROM account WHERE idx = $1;`, idx, -- ) -- return account, tracerr.Wrap(err) -+ return hdb.GetNodeInfo() - } -diff --git a/db/historydb/historydb.go b/db/historydb/historydb.go -index e887e70..3997f57 100644 ---- a/db/historydb/historydb.go -+++ b/db/historydb/historydb.go -@@ -1139,17 +1139,6 @@ func (hdb *HistoryDB) AddBlockSCData(blockData *common.BlockData) (err error) { - return tracerr.Wrap(txn.Commit()) - } - --// GetCoordinatorAPI returns a coordinator by its bidderAddr --func (hdb *HistoryDB) GetCoordinatorAPI(bidderAddr ethCommon.Address) (*CoordinatorAPI, error) { -- coordinator := &CoordinatorAPI{} -- err := meddler.QueryRow( -- hdb.dbRead, coordinator, -- "SELECT * FROM coordinator WHERE bidder_addr = $1 ORDER BY item_id DESC LIMIT 1;", -- bidderAddr, -- ) -- return coordinator, tracerr.Wrap(err) --} -- - // AddAuctionVars insert auction vars into the DB - func (hdb *HistoryDB) AddAuctionVars(auctionVars *common.AuctionVariables) error { - return tracerr.Wrap(meddler.Insert(hdb.dbWrite, "auction_vars", auctionVars)) -diff --git a/db/historydb/views.go b/db/historydb/views.go -index fe71733..e7bebe5 100644 ---- a/db/historydb/views.go -+++ b/db/historydb/views.go -@@ -313,17 +313,6 @@ type Metrics struct { - EstimatedTimeToForgeL1 float64 `json:"estimatedTimeToForgeL1" meddler:"estimatedTimeToForgeL1"` - } - --// MetricsTotals is used to get temporal information from HistoryDB --// to calculate data to be stored into the Metrics struct --type MetricsTotals struct { -- TotalTransactions uint64 `meddler:"total_txs"` -- FirstBatchNum common.BatchNum `meddler:"batch_num"` -- TotalBatches int64 `meddler:"total_batches"` -- TotalFeesUSD float64 `meddler:"total_fees"` -- MinTimestamp time.Time `meddler:"min_timestamp,utctime"` -- MaxTimestamp time.Time `meddler:"max_timestamp,utctime"` --} -- - // BidAPI is a representation of a bid with additional information - // required by the API - type BidAPI struct { -diff --git a/db/migrations/0001.sql b/db/migrations/0001.sql -index d09a432..ce5dbe0 100644 ---- a/db/migrations/0001.sql -+++ b/db/migrations/0001.sql -@@ -661,6 +661,13 @@ CREATE TABLE account_creation_auth ( - timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT timezone('utc', now()) - ); - -+CREATE TABLE node_info ( -+ state BYTEA, -- object returned by GET /state -+ pool_max_txs BIGINT, -- L2DB config -+ min_fee NUMERIC, -- L2DB config -+ constants BYTEA -- info of the network that is constant -+) -+ - -- +migrate Down - -- triggers - DROP TRIGGER IF EXISTS trigger_token_usd_update ON token; -@@ -675,6 +682,7 @@ DROP FUNCTION IF EXISTS set_tx; - DROP FUNCTION IF EXISTS forge_l1_user_txs; - DROP FUNCTION IF EXISTS set_pool_tx; - -- drop tables IF EXISTS -+DROP TABLE IF EXISTS node_info; - DROP TABLE IF EXISTS account_creation_auth; - DROP TABLE IF EXISTS tx_pool; - DROP TABLE IF EXISTS auction_vars; -diff --git a/go.mod b/go.mod -index 2fdd0e5..3f03bdc 100644 ---- a/go.mod -+++ b/go.mod -@@ -26,6 +26,7 @@ require ( - github.com/russross/meddler v1.0.0 - github.com/stretchr/testify v1.6.1 - github.com/urfave/cli/v2 v2.2.0 -+ github.com/ztrue/tracerr v0.3.0 - go.uber.org/zap v1.16.0 - golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 - golang.org/x/net v0.0.0-20200822124328-c89045814202 -diff --git a/go.sum b/go.sum -index 3def156..749aa10 100644 ---- a/go.sum -+++ b/go.sum -@@ -690,6 +690,8 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDf - github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= - github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= - github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -+github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= -+github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= - go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= - go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= - go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -diff --git a/node/node.go b/node/node.go -index ddd5bdf..252b9b3 100644 ---- a/node/node.go -+++ b/node/node.go -@@ -67,6 +67,7 @@ type Node struct { - mode Mode - sqlConnRead *sqlx.DB - sqlConnWrite *sqlx.DB -+ historyDB *historydb.HistoryDB - ctx context.Context - wg sync.WaitGroup - cancel context.CancelFunc -@@ -235,6 +236,20 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) { - WDelayer: *sync.WDelayerConstants(), - } - -+ if err := historyDB.SetInitialNodeInfo( -+ cfg.Coordinator.L2DB.MaxTxs, -+ cfg.Coordinator.L2DB.MinFeeUSD, -+ &historydb.Constants{ -+ RollupConstants: scConsts.Rollup, -+ AuctionConstants: scConsts.Auction, -+ WDelayerConstants: scConsts.WDelayer, -+ ChainID: chainIDU16, -+ HermezAddress: cfg.SmartContracts.Rollup, -+ }, -+ ); err != nil { -+ return nil, tracerr.Wrap(err) -+ } -+ - var coord *coordinator.Coordinator - var l2DB *l2db.L2DB - if mode == ModeCoordinator { -@@ -400,23 +415,11 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) { - coord, cfg.API.Explorer, - server, - historyDB, -- stateDB, - l2DB, -- &api.Config{ -- RollupConstants: scConsts.Rollup, -- AuctionConstants: scConsts.Auction, -- WDelayerConstants: scConsts.WDelayer, -- ChainID: chainIDU16, -- HermezAddress: cfg.SmartContracts.Rollup, -- }, -- cfg.Coordinator.ForgeDelay.Duration, - ) - if err != nil { - return nil, tracerr.Wrap(err) - } -- nodeAPI.api.SetRollupVariables(*initSCVars.Rollup) -- nodeAPI.api.SetAuctionVariables(*initSCVars.Auction) -- nodeAPI.api.SetWDelayerVariables(*initSCVars.WDelayer) - } - var debugAPI *debugapi.DebugAPI - if cfg.Debug.APIAddress != "" { -@@ -438,11 +441,108 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) { - mode: mode, - sqlConnRead: dbRead, - sqlConnWrite: dbWrite, -+ historyDB: historyDB, - ctx: ctx, - cancel: cancel, - }, nil - } - -+// APIServer is a server that only runs the API -+type APIServer struct { -+ nodeAPI *NodeAPI -+} -+ -+func NewAPIServer(mode Mode, cfg *config.APIServer) (*APIServer, error) { -+ // NOTE: I just copied some parts of NewNode related to starting the -+ // API, but it still cotains many parameters that are not available -+ meddler.Debug = cfg.Debug.MeddlerLogs -+ // Stablish DB connection -+ dbWrite, err := dbUtils.InitSQLDB( -+ cfg.PostgreSQL.PortWrite, -+ cfg.PostgreSQL.HostWrite, -+ cfg.PostgreSQL.UserWrite, -+ cfg.PostgreSQL.PasswordWrite, -+ cfg.PostgreSQL.NameWrite, -+ ) -+ if err != nil { -+ return nil, tracerr.Wrap(fmt.Errorf("dbUtils.InitSQLDB: %w", err)) -+ } -+ var dbRead *sqlx.DB -+ if cfg.PostgreSQL.HostRead == "" { -+ dbRead = dbWrite -+ } else if cfg.PostgreSQL.HostRead == cfg.PostgreSQL.HostWrite { -+ return nil, tracerr.Wrap(fmt.Errorf( -+ "PostgreSQL.HostRead and PostgreSQL.HostWrite must be different", -+ )) -+ } else { -+ dbRead, err = dbUtils.InitSQLDB( -+ cfg.PostgreSQL.PortRead, -+ cfg.PostgreSQL.HostRead, -+ cfg.PostgreSQL.UserRead, -+ cfg.PostgreSQL.PasswordRead, -+ cfg.PostgreSQL.NameRead, -+ ) -+ if err != nil { -+ return nil, tracerr.Wrap(fmt.Errorf("dbUtils.InitSQLDB: %w", err)) -+ } -+ } -+ var apiConnCon *dbUtils.APIConnectionController -+ if cfg.API.Explorer || mode == ModeCoordinator { -+ apiConnCon = dbUtils.NewAPICnnectionController( -+ cfg.API.MaxSQLConnections, -+ cfg.API.SQLConnectionTimeout.Duration, -+ ) -+ } -+ -+ historyDB := historydb.NewHistoryDB(dbRead, dbWrite, apiConnCon) -+ -+ var l2DB *l2db.L2DB -+ if mode == ModeCoordinator { -+ l2DB = l2db.NewL2DB( -+ dbRead, dbWrite, -+ cfg.L2DB.SafetyPeriod, -+ cfg.L2DB.MaxTxs, -+ cfg.L2DB.MinFeeUSD, -+ cfg.L2DB, -+ apiConnCon, -+ ) -+ } -+ -+ var nodeAPI *NodeAPI -+ if cfg.API.Address != "" { -+ if cfg.Debug.GinDebugMode { -+ gin.SetMode(gin.DebugMode) -+ } else { -+ gin.SetMode(gin.ReleaseMode) -+ } -+ if cfg.API.UpdateMetricsInterval.Duration == 0 { -+ return nil, tracerr.Wrap(fmt.Errorf("invalid cfg.API.UpdateMetricsInterval: %v", -+ cfg.API.UpdateMetricsInterval.Duration)) -+ } -+ if cfg.API.UpdateRecommendedFeeInterval.Duration == 0 { -+ return nil, tracerr.Wrap(fmt.Errorf("invalid cfg.API.UpdateRecommendedFeeInterval: %v", -+ cfg.API.UpdateRecommendedFeeInterval.Duration)) -+ } -+ server := gin.Default() -+ coord := false -+ if mode == ModeCoordinator { -+ coord = cfg.Coordinator.API.Coordinator -+ } -+ var err error -+ nodeAPI, err = NewNodeAPI( -+ cfg.API.Address, -+ coord, cfg.API.Explorer, -+ server, -+ historyDB, -+ l2DB, -+ ) -+ if err != nil { -+ return nil, tracerr.Wrap(err) -+ } -+ } -+ // ETC... -+} -+ - // NodeAPI holds the node http API - type NodeAPI struct { //nolint:golint - api *api.API -@@ -462,10 +562,7 @@ func NewNodeAPI( - coordinatorEndpoints, explorerEndpoints bool, - server *gin.Engine, - hdb *historydb.HistoryDB, -- sdb *statedb.StateDB, - l2db *l2db.L2DB, -- config *api.Config, -- forgeDelay time.Duration, - ) (*NodeAPI, error) { - engine := gin.Default() - engine.NoRoute(handleNoRoute) -@@ -475,10 +572,6 @@ func NewNodeAPI( - engine, - hdb, - l2db, -- config, -- &api.NodeConfig{ -- ForgeDelay: forgeDelay.Seconds(), -- }, - ) - if err != nil { - return nil, tracerr.Wrap(err) -@@ -534,17 +627,17 @@ func (n *Node) handleNewBlock(ctx context.Context, stats *synchronizer.Stats, va - } - if n.nodeAPI != nil { - if vars.Rollup != nil { -- n.nodeAPI.api.SetRollupVariables(*vars.Rollup) -+ n.historyDB.SetRollupVariables(*vars.Rollup) - } - if vars.Auction != nil { -- n.nodeAPI.api.SetAuctionVariables(*vars.Auction) -+ n.historyDB.SetAuctionVariables(*vars.Auction) - } - if vars.WDelayer != nil { -- n.nodeAPI.api.SetWDelayerVariables(*vars.WDelayer) -+ n.historyDB.SetWDelayerVariables(*vars.WDelayer) - } - - if stats.Synced() { -- if err := n.nodeAPI.api.UpdateNetworkInfo( -+ if err := n.historyDB.UpdateNetworkInfo( - stats.Eth.LastBlock, stats.Sync.LastBlock, - common.BatchNum(stats.Eth.LastBatchNum), - stats.Sync.Auction.CurrentSlot.SlotNum, -@@ -552,7 +645,7 @@ func (n *Node) handleNewBlock(ctx context.Context, stats *synchronizer.Stats, va - log.Errorw("API.UpdateNetworkInfo", "err", err) - } - } else { -- n.nodeAPI.api.UpdateNetworkInfoBlock( -+ n.historyDB.UpdateNetworkInfoBlock( - stats.Eth.LastBlock, stats.Sync.LastBlock, - ) - } -@@ -566,15 +659,13 @@ func (n *Node) handleReorg(ctx context.Context, stats *synchronizer.Stats, vars - Vars: vars, - }) - } -- if n.nodeAPI != nil { -- vars := n.sync.SCVars() -- n.nodeAPI.api.SetRollupVariables(*vars.Rollup) -- n.nodeAPI.api.SetAuctionVariables(*vars.Auction) -- n.nodeAPI.api.SetWDelayerVariables(*vars.WDelayer) -- n.nodeAPI.api.UpdateNetworkInfoBlock( -- stats.Eth.LastBlock, stats.Sync.LastBlock, -- ) -- } -+ vars = n.sync.SCVars() -+ n.historyDB.SetRollupVariables(*vars.Rollup) -+ n.historyDB.SetAuctionVariables(*vars.Auction) -+ n.historyDB.SetWDelayerVariables(*vars.WDelayer) -+ n.historyDB.UpdateNetworkInfoBlock( -+ stats.Eth.LastBlock, stats.Sync.LastBlock, -+ ) - } - - // TODO(Edu): Consider keeping the `lastBlock` inside synchronizer so that we -@@ -704,7 +795,7 @@ func (n *Node) StartNodeAPI() { - n.wg.Add(1) - go func() { - // Do an initial update on startup -- if err := n.nodeAPI.api.UpdateMetrics(); err != nil { -+ if err := n.historyDB.UpdateMetrics(); err != nil { - log.Errorw("API.UpdateMetrics", "err", err) - } - for { -@@ -714,7 +805,7 @@ func (n *Node) StartNodeAPI() { - n.wg.Done() - return - case <-time.After(n.cfg.API.UpdateMetricsInterval.Duration): -- if err := n.nodeAPI.api.UpdateMetrics(); err != nil { -+ if err := n.historyDB.UpdateMetrics(); err != nil { - log.Errorw("API.UpdateMetrics", "err", err) - } - } -@@ -724,7 +815,7 @@ func (n *Node) StartNodeAPI() { - n.wg.Add(1) - go func() { - // Do an initial update on startup -- if err := n.nodeAPI.api.UpdateRecommendedFee(); err != nil { -+ if err := n.historyDB.UpdateRecommendedFee(); err != nil { - log.Errorw("API.UpdateRecommendedFee", "err", err) - } - for { -@@ -734,7 +825,7 @@ func (n *Node) StartNodeAPI() { - n.wg.Done() - return - case <-time.After(n.cfg.API.UpdateRecommendedFeeInterval.Duration): -- if err := n.nodeAPI.api.UpdateRecommendedFee(); err != nil { -+ if err := n.historyDB.UpdateRecommendedFee(); err != nil { - log.Errorw("API.UpdateRecommendedFee", "err", err) - } - } diff --git a/go.mod b/go.mod index 3f03bdc..2fdd0e5 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,6 @@ require ( github.com/russross/meddler v1.0.0 github.com/stretchr/testify v1.6.1 github.com/urfave/cli/v2 v2.2.0 - github.com/ztrue/tracerr v0.3.0 go.uber.org/zap v1.16.0 golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 golang.org/x/net v0.0.0-20200822124328-c89045814202 diff --git a/go.sum b/go.sum index 749aa10..3def156 100644 --- a/go.sum +++ b/go.sum @@ -690,8 +690,6 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDf github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= -github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=