func (app *App) doCoinbaseTx(block *agtypes.BlockCache) error {
	var addr ethcmn.Address
	copy(addr[:], block.Header.CoinBase)
	rewards := calculateRewards(uint64(block.Header.Height))
	app.currentEvmState.AddBalance(addr, rewards)
	return nil
}
doCoinbaseTx send block rewards to block maker
package app
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"math/big"
	"github.com/vmihailenco/msgpack"
	agtypes "github.com/annchain/annchain/angine/types"
	cmn "github.com/annchain/annchain/module/lib/go-common"
	crypto "github.com/annchain/annchain/module/lib/go-crypto"
	"github.com/annchain/annchain/module/lib/go-merkle"
	"github.com/annchain/annchain/module/xlib/def"
	"github.com/annchain/annchain/tools"
	"github.com/annchain/annchain/types"
	ethcmn "github.com/annchain/anth/common"
	"github.com/annchain/anth/core"
	ethtypes "github.com/annchain/anth/core/types"
	"github.com/annchain/anth/params"
	"go.uber.org/zap"
)
const (
	WorldRandPrefix = "world-rand-"
)
func (app *App) RegisterValidators(validatorset *agtypes.ValidatorSet) {
	for _, validator := range validatorset.Validators {
		if pub, ok := validator.GetPubKey().(*crypto.PubKeyEd25519); ok {
			app.currentShareState.AddGuaranty(pub, new(big.Int).SetUint64(uint64(validator.VotingPower)), 1)
		}
	}
}
func (app *App) ValSetLoader() agtypes.ValSetLoaderFunc {
	election := app.Config.GetInt64("election")
	return func(height, round def.INT) *agtypes.ValidatorSet {
		if height%election > 0 {
			return nil
		}
		worldRand, err := app.getWorldRand(uint64(height))
		if err != nil {
			return nil
		}
		fmt.Printf("======= Finally we got world rand : %x\n", worldRand)
		vals := app.doElect(new(big.Int).SetBytes(worldRand), height, round)
		return agtypes.NewValidatorSet(vals)
	}
}
func (app *App) getWorldRand(height uint64) ([]byte, error) {
	var votes []types.WorldRandVote
	begin, _, _ := app.calElectionTerm(height)
	key := makeWorldRandKey(begin)
	value := app.Database.Get(key)
	if len(value) > 0 {
		if err := msgpack.Unmarshal(value, &votes); err != nil {
			app.logger.Error("Unmarshal globalrand votes failed", zap.Error(err))
			return nil, err
		}
	}
	fmt.Printf("======= We got %d votes for height %d\n", len(votes), begin)
	votesAmt := app.Config.GetInt("worldrand_votes_amount")
	bs := make([][]byte, votesAmt)
	for i := 0; i < votesAmt && i < len(votes); i++ {
		bs[i] = votes[i].Sig
	}
	worldRand := merkle.SimpleHashFromHashes(bs)
	return worldRand, nil
}
func (app *App) doElect(bigbang *big.Int, height, round def.INT) []*agtypes.Validator {
	shrs := make([]*Share, 0, 15)
	exists := make(map[*Share]struct{})
	accList := make([]*Share, 0, app.ShareState.Size())
	accHeap := cmn.NewHeap()  
	luckyThreshold := app.Config.GetInt64("elect_threshold_lucky")
	app.ShareState.Iterate(func(shr *Share) bool {
		if shr.GHeight == 0 || shr.ShareGuaranty.Cmp(big0) == 0 {  
			return false
		}
		if shr.ShareGuaranty.Cmp(big.NewInt(luckyThreshold)) < 0 {  
			return false
		}
		newShr := shr.Copy()
		accList = append(accList, newShr)
		accHeap.Push(newShr, newShr)
		if accHeap.Len() > 32 {
			accHeap.Pop()
		}
		return false
	})
	richThreshold := app.Config.GetInt64("elect_threshold_rich")
	richGuys := make([]*Share, 0, accHeap.Len())
	for accHeap.Len() > 0 {
		shr := accHeap.Pop().(*Share)
		if shr.ShareGuaranty.Cmp(big.NewInt(richThreshold)) >= 0 {  
			richGuys = append(richGuys, shr)
		}
	}
	pickedRichGuys, err := pickAccounts(richGuys, exists, 11, bigbang)
	if err != nil {
		fmt.Println("error in pickAccounts:", err.Error())
		return nil
	}
	shrs = append(shrs, pickedRichGuys...)
	for i := 0; i < len(richGuys); i++ {
		exists[richGuys[i]] = struct{}{}
	}
	numLuckyGuys := len(accList) - len(pickedRichGuys)
	if numLuckyGuys < 0 {
		numLuckyGuys = 0
	} else if numLuckyGuys > 4 {
		numLuckyGuys = 4
	}
	luckyguys, err := pickAccounts(accList, exists, numLuckyGuys, bigbang)
	if err != nil {
		fmt.Println("error in pickAccounts:", err.Error())
		return nil
	}
	shrs = append(shrs, luckyguys...)
	vals := make([]*agtypes.Validator, len(shrs))
	for i, v := range shrs {
		var pk crypto.PubKeyEd25519
		copy(pk[:], v.Pubkey)
		vals[i] = &agtypes.Validator{
			PubKey:      crypto.StPubKey{PubKey: &pk},
			Address:     pk.Address(),
			VotingPower: v.ShareGuaranty.Int64(),
		}
	}
	return vals
}
func pickAccounts(froms []*Share, exists map[*Share]struct{}, maxPick int, bigbang *big.Int) ([]*Share, error) {
	if maxPick == 0 {
		return make([]*Share, 0), nil
	}
	if len(froms) <= maxPick {
		for i := 0; i < len(froms); i++ {
			exists[froms[i]] = struct{}{}
		}
		return froms, nil
	}
	guys := make([]*Share, 0, maxPick)
	for len(guys) < maxPick {
		guy, err := randomSelect(froms, exists, bigbang)
		if err != nil {
			fmt.Println("error in randomSelect:", err.Error())
			return nil, nil
		}
		guys = append(guys, guy)
		exists[guy] = struct{}{}
	}
	return guys, nil
}
func randomSelect(accs []*Share, exists map[*Share]struct{}, bigbang *big.Int) (*Share, error) {
	if len(accs) == len(exists) {
		return nil, fmt.Errorf("No account can be picked any more")
	}
	type shareVotes struct {
		ref        *Share
		votesBegin *big.Int
		votesEnd   *big.Int
	}
	totalShare := new(big.Int)
	votes := make([]shareVotes, 0, len(accs))
	for i := 0; i < len(accs); i++ {
		if _, yes := exists[accs[i]]; !yes {
			votes = append(votes, shareVotes{
				ref:        accs[i],
				votesBegin: new(big.Int).Set(totalShare),
				votesEnd:   new(big.Int).Add(totalShare, accs[i].ShareGuaranty),
			})
			totalShare.Add(totalShare, accs[i].ShareGuaranty)
		}
	}
	lottery := new(big.Int).Mod(bigbang, totalShare)
	for i := 0; i < len(votes); i++ {
		if lottery.Cmp(votes[i].votesEnd) < 0 {
			return votes[i].ref, nil
		}
	}
	fmt.Println("Should never happen")
	return nil, nil
}
func (app *App) calElectionTerm(height uint64) (begin, end, mid uint64) {
	electionSpan := uint64(app.Config.GetInt64("election"))
	worldRandThreshold := app.Config.GetFloat64("worldrand_threshold")
	if height%electionSpan == 0 {
		height = height - 1
	}
	begin = height - (height % electionSpan) + 1
	end = begin + electionSpan - 1
	mid = begin + uint64(float64(electionSpan)*worldRandThreshold)
	return
}
func (app *App) prepareGlobalRand(height, round uint64) {
	privkey := app.AngineRef.PrivValidator().GetPrivKey()
	pubkey := app.AngineRef.PrivValidator().GetPubKey()
	begin, end, mid := app.calElectionTerm(uint64(height))
	if height < mid || height > end || round > 1 {
		return
	}
	if !app.AngineRef.IsNodeValidator(pubkey) {
		return
	}
	fr := crypto.Sha256(privkey.Bytes())
	frv := new(big.Int).SetBytes(fr)
	frv = frv.Add(frv, new(big.Int).SetUint64((begin+1)*17))
	target := mid + frv.Mod(frv, big.NewInt(int64(end-mid-1))).Uint64()
	if target != height {
		return
	}
	blockMeta, err := app.AngineRef.GetBlockMeta(int64(begin))
	if err != nil {
		app.logger.Error("GetBlockMeta failed:", zap.Error(err))
		return
	}
	sig := privkey.Sign(blockMeta.GetHash())
	tx := &types.WorldRandTx{
		Height: begin,
		Pubkey: pubkey.Bytes(),
		Sig:    sig.Bytes(),
	}
	txBytes, err := tools.ToBytes(tx)
	if err != nil {
		app.logger.Error("ToBytes failed:", zap.Error(err))
		return
	}
	b := agtypes.WrapTx(types.TxTagAngineWorldRand, txBytes)
	app.AngineRef.BroadcastTx(b)
}
func (app *App) CheckEcoTx(bs []byte) error {
	return nil
}