From 6a100811f4792d1eeafdecc4983aad483bafeccd Mon Sep 17 00:00:00 2001 From: Jamie Holdstock Date: Thu, 28 May 2020 07:07:33 +0100 Subject: [PATCH] Enable pool closure (#80) * Enable pool closure. * Move homepage to its own file * Docs and rename status>info --- config.go | 3 +++ docs/api.md | 25 +++++++++---------- main.go | 6 +++++ webapi/getfeeaddress.go | 5 ++++ webapi/homepage.go | 44 ++++++++++++++++++++++++++++++++++ webapi/status.go | 23 ------------------ webapi/templates/homepage.html | 1 + webapi/types.go | 10 ++++---- webapi/vspstatus.go | 18 ++++++++++++++ webapi/webapi.go | 36 ++-------------------------- 10 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 webapi/homepage.go delete mode 100644 webapi/status.go create mode 100644 webapi/vspstatus.go diff --git a/config.go b/config.go index f5890a1..07713fb 100644 --- a/config.go +++ b/config.go @@ -29,6 +29,7 @@ var ( defaultWalletHost = "127.0.0.1" defaultWebServerDebug = false defaultBackupInterval = time.Minute * 3 + defaultVspClosed = false ) // config defines the configuration options for the VSP. @@ -51,6 +52,7 @@ type config struct { WebServerDebug bool `long:"webserverdebug" ini-name:"webserverdebug" description:"Enable web server debug mode (verbose logging to terminal and live-reloading templates)."` SupportEmail string `long:"supportemail" ini-name:"supportemail" description:"Email address for users in need of support."` BackupInterval time.Duration `long:"backupinterval" ini-name:"backupinterval" description:"Time period between automatic database backups. Valid time units are {s,m,h}. Minimum 30 seconds."` + VspClosed bool `long:"vspclosed" ini-name:"vspclosed" description:"Closed prevents the VSP from accepting new tickets."` dbPath string netParams *netParams @@ -156,6 +158,7 @@ func loadConfig() (*config, error) { WalletHost: defaultWalletHost, WebServerDebug: defaultWebServerDebug, BackupInterval: defaultBackupInterval, + VspClosed: defaultVspClosed, } // Pre-parse the command line options to see if an alternative config diff --git a/docs/api.md b/docs/api.md index d31cb58..9c5059a 100644 --- a/docs/api.md +++ b/docs/api.md @@ -15,13 +15,15 @@ ## Expected usage -### Get VSP public key +### Get VSP info -Clients should first retrieve the VSP's public key so they can check the -signature on later API responses. A VSP should never change their public key so -it can be requested once and cached indefinitely. +Clients should retrieve the VSP's public key so they can check the signature on +future API responses. A VSP should never change their public key so it can be +requested once and cached indefinitely. `vspclosed` indicates that the VSP is +not currently accepting new tickets. Calling `/feeaddress` when a VSP is closed +will result in an error. -- `GET /api/pubkey` +- `GET /api/vspinfo` No request body. @@ -29,8 +31,11 @@ it can be requested once and cached indefinitely. ```json { - "timestamp":1590509065, - "pubkey":"bLNwVVcda3LqRLv+m0J5sjd60+twjO/fuhcx8RUErDQ=" + "timestamp":1590599436, + "pubkey":"SjAmrAqH7LScCUwM1qo5O6Cu7aKhrM1ORszgZwD7HmU=", + "feepercentage":0.05, + "vspclosed":false, + "network":"testnet3" } ``` @@ -101,11 +106,7 @@ has 6 confirmations. } ``` -### Information requests - -Clients can check the status of the server at any time. - -// TODO +### Ticket Status Clients can check the status of a ticket at any time after calling `/feeaddress`. diff --git a/main.go b/main.go index 3120be1..6b8def8 100644 --- a/main.go +++ b/main.go @@ -44,6 +44,11 @@ func run(ctx context.Context) error { return err } + if cfg.VspClosed { + log.Warnf("Config --vspclosed is set. This will prevent vspd from " + + "accepting new tickets.") + } + // Waitgroup for services to signal when they have shutdown cleanly. var shutdownWg sync.WaitGroup defer log.Info("Shutdown complete") @@ -117,6 +122,7 @@ func run(ctx context.Context) error { NetParams: cfg.netParams.Params, FeeAddressExpiration: defaultFeeAddressExpiration, SupportEmail: cfg.SupportEmail, + VspClosed: cfg.VspClosed, } err = webapi.Start(ctx, shutdownRequestChannel, &shutdownWg, cfg.Listen, db, dcrdConnect, walletConnect, cfg.WebServerDebug, cfg.FeeXPub, apiCfg) diff --git a/webapi/getfeeaddress.go b/webapi/getfeeaddress.go index abc13f9..db3202a 100644 --- a/webapi/getfeeaddress.go +++ b/webapi/getfeeaddress.go @@ -69,6 +69,11 @@ func feeAddress(c *gin.Context) { commitmentAddress := c.MustGet("CommitmentAddress").(string) dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC) + if cfg.VspClosed { + sendErrorResponse("pool is not accepting new tickets", http.StatusBadRequest, c) + return + } + var feeAddressRequest FeeAddressRequest if err := binding.JSON.BindBody(rawRequest, &feeAddressRequest); err != nil { log.Warnf("Bad feeaddress request from %s: %v", c.ClientIP(), err) diff --git a/webapi/homepage.go b/webapi/homepage.go new file mode 100644 index 0000000..156adb5 --- /dev/null +++ b/webapi/homepage.go @@ -0,0 +1,44 @@ +package webapi + +import ( + "net/http" + "time" + + "github.com/jholdstock/vspd/database" + + "github.com/gin-gonic/gin" +) + +type vspStats struct { + PubKey []byte + TotalTickets int + FeePaidTickets int + VSPFee float64 + Network string + UpdateTime string + SupportEmail string + VspClosed bool +} + +var stats *vspStats + +func updateVSPStats(db *database.VspDatabase, cfg Config) (*vspStats, error) { + total, feePaid, err := db.CountTickets() + if err != nil { + return nil, err + } + return &vspStats{ + PubKey: signPubKey, + TotalTickets: total, + FeePaidTickets: feePaid, + VSPFee: cfg.VSPFee, + Network: cfg.NetParams.Name, + UpdateTime: time.Now().Format("Mon Jan _2 15:04:05 2006"), + SupportEmail: cfg.SupportEmail, + VspClosed: cfg.VspClosed, + }, nil +} + +func homepage(c *gin.Context) { + c.HTML(http.StatusOK, "homepage.html", stats) +} diff --git a/webapi/status.go b/webapi/status.go deleted file mode 100644 index e48aa05..0000000 --- a/webapi/status.go +++ /dev/null @@ -1,23 +0,0 @@ -package webapi - -import ( - "time" - - "github.com/gin-gonic/gin" -) - -// pubKey is the handler for "GET /pubkey". -func pubKey(c *gin.Context) { - sendJSONResponse(pubKeyResponse{ - Timestamp: time.Now().Unix(), - PubKey: signPubKey, - }, c) -} - -// fee is the handler for "GET /fee". -func fee(c *gin.Context) { - sendJSONResponse(feeResponse{ - Timestamp: time.Now().Unix(), - FeePercentage: cfg.VSPFee, - }, c) -} diff --git a/webapi/templates/homepage.html b/webapi/templates/homepage.html index 37d46a8..20ab7c2 100644 --- a/webapi/templates/homepage.html +++ b/webapi/templates/homepage.html @@ -48,6 +48,7 @@ Network:{{ .Network }} Support:{{ .SupportEmail }} Pubkey:{{ printf "%x" .PubKey }} + VSP closed:{{ .VspClosed }}

Last updated: {{.UpdateTime}}

diff --git a/webapi/types.go b/webapi/types.go index 6e8478a..1fec776 100644 --- a/webapi/types.go +++ b/webapi/types.go @@ -1,13 +1,11 @@ package webapi -type pubKeyResponse struct { - Timestamp int64 `json:"timestamp" binding:"required"` - PubKey []byte `json:"pubkey" binding:"required"` -} - -type feeResponse struct { +type vspInfoResponse struct { Timestamp int64 `json:"timestamp" binding:"required"` + PubKey []byte `json:"pubkey" binding:"required"` FeePercentage float64 `json:"feepercentage" binding:"required"` + VspClosed bool `json:"vspclosed" binding:"required"` + Network string `json:"network" binding:"required"` } type FeeAddressRequest struct { diff --git a/webapi/vspstatus.go b/webapi/vspstatus.go new file mode 100644 index 0000000..3c71f4d --- /dev/null +++ b/webapi/vspstatus.go @@ -0,0 +1,18 @@ +package webapi + +import ( + "time" + + "github.com/gin-gonic/gin" +) + +// vspInfo is the handler for "GET /vspinfo". +func vspInfo(c *gin.Context) { + sendJSONResponse(vspInfoResponse{ + Timestamp: time.Now().Unix(), + PubKey: signPubKey, + FeePercentage: cfg.VSPFee, + Network: cfg.NetParams.Name, + VspClosed: cfg.VspClosed, + }, c) +} diff --git a/webapi/webapi.go b/webapi/webapi.go index 1857340..66fe296 100644 --- a/webapi/webapi.go +++ b/webapi/webapi.go @@ -24,6 +24,7 @@ type Config struct { FeeAccountName string FeeAddressExpiration time.Duration SupportEmail string + VspClosed bool } const ( @@ -34,18 +35,6 @@ const ( relayFee = 0.0001 ) -type vspStats struct { - PubKey []byte - TotalTickets int - FeePaidTickets int - VSPFee float64 - Network string - UpdateTime string - SupportEmail string -} - -var stats *vspStats - var cfg Config var db *database.VspDatabase var dcrdConnect rpc.Connect @@ -185,8 +174,7 @@ func router(debugMode bool) *gin.Engine { // These routes have no extra middleware. They can be accessed by anybody. router.GET("/", homepage) - router.GET("/api/fee", fee) - router.GET("/api/pubkey", pubKey) + router.GET("/api/vspinfo", vspInfo) // These API routes access dcrd and they need authentication. feeOnly := router.Group("/api").Use( @@ -206,26 +194,6 @@ func router(debugMode bool) *gin.Engine { return router } -func updateVSPStats(db *database.VspDatabase, cfg Config) (*vspStats, error) { - total, feePaid, err := db.CountTickets() - if err != nil { - return nil, err - } - return &vspStats{ - PubKey: signPubKey, - TotalTickets: total, - FeePaidTickets: feePaid, - VSPFee: cfg.VSPFee, - Network: cfg.NetParams.Name, - UpdateTime: time.Now().Format("Mon Jan _2 15:04:05 2006"), - SupportEmail: cfg.SupportEmail, - }, nil -} - -func homepage(c *gin.Context) { - c.HTML(http.StatusOK, "homepage.html", stats) -} - func sendJSONResponse(resp interface{}, c *gin.Context) { dec, err := json.Marshal(resp) if err != nil {