From 02becf9e7cd0eb9f2e80ddf65cf82b856759d091 Mon Sep 17 00:00:00 2001
From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com>
Date: Mon, 25 Apr 2022 10:19:09 -0400
Subject: [PATCH] fix: data race issues with api.Server (backport #11724)
 (#11749)

---
 CHANGELOG.md         |  1 +
 server/api/server.go | 17 +++++++++++++++--
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef0dc0a3178f..fe48bd636b7c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -211,6 +211,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
 
 ### Bug Fixes
 
+* [\#11724](https://github.com/cosmos/cosmos-sdk/pull/11724) Fix data race issues with `api.Server`.
 * [\#11354](https://github.com/cosmos/cosmos-sdk/pull/11355) Added missing pagination flag for `bank q total` query.
 * [\#11197](https://github.com/cosmos/cosmos-sdk/pull/11197) Signing with multisig now works with multisig address which is not in the keyring.
 * (makefile) [\#11285](https://github.com/cosmos/cosmos-sdk/pull/11285) Fix lint-fix make target.
diff --git a/server/api/server.go b/server/api/server.go
index 18daefb83c8c..c052c03f52ca 100644
--- a/server/api/server.go
+++ b/server/api/server.go
@@ -5,6 +5,7 @@ import (
 	"net"
 	"net/http"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/gogo/gateway"
@@ -30,8 +31,13 @@ type Server struct {
 	GRPCGatewayRouter *runtime.ServeMux
 	ClientCtx         client.Context
 
-	logger   log.Logger
-	metrics  *telemetry.Metrics
+	logger  log.Logger
+	metrics *telemetry.Metrics
+	// Start() is blocking and generally called from a separate goroutine.
+	// Close() can be called asynchronously and access shared memory
+	// via the listener. Therefore, we sync access to Start and Close with
+	// this mutex to avoid data races.
+	mtx      sync.Mutex
 	listener net.Listener
 }
 
@@ -83,9 +89,11 @@ func New(clientCtx client.Context, logger log.Logger) *Server {
 // and are delegated to the Tendermint JSON RPC server. The process is
 // non-blocking, so an external signal handler must be used.
 func (s *Server) Start(cfg config.Config) error {
+	s.mtx.Lock()
 	if cfg.Telemetry.Enabled {
 		m, err := telemetry.New(cfg.Telemetry)
 		if err != nil {
+			s.mtx.Unlock()
 			return err
 		}
 
@@ -101,6 +109,7 @@ func (s *Server) Start(cfg config.Config) error {
 
 	listener, err := tmrpcserver.Listen(cfg.API.Address, tmCfg.MaxOpenConnections)
 	if err != nil {
+		s.mtx.Unlock()
 		return err
 	}
 
@@ -111,15 +120,19 @@ func (s *Server) Start(cfg config.Config) error {
 
 	if cfg.API.EnableUnsafeCORS {
 		allowAllCORS := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}))
+		s.mtx.Unlock()
 		return tmrpcserver.Serve(s.listener, allowAllCORS(h), s.logger, tmCfg)
 	}
 
 	s.logger.Info("starting API server...")
+	s.mtx.Unlock()
 	return tmrpcserver.Serve(s.listener, s.Router, s.logger, tmCfg)
 }
 
 // Close closes the API server.
 func (s *Server) Close() error {
+	s.mtx.Lock()
+	defer s.mtx.Unlock()
 	return s.listener.Close()
 }