func setupBlockDB() (database.Db, error) {
	if cfg.Core.Datastore.DBType == "memdb" {
		logging.CPrint(logging.INFO, "creating block database in memory", logging.LogFormat{})
		db, err := database.CreateDB("memdb")
		if err != nil {
			return nil, err
		}
		return db, nil
	}
	err := os.MkdirAll(cfg.Core.Datastore.Dir, 0700)
	if err != nil {
		return nil, err
	}
	if err = storage.CheckCompatibility(cfg.Core.Datastore.DBType, cfg.Core.Datastore.Dir); err != nil {
		logging.CPrint(logging.ERROR, "check storage compatibility failed", logging.LogFormat{"err": err})
		return nil, err
	}
	dbPath := blockDbPath(cfg.Core.Datastore.DBType)
	db, err := database.OpenDB(cfg.Core.Datastore.DBType, dbPath, false)
	if err != nil {
		logging.CPrint(logging.WARN, "open db failed", logging.LogFormat{"err": err, "path": dbPath})
		db, err = database.CreateDB(cfg.Core.Datastore.DBType, dbPath)
		if err != nil {
			logging.CPrint(logging.ERROR, "create db failed", logging.LogFormat{"err": err, "path": dbPath})
			return nil, err
		}
	}
	return db, nil
}
setupBlockDB loads (or creates when needed) the block database taking into
account the selected database backend.  It also contains additional logic
such warning the user if there are multiple databases which consume space on
the file system and ensuring the regression test database is clean when in
regression test mode.
package main
import (
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path/filepath"
	"runtime"
	"github.com/massnetorg/mass-core/blockchain/state"
	"github.com/massnetorg/mass-core/database"
	_ "github.com/massnetorg/mass-core/database/ldb"
	"github.com/massnetorg/mass-core/database/storage"
	_ "github.com/massnetorg/mass-core/database/storage/ldbstorage"
	_ "github.com/massnetorg/mass-core/database/storage/rdbstorage"
	"github.com/massnetorg/mass-core/limits"
	"github.com/massnetorg/mass-core/logging"
	"github.com/massnetorg/mass-core/trie/massdb"
	"github.com/massnetorg/mass-core/trie/rawdb"
	"github.com/massnetorg/mass-core/version"
	"massnet.org/mass-wallet/config"
	_ "massnet.org/mass-wallet/masswallet/db/ldb"
	_ "massnet.org/mass-wallet/masswallet/db/rdb"
)
var (
	cfg             *config.Config
	closeDbChannel  = make(chan struct{})
	shutdownChannel = make(chan struct{})
)
var winServiceMain func() (bool, error)
func massMain(serverChan chan<- *server) error {
	tempCfg, _, err := config.ParseConfig()
	if err != nil {
		return err
	}
	config.LoadConfig(tempCfg)
	cfg = config.CheckConfig(tempCfg)
	logging.Init(cfg.Core.Log.LogDir, config.DefaultLoggingFilename, cfg.Core.Log.LogLevel, 1, false)
	logging.CPrint(logging.INFO, fmt.Sprintf("version %s", version.GetVersion()), logging.LogFormat{})
	if cfg.Core.Metrics.ProfilePort != "" {
		go func() {
			listenAddr := net.JoinHostPort("", cfg.Core.Metrics.ProfilePort)
			logging.CPrint(logging.INFO, fmt.Sprintf("profile server listening on %s", listenAddr), logging.LogFormat{})
			profileRedirect := http.RedirectHandler("/debug/pprof",
				http.StatusSeeOther)
			http.Handle("/", profileRedirect)
			logging.CPrint(logging.ERROR, fmt.Sprintf("%v", http.ListenAndServe(listenAddr, nil)), logging.LogFormat{})
		}()
	}
	bindingDb, err := openStateDatabase(cfg.Core.Datastore.Dir, "bindingstate", 0, 0, "", false)
	if err != nil {
		logging.CPrint(logging.ERROR, "failed to load binding database", logging.LogFormat{"err": err})
		return err
	}
	db, err := setupBlockDB()
	if err != nil {
		bindingDb.Close()
		logging.CPrint(logging.ERROR, "setupBlockDB error", logging.LogFormat{"err": err})
		return err
	}
	server, err := newServer(db, state.NewDatabase(bindingDb), config.ChainParams)
	if err != nil {
		bindingDb.Close()
		db.Close()
		logging.CPrint(logging.ERROR, "unable to start server on address", logging.LogFormat{"addr": cfg.Core.P2P.ListenAddress, "err": err})
		return err
	}
	loader := NewLoader(server, config.ChainParams, cfg)
	if err = loader.LoadWallet(); err != nil {
		bindingDb.Close()
		db.Close()
		return err
	}
	addInterruptHandler(func() {
		server.Stop()
		err := loader.UnloadWallet()
		if err != nil {
			logging.CPrint(logging.ERROR, "failed to unload wallet", logging.LogFormat{"err": err})
		}
		server.WaitForShutdown()
		err0 := bindingDb.Close()
		err1 := db.Close()
		logging.CPrint(logging.INFO, "db closed", logging.LogFormat{
			"binding error": err0,
			"chain error":   err1,
		})
		closeDbChannel <- struct{}{}
	})
	server.Start()
	if serverChan != nil {
		serverChan <- server
	}
	go func() {
		shutdownChannel <- (<-closeDbChannel)
	}()
	<-shutdownChannel
	return nil
}
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	if err := limits.SetLimits(); err != nil {
		fmt.Fprintf(os.Stderr, "failed to set limits: %v\n", err)
		os.Exit(1)
	}
	if runtime.GOOS == "windows" {
		isService, err := winServiceMain()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		if isService {
			os.Exit(0)
		}
	}
	if err := massMain(nil); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
const blockDbNamePrefix = "blocks"
func blockDbPath(dbType string) string {
	dbName := blockDbNamePrefix + ".db"
	if dbType == "sqlite" {
		dbName = dbName + ".db"
	}
	dbPath := filepath.Join(cfg.Core.Datastore.Dir, dbName)
	return dbPath
}