github.com/Gessiux/neatchain@v1.3.1/chain/consensus/neatcon/engine.go (about) 1 package neatcon 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "math/big" 8 "time" 9 10 "github.com/Gessiux/go-wire" 11 "github.com/Gessiux/neatchain/chain/consensus" 12 "github.com/Gessiux/neatchain/chain/consensus/neatcon/epoch" 13 ntcTypes "github.com/Gessiux/neatchain/chain/consensus/neatcon/types" 14 "github.com/Gessiux/neatchain/chain/core/state" 15 "github.com/Gessiux/neatchain/chain/core/types" 16 "github.com/Gessiux/neatchain/network/rpc" 17 "github.com/Gessiux/neatchain/params" 18 "github.com/Gessiux/neatchain/utilities/common" 19 lru "github.com/hashicorp/golang-lru" 20 ) 21 22 const ( 23 // fetcherID is the ID indicates the block is from NeatCon engine 24 fetcherID = "neatcon" 25 ) 26 27 var ( 28 // errInvalidProposal is returned when a prposal is malformed. 29 errInvalidProposal = errors.New("invalid proposal") 30 // errInvalidSignature is returned when given signature is not signed by given 31 // address. 32 errInvalidSignature = errors.New("invalid signature") 33 // errUnknownBlock is returned when the list of validators is requested for a block 34 // that is not part of the local blockchain. 35 errUnknownBlock = errors.New("unknown block") 36 // errUnauthorized is returned if a header is signed by a non authorized entity. 37 errUnauthorized = errors.New("unauthorized") 38 // errInvalidDifficulty is returned if the difficulty of a block is not 1 39 errInvalidDifficulty = errors.New("invalid difficulty") 40 // errInvalidExtraDataFormat is returned when the extra data format is incorrect 41 errInvalidExtraDataFormat = errors.New("invalid extra data format") 42 // errInvalidMixDigest is returned if a block's mix digest is not Istanbul digest. 43 errInvalidMixDigest = errors.New("invalid NeatCon mix digest") 44 // errInvalidNonce is returned if a block's nonce is invalid 45 errInvalidNonce = errors.New("invalid nonce") 46 // errInvalidUncleHash is returned if a block contains an non-empty uncle list. 47 errInvalidUncleHash = errors.New("non empty uncle hash") 48 // errInconsistentValidatorSet is returned if the validator set is inconsistent 49 errInconsistentValidatorSet = errors.New("inconsistent validator set") 50 // errInvalidTimestamp is returned if the timestamp of a block is lower than the previous block's timestamp + the minimum block period. 51 errInvalidTimestamp = errors.New("invalid timestamp") 52 // errInvalidVotingChain is returned if an authorization list is attempted to 53 // be modified via out-of-range or non-contiguous headers. 54 errInvalidVotingChain = errors.New("invalid voting chain") 55 // errInvalidVote is returned if a nonce value is something else that the two 56 // allowed constants of 0x00..0 or 0xff..f. 57 errInvalidVote = errors.New("vote nonce not 0x00..0 or 0xff..f") 58 // errInvalidCommittedSeals is returned if the committed seal is not signed by any of parent validators. 59 errInvalidCommittedSeals = errors.New("invalid committed seals") 60 // errEmptyCommittedSeals is returned if the field of committed seals is zero. 61 errEmptyCommittedSeals = errors.New("zero committed seals") 62 // errMismatchTxhashes is returned if the TxHash in header is mismatch. 63 errMismatchTxhashes = errors.New("mismatch transactions hashes") 64 65 // errInvalidMainChainNumber is returned when side chain block doesn't contain the valid main chain height 66 errInvalidMainChainNumber = errors.New("invalid Main Chain Height") 67 // errMainChainNotCatchup is returned if side chain wait more than 300 seconds for main chain to catch up 68 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") 69 ) 70 71 var ( 72 now = time.Now 73 74 inmemoryAddresses = 20 // Number of recent addresses from ecrecover 75 recentAddresses, _ = lru.NewARC(inmemoryAddresses) 76 77 _ consensus.Engine = (*backend)(nil) 78 79 // Address for Side Chain Reward 80 sideChainRewardAddress = common.StringToAddress("NEAToND9QsiAFbMan5tqVg899qAv2EsQ") 81 ) 82 83 // APIs returns the RPC APIs this consensus engine provides. 84 func (sb *backend) APIs(chain consensus.ChainReader) []rpc.API { 85 return []rpc.API{{ 86 Namespace: "neat", 87 Version: "1.0", 88 Service: &API{chain: chain, neatcon: sb}, 89 Public: true, 90 }} 91 } 92 93 // Start implements consensus.NeatCon.Start 94 func (sb *backend) Start(chain consensus.ChainReader, currentBlock func() *types.Block, hasBadBlock func(hash common.Hash) bool) error { 95 96 sb.logger.Info("NeatCon backend Start") 97 98 sb.coreMu.Lock() 99 defer sb.coreMu.Unlock() 100 if sb.coreStarted { 101 return ErrStartedEngine 102 } 103 104 // clear previous data 105 sb.proposedBlockHash = common.Hash{} 106 if sb.commitCh != nil { 107 close(sb.commitCh) 108 } 109 sb.commitCh = make(chan *types.Block, 1) 110 if sb.vcommitCh != nil { 111 close(sb.vcommitCh) 112 } 113 sb.vcommitCh = make(chan *ntcTypes.IntermediateBlockResult, 1) 114 115 sb.chain = chain 116 fmt.Printf("neatcon backend start chain %v\n", 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.NeatCon.Stop 130 func (sb *backend) Stop() error { 131 132 sb.logger.Info("NeatCon 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("neatcon 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("Your node is synchronized. This is Neat!") 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 neatchain, 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 := ntcTypes.ExtractNeatConExtra(header); err != nil { 194 return errInvalidExtraDataFormat 195 } 196 197 // Ensure that the coinbase is valid 198 if header.Nonce != (types.NeatConEmptyNonce) && !bytes.Equal(header.Nonce[:], types.NeatConNonce) { 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.NeatConDigest { 203 return errInvalidMixDigest 204 } 205 // Ensure that the block doesn't contain any uncles which are meaningless in Istanbul 206 if header.UncleHash != types.NeatConNilUncleHash { 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.NeatConDefaultDifficulty) != 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("NeatCon 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 Side 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("NeatCon 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("NeatCon 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("NeatCon 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 neatchain, 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.NeatConEmptyNonce) && !bytes.Equal(header.Nonce[:], types.NeatConNonce) { 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.NeatConDigest { 307 return errInvalidMixDigest 308 } 309 // Ensure that the block doesn't contain any uncles which are meaningless in Istanbul 310 if header.UncleHash != types.NeatConNilUncleHash { 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.NeatConDefaultDifficulty) != 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("NeatCon is verifying 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 ncExtra, err := ntcTypes.ExtractNeatConExtra(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(), ncExtra.ValidatorsHash) { 377 sb.logger.Errorf("verifyCommittedSeals error. Our Validator Set %x, ncExtra Valdiator %x", valSet.Hash(), ncExtra.ValidatorsHash) 378 sb.logger.Errorf("verifyCommittedSeals error. epoch validator set %v, extra data %v", valSet.String(), ncExtra.String()) 379 return errInconsistentValidatorSet 380 } 381 382 seenCommit := ncExtra.SeenCommit 383 if !bytes.Equal(ncExtra.SeenCommitHash, seenCommit.Hash()) { 384 sb.logger.Errorf("verifyCommittedSeals SeenCommit is %#+v", seenCommit) 385 sb.logger.Errorf("verifyCommittedSeals error. Our SeenCommitHash %x, ncExtra SeenCommitHash %x", seenCommit.Hash(), ncExtra.SeenCommitHash) 386 return errInvalidCommittedSeals 387 } 388 389 if err = valSet.VerifyCommit(ncExtra.ChainID, ncExtra.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.NeatConDefaultDifficulty) != 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.NeatConEmptyNonce 419 header.MixDigest = types.NeatConDigest 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.NeatConDefaultDifficulty 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 Side Chain 444 if sb.chainConfig.NeatChainId != params.MainnetChainConfig.NeatChainId && sb.chainConfig.NeatChainId != params.TestnetChainConfig.NeatChainId { 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("NeatCon Finalize, receipts are: %v", receipts) 460 461 // Check if any Side Chain need to be launch and Update their account balance accordingly 462 if sb.chainConfig.NeatChainId == params.MainnetChainConfig.NeatChainId || sb.chainConfig.NeatChainId == params.TestnetChainConfig.NeatChainId { 463 // Check the Side Chain Start 464 readyId, updateBytes, removedId := sb.core.cch.ReadyForLaunchSideChain(header.Number, state) 465 if len(readyId) > 0 || updateBytes != nil || len(removedId) > 0 { 466 if ok := ops.Append(&types.LaunchSideChainsOp{ 467 SideChainIds: readyId, 468 NewPendingIdx: updateBytes, 469 DeleteSideChainIds: removedId, 470 }); !ok { 471 // This should not happened 472 sb.logger.Error("NeatCon Finalize, Fail to append LaunchSideChainsOp, only one LaunchSideChainsOp is allowed in each block") 473 } 474 } 475 } 476 477 curBlockNumber := header.Number.Uint64() 478 epoch := sb.GetEpoch().GetEpochByBlockNumber(curBlockNumber) 479 480 // Calculate the rewards 481 accumulateRewards(sb.chainConfig, state, header, epoch, totalGasFee) 482 483 // update validator status include participating consensus block times and forbidden 484 if header.Number.Uint64() > 1 { 485 //TODO use chain instead of sb.chain 486 prevHeader := chain.GetHeaderByNumber(header.Number.Uint64() - 1) 487 if prevHeader != nil { 488 extra, err := ntcTypes.ExtractNeatConExtra(prevHeader) 489 if err == nil { 490 epoch.UpdateForbiddenState(header, prevHeader, extra.SeenCommit, state) 491 } 492 } 493 } 494 495 // Check the Epoch switch and update their account balance accordingly (Refund the Locked Balance) 496 if ok, newValidators, _ := epoch.ShouldEnterNewEpoch(header.Number.Uint64(), state); ok { 497 ops.Append(&ntcTypes.SwitchEpochOp{ 498 ChainId: sb.chainConfig.NeatChainId, 499 NewValidators: newValidators, 500 }) 501 502 } 503 504 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 505 header.UncleHash = types.NeatConNilUncleHash 506 // Assemble and return the final block for sealing 507 return types.NewBlock(header, txs, nil, receipts), nil 508 } 509 510 // Seal generates a new block for the given input block with the local miner's 511 // seal place on top. 512 func (sb *backend) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (interface{}, error) { 513 514 sb.logger.Info("NeatCon backend seal") 515 // update the block header timestamp and signature and propose the block to core engine 516 header := block.Header() 517 number := header.Number.Uint64() 518 parent := chain.GetHeader(header.ParentHash, number-1) 519 if parent == nil { 520 return nil, consensus.ErrUnknownAncestor 521 } 522 block, err := sb.updateBlock(parent, block) 523 if err != nil { 524 return nil, err 525 } 526 // wait for the timestamp of header, use this to adjust the block period 527 delay := time.Unix(block.Header().Time.Int64(), 0).Sub(now()) 528 select { 529 case <-time.After(delay): 530 case <-stop: 531 return nil, nil 532 } 533 // get the proposed block hash and clear it if the seal() is completed. 534 sb.sealMu.Lock() 535 sb.proposedBlockHash = block.Hash() 536 clear := func() { 537 sb.proposedBlockHash = common.Hash{} 538 sb.sealMu.Unlock() 539 } 540 defer clear() 541 542 // post block into NeatCon engine 543 sb.logger.Infof("NeatCon Seal, before fire event with block height: %d", block.NumberU64()) 544 go ntcTypes.FireEventRequest(sb.core.EventSwitch(), ntcTypes.EventDataRequest{Proposal: block}) 545 //go sb.EventMux().Post(ntcTypes.RequestEvent{ 546 // Proposal: block, 547 //}) 548 549 for { 550 select { 551 case result, ok := <-sb.commitCh: 552 553 if ok { 554 sb.logger.Debugf("NeatCon Seal, got result with block.Hash: %x, result.Hash: %x", block.Hash(), result.Hash()) 555 // if the block hash and the hash from channel are the same, 556 // return the result. Otherwise, keep waiting the next hash. 557 if block.Hash() == result.Hash() { 558 return result, nil 559 } 560 sb.logger.Debug("NeatCon Seal, hash are different") 561 } else { 562 sb.logger.Debug("NeatCon Seal, has been restart, just return") 563 return nil, nil 564 } 565 566 case iresult, ok := <-sb.vcommitCh: 567 568 if ok { 569 sb.logger.Debugf("NeatCon Seal, v got result with block.Hash: %x, result.Hash: %x", block.Hash(), iresult.Block.Hash()) 570 if block.Hash() != iresult.Block.Hash() { 571 return iresult, nil 572 } 573 sb.logger.Debug("NeatCon Seal, v hash are the same") 574 } else { 575 sb.logger.Debug("NeatCon Seal, v has been restart, just return") 576 return nil, nil 577 } 578 579 case <-stop: 580 sb.logger.Debug("NeatCon Seal, stop") 581 return nil, nil 582 } 583 } 584 585 return nil, nil 586 } 587 588 // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty 589 // that a new block should have based on the previous blocks in the chain and the 590 // current signer. 591 func (sb *backend) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { 592 593 return types.NeatConDefaultDifficulty 594 } 595 596 // Commit implements istanbul.Backend.Commit 597 func (sb *backend) Commit(proposal *ntcTypes.NCBlock, seals [][]byte, isProposer func() bool) error { 598 // Check if the proposal is a valid block 599 block := proposal.Block 600 601 h := block.Header() 602 // Append seals into extra-data 603 err := writeCommittedSeals(h, proposal.NTCExtra) 604 if err != nil { 605 return err 606 } 607 // update block's header 608 block = block.WithSeal(h) 609 610 sb.logger.Debugf("NeatCon Commit, hash: %x, number: %v", block.Hash(), block.Number().Int64()) 611 sb.logger.Debugf("NeatCon Commit, block: %s", block.String()) 612 613 // - if the proposed and committed blocks are the same, send the proposed hash 614 // to commit channel, which is being watched inside the engine.Seal() function. 615 // - otherwise, we try to insert the block. 616 // -- if success, the ChainHeadEvent event will be broadcasted, try to build 617 // the next block and the previous Seal() will be stopped. 618 // -- otherwise, a error will be returned and a round change event will be fired. 619 if isProposer() && (sb.proposedBlockHash == block.Hash()) { // for proposer 620 // feed block hash to Seal() and wait the Seal() result 621 sb.logger.Debugf("NeatCon Commit, proposer | feed to Seal: %x", block.Hash()) 622 sb.commitCh <- block 623 return nil 624 } else { // for other validators 625 if proposal.IntermediateResult != nil { 626 sb.logger.Debugf("NeatCon Commit, validator | feed to Seal: %x", block.Hash()) 627 proposal.IntermediateResult.Block = block 628 sb.vcommitCh <- proposal.IntermediateResult 629 } else { 630 sb.logger.Debugf("NeatCon Commit, validator | fetcher enqueue: %x", block.Hash()) 631 if sb.broadcaster != nil { 632 sb.broadcaster.Enqueue(fetcherID, block) 633 } 634 } 635 return nil 636 } 637 } 638 639 // Stop implements consensus.Istanbul.Stop 640 func (sb *backend) ChainReader() consensus.ChainReader { 641 642 return sb.chain 643 } 644 645 func (sb *backend) ShouldStart() bool { 646 return sb.shouldStart 647 } 648 649 func (sb *backend) IsStarted() bool { 650 sb.coreMu.RLock() 651 start := sb.coreStarted 652 sb.coreMu.RUnlock() 653 654 return start 655 } 656 657 func (sb *backend) ForceStart() { 658 sb.shouldStart = true 659 } 660 661 // GetEpoch Get Epoch from NeatCon Engine 662 func (sb *backend) GetEpoch() *epoch.Epoch { 663 return sb.core.consensusState.Epoch 664 } 665 666 // SetEpoch Set Epoch to NeatCon Engine 667 func (sb *backend) SetEpoch(ep *epoch.Epoch) { 668 sb.core.consensusState.Epoch = ep 669 } 670 671 // Return the private validator address of consensus 672 func (sb *backend) PrivateValidator() common.Address { 673 if sb.core.privValidator != nil { 674 return sb.core.privValidator.Address 675 } 676 return common.Address{} 677 } 678 679 // update timestamp and signature of the block based on its number of transactions 680 func (sb *backend) updateBlock(parent *types.Header, block *types.Block) (*types.Block, error) { 681 682 sb.logger.Debug("NeatCon backend update block") 683 684 header := block.Header() 685 /* 686 //sign the hash 687 seal, err := sb.Sign(sigHash(header).Bytes()) 688 if err != nil { 689 return nil, err 690 } 691 */ 692 //err := writeSeal(header, seal) 693 err := writeSeal(header, []byte{}) 694 if err != nil { 695 return nil, err 696 } 697 698 return block.WithSeal(header), nil 699 } 700 701 // prepareExtra returns a extra-data of the given header and validators 702 func prepareExtra(header *types.Header, vals []common.Address) ([]byte, error) { 703 704 //logger.Info("NeatCon (backend) prepare extra ") 705 706 header.Extra = types.MagicExtra 707 return nil, nil 708 } 709 710 // writeSeal writes the extra-data field of the given header with the given seals. 711 // suggest to rename to writeSeal. 712 func writeSeal(h *types.Header, seal []byte) error { 713 714 //logger.Info("NeatCon backend write seal") 715 payload := types.MagicExtra 716 h.Extra = payload 717 return nil 718 } 719 720 // writeCommittedSeals writes the extra-data field of a block header with given committed seals. 721 func writeCommittedSeals(h *types.Header, ncExtra *ntcTypes.NeatConExtra) error { 722 723 //logger.Info("NeatCon backend write committed seals") 724 h.Extra = wire.BinaryBytes(*ncExtra) 725 return nil 726 } 727 728 // AccumulateRewards credits the coinbase of the given block with the mining reward. 729 // Main Chain: 730 // The total reward consists of the static block reward of the Epoch and total tx gas fee. 731 // Side Chain: 732 // The total reward consists of the static block reward of Owner setup and total tx gas fee. 733 // 734 // If the coinbase is Candidate, divide the rewards by weight 735 func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, ep *epoch.Epoch, totalGasFee *big.Int) { 736 // Total Reward = Block Reward + Total Gas Fee 737 var coinbaseReward *big.Int 738 if config.NeatChainId == params.MainnetChainConfig.NeatChainId || config.NeatChainId == params.TestnetChainConfig.NeatChainId { 739 // Main Chain 740 741 rewardPerBlock := ep.RewardPerBlock 742 if rewardPerBlock != nil && rewardPerBlock.Sign() == 1 { 743 coinbaseReward = big.NewInt(0) 744 coinbaseReward.Add(rewardPerBlock, totalGasFee) 745 } else { 746 coinbaseReward = totalGasFee 747 } 748 } else { 749 // Side Chain 750 rewardPerBlock := state.GetSideChainRewardPerBlock() 751 if rewardPerBlock != nil && rewardPerBlock.Sign() == 1 { 752 sideChainRewardBalance := state.GetBalance(sideChainRewardAddress) 753 if sideChainRewardBalance.Cmp(rewardPerBlock) == -1 { 754 rewardPerBlock = sideChainRewardBalance 755 } 756 // sub balance from sideChainRewardAddress, reward per blocks 757 state.SubBalance(sideChainRewardAddress, rewardPerBlock) 758 759 coinbaseReward = new(big.Int).Add(rewardPerBlock, totalGasFee) 760 } else { 761 coinbaseReward = totalGasFee 762 } 763 } 764 765 // Coinbase Reward = Self Reward + Delegate Reward (if Deposit Proxied Balance > 0) 766 // 767 // IF commission > 0 768 // Self Reward = Self Reward + Commission Reward 769 // Commission Reward = Delegate Reward * Commission / 100 770 771 // Deposit Part 772 selfDeposit := state.GetDepositBalance(header.Coinbase) 773 totalProxiedDeposit := state.GetTotalDepositProxiedBalance(header.Coinbase) 774 totalDeposit := new(big.Int).Add(selfDeposit, totalProxiedDeposit) 775 776 var selfReward, delegateReward *big.Int 777 if totalProxiedDeposit.Sign() == 0 { 778 selfReward = coinbaseReward 779 } else { 780 selfReward = new(big.Int) 781 // selfPercent = selfDeposit / totalDeposit 782 selfPercent := new(big.Float).Quo(new(big.Float).SetInt(selfDeposit), new(big.Float).SetInt(totalDeposit)) 783 784 // selftReward = coinbaseReward * selfPercent 785 new(big.Float).Mul(new(big.Float).SetInt(coinbaseReward), selfPercent).Int(selfReward) 786 787 // delegateReward = coinbaseReward - selfReward 788 delegateReward = new(big.Int).Sub(coinbaseReward, selfReward) 789 commission := state.GetCommission(header.Coinbase) 790 if commission > 0 { 791 // commissionReward = delegateReward * commission / 100 792 commissionReward := new(big.Int).Mul(delegateReward, big.NewInt(int64(commission))) 793 commissionReward.Quo(commissionReward, big.NewInt(100)) 794 795 // Add the commission to self reward selfReward = selfReward + commissionReward 796 selfReward.Add(selfReward, commissionReward) 797 798 // Sub the commission from delegate reward delegateReward = delegateReward - commissionReward 799 delegateReward.Sub(delegateReward, commissionReward) 800 } 801 } 802 803 // Move the self reward to Reward Trie 804 //divideRewardByEpoch(state, header.Coinbase, ep.Number, selfReward) 805 state.AddRewardBalanceByDelegateAddress(header.Coinbase, header.Coinbase, selfReward) 806 //state.MarkAddressReward(header.Coinbase) 807 808 // Calculate the Delegate Reward 809 if delegateReward != nil && delegateReward.Sign() > 0 { 810 totalIndividualReward := big.NewInt(0) 811 // Split the reward based on Weight stack 812 state.ForEachProxied(header.Coinbase, func(key common.Address, proxiedBalance, depositProxiedBalance, pendingRefundBalance *big.Int) bool { 813 if depositProxiedBalance.Sign() == 1 { 814 // deposit * delegateReward / total deposit 815 individualReward := new(big.Int).Quo(new(big.Int).Mul(depositProxiedBalance, delegateReward), totalProxiedDeposit) 816 //divideRewardByEpoch(state, key, ep.Number, individualReward) 817 state.AddRewardBalanceByDelegateAddress(key, header.Coinbase, individualReward) 818 //state.MarkAddressReward(key) 819 totalIndividualReward.Add(totalIndividualReward, individualReward) 820 } 821 return true 822 }) 823 // Recheck the Total Individual Reward, Float the difference 824 cmp := delegateReward.Cmp(totalIndividualReward) 825 if cmp == 1 { 826 // if delegate reward > actual given reward, give remaining reward to Candidate 827 diff := new(big.Int).Sub(delegateReward, totalIndividualReward) 828 //state.AddRewardBalanceByEpochNumber(header.Coinbase, ep.Number, diff) 829 state.AddRewardBalanceByDelegateAddress(header.Coinbase, header.Coinbase, diff) 830 } else if cmp == -1 { 831 // if delegate reward < actual given reward, subtract the diff from Candidate 832 diff := new(big.Int).Sub(totalIndividualReward, delegateReward) 833 //state.SubRewardBalanceByEpochNumber(header.Coinbase, ep.Number, diff) 834 state.SubRewardBalanceByDelegateAddress(header.Coinbase, header.Coinbase, diff) 835 } 836 } 837 } 838 839 //func divideRewardByEpoch(state *state.StateDB, addr common.Address, epochNumber uint64, reward *big.Int) { 840 // epochReward := new(big.Int).Quo(reward, big.NewInt(12)) 841 // lastEpochReward := new(big.Int).Set(reward) 842 // for i := epochNumber; i < epochNumber+12; i++ { 843 // if i == epochNumber+11 { 844 // state.AddRewardBalanceByEpochNumber(addr, i, lastEpochReward) 845 // } else { 846 // state.AddRewardBalanceByEpochNumber(addr, i, epochReward) 847 // lastEpochReward.Sub(lastEpochReward, epochReward) 848 // } 849 // } 850 // state.MarkAddressReward(addr) 851 //}