Handling transactions with more than one instruction in solana watcher (#932)

Add redeem controller

Co-authored-by: walker-16 <agpazos85@gmail.com>
This commit is contained in:
ftocal 2024-01-02 11:05:10 -03:00 committed by GitHub
parent d7391f6ba1
commit bb5840f70f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 79 additions and 9 deletions

View File

@ -16,6 +16,7 @@ import (
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/builder"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/config"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/http/infrastructure"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/http/redeem"
cwAlert "github.com/wormhole-foundation/wormhole-explorer/contract-watcher/internal/alert"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/internal/ankr"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/internal/metrics"
@ -114,7 +115,8 @@ func Run() {
processor.Start(rootCtx)
// create and start server.
server := infrastructure.NewServer(logger, config.Port, config.PprofEnabled, healthChecks...)
redeemController := redeem.NewController(watchers, logger)
server := infrastructure.NewServer(logger, config.Port, config.PprofEnabled, redeemController, healthChecks...)
server.Start()
logger.Info("Started wormhole-explorer-contract-watcher")

View File

@ -5,6 +5,7 @@ import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/pprof"
health "github.com/wormhole-foundation/wormhole-explorer/common/health"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/http/redeem"
"go.uber.org/zap"
)
@ -14,7 +15,7 @@ type Server struct {
logger *zap.Logger
}
func NewServer(logger *zap.Logger, port string, pprofEnabled bool, checks ...health.Check) *Server {
func NewServer(logger *zap.Logger, port string, pprofEnabled bool, redeemController *redeem.Controller, checks ...health.Check) *Server {
app := fiber.New(fiber.Config{DisableStartupMessage: true})
// Configure middleware
@ -32,6 +33,8 @@ func NewServer(logger *zap.Logger, port string, pprofEnabled bool, checks ...hea
api.Get("/health", ctrl.HealthCheck)
api.Get("/ready", ctrl.ReadyCheck)
api.Post("/backfill", redeemController.Backfill)
return &Server{
app: app,
port: port,

View File

@ -0,0 +1,45 @@
package redeem
import (
"github.com/gofiber/fiber/v2"
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/watcher"
"go.uber.org/zap"
)
// Controller definition.
type Controller struct {
watcherByBlockchain map[string]watcher.ContractWatcher
logger *zap.Logger
}
// NewController creates a Controller instance.
func NewController(watckers []watcher.ContractWatcher, logger *zap.Logger) *Controller {
watcherByBlockchain := make(map[string]watcher.ContractWatcher)
for _, w := range watckers {
watcherByBlockchain[w.GetBlockchain()] = w
}
return &Controller{watcherByBlockchain: watcherByBlockchain, logger: logger}
}
func (c *Controller) Backfill(ctx *fiber.Ctx) error {
payload := struct {
Blockchain string `json:"blockchain"`
FromBlock uint64 `json:"fromBlock"`
ToBlock uint64 `json:"toBlock"`
}{}
if err := ctx.BodyParser(&payload); err != nil {
return err
}
c.logger.Info("Executing contract-watcher", zap.Any("payload", payload))
watcher, ok := c.watcherByBlockchain[payload.Blockchain]
if !ok {
return fiber.NewError(fiber.StatusNotFound, "Blockchain not found")
}
watcher.Backfill(ctx.Context(), payload.FromBlock, payload.ToBlock, 100, false)
return nil
}

View File

@ -62,6 +62,10 @@ func NewAptosWatcher(client *aptos.AptosSDK, params AptosParams, repo *storage.R
}
}
func (w *AptosWatcher) GetBlockchain() string {
return w.blockchain
}
func (w *AptosWatcher) Start(ctx context.Context) error {
// get the current block for the chain.
cBlock, err := w.repository.GetCurrentBlock(ctx, w.blockchain, w.initialBlock)

View File

@ -6,6 +6,7 @@ import "context"
// It Tracks contract operations and persist the tx data
// Backfill is used to backfill the contract data from the past
type ContractWatcher interface {
GetBlockchain() string
Start(ctx context.Context) error
Close()
Backfill(ctx context.Context, fromBlock uint64, toBlock uint64, pageSize uint64, persistBlock bool)

View File

@ -56,6 +56,10 @@ func NewEvmStandardWatcher(client *evm.EvmSDK, params EVMParams, repo *storage.R
}
}
func (w *EvmStandardWatcher) GetBlockchain() string {
return w.blockchain
}
func (w *EvmStandardWatcher) Start(ctx context.Context) error {
// get the current block for the chain.
cBlock, err := w.repository.GetCurrentBlock(ctx, w.blockchain, w.initialBlock)

View File

@ -51,6 +51,10 @@ func NewEVMWatcher(client *ankr.AnkrSDK, repo *storage.Repository, params EVMPar
}
}
func (w *EVMWatcher) GetBlockchain() string {
return w.blockchain
}
func (w *EVMWatcher) Start(ctx context.Context) error {
// get the current block for the chain.
currentBlock, err := w.repository.GetCurrentBlock(ctx, w.blockchain, w.initialBlock)

View File

@ -115,6 +115,10 @@ func NewSolanaWatcher(client *solana.SolanaSDK, repo *storage.Repository, params
}
}
func (w *SolanaWatcher) GetBlockchain() string {
return w.blockchain
}
func (w *SolanaWatcher) Start(ctx context.Context) error {
// get the current block for the chain.
cBlock, err := w.repository.GetCurrentBlock(ctx, w.blockchain, w.initialBlock)
@ -208,7 +212,6 @@ func (w *SolanaWatcher) processMultipleBlocks(ctx context.Context, fromBlock uin
}
w.repository.UpdateWatcherBlock(ctx, w.chainID, watcherBlock)
}
}
func (w *SolanaWatcher) processBlock(ctx context.Context, block uint64, latestBlock *solana.GetLatestBlockResult, logger *zap.Logger) {
@ -221,7 +224,7 @@ func (w *SolanaWatcher) processBlock(ctx context.Context, block uint64, latestBl
result, err := w.client.GetBlock(ctx, block)
if err != nil {
if err == solana.ErrSlotSkipped {
logger.Info("slot was skipped")
logger.Debug("slot was skipped")
return nil
}
return fmt.Errorf("cannot get block. %w", err)
@ -323,8 +326,7 @@ func (w *SolanaWatcher) processTransaction(ctx context.Context, txRpc *rpc.Trans
log.Error("getting transaction detail failed", zap.Error(err))
continue
}
if len(t.Message.Instructions) == 1 {
instruccion := t.Message.Instructions[0]
for i, instruccion := range t.Message.Instructions {
if len(instruccion.Data) == 0 {
log.Debug("instruction data is empty")
continue
@ -337,7 +339,7 @@ func (w *SolanaWatcher) processTransaction(ctx context.Context, txRpc *rpc.Trans
var data postVAAData
if err := borsh.Deserialize(&data, instruccion.Data[1:]); err != nil {
log.Error("failed to deserialize instruction data", zap.Error(err))
log.Error("failed to deserialize instruction data", zap.Error(err), zap.Int("index", i))
continue
}
@ -357,8 +359,8 @@ func (w *SolanaWatcher) processTransaction(ctx context.Context, txRpc *rpc.Trans
// update global transaction and check if it should be updated.
updateGlobalTransaction(ctx, w.chainID, globalTx, w.repository, log)
} else {
log.Warn("transaction has more than one instruction")
break
}
}
}

View File

@ -70,6 +70,11 @@ func NewTerraWatcher(terraSDK *terra.TerraSDK, params TerraParams, repository *s
}
}
// GetBlockchain returns the blockchain name.
func (w *TerraWatcher) GetBlockchain() string {
return w.blockchain
}
// Start starts the terra watcher.
func (w *TerraWatcher) Start(ctx context.Context) error {
// get the current block for the chain.