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 }