From 1867dbb9686c93f69eb08381420e4b95e8d56759 Mon Sep 17 00:00:00 2001 From: webpiratt <213060745+webpiratt@users.noreply.github.com> Date: Wed, 11 Jun 2025 21:24:39 +0300 Subject: [PATCH] tx_indexer --- api/plugin.go | 41 ++++++++------- api/server.go | 50 ++++++++++--------- cmd/dca/server/main.go | 20 +++++++- cmd/dca/worker/config.go | 3 ++ cmd/dca/worker/main.go | 19 ++++++- cmd/payroll/server/main.go | 20 +++++++- cmd/payroll/worker/main.go | 19 ++++++- cmd/tx_indexer/config.go | 34 +++++++++++++ cmd/tx_indexer/main.go | 46 +++++++++++++++++ config-server.yaml | 6 ++- config-tx-indexer.yaml | 11 ++++ go.mod | 10 ++-- go.sum | 20 +++++--- .../plugin/20250603181247_tx_indexer.sql | 33 ++++++++++++ 14 files changed, 272 insertions(+), 60 deletions(-) create mode 100644 cmd/tx_indexer/config.go create mode 100644 cmd/tx_indexer/main.go create mode 100644 config-tx-indexer.yaml create mode 100644 storage/postgres/migrations/plugin/20250603181247_tx_indexer.sql diff --git a/api/plugin.go b/api/plugin.go index fb78bbd..a767383 100644 --- a/api/plugin.go +++ b/api/plugin.go @@ -18,12 +18,12 @@ import ( v1 "github.com/vultisig/commondata/go/vultisig/vault/v1" "github.com/vultisig/mobile-tss-lib/tss" vcommon "github.com/vultisig/verifier/common" + "github.com/vultisig/verifier/tx_indexer/pkg/storage" vtypes "github.com/vultisig/verifier/types" "github.com/vultisig/plugin/common" "github.com/vultisig/plugin/internal/sigutil" "github.com/vultisig/plugin/internal/tasks" - "github.com/vultisig/plugin/internal/types" ) type ErrorResponse struct { @@ -99,6 +99,25 @@ func (s *Server) SignPluginMessages(c echo.Context) error { req.Parties = []string{common.PluginPartyID, common.VerifierPartyID} + if s.txIndexerService != nil { + for i, msg := range req.Messages { + txToTrack, e := s.txIndexerService.CreateTx( + c.Request().Context(), + storage.CreateTxDto{ + PluginID: policy.PluginID, + ChainID: msg.Chain, + PolicyID: policy.ID, + FromPublicKey: req.PublicKey, + ProposedTxHex: req.Transaction, + }, + ) + if e != nil { + return fmt.Errorf("s.txIndexerService.CreateTx: %w", e) + } + req.Messages[i].TxIndexerID = txToTrack.ID.String() + } + } + buf, err := json.Marshal(req) if err != nil { return fmt.Errorf("fail to marshal to json, err: %w", err) @@ -106,14 +125,10 @@ func (s *Server) SignPluginMessages(c echo.Context) error { // TODO: check if this is relevant // check that tx is done only once per period + // (by @webpiratt: period depends on particular dca/payroll strategy (monthly/daily tx send, etc), + // maybe consider to add some additional metadata there to enable tx replay protection correctly) // should we also copy the db to the vultiserver, so that it can be used by the vultiserver (and use scheduler.go)? or query the blockchain? - txToSign, err := s.db.GetTransactionByHash(c.Request().Context(), txHash) - if err != nil { - s.logger.Errorf("Failed to get transaction by hash from database: %v", err) - return fmt.Errorf("fail to get transaction by hash: %w", err) - } - s.logger.Debug("PLUGIN SERVER: KEYSIGN TASK") ti, err := s.client.EnqueueContext(c.Request().Context(), @@ -122,22 +137,10 @@ func (s *Server) SignPluginMessages(c echo.Context) error { asynq.Timeout(2*time.Minute), asynq.Retention(5*time.Minute), asynq.Queue(tasks.QUEUE_NAME)) - if err != nil { - txToSign.Metadata["error"] = err.Error() - if updateErr := s.db.UpdateTransactionStatus(c.Request().Context(), txToSign.ID, types.StatusSigningFailed, txToSign.Metadata); updateErr != nil { - s.logger.Errorf("Failed to update transaction status: %v", updateErr) - } return fmt.Errorf("fail to enqueue keysign task: %w", err) } - txToSign.Metadata["task_id"] = ti.ID - if err := s.db.UpdateTransactionStatus(c.Request().Context(), txToSign.ID, types.StatusSigned, txToSign.Metadata); err != nil { - s.logger.Errorf("Failed to update transaction with task ID: %v", err) - } - - s.logger.Infof("Created transaction history for tx from plugin: %s...", req.Transaction[:min(20, len(req.Transaction))]) - return c.JSON(http.StatusOK, ti.ID) } diff --git a/api/server.go b/api/server.go index ba47189..a68b3c1 100644 --- a/api/server.go +++ b/api/server.go @@ -17,6 +17,7 @@ import ( "github.com/vultisig/mobile-tss-lib/tss" vcommon "github.com/vultisig/verifier/common" "github.com/vultisig/verifier/plugin" + "github.com/vultisig/verifier/tx_indexer" vtypes "github.com/vultisig/verifier/types" "github.com/vultisig/verifier/vault" @@ -30,18 +31,19 @@ import ( ) type Server struct { - cfg ServerConfig - db storage.DatabaseStorage - redis *storage.RedisStorage - vaultStorage vault.Storage - client *asynq.Client - inspector *asynq.Inspector - sdClient *statsd.Client - scheduler *scheduler.SchedulerService - policyService service.Policy - plugin plugin.Plugin - logger *logrus.Logger - mode string + cfg ServerConfig + db storage.DatabaseStorage + redis *storage.RedisStorage + vaultStorage vault.Storage + client *asynq.Client + inspector *asynq.Inspector + sdClient *statsd.Client + scheduler *scheduler.SchedulerService + policyService service.Policy + plugin plugin.Plugin + txIndexerService *tx_indexer.Service + logger *logrus.Logger + mode string } // NewServer returns a new server. @@ -55,6 +57,7 @@ func NewServer( inspector *asynq.Inspector, sdClient *statsd.Client, p plugin.Plugin, + txIndexerService *tx_indexer.Service, ) *Server { logger := logrus.WithField("service", "plugin").Logger schedulerService, err := scheduler.NewSchedulerService( @@ -73,17 +76,18 @@ func NewServer( } return &Server{ - cfg: cfg, - redis: redis, - client: client, - inspector: inspector, - sdClient: sdClient, - vaultStorage: vaultStorage, - plugin: p, - db: db, - scheduler: schedulerService, - logger: logger, - policyService: policyService, + cfg: cfg, + redis: redis, + client: client, + inspector: inspector, + sdClient: sdClient, + vaultStorage: vaultStorage, + plugin: p, + db: db, + scheduler: schedulerService, + logger: logger, + policyService: policyService, + txIndexerService: txIndexerService, } } diff --git a/cmd/dca/server/main.go b/cmd/dca/server/main.go index cd10997..577f70f 100644 --- a/cmd/dca/server/main.go +++ b/cmd/dca/server/main.go @@ -1,12 +1,15 @@ package main import ( + "context" "fmt" "net" "github.com/DataDog/datadog-go/statsd" "github.com/hibiken/asynq" "github.com/sirupsen/logrus" + "github.com/vultisig/verifier/tx_indexer" + tx_indexer_storage "github.com/vultisig/verifier/tx_indexer/pkg/storage" "github.com/vultisig/verifier/vault" "github.com/vultisig/plugin/api" @@ -16,6 +19,8 @@ import ( ) func main() { + ctx := context.Background() + cfg, err := GetConfigure() if err != nil { panic(err) @@ -50,6 +55,17 @@ func main() { panic(err) } + txIndexerStore, err := tx_indexer_storage.NewPostgresTxIndexStore(ctx, cfg.Database.DSN) + if err != nil { + panic(fmt.Errorf("tx_indexer_storage.NewPostgresTxIndexStore: %w", err)) + } + + txIndexerService := tx_indexer.NewService( + logger, + txIndexerStore, + tx_indexer.Chains(), + ) + db, err := postgres.NewPostgresBackend(cfg.Database.DSN, nil) if err != nil { logger.Fatalf("Failed to connect to database: %v", err) @@ -67,7 +83,9 @@ func main() { client, inspector, sdClient, - p) + p, + txIndexerService, + ) if err := server.StartServer(); err != nil { panic(err) } diff --git a/cmd/dca/worker/config.go b/cmd/dca/worker/config.go index fdc4256..d504e28 100644 --- a/cmd/dca/worker/config.go +++ b/cmd/dca/worker/config.go @@ -11,6 +11,9 @@ import ( ) type DCAWorkerConfig struct { + Database struct { + DSN string `mapstructure:"dsn" json:"dsn,omitempty"` + } `mapstructure:"database" json:"database,omitempty"` Redis storage.RedisConfig `mapstructure:"redis" json:"redis,omitempty"` BlockStorage vault_config.BlockStorageConfig `mapstructure:"block_storage" json:"block_storage,omitempty"` VaultServiceConfig vault_config.Config `mapstructure:"vault_service" json:"vault_service,omitempty"` diff --git a/cmd/dca/worker/main.go b/cmd/dca/worker/main.go index 465f9b5..849043a 100644 --- a/cmd/dca/worker/main.go +++ b/cmd/dca/worker/main.go @@ -1,17 +1,22 @@ package main import ( + "context" "fmt" "github.com/DataDog/datadog-go/statsd" "github.com/hibiken/asynq" "github.com/sirupsen/logrus" + "github.com/vultisig/verifier/tx_indexer" + "github.com/vultisig/verifier/tx_indexer/pkg/storage" "github.com/vultisig/verifier/vault" "github.com/vultisig/plugin/internal/tasks" ) func main() { + ctx := context.Background() + cfg, err := GetConfigure() if err != nil { panic(err) @@ -45,12 +50,24 @@ func main() { }, }, ) + + txIndexerStore, err := storage.NewPostgresTxIndexStore(ctx, cfg.Database.DSN) + if err != nil { + panic(fmt.Errorf("storage.NewPostgresTxIndexStore: %w", err)) + } + + txIndexerService := tx_indexer.NewService( + logger, + txIndexerStore, + tx_indexer.Chains(), + ) + vaultService, err := vault.NewManagementService( cfg.VaultServiceConfig, client, sdClient, vaultStorage, - nil, // not used in plugin + txIndexerService, ) if err != nil { panic(fmt.Errorf("failed to create vault service: %w", err)) diff --git a/cmd/payroll/server/main.go b/cmd/payroll/server/main.go index 4f9cadd..267ccc8 100644 --- a/cmd/payroll/server/main.go +++ b/cmd/payroll/server/main.go @@ -1,12 +1,15 @@ package main import ( + "context" "fmt" "net" "github.com/DataDog/datadog-go/statsd" "github.com/hibiken/asynq" "github.com/sirupsen/logrus" + "github.com/vultisig/verifier/tx_indexer" + tx_indexer_storage "github.com/vultisig/verifier/tx_indexer/pkg/storage" "github.com/vultisig/verifier/vault" "github.com/vultisig/plugin/api" @@ -16,6 +19,8 @@ import ( ) func main() { + ctx := context.Background() + cfg, err := GetConfigure() if err != nil { panic(err) @@ -51,6 +56,17 @@ func main() { panic(err) } + txIndexerStore, err := tx_indexer_storage.NewPostgresTxIndexStore(ctx, cfg.Database.DSN) + if err != nil { + panic(fmt.Errorf("tx_indexer_storage.NewPostgresTxIndexStore: %w", err)) + } + + txIndexerService := tx_indexer.NewService( + logger, + txIndexerStore, + tx_indexer.Chains(), + ) + db, err := postgres.NewPostgresBackend(cfg.Database.DSN, nil) if err != nil { logger.Fatalf("Failed to connect to database: %v", err) @@ -68,7 +84,9 @@ func main() { client, inspector, sdClient, - p) + p, + txIndexerService, + ) if err := server.StartServer(); err != nil { panic(err) } diff --git a/cmd/payroll/worker/main.go b/cmd/payroll/worker/main.go index e44a066..7019760 100644 --- a/cmd/payroll/worker/main.go +++ b/cmd/payroll/worker/main.go @@ -1,11 +1,14 @@ package main import ( + "context" "fmt" "github.com/DataDog/datadog-go/statsd" "github.com/hibiken/asynq" "github.com/sirupsen/logrus" + "github.com/vultisig/verifier/tx_indexer" + "github.com/vultisig/verifier/tx_indexer/pkg/storage" "github.com/vultisig/verifier/vault" "github.com/vultisig/plugin/internal/scheduler" @@ -15,6 +18,8 @@ import ( ) func main() { + ctx := context.Background() + cfg, err := GetConfigure() if err != nil { panic(err) @@ -49,12 +54,24 @@ func main() { }, }, ) + + txIndexerStore, err := storage.NewPostgresTxIndexStore(ctx, cfg.Database.DSN) + if err != nil { + panic(fmt.Errorf("storage.NewPostgresTxIndexStore: %w", err)) + } + + txIndexerService := tx_indexer.NewService( + logger, + txIndexerStore, + tx_indexer.Chains(), + ) + vaultService, err := vault.NewManagementService( cfg.VaultServiceConfig, client, sdClient, vaultStorage, - nil, // not used in plugin + txIndexerService, ) if err != nil { panic(fmt.Errorf("failed to create vault service: %w", err)) diff --git a/cmd/tx_indexer/config.go b/cmd/tx_indexer/config.go new file mode 100644 index 0000000..60084dc --- /dev/null +++ b/cmd/tx_indexer/config.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "os" + + "github.com/spf13/viper" + "github.com/vultisig/verifier/tx_indexer/pkg/config" +) + +func GetConfigure() (*config.Config, error) { + configName := os.Getenv("VS_CONFIG_NAME") + if configName == "" { + configName = "config" + } + + return ReadConfig(configName) +} + +func ReadConfig(configName string) (*config.Config, error) { + viper.SetConfigName(configName) + viper.AddConfigPath(".") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + return nil, fmt.Errorf("failed to read config file, %w", err) + } + var cfg config.Config + err := viper.Unmarshal(&cfg) + if err != nil { + return nil, fmt.Errorf("unable to decode into struct, %w", err) + } + return &cfg, nil +} diff --git a/cmd/tx_indexer/main.go b/cmd/tx_indexer/main.go new file mode 100644 index 0000000..f3bc8ac --- /dev/null +++ b/cmd/tx_indexer/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "context" + "fmt" + + "github.com/sirupsen/logrus" + "github.com/vultisig/verifier/tx_indexer" + "github.com/vultisig/verifier/tx_indexer/pkg/storage" +) + +func main() { + ctx := context.Background() + + logger := logrus.New() + + cfg, err := GetConfigure() + if err != nil { + panic(fmt.Errorf("GetConfigure: %w", err)) + } + + rpcs, err := tx_indexer.Rpcs(ctx, cfg.Rpc) + if err != nil { + panic(fmt.Errorf("tx_indexer.Rpcs: %w", err)) + } + + txIndexerStore, err := storage.NewPostgresTxIndexStore(ctx, cfg.Database.DSN) + if err != nil { + panic(fmt.Errorf("storage.NewPostgresTxIndexStore: %w", err)) + } + + worker := tx_indexer.NewWorker( + logger, + cfg.Interval, + cfg.IterationTimeout, + cfg.MarkLostAfter, + cfg.Concurrency, + txIndexerStore, + rpcs, + ) + + err = worker.Run() + if err != nil { + panic(fmt.Errorf("failed to start worker: %w", err)) + } +} diff --git a/config-server.yaml b/config-server.yaml index 8d88797..626b745 100644 --- a/config-server.yaml +++ b/config-server.yaml @@ -3,6 +3,9 @@ server: host: "localhost" vaults_file_path: "/tmp/vultisigner/server/vaults" +database: + dsn: postgres://myuser:mypassword@localhost:5432/vultisig-plugin?sslmode=disable + redis: host: "localhost" port: "6379" @@ -12,7 +15,7 @@ redis: block_storage: type: "s3" endpoint: "http://localhost:9000" - bucket: "vultiserver" + bucket: "vultiserver" access_key: "minioadmin" secret: "minioadmin" region: "us-east-1" @@ -22,4 +25,3 @@ block_storage: relay: server: "https://api.vultisig.com/router" - \ No newline at end of file diff --git a/config-tx-indexer.yaml b/config-tx-indexer.yaml new file mode 100644 index 0000000..b8bace0 --- /dev/null +++ b/config-tx-indexer.yaml @@ -0,0 +1,11 @@ +database: + dsn: postgres://myuser:mypassword@localhost:5432/vultisig-plugin?sslmode=disable +rpc: + bitcoin: + url: + ethereum: + url: +interval: 10s +iteration_timeout: 3m +mark_lost_after: 3h +concurrency: 50 diff --git a/go.mod b/go.mod index 719913a..172d282 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/vultisig/commondata v0.0.0-20250430024109-a2492623ef05 github.com/vultisig/mobile-tss-lib v0.0.0-20250316003201-2e7e570a4a74 github.com/vultisig/recipes v0.0.0-20250606100120-0ee16a73412d - github.com/vultisig/verifier v0.0.0-20250610121912-6a1629a06b29 + github.com/vultisig/verifier v0.0.0-20250611063307-6e5e760de529 github.com/vultisig/vultiserver v0.0.0-20250515110921-82d56d3d9cc9 ) @@ -41,6 +41,9 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/btcsuite/btcd/btcutil v1.1.6 // indirect + github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect + github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect + github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect @@ -63,6 +66,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dchest/siphash v1.2.2 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect @@ -80,16 +84,14 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect - github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/glog v1.2.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.1 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/iancoleman/strcase v0.3.0 // indirect diff --git a/go.sum b/go.sum index 9868490..e679b9e 100644 --- a/go.sum +++ b/go.sum @@ -85,16 +85,19 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtyd github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= @@ -235,6 +238,7 @@ github.com/ethereum/go-ethereum v1.15.11 h1:JK73WKeu0WC0O1eyX+mdQAVHUV+UR1a9VB/d github.com/ethereum/go-ethereum v1.15.11/go.mod h1:mf8YiHIb0GR4x4TipcvBUPxJLw1mFdmxzoDi11sDRoI= github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -309,8 +313,6 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= -github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc= github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= @@ -382,8 +384,6 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -396,8 +396,6 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -508,8 +506,11 @@ github.com/ltcsuite/ltcd/chaincfg/chainhash v1.0.2/go.mod h1:nkLkAFGhursWf2U68gt github.com/ltcsuite/ltcd/ltcutil v1.1.3 h1:8AapjCPLIt/wtYe6Odfk1EC2y9mcbpgjyxyCoNjAkFI= github.com/ltcsuite/ltcd/ltcutil v1.1.3/go.mod h1:z8txd/ohBFrOMBUT70K8iZvHJD/Vc3gzx+6BP6cBxQw= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -746,8 +747,8 @@ github.com/vultisig/mobile-tss-lib v0.0.0-20250316003201-2e7e570a4a74 h1:goqwk4n github.com/vultisig/mobile-tss-lib v0.0.0-20250316003201-2e7e570a4a74/go.mod h1:nOykk4nOy1L3yXtLSlYvVsgizBnCQ3tR2N5uwGPdvaM= github.com/vultisig/recipes v0.0.0-20250606100120-0ee16a73412d h1:BVc4OL0BNY/cCmptU3EeqAoxcX8vS13Pr13gWpd5Xi0= github.com/vultisig/recipes v0.0.0-20250606100120-0ee16a73412d/go.mod h1:JT1FTsiJ8tY5W065vSsrxvrCSl1amp5o6SsBc1VVcCQ= -github.com/vultisig/verifier v0.0.0-20250610121912-6a1629a06b29 h1:FSGm3xrw/9i1e2CgtVibtK+kamMskw2KND6KPtcvtQA= -github.com/vultisig/verifier v0.0.0-20250610121912-6a1629a06b29/go.mod h1:YpvZN2mbn6Z/34FDfnMS/TdE+B5Y8jghu5FvqOfRmB0= +github.com/vultisig/verifier v0.0.0-20250611063307-6e5e760de529 h1:owEyLmbtlN1yL0xG7EhzXgvXbBZYHSHITh4P8lvPhyQ= +github.com/vultisig/verifier v0.0.0-20250611063307-6e5e760de529/go.mod h1:YpvZN2mbn6Z/34FDfnMS/TdE+B5Y8jghu5FvqOfRmB0= github.com/vultisig/vultiserver v0.0.0-20250515110921-82d56d3d9cc9 h1:pZhGN8q8+gPB1JJjVDC1hDg8qn6Tbj0XBJymgTQ8qQg= github.com/vultisig/vultiserver v0.0.0-20250515110921-82d56d3d9cc9/go.mod h1:HwP2IgW6Mcu/gX8paFuKvfibrGE9UmPgkOFTub6dskM= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -877,6 +878,7 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -892,8 +894,10 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/storage/postgres/migrations/plugin/20250603181247_tx_indexer.sql b/storage/postgres/migrations/plugin/20250603181247_tx_indexer.sql new file mode 100644 index 0000000..ff18cc6 --- /dev/null +++ b/storage/postgres/migrations/plugin/20250603181247_tx_indexer.sql @@ -0,0 +1,33 @@ +-- +goose Up +-- +goose StatementBegin +BEGIN; +CREATE TYPE tx_indexer_status AS ENUM ('PROPOSED', 'VERIFIED', 'SIGNED'); + +CREATE TYPE tx_indexer_status_onchain AS ENUM ('PENDING', 'SUCCESS', 'FAIL'); + +CREATE TABLE tx_indexer ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + plugin_id VARCHAR(255) NOT NULL, + tx_hash VARCHAR(255), + chain_id INTEGER NOT NULL, + policy_id UUID NOT NULL, + from_public_key VARCHAR(255) NOT NULL, + proposed_tx_hex TEXT NOT NULL, + + status tx_indexer_status NOT NULL DEFAULT 'PROPOSED', + status_onchain tx_indexer_status_onchain, + + -- is Tx stuck in status_onchain=PENDING more than configured timeout, + -- flag to exclude it from on-chain status polling + lost BOOLEAN NOT NULL DEFAULT false, + -- when signed tx broadcasted on-chain + broadcasted_at TIMESTAMP, + -- to reindex something: set lost=false and broadcasted_at=now() + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_tx_indexer_status_onchain_lost ON tx_indexer(status_onchain, lost); +END; +-- +goose StatementEnd