github.com/codingfuture/orig-energi3@v0.8.4/energi/consensus/engine.go (about) 1 // Copyright 2019 The Energi Core Authors 2 // This file is part of the Energi Core library. 3 // 4 // The Energi Core 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 Energi Core 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 Energi Core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package consensus 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 "strings" 24 "sync/atomic" 25 "time" 26 27 "github.com/ethereum/go-ethereum/accounts/abi" 28 "github.com/ethereum/go-ethereum/common" 29 eth_consensus "github.com/ethereum/go-ethereum/consensus" 30 "github.com/ethereum/go-ethereum/consensus/misc" 31 "github.com/ethereum/go-ethereum/core" 32 "github.com/ethereum/go-ethereum/core/state" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/core/vm" 35 "github.com/ethereum/go-ethereum/crypto" 36 "github.com/ethereum/go-ethereum/ethdb" 37 "github.com/ethereum/go-ethereum/log" 38 "github.com/ethereum/go-ethereum/params" 39 "github.com/ethereum/go-ethereum/rlp" 40 "github.com/ethereum/go-ethereum/rpc" 41 42 lru "github.com/hashicorp/golang-lru" 43 "golang.org/x/crypto/sha3" 44 45 energi_abi "energi.world/core/gen3/energi/abi" 46 energi_params "energi.world/core/gen3/energi/params" 47 ) 48 49 var ( 50 sealLen = 65 51 uncleHash = types.CalcUncleHash(nil) 52 53 errMissingSig = errors.New("Signature is missing") 54 errInvalidSig = errors.New("Invalid signature") 55 56 errBlacklistedCoinbase = errors.New("Blacklisted coinbase") 57 ) 58 59 type ChainReader = eth_consensus.ChainReader 60 type AccountsFn func() []common.Address 61 type SignerFn func(common.Address, []byte) ([]byte, error) 62 type PeerCountFn func() int 63 type DiffFn func(ChainReader, uint64, *types.Header, *timeTarget) *big.Int 64 65 type Energi struct { 66 config *params.EnergiConfig 67 db ethdb.Database 68 rewardAbi abi.ABI 69 dposAbi abi.ABI 70 blacklistAbi abi.ABI 71 sporkAbi abi.ABI 72 mnregAbi abi.ABI 73 treasuryAbi abi.ABI 74 systemFaucet common.Address 75 xferGas uint64 76 callGas uint64 77 unlimitedGas uint64 78 signerFn SignerFn 79 accountsFn AccountsFn 80 peerCountFn PeerCountFn 81 diffFn DiffFn 82 testing bool 83 now func() uint64 84 knownStakes KnownStakes 85 nextKSPurge uint64 86 nonceCap uint64 87 txhashMap *lru.Cache 88 } 89 90 func New(config *params.EnergiConfig, db ethdb.Database) *Energi { 91 reward_abi, err := abi.JSON(strings.NewReader(energi_abi.IBlockRewardABI)) 92 if err != nil { 93 panic(err) 94 return nil 95 } 96 97 dpos_abi, err := abi.JSON(strings.NewReader(energi_abi.IDelegatedPoSABI)) 98 if err != nil { 99 panic(err) 100 return nil 101 } 102 103 blacklist_abi, err := abi.JSON(strings.NewReader(energi_abi.IBlacklistRegistryABI)) 104 if err != nil { 105 panic(err) 106 return nil 107 } 108 109 spork_abi, err := abi.JSON(strings.NewReader(energi_abi.ISporkRegistryABI)) 110 if err != nil { 111 panic(err) 112 return nil 113 } 114 115 mngreg_abi, err := abi.JSON(strings.NewReader(energi_abi.IMasternodeRegistryV2ABI)) 116 if err != nil { 117 panic(err) 118 return nil 119 } 120 121 treasury_abi, err := abi.JSON(strings.NewReader(energi_abi.ITreasuryABI)) 122 if err != nil { 123 panic(err) 124 return nil 125 } 126 127 txhashMap, err := lru.New(8) 128 if err != nil { 129 panic(err) 130 return nil 131 } 132 133 return &Energi{ 134 config: config, 135 db: db, 136 rewardAbi: reward_abi, 137 dposAbi: dpos_abi, 138 blacklistAbi: blacklist_abi, 139 sporkAbi: spork_abi, 140 mnregAbi: mngreg_abi, 141 treasuryAbi: treasury_abi, 142 systemFaucet: energi_params.Energi_SystemFaucet, 143 xferGas: 0, 144 callGas: 30000, 145 unlimitedGas: energi_params.UnlimitedGas, 146 diffFn: calcPoSDifficultyV1, 147 now: func() uint64 { return uint64(time.Now().Unix()) }, 148 nextKSPurge: 0, 149 txhashMap: txhashMap, 150 } 151 } 152 153 func (e *Energi) createEVM( 154 msg types.Message, 155 chain ChainReader, 156 header *types.Header, 157 statedb *state.StateDB, 158 ) *vm.EVM { 159 vmc := &vm.Config{} 160 161 if bc, ok := chain.(*core.BlockChain); ok { 162 vmc = bc.GetVMConfig() 163 } 164 165 // Only From() is used by fact 166 ctx := core.NewEVMContext(msg, header, chain.(core.ChainContext), &header.Coinbase) 167 ctx.GasLimit = e.xferGas 168 return vm.NewEVM(ctx, statedb, chain.Config(), *vmc) 169 } 170 171 // Author retrieves the Ethereum address of the account that minted the given 172 // block, which may be different from the header's coinbase if a consensus 173 // engine is based on signatures. 174 func (e *Energi) Author(header *types.Header) (common.Address, error) { 175 return common.Address{}, nil 176 } 177 178 // VerifyHeader checks whether a header conforms to the consensus rules of a 179 // given engine. Verifying the seal may be done optionally here, or explicitly 180 // via the VerifySeal method. 181 func (e *Energi) VerifyHeader(chain ChainReader, header *types.Header, seal bool) error { 182 var err error 183 is_migration := header.IsGen2Migration() 184 185 // Ensure that the header's extra-data section is of a reasonable size 186 if uint64(len(header.Extra)) > params.MaximumExtraDataSize && !is_migration { 187 return fmt.Errorf("extra-data too long: %d > %d", 188 len(header.Extra), params.MaximumExtraDataSize) 189 } 190 191 // A special Migration block #1 192 if is_migration && (header.Coinbase != energi_params.Energi_MigrationContract) { 193 log.Error("PoS migration mismatch", 194 "signer", header.Coinbase, 195 "required", energi_params.Energi_MigrationContract) 196 return errors.New("Invalid Migration") 197 } 198 199 parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) 200 201 if parent == nil { 202 if header.Number.Cmp(common.Big0) != 0 { 203 log.Trace("Not found parent", "number", header.Number, 204 "hash", header.Hash(), "parent", header.ParentHash) 205 return eth_consensus.ErrUnknownAncestor 206 } 207 208 return nil 209 } 210 211 time_target := e.calcTimeTarget(chain, parent) 212 err = e.checkTime(header, time_target) 213 if err != nil { 214 return err 215 } 216 217 modifier := e.calcPoSModifier(chain, header.Time, parent) 218 if header.MixDigest != modifier { 219 return fmt.Errorf("invalid modifier: have %v, want %v", 220 header.MixDigest, modifier) 221 } 222 223 difficulty := e.calcPoSDifficulty(chain, header.Time, parent, time_target) 224 225 if header.Difficulty.Cmp(difficulty) != 0 { 226 return fmt.Errorf("invalid difficulty: have %v, want %v", 227 header.Difficulty, difficulty) 228 } 229 230 cap := uint64(0x7fffffffffffffff) 231 if header.GasLimit > cap { 232 return fmt.Errorf("invalid gasLimit: have %v, max %v", 233 header.GasLimit, cap) 234 } 235 236 // Verify that the gasUsed is <= gasLimit, except for migration 237 if (header.GasUsed > header.GasLimit) && !is_migration { 238 return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", 239 header.GasUsed, header.GasLimit) 240 } 241 242 // Verify that the gas limit remains within allowed bounds 243 diff := int64(parent.GasLimit) - int64(header.GasLimit) 244 if diff < 0 { 245 diff *= -1 246 } 247 limit := parent.GasLimit / params.GasLimitBoundDivisor 248 249 if (uint64(diff) >= limit) && !is_migration && !parent.IsGen2Migration() { 250 return fmt.Errorf("invalid gas limit: have %d, want %d += %d", 251 header.GasLimit, parent.GasLimit, limit) 252 } 253 254 if header.GasLimit < params.MinGasLimit { 255 return fmt.Errorf("invalid gas limit: have %d, minimum %d", 256 header.GasLimit, params.MinGasLimit) 257 } 258 259 // Verify that the block number is parent's +1 260 if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { 261 return eth_consensus.ErrInvalidNumber 262 } 263 264 // We skip checks only where full previous meturity period state is required. 265 if seal { 266 // Verify the engine specific seal securing the block 267 err = e.VerifySeal(chain, header) 268 if err != nil { 269 return err 270 } 271 272 err = e.verifyPoSHash(chain, header) 273 if err != nil { 274 return err 275 } 276 } 277 278 if err = misc.VerifyForkHashes(chain.Config(), header, false); err != nil { 279 return err 280 } 281 282 // DoS protection 283 if seal && chain.GetHeader(header.Hash(), header.Number.Uint64()) == nil { 284 if err = e.checkDoS(chain, header, parent); err != nil { 285 return err 286 } 287 } 288 289 return nil 290 } 291 292 // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers 293 // concurrently. The method returns a quit channel to abort the operations and 294 // a results channel to retrieve the async verifications (the order is that of 295 // the input slice). 296 func (e *Energi) VerifyHeaders( 297 chain ChainReader, headers []*types.Header, seals []bool, 298 ) ( 299 chan<- struct{}, <-chan error, chan<- bool, 300 ) { 301 abort := make(chan struct{}) 302 results := make(chan error, len(headers)) 303 ready := make(chan bool, len(headers)) 304 305 go func() { 306 for i, header := range headers { 307 // NOTE: unlike Ethash with DAG, there is little sense of this 308 // batch async routine overhead 309 select { 310 case <-abort: 311 return 312 case <-ready: 313 } 314 315 err := e.VerifyHeader(chain, header, seals[i]) 316 317 select { 318 case <-abort: 319 return 320 case results <- err: 321 } 322 } 323 }() 324 325 return abort, results, ready 326 } 327 328 // VerifyUncles verifies that the given block's uncles conform to the consensus 329 // rules of a given engine. 330 func (e *Energi) VerifyUncles(chain ChainReader, block *types.Block) error { 331 if len(block.Uncles()) > 0 { 332 return errors.New("uncles not allowed") 333 } 334 return nil 335 } 336 337 // VerifySeal checks whether the crypto seal on a header is valid according to 338 // the consensus rules of the given engine. 339 func (e *Energi) VerifySeal(chain ChainReader, header *types.Header) error { 340 parent_number := header.Number.Uint64() - 1 341 blockst := chain.CalculateBlockState(header.ParentHash, parent_number) 342 if blockst == nil { 343 log.Error("PoS state root failure", "header", header.ParentHash) 344 return eth_consensus.ErrMissingState 345 } 346 347 // DBL-8: blacklist block generation 348 if core.IsBlacklisted(blockst, header.Coinbase) { 349 log.Debug("Blacklisted Coinbase", "addr", header.Coinbase) 350 return errBlacklistedCoinbase 351 } 352 353 // Retrieve the signature from the header extra-data 354 if len(header.Signature) != sealLen { 355 return errMissingSig 356 } 357 358 sighash := e.SignatureHash(header) 359 log.Trace("PoS verify signature hash", "sighash", sighash) 360 361 r := new(big.Int).SetBytes(header.Signature[:32]) 362 s := new(big.Int).SetBytes(header.Signature[32:64]) 363 v := header.Signature[64] 364 365 if !crypto.ValidateSignatureValues(v, r, s, true) { 366 return types.ErrInvalidSig 367 } 368 369 pubkey, err := crypto.Ecrecover(sighash.Bytes(), header.Signature) 370 if err != nil { 371 return err 372 } 373 374 var addr common.Address 375 copy(addr[:], crypto.Keccak256(pubkey[1:])[12:]) 376 377 if addr != header.Coinbase { 378 // POS-5: Delegated PoS 379 //-- 380 parent := chain.GetHeader(header.ParentHash, parent_number) 381 if parent == nil { 382 return eth_consensus.ErrUnknownAncestor 383 } 384 385 if blockst.GetCodeSize(header.Coinbase) > 0 { 386 signerData, err := e.dposAbi.Pack("signerAddress") 387 if err != nil { 388 log.Error("Fail to prepare signerAddress() call", "err", err) 389 return err 390 } 391 392 msg := types.NewMessage( 393 e.systemFaucet, 394 &header.Coinbase, 395 0, 396 common.Big0, 397 e.callGas, 398 common.Big0, 399 signerData, 400 false, 401 ) 402 403 rev_id := blockst.Snapshot() 404 evm := e.createEVM(msg, chain, parent, blockst) 405 gp := core.GasPool(e.callGas) 406 output, _, _, err := core.ApplyMessage(evm, msg, &gp) 407 blockst.RevertToSnapshot(rev_id) 408 if err != nil { 409 log.Trace("Fail to get signerAddress()", "err", err) 410 return err 411 } 412 413 // 414 signer := common.Address{} 415 err = e.dposAbi.Unpack(&signer, "signerAddress", output) 416 if err != nil { 417 log.Error("Failed to unpack signerAddress() call", "err", err) 418 return err 419 } 420 421 if signer == addr { 422 return nil 423 } 424 425 log.Trace("PoS seal compare", "addr", addr, "signer", signer) 426 } else { 427 log.Trace("PoS seal compare", "addr", addr, "coinbase", header.Coinbase) 428 } 429 430 return errInvalidSig 431 } 432 433 return nil 434 } 435 436 // Prepare initializes the consensus fields of a block header according to the 437 // rules of a particular engine. The changes are executed inline. 438 func (e *Energi) Prepare(chain ChainReader, header *types.Header) error { 439 parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) 440 441 if parent == nil { 442 log.Error("Fail to find parent", "header", header) 443 return eth_consensus.ErrUnknownAncestor 444 } 445 446 _, err := e.posPrepare(chain, header, parent) 447 return err 448 } 449 450 func (e *Energi) posPrepare( 451 chain ChainReader, 452 header *types.Header, 453 parent *types.Header, 454 ) (time_target *timeTarget, err error) { 455 // Clear field to be set in mining 456 header.Coinbase = common.Address{} 457 header.Nonce = types.BlockNonce{} 458 459 time_target = e.calcTimeTarget(chain, parent) 460 461 err = e.enforceTime(header, time_target) 462 463 // Repurpose the MixDigest field 464 header.MixDigest = e.calcPoSModifier(chain, header.Time, parent) 465 466 // Diff 467 header.Difficulty = e.calcPoSDifficulty(chain, header.Time, parent, time_target) 468 469 return time_target, err 470 } 471 472 // Finalize runs any post-transaction state modifications (e.g. block rewards) 473 // and assembles the final block. 474 // Note: The block header and state database might be updated to reflect any 475 // consensus rules that happen at finalization (e.g. block rewards). 476 func (e *Energi) Finalize( 477 chain ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, 478 uncles []*types.Header, receipts []*types.Receipt, 479 ) (*types.Block, []*types.Receipt, error) { 480 ctxs := types.Transactions{} 481 482 for i := (len(txs) - 1); i >= 0; i-- { 483 if !txs[i].IsConsensus() { 484 i++ 485 ctxs = txs[i:] 486 txs = txs[:i] 487 break 488 } else if i == 0 { 489 ctxs = txs[:] 490 txs = txs[:0] 491 break 492 } 493 } 494 495 block, receipts, err := e.finalize(chain, header, state, txs, receipts) 496 if err != nil { 497 return nil, nil, err 498 } 499 500 ntxs := block.Transactions()[len(txs):] 501 if len(ntxs) != len(ctxs) { 502 log.Trace("Consensus TX length mismatch", "ntxs", len(ntxs), "ctxs", len(ctxs)) 503 return nil, nil, eth_consensus.ErrInvalidConsensusTx 504 } 505 for i, tx := range ntxs { 506 if tx.Hash() != ctxs[i].Hash() { 507 log.Trace("Consensus TX hash mismatch", "pos", i, "ctx", ctxs[i].Hash(), "ntx", tx.Hash()) 508 return nil, nil, eth_consensus.ErrInvalidConsensusTx 509 } 510 } 511 512 return block, receipts, err 513 } 514 515 func (e *Energi) finalize( 516 chain ChainReader, header *types.Header, state *state.StateDB, 517 txs []*types.Transaction, receipts []*types.Receipt, 518 ) (*types.Block, []*types.Receipt, error) { 519 var err error 520 521 // Do not finalize too early in mining 522 if (header.Coinbase != common.Address{}) { 523 txs, receipts, err = e.govFinalize(chain, header, state, txs, receipts) 524 } 525 526 header.UncleHash = uncleHash 527 528 return types.NewBlock(header, txs, nil, receipts), receipts, err 529 } 530 531 func (e *Energi) govFinalize( 532 chain ChainReader, 533 header *types.Header, 534 state *state.StateDB, 535 txs types.Transactions, 536 receipts types.Receipts, 537 ) (types.Transactions, types.Receipts, error) { 538 err := e.processConsensusGasLimits(chain, header, state) 539 if err == nil { 540 txs, receipts, err = e.processBlockRewards(chain, header, state, txs, receipts) 541 } 542 if err == nil { 543 err = e.processMasternodes(chain, header, state) 544 } 545 if err == nil { 546 err = e.processBlacklists(chain, header, state) 547 } 548 if err == nil { 549 txs, receipts, err = e.processDrainable(chain, header, state, txs, receipts) 550 } 551 if err == nil { 552 err = e.finalizeMigration(chain, header, state, txs) 553 } 554 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 555 return txs, receipts, err 556 } 557 558 // Seal generates a new sealing request for the given input block and pushes 559 // the result into the given channel. 560 // 561 // Note, the method returns immediately and will send the result async. More 562 // than one result may also be returned depending on the consensus algorithm. 563 func (e *Energi) Seal( 564 chain ChainReader, 565 block *types.Block, 566 results chan<- *eth_consensus.SealResult, 567 stop <-chan struct{}, 568 ) (err error) { 569 go func() { 570 header := block.Header() 571 txhash := header.TxHash 572 result := eth_consensus.NewSealResult(block, nil, nil) 573 574 if header.Number.Cmp(common.Big0) != 0 { 575 success, err := e.mine(chain, header, stop) 576 577 // NOTE: due to the fact that PoS mining may change Coinbase 578 // it is required to reprocess all transaction with correct 579 // state of the block (input parameters). This is essential 580 // for consensus and correct distribution of gas. 581 if success && err == nil { 582 result, err = e.recreateBlock(chain, header, block.Transactions()) 583 } 584 585 if err != nil { 586 log.Error("PoS miner error", "err", err) 587 success = false 588 } 589 590 if !success { 591 select { 592 case results <- eth_consensus.NewSealResult(nil, nil, nil): 593 default: 594 } 595 return 596 } 597 598 header = result.Block.Header() 599 } 600 601 sighash := e.SignatureHash(header) 602 log.Trace("PoS seal hash", "sighash", sighash) 603 604 header.Signature, err = e.signerFn(header.Coinbase, sighash.Bytes()) 605 if err != nil { 606 log.Error("PoS miner error", "err", err) 607 return 608 } 609 610 result.Block = result.Block.WithSeal(header) 611 e.txhashMap.Add(header.TxHash, txhash) 612 613 select { 614 case results <- result: 615 log.Info("PoS seal has submitted solution", "block", result.Block.Hash()) 616 default: 617 log.Warn("PoS seal is not read by miner", "sealhash", e.SealHash(header)) 618 } 619 }() 620 621 return nil 622 } 623 624 func (e *Energi) recreateBlock( 625 chain ChainReader, 626 header *types.Header, 627 txs types.Transactions, 628 ) ( 629 result *eth_consensus.SealResult, err error, 630 ) { 631 var ( 632 usedGas = new(uint64) 633 gp = new(core.GasPool).AddGas(header.GasLimit) 634 635 bc *core.BlockChain 636 ok bool 637 ) 638 639 blstate := chain.CalculateBlockState(header.ParentHash, header.Number.Uint64()-1) 640 if err != nil { 641 return nil, eth_consensus.ErrUnknownAncestor 642 } 643 644 vmc := &vm.Config{} 645 if bc, ok = chain.(*core.BlockChain); ok { 646 vmc = bc.GetVMConfig() 647 } 648 649 receipts := make(types.Receipts, 0, len(txs)) 650 651 for i, tx := range txs { 652 blstate.Prepare(tx.Hash(), common.Hash{}, i) 653 receipt, _, err := core.ApplyTransaction( 654 chain.Config(), bc, nil, 655 gp, blstate, header, tx, usedGas, *vmc) 656 if err != nil { 657 return nil, err 658 } 659 receipts = append(receipts, receipt) 660 } 661 662 header.GasUsed = *usedGas 663 header.Bloom = types.Bloom{} 664 665 block, receipts, err := e.finalize(chain, header, blstate, txs, receipts) 666 return eth_consensus.NewSealResult(block, blstate, receipts), err 667 } 668 669 // SealHash returns the hash of a block prior to it being sealed. 670 func (e *Energi) SealHash(header *types.Header) (hash common.Hash) { 671 hasher := sha3.NewLegacyKeccak256() 672 673 txhash := header.TxHash 674 675 if item, ok := e.txhashMap.Get(txhash); ok { 676 txhash = item.(common.Hash) 677 } 678 679 rlp.Encode(hasher, []interface{}{ 680 // NOTE: commented parts are part of "mining" process 681 header.ParentHash, 682 header.UncleHash, 683 //header.Coinbase, 684 //header.Root, 685 txhash, 686 //header.ReceiptHash, 687 //header.Bloom, 688 //header.Difficulty, 689 header.Number, 690 header.GasLimit, 691 //header.GasUsed, 692 //header.Time, 693 //header.Extra, 694 //header.MixDigest, 695 //header.Nonce, 696 //header.Signature, 697 }) 698 hasher.Sum(hash[:0]) 699 return hash 700 } 701 702 func (e *Energi) SignatureHash(header *types.Header) (hash common.Hash) { 703 hasher := sha3.NewLegacyKeccak256() 704 705 rlp.Encode(hasher, []interface{}{ 706 header.ParentHash, 707 header.UncleHash, 708 header.Coinbase, 709 header.Root, 710 header.TxHash, 711 header.ReceiptHash, 712 header.Bloom, 713 header.Difficulty, 714 header.Number, 715 header.GasLimit, 716 header.GasUsed, 717 header.Time, 718 header.Extra, 719 header.MixDigest, 720 header.Nonce, 721 //header.Signature, 722 }) 723 hasher.Sum(hash[:0]) 724 return hash 725 } 726 727 func (e *Energi) SetMinerNonceCap(nonceCap uint64) { 728 atomic.StoreUint64(&e.nonceCap, nonceCap) 729 } 730 func (e *Energi) GetMinerNonceCap() uint64 { 731 return atomic.LoadUint64(&e.nonceCap) 732 } 733 func (e *Energi) SetMinerCB( 734 accountsFn AccountsFn, 735 signerFn SignerFn, 736 peerCountFn PeerCountFn, 737 ) { 738 if e.signerFn != nil { 739 panic("Callbacks must be set only once!") 740 } 741 742 e.signerFn = signerFn 743 e.accountsFn = accountsFn 744 e.peerCountFn = peerCountFn 745 } 746 747 // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty 748 // that a new block should have. 749 func (e *Energi) CalcDifficulty(chain ChainReader, time uint64, parent *types.Header) *big.Int { 750 time_target := e.calcTimeTarget(chain, parent) 751 return e.calcPoSDifficulty(chain, time, parent, time_target) 752 } 753 754 // APIs returns the RPC APIs this consensus engine provides. 755 func (e *Energi) APIs(chain ChainReader) []rpc.API { 756 return make([]rpc.API, 0) 757 } 758 759 // Close terminates any background threads maintained by the consensus engine. 760 func (e *Energi) Close() error { 761 return nil 762 } 763 764 func (e *Energi) processConsensusGasLimits( 765 chain ChainReader, 766 header *types.Header, 767 state *state.StateDB, 768 ) error { 769 callData, err := e.sporkAbi.Pack("consensusGasLimits") 770 if err != nil { 771 log.Error("Fail to prepare consensusGasLimits() call", "err", err) 772 return err 773 } 774 775 // consensusGasLimits() 776 msg := types.NewMessage( 777 e.systemFaucet, 778 &energi_params.Energi_SporkRegistry, 779 0, 780 common.Big0, 781 e.callGas, 782 common.Big0, 783 callData, 784 false, 785 ) 786 rev_id := state.Snapshot() 787 evm := e.createEVM(msg, chain, header, state) 788 gp := core.GasPool(e.callGas) 789 output, _, _, err := core.ApplyMessage(evm, msg, &gp) 790 state.RevertToSnapshot(rev_id) 791 if err != nil { 792 log.Error("Failed in consensusGasLimits() call", "err", err) 793 return err 794 } 795 796 // 797 ret := new(struct { 798 CallGas *big.Int 799 XferGas *big.Int 800 }) 801 err = e.sporkAbi.Unpack(ret, "consensusGasLimits", output) 802 if err != nil { 803 log.Error("Failed to unpack consensusGasLimits() call", "err", err) 804 return err 805 } 806 807 e.callGas = ret.CallGas.Uint64() 808 e.xferGas = ret.XferGas.Uint64() 809 log.Trace("Consensus Gas", "call", e.callGas, "xfer", e.xferGas) 810 811 return nil 812 }