func (met *Metropolis) SetOrg(chainID, appname string, o *OrgNode) {
	met.mtx.Lock()
	met.Orgs[ChainID(chainID)] = o
	met.OrgApps[ChainID(chainID)] = AppName(appname)
	met.mtx.Unlock()
}
SetOrg wraps some atomic operations that need to be done when this node create/join an organization
package node
import (
	"bytes"
	"encoding/binary"
	"encoding/gob"
	"encoding/json"
	"fmt"
	"math/big"
	"path"
	"strconv"
	"sync"
	"time"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
	"github.com/tendermint/tmlibs/db"
	"go.uber.org/zap"
	ac "github.com/Baptist-Publication/angine/config"
	pbtypes "github.com/Baptist-Publication/angine/protos/types"
	agtypes "github.com/Baptist-Publication/angine/types"
	cmn "github.com/Baptist-Publication/chorus-module/lib/go-common"
	"github.com/Baptist-Publication/chorus-module/lib/go-crypto"
	"github.com/Baptist-Publication/chorus-module/lib/go-merkle"
	"github.com/Baptist-Publication/chorus-module/xlib"
	acfg "github.com/Baptist-Publication/chorus/src/chain/config"
	"github.com/Baptist-Publication/chorus/src/chain/log"
)
const (
	BASE_APP_NAME = "metropolis"
	StartRedeemHeight = 15000
)
type (
	AppName string
	ChainID string
	MetropolisState struct {
		OrgStateHash   []byte
		OrgHeights     []agtypes.INT
		EventStateHash []byte
		AccStateHash   []byte
		PowerStateHash []byte
	}
	Metropolis struct {
		agtypes.BaseApplication
		mtx  sync.Mutex
		node *Node
		core Core
		config      *viper.Viper
		angineHooks agtypes.Hooks
		logger      *zap.Logger
		state *MetropolisState
		OrgStateDB db.DB
		OrgState *OrgState
		OrgApps  map[ChainID]AppName
		Orgs map[ChainID]*OrgNode
		PendingOrgTxs map[string]*OrgTx
		EventStateDB   db.DB
		EventState     *EventState
		EventWarehouse *EventWarehouse
		EventCodeBase  db.DB
		PendingEventRequestTxs map[string]*EventRequestTx
		accStateDB db.DB
		accState   *AccState
		powerStateDB db.DB
		powerState   *PowerState
		FeeAccum *big.Int
	}
	LastBlockInfo struct {
		Height agtypes.INT `msgpack:"height"`
		Hash []byte `msgpack:"hash"`
	}
)
var (
	ErrUnknownTx = fmt.Errorf("please give me something that I actually know about")
	Big0 = new(big.Int).SetUint64(0)
)
func NewLastBlockInfo() *LastBlockInfo {
	return &LastBlockInfo{
		Height: 0,
		Hash:   make([]byte, 0),
	}
}
func NewMetropolis(logger *zap.Logger, conf *viper.Viper) *Metropolis {
	datadir := conf.GetString("db_dir")
	met := Metropolis{
		config: conf,
		logger: logger,
		state: &MetropolisState{
			OrgHeights:     make([]agtypes.INT, 0),
			OrgStateHash:   make([]byte, 0),
			EventStateHash: make([]byte, 0),
			AccStateHash:   make([]byte, 0),
			PowerStateHash: make([]byte, 0),
		},
		OrgApps: make(map[ChainID]AppName),
		Orgs:    make(map[ChainID]*OrgNode),
		PendingOrgTxs:          make(map[string]*OrgTx),
		PendingEventRequestTxs: make(map[string]*EventRequestTx),
	}
	var err error
	if err = met.BaseApplication.InitBaseApplication(BASE_APP_NAME, datadir); err != nil {
		cmn.PanicCrisis(err)
	}
	if met.OrgStateDB, err = db.NewGoLevelDB("orgStatus", datadir); err != nil {
		cmn.PanicCrisis(err)
	}
	met.OrgState = NewOrgState(met.OrgStateDB)
	if met.EventStateDB, err = db.NewGoLevelDB("eventstate", datadir); err != nil {
		cmn.PanicCrisis(err)
	}
	met.EventState = NewEventState(met.EventStateDB)
	ewhDB, err := db.NewGoLevelDB("eventwarehouse", datadir)
	if err != nil {
		cmn.PanicCrisis(err)
	}
	met.EventWarehouse = NewEventWarehouse(ewhDB)
	met.EventCodeBase, err = db.NewGoLevelDB("eventcodebase", datadir)
	if err != nil {
		cmn.PanicCrisis(err)
	}
	if met.accStateDB, err = db.NewGoLevelDB("accountstate", datadir); err != nil {
		cmn.PanicCrisis(err)
	}
	met.accState = NewAccState(met.accStateDB)
	if met.powerStateDB, err = db.NewGoLevelDB("powerstate", datadir); err != nil {
		cmn.PanicCrisis(err)
	}
	met.powerState = NewPowerState(met.powerStateDB)
	met.angineHooks = agtypes.Hooks{
		OnExecute: agtypes.NewHook(met.OnExecute),
		OnCommit:  agtypes.NewHook(met.OnCommit),
	}
	return &met
}
func (met *Metropolis) Hash() []byte {
	return met.state.Hash()
}
func (met *Metropolis) Lock() {
	met.mtx.Lock()
}
func (met *Metropolis) Unlock() {
	met.mtx.Unlock()
}
func (met *Metropolis) SetNode(n *Node) {
	met.node = n
}
func (met *Metropolis) SetCore(c Core) {
	met.core = c
}
func (met *Metropolis) BroadcastTx(tx []byte) error {
	return met.core.GetEngine().BroadcastTx(tx)
}
func (met *Metropolis) GetNodePubKey() crypto.PubKey {
	return met.core.GetEngine().PrivValidator().GetPubKey()
}
func (met *Metropolis) Stop() {
	for i := range met.Orgs {
		met.Orgs[i].Stop()
	}
}
func (met *Metropolis) Load(lb *LastBlockInfo) error {
	met.Lock()
	defer met.Unlock()
	state := &MetropolisState{}
	if lb == nil {
		return nil
	}
	bs := met.Database.Get(lb.Hash)
	if err := state.FromBytes(bs); err != nil {
		return errors.Wrap(err, "fail to restore metropolis state")
	}
	met.state = state
	met.OrgState.Load(met.state.OrgStateHash)
	met.EventState.Load(met.state.EventStateHash)
	if met.config.GetBool("enable_incentive") {
		met.accState.Load(met.state.AccStateHash)
		met.powerState.Load(met.state.PowerStateHash)
	}
	return nil
}
func (met *Metropolis) Start() error {
	if err := met.spawnOffchainEventListener(); err != nil {
		met.logger.Error("fail to start event server", zap.Error(err))
		return err
	}
	lastBlock := NewLastBlockInfo()
	if res, err := met.LoadLastBlock(lastBlock); err == nil {
		lastBlock = res.(*LastBlockInfo)
	}
	if lastBlock.Hash == nil || len(lastBlock.Hash) == 0 {
		return nil
	}
	if err := met.Load(lastBlock); err != nil {
		met.logger.Error("fail to load metropolis state", zap.Error(err))
		return err
	}
	for _, height := range met.state.OrgHeights {
		block, _, err := met.core.GetEngine().GetBlock(agtypes.INT(height))
		if err != nil {
			return err
		}
		for _, tx := range block.Data.Txs {
			txBytes := agtypes.UnwrapTx(tx)
			switch {
			case IsOrgCancelTx(tx):
				met.restoreOrgCancel(txBytes)
			case IsOrgConfirmTx(tx):
				met.restoreOrgConfirm(txBytes)
			case IsOrgTx(tx):
				met.restoreOrg(txBytes)
			}
		}
	}
	return nil
}
func (met *Metropolis) GetAngineHooks() agtypes.Hooks {
	return met.angineHooks
}
func (met *Metropolis) GetAttributes() map[string]string {
	return nil
}
func (met *Metropolis) CompatibleWithAngine() {}
func (met *Metropolis) OnCommit(height, round agtypes.INT, block *agtypes.BlockCache) (interface{}, error) {
	var err error
	if met.state.OrgStateHash, err = met.OrgState.Commit(); err != nil {
		met.logger.Error("fail to commit orgState", zap.Error(err))
		return nil, err
	}
	if met.state.EventStateHash, err = met.EventState.Commit(); err != nil {
		met.logger.Error("fail to commit eventState", zap.Error(err))
		return nil, err
	}
	if met.config.GetBool("enable_incentive") {
		if met.state.AccStateHash, err = met.accState.Commit(); err != nil {
			met.logger.Error("fail to commit accState", zap.Error(err))
			return nil, err
		}
		if met.state.PowerStateHash, err = met.powerState.Commit(); err != nil {
			met.logger.Error("fail to commit powerState", zap.Error(err))
			return nil, err
		}
	}
	met.state.OrgHeights = sterilizeOrgHeights(met.state.OrgHeights)
	lastBlock := LastBlockInfo{Height: height, Hash: met.Hash()}
	met.Database.SetSync(lastBlock.Hash, met.state.ToBytes())
	met.SaveLastBlock(lastBlock)
	defer func() {
		met.OrgState.Reload(met.state.OrgStateHash)
		met.EventState.Reload(met.state.EventStateHash)
		if met.config.GetBool("enable_incentive") {
			met.accState.Reload(met.state.AccStateHash)
			met.powerState.Reload(met.state.PowerStateHash)
		}
	}()
	fmt.Println("height:", height, "fee:", met.FeeAccum.String(), "account size:", met.accState.Size(), "power size:", met.powerState.Size())
	return agtypes.CommitResult{AppHash: lastBlock.Hash}, nil
}
func (met *Metropolis) IsTxKnown(bs []byte) bool {
	return IsOrgRelatedTx(bs)
}
func (met *Metropolis) Info() (resInfo agtypes.ResultInfo) {
	lb := NewLastBlockInfo()
	if res, err := met.LoadLastBlock(lb); err == nil {
		lb = res.(*LastBlockInfo)
	}
	resInfo.LastBlockAppHash = lb.Hash
	resInfo.LastBlockHeight = lb.Height
	resInfo.Version = "alpha 0.2"
	resInfo.Data = "metropolis with organizations and inter-organization communication"
	return
}
func (met *Metropolis) SetOption() {}
func (met *Metropolis) Query(query []byte) agtypes.Result {
	if len(query) == 0 {
		return agtypes.NewResultOK([]byte{}, "Empty query")
	}
	var res agtypes.Result
	switch query[0] {
	case agtypes.QueryTxExecution:
		qryRes, err := met.core.GetEngine().Query(query[0], query[1:])
		if err != nil {
			return agtypes.NewError(pbtypes.CodeType_InternalError, err.Error())
		}
		info, ok := qryRes.(*agtypes.TxExecutionResult)
		if !ok {
			return agtypes.NewError(pbtypes.CodeType_InternalError, err.Error())
		}
		res.Code = pbtypes.CodeType_OK
		res.Data, _ = info.ToBytes()
		return res
	case QueryEvents:
		keys := make([]string, 0)
		for k := range met.EventWarehouse.state.state {
			keys = append(keys, k)
		}
		buffers := &bytes.Buffer{}
		encoder := gob.NewEncoder(buffers)
		if err := encoder.Encode(keys); err != nil {
			res.Code = pbtypes.CodeType_InternalError
			res.Log = err.Error()
		} else {
			res.Code = pbtypes.CodeType_OK
			res.Data = buffers.Bytes()
		}
	case QueryNonce:
		var pubkey crypto.PubKeyEd25519
		copy(pubkey[:], query[1:])
		nonce := met.accState.QueryNonce(&pubkey)
		res.Code = pbtypes.CodeType_OK
		res.Data = make([]byte, 8)
		binary.LittleEndian.PutUint64(res.Data, nonce)
	case QueryBalance:
		var pubkey crypto.PubKeyEd25519
		copy(pubkey[:], query[1:])
		balance := met.accState.QueryBalance(&pubkey)
		res.Code = pbtypes.CodeType_OK
		res.Data = []byte(balance.String())
	case QueryPower:
		var pubkey crypto.PubKeyEd25519
		copy(pubkey[:], query[1:])
		power, mHeight := met.powerState.QueryPower(&pubkey)
		bs, err := json.Marshal([]string{power.String(), strconv.Itoa(int(mHeight))})
		if err != nil {
			res.Code = pbtypes.CodeType_InternalError
		} else {
			res.Code = pbtypes.CodeType_OK
			res.Data = bs
		}
	}
	return res
}