github.com/nnlgsakib/mind-dpos@v0.0.0-20230606105614-f3c8ca06f808/consensus/alien/snapshot.go (about)

     1  // Copyright 2018 The gttc Authors
     2  // This file is part of the gttc library.
     3  //
     4  // The gttc library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The gttc library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the gttc library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package alien implements the delegated-proof-of-stake consensus engine.
    18  
    19  package alien
    20  
    21  import (
    22  	"encoding/json"
    23  	"errors"
    24  	"github.com/TTCECO/gttc/common"
    25  	"github.com/TTCECO/gttc/core/types"
    26  	"github.com/TTCECO/gttc/ethdb"
    27  	"github.com/TTCECO/gttc/params"
    28  	"github.com/hashicorp/golang-lru"
    29  	"math/big"
    30  	"sort"
    31  	"strings"
    32  	"time"
    33  )
    34  
    35  const (
    36  	defaultFullCredit               = 28800 // no punished
    37  	missingPublishCredit            = 100   // punished for missing one block seal
    38  	signRewardCredit                = 10    // seal one block
    39  	autoRewardCredit                = 1     // credit auto recover for each block
    40  	minCalSignerQueueCredit         = 10000 // when calculate the signerQueue
    41  	defaultOfficialMaxSignerCount   = 21    // official max signer count
    42  	defaultOfficialFirstLevelCount  = 10    // official first level , 100% in signer queue
    43  	defaultOfficialSecondLevelCount = 20    // official second level, 60% in signer queue
    44  	defaultOfficialThirdLevelCount  = 30    // official third level, 40% in signer queue
    45  	defaultOfficialMaxValidCount    = 50    // official max valid candidate count, sort by vote
    46  
    47  	maxUncheckBalanceVoteCount = 10000 // not check current balance when calculate expired
    48  	// the credit of one signer is at least minCalSignerQueueCredit
    49  	candidateStateNormal = 1
    50  	candidateMaxLen      = 500 // if candidateNeedPD is false and candidate is more than candidateMaxLen, then minimum tickets candidates will be remove in each LCRS*loop
    51  	// reward for side chain
    52  	scRewardDelayLoopCount     = 0                          //
    53  	scRewardExpiredLoopCount   = scRewardDelayLoopCount + 4 //
    54  	scMaxCountPerPeriod        = 6
    55  	scMaxConfirmedRecordLength = defaultOfficialMaxSignerCount * 50 // max record length for each side chain
    56  	// proposal refund
    57  	proposalRefundDelayLoopCount   = 0
    58  	proposalRefundExpiredLoopCount = proposalRefundDelayLoopCount + 2
    59  	// notice
    60  	mcNoticeClearDelayLoopCount = 4 // this count can be hundreds times
    61  	scNoticeClearDelayLoopCount = mcNoticeClearDelayLoopCount * scMaxCountPerPeriod * 2
    62  	scGasChargingDelayLoopCount = 1 // 1 is always enough
    63  	// bug fix
    64  	bugFixBlockNumber = 14456164   // fix bug for header
    65  )
    66  
    67  var (
    68  	errIncorrectTallyCount = errors.New("incorrect tally count")
    69  	errAllStakeMissing     = errors.New("all stake for this signer is zero")
    70  )
    71  
    72  // SCCurrentBlockReward is base on scMaxCountPerPeriod = 6
    73  var SCCurrentBlockReward = map[uint64]map[uint64]uint64{1: {1: 100},
    74  	2: {1: 30, 2: 70},
    75  	3: {1: 15, 2: 30, 3: 55},
    76  	4: {1: 5, 2: 15, 3: 30, 4: 50},
    77  	5: {1: 5, 2: 10, 3: 15, 4: 25, 5: 45},
    78  	6: {1: 1, 2: 4, 3: 10, 4: 15, 5: 25, 6: 45}}
    79  
    80  // Score to calculate at one main chain block, for calculate the side chain reward
    81  type SCBlockReward struct {
    82  	RewardScoreMap map[common.Address]uint64 //sum(this value) in one period == 100
    83  }
    84  
    85  // Record for one side chain
    86  type SCReward struct {
    87  	SCBlockRewardMap map[uint64]*SCBlockReward
    88  }
    89  
    90  type SCRentInfo struct {
    91  	RentPerPeriod   *big.Int `json:"rentPerPeriod"`
    92  	MaxRewardNumber *big.Int `json:"maxRewardNumber"`
    93  }
    94  
    95  // SCRecord is the state record for side chain
    96  type SCRecord struct {
    97  	Record              map[uint64][]*SCConfirmation `json:"record"`              // Confirmation Record of one side chain
    98  	LastConfirmedNumber uint64                       `json:"lastConfirmedNumber"` // Last confirmed header number of one side chain
    99  	MaxHeaderNumber     uint64                       `json:"maxHeaderNumber"`     // max header number of one side chain
   100  	CountPerPeriod      uint64                       `json:"countPerPeriod"`      // block sealed per period on this side chain
   101  	RewardPerPeriod     uint64                       `json:"rewardPerPeriod"`     // full reward per period, number per thousand
   102  	RentReward          map[common.Hash]*SCRentInfo  `json:"rentReward"`          // reward info by rent
   103  }
   104  
   105  type NoticeCR struct {
   106  	NRecord map[common.Address]bool `json:"noticeConfirmRecord"`
   107  	Number  uint64                  `json:"firstReceivedNumber"` // this number will fill when there are more than 2/3+1 maxSignerCnt
   108  	Type    uint64                  `json:"noticeType"`
   109  	Success bool                    `json:"success"`
   110  }
   111  
   112  // CCNotice (cross chain notice) contain the information main chain need to notify given side chain
   113  //
   114  type CCNotice struct {
   115  	CurrentCharging map[common.Hash]GasCharging `json:"currentCharging"` // common.Hash here is the proposal txHash not the hash of side chain
   116  	ConfirmReceived map[common.Hash]NoticeCR    `json:"confirmReceived"` // record the confirm address
   117  }
   118  
   119  // Snapshot is the state of the authorization voting at a given point in time.
   120  type Snapshot struct {
   121  	config   *params.AlienConfig // Consensus engine parameters to fine tune behavior
   122  	sigcache *lru.ARCCache       // Cache of recent block signatures to speed up ecrecover
   123  	LCRS     uint64              // Loop count to recreate signers from top tally
   124  
   125  	Period          uint64                                            `json:"period"`            // Period of seal each block
   126  	Number          uint64                                            `json:"number"`            // Block number where the snapshot was created
   127  	ConfirmedNumber uint64                                            `json:"confirmedNumber"`   // Block number confirmed when the snapshot was created
   128  	Hash            common.Hash                                       `json:"hash"`              // Block hash where the snapshot was created
   129  	HistoryHash     []common.Hash                                     `json:"historyHash"`       // Block hash list for two recent loop
   130  	Signers         []*common.Address                                 `json:"signers"`           // Signers queue in current header
   131  	Votes           map[common.Address]*Vote                          `json:"votes"`             // All validate votes from genesis block
   132  	Tally           map[common.Address]*big.Int                       `json:"tally"`             // Stake for each candidate address
   133  	Voters          map[common.Address]*big.Int                       `json:"voters"`            // Block number for each voter address
   134  	Candidates      map[common.Address]uint64                         `json:"candidates"`        // Candidates for Signers (0- adding procedure 1- normal 2- removing procedure)
   135  	Punished        map[common.Address]uint64                         `json:"punished"`          // The signer be punished count cause of missing seal
   136  	Confirmations   map[uint64][]*common.Address                      `json:"confirms"`          // The signer confirm given block number
   137  	Proposals       map[common.Hash]*Proposal                         `json:"proposals"`         // The Proposals going or success (failed proposal will be removed)
   138  	HeaderTime      uint64                                            `json:"headerTime"`        // Time of the current header
   139  	LoopStartTime   uint64                                            `json:"loopStartTime"`     // Start Time of the current loop
   140  	ProposalRefund  map[uint64]map[common.Address]*big.Int            `json:"proposalRefund"`    // Refund proposal deposit
   141  	SCCoinbase      map[common.Address]map[common.Hash]common.Address `json:"sideChainCoinbase"` // main chain set Coinbase of side chain setting
   142  	SCRecordMap     map[common.Hash]*SCRecord                         `json:"sideChainRecord"`   // main chain record Confirmation of side chain setting
   143  	SCRewardMap     map[common.Hash]*SCReward                         `json:"sideChainReward"`   // main chain record Side Chain Reward
   144  	SCNoticeMap     map[common.Hash]*CCNotice                         `json:"sideChainNotice"`   // main chain record Notification to side chain
   145  	LocalNotice     *CCNotice                                         `json:"localNotice"`       // side chain record Notification
   146  	MinerReward     uint64                                            `json:"minerReward"`       // miner reward per thousand
   147  	MinVB           *big.Int                                          `json:"minVoterBalance"`   // min voter balance
   148  }
   149  
   150  // newSnapshot creates a new snapshot with the specified startup parameters. only ever use if for
   151  // the genesis block.
   152  func newSnapshot(config *params.AlienConfig, sigcache *lru.ARCCache, hash common.Hash, votes []*Vote, lcrs uint64) *Snapshot {
   153  
   154  	snap := &Snapshot{
   155  		config:          config,
   156  		sigcache:        sigcache,
   157  		LCRS:            lcrs,
   158  		Period:          config.Period,
   159  		Number:          0,
   160  		ConfirmedNumber: 0,
   161  		Hash:            hash,
   162  		HistoryHash:     []common.Hash{},
   163  		Signers:         []*common.Address{},
   164  		Votes:           make(map[common.Address]*Vote),
   165  		Tally:           make(map[common.Address]*big.Int),
   166  		Voters:          make(map[common.Address]*big.Int),
   167  		Punished:        make(map[common.Address]uint64),
   168  		Candidates:      make(map[common.Address]uint64),
   169  		Confirmations:   make(map[uint64][]*common.Address),
   170  		Proposals:       make(map[common.Hash]*Proposal),
   171  		HeaderTime:      uint64(time.Now().Unix()) - 1,
   172  		LoopStartTime:   config.GenesisTimestamp,
   173  		SCCoinbase:      make(map[common.Address]map[common.Hash]common.Address),
   174  		SCRecordMap:     make(map[common.Hash]*SCRecord),
   175  		SCRewardMap:     make(map[common.Hash]*SCReward),
   176  		SCNoticeMap:     make(map[common.Hash]*CCNotice),
   177  		LocalNotice:     &CCNotice{CurrentCharging: make(map[common.Hash]GasCharging), ConfirmReceived: make(map[common.Hash]NoticeCR)},
   178  		ProposalRefund:  make(map[uint64]map[common.Address]*big.Int),
   179  		MinerReward:     minerRewardPerThousand,
   180  		MinVB:           config.MinVoterBalance,
   181  	}
   182  	snap.HistoryHash = append(snap.HistoryHash, hash)
   183  
   184  	for _, vote := range votes {
   185  		// init Votes from each vote
   186  		snap.Votes[vote.Voter] = vote
   187  		// init Tally
   188  		_, ok := snap.Tally[vote.Candidate]
   189  		if !ok {
   190  			snap.Tally[vote.Candidate] = big.NewInt(0)
   191  		}
   192  		snap.Tally[vote.Candidate].Add(snap.Tally[vote.Candidate], vote.Stake)
   193  		// init Voters
   194  		snap.Voters[vote.Voter] = big.NewInt(0) // block number is 0 , vote in genesis block
   195  		// init Candidates
   196  		snap.Candidates[vote.Voter] = candidateStateNormal
   197  	}
   198  
   199  	if len(config.SelfVoteSigners) > 0 {
   200  		var prefixSelfVoteSigners []common.Address
   201  		for _, unPrefixSelfVoteSigners := range config.SelfVoteSigners {
   202  			prefixSelfVoteSigners = append(prefixSelfVoteSigners, common.Address(unPrefixSelfVoteSigners))
   203  		}
   204  		for i := 0; i < int(config.MaxSignerCount); i++ {
   205  			snap.Signers = append(snap.Signers, &prefixSelfVoteSigners[i%len(prefixSelfVoteSigners)])
   206  		}
   207  	}
   208  
   209  	return snap
   210  }
   211  
   212  // loadSnapshot loads an existing snapshot from the database.
   213  func loadSnapshot(config *params.AlienConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
   214  	blob, err := db.Get(append([]byte("alien-"), hash[:]...))
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	snap := new(Snapshot)
   219  	if err := json.Unmarshal(blob, snap); err != nil {
   220  		return nil, err
   221  	}
   222  	snap.config = config
   223  	snap.sigcache = sigcache
   224  
   225  	// miner reward per thousand proposal must larger than 0
   226  	// so minerReward is zeron only when update the program
   227  	if snap.MinerReward == 0 {
   228  		snap.MinerReward = minerRewardPerThousand
   229  	}
   230  	if snap.MinVB == nil {
   231  		snap.MinVB = new(big.Int).Set(minVoterBalance)
   232  	}
   233  	return snap, nil
   234  }
   235  
   236  // store inserts the snapshot into the database.
   237  func (s *Snapshot) store(db ethdb.Database) error {
   238  	blob, err := json.Marshal(s)
   239  	if err != nil {
   240  		return err
   241  	}
   242  	return db.Put(append([]byte("alien-"), s.Hash[:]...), blob)
   243  }
   244  
   245  // copy creates a deep copy of the snapshot, though not the individual votes.
   246  func (s *Snapshot) copy() *Snapshot {
   247  	cpy := &Snapshot{
   248  		config:          s.config,
   249  		sigcache:        s.sigcache,
   250  		LCRS:            s.LCRS,
   251  		Period:          s.Period,
   252  		Number:          s.Number,
   253  		ConfirmedNumber: s.ConfirmedNumber,
   254  		Hash:            s.Hash,
   255  		HistoryHash:     make([]common.Hash, len(s.HistoryHash)),
   256  
   257  		Signers:       make([]*common.Address, len(s.Signers)),
   258  		Votes:         make(map[common.Address]*Vote),
   259  		Tally:         make(map[common.Address]*big.Int),
   260  		Voters:        make(map[common.Address]*big.Int),
   261  		Candidates:    make(map[common.Address]uint64),
   262  		Punished:      make(map[common.Address]uint64),
   263  		Proposals:     make(map[common.Hash]*Proposal),
   264  		Confirmations: make(map[uint64][]*common.Address),
   265  
   266  		HeaderTime:     s.HeaderTime,
   267  		LoopStartTime:  s.LoopStartTime,
   268  		SCCoinbase:     make(map[common.Address]map[common.Hash]common.Address),
   269  		SCRecordMap:    make(map[common.Hash]*SCRecord),
   270  		SCRewardMap:    make(map[common.Hash]*SCReward),
   271  		SCNoticeMap:    make(map[common.Hash]*CCNotice),
   272  		LocalNotice:    &CCNotice{CurrentCharging: make(map[common.Hash]GasCharging), ConfirmReceived: make(map[common.Hash]NoticeCR)},
   273  		ProposalRefund: make(map[uint64]map[common.Address]*big.Int),
   274  
   275  		MinerReward: s.MinerReward,
   276  		MinVB:       nil,
   277  	}
   278  	copy(cpy.HistoryHash, s.HistoryHash)
   279  	copy(cpy.Signers, s.Signers)
   280  	for voter, vote := range s.Votes {
   281  		cpy.Votes[voter] = &Vote{
   282  			Voter:     vote.Voter,
   283  			Candidate: vote.Candidate,
   284  			Stake:     new(big.Int).Set(vote.Stake),
   285  		}
   286  	}
   287  	for candidate, tally := range s.Tally {
   288  		cpy.Tally[candidate] = new(big.Int).Set(tally)
   289  	}
   290  	for voter, number := range s.Voters {
   291  		cpy.Voters[voter] = new(big.Int).Set(number)
   292  	}
   293  	for candidate, state := range s.Candidates {
   294  		cpy.Candidates[candidate] = state
   295  	}
   296  	for signer, cnt := range s.Punished {
   297  		cpy.Punished[signer] = cnt
   298  	}
   299  	for blockNumber, confirmers := range s.Confirmations {
   300  		cpy.Confirmations[blockNumber] = make([]*common.Address, len(confirmers))
   301  		copy(cpy.Confirmations[blockNumber], confirmers)
   302  	}
   303  	for txHash, proposal := range s.Proposals {
   304  		cpy.Proposals[txHash] = proposal.copy()
   305  	}
   306  	for signer, sc := range s.SCCoinbase {
   307  		cpy.SCCoinbase[signer] = make(map[common.Hash]common.Address)
   308  		for hash, addr := range sc {
   309  			cpy.SCCoinbase[signer][hash] = addr
   310  		}
   311  	}
   312  	for hash, scc := range s.SCRecordMap {
   313  		cpy.SCRecordMap[hash] = &SCRecord{
   314  			LastConfirmedNumber: scc.LastConfirmedNumber,
   315  			MaxHeaderNumber:     scc.MaxHeaderNumber,
   316  			CountPerPeriod:      scc.CountPerPeriod,
   317  			RewardPerPeriod:     scc.RewardPerPeriod,
   318  			Record:              make(map[uint64][]*SCConfirmation),
   319  			RentReward:          make(map[common.Hash]*SCRentInfo),
   320  		}
   321  		for number, scConfirmation := range scc.Record {
   322  			cpy.SCRecordMap[hash].Record[number] = make([]*SCConfirmation, len(scConfirmation))
   323  			copy(cpy.SCRecordMap[hash].Record[number], scConfirmation)
   324  		}
   325  		for rentHash, scRentInfo := range scc.RentReward {
   326  			cpy.SCRecordMap[hash].RentReward[rentHash] = &SCRentInfo{new(big.Int).Set(scRentInfo.RentPerPeriod), new(big.Int).Set(scRentInfo.MaxRewardNumber)}
   327  		}
   328  	}
   329  
   330  	for hash, sca := range s.SCRewardMap {
   331  		cpy.SCRewardMap[hash] = &SCReward{
   332  			SCBlockRewardMap: make(map[uint64]*SCBlockReward),
   333  		}
   334  		for number, blockReward := range sca.SCBlockRewardMap {
   335  			cpy.SCRewardMap[hash].SCBlockRewardMap[number] = &SCBlockReward{
   336  				RewardScoreMap: make(map[common.Address]uint64),
   337  			}
   338  			for addr, score := range blockReward.RewardScoreMap {
   339  				cpy.SCRewardMap[hash].SCBlockRewardMap[number].RewardScoreMap[addr] = score
   340  			}
   341  		}
   342  	}
   343  
   344  	for hash, scn := range s.SCNoticeMap {
   345  		cpy.SCNoticeMap[hash] = &CCNotice{
   346  			CurrentCharging: make(map[common.Hash]GasCharging),
   347  			ConfirmReceived: make(map[common.Hash]NoticeCR),
   348  		}
   349  		for txHash, charge := range scn.CurrentCharging {
   350  			cpy.SCNoticeMap[hash].CurrentCharging[txHash] = GasCharging{charge.Target, charge.Volume, charge.Hash}
   351  		}
   352  		for txHash, confirm := range scn.ConfirmReceived {
   353  			cpy.SCNoticeMap[hash].ConfirmReceived[txHash] = NoticeCR{make(map[common.Address]bool), confirm.Number, confirm.Type, confirm.Success}
   354  			for addr, b := range confirm.NRecord {
   355  				cpy.SCNoticeMap[hash].ConfirmReceived[txHash].NRecord[addr] = b
   356  			}
   357  		}
   358  	}
   359  
   360  	for txHash, charge := range s.LocalNotice.CurrentCharging {
   361  		cpy.LocalNotice.CurrentCharging[txHash] = GasCharging{charge.Target, charge.Volume, charge.Hash}
   362  	}
   363  	for txHash, confirm := range s.LocalNotice.ConfirmReceived {
   364  		cpy.LocalNotice.ConfirmReceived[txHash] = NoticeCR{make(map[common.Address]bool), confirm.Number, confirm.Type, confirm.Success}
   365  		for addr, b := range confirm.NRecord {
   366  			cpy.LocalNotice.ConfirmReceived[txHash].NRecord[addr] = b
   367  		}
   368  	}
   369  
   370  	for number, refund := range s.ProposalRefund {
   371  		cpy.ProposalRefund[number] = make(map[common.Address]*big.Int)
   372  		for proposer, deposit := range refund {
   373  			cpy.ProposalRefund[number][proposer] = new(big.Int).Set(deposit)
   374  		}
   375  	}
   376  	// miner reward per thousand proposal must larger than 0
   377  	// so minerReward is zeron only when update the program
   378  	if s.MinerReward == 0 {
   379  		cpy.MinerReward = minerRewardPerThousand
   380  	}
   381  	if s.MinVB == nil {
   382  		cpy.MinVB = new(big.Int).Set(minVoterBalance)
   383  	} else {
   384  		cpy.MinVB = new(big.Int).Set(s.MinVB)
   385  	}
   386  
   387  	return cpy
   388  }
   389  
   390  // apply creates a new authorization snapshot by applying the given headers to
   391  // the original one.
   392  func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
   393  	// Allow passing in no headers for cleaner code
   394  	if len(headers) == 0 {
   395  		return s, nil
   396  	}
   397  	// Sanity check that the headers can be applied
   398  	for i := 0; i < len(headers)-1; i++ {
   399  		if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 {
   400  			return nil, errInvalidVotingChain
   401  		}
   402  	}
   403  	if headers[0].Number.Uint64() != s.Number+1 {
   404  		return nil, errInvalidVotingChain
   405  	}
   406  	// Iterate through the headers and create a new snapshot
   407  	snap := s.copy()
   408  
   409  	for _, header := range headers {
   410  		// Resolve the authorization key and check against signers
   411  		coinbase, err := ecrecover(header, s.sigcache)
   412  		if err != nil {
   413  			return nil, err
   414  		}
   415  		if coinbase.Str() != header.Coinbase.Str() && header.Number.Cmp(big.NewInt(bugFixBlockNumber)) != 0{
   416  			return nil, errUnauthorized
   417  		}
   418  
   419  		headerExtra := HeaderExtra{}
   420  		err = decodeHeaderExtra(s.config, header.Number, header.Extra[extraVanity:len(header.Extra)-extraSeal], &headerExtra)
   421  		if err != nil {
   422  			return nil, err
   423  		}
   424  		snap.HeaderTime = header.Time.Uint64()
   425  		snap.LoopStartTime = headerExtra.LoopStartTime
   426  		snap.Signers = nil
   427  		for i := range headerExtra.SignerQueue {
   428  			snap.Signers = append(snap.Signers, &headerExtra.SignerQueue[i])
   429  		}
   430  
   431  		snap.ConfirmedNumber = headerExtra.ConfirmedBlockNumber
   432  
   433  		if len(snap.HistoryHash) >= int(s.config.MaxSignerCount)*2 {
   434  			snap.HistoryHash = snap.HistoryHash[1 : int(s.config.MaxSignerCount)*2]
   435  		}
   436  		snap.HistoryHash = append(snap.HistoryHash, header.Hash())
   437  
   438  		// deal the new confirmation in this block
   439  		snap.updateSnapshotByConfirmations(headerExtra.CurrentBlockConfirmations)
   440  
   441  		// deal the new vote from voter
   442  		snap.updateSnapshotByVotes(headerExtra.CurrentBlockVotes, header.Number)
   443  
   444  		// deal the voter which balance modified
   445  		snap.updateSnapshotByMPVotes(headerExtra.ModifyPredecessorVotes)
   446  
   447  		// deal the snap related with punished
   448  		snap.updateSnapshotForPunish(headerExtra.SignerMissing, header.Number, header.Coinbase)
   449  
   450  		// deal proposals
   451  		snap.updateSnapshotByProposals(headerExtra.CurrentBlockProposals, header.Number)
   452  
   453  		// deal declares
   454  		snap.updateSnapshotByDeclares(headerExtra.CurrentBlockDeclares, header.Number)
   455  
   456  		// deal trantor upgrade
   457  		if snap.Period == 0 {
   458  			snap.Period = snap.config.Period
   459  		}
   460  
   461  		// deal setcoinbase for side chain
   462  		snap.updateSnapshotBySetSCCoinbase(headerExtra.SideChainSetCoinbases)
   463  
   464  		// deal confirmation for side chain
   465  		snap.updateSnapshotBySCConfirm(headerExtra.SideChainConfirmations, header.Number)
   466  
   467  		// deal notice confirmation
   468  		snap.updateSnapshotByNoticeConfirm(headerExtra.SideChainNoticeConfirmed, header.Number)
   469  
   470  		// calculate proposal result
   471  		snap.calculateProposalResult(header.Number)
   472  
   473  		// check the len of candidate if not candidateNeedPD
   474  		if !candidateNeedPD && (snap.Number+1)%(snap.config.MaxSignerCount*snap.LCRS) == 0 && len(snap.Candidates) > candidateMaxLen {
   475  			snap.removeExtraCandidate()
   476  		}
   477  
   478  		/*
   479  		 * follow methods only work on side chain !!!! not like above method
   480  		 */
   481  
   482  		// deal the notice from main chain
   483  		snap.updateSnapshotBySCCharging(headerExtra.SideChainCharging, header.Number, header.Coinbase)
   484  
   485  		snap.updateSnapshotForExpired(header.Number)
   486  	}
   487  	snap.Number += uint64(len(headers))
   488  	snap.Hash = headers[len(headers)-1].Hash()
   489  
   490  	err := snap.verifyTallyCnt()
   491  	if err != nil {
   492  		return nil, err
   493  	}
   494  	return snap, nil
   495  }
   496  
   497  func (s *Snapshot) removeExtraCandidate() {
   498  	// remove minimum tickets tally beyond candidateMaxLen
   499  	tallySlice := s.buildTallySlice()
   500  	sort.Sort(TallySlice(tallySlice))
   501  	if len(tallySlice) > candidateMaxLen {
   502  		removeNeedTally := tallySlice[candidateMaxLen:]
   503  		for _, tallySlice := range removeNeedTally {
   504  			if _, ok := s.SCCoinbase[tallySlice.addr]; ok {
   505  				delete(s.SCCoinbase, tallySlice.addr)
   506  			}
   507  			delete(s.Candidates, tallySlice.addr)
   508  		}
   509  	}
   510  }
   511  
   512  func (s *Snapshot) verifyTallyCnt() error {
   513  
   514  	tallyTarget := make(map[common.Address]*big.Int)
   515  	for _, v := range s.Votes {
   516  		if _, ok := tallyTarget[v.Candidate]; ok {
   517  			tallyTarget[v.Candidate].Add(tallyTarget[v.Candidate], v.Stake)
   518  		} else {
   519  			tallyTarget[v.Candidate] = new(big.Int).Set(v.Stake)
   520  		}
   521  	}
   522  
   523  	for address, tally := range s.Tally {
   524  		if targetTally, ok := tallyTarget[address]; ok && targetTally.Cmp(tally) == 0 {
   525  			continue
   526  		} else {
   527  			return errIncorrectTallyCount
   528  		}
   529  	}
   530  
   531  	return nil
   532  }
   533  
   534  func (s *Snapshot) updateSnapshotBySetSCCoinbase(scCoinbases []SCSetCoinbase) {
   535  	for _, scc := range scCoinbases {
   536  		if _, ok := s.SCCoinbase[scc.Signer]; !ok {
   537  			s.SCCoinbase[scc.Signer] = make(map[common.Hash]common.Address)
   538  		}
   539  		s.SCCoinbase[scc.Signer][scc.Hash] = scc.Coinbase
   540  	}
   541  }
   542  
   543  func (s *Snapshot) isSideChainCoinbase(sc common.Hash, address common.Address, realtime bool) bool {
   544  	// check is side chain coinbase
   545  	// is use the coinbase of main chain as coinbase of side chain , return false
   546  	// the main chain cloud seal block, but not recommend for send confirm tx usually fail
   547  	if realtime {
   548  		for _, signer := range s.Signers {
   549  			if _, ok := s.SCCoinbase[*signer]; ok {
   550  				if coinbase, ok := s.SCCoinbase[*signer][sc]; ok && coinbase == address {
   551  					return true
   552  				}
   553  			}
   554  		}
   555  	} else {
   556  		for _, coinbaseMap := range s.SCCoinbase {
   557  			if coinbase, ok := coinbaseMap[sc]; ok && coinbase == address {
   558  				return true
   559  			}
   560  		}
   561  
   562  	}
   563  	return false
   564  }
   565  
   566  func (s *Snapshot) updateSnapshotBySCConfirm(scConfirmations []SCConfirmation, headerNumber *big.Int) {
   567  	// todo ,if diff side chain coinbase send confirm for the same side chain , same number ...
   568  	for _, scc := range scConfirmations {
   569  		// new confirmation header number must larger than last confirmed number of this side chain
   570  		if s.isSideChainCoinbase(scc.Hash, scc.Coinbase, false) {
   571  			if _, ok := s.SCRecordMap[scc.Hash]; ok && scc.Number > s.SCRecordMap[scc.Hash].LastConfirmedNumber {
   572  				s.SCRecordMap[scc.Hash].Record[scc.Number] = append(s.SCRecordMap[scc.Hash].Record[scc.Number], scc.copy())
   573  				if scc.Number > s.SCRecordMap[scc.Hash].MaxHeaderNumber {
   574  					s.SCRecordMap[scc.Hash].MaxHeaderNumber = scc.Number
   575  				}
   576  			}
   577  		}
   578  	}
   579  	// calculate the side chain reward in each loop
   580  	if (headerNumber.Uint64()+1)%s.config.MaxSignerCount == 0 {
   581  		s.checkSCConfirmation(headerNumber)
   582  		s.updateSCConfirmation(headerNumber)
   583  	}
   584  }
   585  
   586  func (s *Snapshot) updateSnapshotByNoticeConfirm(scNoticeConfirmed []SCConfirmation, headerNumber *big.Int) {
   587  	// record the confirmed info into Notice, and remove notice if there are enough confirm
   588  	// may be receive confirmed more than 2/3+1 and the remove will delay a reasonable loop count (4)
   589  	for _, noticeConfirm := range scNoticeConfirmed {
   590  		// check if the coinbase of this side chain
   591  		// todo check if the current coinbase of this side chain.
   592  		if !s.isSideChainCoinbase(noticeConfirm.Hash, noticeConfirm.Coinbase, true) {
   593  			continue
   594  		}
   595  		// noticeConfirm.Hash is the hash of side chain
   596  		if _, ok := s.SCNoticeMap[noticeConfirm.Hash]; ok {
   597  			for _, strHash := range noticeConfirm.LoopInfo {
   598  				// check the charging current exist
   599  				noticeHash := common.HexToHash(strHash)
   600  				if _, ok := s.SCNoticeMap[noticeConfirm.Hash].CurrentCharging[noticeHash]; ok {
   601  					//noticeType = noticeTypeGasCharging
   602  					if _, ok := s.SCNoticeMap[noticeConfirm.Hash].ConfirmReceived[noticeHash]; !ok {
   603  						s.SCNoticeMap[noticeConfirm.Hash].ConfirmReceived[noticeHash] = NoticeCR{make(map[common.Address]bool), 0, noticeTypeGasCharging, false}
   604  					}
   605  					s.SCNoticeMap[noticeConfirm.Hash].ConfirmReceived[noticeHash].NRecord[noticeConfirm.Coinbase] = true
   606  				}
   607  			}
   608  		}
   609  	}
   610  
   611  	// check notice confirm number
   612  	if (headerNumber.Uint64()+1)%s.config.MaxSignerCount == 0 {
   613  		// todo : check if the enough coinbase is the side chain coinbase which main chain coinbase is in the signers
   614  		// todo : if checked ,then update the number in noticeConfirmed
   615  		// todo : remove the notice , delete(notice,hash) to stop the broadcast to side chain
   616  
   617  		for chainHash, scNotice := range s.SCNoticeMap {
   618  			// check each side chain
   619  			for noticeHash, noticeRecord := range scNotice.ConfirmReceived {
   620  				if len(noticeRecord.NRecord) >= int(2*s.config.MaxSignerCount/3+1) && !noticeRecord.Success {
   621  					s.SCNoticeMap[chainHash].ConfirmReceived[noticeHash] = NoticeCR{noticeRecord.NRecord, headerNumber.Uint64(), noticeRecord.Type, true}
   622  				}
   623  
   624  				if noticeRecord.Success && noticeRecord.Number < headerNumber.Uint64()-s.config.MaxSignerCount*mcNoticeClearDelayLoopCount {
   625  					delete(s.SCNoticeMap[chainHash].CurrentCharging, noticeHash)
   626  					delete(s.SCNoticeMap[chainHash].ConfirmReceived, noticeHash)
   627  				}
   628  			}
   629  		}
   630  	}
   631  
   632  }
   633  
   634  func (s *Snapshot) updateSnapshotBySCCharging(scCharging []GasCharging, headerNumber *big.Int, coinbase common.Address) {
   635  	for _, charge := range scCharging {
   636  		if _, ok := s.LocalNotice.CurrentCharging[charge.Hash]; !ok {
   637  			s.LocalNotice.CurrentCharging[charge.Hash] = GasCharging{charge.Target, charge.Volume, charge.Hash}
   638  			s.LocalNotice.ConfirmReceived[charge.Hash] = NoticeCR{make(map[common.Address]bool), 0, noticeTypeGasCharging, false}
   639  
   640  		}
   641  		s.LocalNotice.ConfirmReceived[charge.Hash].NRecord[coinbase] = true
   642  	}
   643  
   644  	if (headerNumber.Uint64()+1)%s.config.MaxSignerCount == 0 {
   645  		for hash, noticeRecord := range s.LocalNotice.ConfirmReceived {
   646  			if len(noticeRecord.NRecord) >= int(2*s.config.MaxSignerCount/3+1) && !noticeRecord.Success {
   647  				s.LocalNotice.ConfirmReceived[hash] = NoticeCR{noticeRecord.NRecord, headerNumber.Uint64(), noticeTypeGasCharging, true}
   648  				// todo charging the gas fee on set block
   649  
   650  			}
   651  			if noticeRecord.Success && noticeRecord.Number < headerNumber.Uint64()-s.config.MaxSignerCount*scNoticeClearDelayLoopCount {
   652  				delete(s.LocalNotice.CurrentCharging, hash)
   653  				delete(s.LocalNotice.ConfirmReceived, hash)
   654  			}
   655  		}
   656  	}
   657  
   658  }
   659  
   660  func (s *Snapshot) checkSCConfirmation(headerNumber *big.Int) {
   661  	for hash, scRecord := range s.SCRecordMap {
   662  		// check maxRentRewardNumber by headerNumber
   663  		for txHash, scRentInfo := range scRecord.RentReward {
   664  			if scRentInfo.MaxRewardNumber.Uint64() < headerNumber.Uint64()-scRewardExpiredLoopCount*s.config.MaxSignerCount {
   665  				delete(s.SCRecordMap[hash].RentReward, txHash)
   666  			}
   667  		}
   668  
   669  		// if size of confirmed record from one side chain larger than scMaxConfirmedRecordLength
   670  		// we reset the record info of this side chain, good enough for now
   671  		if len(scRecord.Record) > scMaxConfirmedRecordLength {
   672  			s.SCRecordMap[hash].Record = make(map[uint64][]*SCConfirmation)
   673  			s.SCRecordMap[hash].LastConfirmedNumber = 0
   674  			s.SCRecordMap[hash].MaxHeaderNumber = 0
   675  			// the rentReward info will be kept, do not delete
   676  		}
   677  	}
   678  
   679  }
   680  
   681  func (s *Snapshot) calculateSCConfirmedNumber(record *SCRecord, minConfirmedSignerCount int) (uint64, map[uint64]common.Address) {
   682  	// todo : add params scHash, so can check if the address in SCRecord is belong to this side chain
   683  
   684  	confirmedNumber := record.LastConfirmedNumber
   685  	confirmedRecordMap := make(map[string]map[common.Address]bool)
   686  	confirmedCoinbase := make(map[uint64]common.Address)
   687  	sep := ":"
   688  	tmpHeaderNum := new(big.Int)
   689  	for i := record.LastConfirmedNumber + 1; i <= record.MaxHeaderNumber; i++ {
   690  		if _, ok := record.Record[i]; ok {
   691  			// during reorged, the side chain loop info may more than one for each side chain block number.
   692  			for _, scConfirm := range record.Record[i] {
   693  				// loopInfo slice contain number and coinbase address of side chain block,
   694  				// so the length of loop info must larger than twice of minConfirmedSignerCount .
   695  				if len(scConfirm.LoopInfo) >= minConfirmedSignerCount*2 {
   696  					key := strings.Join(scConfirm.LoopInfo, sep)
   697  					if _, ok := confirmedRecordMap[key]; !ok {
   698  						confirmedRecordMap[key] = make(map[common.Address]bool)
   699  					}
   700  					// new coinbase for same loop info
   701  					if _, ok := confirmedRecordMap[key][scConfirm.Coinbase]; !ok {
   702  						confirmedRecordMap[key][scConfirm.Coinbase] = true
   703  						if len(confirmedRecordMap[key]) >= minConfirmedSignerCount {
   704  							err := tmpHeaderNum.UnmarshalText([]byte(scConfirm.LoopInfo[len(scConfirm.LoopInfo)-2]))
   705  							if err == nil && tmpHeaderNum.Uint64() > confirmedNumber {
   706  								confirmedNumber = tmpHeaderNum.Uint64()
   707  							}
   708  						}
   709  					}
   710  				}
   711  			}
   712  		}
   713  	}
   714  
   715  	for info, confirm := range confirmedRecordMap {
   716  		if len(confirm) >= minConfirmedSignerCount {
   717  			infos := strings.Split(info, sep)
   718  			for i := 0; i+1 < len(infos); i += 2 {
   719  				err := tmpHeaderNum.UnmarshalText([]byte(infos[i]))
   720  				if err != nil {
   721  					continue
   722  				}
   723  				confirmedCoinbase[tmpHeaderNum.Uint64()] = common.HexToAddress(infos[i+1])
   724  			}
   725  		}
   726  	}
   727  
   728  	// for calculate side chain reward
   729  	// if the side chain count per period is more than one
   730  	// then the reward should calculate continue till one coinbase finished.
   731  	if record.CountPerPeriod > 1 && confirmedNumber > record.LastConfirmedNumber {
   732  		if lastConfirmedCoinbase, ok := confirmedCoinbase[confirmedNumber]; ok {
   733  			for i := confirmedNumber - 1; i > confirmedNumber-record.CountPerPeriod; i-- {
   734  				if lastConfirmedCoinbase != confirmedCoinbase[i] {
   735  					confirmedNumber = i
   736  					break
   737  				}
   738  			}
   739  			for i := confirmedNumber + 1; i < confirmedNumber+record.CountPerPeriod; i++ {
   740  				if _, ok = confirmedCoinbase[i]; ok {
   741  					delete(confirmedCoinbase, i)
   742  				}
   743  			}
   744  		}
   745  	}
   746  
   747  	return confirmedNumber, confirmedCoinbase
   748  }
   749  
   750  func (s *Snapshot) calculateCurrentBlockReward(currentCount uint64, periodCount uint64) uint64 {
   751  	currentRewardPercentage := uint64(0)
   752  	if periodCount > uint64(scMaxCountPerPeriod) {
   753  		periodCount = scMaxCountPerPeriod
   754  	}
   755  	if v, ok := SCCurrentBlockReward[periodCount][currentCount]; ok {
   756  		currentRewardPercentage = v
   757  	}
   758  	return currentRewardPercentage
   759  }
   760  
   761  func (s *Snapshot) updateSCConfirmation(headerNumber *big.Int) {
   762  	minConfirmedSignerCount := int(2 * s.config.MaxSignerCount / 3)
   763  	for scHash, record := range s.SCRecordMap {
   764  		if _, ok := s.SCRewardMap[scHash]; !ok {
   765  			s.SCRewardMap[scHash] = &SCReward{SCBlockRewardMap: make(map[uint64]*SCBlockReward)}
   766  		}
   767  		currentReward := &SCBlockReward{RewardScoreMap: make(map[common.Address]uint64)}
   768  		confirmedNumber, confirmedCoinbase := s.calculateSCConfirmedNumber(record, minConfirmedSignerCount)
   769  		if confirmedNumber > record.LastConfirmedNumber {
   770  			// todo: map coinbase of side chain to coin base of main chain here
   771  			lastSCCoinbase := common.Address{}
   772  			currentSCCoinbaseCount := uint64(0)
   773  			for n := record.LastConfirmedNumber + 1; n <= confirmedNumber; n++ {
   774  				if scCoinbase, ok := confirmedCoinbase[n]; ok {
   775  					// if scCoinbase not same with lastSCCoinbase recount
   776  					if lastSCCoinbase != scCoinbase {
   777  						currentSCCoinbaseCount = 1
   778  					} else {
   779  						currentSCCoinbaseCount++
   780  					}
   781  
   782  					if _, ok := currentReward.RewardScoreMap[scCoinbase]; !ok {
   783  						currentReward.RewardScoreMap[scCoinbase] = s.calculateCurrentBlockReward(currentSCCoinbaseCount, record.CountPerPeriod)
   784  					} else {
   785  						currentReward.RewardScoreMap[scCoinbase] += s.calculateCurrentBlockReward(currentSCCoinbaseCount, record.CountPerPeriod)
   786  					}
   787  
   788  					// update lastSCCoinbase
   789  					lastSCCoinbase = scCoinbase
   790  				}
   791  			}
   792  
   793  			for i := record.LastConfirmedNumber + 1; i <= confirmedNumber; i++ {
   794  				if _, ok := s.SCRecordMap[scHash].Record[i]; ok {
   795  					delete(s.SCRecordMap[scHash].Record, i)
   796  				}
   797  			}
   798  			s.SCRecordMap[scHash].LastConfirmedNumber = confirmedNumber
   799  		}
   800  		// clear empty block number for side chain
   801  		if len(currentReward.RewardScoreMap) != 0 {
   802  			s.SCRewardMap[scHash].SCBlockRewardMap[headerNumber.Uint64()] = currentReward
   803  		}
   804  	}
   805  
   806  	for scHash := range s.SCRewardMap {
   807  		// clear expired side chain reward record
   808  		for number := range s.SCRewardMap[scHash].SCBlockRewardMap {
   809  			if number < headerNumber.Uint64()-scRewardExpiredLoopCount*s.config.MaxSignerCount {
   810  				delete(s.SCRewardMap[scHash].SCBlockRewardMap, number)
   811  			}
   812  		}
   813  		// clear this side chain if reward is empty
   814  		if len(s.SCRewardMap[scHash].SCBlockRewardMap) == 0 {
   815  			delete(s.SCRewardMap, scHash)
   816  		}
   817  	}
   818  
   819  }
   820  
   821  func (s *Snapshot) updateSnapshotByDeclares(declares []Declare, headerNumber *big.Int) {
   822  	for _, declare := range declares {
   823  		if proposal, ok := s.Proposals[declare.ProposalHash]; ok {
   824  			// check the proposal enable status and valid block number
   825  			if proposal.ReceivedNumber.Uint64()+proposal.ValidationLoopCnt*s.config.MaxSignerCount < headerNumber.Uint64() || !s.isCandidate(declare.Declarer) {
   826  				continue
   827  			}
   828  			// check if this signer already declare on this proposal
   829  			alreadyDeclare := false
   830  			for _, v := range proposal.Declares {
   831  				if v.Declarer.Str() == declare.Declarer.Str() {
   832  					// this declarer already declare for this proposal
   833  					alreadyDeclare = true
   834  					break
   835  				}
   836  			}
   837  			if alreadyDeclare {
   838  				continue
   839  			}
   840  			// add declare to proposal
   841  			s.Proposals[declare.ProposalHash].Declares = append(s.Proposals[declare.ProposalHash].Declares,
   842  				&Declare{declare.ProposalHash, declare.Declarer, declare.Decision})
   843  
   844  		}
   845  	}
   846  }
   847  
   848  func (s *Snapshot) calculateProposalResult(headerNumber *big.Int) {
   849  	// process the expire proposal refund record
   850  	expiredHeaderNumber := headerNumber.Uint64() - proposalRefundExpiredLoopCount*s.config.MaxSignerCount
   851  	if _, ok := s.ProposalRefund[expiredHeaderNumber]; ok {
   852  		delete(s.ProposalRefund, expiredHeaderNumber)
   853  	}
   854  
   855  	for hashKey, proposal := range s.Proposals {
   856  		// the result will be calculate at receiverdNumber + vlcnt + 1
   857  		if proposal.ReceivedNumber.Uint64()+proposal.ValidationLoopCnt*s.config.MaxSignerCount+1 == headerNumber.Uint64() {
   858  			//return deposit for proposal
   859  			if _, ok := s.ProposalRefund[headerNumber.Uint64()]; !ok {
   860  				s.ProposalRefund[headerNumber.Uint64()] = make(map[common.Address]*big.Int)
   861  			}
   862  			if _, ok := s.ProposalRefund[headerNumber.Uint64()][proposal.Proposer]; !ok {
   863  				s.ProposalRefund[headerNumber.Uint64()][proposal.Proposer] = new(big.Int).Set(proposal.CurrentDeposit)
   864  			} else {
   865  				s.ProposalRefund[headerNumber.Uint64()][proposal.Proposer].Add(s.ProposalRefund[headerNumber.Uint64()][proposal.Proposer], proposal.CurrentDeposit)
   866  			}
   867  
   868  			// calculate the current stake of this proposal
   869  			judegmentStake := big.NewInt(0)
   870  			for _, tally := range s.Tally {
   871  				judegmentStake.Add(judegmentStake, tally)
   872  			}
   873  			judegmentStake.Mul(judegmentStake, big.NewInt(2))
   874  			judegmentStake.Div(judegmentStake, big.NewInt(3))
   875  			// calculate declare stake
   876  			yesDeclareStake := big.NewInt(0)
   877  			for _, declare := range proposal.Declares {
   878  				if declare.Decision {
   879  					if _, ok := s.Tally[declare.Declarer]; ok {
   880  						yesDeclareStake.Add(yesDeclareStake, s.Tally[declare.Declarer])
   881  					}
   882  				}
   883  			}
   884  			if yesDeclareStake.Cmp(judegmentStake) > 0 {
   885  				// process add candidate
   886  				switch proposal.ProposalType {
   887  				case proposalTypeCandidateAdd:
   888  					if candidateNeedPD {
   889  						s.Candidates[proposal.TargetAddress] = candidateStateNormal
   890  					}
   891  				case proposalTypeCandidateRemove:
   892  					if _, ok := s.Candidates[proposal.TargetAddress]; ok && candidateNeedPD {
   893  						delete(s.Candidates, proposal.TargetAddress)
   894  					}
   895  				case proposalTypeMinerRewardDistributionModify:
   896  					s.MinerReward = s.Proposals[hashKey].MinerRewardPerThousand
   897  
   898  				case proposalTypeSideChainAdd:
   899  					if _, ok := s.SCRecordMap[proposal.SCHash]; !ok {
   900  						s.SCRecordMap[proposal.SCHash] = &SCRecord{make(map[uint64][]*SCConfirmation), 0, 0, proposal.SCBlockCountPerPeriod, proposal.SCBlockRewardPerPeriod, make(map[common.Hash]*SCRentInfo)}
   901  					} else {
   902  						s.SCRecordMap[proposal.SCHash].CountPerPeriod = proposal.SCBlockCountPerPeriod
   903  						s.SCRecordMap[proposal.SCHash].RewardPerPeriod = proposal.SCBlockRewardPerPeriod
   904  					}
   905  				case proposalTypeSideChainRemove:
   906  					if _, ok := s.SCRecordMap[proposal.SCHash]; ok {
   907  						delete(s.SCRecordMap, proposal.SCHash)
   908  					}
   909  				case proposalTypeMinVoterBalanceModify:
   910  					s.MinVB = new(big.Int).Mul(new(big.Int).SetUint64(s.Proposals[hashKey].MinVoterBalance), big.NewInt(1e+18))
   911  				case proposalTypeProposalDepositModify:
   912  					//proposalDeposit = new(big.Int).Mul(new(big.Int).SetUint64(s.Proposals[hashKey].ProposalDeposit), big.NewInt(1e+18))
   913  				case proposalTypeRentSideChain:
   914  					// check if buy success
   915  					if _, ok := s.SCRecordMap[proposal.SCHash]; !ok {
   916  						// refund the rent fee if the side chain do not exist now, (exist when proposal)
   917  						refundSCRentFee := new(big.Int).Mul(new(big.Int).SetUint64(s.Proposals[hashKey].SCRentFee), big.NewInt(1e+18))
   918  						s.ProposalRefund[headerNumber.Uint64()][proposal.Proposer].Add(s.ProposalRefund[headerNumber.Uint64()][proposal.Proposer], refundSCRentFee)
   919  					} else {
   920  						// add rent reward info to scConfirmation
   921  						rentFee := new(big.Int).Mul(new(big.Int).SetUint64(proposal.SCRentFee), big.NewInt(1e+18))
   922  						rentPerPeriod := new(big.Int).Div(rentFee, new(big.Int).SetUint64(proposal.SCRentLength))
   923  						maxRewardNumber := new(big.Int).Add(headerNumber, new(big.Int).SetUint64(proposal.SCRentLength))
   924  						s.SCRecordMap[proposal.SCHash].RentReward[proposal.Hash] = &SCRentInfo{
   925  							rentPerPeriod,
   926  							maxRewardNumber,
   927  						}
   928  						if _, ok := s.SCNoticeMap[proposal.SCHash]; !ok {
   929  							s.SCNoticeMap[proposal.SCHash] = &CCNotice{make(map[common.Hash]GasCharging), make(map[common.Hash]NoticeCR)}
   930  						}
   931  						s.SCNoticeMap[proposal.SCHash].CurrentCharging[proposal.Hash] = GasCharging{proposal.TargetAddress, proposal.SCRentFee * proposal.SCRentRate, proposal.Hash}
   932  					}
   933  				default:
   934  					// todo
   935  				}
   936  			} else {
   937  				// reach the target header number, but not success
   938  				switch proposal.ProposalType {
   939  				case proposalTypeRentSideChain:
   940  					// refund the side chain rent fee
   941  					refundSCRentFee := new(big.Int).Mul(new(big.Int).SetUint64(s.Proposals[hashKey].SCRentFee), big.NewInt(1e+18))
   942  					s.ProposalRefund[headerNumber.Uint64()][proposal.Proposer].Add(s.ProposalRefund[headerNumber.Uint64()][proposal.Proposer], refundSCRentFee)
   943  				default:
   944  					// todo
   945  
   946  				}
   947  			}
   948  
   949  			// remove all proposal
   950  			delete(s.Proposals, hashKey)
   951  		}
   952  
   953  	}
   954  
   955  }
   956  
   957  func (s *Snapshot) updateSnapshotByProposals(proposals []Proposal, headerNumber *big.Int) {
   958  	for _, proposal := range proposals {
   959  		proposal.ReceivedNumber = new(big.Int).Set(headerNumber)
   960  		s.Proposals[proposal.Hash] = &proposal
   961  	}
   962  }
   963  
   964  func (s *Snapshot) updateSnapshotForExpired(headerNumber *big.Int) {
   965  
   966  	// deal the expired vote
   967  	var expiredVotes []*Vote
   968  	checkBalance := false
   969  	if len(s.Voters) > maxUncheckBalanceVoteCount {
   970  		checkBalance = true
   971  	}
   972  
   973  	for voterAddress, voteNumber := range s.Voters {
   974  		// clear the vote
   975  		if expiredVote, ok := s.Votes[voterAddress]; ok {
   976  			if headerNumber.Uint64()-voteNumber.Uint64() > s.config.Epoch || (checkBalance && s.Votes[voterAddress].Stake.Cmp(s.MinVB) < 0) {
   977  				expiredVotes = append(expiredVotes, expiredVote)
   978  			}
   979  		}
   980  	}
   981  	// remove expiredVotes only enough voters left
   982  	if uint64(len(s.Voters)-len(expiredVotes)) >= s.config.MaxSignerCount {
   983  		for _, expiredVote := range expiredVotes {
   984  			if _, ok := s.Tally[expiredVote.Candidate]; ok {
   985  				s.Tally[expiredVote.Candidate].Sub(s.Tally[expiredVote.Candidate], expiredVote.Stake)
   986  				if s.Tally[expiredVote.Candidate].Cmp(big.NewInt(0)) == 0 {
   987  					delete(s.Tally, expiredVote.Candidate)
   988  				}
   989  			}
   990  			delete(s.Votes, expiredVote.Voter)
   991  			delete(s.Voters, expiredVote.Voter)
   992  		}
   993  	}
   994  
   995  	// deal the expired confirmation
   996  	for blockNumber := range s.Confirmations {
   997  		if headerNumber.Uint64()-blockNumber > s.config.MaxSignerCount {
   998  			delete(s.Confirmations, blockNumber)
   999  		}
  1000  	}
  1001  
  1002  	// remove 0 stake tally
  1003  	for address, tally := range s.Tally {
  1004  		if tally.Cmp(big.NewInt(0)) <= 0 {
  1005  			if _, ok := s.SCCoinbase[address]; ok {
  1006  				delete(s.SCCoinbase, address)
  1007  			}
  1008  			delete(s.Tally, address)
  1009  		}
  1010  	}
  1011  }
  1012  
  1013  func (s *Snapshot) updateSnapshotByConfirmations(confirmations []Confirmation) {
  1014  	for _, confirmation := range confirmations {
  1015  		_, ok := s.Confirmations[confirmation.BlockNumber.Uint64()]
  1016  		if !ok {
  1017  			s.Confirmations[confirmation.BlockNumber.Uint64()] = []*common.Address{}
  1018  		}
  1019  		addConfirmation := true
  1020  		for _, address := range s.Confirmations[confirmation.BlockNumber.Uint64()] {
  1021  			if confirmation.Signer.Str() == address.Str() {
  1022  				addConfirmation = false
  1023  				break
  1024  			}
  1025  		}
  1026  		if addConfirmation == true {
  1027  			var confirmSigner common.Address
  1028  			confirmSigner.Set(confirmation.Signer)
  1029  			s.Confirmations[confirmation.BlockNumber.Uint64()] = append(s.Confirmations[confirmation.BlockNumber.Uint64()], &confirmSigner)
  1030  		}
  1031  	}
  1032  }
  1033  
  1034  func (s *Snapshot) updateSnapshotByVotes(votes []Vote, headerNumber *big.Int) {
  1035  	for _, vote := range votes {
  1036  		// update Votes, Tally, Voters data
  1037  		if lastVote, ok := s.Votes[vote.Voter]; ok {
  1038  			s.Tally[lastVote.Candidate].Sub(s.Tally[lastVote.Candidate], lastVote.Stake)
  1039  		}
  1040  		if _, ok := s.Tally[vote.Candidate]; ok {
  1041  
  1042  			s.Tally[vote.Candidate].Add(s.Tally[vote.Candidate], vote.Stake)
  1043  		} else {
  1044  			s.Tally[vote.Candidate] = new(big.Int).Set(vote.Stake)
  1045  			if !candidateNeedPD {
  1046  				s.Candidates[vote.Candidate] = candidateStateNormal
  1047  			}
  1048  		}
  1049  
  1050  		s.Votes[vote.Voter] = &Vote{vote.Voter, vote.Candidate, new(big.Int).Set(vote.Stake)}
  1051  		s.Voters[vote.Voter] = new(big.Int).Set(headerNumber)
  1052  	}
  1053  }
  1054  
  1055  func (s *Snapshot) updateSnapshotByMPVotes(votes []Vote) {
  1056  	for _, txVote := range votes {
  1057  
  1058  		if lastVote, ok := s.Votes[txVote.Voter]; ok {
  1059  			s.Tally[lastVote.Candidate].Sub(s.Tally[lastVote.Candidate], lastVote.Stake)
  1060  			s.Tally[lastVote.Candidate].Add(s.Tally[lastVote.Candidate], txVote.Stake)
  1061  			s.Votes[txVote.Voter] = &Vote{Voter: txVote.Voter, Candidate: lastVote.Candidate, Stake: txVote.Stake}
  1062  			// do not modify header number of snap.Voters
  1063  		}
  1064  	}
  1065  }
  1066  
  1067  func (s *Snapshot) updateSnapshotForPunish(signerMissing []common.Address, headerNumber *big.Int, coinbase common.Address) {
  1068  	// set punished count to half of origin in Epoch
  1069  	/*
  1070  		if headerNumber.Uint64()%s.config.Epoch == 0 {
  1071  			for bePublished := range s.Punished {
  1072  				if count := s.Punished[bePublished] / 2; count > 0 {
  1073  					s.Punished[bePublished] = count
  1074  				} else {
  1075  					delete(s.Punished, bePublished)
  1076  				}
  1077  			}
  1078  		}
  1079  	*/
  1080  	// punish the missing signer
  1081  	for _, signerEach := range signerMissing {
  1082  		if _, ok := s.Punished[signerEach]; ok {
  1083  			// 10 times of defaultFullCredit is big enough for calculate signer order
  1084  			if s.Punished[signerEach] <= 10*defaultFullCredit {
  1085  				s.Punished[signerEach] += missingPublishCredit
  1086  			}
  1087  		} else {
  1088  			s.Punished[signerEach] = missingPublishCredit
  1089  		}
  1090  	}
  1091  	// reduce the punish of sign signer
  1092  	if _, ok := s.Punished[coinbase]; ok {
  1093  
  1094  		if s.Punished[coinbase] > signRewardCredit {
  1095  			s.Punished[coinbase] -= signRewardCredit
  1096  		} else {
  1097  			delete(s.Punished, coinbase)
  1098  		}
  1099  	}
  1100  	// reduce the punish for all punished
  1101  	for signerEach := range s.Punished {
  1102  		if s.Punished[signerEach] > autoRewardCredit {
  1103  			s.Punished[signerEach] -= autoRewardCredit
  1104  		} else {
  1105  			delete(s.Punished, signerEach)
  1106  		}
  1107  	}
  1108  
  1109  	// clear all punish score at the beginning of trantor block
  1110  	if s.config.IsTrantor(headerNumber) && !s.config.IsTrantor(new(big.Int).Sub(headerNumber, big.NewInt(1))) {
  1111  		s.Punished = make(map[common.Address]uint64)
  1112  	}
  1113  
  1114  }
  1115  
  1116  // inturn returns if a signer at a given block height is in-turn or not.
  1117  func (s *Snapshot) inturn(signer common.Address, headerTime uint64) bool {
  1118  	// if all node stop more than period of one loop
  1119  	if signersCount := len(s.Signers); signersCount > 0 {
  1120  		if loopIndex := ((headerTime - s.LoopStartTime) / s.config.Period) % uint64(signersCount); *s.Signers[loopIndex] == signer {
  1121  			return true
  1122  		}
  1123  	}
  1124  	return false
  1125  
  1126  }
  1127  
  1128  // check if side chain is exist (in side chain confirmation)
  1129  func (s *Snapshot) isSideChainExist(hash common.Hash) bool {
  1130  	if _, ok := s.SCRecordMap[hash]; ok {
  1131  		return true
  1132  	}
  1133  	return false
  1134  }
  1135  
  1136  // check if address belong to voter
  1137  func (s *Snapshot) isVoter(address common.Address) bool {
  1138  	if _, ok := s.Voters[address]; ok {
  1139  		return true
  1140  	}
  1141  	return false
  1142  }
  1143  
  1144  // check if address belong to candidate
  1145  func (s *Snapshot) isCandidate(address common.Address) bool {
  1146  	if _, ok := s.Candidates[address]; ok {
  1147  		return true
  1148  	}
  1149  	return false
  1150  }
  1151  
  1152  // get last block number meet the confirm condition
  1153  func (s *Snapshot) getLastConfirmedBlockNumber(confirmations []Confirmation) *big.Int {
  1154  
  1155  	cpyConfirmations := make(map[uint64][]*common.Address)
  1156  	for blockNumber, confirmers := range s.Confirmations {
  1157  		cpyConfirmations[blockNumber] = make([]*common.Address, len(confirmers))
  1158  		copy(cpyConfirmations[blockNumber], confirmers)
  1159  	}
  1160  	// update confirmation into snapshot
  1161  	for _, confirmation := range confirmations {
  1162  		_, ok := cpyConfirmations[confirmation.BlockNumber.Uint64()]
  1163  		if !ok {
  1164  			cpyConfirmations[confirmation.BlockNumber.Uint64()] = []*common.Address{}
  1165  		}
  1166  		addConfirmation := true
  1167  		for _, address := range cpyConfirmations[confirmation.BlockNumber.Uint64()] {
  1168  			if confirmation.Signer.Str() == address.Str() {
  1169  				addConfirmation = false
  1170  				break
  1171  			}
  1172  		}
  1173  		if addConfirmation == true {
  1174  			var confirmSigner common.Address
  1175  			confirmSigner.Set(confirmation.Signer)
  1176  			cpyConfirmations[confirmation.BlockNumber.Uint64()] = append(cpyConfirmations[confirmation.BlockNumber.Uint64()], &confirmSigner)
  1177  		}
  1178  	}
  1179  
  1180  	i := s.Number
  1181  	for ; i > s.Number-s.config.MaxSignerCount*2/3+1; i-- {
  1182  		if confirmers, ok := cpyConfirmations[i]; ok {
  1183  			if len(confirmers) > int(s.config.MaxSignerCount*2/3) {
  1184  				return big.NewInt(int64(i))
  1185  			}
  1186  		}
  1187  	}
  1188  	return big.NewInt(int64(i))
  1189  }
  1190  
  1191  func (s *Snapshot) calculateProposalRefund() map[common.Address]*big.Int {
  1192  
  1193  	if refund, ok := s.ProposalRefund[s.Number-proposalRefundDelayLoopCount*s.config.MaxSignerCount]; ok {
  1194  		return refund
  1195  	}
  1196  	return make(map[common.Address]*big.Int)
  1197  }
  1198  
  1199  func (s *Snapshot) calculateVoteReward(coinbase common.Address, votersReward *big.Int) (map[common.Address]*big.Int, error) {
  1200  	rewards := make(map[common.Address]*big.Int)
  1201  	allStake := big.NewInt(0)
  1202  
  1203  	for voter, vote := range s.Votes {
  1204  		if vote.Candidate.Str() == coinbase.Str() && s.Voters[vote.Voter].Uint64() < s.Number-s.config.MaxSignerCount {
  1205  			allStake.Add(allStake, vote.Stake)
  1206  			rewards[voter] = new(big.Int).Set(vote.Stake)
  1207  		}
  1208  	}
  1209  
  1210  	if allStake.Cmp(big.NewInt(0)) <= 0 && len(rewards) > 0 {
  1211  		return nil, errAllStakeMissing
  1212  	}
  1213  	for _, stake := range rewards {
  1214  		stake.Mul(stake, votersReward)
  1215  		stake.Div(stake, allStake)
  1216  	}
  1217  	return rewards, nil
  1218  }
  1219  
  1220  func (s *Snapshot) calculateGasCharging() map[common.Address]*big.Int {
  1221  	gasCharge := make(map[common.Address]*big.Int)
  1222  	for hash, noticeRecord := range s.LocalNotice.ConfirmReceived {
  1223  		if noticeRecord.Success && s.Number == noticeRecord.Number+scGasChargingDelayLoopCount*s.config.MaxSignerCount {
  1224  			if charge, ok := s.LocalNotice.CurrentCharging[hash]; ok {
  1225  				if _, ok := gasCharge[charge.Target]; !ok {
  1226  					gasCharge[charge.Target] = new(big.Int).Mul(big.NewInt(1e+18), new(big.Int).SetUint64(charge.Volume))
  1227  				} else {
  1228  					gasCharge[charge.Target].Add(gasCharge[charge.Target], new(big.Int).Mul(big.NewInt(1e+18), new(big.Int).SetUint64(charge.Volume)))
  1229  				}
  1230  			}
  1231  		}
  1232  	}
  1233  	return gasCharge
  1234  }
  1235  
  1236  func (s *Snapshot) calculateSCReward(minerReward *big.Int) (map[common.Address]*big.Int, *big.Int) {
  1237  
  1238  	minerLeft := new(big.Int).Set(minerReward)
  1239  	scRewardAll := new(big.Int).Set(minerReward)
  1240  	scRewards := make(map[common.Address]*big.Int)
  1241  
  1242  	// need to deal with sum of record.RewardPerPeriod for all side chain is larger than 100% situation
  1243  	scRewardMilliSum := uint64(0)
  1244  	for _, record := range s.SCRecordMap {
  1245  		scRewardMilliSum += record.RewardPerPeriod
  1246  	}
  1247  
  1248  	if scRewardMilliSum > 0 && scRewardMilliSum < 1000 {
  1249  		scRewardAll.Mul(scRewardAll, new(big.Int).SetUint64(scRewardMilliSum))
  1250  		scRewardAll.Div(scRewardAll, big.NewInt(1000))
  1251  		minerLeft.Sub(minerLeft, scRewardAll)
  1252  		scRewardMilliSum = 1000
  1253  	} else if scRewardMilliSum >= 1000 {
  1254  		minerLeft.SetUint64(0)
  1255  	} else {
  1256  		scRewardAll.SetUint64(0)
  1257  		scRewardMilliSum = 1000
  1258  	}
  1259  
  1260  	for scHash := range s.SCRewardMap {
  1261  		// check reward for the block number is exist
  1262  		if reward, ok := s.SCRewardMap[scHash].SCBlockRewardMap[s.Number-scRewardDelayLoopCount*s.config.MaxSignerCount]; ok {
  1263  			// check confirm is exist, to get countPerPeriod and rewardPerPeriod
  1264  			if confirmation, ok := s.SCRecordMap[scHash]; ok {
  1265  				// calculate the rent still not reach on this side chain
  1266  				scRentSumPerPeriod := big.NewInt(0)
  1267  				for _, rent := range confirmation.RentReward {
  1268  					if rent.MaxRewardNumber.Uint64() >= s.Number-scRewardDelayLoopCount*s.config.MaxSignerCount {
  1269  						scRentSumPerPeriod.Add(scRentSumPerPeriod, rent.RentPerPeriod)
  1270  					}
  1271  				}
  1272  
  1273  				// calculate the side chain reward base on score/100 and record.RewardPerPeriod
  1274  				for addr, score := range reward.RewardScoreMap {
  1275  					singleReward := new(big.Int).Set(scRewardAll)
  1276  					singleReward.Mul(singleReward, new(big.Int).SetUint64(confirmation.RewardPerPeriod))
  1277  					singleReward.Div(singleReward, new(big.Int).SetUint64(scRewardMilliSum))
  1278  					singleReward.Add(singleReward, scRentSumPerPeriod)
  1279  					singleReward.Mul(singleReward, new(big.Int).SetUint64(score))
  1280  					singleReward.Div(singleReward, new(big.Int).SetUint64(100)) // for score/100
  1281  
  1282  					if _, ok := scRewards[addr]; ok {
  1283  						scRewards[addr].Add(scRewards[addr], singleReward)
  1284  					} else {
  1285  						scRewards[addr] = singleReward
  1286  					}
  1287  				}
  1288  			}
  1289  		}
  1290  	}
  1291  	return scRewards, minerLeft
  1292  
  1293  }