diff --git a/.github/workflows/bridge_history_api.yml b/.github/workflows/bridge_history_api.yml index 49250d9da..cd4b44ff9 100644 --- a/.github/workflows/bridge_history_api.yml +++ b/.github/workflows/bridge_history_api.yml @@ -25,20 +25,20 @@ defaults: working-directory: 'bridge-history-api' jobs: - # check: - # if: github.event.pull_request.draft == false - # runs-on: ubuntu-latest - # steps: - # - name: Install Go - # uses: actions/setup-go@v2 - # with: - # go-version: 1.19.x - # - name: Checkout code - # uses: actions/checkout@v2 - # - name: Lint - # run: | - # rm -rf $HOME/.cache/golangci-lint - # make lint + check: + if: github.event.pull_request.draft == false + runs-on: ubuntu-latest + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: 1.19.x + - name: Checkout code + uses: actions/checkout@v2 + - name: Lint + run: | + rm -rf $HOME/.cache/golangci-lint + make lint test: if: github.event.pull_request.draft == false runs-on: ubuntu-latest diff --git a/bridge-history-api/cmd/backend_server/app/app.go b/bridge-history-api/cmd/backend_server/app/app.go index 26f7408d0..e46ac00a0 100644 --- a/bridge-history-api/cmd/backend_server/app/app.go +++ b/bridge-history-api/cmd/backend_server/app/app.go @@ -24,37 +24,40 @@ var ( var database db.OrmFactory func pong(ctx iris.Context) { - ctx.WriteString("pong") + _, err := ctx.WriteString("pong") + if err != nil { + log.Error("failed to write pong", "err", err) + } } -func setupQueryByAddressHandler(backend_app *mvc.Application) { +func setupQueryByAddressHandler(backendApp *mvc.Application) { // Register Dependencies. - backend_app.Register( + backendApp.Register( database, service.NewHistoryService, ) // Register Controllers. - backend_app.Handle(new(controller.QueryAddressController)) + backendApp.Handle(new(controller.QueryAddressController)) } -func setupQueryClaimableHandler(backend_app *mvc.Application) { +func setupQueryClaimableHandler(backendApp *mvc.Application) { // Register Dependencies. - backend_app.Register( + backendApp.Register( database, service.NewHistoryService, ) // Register Controllers. - backend_app.Handle(new(controller.QueryClaimableController)) + backendApp.Handle(new(controller.QueryClaimableController)) } -func setupQueryByHashHandler(backend_app *mvc.Application) { - backend_app.Register( +func setupQueryByHashHandler(backendApp *mvc.Application) { + backendApp.Register( database, service.NewHistoryService, ) - backend_app.Handle(new(controller.QueryHashController)) + backendApp.Handle(new(controller.QueryHashController)) } func init() { @@ -87,7 +90,11 @@ func action(ctx *cli.Context) error { if err != nil { log.Crit("can not connect to database", "err", err) } - defer database.Close() + defer func() { + if err = database.Close(); err != nil { + log.Error("failed to close database", "err", err) + } + }() bridgeApp := iris.New() bridgeApp.UseRouter(corsOptions) bridgeApp.Get("/ping", pong).Describe("healthcheck") diff --git a/bridge-history-api/cmd/cross_msg_fetcher/app/app.go b/bridge-history-api/cmd/cross_msg_fetcher/app/app.go index 4fdfa95a5..b76e614b2 100644 --- a/bridge-history-api/cmd/cross_msg_fetcher/app/app.go +++ b/bridge-history-api/cmd/cross_msg_fetcher/app/app.go @@ -12,8 +12,8 @@ import ( "github.com/urfave/cli/v2" "bridge-history-api/config" - "bridge-history-api/cross_msg" - "bridge-history-api/cross_msg/message_proof" + "bridge-history-api/crossmsg" + "bridge-history-api/crossmsg/messageproof" "bridge-history-api/db" cutils "bridge-history-api/utils" ) @@ -54,15 +54,20 @@ func action(ctx *cli.Context) error { if err != nil { log.Crit("failed to connect l2 geth", "config file", cfgFile, "error", err) } + db, err := db.NewOrmFactory(cfg) - defer db.Close() + defer func() { + if deferErr := db.Close(); deferErr != nil { + log.Error("failed to close db", "err", err) + } + }() if err != nil { log.Crit("failed to connect to db", "config file", cfgFile, "error", err) } - l1worker := &cross_msg.FetchEventWorker{F: cross_msg.L1FetchAndSaveEvents, G: cross_msg.GetLatestL1ProcessedHeight, Name: "L1 events fetch Worker"} + l1worker := &crossmsg.FetchEventWorker{F: crossmsg.L1FetchAndSaveEvents, G: crossmsg.GetLatestL1ProcessedHeight, Name: "L1 events fetch Worker"} - l2worker := &cross_msg.FetchEventWorker{F: cross_msg.L2FetchAndSaveEvents, G: cross_msg.GetLatestL2ProcessedHeight, Name: "L2 events fetch Worker"} + l2worker := &crossmsg.FetchEventWorker{F: crossmsg.L2FetchAndSaveEvents, G: crossmsg.GetLatestL2ProcessedHeight, Name: "L2 events fetch Worker"} l1AddressList := []common.Address{ common.HexToAddress(cfg.L1.CustomERC20GatewayAddr), @@ -84,7 +89,7 @@ func action(ctx *cli.Context) error { common.HexToAddress(cfg.L2.WETHGatewayAddr), } - l1crossMsgFetcher, err := cross_msg.NewCrossMsgFetcher(subCtx, cfg.L1, db, l1client, l1worker, l1AddressList, cross_msg.L1ReorgHandling) + l1crossMsgFetcher, err := crossmsg.NewMsgFetcher(subCtx, cfg.L1, db, l1client, l1worker, l1AddressList, crossmsg.L1ReorgHandling) if err != nil { log.Crit("failed to create l1 cross message fetcher", "error", err) } @@ -92,7 +97,7 @@ func action(ctx *cli.Context) error { go l1crossMsgFetcher.Start() defer l1crossMsgFetcher.Stop() - l2crossMsgFetcher, err := cross_msg.NewCrossMsgFetcher(subCtx, cfg.L2, db, l2client, l2worker, l2AddressList, cross_msg.L2ReorgHandling) + l2crossMsgFetcher, err := crossmsg.NewMsgFetcher(subCtx, cfg.L2, db, l2client, l2worker, l2AddressList, crossmsg.L2ReorgHandling) if err != nil { log.Crit("failed to create l2 cross message fetcher", "error", err) } @@ -101,17 +106,17 @@ func action(ctx *cli.Context) error { defer l2crossMsgFetcher.Stop() // BlockTimestamp fetcher for l1 and l2 - l1BlockTimeFetcher := cross_msg.NewBlockTimestampFetcher(subCtx, cfg.L1.Confirmation, int(cfg.L1.BlockTime), l1client, db.UpdateL1BlockTimestamp, db.GetL1EarliestNoBlockTimestampHeight) + l1BlockTimeFetcher := crossmsg.NewBlockTimestampFetcher(subCtx, cfg.L1.Confirmation, int(cfg.L1.BlockTime), l1client, db.UpdateL1BlockTimestamp, db.GetL1EarliestNoBlockTimestampHeight) go l1BlockTimeFetcher.Start() defer l1BlockTimeFetcher.Stop() - l2BlockTimeFetcher := cross_msg.NewBlockTimestampFetcher(subCtx, cfg.L2.Confirmation, int(cfg.L2.BlockTime), l2client, db.UpdateL2BlockTimestamp, db.GetL2EarliestNoBlockTimestampHeight) + l2BlockTimeFetcher := crossmsg.NewBlockTimestampFetcher(subCtx, cfg.L2.Confirmation, int(cfg.L2.BlockTime), l2client, db.UpdateL2BlockTimestamp, db.GetL2EarliestNoBlockTimestampHeight) go l2BlockTimeFetcher.Start() defer l2BlockTimeFetcher.Stop() // Proof updater and batch fetcher - l2msgProofUpdater := message_proof.NewMsgProofUpdater(subCtx, cfg.L1.Confirmation, cfg.BatchInfoFetcher.BatchIndexStartBlock, db) - batchFetcher := cross_msg.NewBatchInfoFetcher(subCtx, common.HexToAddress(cfg.BatchInfoFetcher.ScrollChainAddr), cfg.BatchInfoFetcher.BatchIndexStartBlock, cfg.L1.Confirmation, int(cfg.L1.BlockTime), l1client, db, l2msgProofUpdater) + l2msgProofUpdater := messageproof.NewMsgProofUpdater(subCtx, cfg.L1.Confirmation, cfg.BatchInfoFetcher.BatchIndexStartBlock, db) + batchFetcher := crossmsg.NewBatchInfoFetcher(subCtx, common.HexToAddress(cfg.BatchInfoFetcher.ScrollChainAddr), cfg.BatchInfoFetcher.BatchIndexStartBlock, cfg.L1.Confirmation, int(cfg.L1.BlockTime), l1client, db, l2msgProofUpdater) go batchFetcher.Start() defer batchFetcher.Stop() diff --git a/bridge-history-api/config/config.go b/bridge-history-api/config/config.go index cbc3d1e30..d87851316 100644 --- a/bridge-history-api/config/config.go +++ b/bridge-history-api/config/config.go @@ -6,6 +6,7 @@ import ( "path/filepath" ) +// BatchInfoFetcherConfig is the configuration of BatchInfoFetcher type BatchInfoFetcherConfig struct { BatchIndexStartBlock uint64 `json:"batchIndexStartBlock"` ScrollChainAddr string `json:"ScrollChainAddr"` @@ -21,6 +22,7 @@ type DBConfig struct { MaxIdleNum int `json:"maxIdleNum"` } +// LayerConfig is the configuration of Layer1/Layer2 type LayerConfig struct { Confirmation uint64 `json:"confirmation"` Endpoint string `json:"endpoint"` @@ -35,6 +37,7 @@ type LayerConfig struct { CustomERC20GatewayAddr string `json:"CustomERC20GatewayAddr"` } +// ServerConfig is the configuration of the bridge history backend server port type ServerConfig struct { HostPort string `json:"hostPort"` } diff --git a/bridge-history-api/controller/controller.go b/bridge-history-api/controller/controller.go index 684b2b0b7..046d1a35d 100644 --- a/bridge-history-api/controller/controller.go +++ b/bridge-history-api/controller/controller.go @@ -7,18 +7,22 @@ import ( "github.com/ethereum/go-ethereum/common" ) +// QueryAddressController contains the query by address service type QueryAddressController struct { Service service.HistoryService } +// QueryHashController contains the query by hash service type QueryHashController struct { Service service.HistoryService } +// QueryClaimableController contains the query claimable txs service type QueryClaimableController struct { Service service.HistoryService } +// Get defines the http get method behavior for QueryClaimableController func (c *QueryClaimableController) Get(req model.QueryByAddressRequest) (*model.QueryByAddressResponse, error) { txs, total, err := c.Service.GetClaimableTxsByAddress(common.HexToAddress(req.Address), int64(req.Offset), int64(req.Limit)) if err != nil { @@ -32,6 +36,7 @@ func (c *QueryClaimableController) Get(req model.QueryByAddressRequest) (*model. }}, nil } +// Get defines the http get method behavior for QueryAddressController func (c *QueryAddressController) Get(req model.QueryByAddressRequest) (*model.QueryByAddressResponse, error) { message, total, err := c.Service.GetTxsByAddress(common.HexToAddress(req.Address), int64(req.Offset), int64(req.Limit)) if err != nil { @@ -45,6 +50,7 @@ func (c *QueryAddressController) Get(req model.QueryByAddressRequest) (*model.Qu }}, nil } +// Post defines the http post method behavior for QueryHashController func (c *QueryHashController) Post(req model.QueryByHashRequest) (*model.QueryByHashResponse, error) { result, err := c.Service.GetTxsByHashes(req.Txs) if err != nil { diff --git a/bridge-history-api/cross_msg/batch_info_fetcher.go b/bridge-history-api/crossmsg/batch_info_fetcher.go similarity index 85% rename from bridge-history-api/cross_msg/batch_info_fetcher.go rename to bridge-history-api/crossmsg/batch_info_fetcher.go index aa43bd0cf..dfe9e6b96 100644 --- a/bridge-history-api/cross_msg/batch_info_fetcher.go +++ b/bridge-history-api/crossmsg/batch_info_fetcher.go @@ -1,4 +1,4 @@ -package cross_msg +package crossmsg import ( "context" @@ -8,11 +8,12 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" - "bridge-history-api/cross_msg/message_proof" + "bridge-history-api/crossmsg/messageproof" "bridge-history-api/db" "bridge-history-api/utils" ) +// BatchInfoFetcher fetches batch info from l1 chain and update db type BatchInfoFetcher struct { ctx context.Context scrollChainAddr common.Address @@ -21,10 +22,11 @@ type BatchInfoFetcher struct { blockTimeInSec int client *ethclient.Client db db.OrmFactory - msgProofUpdater *message_proof.MsgProofUpdater + msgProofUpdater *messageproof.MsgProofUpdater } -func NewBatchInfoFetcher(ctx context.Context, scrollChainAddr common.Address, batchInfoStartNumber uint64, confirmation uint64, blockTimeInSec int, client *ethclient.Client, db db.OrmFactory, msgProofUpdater *message_proof.MsgProofUpdater) *BatchInfoFetcher { +// NewBatchInfoFetcher creates a new BatchInfoFetcher instance +func NewBatchInfoFetcher(ctx context.Context, scrollChainAddr common.Address, batchInfoStartNumber uint64, confirmation uint64, blockTimeInSec int, client *ethclient.Client, db db.OrmFactory, msgProofUpdater *messageproof.MsgProofUpdater) *BatchInfoFetcher { return &BatchInfoFetcher{ ctx: ctx, scrollChainAddr: scrollChainAddr, @@ -37,13 +39,14 @@ func NewBatchInfoFetcher(ctx context.Context, scrollChainAddr common.Address, ba } } +// Start the BatchInfoFetcher func (b *BatchInfoFetcher) Start() { log.Info("BatchInfoFetcher Start") // Fetch batch info at beginning // Then start msg proof updater after db have some bridge batch err := b.fetchBatchInfo() if err != nil { - log.Error("fetch batch info at begining failed: ", "err", err) + log.Error("fetch batch info at beginning failed: ", "err", err) } go b.msgProofUpdater.Start() @@ -65,6 +68,7 @@ func (b *BatchInfoFetcher) Start() { }() } +// Stop the BatchInfoFetcher and call msg proof updater to stop func (b *BatchInfoFetcher) Stop() { log.Info("BatchInfoFetcher Stop") b.msgProofUpdater.Stop() diff --git a/bridge-history-api/cross_msg/block_timestamp_fetcher.go b/bridge-history-api/crossmsg/block_timestamp_fetcher.go similarity index 84% rename from bridge-history-api/cross_msg/block_timestamp_fetcher.go rename to bridge-history-api/crossmsg/block_timestamp_fetcher.go index 61d01740c..ed0b9df00 100644 --- a/bridge-history-api/cross_msg/block_timestamp_fetcher.go +++ b/bridge-history-api/crossmsg/block_timestamp_fetcher.go @@ -1,4 +1,4 @@ -package cross_msg +package crossmsg import ( "context" @@ -9,9 +9,13 @@ import ( "github.com/ethereum/go-ethereum/log" ) +// GetEarliestNoBlockTimestampHeightFunc is a function type that gets the earliest record without block timestamp from database type GetEarliestNoBlockTimestampHeightFunc func() (uint64, error) + +// UpdateBlockTimestampFunc is a function type that updates block timestamp into database type UpdateBlockTimestampFunc func(height uint64, timestamp time.Time) error +// BlockTimestampFetcher fetches block timestamp from blockchain and saves them to database type BlockTimestampFetcher struct { ctx context.Context confirmation uint64 @@ -21,6 +25,7 @@ type BlockTimestampFetcher struct { getEarliestNoBlockTimestampHeightFunc GetEarliestNoBlockTimestampHeightFunc } +// NewBlockTimestampFetcher creates a new BlockTimestampFetcher instance func NewBlockTimestampFetcher(ctx context.Context, confirmation uint64, blockTimeInSec int, client *ethclient.Client, updateBlockTimestampFunc UpdateBlockTimestampFunc, getEarliestNoBlockTimestampHeightFunc GetEarliestNoBlockTimestampHeightFunc) *BlockTimestampFetcher { return &BlockTimestampFetcher{ ctx: ctx, @@ -32,6 +37,7 @@ func NewBlockTimestampFetcher(ctx context.Context, confirmation uint64, blockTim } } +// Start the BlockTimestampFetcher func (b *BlockTimestampFetcher) Start() { go func() { tick := time.NewTicker(time.Duration(b.blockTimeInSec) * time.Second) @@ -73,6 +79,7 @@ func (b *BlockTimestampFetcher) Start() { }() } +// Stop the BlockTimestampFetcher and log the info func (b *BlockTimestampFetcher) Stop() { log.Info("BlockTimestampFetcher Stop") } diff --git a/bridge-history-api/cross_msg/cross_msg_fetcher.go b/bridge-history-api/crossmsg/cross_msg_fetcher.go similarity index 84% rename from bridge-history-api/cross_msg/cross_msg_fetcher.go rename to bridge-history-api/crossmsg/cross_msg_fetcher.go index 86f952f1e..f330d5ec0 100644 --- a/bridge-history-api/cross_msg/cross_msg_fetcher.go +++ b/bridge-history-api/crossmsg/cross_msg_fetcher.go @@ -1,4 +1,4 @@ -package cross_msg +package crossmsg import ( "context" @@ -18,7 +18,8 @@ import ( "bridge-history-api/utils" ) -type CrossMsgFetcher struct { +// MsgFetcher fetches cross message events from blockchain and saves them to database +type MsgFetcher struct { ctx context.Context config *config.LayerConfig db db.OrmFactory @@ -32,8 +33,9 @@ type CrossMsgFetcher struct { reorgEndCh chan struct{} } -func NewCrossMsgFetcher(ctx context.Context, config *config.LayerConfig, db db.OrmFactory, client *ethclient.Client, worker *FetchEventWorker, addressList []common.Address, reorg ReorgHandling) (*CrossMsgFetcher, error) { - crossMsgFetcher := &CrossMsgFetcher{ +// NewMsgFetcher creates a new MsgFetcher instance +func NewMsgFetcher(ctx context.Context, config *config.LayerConfig, db db.OrmFactory, client *ethclient.Client, worker *FetchEventWorker, addressList []common.Address, reorg ReorgHandling) (*MsgFetcher, error) { + msgFetcher := &MsgFetcher{ ctx: ctx, config: config, db: db, @@ -45,11 +47,12 @@ func NewCrossMsgFetcher(ctx context.Context, config *config.LayerConfig, db db.O reorgStartCh: make(chan struct{}), reorgEndCh: make(chan struct{}), } - return crossMsgFetcher, nil + return msgFetcher, nil } -func (c *CrossMsgFetcher) Start() { - log.Info("CrossMsgFetcher Start") +// Start the MsgFetcher +func (c *MsgFetcher) Start() { + log.Info("MsgFetcher Start") // fetch missing events from finalized blocks, we don't handle reorgs here c.forwardFetchAndSaveMissingEvents(c.config.Confirmation) @@ -94,12 +97,13 @@ func (c *CrossMsgFetcher) Start() { }() } -func (c *CrossMsgFetcher) Stop() { - log.Info("CrossMsgFetcher Stop") +// Stop the MsgFetcher and log the info +func (c *MsgFetcher) Stop() { + log.Info("MsgFetcher Stop") } // forwardFetchAndSaveMissingEvents will fetch all events from the latest processed height to the latest block number. -func (c *CrossMsgFetcher) forwardFetchAndSaveMissingEvents(confirmation uint64) { +func (c *MsgFetcher) forwardFetchAndSaveMissingEvents(confirmation uint64) { // if we fetch to the latest block, shall not exceed cachedHeaders var number uint64 var err error @@ -124,7 +128,7 @@ func (c *CrossMsgFetcher) forwardFetchAndSaveMissingEvents(confirmation uint64) if processedHeight <= 0 || processedHeight < int64(c.config.StartHeight) { processedHeight = int64(c.config.StartHeight) } else { - processedHeight += 1 + processedHeight++ } for from := processedHeight; from <= int64(number); from += fetchLimit { to := from + fetchLimit - 1 @@ -139,7 +143,7 @@ func (c *CrossMsgFetcher) forwardFetchAndSaveMissingEvents(confirmation uint64) } } -func (c *CrossMsgFetcher) fetchMissingLatestHeaders() { +func (c *MsgFetcher) fetchMissingLatestHeaders() { var start int64 number, err := c.client.BlockNumber(c.ctx) if err != nil { @@ -159,7 +163,7 @@ func (c *CrossMsgFetcher) fetchMissingLatestHeaders() { close(c.reorgEndCh) return default: - header, err := c.client.HeaderByNumber(c.ctx, big.NewInt(int64(i))) + header, err := c.client.HeaderByNumber(c.ctx, big.NewInt(i)) if err != nil { log.Error("failed to get latest header", "err", err) return @@ -181,9 +185,9 @@ func (c *CrossMsgFetcher) fetchMissingLatestHeaders() { c.mu.Lock() index, ok, validHeaders := BackwardFindReorgBlock(c.ctx, c.cachedHeaders, c.client, header) if !ok { - log.Error("Reorg happended too earlier than cached headers", "reorg height", header.Number) - num, err := utils.GetSafeBlockNumber(c.ctx, c.client, c.config.Confirmation) - if err != nil { + log.Error("Reorg happened too earlier than cached headers", "reorg height", header.Number) + num, getSafeErr := utils.GetSafeBlockNumber(c.ctx, c.client, c.config.Confirmation) + if getSafeErr != nil { log.Crit("Can not get safe number during reorg, quit the process", "err", err) } // clear all our saved data, because no data is safe now diff --git a/bridge-history-api/cross_msg/fetch_missing_event.go b/bridge-history-api/crossmsg/fetch_missing_event.go similarity index 83% rename from bridge-history-api/cross_msg/fetch_missing_event.go rename to bridge-history-api/crossmsg/fetch_missing_event.go index 91ca71e14..9eb7dfdf9 100644 --- a/bridge-history-api/cross_msg/fetch_missing_event.go +++ b/bridge-history-api/crossmsg/fetch_missing_event.go @@ -1,4 +1,4 @@ -package cross_msg +package crossmsg import ( "context" @@ -25,14 +25,15 @@ type FetchAndSave func(ctx context.Context, client *ethclient.Client, database d // GetLatestProcessed is a function type that gets the latest processed block height from database type GetLatestProcessed func(db db.OrmFactory) (int64, error) -type UpdateXHash func(ctx context.Context) +// FetchEventWorker defines worker with fetch and save function, processed number getter, and name type FetchEventWorker struct { F FetchAndSave G GetLatestProcessed Name string } +// GetLatestL1ProcessedHeight get L1 the latest processed height func GetLatestL1ProcessedHeight(db db.OrmFactory) (int64, error) { crossHeight, err := db.GetLatestL1ProcessedHeight() if err != nil { @@ -46,11 +47,11 @@ func GetLatestL1ProcessedHeight(db db.OrmFactory) (int64, error) { } if crossHeight > relayedHeight { return crossHeight, nil - } else { - return relayedHeight, nil } + return relayedHeight, nil } +// GetLatestL2ProcessedHeight get L2 latest processed height func GetLatestL2ProcessedHeight(db db.OrmFactory) (int64, error) { crossHeight, err := db.GetLatestL2ProcessedHeight() if err != nil { @@ -77,6 +78,7 @@ func GetLatestL2ProcessedHeight(db db.OrmFactory) (int64, error) { return maxHeight, nil } +// L1FetchAndSaveEvents fetch and save events on L1 func L1FetchAndSaveEvents(ctx context.Context, client *ethclient.Client, database db.OrmFactory, from int64, to int64, addrList []common.Address) error { query := geth.FilterQuery{ FromBlock: big.NewInt(from), // inclusive @@ -110,19 +112,25 @@ func L1FetchAndSaveEvents(ctx context.Context, client *ethclient.Client, databas } err = database.BatchInsertL1CrossMsgDBTx(dbTx, depositL1CrossMsgs) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("l1FetchAndSaveEvents: Failed to insert cross msg event logs", "err", err) } err = database.BatchInsertRelayedMsgDBTx(dbTx, relayedMsg) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("l1FetchAndSaveEvents: Failed to insert relayed message event logs", "err", err) } err = dbTx.Commit() if err != nil { // if we can not insert into DB, there must something wrong, need a on-call member handle the dababase manually - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Error("l1FetchAndSaveEvents: Failed to commit db transaction", "err", err) return err } @@ -130,6 +138,7 @@ func L1FetchAndSaveEvents(ctx context.Context, client *ethclient.Client, databas return nil } +// L2FetchAndSaveEvents fetche and save events on L2 func L2FetchAndSaveEvents(ctx context.Context, client *ethclient.Client, database db.OrmFactory, from int64, to int64, addrList []common.Address) error { query := geth.FilterQuery{ FromBlock: big.NewInt(from), // inclusive @@ -164,26 +173,34 @@ func L2FetchAndSaveEvents(ctx context.Context, client *ethclient.Client, databas } err = database.BatchInsertL2CrossMsgDBTx(dbTx, depositL2CrossMsgs) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("l2FetchAndSaveEvents: Failed to insert cross msg event logs", "err", err) } err = database.BatchInsertRelayedMsgDBTx(dbTx, relayedMsg) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("l2FetchAndSaveEvents: Failed to insert relayed message event logs", "err", err) } err = database.BatchInsertL2SentMsgDBTx(dbTx, l2SentMsgs) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("l2FetchAndSaveEvents: Failed to insert l2 sent message", "err", err) } err = dbTx.Commit() if err != nil { // if we can not insert into DB, there must something wrong, need a on-call member handle the dababase manually - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Error("l2FetchAndSaveEvents: Failed to commit db transaction", "err", err) return err } @@ -191,6 +208,7 @@ func L2FetchAndSaveEvents(ctx context.Context, client *ethclient.Client, databas return nil } +// FetchAndSaveBatchIndex fetche and save batch index func FetchAndSaveBatchIndex(ctx context.Context, client *ethclient.Client, database db.OrmFactory, from int64, to int64, scrollChainAddr common.Address) error { query := geth.FilterQuery{ FromBlock: big.NewInt(from), // inclusive @@ -217,13 +235,17 @@ func FetchAndSaveBatchIndex(ctx context.Context, client *ethclient.Client, datab } err = database.BatchInsertRollupBatchDBTx(dbTx, rollupBatches) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("FetchAndSaveBatchIndex: Failed to insert batch commit msg event logs", "err", err) } err = dbTx.Commit() if err != nil { // if we can not insert into DB, there must something wrong, need a on-call member handle the dababase manually - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Error("FetchAndSaveBatchIndex: Failed to commit db transaction", "err", err) return err } diff --git a/bridge-history-api/cross_msg/message_proof/msg_proof_updater.go b/bridge-history-api/crossmsg/messageproof/msg_proof_updater.go similarity index 95% rename from bridge-history-api/cross_msg/message_proof/msg_proof_updater.go rename to bridge-history-api/crossmsg/messageproof/msg_proof_updater.go index 458931d94..6ecfd302d 100644 --- a/bridge-history-api/cross_msg/message_proof/msg_proof_updater.go +++ b/bridge-history-api/crossmsg/messageproof/msg_proof_updater.go @@ -1,4 +1,4 @@ -package message_proof +package messageproof import ( "context" @@ -14,12 +14,14 @@ import ( "bridge-history-api/db/orm" ) +// MsgProofUpdater is used to update message proof in db type MsgProofUpdater struct { ctx context.Context db db.OrmFactory withdrawTrie *WithdrawTrie } +// NewMsgProofUpdater new MsgProofUpdater instance func NewMsgProofUpdater(ctx context.Context, confirmations uint64, startBlock uint64, db db.OrmFactory) *MsgProofUpdater { return &MsgProofUpdater{ ctx: ctx, @@ -28,6 +30,7 @@ func NewMsgProofUpdater(ctx context.Context, confirmations uint64, startBlock ui } } +// Start the MsgProofUpdater func (m *MsgProofUpdater) Start() { log.Info("MsgProofUpdater Start") m.initialize(m.ctx) @@ -83,6 +86,7 @@ func (m *MsgProofUpdater) Start() { } +// Stop the MsgProofUpdater func (m *MsgProofUpdater) Stop() { log.Info("MsgProofUpdater Stop") } @@ -112,7 +116,7 @@ func (m *MsgProofUpdater) initializeWithdrawTrie() error { return fmt.Errorf("failed to get first l2 message: %v", err) } // no l2 message - // TO DO: check if we realy dont have l2 sent message with nonce 0 + // TO DO: check if we really dont have l2 sent message with nonce 0 if firstMsg == nil { log.Info("No first l2sentmsg in db") return nil @@ -183,7 +187,7 @@ func (m *MsgProofUpdater) updateMsgProof(msgs []*orm.L2SentMsg, proofs [][]byte, if len(msgs) == 0 { return nil } - // this should not happend, but double checked + // this should not happen, but double check if len(msgs) != len(proofs) { return fmt.Errorf("illegal state: len(msgs) != len(proofs)") } diff --git a/bridge-history-api/cross_msg/message_proof/withdraw_trie.go b/bridge-history-api/crossmsg/messageproof/withdraw_trie.go similarity index 99% rename from bridge-history-api/cross_msg/message_proof/withdraw_trie.go rename to bridge-history-api/crossmsg/messageproof/withdraw_trie.go index 331a1a8b5..4dbd300eb 100644 --- a/bridge-history-api/cross_msg/message_proof/withdraw_trie.go +++ b/bridge-history-api/crossmsg/messageproof/withdraw_trie.go @@ -1,4 +1,4 @@ -package message_proof +package messageproof import ( "github.com/ethereum/go-ethereum/common" diff --git a/bridge-history-api/cross_msg/message_proof/withdraw_trie_test.go b/bridge-history-api/crossmsg/messageproof/withdraw_trie_test.go similarity index 99% rename from bridge-history-api/cross_msg/message_proof/withdraw_trie_test.go rename to bridge-history-api/crossmsg/messageproof/withdraw_trie_test.go index e003a9cea..08900a10f 100644 --- a/bridge-history-api/cross_msg/message_proof/withdraw_trie_test.go +++ b/bridge-history-api/crossmsg/messageproof/withdraw_trie_test.go @@ -1,4 +1,4 @@ -package message_proof +package messageproof import ( "math/big" diff --git a/bridge-history-api/cross_msg/msg_fetcher_test.go b/bridge-history-api/crossmsg/msg_fetcher_test.go similarity index 89% rename from bridge-history-api/cross_msg/msg_fetcher_test.go rename to bridge-history-api/crossmsg/msg_fetcher_test.go index 5ec8fc8a8..3a20bca7c 100644 --- a/bridge-history-api/cross_msg/msg_fetcher_test.go +++ b/bridge-history-api/crossmsg/msg_fetcher_test.go @@ -1,4 +1,4 @@ -package cross_msg_test +package crossmsg_test import ( "crypto/rand" @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" - "bridge-history-api/cross_msg" + "bridge-history-api/crossmsg" ) func TestMergeIntoList(t *testing.T) { @@ -18,7 +18,7 @@ func TestMergeIntoList(t *testing.T) { assert.Equal(t, headers[0].Hash(), headers[1].ParentHash) headers2, err := generateHeaders(18) assert.NoError(t, err) - result := cross_msg.MergeAddIntoHeaderList(headers, headers2, 64) + result := crossmsg.MergeAddIntoHeaderList(headers, headers2, 64) assert.Equal(t, 64, len(result)) assert.Equal(t, headers2[len(headers2)-1], result[len(result)-1]) assert.NotEqual(t, headers[0], result[0]) @@ -53,7 +53,7 @@ func generateHeaders(amount int) ([]*types.Header, error) { Time: uint64(i * 15), Extra: []byte{}, MixDigest: common.Hash{}, - Nonce: types.EncodeNonce(uint64(nonce.Uint64())), + Nonce: types.EncodeNonce(nonce.Uint64()), } headers[i] = header } diff --git a/bridge-history-api/cross_msg/reorg_handle.go b/bridge-history-api/crossmsg/reorg_handle.go similarity index 63% rename from bridge-history-api/cross_msg/reorg_handle.go rename to bridge-history-api/crossmsg/reorg_handle.go index 6ed912dc1..39ee5cc03 100644 --- a/bridge-history-api/cross_msg/reorg_handle.go +++ b/bridge-history-api/crossmsg/reorg_handle.go @@ -1,4 +1,4 @@ -package cross_msg +package crossmsg import ( "context" @@ -10,6 +10,7 @@ import ( "bridge-history-api/db" ) +// ReorgHandling handles reorg function type type ReorgHandling func(ctx context.Context, reorgHeight int64, db db.OrmFactory) error func reverseArray(arr []*types.Header) []*types.Header { @@ -20,10 +21,12 @@ func reverseArray(arr []*types.Header) []*types.Header { return arr } +// IsParentAndChild match the child header ParentHash with parent header Hash func IsParentAndChild(parentHeader *types.Header, header *types.Header) bool { return header.ParentHash == parentHeader.Hash() } +// MergeAddIntoHeaderList merges two header lists, if exceed the max length then drop the oldest entries func MergeAddIntoHeaderList(baseArr, extraArr []*types.Header, maxLength int) []*types.Header { mergedArr := append(baseArr, extraArr...) if len(mergedArr) <= maxLength { @@ -34,11 +37,12 @@ func MergeAddIntoHeaderList(baseArr, extraArr []*types.Header, maxLength int) [] return mergedArr[startIndex:] } -func BackwardFindReorgBlock(ctx context.Context, headers []*types.Header, client *ethclient.Client, header *types.Header) (int, bool, []*types.Header) { +// BackwardFindReorgBlock finds the reorg block by backward search +func BackwardFindReorgBlock(ctx context.Context, headers []*types.Header, client *ethclient.Client, lastHeader *types.Header) (int, bool, []*types.Header) { maxStep := len(headers) - backwardHeaderList := []*types.Header{header} + backwardHeaderList := []*types.Header{lastHeader} for iterRound := 0; iterRound < maxStep; iterRound++ { - header, err := client.HeaderByHash(ctx, header.ParentHash) + header, err := client.HeaderByHash(ctx, lastHeader.ParentHash) if err != nil { log.Error("BackwardFindReorgBlock failed", "error", err) return -1, false, nil @@ -50,10 +54,12 @@ func BackwardFindReorgBlock(ctx context.Context, headers []*types.Header, client return j, true, backwardHeaderList } } + lastHeader = header } return -1, false, nil } +// L1ReorgHandling handles l1 reorg func L1ReorgHandling(ctx context.Context, reorgHeight int64, db db.OrmFactory) error { dbTx, err := db.Beginx() if err != nil { @@ -61,47 +67,64 @@ func L1ReorgHandling(ctx context.Context, reorgHeight int64, db db.OrmFactory) e } err = db.DeleteL1CrossMsgAfterHeightDBTx(dbTx, reorgHeight) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("delete l1 cross msg from height", "height", reorgHeight, "err", err) } err = db.DeleteL1RelayedHashAfterHeightDBTx(dbTx, reorgHeight) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("delete l1 relayed hash from height", "height", reorgHeight, "err", err) } err = dbTx.Commit() if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Error("commit tx failed", "err", err) return err } return nil } +// L2ReorgHandling handles l2 reorg func L2ReorgHandling(ctx context.Context, reorgHeight int64, db db.OrmFactory) error { dbTx, err := db.Beginx() if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("begin db tx failed", "err", err) } err = db.DeleteL2CrossMsgFromHeightDBTx(dbTx, reorgHeight) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("delete l2 cross msg from height", "height", reorgHeight, "err", err) } err = db.DeleteL2RelayedHashAfterHeightDBTx(dbTx, reorgHeight) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("delete l2 relayed hash from height", "height", reorgHeight, "err", err) } err = db.DeleteL2SentMsgAfterHeightDBTx(dbTx, reorgHeight) if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Crit("delete l2 sent msg from height", "height", reorgHeight, "err", err) } err = dbTx.Commit() if err != nil { - dbTx.Rollback() + if rollBackErr := dbTx.Rollback(); rollBackErr != nil { + log.Error("dbTx Rollback failed", "err", rollBackErr) + } log.Error("commit tx failed", "err", err) return err } diff --git a/bridge-history-api/db/orm/batch.go b/bridge-history-api/db/orm/batch.go index bca6d0f23..e76b2a52b 100644 --- a/bridge-history-api/db/orm/batch.go +++ b/bridge-history-api/db/orm/batch.go @@ -11,6 +11,7 @@ type rollupBatchOrm struct { db *sqlx.DB } +// RollupBatch is the struct for rollup_batch table type RollupBatch struct { ID uint64 `json:"id" db:"id"` BatchIndex uint64 `json:"batch_index" db:"batch_index"` diff --git a/bridge-history-api/db/orm/interface.go b/bridge-history-api/db/orm/interface.go index a7eb1e8e9..317961e4a 100644 --- a/bridge-history-api/db/orm/interface.go +++ b/bridge-history-api/db/orm/interface.go @@ -8,7 +8,10 @@ import ( "github.com/jmoiron/sqlx" ) +// AssetType can be ETH/ERC20/ERC1155/ERC721 type AssetType int + +// MsgType can be layer1/layer2 msg type MsgType int func (a AssetType) String() string { @@ -26,15 +29,22 @@ func (a AssetType) String() string { } const ( + // ETH = 0 ETH AssetType = iota + // ERC20 = 1 ERC20 + // ERC721 = 2 ERC721 + // ERC1155 = 3 ERC1155 ) const ( + // UnknownMsg = 0 UnknownMsg MsgType = iota + // Layer1Msg = 1 Layer1Msg + // Layer2Msg = 2 Layer2Msg ) @@ -89,15 +99,17 @@ type L2CrossMsgOrm interface { GetL2CrossMsgByMsgHashList(msgHashList []string) ([]*CrossMsg, error) } +// RelayedMsgOrm provides operations on relayed_msg table type RelayedMsgOrm interface { BatchInsertRelayedMsgDBTx(dbTx *sqlx.Tx, messages []*RelayedMsg) error - GetRelayedMsgByHash(msg_hash string) (*RelayedMsg, error) + GetRelayedMsgByHash(msgHash string) (*RelayedMsg, error) GetLatestRelayedHeightOnL1() (int64, error) GetLatestRelayedHeightOnL2() (int64, error) DeleteL1RelayedHashAfterHeightDBTx(dbTx *sqlx.Tx, height int64) error DeleteL2RelayedHashAfterHeightDBTx(dbTx *sqlx.Tx, height int64) error } +// L2SentMsgOrm provides operations on l2_sent_msg table type L2SentMsgOrm interface { BatchInsertL2SentMsgDBTx(dbTx *sqlx.Tx, messages []*L2SentMsg) error GetL2SentMsgByHash(l2Hash string) (*L2SentMsg, error) @@ -105,13 +117,14 @@ type L2SentMsgOrm interface { GetL2SentMessageByNonce(nonce uint64) (*L2SentMsg, error) GetLatestL2SentMsgLEHeight(endBlockNumber uint64) (*L2SentMsg, error) GetL2SentMsgMsgHashByHeightRange(startHeight, endHeight uint64) ([]*L2SentMsg, error) - UpdateL2MessageProofInDBTx(ctx context.Context, dbTx *sqlx.Tx, msgHash string, proof string, batch_index uint64) error + UpdateL2MessageProofInDBTx(ctx context.Context, dbTx *sqlx.Tx, msgHash string, proof string, batchIndex uint64) error GetLatestL2SentMsgBatchIndex() (int64, error) GetClaimableL2SentMsgByAddressWithOffset(address string, offset int64, limit int64) ([]*L2SentMsg, error) GetClaimableL2SentMsgByAddressTotalNum(address string) (uint64, error) DeleteL2SentMsgAfterHeightDBTx(dbTx *sqlx.Tx, height int64) error } +// RollupBatchOrm provides operations on rollup_batch table type RollupBatchOrm interface { GetLatestRollupBatch() (*RollupBatch, error) GetRollupBatchByIndex(index uint64) (*RollupBatch, error) diff --git a/bridge-history-api/db/orm/l1_cross_msg.go b/bridge-history-api/db/orm/l1_cross_msg.go index 4816c2818..1ade7e55e 100644 --- a/bridge-history-api/db/orm/l1_cross_msg.go +++ b/bridge-history-api/db/orm/l1_cross_msg.go @@ -37,7 +37,14 @@ func (l *l1CrossMsgOrm) GetL1CrossMsgByHash(l1Hash common.Hash) (*CrossMsg, erro func (l *l1CrossMsgOrm) GetL1CrossMsgsByAddress(sender common.Address) ([]*CrossMsg, error) { var results []*CrossMsg rows, err := l.db.Queryx(`SELECT * FROM cross_message WHERE sender = $1 AND msg_type = 1 AND deleted_at IS NULL;`, sender.String(), Layer1Msg) - + if err != nil { + return nil, err + } + defer func() { + if err = rows.Close(); err != nil { + log.Error("failed to close rows", "err", err) + } + }() for rows.Next() { msg := &CrossMsg{} if err = rows.StructScan(msg); err != nil { diff --git a/bridge-history-api/db/orm/l2_cross_msg.go b/bridge-history-api/db/orm/l2_cross_msg.go index 24ea1eead..1e1904998 100644 --- a/bridge-history-api/db/orm/l2_cross_msg.go +++ b/bridge-history-api/db/orm/l2_cross_msg.go @@ -38,7 +38,14 @@ func (l *l2CrossMsgOrm) GetL2CrossMsgByHash(l2Hash common.Hash) (*CrossMsg, erro func (l *l2CrossMsgOrm) GetL2CrossMsgByAddress(sender common.Address) ([]*CrossMsg, error) { var results []*CrossMsg rows, err := l.db.Queryx(`SELECT * FROM cross_message WHERE sender = $1 AND msg_type = $2 AND deleted_at IS NULL;`, sender.String(), Layer2Msg) - + if err != nil { + return nil, err + } + defer func() { + if err = rows.Close(); err != nil { + log.Error("failed to close rows", "err", err) + } + }() for rows.Next() { msg := &CrossMsg{} if err = rows.StructScan(msg); err != nil { @@ -145,6 +152,14 @@ func (l *l2CrossMsgOrm) GetL2EarliestNoBlockTimestampHeight() (uint64, error) { func (l *l2CrossMsgOrm) GetL2CrossMsgByMsgHashList(msgHashList []string) ([]*CrossMsg, error) { var results []*CrossMsg rows, err := l.db.Queryx(`SELECT * FROM cross_message WHERE msg_hash = ANY($1) AND msg_type = $2 AND deleted_at IS NULL;`, pq.Array(msgHashList), Layer2Msg) + if err != nil { + return nil, err + } + defer func() { + if err = rows.Close(); err != nil { + log.Error("failed to close rows", "err", err) + } + }() for rows.Next() { msg := &CrossMsg{} if err = rows.StructScan(msg); err != nil { diff --git a/bridge-history-api/db/orm/l2_sent_msg.go b/bridge-history-api/db/orm/l2_sent_msg.go index dac27ea75..147630196 100644 --- a/bridge-history-api/db/orm/l2_sent_msg.go +++ b/bridge-history-api/db/orm/l2_sent_msg.go @@ -9,6 +9,7 @@ import ( "github.com/jmoiron/sqlx" ) +// L2SentMsg defines the struct for l2_sent_msg table record type L2SentMsg struct { ID uint64 `json:"id" db:"id"` OriginalSender string `json:"original_sender" db:"original_sender"` @@ -89,8 +90,8 @@ func (l *l2SentMsgOrm) GetLatestSentMsgHeightOnL2() (int64, error) { return 0, nil } -func (l *l2SentMsgOrm) UpdateL2MessageProofInDBTx(ctx context.Context, dbTx *sqlx.Tx, msgHash string, proof string, batch_index uint64) error { - if _, err := dbTx.ExecContext(ctx, l.db.Rebind("update l2_sent_msg set msg_proof = ?, batch_index = ? where msg_hash = ? AND deleted_at IS NULL;"), proof, batch_index, msgHash); err != nil { +func (l *l2SentMsgOrm) UpdateL2MessageProofInDBTx(ctx context.Context, dbTx *sqlx.Tx, msgHash string, proof string, batchIndex uint64) error { + if _, err := dbTx.ExecContext(ctx, l.db.Rebind("update l2_sent_msg set msg_proof = ?, batch_index = ? where msg_hash = ? AND deleted_at IS NULL;"), proof, batchIndex, msgHash); err != nil { return err } return nil @@ -117,6 +118,11 @@ func (l *l2SentMsgOrm) GetL2SentMsgMsgHashByHeightRange(startHeight, endHeight u if err != nil { return nil, err } + defer func() { + if err = rows.Close(); err != nil { + log.Error("failed to close rows", "err", err) + } + }() for rows.Next() { msg := &L2SentMsg{} if err = rows.StructScan(msg); err != nil { @@ -158,6 +164,11 @@ func (l *l2SentMsgOrm) GetClaimableL2SentMsgByAddressWithOffset(address string, if err != nil { return nil, err } + defer func() { + if err = rows.Close(); err != nil { + log.Error("failed to close rows", "err", err) + } + }() for rows.Next() { msg := &L2SentMsg{} if err = rows.StructScan(msg); err != nil { diff --git a/bridge-history-api/db/orm/relayed_msg.go b/bridge-history-api/db/orm/relayed_msg.go index fb43d13fa..684e85f8f 100644 --- a/bridge-history-api/db/orm/relayed_msg.go +++ b/bridge-history-api/db/orm/relayed_msg.go @@ -8,6 +8,7 @@ import ( "github.com/jmoiron/sqlx" ) +// RelayedMsg is the struct for relayed_msg table type RelayedMsg struct { MsgHash string `json:"msg_hash" db:"msg_hash"` Height uint64 `json:"height" db:"height"` @@ -46,9 +47,9 @@ func (l *relayedMsgOrm) BatchInsertRelayedMsgDBTx(dbTx *sqlx.Tx, messages []*Rel return nil } -func (l *relayedMsgOrm) GetRelayedMsgByHash(msg_hash string) (*RelayedMsg, error) { +func (l *relayedMsgOrm) GetRelayedMsgByHash(msgHash string) (*RelayedMsg, error) { result := &RelayedMsg{} - row := l.db.QueryRowx(`SELECT msg_hash, height, layer1_hash, layer2_hash FROM relayed_msg WHERE msg_hash = $1 AND deleted_at IS NULL;`, msg_hash) + row := l.db.QueryRowx(`SELECT msg_hash, height, layer1_hash, layer2_hash FROM relayed_msg WHERE msg_hash = $1 AND deleted_at IS NULL;`, msgHash) if err := row.StructScan(result); err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil diff --git a/bridge-history-api/db/orm_factory.go b/bridge-history-api/db/orm_factory.go index 1f16a05ef..e4ffc3992 100644 --- a/bridge-history-api/db/orm_factory.go +++ b/bridge-history-api/db/orm_factory.go @@ -4,6 +4,7 @@ import ( "database/sql" "errors" + "github.com/ethereum/go-ethereum/log" "github.com/jmoiron/sqlx" _ "github.com/lib/pq" //nolint:golint @@ -82,6 +83,11 @@ func (o *ormFactory) GetCrossMsgsByAddressWithOffset(sender string, offset int64 if err != nil || rows == nil { return nil, err } + defer func() { + if err = rows.Close(); err != nil { + log.Error("failed to close rows", "err", err) + } + }() for rows.Next() { msg := &orm.CrossMsg{} if err = rows.StructScan(msg); err != nil { diff --git a/bridge-history-api/model/request.go b/bridge-history-api/model/request.go index 3bae27fd6..779a84c96 100644 --- a/bridge-history-api/model/request.go +++ b/bridge-history-api/model/request.go @@ -1,11 +1,13 @@ package model +// QueryByAddressRequest the request parameter of address api type QueryByAddressRequest struct { Address string `url:"address"` Offset int `url:"offset"` Limit int `url:"limit"` } +// QueryByHashRequest the request parameter of hash api type QueryByHashRequest struct { Txs []string `url:"txs"` } diff --git a/bridge-history-api/model/response.go b/bridge-history-api/model/response.go index 89a2ae90f..5e53419e8 100644 --- a/bridge-history-api/model/response.go +++ b/bridge-history-api/model/response.go @@ -2,16 +2,19 @@ package model import "bridge-history-api/service" +// Data the return struct of apis type Data struct { Result []*service.TxHistoryInfo `json:"result"` Total uint64 `json:"total"` } +// QueryByAddressResponse the schema of address api response type QueryByAddressResponse struct { Message string `json:"message"` Data *Data `json:"data"` } +// QueryByHashResponse the schema of hash api response type QueryByHashResponse struct { Message string `json:"message"` Data *Data `json:"data"` diff --git a/bridge-history-api/service/service.go b/bridge-history-api/service/service.go index 7a3f21c21..6ff3f7817 100644 --- a/bridge-history-api/service/service.go +++ b/bridge-history-api/service/service.go @@ -11,6 +11,7 @@ import ( "bridge-history-api/db/orm" ) +// Finalized the schema of tx finalized infos type Finalized struct { Hash string `json:"hash"` Amount string `json:"amount"` @@ -20,6 +21,7 @@ type Finalized struct { BlockTimestamp *time.Time `json:"blockTimestamp"` // uselesss } +// UserClaimInfo the schema of tx claim infos type UserClaimInfo struct { From string `json:"from"` To string `json:"to"` @@ -31,6 +33,7 @@ type UserClaimInfo struct { BatchIndex string `json:"batch_index"` } +// TxHistoryInfo the schema of tx history infos type TxHistoryInfo struct { Hash string `json:"hash"` Amount string `json:"amount"` @@ -61,6 +64,7 @@ type historyBackend struct { db db.OrmFactory } +// GetCrossTxClaimInfo get UserClaimInfos by address func GetCrossTxClaimInfo(msgHash string, db db.OrmFactory) *UserClaimInfo { l2sentMsg, err := db.GetL2SentMsgByHash(msgHash) if err != nil { @@ -107,6 +111,7 @@ func updateCrossTxHash(msgHash string, txInfo *TxHistoryInfo, db db.OrmFactory) } +// GetClaimableTxsByAddress get all claimable txs under given address func (h *historyBackend) GetClaimableTxsByAddress(address common.Address, offset int64, limit int64) ([]*TxHistoryInfo, uint64, error) { var txHistories []*TxHistoryInfo total, err := h.db.GetClaimableL2SentMsgByAddressTotalNum(address.Hex()) @@ -149,6 +154,7 @@ func (h *historyBackend) GetClaimableTxsByAddress(address common.Address, offset return txHistories, total, err } +// GetTxsByAddress get all txs under given address func (h *historyBackend) GetTxsByAddress(address common.Address, offset int64, limit int64) ([]*TxHistoryInfo, uint64, error) { var txHistories []*TxHistoryInfo total, err := h.db.GetTotalCrossMsgCountByAddress(address.String()) @@ -180,6 +186,7 @@ func (h *historyBackend) GetTxsByAddress(address common.Address, offset int64, l return txHistories, total, nil } +// GetTxsByHashes get tx infos under given tx hashes func (h *historyBackend) GetTxsByHashes(hashes []string) ([]*TxHistoryInfo, error) { txHistories := make([]*TxHistoryInfo, 0) for _, hash := range hashes { diff --git a/bridge-history-api/utils/parse_event.go b/bridge-history-api/utils/parse_event.go index 0b8611e09..40ea2f0c3 100644 --- a/bridge-history-api/utils/parse_event.go +++ b/bridge-history-api/utils/parse_event.go @@ -14,6 +14,7 @@ import ( "bridge-history-api/db/orm" ) +// CachedParsedTxCalldata store parsed batch infos type CachedParsedTxCalldata struct { CallDataIndex uint64 BatchIndices []uint64 @@ -21,6 +22,7 @@ type CachedParsedTxCalldata struct { EndBlocks []uint64 } +// ParseBackendL1EventLogs parses L1 watched events func ParseBackendL1EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedMsg, error) { // Need use contract abi to parse event Log // Can only be tested after we have our contracts set up @@ -166,6 +168,7 @@ func ParseBackendL1EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedM return l1CrossMsg, relayedMsgs, nil } +// ParseBackendL2EventLogs parses L2 watched events func ParseBackendL2EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedMsg, []*orm.L2SentMsg, error) { // Need use contract abi to parse event Log // Can only be tested after we have our contracts set up @@ -328,6 +331,7 @@ func ParseBackendL2EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedM return l2CrossMsg, relayedMsgs, l2SentMsgs, nil } +// ParseBatchInfoFromScrollChain parses ScrollChain events func ParseBatchInfoFromScrollChain(ctx context.Context, client *ethclient.Client, logs []types.Log) ([]*orm.RollupBatch, error) { var rollupBatches []*orm.RollupBatch cache := make(map[string]CachedParsedTxCalldata) diff --git a/bridge-history-api/utils/utils.go b/bridge-history-api/utils/utils.go index d2c148e1b..0039e8be2 100644 --- a/bridge-history-api/utils/utils.go +++ b/bridge-history-api/utils/utils.go @@ -22,6 +22,7 @@ func Keccak2(a common.Hash, b common.Hash) common.Hash { return common.BytesToHash(crypto.Keccak256(append(a.Bytes()[:], b.Bytes()[:]...))) } +// GetSafeBlockNumber get the safe block number, which is the current block number minus the confirmations func GetSafeBlockNumber(ctx context.Context, client *ethclient.Client, confirmations uint64) (uint64, error) { number, err := client.BlockNumber(ctx) if err != nil || number <= confirmations { diff --git a/build/.golangci.yml b/build/.golangci.yml index 0545c4a18..72bbe0344 100644 --- a/build/.golangci.yml +++ b/build/.golangci.yml @@ -209,6 +209,13 @@ issues: linters: - errcheck - gosec + + # Exclude abi files in bridge-history-api + - path: backend_abi\.go + linters: + - errcheck + - gosec + - golint # Exclude some staticcheck messages - linters: