func GetNodeInfo(id proto.NodeID) (nodeInfo *proto.Node, err error) {
	pksLock.Lock()
	defer pksLock.Unlock()
	if pks == nil || pks.db == nil {
		return nil, ErrPKSNotInitialized
	}
	if err = func() (err error) {
		var rawNodeInfo []byte
		if err = pks.db.Writer().QueryRow(getRecordSQL, string(id)).Scan(&rawNodeInfo); err != nil {
			if errors.Cause(err) == sql.ErrNoRows {
				err = ErrKeyNotFound
			}
			return
		}
		err = utils.DecodeMsgPack(rawNodeInfo, &nodeInfo)
		log.Debugf("get node info: %#v", nodeInfo)
		return
	}(); err != nil {
		err = errors.Wrap(err, "get node info failed")
	}
	return
}
GetNodeInfo gets node info of given id
Returns an error if the id was not found.
package kms
import (
	"database/sql"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"github.com/pkg/errors"
	"github.com/SQLess/SQLess/conf"
	"github.com/SQLess/SQLess/crypto/asymmetric"
	"github.com/SQLess/SQLess/crypto/hash"
	mine "github.com/SQLess/SQLess/pow/cpuminer"
	"github.com/SQLess/SQLess/proto"
	"github.com/SQLess/SQLess/utils"
	"github.com/SQLess/SQLess/utils/log"
	xs "github.com/SQLess/SQLess/xenomint/sqlite"
)
type PublicKeyStore struct {
	db *xs.SQLite3
}
var (
	pks     *PublicKeyStore
	pksLock sync.Mutex
	Unittest bool
)
var (
	BP *conf.BPInfo
)
var (
	initTableSQL = `CREATE TABLE IF NOT EXISTS "kms" (
		"id"   TEXT,
		"node" BLOB,
		UNIQUE ("id")
	)`
	deleteAllSQL    = `DELETE FROM "kms"`
	deleteRecordSQL = `DELETE FROM "kms" WHERE "id" = ?`
	setRecordSQL    = `INSERT OR REPLACE INTO "kms" ("id", "node") VALUES(?, ?)`
	getRecordSQL    = `SELECT "node" FROM "kms" WHERE "id" = ? LIMIT 1`
	getAllNodeIDSQL = `SELECT "id" FROM "kms"`
)
func init() {
	if strings.HasSuffix(os.Args[0], ".test") ||
		strings.HasSuffix(os.Args[0], ".test.exe") ||
		strings.HasPrefix(filepath.Base(os.Args[0]), "___") {
		_, testFile, _, _ := runtime.Caller(0)
		confFile := filepath.Join(filepath.Dir(testFile), "config.yaml")
		log.WithField("conf", confFile).Debug("current test filename")
		log.Debugf("os.Args: %#v", os.Args)
		var err error
		conf.GConf, err = conf.LoadConfig(confFile)
		if err != nil {
			log.WithError(err).Fatal("load config for test in kms failed")
		}
		InitBP()
	}
}
func InitBP() {
	if conf.GConf == nil {
		log.Fatal("must call conf.LoadConfig first")
	}
	if conf.GConf.BP == nil && len(conf.GConf.SeedBPNodes) > 0 {
		seedBP := &conf.GConf.SeedBPNodes[0]
		conf.GConf.BP = &conf.BPInfo{
			PublicKey: seedBP.PublicKey,
			NodeID:    seedBP.ID,
			Nonce:     seedBP.Nonce,
		}
	}
	if conf.GConf.BP == nil {
		log.Fatal("no available block producer config")
	}
	BP = conf.GConf.BP
	err := hash.Decode(&conf.GConf.BP.RawNodeID.Hash, string(conf.GConf.BP.NodeID))
	if err != nil {
		log.WithError(err).Fatal("BP.NodeID error")
	}
}
var (
	ErrPKSNotInitialized = errors.New("public keystore not initialized")
	ErrNilNode = errors.New("nil node")
	ErrKeyNotFound = errors.New("key not found")
	ErrNodeIDKeyNonceNotMatch = errors.New("nodeID, key, nonce not match")
)
func InitPublicKeyStore(dbPath string, initNodes []proto.Node) (err error) {
	ClosePublicKeyStore()
	pksLock.Lock()
	InitBP()
	var strg *xs.SQLite3
	if strg, err = func() (strg *xs.SQLite3, err error) {
		if err = removeFileIfIsNotSQLite(dbPath); err != nil {
			return
		}
		if strg, err = xs.NewSqlite(dbPath); err != nil {
			return
		}
		if _, err = strg.Writer().Exec(initTableSQL); err != nil {
			return
		}
		return
	}(); err != nil {
		pksLock.Unlock()
		log.WithError(err).Error("InitPublicKeyStore failed")
		return
	}
	pks = &PublicKeyStore{
		db: strg,
	}
	pksLock.Unlock()
	for _, n := range initNodes {
		err = setNode(&n)
		if err != nil {
			err = errors.Wrap(err, "set init nodes failed")
			return
		}
	}
	return
}
func GetPublicKey(id proto.NodeID) (publicKey *asymmetric.PublicKey, err error) {
	node, err := GetNodeInfo(id)
	if err == nil {
		publicKey = node.PublicKey
	}
	return
}