github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/consensus/neatcon/engine.go (about) 1 package neatcon 2 3 import ( 4 "bytes" 5 "errors" 6 "math/big" 7 "time" 8 9 lru "github.com/hashicorp/golang-lru" 10 "github.com/neatio-net/neatio/chain/consensus" 11 "github.com/neatio-net/neatio/chain/consensus/neatcon/epoch" 12 ntcTypes "github.com/neatio-net/neatio/chain/consensus/neatcon/types" 13 "github.com/neatio-net/neatio/chain/core/state" 14 "github.com/neatio-net/neatio/chain/core/types" 15 "github.com/neatio-net/neatio/network/rpc" 16 "github.com/neatio-net/neatio/params" 17 "github.com/neatio-net/neatio/utilities/common" 18 "github.com/neatio-net/wire-go" 19 ) 20 21 const ( 22 fetcherID = "neatcon" 23 ) 24 25 var ( 26 errInvalidProposal = errors.New("invalid proposal") 27 28 errInvalidSignature = errors.New("invalid signature") 29 30 errUnknownBlock = errors.New("unknown block") 31 32 errUnauthorized = errors.New("unauthorized") 33 34 errInvalidDifficulty = errors.New("invalid difficulty") 35 36 errInvalidExtraDataFormat = errors.New("invalid extra data format") 37 38 errInvalidMixDigest = errors.New("invalid NeatCon mix digest") 39 40 errInvalidNonce = errors.New("invalid nonce") 41 42 errInvalidUncleHash = errors.New("non empty uncle hash") 43 44 errInconsistentValidatorSet = errors.New("inconsistent validator set") 45 46 errInvalidTimestamp = errors.New("invalid timestamp") 47 48 errInvalidVotingChain = errors.New("invalid voting chain") 49 50 errInvalidVote = errors.New("vote nonce not 0x00..0 or 0xff..f") 51 52 errInvalidCommittedSeals = errors.New("invalid committed seals") 53 54 errEmptyCommittedSeals = errors.New("zero committed seals") 55 56 errMismatchTxhashes = errors.New("mismatch transactions hashes") 57 58 errInvalidMainChainNumber = errors.New("invalid Main Chain Height") 59 60 errMainChainNotCatchup = errors.New("unable proceed the block due to main chain not catch up by waiting for more than 300 seconds, please catch up the main chain first") 61 ) 62 63 var ( 64 now = time.Now 65 66 inmemoryAddresses = 20 67 recentAddresses, _ = lru.NewARC(inmemoryAddresses) 68 69 _ consensus.Engine = (*backend)(nil) 70 71 neatGenesisAddress = common.HexToAddress("0x0000000000000000000000000000000000000000") 72 foundationAddress = common.HexToAddress("0xbbe9e63Dcb95105A3Ab5e9094B0C866F0f418987") 73 74 sideChainRewardAddress = common.StringToAddress("0x0000000000000000000000000000000000000535") 75 ) 76 77 func (sb *backend) APIs(chain consensus.ChainReader) []rpc.API { 78 return []rpc.API{{ 79 Namespace: "neat", 80 Version: "1.0", 81 Service: &API{chain: chain, neatcon: sb}, 82 Public: true, 83 }} 84 } 85 86 func (sb *backend) Start(chain consensus.ChainReader, currentBlock func() *types.Block, hasBadBlock func(hash common.Hash) bool) error { 87 88 sb.logger.Info("NeatCon backend Start") 89 90 sb.coreMu.Lock() 91 defer sb.coreMu.Unlock() 92 if sb.coreStarted { 93 return ErrStartedEngine 94 } 95 96 sb.proposedBlockHash = common.Hash{} 97 if sb.commitCh != nil { 98 close(sb.commitCh) 99 } 100 sb.commitCh = make(chan *types.Block, 1) 101 if sb.vcommitCh != nil { 102 close(sb.vcommitCh) 103 } 104 sb.vcommitCh = make(chan *ntcTypes.IntermediateBlockResult, 1) 105 106 sb.chain = chain 107 sb.currentBlock = currentBlock 108 sb.hasBadBlock = hasBadBlock 109 110 if _, err := sb.core.Start(); err != nil { 111 return err 112 } 113 114 sb.coreStarted = true 115 116 return nil 117 } 118 119 func (sb *backend) Stop() error { 120 121 sb.logger.Info("NeatCon backend stop") 122 123 sb.coreMu.Lock() 124 defer sb.coreMu.Unlock() 125 if !sb.coreStarted { 126 return ErrStoppedEngine 127 } 128 if !sb.core.Stop() { 129 return errors.New("neatcon stop error") 130 } 131 sb.coreStarted = false 132 133 return nil 134 } 135 136 func (sb *backend) Close() error { 137 sb.core.epochDB.Close() 138 return nil 139 } 140 141 func (sb *backend) Author(header *types.Header) (common.Address, error) { 142 return header.Coinbase, nil 143 } 144 145 func (sb *backend) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { 146 147 //sb.logger.Info("Your node is synchronized. This is Neat!") 148 149 return sb.verifyHeader(chain, header, nil) 150 } 151 152 func (sb *backend) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 153 154 if header.Number == nil { 155 return errUnknownBlock 156 } 157 158 if header.Time.Cmp(big.NewInt(now().Unix())) > 0 { 159 sb.logger.Warnf("date/time different between different nodes. block from future with time:%v, bigger than now:%v", header.Time.Uint64(), now().Unix()) 160 161 } 162 163 if _, err := ntcTypes.ExtractNeatConExtra(header); err != nil { 164 return errInvalidExtraDataFormat 165 } 166 167 if header.Nonce != (types.NeatConEmptyNonce) && !bytes.Equal(header.Nonce[:], types.NeatConNonce) { 168 return errInvalidNonce 169 } 170 171 if header.MixDigest != types.NeatConDigest { 172 return errInvalidMixDigest 173 } 174 175 if header.UncleHash != types.NeatConNilUncleHash { 176 return errInvalidUncleHash 177 } 178 179 if header.Difficulty == nil || header.Difficulty.Cmp(types.NeatConDefaultDifficulty) != 0 { 180 return errInvalidDifficulty 181 } 182 183 if header.Number.Uint64() > sb.GetEpoch().EndBlock { 184 for { 185 duration := 2 * time.Second 186 sb.logger.Infof("NeatCon VerifyHeader, Epoch Switch, wait for %v then try again", duration) 187 time.Sleep(duration) 188 189 if header.Number.Uint64() <= sb.GetEpoch().EndBlock { 190 break 191 } 192 } 193 } 194 195 if fieldError := sb.verifyCascadingFields(chain, header, parents); fieldError != nil { 196 return fieldError 197 } 198 199 if !sb.chainConfig.IsMainChain() { 200 if header.MainChainNumber == nil { 201 return errInvalidMainChainNumber 202 } 203 204 tried := 0 205 for { 206 207 ourMainChainHeight := sb.core.cch.GetHeightFromMainChain() 208 if ourMainChainHeight.Cmp(header.MainChainNumber) >= 0 { 209 break 210 } 211 212 if tried == 10 { 213 sb.logger.Warnf("NeatCon VerifyHeader, Main Chain Number mismatch, after retried %d times", tried) 214 return errMainChainNotCatchup 215 } 216 217 duration := 30 * time.Second 218 tried++ 219 sb.logger.Infof("NeatCon VerifyHeader, Main Chain Number mismatch, wait for %v then try again (count %d)", duration, tried) 220 time.Sleep(duration) 221 } 222 } 223 224 return nil 225 } 226 227 func (sb *backend) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 228 229 number := header.Number.Uint64() 230 if number == 0 { 231 return nil 232 } 233 234 var parent *types.Header 235 if len(parents) > 0 { 236 parent = parents[len(parents)-1] 237 } else { 238 parent = chain.GetHeader(header.ParentHash, number-1) 239 } 240 if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { 241 return consensus.ErrUnknownAncestor 242 } 243 244 err := sb.verifyCommittedSeals(chain, header, parents) 245 return err 246 } 247 248 func (sb *backend) VerifyHeaderBeforeConsensus(chain consensus.ChainReader, header *types.Header, seal bool) error { 249 //sb.logger.Info("NeatCon backend verify header before consensus") 250 251 if header.Number == nil { 252 return errUnknownBlock 253 } 254 255 if header.Time.Cmp(big.NewInt(now().Unix())) > 0 { 256 sb.logger.Warnf("date/time different between different nodes. block from future with time:%v, bigger than now:%v", header.Time.Uint64(), now().Unix()) 257 258 } 259 260 if header.Nonce != (types.NeatConEmptyNonce) && !bytes.Equal(header.Nonce[:], types.NeatConNonce) { 261 return errInvalidNonce 262 } 263 264 if header.MixDigest != types.NeatConDigest { 265 return errInvalidMixDigest 266 } 267 268 if header.UncleHash != types.NeatConNilUncleHash { 269 return errInvalidUncleHash 270 } 271 272 if header.Difficulty == nil || header.Difficulty.Cmp(types.NeatConDefaultDifficulty) != 0 { 273 return errInvalidDifficulty 274 } 275 276 return nil 277 } 278 279 func (sb *backend) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 280 abort := make(chan struct{}) 281 results := make(chan error, len(headers)) 282 283 //sb.logger.Info("NeatCon backend verify headers") 284 285 go func() { 286 for i, header := range headers { 287 err := sb.verifyHeader(chain, header, headers[:i]) 288 select { 289 case <-abort: 290 return 291 case results <- err: 292 } 293 } 294 }() 295 296 return abort, results 297 } 298 299 func (sb *backend) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 300 301 if len(block.Uncles()) > 0 { 302 return errInvalidUncleHash 303 } 304 return nil 305 } 306 307 func (sb *backend) verifyCommittedSeals(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 308 309 ncExtra, err := ntcTypes.ExtractNeatConExtra(header) 310 if err != nil { 311 return errInvalidExtraDataFormat 312 } 313 314 epoch := sb.core.consensusState.Epoch 315 if epoch == nil || epoch.Validators == nil { 316 sb.logger.Errorf("verifyCommittedSeals error. Epoch %v", epoch) 317 return errInconsistentValidatorSet 318 } 319 320 epoch = epoch.GetEpochByBlockNumber(header.Number.Uint64()) 321 if epoch == nil || epoch.Validators == nil { 322 sb.logger.Errorf("verifyCommittedSeals error. Epoch %v", epoch) 323 return errInconsistentValidatorSet 324 } 325 326 valSet := epoch.Validators 327 if !bytes.Equal(valSet.Hash(), ncExtra.ValidatorsHash) { 328 sb.logger.Errorf("verifyCommittedSeals error. Our Validator Set %x, ncExtra Valdiator %x", valSet.Hash(), ncExtra.ValidatorsHash) 329 sb.logger.Errorf("verifyCommittedSeals error. epoch validator set %v, extra data %v", valSet.String(), ncExtra.String()) 330 return errInconsistentValidatorSet 331 } 332 333 seenCommit := ncExtra.SeenCommit 334 if !bytes.Equal(ncExtra.SeenCommitHash, seenCommit.Hash()) { 335 sb.logger.Errorf("verifyCommittedSeals SeenCommit is %#+v", seenCommit) 336 sb.logger.Errorf("verifyCommittedSeals error. Our SeenCommitHash %x, ncExtra SeenCommitHash %x", seenCommit.Hash(), ncExtra.SeenCommitHash) 337 return errInvalidCommittedSeals 338 } 339 340 if err = valSet.VerifyCommit(ncExtra.ChainID, ncExtra.Height, seenCommit); err != nil { 341 sb.logger.Errorf("verifyCommittedSeals verify commit err %v", err) 342 return errInvalidSignature 343 } 344 345 return nil 346 } 347 348 func (sb *backend) VerifySeal(chain consensus.ChainReader, header *types.Header) error { 349 350 number := header.Number.Uint64() 351 if number == 0 { 352 return errUnknownBlock 353 } 354 355 if header.Difficulty.Cmp(types.NeatConDefaultDifficulty) != 0 { 356 return errInvalidDifficulty 357 } 358 359 return nil 360 } 361 362 func (sb *backend) Prepare(chain consensus.ChainReader, header *types.Header) error { 363 364 header.Nonce = types.NeatConEmptyNonce 365 header.MixDigest = types.NeatConDigest 366 367 number := header.Number.Uint64() 368 parent := chain.GetHeader(header.ParentHash, number-1) 369 if parent == nil { 370 return consensus.ErrUnknownAncestor 371 } 372 373 header.Difficulty = types.NeatConDefaultDifficulty 374 375 extra, err := prepareExtra(header, nil) 376 if err != nil { 377 return err 378 } 379 header.Extra = extra 380 381 header.Time = big.NewInt(time.Now().Unix()) 382 383 if sb.chainConfig.NeatChainId != params.MainnetChainConfig.NeatChainId && sb.chainConfig.NeatChainId != params.TestnetChainConfig.NeatChainId { 384 header.MainChainNumber = sb.core.cch.GetHeightFromMainChain() 385 } 386 387 return nil 388 } 389 390 func (sb *backend) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, 391 totalGasFee *big.Int, uncles []*types.Header, receipts []*types.Receipt, ops *types.PendingOps) (*types.Block, error) { 392 393 sb.logger.Debugf("NeatCon Finalize, receipts are: %v", receipts) 394 395 if sb.chainConfig.NeatChainId == params.MainnetChainConfig.NeatChainId || sb.chainConfig.NeatChainId == params.TestnetChainConfig.NeatChainId { 396 397 readyId, updateBytes, removedId := sb.core.cch.ReadyForLaunchSideChain(header.Number, state) 398 if len(readyId) > 0 || updateBytes != nil || len(removedId) > 0 { 399 if ok := ops.Append(&types.LaunchSideChainsOp{ 400 SideChainIds: readyId, 401 NewPendingIdx: updateBytes, 402 DeleteSideChainIds: removedId, 403 }); !ok { 404 405 sb.logger.Error("NeatCon Finalize, Fail to append LaunchSideChainsOp, only one LaunchSideChainsOp is allowed in each block") 406 } 407 } 408 } 409 410 curBlockNumber := header.Number.Uint64() 411 epoch := sb.GetEpoch().GetEpochByBlockNumber(curBlockNumber) 412 413 genesisHeader := chain.GetBlockByNumber(1) 414 if genesisHeader != nil { 415 genesisCoinbase := genesisHeader.Header().Coinbase 416 neatGenesisAddress = state.GetAddress(genesisCoinbase) 417 } 418 419 accumulateRewards(sb.chainConfig, state, header, epoch, totalGasFee) 420 421 if ok, newValidators, _ := epoch.ShouldEnterNewEpoch(header.Number.Uint64(), state); ok { 422 ops.Append(&ntcTypes.SwitchEpochOp{ 423 ChainId: sb.chainConfig.NeatChainId, 424 NewValidators: newValidators, 425 }) 426 427 } 428 429 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 430 header.UncleHash = types.NeatConNilUncleHash 431 432 return types.NewBlock(header, txs, nil, receipts), nil 433 } 434 435 func (sb *backend) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (interface{}, error) { 436 437 //sb.logger.Info("NeatCon backend seal") 438 439 header := block.Header() 440 number := header.Number.Uint64() 441 parent := chain.GetHeader(header.ParentHash, number-1) 442 if parent == nil { 443 return nil, consensus.ErrUnknownAncestor 444 } 445 block, err := sb.updateBlock(parent, block) 446 if err != nil { 447 return nil, err 448 } 449 450 delay := time.Unix(block.Header().Time.Int64(), 0).Sub(now()) 451 select { 452 case <-time.After(delay): 453 case <-stop: 454 return nil, nil 455 } 456 457 sb.sealMu.Lock() 458 sb.proposedBlockHash = block.Hash() 459 clear := func() { 460 sb.proposedBlockHash = common.Hash{} 461 sb.sealMu.Unlock() 462 } 463 defer clear() 464 465 //sb.logger.Infof("NeatCon Seal, before fire event with block height: %d", block.NumberU64()) 466 go ntcTypes.FireEventRequest(sb.core.EventSwitch(), ntcTypes.EventDataRequest{Proposal: block}) 467 468 for { 469 select { 470 case result, ok := <-sb.commitCh: 471 472 if ok { 473 sb.logger.Debugf("NeatCon Seal, got result with block.Hash: %x, result.Hash: %x", block.Hash(), result.Hash()) 474 475 if block.Hash() == result.Hash() { 476 return result, nil 477 } 478 sb.logger.Debug("NeatCon Seal, hash are different") 479 } else { 480 sb.logger.Debug("NeatCon Seal, has been restart, just return") 481 return nil, nil 482 } 483 484 case iresult, ok := <-sb.vcommitCh: 485 486 if ok { 487 sb.logger.Debugf("NeatCon Seal, v got result with block.Hash: %x, result.Hash: %x", block.Hash(), iresult.Block.Hash()) 488 if block.Hash() != iresult.Block.Hash() { 489 return iresult, nil 490 } 491 sb.logger.Debug("NeatCon Seal, v hash are the same") 492 } else { 493 sb.logger.Debug("NeatCon Seal, v has been restart, just return") 494 return nil, nil 495 } 496 497 case <-stop: 498 sb.logger.Debug("NeatCon Seal, stop") 499 return nil, nil 500 } 501 } 502 503 return nil, nil 504 } 505 506 func (sb *backend) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { 507 508 return types.NeatConDefaultDifficulty 509 } 510 511 func (sb *backend) Commit(proposal *ntcTypes.NCBlock, seals [][]byte, isProposer func() bool) error { 512 513 block := proposal.Block 514 515 h := block.Header() 516 517 err := writeCommittedSeals(h, proposal.NTCExtra) 518 if err != nil { 519 return err 520 } 521 522 block = block.WithSeal(h) 523 524 sb.logger.Debugf("NeatCon Commit, hash: %x, number: %v", block.Hash(), block.Number().Int64()) 525 sb.logger.Debugf("NeatCon Commit, block: %s", block.String()) 526 527 if isProposer() && (sb.proposedBlockHash == block.Hash()) { 528 529 sb.logger.Debugf("NeatCon Commit, proposer | feed to Seal: %x", block.Hash()) 530 sb.commitCh <- block 531 return nil 532 } else { 533 if proposal.IntermediateResult != nil { 534 sb.logger.Debugf("NeatCon Commit, validator | feed to Seal: %x", block.Hash()) 535 proposal.IntermediateResult.Block = block 536 sb.vcommitCh <- proposal.IntermediateResult 537 } else { 538 sb.logger.Debugf("NeatCon Commit, validator | fetcher enqueue: %x", block.Hash()) 539 if sb.broadcaster != nil { 540 sb.broadcaster.Enqueue(fetcherID, block) 541 } 542 } 543 return nil 544 } 545 } 546 547 func (sb *backend) ChainReader() consensus.ChainReader { 548 549 return sb.chain 550 } 551 552 func (sb *backend) ShouldStart() bool { 553 return sb.shouldStart 554 } 555 556 func (sb *backend) IsStarted() bool { 557 sb.coreMu.RLock() 558 start := sb.coreStarted 559 sb.coreMu.RUnlock() 560 561 return start 562 } 563 564 func (sb *backend) ForceStart() { 565 sb.shouldStart = true 566 } 567 568 func (sb *backend) GetEpoch() *epoch.Epoch { 569 return sb.core.consensusState.Epoch 570 } 571 572 func (sb *backend) SetEpoch(ep *epoch.Epoch) { 573 sb.core.consensusState.Epoch = ep 574 } 575 576 func (sb *backend) PrivateValidator() common.Address { 577 if sb.core.privValidator != nil { 578 return sb.core.privValidator.Address 579 } 580 return common.Address{} 581 } 582 583 func (sb *backend) updateBlock(parent *types.Header, block *types.Block) (*types.Block, error) { 584 585 sb.logger.Debug("NeatCon backend update block") 586 587 header := block.Header() 588 err := writeSeal(header, []byte{}) 589 if err != nil { 590 return nil, err 591 } 592 593 return block.WithSeal(header), nil 594 } 595 596 func prepareExtra(header *types.Header, vals []common.Address) ([]byte, error) { 597 598 header.Extra = types.MagicExtra 599 return nil, nil 600 } 601 602 func writeSeal(h *types.Header, seal []byte) error { 603 604 if h.Extra == nil { 605 payload := types.MagicExtra 606 h.Extra = payload 607 } 608 return nil 609 } 610 611 func writeCommittedSeals(h *types.Header, ncExtra *ntcTypes.NeatConExtra) error { 612 613 h.Extra = wire.BinaryBytes(*ncExtra) 614 return nil 615 } 616 617 func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, ep *epoch.Epoch, totalGasFee *big.Int) { 618 tenPercentGasFee := big.NewInt(0).Div(totalGasFee, big.NewInt(10)) 619 state.AddBalance(foundationAddress, tenPercentGasFee) 620 621 var coinbaseReward *big.Int 622 if config.NeatChainId == params.MainnetChainConfig.NeatChainId || config.NeatChainId == params.TestnetChainConfig.NeatChainId { 623 rewardPerBlock := ep.RewardPerBlock 624 if rewardPerBlock != nil && rewardPerBlock.Sign() == 1 { 625 zeroAddress := common.Address{} 626 if neatGenesisAddress == zeroAddress { 627 coinbaseReward = big.NewInt(0) 628 coinbaseReward.Add(rewardPerBlock, tenPercentGasFee) 629 } else { 630 coinbaseReward = new(big.Int).Mul(rewardPerBlock, big.NewInt(8)) 631 coinbaseReward.Quo(coinbaseReward, big.NewInt(10)) 632 foundationReward := new(big.Int).Sub(rewardPerBlock, coinbaseReward) 633 state.AddBalance(neatGenesisAddress, foundationReward) 634 coinbaseReward.Add(coinbaseReward, tenPercentGasFee) 635 } 636 } else { 637 coinbaseReward = tenPercentGasFee 638 } 639 } else { 640 rewardPerBlock := state.GetSideChainRewardPerBlock() 641 if rewardPerBlock != nil && rewardPerBlock.Sign() == 1 { 642 sideChainRewardBalance := state.GetBalance(sideChainRewardAddress) 643 if sideChainRewardBalance.Cmp(rewardPerBlock) == -1 { 644 rewardPerBlock = sideChainRewardBalance 645 } 646 647 state.SubBalance(sideChainRewardAddress, rewardPerBlock) 648 649 coinbaseReward = new(big.Int).Add(rewardPerBlock, tenPercentGasFee) 650 } else { 651 coinbaseReward = tenPercentGasFee 652 } 653 } 654 655 selfDeposit := state.GetDepositBalance(header.Coinbase) 656 totalProxiedDeposit := state.GetTotalDepositProxiedBalance(header.Coinbase) 657 totalDeposit := new(big.Int).Add(selfDeposit, totalProxiedDeposit) 658 659 var selfReward, delegateReward *big.Int 660 if totalProxiedDeposit.Sign() == 0 { 661 selfReward = coinbaseReward 662 } else { 663 selfReward = new(big.Int) 664 665 selfPercent := new(big.Float).Quo(new(big.Float).SetInt(selfDeposit), new(big.Float).SetInt(totalDeposit)) 666 667 new(big.Float).Mul(new(big.Float).SetInt(coinbaseReward), selfPercent).Int(selfReward) 668 669 delegateReward = new(big.Int).Sub(coinbaseReward, selfReward) 670 commission := state.GetCommission(header.Coinbase) 671 if commission > 0 { 672 673 commissionReward := new(big.Int).Mul(delegateReward, big.NewInt(int64(commission))) 674 commissionReward.Quo(commissionReward, big.NewInt(100)) 675 676 selfReward.Add(selfReward, commissionReward) 677 678 delegateReward.Sub(delegateReward, commissionReward) 679 } 680 } 681 682 state.AddRewardBalanceByDelegateAddress(header.Coinbase, header.Coinbase, selfReward) 683 684 if delegateReward != nil && delegateReward.Sign() > 0 { 685 totalIndividualReward := big.NewInt(0) 686 687 state.ForEachProxied(header.Coinbase, func(key common.Address, proxiedBalance, depositProxiedBalance, pendingRefundBalance *big.Int) bool { 688 if depositProxiedBalance.Sign() == 1 { 689 690 individualReward := new(big.Int).Quo(new(big.Int).Mul(depositProxiedBalance, delegateReward), totalProxiedDeposit) 691 692 state.AddRewardBalanceByDelegateAddress(key, header.Coinbase, individualReward) 693 694 totalIndividualReward.Add(totalIndividualReward, individualReward) 695 } 696 return true 697 }) 698 699 cmp := delegateReward.Cmp(totalIndividualReward) 700 if cmp == 1 { 701 702 diff := new(big.Int).Sub(delegateReward, totalIndividualReward) 703 704 state.AddRewardBalanceByDelegateAddress(header.Coinbase, header.Coinbase, diff) 705 } else if cmp == -1 { 706 707 diff := new(big.Int).Sub(totalIndividualReward, delegateReward) 708 709 state.SubRewardBalanceByDelegateAddress(header.Coinbase, header.Coinbase, diff) 710 } 711 } 712 713 }