github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/consensus/ipbft/engine.go (about) 1 package ipbft 2 3 import ( 4 "bytes" 5 "errors" 6 "github.com/hashicorp/golang-lru" 7 "github.com/intfoundation/go-wire" 8 "github.com/intfoundation/intchain/common" 9 "github.com/intfoundation/intchain/consensus" 10 "github.com/intfoundation/intchain/consensus/ipbft/epoch" 11 tdmTypes "github.com/intfoundation/intchain/consensus/ipbft/types" 12 "github.com/intfoundation/intchain/core/state" 13 "github.com/intfoundation/intchain/core/types" 14 "github.com/intfoundation/intchain/params" 15 "github.com/intfoundation/intchain/rpc" 16 "math/big" 17 "time" 18 ) 19 20 const ( 21 // fetcherID is the ID indicates the block is from Tendermint engine 22 fetcherID = "ipbft" 23 ) 24 25 var ( 26 // errInvalidProposal is returned when a prposal is malformed. 27 errInvalidProposal = errors.New("invalid proposal") 28 // errInvalidSignature is returned when given signature is not signed by given 29 // address. 30 errInvalidSignature = errors.New("invalid signature") 31 // errUnknownBlock is returned when the list of validators is requested for a block 32 // that is not part of the local blockchain. 33 errUnknownBlock = errors.New("unknown block") 34 // errUnauthorized is returned if a header is signed by a non authorized entity. 35 errUnauthorized = errors.New("unauthorized") 36 // errInvalidDifficulty is returned if the difficulty of a block is not 1 37 errInvalidDifficulty = errors.New("invalid difficulty") 38 // errInvalidExtraDataFormat is returned when the extra data format is incorrect 39 errInvalidExtraDataFormat = errors.New("invalid extra data format") 40 // errInvalidMixDigest is returned if a block's mix digest is not Istanbul digest. 41 errInvalidMixDigest = errors.New("invalid Tendermint mix digest") 42 // errInvalidNonce is returned if a block's nonce is invalid 43 errInvalidNonce = errors.New("invalid nonce") 44 // errInvalidUncleHash is returned if a block contains an non-empty uncle list. 45 errInvalidUncleHash = errors.New("non empty uncle hash") 46 // errInconsistentValidatorSet is returned if the validator set is inconsistent 47 errInconsistentValidatorSet = errors.New("inconsistent validator set") 48 // errInvalidTimestamp is returned if the timestamp of a block is lower than the previous block's timestamp + the minimum block period. 49 errInvalidTimestamp = errors.New("invalid timestamp") 50 // errInvalidVotingChain is returned if an authorization list is attempted to 51 // be modified via out-of-range or non-contiguous headers. 52 errInvalidVotingChain = errors.New("invalid voting chain") 53 // errInvalidVote is returned if a nonce value is something else that the two 54 // allowed constants of 0x00..0 or 0xff..f. 55 errInvalidVote = errors.New("vote nonce not 0x00..0 or 0xff..f") 56 // errInvalidCommittedSeals is returned if the committed seal is not signed by any of parent validators. 57 errInvalidCommittedSeals = errors.New("invalid committed seals") 58 // errEmptyCommittedSeals is returned if the field of committed seals is zero. 59 errEmptyCommittedSeals = errors.New("zero committed seals") 60 // errMismatchTxhashes is returned if the TxHash in header is mismatch. 61 errMismatchTxhashes = errors.New("mismatch transactions hashes") 62 63 // errInvalidMainChainNumber is returned when child chain block doesn't contain the valid main chain height 64 errInvalidMainChainNumber = errors.New("invalid Main Chain Height") 65 // errMainChainNotCatchup is returned if child chain wait more than 300 seconds for main chain to catch up 66 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") 67 ) 68 69 var ( 70 now = time.Now 71 72 inmemoryAddresses = 20 // Number of recent addresses from ecrecover 73 recentAddresses, _ = lru.NewARC(inmemoryAddresses) 74 75 _ consensus.Engine = (*backend)(nil) 76 77 foundationAddress = common.HexToAddress("0x0000000000000000000000000000000000000000") 78 feeAddress = common.HexToAddress("0x0000000000000000000000000000000000000001") 79 80 // Address for Child Chain Reward 81 childChainRewardAddress = common.StringToAddress("0x0000000000000000000000000000000000001003") 82 ) 83 84 // APIs returns the RPC APIs this consensus engine provides. 85 func (sb *backend) APIs(chain consensus.ChainReader) []rpc.API { 86 return []rpc.API{{ 87 Namespace: "int", 88 Version: "1.0", 89 Service: &API{chain: chain, tendermint: sb}, 90 Public: true, 91 }} 92 } 93 94 // Start implements consensus.Tendermint.Start 95 func (sb *backend) Start(chain consensus.ChainReader, currentBlock func() *types.Block, hasBadBlock func(hash common.Hash) bool) error { 96 97 sb.logger.Info("IPBFT backend Start") 98 99 sb.coreMu.Lock() 100 defer sb.coreMu.Unlock() 101 if sb.coreStarted { 102 return ErrStartedEngine 103 } 104 105 // clear previous data 106 sb.proposedBlockHash = common.Hash{} 107 if sb.commitCh != nil { 108 close(sb.commitCh) 109 } 110 sb.commitCh = make(chan *types.Block, 1) 111 if sb.vcommitCh != nil { 112 close(sb.vcommitCh) 113 } 114 sb.vcommitCh = make(chan *tdmTypes.IntermediateBlockResult, 1) 115 116 sb.chain = chain 117 sb.currentBlock = currentBlock 118 sb.hasBadBlock = hasBadBlock 119 120 if _, err := sb.core.Start(); err != nil { 121 return err 122 } 123 124 sb.coreStarted = true 125 126 return nil 127 } 128 129 // Stop implements consensus.Tendermint.Stop 130 func (sb *backend) Stop() error { 131 132 sb.logger.Info("IPBFT backend stop") 133 134 //debug.PrintStack() 135 136 sb.coreMu.Lock() 137 defer sb.coreMu.Unlock() 138 if !sb.coreStarted { 139 return ErrStoppedEngine 140 } 141 if !sb.core.Stop() { 142 return errors.New("ipbft stop error") 143 } 144 sb.coreStarted = false 145 146 return nil 147 } 148 149 func (sb *backend) Close() error { 150 sb.core.epochDB.Close() 151 return nil 152 } 153 154 // Author retrieves the Ethereum address of the account that minted the given 155 // block, which may be different from the header's coinbase if a consensus 156 // engine is based on signatures. 157 func (sb *backend) Author(header *types.Header) (common.Address, error) { 158 return header.Coinbase, nil 159 } 160 161 // VerifyHeader checks whether a header conforms to the consensus rules of a 162 // given engine. Verifying the seal may be done optionally here, or explicitly 163 // via the VerifySeal method. 164 func (sb *backend) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { 165 166 sb.logger.Info("IPBFT backend verify header") 167 168 return sb.verifyHeader(chain, header, nil) 169 } 170 171 // verifyHeader checks whether a header conforms to the consensus rules.The 172 // caller may optionally pass in a batch of parents (ascending order) to avoid 173 // looking those up from the database. This is useful for concurrently verifying 174 // a batch of new headers. 175 func (sb *backend) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 176 177 if header.Number == nil { 178 return errUnknownBlock 179 } 180 181 //if header.Number.Uint64() == 0 { 182 // return nil // Ignore verify for genesis block 183 //} 184 185 // Don't waste time checking blocks from the future 186 if header.Time.Cmp(big.NewInt(now().Unix())) > 0 { 187 sb.logger.Warnf("date/time different between different nodes. block from future with time:%v, bigger than now:%v", header.Time.Uint64(), now().Unix()) 188 //in intchain, avoid the time difference to tolerate time gap between nodes 189 //return consensus.ErrFutureBlock 190 } 191 192 // Ensure that the extra data format is satisfied 193 if _, err := tdmTypes.ExtractTendermintExtra(header); err != nil { 194 return errInvalidExtraDataFormat 195 } 196 197 // Ensure that the coinbase is valid 198 if header.Nonce != (types.TendermintEmptyNonce) && !bytes.Equal(header.Nonce[:], types.TendermintNonce) { 199 return errInvalidNonce 200 } 201 // Ensure that the mix digest is zero as we don't have fork protection currently 202 if header.MixDigest != types.TendermintDigest { 203 return errInvalidMixDigest 204 } 205 // Ensure that the block doesn't contain any uncles which are meaningless in Istanbul 206 if header.UncleHash != types.TendermintNilUncleHash { 207 return errInvalidUncleHash 208 } 209 // Ensure that the block's difficulty is meaningful (may not be correct at this point) 210 if header.Difficulty == nil || header.Difficulty.Cmp(types.TendermintDefaultDifficulty) != 0 { 211 return errInvalidDifficulty 212 } 213 214 // In case of Epoch switch, we have to wait for the Epoch switched first, then verify the following fields 215 if header.Number.Uint64() > sb.GetEpoch().EndBlock { 216 for { 217 duration := 2 * time.Second 218 sb.logger.Infof("IPBFT VerifyHeader, Epoch Switch, wait for %v then try again", duration) 219 time.Sleep(duration) 220 221 if header.Number.Uint64() <= sb.GetEpoch().EndBlock { 222 break 223 } 224 } 225 } 226 227 if fieldError := sb.verifyCascadingFields(chain, header, parents); fieldError != nil { 228 return fieldError 229 } 230 231 // Check the MainChainNumber if on Child Chain 232 if !sb.chainConfig.IsMainChain() { 233 if header.MainChainNumber == nil { 234 return errInvalidMainChainNumber 235 } 236 237 tried := 0 238 for { 239 // Check our main chain has already run ahead 240 ourMainChainHeight := sb.core.cch.GetHeightFromMainChain() 241 if ourMainChainHeight.Cmp(header.MainChainNumber) >= 0 { 242 break 243 } 244 245 if tried == 10 { 246 sb.logger.Warnf("IPBFT VerifyHeader, Main Chain Number mismatch, after retried %d times", tried) 247 return errMainChainNotCatchup 248 } 249 250 // Sleep for a while and check again 251 duration := 30 * time.Second 252 tried++ 253 sb.logger.Infof("IPBFT VerifyHeader, Main Chain Number mismatch, wait for %v then try again (count %d)", duration, tried) 254 time.Sleep(duration) 255 } 256 } 257 258 return nil 259 } 260 261 // verifyCascadingFields verifies all the header fields that are not standalone, 262 // rather depend on a batch of previous headers. The caller may optionally pass 263 // in a batch of parents (ascending order) to avoid looking those up from the 264 // database. This is useful for concurrently verifying a batch of new headers. 265 func (sb *backend) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 266 // The genesis block is the always valid dead-end 267 268 number := header.Number.Uint64() 269 if number == 0 { 270 return nil 271 } 272 // Ensure that the block's timestamp isn't too close to it's parent 273 var parent *types.Header 274 if len(parents) > 0 { 275 parent = parents[len(parents)-1] 276 } else { 277 parent = chain.GetHeader(header.ParentHash, number-1) 278 } 279 if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { 280 return consensus.ErrUnknownAncestor 281 } 282 283 err := sb.verifyCommittedSeals(chain, header, parents) 284 return err 285 } 286 287 func (sb *backend) VerifyHeaderBeforeConsensus(chain consensus.ChainReader, header *types.Header, seal bool) error { 288 sb.logger.Info("IPBFT backend verify header before consensus") 289 290 if header.Number == nil { 291 return errUnknownBlock 292 } 293 294 // Don't waste time checking blocks from the future 295 if header.Time.Cmp(big.NewInt(now().Unix())) > 0 { 296 sb.logger.Warnf("date/time different between different nodes. block from future with time:%v, bigger than now:%v", header.Time.Uint64(), now().Unix()) 297 //in intchain, avoid the time difference to tolerate time gap between nodes 298 //return consensus.ErrFutureBlock 299 } 300 301 // Ensure that the coinbase is valid 302 if header.Nonce != (types.TendermintEmptyNonce) && !bytes.Equal(header.Nonce[:], types.TendermintNonce) { 303 return errInvalidNonce 304 } 305 // Ensure that the mix digest is zero as we don't have fork protection currently 306 if header.MixDigest != types.TendermintDigest { 307 return errInvalidMixDigest 308 } 309 // Ensure that the block doesn't contain any uncles which are meaningless in Istanbul 310 if header.UncleHash != types.TendermintNilUncleHash { 311 return errInvalidUncleHash 312 } 313 // Ensure that the block's difficulty is meaningful (may not be correct at this point) 314 if header.Difficulty == nil || header.Difficulty.Cmp(types.TendermintDefaultDifficulty) != 0 { 315 return errInvalidDifficulty 316 } 317 318 return nil 319 } 320 321 // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers 322 // concurrently. The method returns a quit channel to abort the operations and 323 // a results channel to retrieve the async verifications (the order is that of 324 // the input slice). 325 func (sb *backend) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 326 abort := make(chan struct{}) 327 results := make(chan error, len(headers)) 328 329 sb.logger.Info("IPBFT backend verify headers") 330 331 go func() { 332 for i, header := range headers { 333 err := sb.verifyHeader(chain, header, headers[:i]) 334 select { 335 case <-abort: 336 return 337 case results <- err: 338 } 339 } 340 }() 341 342 return abort, results 343 } 344 345 // VerifyUncles verifies that the given block's uncles conform to the consensus 346 // rules of a given engine. 347 func (sb *backend) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 348 349 if len(block.Uncles()) > 0 { 350 return errInvalidUncleHash 351 } 352 return nil 353 } 354 355 // verifyCommittedSeals checks whether every committed seal is signed by one of the parent's validators 356 func (sb *backend) verifyCommittedSeals(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 357 358 tdmExtra, err := tdmTypes.ExtractTendermintExtra(header) 359 if err != nil { 360 return errInvalidExtraDataFormat 361 } 362 363 epoch := sb.core.consensusState.Epoch 364 if epoch == nil || epoch.Validators == nil { 365 sb.logger.Errorf("verifyCommittedSeals error. Epoch %v", epoch) 366 return errInconsistentValidatorSet 367 } 368 369 epoch = epoch.GetEpochByBlockNumber(header.Number.Uint64()) 370 if epoch == nil || epoch.Validators == nil { 371 sb.logger.Errorf("verifyCommittedSeals error. Epoch %v", epoch) 372 return errInconsistentValidatorSet 373 } 374 375 valSet := epoch.Validators 376 if !bytes.Equal(valSet.Hash(), tdmExtra.ValidatorsHash) { 377 sb.logger.Errorf("verifyCommittedSeals error. Our Validator Set %x, tdmExtra Valdiator %x", valSet.Hash(), tdmExtra.ValidatorsHash) 378 sb.logger.Errorf("verifyCommittedSeals error. epoch validator set %v, extra data %v", valSet.String(), tdmExtra.String()) 379 return errInconsistentValidatorSet 380 } 381 382 seenCommit := tdmExtra.SeenCommit 383 if !bytes.Equal(tdmExtra.SeenCommitHash, seenCommit.Hash()) { 384 sb.logger.Errorf("verifyCommittedSeals SeenCommit is %#+v", seenCommit) 385 sb.logger.Errorf("verifyCommittedSeals error. Our SeenCommitHash %x, tdmExtra SeenCommitHash %x", seenCommit.Hash(), tdmExtra.SeenCommitHash) 386 return errInvalidCommittedSeals 387 } 388 389 if err = valSet.VerifyCommit(tdmExtra.ChainID, tdmExtra.Height, seenCommit); err != nil { 390 sb.logger.Errorf("verifyCommittedSeals verify commit err %v", err) 391 return errInvalidSignature 392 } 393 394 return nil 395 } 396 397 // VerifySeal checks whether the crypto seal on a header is valid according to 398 // the consensus rules of the given engine. 399 func (sb *backend) VerifySeal(chain consensus.ChainReader, header *types.Header) error { 400 // get parent header and ensure the signer is in parent's validator set 401 number := header.Number.Uint64() 402 if number == 0 { 403 return errUnknownBlock 404 } 405 406 // ensure that the difficulty equals to defaultDifficulty 407 if header.Difficulty.Cmp(types.TendermintDefaultDifficulty) != 0 { 408 return errInvalidDifficulty 409 } 410 411 return nil 412 } 413 414 // Prepare initializes the consensus fields of a block header according to the 415 // rules of a particular engine. The changes are executed inline. 416 func (sb *backend) Prepare(chain consensus.ChainReader, header *types.Header) error { 417 418 header.Nonce = types.TendermintEmptyNonce 419 header.MixDigest = types.TendermintDigest 420 421 // copy the parent extra data as the header extra data 422 number := header.Number.Uint64() 423 parent := chain.GetHeader(header.ParentHash, number-1) 424 if parent == nil { 425 return consensus.ErrUnknownAncestor 426 } 427 // use the same difficulty for all blocks 428 header.Difficulty = types.TendermintDefaultDifficulty 429 430 // add validators in snapshot to extraData's validators section 431 extra, err := prepareExtra(header, nil) 432 if err != nil { 433 return err 434 } 435 header.Extra = extra 436 437 // set header's timestamp 438 //header.Time = new(big.Int).Add(parent.Time, new(big.Int).SetUint64(sb.config.BlockPeriod)) 439 //if header.Time.Int64() < time.Now().Unix() { 440 header.Time = big.NewInt(time.Now().Unix()) 441 //} 442 443 // Add Main Chain Height if running on Child Chain 444 if sb.chainConfig.IntChainId != params.MainnetChainConfig.IntChainId && sb.chainConfig.IntChainId != params.TestnetChainConfig.IntChainId { 445 header.MainChainNumber = sb.core.cch.GetHeightFromMainChain() 446 } 447 448 return nil 449 } 450 451 // Finalize runs any post-transaction state modifications (e.g. block rewards) 452 // and assembles the final block. 453 // 454 // Note, the block header and state database might be updated to reflect any 455 // consensus rules that happen at finalization (e.g. block rewards). 456 func (sb *backend) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, 457 totalGasFee *big.Int, uncles []*types.Header, receipts []*types.Receipt, ops *types.PendingOps) (*types.Block, error) { 458 459 sb.logger.Debugf("IPBFT Finalize, receipts are: %v", receipts) 460 461 // Check if any Child Chain need to be launch and Update their account balance accordingly 462 if sb.chainConfig.IntChainId == params.MainnetChainConfig.IntChainId || sb.chainConfig.IntChainId == params.TestnetChainConfig.IntChainId { 463 // Check the Child Chain Start 464 readyId, updateBytes, removedId := sb.core.cch.ReadyForLaunchChildChain(header.Number, state) 465 if len(readyId) > 0 || updateBytes != nil || len(removedId) > 0 { 466 if ok := ops.Append(&types.LaunchChildChainsOp{ 467 ChildChainIds: readyId, 468 NewPendingIdx: updateBytes, 469 DeleteChildChainIds: removedId, 470 }); !ok { 471 // This should not happened 472 sb.logger.Error("IPBFT Finalize, Fail to append LaunchChildChainsOp, only one LaunchChildChainsOp is allowed in each block") 473 } 474 } 475 } 476 477 curBlockNumber := header.Number.Uint64() 478 epoch := sb.GetEpoch().GetEpochByBlockNumber(curBlockNumber) 479 480 genesisHeader := chain.GetBlockByNumber(1) 481 if genesisHeader != nil { 482 genesisCoinbase := genesisHeader.Header().Coinbase 483 foundationAddress = state.GetAddress(genesisCoinbase) 484 } 485 486 // Calculate the rewards 487 accumulateRewards(sb.chainConfig, state, header, epoch, totalGasFee) 488 489 // update validator status include participating consensus block times and forbidden 490 //if header.Number.Uint64() > 1 { 491 // //TODO slash in the future 492 // prevHeader := chain.GetHeaderByNumber(header.Number.Uint64() - 1) 493 // if prevHeader != nil { 494 // extra, err := tdmTypes.ExtractTendermintExtra(prevHeader) 495 // if err == nil { 496 // epoch.UpdateForbiddenState(header, prevHeader, extra.SeenCommit, state) 497 // } 498 // } 499 //} 500 501 // Check the Epoch switch and update their account balance accordingly (Refund the Locked Balance) 502 if ok, newValidators, _ := epoch.ShouldEnterNewEpoch(header.Number.Uint64(), state); ok { 503 ops.Append(&tdmTypes.SwitchEpochOp{ 504 ChainId: sb.chainConfig.IntChainId, 505 NewValidators: newValidators, 506 //NewCandidates: newCandidates, 507 }) 508 509 } 510 511 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 512 header.UncleHash = types.TendermintNilUncleHash 513 // Assemble and return the final block for sealing 514 return types.NewBlock(header, txs, nil, receipts), nil 515 } 516 517 // Seal generates a new block for the given input block with the local miner's 518 // seal place on top. 519 func (sb *backend) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (interface{}, error) { 520 521 sb.logger.Info("IPBFT backend seal") 522 // update the block header timestamp and signature and propose the block to core engine 523 header := block.Header() 524 number := header.Number.Uint64() 525 parent := chain.GetHeader(header.ParentHash, number-1) 526 if parent == nil { 527 return nil, consensus.ErrUnknownAncestor 528 } 529 block, err := sb.updateBlock(parent, block) 530 if err != nil { 531 return nil, err 532 } 533 // wait for the timestamp of header, use this to adjust the block period 534 delay := time.Unix(block.Header().Time.Int64(), 0).Sub(now()) 535 select { 536 case <-time.After(delay): 537 case <-stop: 538 return nil, nil 539 } 540 // get the proposed block hash and clear it if the seal() is completed. 541 sb.sealMu.Lock() 542 sb.proposedBlockHash = block.Hash() 543 clear := func() { 544 sb.proposedBlockHash = common.Hash{} 545 sb.sealMu.Unlock() 546 } 547 defer clear() 548 549 // post block into IPBFT engine 550 sb.logger.Infof("IPBFT Seal, before fire event with block height: %d", block.NumberU64()) 551 go tdmTypes.FireEventRequest(sb.core.EventSwitch(), tdmTypes.EventDataRequest{Proposal: block}) 552 //go sb.EventMux().Post(tdmTypes.RequestEvent{ 553 // Proposal: block, 554 //}) 555 556 for { 557 select { 558 case result, ok := <-sb.commitCh: 559 560 if ok { 561 sb.logger.Debugf("IPBFT Seal, got result with block.Hash: %x, result.Hash: %x", block.Hash(), result.Hash()) 562 // if the block hash and the hash from channel are the same, 563 // return the result. Otherwise, keep waiting the next hash. 564 if block.Hash() == result.Hash() { 565 return result, nil 566 } 567 sb.logger.Debug("IPBFT Seal, hash are different") 568 } else { 569 sb.logger.Debug("IPBFT Seal, has been restart, just return") 570 return nil, nil 571 } 572 573 case iresult, ok := <-sb.vcommitCh: 574 575 if ok { 576 sb.logger.Debugf("IPBFT Seal, v got result with block.Hash: %x, result.Hash: %x", block.Hash(), iresult.Block.Hash()) 577 if block.Hash() != iresult.Block.Hash() { 578 return iresult, nil 579 } 580 sb.logger.Debug("IPBFT Seal, v hash are the same") 581 } else { 582 sb.logger.Debug("IPBFT Seal, v has been restart, just return") 583 return nil, nil 584 } 585 586 case <-stop: 587 sb.logger.Debug("IPBFT Seal, stop") 588 return nil, nil 589 } 590 } 591 592 return nil, nil 593 } 594 595 // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty 596 // that a new block should have based on the previous blocks in the chain and the 597 // current signer. 598 func (sb *backend) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { 599 600 return types.TendermintDefaultDifficulty 601 } 602 603 // Commit implements istanbul.Backend.Commit 604 func (sb *backend) Commit(proposal *tdmTypes.TdmBlock, seals [][]byte, isProposer func() bool) error { 605 // Check if the proposal is a valid block 606 block := proposal.Block 607 608 h := block.Header() 609 // Append seals into extra-data 610 err := writeCommittedSeals(h, proposal.TdmExtra) 611 if err != nil { 612 return err 613 } 614 // update block's header 615 block = block.WithSeal(h) 616 617 sb.logger.Debugf("IPBFT Commit, hash: %x, number: %v", block.Hash(), block.Number().Int64()) 618 sb.logger.Debugf("IPBFT Commit, block: %s", block.String()) 619 620 // - if the proposed and committed blocks are the same, send the proposed hash 621 // to commit channel, which is being watched inside the engine.Seal() function. 622 // - otherwise, we try to insert the block. 623 // -- if success, the ChainHeadEvent event will be broadcasted, try to build 624 // the next block and the previous Seal() will be stopped. 625 // -- otherwise, a error will be returned and a round change event will be fired. 626 if isProposer() && (sb.proposedBlockHash == block.Hash()) { // for proposer 627 // feed block hash to Seal() and wait the Seal() result 628 sb.logger.Debugf("IPBFT Commit, proposer | feed to Seal: %x", block.Hash()) 629 sb.commitCh <- block 630 return nil 631 } else { // for other validators 632 if proposal.IntermediateResult != nil { 633 sb.logger.Debugf("IPBFT Commit, validator | feed to Seal: %x", block.Hash()) 634 proposal.IntermediateResult.Block = block 635 sb.vcommitCh <- proposal.IntermediateResult 636 } else { 637 sb.logger.Debugf("IPBFT Commit, validator | fetcher enqueue: %x", block.Hash()) 638 if sb.broadcaster != nil { 639 sb.broadcaster.Enqueue(fetcherID, block) 640 } 641 } 642 return nil 643 } 644 } 645 646 // Stop implements consensus.Istanbul.Stop 647 func (sb *backend) ChainReader() consensus.ChainReader { 648 649 return sb.chain 650 } 651 652 func (sb *backend) ShouldStart() bool { 653 return sb.shouldStart 654 } 655 656 func (sb *backend) IsStarted() bool { 657 sb.coreMu.RLock() 658 start := sb.coreStarted 659 sb.coreMu.RUnlock() 660 661 return start 662 } 663 664 func (sb *backend) ForceStart() { 665 sb.shouldStart = true 666 } 667 668 // GetEpoch Get Epoch from Tendermint Engine 669 func (sb *backend) GetEpoch() *epoch.Epoch { 670 return sb.core.consensusState.Epoch 671 } 672 673 // SetEpoch Set Epoch to Tendermint Engine 674 func (sb *backend) SetEpoch(ep *epoch.Epoch) { 675 sb.core.consensusState.Epoch = ep 676 } 677 678 // Return the private validator address of consensus 679 func (sb *backend) PrivateValidator() common.Address { 680 if sb.core.privValidator != nil { 681 return sb.core.privValidator.Address 682 } 683 return common.Address{} 684 } 685 686 // update timestamp and signature of the block based on its number of transactions 687 func (sb *backend) updateBlock(parent *types.Header, block *types.Block) (*types.Block, error) { 688 689 sb.logger.Debug("IPBFT backend update block") 690 691 header := block.Header() 692 /* 693 //sign the hash 694 seal, err := sb.Sign(sigHash(header).Bytes()) 695 if err != nil { 696 return nil, err 697 } 698 */ 699 //err := writeSeal(header, seal) 700 err := writeSeal(header, []byte{}) 701 if err != nil { 702 return nil, err 703 } 704 705 return block.WithSeal(header), nil 706 } 707 708 // prepareExtra returns a extra-data of the given header and validators 709 func prepareExtra(header *types.Header, vals []common.Address) ([]byte, error) { 710 711 //logger.Info("IPBFT (backend) prepare extra ") 712 713 header.Extra = types.MagicExtra 714 return nil, nil 715 } 716 717 // writeSeal writes the extra-data field of the given header with the given seals. 718 // suggest to rename to writeSeal. 719 func writeSeal(h *types.Header, seal []byte) error { 720 721 //logger.Info("IPBFT backend write seal") 722 if h.Extra == nil { 723 payload := types.MagicExtra 724 h.Extra = payload 725 } 726 return nil 727 } 728 729 // writeCommittedSeals writes the extra-data field of a block header with given committed seals. 730 func writeCommittedSeals(h *types.Header, tdmExtra *tdmTypes.TendermintExtra) error { 731 732 //logger.Info("IPBFT backend write committed seals") 733 h.Extra = wire.BinaryBytes(*tdmExtra) 734 return nil 735 } 736 737 // AccumulateRewards credits the coinbase of the given block with the mining reward. 738 // Main Chain: 739 // The total reward consists of the static block reward of the Epoch and total tx gas fee. 740 // Child Chain: 741 // The total reward consists of the static block reward of Owner setup and total tx gas fee. 742 // 743 // If the coinbase is Candidate, divide the rewards by weight 744 func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, ep *epoch.Epoch, totalGasFee *big.Int) { 745 halfGasFee := big.NewInt(0).Div(totalGasFee, big.NewInt(2)) 746 state.AddBalance(feeAddress, halfGasFee) 747 748 var coinbaseReward *big.Int 749 if config.IntChainId == params.MainnetChainConfig.IntChainId || config.IntChainId == params.TestnetChainConfig.IntChainId { 750 rewardPerBlock := ep.RewardPerBlock 751 if rewardPerBlock != nil && rewardPerBlock.Sign() == 1 { 752 zeroAddress := common.Address{} 753 if foundationAddress == zeroAddress { 754 coinbaseReward = big.NewInt(0) 755 coinbaseReward.Add(rewardPerBlock, halfGasFee) 756 } else { 757 coinbaseReward = new(big.Int).Mul(rewardPerBlock, big.NewInt(8)) 758 coinbaseReward.Quo(coinbaseReward, big.NewInt(10)) 759 foundationReward := new(big.Int).Sub(rewardPerBlock, coinbaseReward) 760 state.AddBalance(foundationAddress, foundationReward) 761 coinbaseReward.Add(coinbaseReward, halfGasFee) 762 } 763 } else { 764 coinbaseReward = halfGasFee 765 } 766 } else { 767 rewardPerBlock := state.GetChildChainRewardPerBlock() 768 if rewardPerBlock != nil && rewardPerBlock.Sign() == 1 { 769 childChainRewardBalance := state.GetBalance(childChainRewardAddress) 770 if childChainRewardBalance.Cmp(rewardPerBlock) == -1 { 771 rewardPerBlock = childChainRewardBalance 772 } 773 // sub balance from childChainRewardAddress, reward per blocks 774 state.SubBalance(childChainRewardAddress, rewardPerBlock) 775 776 coinbaseReward = new(big.Int).Add(rewardPerBlock, halfGasFee) 777 } else { 778 coinbaseReward = halfGasFee 779 } 780 } 781 782 // Coinbase Reward = Self Reward + Delegate Reward (if Deposit Proxied Balance > 0) 783 // 784 // IF commission > 0 785 // Self Reward = Self Reward + Commission Reward 786 // Commission Reward = Delegate Reward * Commission / 100 787 788 // Deposit Part 789 selfDeposit := state.GetDepositBalance(header.Coinbase) 790 totalProxiedDeposit := state.GetTotalDepositProxiedBalance(header.Coinbase) 791 totalDeposit := new(big.Int).Add(selfDeposit, totalProxiedDeposit) 792 793 var selfReward, delegateReward *big.Int 794 if totalProxiedDeposit.Sign() == 0 { 795 selfReward = coinbaseReward 796 } else { 797 selfReward = new(big.Int) 798 // selfPercent = selfDeposit / totalDeposit 799 selfPercent := new(big.Float).Quo(new(big.Float).SetInt(selfDeposit), new(big.Float).SetInt(totalDeposit)) 800 801 // selfReward = coinbaseReward * selfPercent 802 new(big.Float).Mul(new(big.Float).SetInt(coinbaseReward), selfPercent).Int(selfReward) 803 804 // delegateReward = coinbaseReward - selfReward 805 delegateReward = new(big.Int).Sub(coinbaseReward, selfReward) 806 commission := state.GetCommission(header.Coinbase) 807 if commission > 0 { 808 // commissionReward = delegateReward * commission / 100 809 commissionReward := new(big.Int).Mul(delegateReward, big.NewInt(int64(commission))) 810 commissionReward.Quo(commissionReward, big.NewInt(100)) 811 812 // Add the commission to self reward selfReward = selfReward + commissionReward 813 selfReward.Add(selfReward, commissionReward) 814 815 // Sub the commission from delegate reward delegateReward = delegateReward - commissionReward 816 delegateReward.Sub(delegateReward, commissionReward) 817 } 818 } 819 820 // Move the self reward to Reward Trie 821 //divideRewardByEpoch(state, header.Coinbase, ep.Number, selfReward) 822 state.AddRewardBalanceByDelegateAddress(header.Coinbase, header.Coinbase, selfReward) 823 //state.MarkAddressReward(header.Coinbase) 824 825 // Calculate the Delegate Reward 826 if delegateReward != nil && delegateReward.Sign() > 0 { 827 totalIndividualReward := big.NewInt(0) 828 // Split the reward based on Weight stack 829 state.ForEachProxied(header.Coinbase, func(key common.Address, proxiedBalance, depositProxiedBalance, pendingRefundBalance *big.Int) bool { 830 if depositProxiedBalance.Sign() == 1 { 831 // deposit * delegateReward / total deposit 832 individualReward := new(big.Int).Quo(new(big.Int).Mul(depositProxiedBalance, delegateReward), totalProxiedDeposit) 833 //divideRewardByEpoch(state, key, ep.Number, individualReward) 834 state.AddRewardBalanceByDelegateAddress(key, header.Coinbase, individualReward) 835 //state.MarkAddressReward(key) 836 totalIndividualReward.Add(totalIndividualReward, individualReward) 837 } 838 return true 839 }) 840 // Recheck the Total Individual Reward, Float the difference 841 cmp := delegateReward.Cmp(totalIndividualReward) 842 if cmp == 1 { 843 // if delegate reward > actual given reward, give remaining reward to Candidate 844 diff := new(big.Int).Sub(delegateReward, totalIndividualReward) 845 //state.AddRewardBalanceByEpochNumber(header.Coinbase, ep.Number, diff) 846 state.AddRewardBalanceByDelegateAddress(header.Coinbase, header.Coinbase, diff) 847 } else if cmp == -1 { 848 // if delegate reward < actual given reward, subtract the diff from Candidate 849 diff := new(big.Int).Sub(totalIndividualReward, delegateReward) 850 //state.SubRewardBalanceByEpochNumber(header.Coinbase, ep.Number, diff) 851 state.SubRewardBalanceByDelegateAddress(header.Coinbase, header.Coinbase, diff) 852 } 853 } 854 855 //err := state.MarkProposedInEpoch(header.Coinbase, ep.Number) 856 //if err != nil { 857 // fmt.Printf("Mark validator proposed failed, error: %v\n", err) 858 //} 859 } 860 861 //func divideRewardByEpoch(state *state.StateDB, addr common.Address, epochNumber uint64, reward *big.Int) { 862 // epochReward := new(big.Int).Quo(reward, big.NewInt(12)) 863 // lastEpochReward := new(big.Int).Set(reward) 864 // for i := epochNumber; i < epochNumber+12; i++ { 865 // if i == epochNumber+11 { 866 // state.AddRewardBalanceByEpochNumber(addr, i, lastEpochReward) 867 // } else { 868 // state.AddRewardBalanceByEpochNumber(addr, i, epochReward) 869 // lastEpochReward.Sub(lastEpochReward, epochReward) 870 // } 871 // } 872 // state.MarkAddressReward(addr) 873 //}