diff --git a/blockbook.go b/blockbook.go index 9188c2c7..77a89f1d 100644 --- a/blockbook.go +++ b/blockbook.go @@ -73,6 +73,8 @@ var ( noTxCache = flag.Bool("notxcache", false, "disable tx cache") + enableSubNewTx = flag.Bool("enablesubnewtx", false, "enable support for subscribing to all new transactions") + computeColumnStats = flag.Bool("computedbstats", false, "compute column stats and exit") computeFeeStatsFlag = flag.Bool("computefeestats", false, "compute fee stats for blocks in blockheight-blockuntil range and exit") dbStatsPeriodHours = flag.Int("dbstatsperiod", 24, "period of db stats collection in hours, 0 disables stats collection") @@ -405,7 +407,7 @@ func startInternalServer() (*server.InternalServer, error) { func startPublicServer() (*server.PublicServer, error) { // start public server in limited functionality, extend it after sync is finished by calling ConnectFullPublicInterface - publicServer, err := server.NewPublicServer(*publicBinding, *certFiles, index, chain, mempool, txCache, *explorerURL, metrics, internalState, *debugMode) + publicServer, err := server.NewPublicServer(*publicBinding, *certFiles, index, chain, mempool, txCache, *explorerURL, metrics, internalState, *debugMode, *enableSubNewTx) if err != nil { return nil, err } diff --git a/docs/api.md b/docs/api.md index ff080d25..00ed2730 100644 --- a/docs/api.md +++ b/docs/api.md @@ -771,6 +771,8 @@ The client can subscribe to the following events: There can be always only one subscription of given event per connection, i.e. new list of addresses replaces previous list of addresses. +The subscribeNewTransaction event is not enabled by default. To enable support, blockbook must be run with the `-enablesubnewtx` flag. + _Note: If there is reorg on the backend (blockchain), you will get a new block hash with the same or even smaller height if the reorg is deeper_ Websocket communication format diff --git a/server/public.go b/server/public.go index 1a9d1dde..a92fc1f1 100644 --- a/server/public.go +++ b/server/public.go @@ -58,7 +58,7 @@ type PublicServer struct { // NewPublicServer creates new public server http interface to blockbook and returns its handle // only basic functionality is mapped, to map all functions, call -func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, explorerURL string, metrics *common.Metrics, is *common.InternalState, debugMode bool) (*PublicServer, error) { +func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, explorerURL string, metrics *common.Metrics, is *common.InternalState, debugMode bool, enableSubNewTx bool) (*PublicServer, error) { api, err := api.NewWorker(db, chain, mempool, txCache, is) if err != nil { @@ -70,7 +70,7 @@ func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bch return nil, err } - websocket, err := NewWebsocketServer(db, chain, mempool, txCache, metrics, is) + websocket, err := NewWebsocketServer(db, chain, mempool, txCache, metrics, is, enableSubNewTx) if err != nil { return nil, err } diff --git a/server/public_test.go b/server/public_test.go index 75748b3b..161ca66f 100644 --- a/server/public_test.go +++ b/server/public_test.go @@ -109,7 +109,7 @@ func setupPublicHTTPServer(t *testing.T) (*PublicServer, string) { } // s.Run is never called, binding can be to any port - s, err := NewPublicServer("localhost:12345", "", d, chain, mempool, txCache, "", metrics, is, false) + s, err := NewPublicServer("localhost:12345", "", d, chain, mempool, txCache, "", metrics, is, false, false) if err != nil { t.Fatal(err) } @@ -1426,14 +1426,14 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { req: websocketReq{ Method: "subscribeNewTransaction", }, - want: `{"id":"37","data":{"subscribed":true}}`, + want: `{"id":"37","data":{"subscribed":false,"message":"subscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}}`, }, { name: "websocket unsubscribeNewTransaction", req: websocketReq{ Method: "unsubscribeNewTransaction", }, - want: `{"id":"38","data":{"subscribed":false}}`, + want: `{"id":"38","data":{"subscribed":false,"message":"unsubscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}}`, }, } diff --git a/server/websocket.go b/server/websocket.go index 7548875d..48b45c80 100644 --- a/server/websocket.go +++ b/server/websocket.go @@ -70,6 +70,7 @@ type WebsocketServer struct { block0hash string newBlockSubscriptions map[*websocketChannel]string newBlockSubscriptionsLock sync.Mutex + newTransactionEnabled bool newTransactionSubscriptions map[*websocketChannel]string newTransactionSubscriptionsLock sync.Mutex addressSubscriptions map[string]map[*websocketChannel]string @@ -79,7 +80,7 @@ type WebsocketServer struct { } // NewWebsocketServer creates new websocket interface to blockbook and returns its handle -func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*WebsocketServer, error) { +func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState, enableSubNewTx bool) (*WebsocketServer, error) { api, err := api.NewWorker(db, chain, mempool, txCache, is) if err != nil { return nil, err @@ -104,6 +105,7 @@ func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain. api: api, block0hash: b0, newBlockSubscriptions: make(map[*websocketChannel]string), + newTransactionEnabled: enableSubNewTx, newTransactionSubscriptions: make(map[*websocketChannel]string), addressSubscriptions: make(map[string]map[*websocketChannel]string), fiatRatesSubscriptions: make(map[string]map[*websocketChannel]string), @@ -667,6 +669,10 @@ func (s *WebsocketServer) sendTransaction(tx string) (res resultSendTransaction, type subscriptionResponse struct { Subscribed bool `json:"subscribed"` } +type subscriptionResponseMessage struct { + Subscribed bool `json:"subscribed"` + Message string `json:"message"` +} func (s *WebsocketServer) subscribeNewBlock(c *websocketChannel, req *websocketReq) (res interface{}, err error) { s.newBlockSubscriptionsLock.Lock() @@ -685,6 +691,9 @@ func (s *WebsocketServer) unsubscribeNewBlock(c *websocketChannel) (res interfac func (s *WebsocketServer) subscribeNewTransaction(c *websocketChannel, req *websocketReq) (res interface{}, err error) { s.newTransactionSubscriptionsLock.Lock() defer s.newTransactionSubscriptionsLock.Unlock() + if !s.newTransactionEnabled { + return &subscriptionResponseMessage{false, "subscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}, nil + } s.newTransactionSubscriptions[c] = req.ID return &subscriptionResponse{true}, nil } @@ -692,6 +701,9 @@ func (s *WebsocketServer) subscribeNewTransaction(c *websocketChannel, req *webs func (s *WebsocketServer) unsubscribeNewTransaction(c *websocketChannel) (res interface{}, err error) { s.newTransactionSubscriptionsLock.Lock() defer s.newTransactionSubscriptionsLock.Unlock() + if !s.newTransactionEnabled { + return &subscriptionResponseMessage{false, "unsubscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}, nil + } delete(s.newTransactionSubscriptions, c) return &subscriptionResponse{false}, nil }