You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1326 lines
44 KiB

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(&currentSlot, &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)
}
}