github.com/igggame/nebulas-go@v2.1.0+incompatible/core/blockchain.go (about) 1 // Copyright (C) 2017 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // the go-nebulas library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 package core 20 21 import ( 22 "crypto/rand" 23 "io" 24 "strings" 25 "time" 26 27 "github.com/nebulasio/go-nebulas/core/state" 28 29 "github.com/gogo/protobuf/proto" 30 lru "github.com/hashicorp/golang-lru" 31 "github.com/nebulasio/go-nebulas/core/pb" 32 "github.com/nebulasio/go-nebulas/storage" 33 "github.com/nebulasio/go-nebulas/util" 34 "github.com/nebulasio/go-nebulas/util/byteutils" 35 "github.com/nebulasio/go-nebulas/util/logging" 36 "github.com/sirupsen/logrus" 37 ) 38 39 // storage: key -> value 40 // scheme -> scheme version 41 // genesis hash -> genesis block 42 // blockchain_tail -> tail block hash 43 // block hash -> block 44 // height -> block hash 45 46 // BlockChain the BlockChain core type. 47 type BlockChain struct { 48 chainID uint32 49 50 genesis *corepb.Genesis 51 52 genesisBlock *Block 53 tailBlock *Block 54 55 bkPool *BlockPool 56 txPool *TransactionPool 57 58 consensusHandler Consensus 59 syncService SyncService 60 61 cachedBlocks *lru.Cache 62 detachedTailBlocks *lru.Cache 63 64 // latest irreversible block 65 lib *Block 66 67 storage storage.Storage 68 69 eventEmitter *EventEmitter 70 71 nvm NVM 72 73 nr NR 74 75 dip Dip 76 77 quitCh chan int 78 79 superNode bool 80 81 // deprecated 82 unsupportedKeyword string 83 } 84 85 const ( 86 87 // EagleNebula chain id for 1.x 88 EagleNebula = 1 << 4 89 90 // ChunkSize is the size of blocks in a chunk 91 ChunkSize = 32 92 93 // Tail Key in storage 94 Tail = "blockchain_tail" 95 96 // LIB (latest irreversible block) in storage 97 LIB = "blockchain_lib" 98 99 // transaction's block height 100 TxBlockHeight = "height" 101 ) 102 103 // NewBlockChain create new #BlockChain instance. 104 func NewBlockChain(neb Neblet) (*BlockChain, error) { 105 if neb == nil || neb.Config() == nil || neb.Config().Chain == nil { 106 return nil, ErrNilArgument 107 } 108 109 var gasPrice, gasLimit *util.Uint128 110 var err error 111 if 0 == len(neb.Config().Chain.GasPrice) { 112 gasPrice = util.NewUint128() 113 } else { 114 gasPrice, err = util.NewUint128FromString(neb.Config().Chain.GasPrice) 115 if err != nil { 116 return nil, err 117 } 118 } 119 120 if 0 == len(neb.Config().Chain.GasLimit) { 121 gasLimit = util.NewUint128() 122 } else { 123 gasLimit, err = util.NewUint128FromString(neb.Config().Chain.GasLimit) 124 if err != nil { 125 return nil, err 126 } 127 } 128 129 blockPool, err := NewBlockPool(128) 130 if err != nil { 131 return nil, err 132 } 133 blockPool.RegisterInNetwork(neb.NetService()) 134 135 txPool, err := NewTransactionPool(327680) 136 if err != nil { 137 return nil, err 138 } 139 txPool.setEventEmitter(neb.EventEmitter()) 140 if err := txPool.SetGasConfig(gasPrice, gasLimit); err != nil { 141 return nil, err 142 } 143 txPool.RegisterInNetwork(neb.NetService()) 144 access, err := NewAccess(neb.Config().Chain.Access) 145 if err != nil { 146 return nil, err 147 } 148 txPool.setAccess(access) 149 150 var bc = &BlockChain{ 151 chainID: neb.Config().Chain.ChainId, 152 genesis: neb.Genesis(), 153 bkPool: blockPool, 154 txPool: txPool, 155 storage: neb.Storage(), 156 eventEmitter: neb.EventEmitter(), 157 nvm: neb.Nvm(), 158 nr: neb.Nr(), 159 dip: neb.Dip(), 160 quitCh: make(chan int, 1), 161 superNode: neb.Config().Chain.SuperNode, 162 unsupportedKeyword: neb.Config().Chain.UnsupportedKeyword, 163 } 164 165 bc.cachedBlocks, err = lru.New(128) 166 if err != nil { 167 return nil, err 168 } 169 170 bc.detachedTailBlocks, err = lru.New(128) 171 if err != nil { 172 return nil, err 173 } 174 175 bc.bkPool.setBlockChain(bc) 176 bc.txPool.setBlockChain(bc) 177 178 return bc, nil 179 } 180 181 // Setup the blockchain 182 func (bc *BlockChain) Setup(neb Neblet) error { 183 bc.consensusHandler = neb.Consensus() 184 185 if err := bc.CheckGenesisConfig(neb); err != nil { 186 return err 187 } 188 189 var err error 190 bc.genesisBlock, err = bc.LoadGenesisFromStorage() 191 if err != nil { 192 return err 193 } 194 195 bc.tailBlock, err = bc.LoadTailFromStorage() 196 if err != nil { 197 return err 198 } 199 logging.CLog().WithFields(logrus.Fields{ 200 "tail": bc.tailBlock, 201 }).Info("Tail Block.") 202 203 bc.lib, err = bc.LoadLIBFromStorage() 204 if err != nil { 205 return err 206 } 207 logging.CLog().WithFields(logrus.Fields{ 208 "block": bc.lib, 209 }).Info("Latest Irreversible Block.") 210 211 return nil 212 } 213 214 // Start start loop. 215 func (bc *BlockChain) Start() { 216 logging.CLog().Info("Starting BlockChain...") 217 218 go bc.loop() 219 } 220 221 // Stop stop loop. 222 func (bc *BlockChain) Stop() { 223 logging.CLog().Info("Stopping BlockChain...") 224 bc.quitCh <- 0 225 } 226 227 func (bc *BlockChain) loop() { 228 logging.CLog().Info("Started BlockChain.") 229 timerChan := time.NewTicker(15 * time.Second).C 230 for { 231 select { 232 case <-bc.quitCh: 233 logging.CLog().Info("Stopped BlockChain.") 234 return 235 case <-timerChan: 236 bc.ConsensusHandler().UpdateLIB() 237 metricsLruCacheBlock.Update(int64(bc.cachedBlocks.Len())) 238 metricsLruTailBlock.Update(int64(bc.detachedTailBlocks.Len())) 239 } 240 } 241 } 242 243 // CheckGenesisConfig check if the genesis and config is valid 244 func (bc *BlockChain) CheckGenesisConfig(neb Neblet) error { 245 genesis, err := DumpGenesis(bc) 246 //db.genesis has and config lack 247 if neb.Genesis() == nil && err == nil { 248 neb.SetGenesis(genesis) 249 if neb.Config().Chain.ChainId != neb.Genesis().Meta.ChainId { 250 return ErrInvalidConfigChainID 251 } 252 } else if neb.Genesis() == nil && err != nil { 253 logging.CLog().Fatal("Failed to find genesis config in config file") 254 } else if neb.Genesis() != nil && err != nil { 255 //first start 256 if neb.Config().Chain.ChainId != neb.Genesis().Meta.ChainId { 257 return ErrInvalidConfigChainID 258 } 259 } else { 260 if neb.Config().Chain.ChainId != neb.Genesis().Meta.ChainId { 261 return ErrInvalidConfigChainID 262 } 263 264 return CheckGenesisConfByDB(genesis, neb.Genesis()) 265 } 266 267 logging.CLog().WithFields(logrus.Fields{ 268 "meta.chainid": neb.Genesis().Meta.ChainId, 269 "consensus.dpos.dynasty": neb.Genesis().Consensus.Dpos.Dynasty, 270 "token.distribution": neb.Genesis().TokenDistribution, 271 }).Info("Genesis Configuration.") 272 return nil 273 } 274 275 // ChainID return the chainID. 276 func (bc *BlockChain) ChainID() uint32 { 277 return bc.chainID 278 } 279 280 // Storage return the storage. 281 func (bc *BlockChain) Storage() storage.Storage { 282 return bc.storage 283 } 284 285 // GenesisBlock return the genesis block. 286 func (bc *BlockChain) GenesisBlock() *Block { 287 return bc.genesisBlock 288 } 289 290 // TailBlock return the tail block. 291 func (bc *BlockChain) TailBlock() *Block { 292 return bc.tailBlock 293 } 294 295 // LIB return the latest irrversible block 296 func (bc *BlockChain) LIB() *Block { 297 return bc.lib 298 } 299 300 // SetLIB update the latest irrversible block 301 func (bc *BlockChain) SetLIB(lib *Block) { 302 bc.lib = lib 303 } 304 305 // EventEmitter return the eventEmitter. 306 func (bc *BlockChain) EventEmitter() *EventEmitter { 307 return bc.eventEmitter 308 } 309 310 func (bc *BlockChain) triggerRevertBlockEvent(blocks []string) { 311 for i := len(blocks) - 1; i >= 0; i-- { 312 bc.eventEmitter.Trigger(&state.Event{ 313 Topic: TopicRevertBlock, 314 Data: blocks[i], 315 }) 316 } 317 } 318 319 func (bc *BlockChain) revertBlocks(from *Block, to *Block) error { 320 reverted := to 321 var revertTimes int64 322 blocks := []string{} 323 for revertTimes = 0; !reverted.Hash().Equals(from.Hash()); { 324 if reverted.Hash().Equals(bc.lib.Hash()) { 325 return ErrCannotRevertLIB 326 } 327 328 reverted.ReturnTransactions() 329 logging.VLog().WithFields(logrus.Fields{ 330 "block": reverted, 331 }).Warn("A block is reverted.") 332 revertTimes++ 333 blocks = append(blocks, reverted.String()) 334 335 reverted = bc.GetBlock(reverted.header.parentHash) 336 if reverted == nil { 337 return ErrMissingParentBlock 338 } 339 } 340 go bc.triggerRevertBlockEvent(blocks) 341 // record count of reverted blocks 342 if revertTimes > 0 { 343 metricsBlockRevertTimesGauge.Update(revertTimes) 344 metricsBlockRevertMeter.Mark(1) 345 } 346 return nil 347 } 348 349 func (bc *BlockChain) dropTxsInBlockFromTxPool(block *Block) { 350 for _, tx := range block.transactions { 351 bc.txPool.Del(tx) 352 } 353 } 354 355 func (bc *BlockChain) triggerNewTailInfo(blocks []*Block) { 356 for i := len(blocks) - 1; i >= 0; i-- { 357 block := blocks[i] 358 bc.eventEmitter.Trigger(&state.Event{ 359 Topic: TopicNewTailBlock, 360 Data: block.String(), 361 }) 362 363 for _, v := range block.transactions { 364 bc.storage.Put(append(v.hash, []byte(TxBlockHeight)...), byteutils.FromUint64(block.height)) 365 events, err := block.FetchEvents(v.hash) 366 if err == nil { 367 for _, e := range events { 368 bc.eventEmitter.Trigger(e) 369 } 370 } 371 } 372 } 373 } 374 375 func (bc *BlockChain) buildIndexByBlockHeight(from *Block, to *Block) error { 376 blocks := []*Block{} 377 for !to.Hash().Equals(from.Hash()) { 378 err := bc.storage.Put(byteutils.FromUint64(to.height), to.Hash()) 379 if err != nil { 380 return err 381 } 382 blocks = append(blocks, to) 383 go bc.dropTxsInBlockFromTxPool(to) 384 to = bc.GetBlock(to.header.parentHash) 385 if to == nil { 386 return ErrMissingParentBlock 387 } 388 } 389 go bc.triggerNewTailInfo(blocks) 390 return nil 391 } 392 393 // SetTailBlock set tail block. 394 func (bc *BlockChain) SetTailBlock(newTail *Block) error { 395 if newTail == nil { 396 return ErrNilArgument 397 } 398 oldTail := bc.tailBlock 399 ancestor, err := bc.FindCommonAncestorWithTail(newTail) 400 if err != nil { 401 logging.VLog().WithFields(logrus.Fields{ 402 "target": newTail, 403 "tail": oldTail, 404 }).Debug("Failed to find common ancestor with tail") 405 return err 406 } 407 408 if err := bc.revertBlocks(ancestor, oldTail); err != nil { 409 logging.VLog().WithFields(logrus.Fields{ 410 "from": ancestor, 411 "to": oldTail, 412 "range": "(from, to]", 413 }).Debug("Failed to revert blocks.") 414 return err 415 } 416 417 // build index by block height 418 if err := bc.buildIndexByBlockHeight(ancestor, newTail); err != nil { 419 logging.VLog().WithFields(logrus.Fields{ 420 "from": ancestor, 421 "to": newTail, 422 "range": "(from, to]", 423 }).Debug("Failed to build index by block height.") 424 return err 425 } 426 427 // record new tail 428 if err := bc.StoreTailHashToStorage(newTail); err != nil { // Refine: rename, delete ToStorage 429 return err 430 } 431 bc.tailBlock = newTail 432 433 metricsBlockHeightGauge.Update(int64(newTail.Height())) 434 metricsBlocktailHashGauge.Update(int64(byteutils.HashBytes(newTail.Hash()))) 435 436 return nil 437 } 438 439 // GetBlockOnCanonicalChainByHeight return block in given height 440 func (bc *BlockChain) GetBlockOnCanonicalChainByHeight(height uint64) *Block { 441 442 if height > bc.tailBlock.height { 443 return nil 444 } 445 446 blockHash, err := bc.storage.Get(byteutils.FromUint64(height)) 447 if err != nil { 448 return nil 449 } 450 return bc.GetBlock(blockHash) 451 } 452 453 // GetBlockOnCanonicalChainByHash check if a block is on canonical chain 454 func (bc *BlockChain) GetBlockOnCanonicalChainByHash(blockHash byteutils.Hash) *Block { 455 blockByHash := bc.GetBlock(blockHash) 456 if blockByHash == nil { 457 logging.VLog().WithFields(logrus.Fields{ 458 "hash": blockHash.Hex(), 459 "tail": bc.tailBlock, 460 "err": "cannot find block with the given hash in local storage", 461 }).Debug("Failed to check a block on canonical chain.") 462 return nil 463 } 464 blockByHeight := bc.GetBlockOnCanonicalChainByHeight(blockByHash.height) 465 if blockByHeight == nil { 466 logging.VLog().WithFields(logrus.Fields{ 467 "height": blockByHash.height, 468 "tail": bc.tailBlock, 469 "err": "cannot find block with the given height in local storage", 470 }).Debug("Failed to check a block on canonical chain.") 471 return nil 472 } 473 if !blockByHeight.Hash().Equals(blockByHash.Hash()) { 474 logging.VLog().WithFields(logrus.Fields{ 475 "blockByHash": blockByHash, 476 "blockByHeight": blockByHeight, 477 "tail": bc.tailBlock, 478 "err": "block with the given hash isn't on canonical chain", 479 }).Debug("Failed to check a block on canonical chain.") 480 return nil 481 } 482 return blockByHeight 483 } 484 485 // GetInputForVRFSigner returns [ getBlock(block.height - 2 * dynasty.size).hash, block.parent.seed ] 486 func (bc *BlockChain) GetInputForVRFSigner(parentHash byteutils.Hash, height uint64) (ancestorHash, parentSeed []byte, err error) { 487 if parentHash == nil || !RandomAvailableAtHeight(height) { 488 return nil, nil, ErrInvalidArgument 489 } 490 491 nob := bc.consensusHandler.NumberOfBlocksInDynasty() 492 if height > nob*2 { 493 b := bc.GetBlockOnCanonicalChainByHeight(height - nob*2) 494 if b == nil { 495 logging.VLog().WithFields(logrus.Fields{ 496 "blockHeight": height, 497 "targetHeight": height - nob, 498 "numOfBlocksInDynasty": nob, 499 }).Error("Block not found.") 500 return nil, nil, ErrNotBlockInCanonicalChain 501 } 502 ancestorHash = b.Hash() 503 } else { 504 ancestorHash = bc.GenesisBlock().Hash() 505 } 506 507 parent := bc.GetBlockOnCanonicalChainByHash(parentHash) 508 if parent == nil || parent.height+1 != height { 509 return nil, nil, ErrInvalidBlockHash 510 } 511 512 if RandomAvailableAtHeight(parent.height) { 513 if !parent.HasRandomSeed() { 514 logging.VLog().WithFields(logrus.Fields{ 515 "parent": parent, 516 }).Error("Parent block has no random seed, unexpected error.") 517 metricsUnexpectedBehavior.Update(1) 518 return nil, nil, ErrInvalidBlockRandom 519 } 520 parentSeed = parent.header.random.VrfSeed 521 } else { 522 parentSeed = bc.GenesisBlock().Hash() 523 } 524 return 525 } 526 527 // FindCommonAncestorWithTail return the block's common ancestor with current tail 528 func (bc *BlockChain) FindCommonAncestorWithTail(block *Block) (*Block, error) { 529 if block == nil { 530 return nil, ErrNilArgument 531 } 532 target := bc.GetBlock(block.Hash()) 533 if target == nil { 534 target = bc.GetBlock(block.ParentHash()) 535 } 536 if target == nil { 537 return nil, ErrMissingParentBlock 538 } 539 540 tail := bc.TailBlock() 541 if tail.Height() > target.Height() { 542 tail = bc.GetBlockOnCanonicalChainByHeight(target.Height()) 543 if tail == nil { 544 return nil, ErrMissingParentBlock 545 } 546 } 547 548 for tail.Height() < target.Height() { 549 target = bc.GetBlock(target.header.parentHash) 550 if target == nil { 551 return nil, ErrMissingParentBlock 552 } 553 } 554 555 for !tail.Hash().Equals(target.Hash()) { 556 tail = bc.GetBlock(tail.header.parentHash) 557 target = bc.GetBlock(target.header.parentHash) 558 if tail == nil || target == nil { 559 return nil, ErrMissingParentBlock 560 } 561 } 562 563 return target, nil 564 } 565 566 // BlockPool return block pool. 567 func (bc *BlockChain) BlockPool() *BlockPool { 568 return bc.bkPool 569 } 570 571 // TransactionPool return block pool. 572 func (bc *BlockChain) TransactionPool() *TransactionPool { 573 return bc.txPool 574 } 575 576 // SetConsensusHandler set consensus handler. 577 func (bc *BlockChain) SetConsensusHandler(handler Consensus) { 578 bc.consensusHandler = handler 579 } 580 581 // SetSyncService set sync service. 582 func (bc *BlockChain) SetSyncService(syncService SyncService) { 583 bc.syncService = syncService 584 } 585 586 // StartActiveSync start active sync task 587 func (bc *BlockChain) StartActiveSync() bool { 588 if bc.syncService.StartActiveSync() { 589 bc.consensusHandler.SuspendMining() 590 go func() { 591 bc.syncService.WaitingForFinish() 592 bc.consensusHandler.ResumeMining() 593 }() 594 return true 595 } 596 return false 597 } 598 599 // IsActiveSyncing returns true if being syncing 600 func (bc *BlockChain) IsActiveSyncing() bool { 601 return bc.syncService.IsActiveSyncing() 602 } 603 604 // ConsensusHandler return consensus handler. 605 func (bc *BlockChain) ConsensusHandler() Consensus { 606 return bc.consensusHandler 607 } 608 609 // NewBlock create new #Block instance. 610 func (bc *BlockChain) NewBlock(coinbase *Address) (*Block, error) { 611 if coinbase == nil { 612 return nil, ErrInvalidArgument 613 } 614 return bc.NewBlockFromParent(coinbase, bc.tailBlock) 615 } 616 617 // NewBlockFromParent create new block from parent block and return it. 618 func (bc *BlockChain) NewBlockFromParent(coinbase *Address, parentBlock *Block) (*Block, error) { 619 if parentBlock == nil || coinbase == nil { 620 return nil, ErrNilArgument 621 } 622 return NewBlock(bc.chainID, coinbase, parentBlock) 623 } 624 625 // PutVerifiedNewBlocks put verified new blocks and tails. 626 func (bc *BlockChain) putVerifiedNewBlocks(parent *Block, allBlocks, tailBlocks []*Block) error { 627 for _, v := range allBlocks { 628 bc.cachedBlocks.Add(v.Hash().Hex(), v) 629 if err := bc.StoreBlockToStorage(v); err != nil { 630 logging.VLog().WithFields(logrus.Fields{ 631 "block": v, 632 "err": err, 633 }).Debug("Failed to store the verified block.") 634 return err 635 } 636 637 logging.VLog().WithFields(logrus.Fields{ 638 "block": v, 639 }).Info("Accepted the new block on chain") 640 641 metricsBlockOnchainTimer.Update(time.Duration(time.Now().Unix() - v.Timestamp())) 642 for _, tx := range v.transactions { 643 metricsTxOnchainTimer.Update(time.Duration(time.Now().Unix() - tx.Timestamp())) 644 } 645 } 646 for _, v := range tailBlocks { 647 bc.detachedTailBlocks.Add(v.Hash().Hex(), v) 648 } 649 650 bc.detachedTailBlocks.Remove(parent.Hash().Hex()) 651 652 return nil 653 } 654 655 // DetachedTailBlocks return detached tail blocks, used by Fork Choice algorithm. 656 func (bc *BlockChain) DetachedTailBlocks() []*Block { 657 ret := make([]*Block, 0) 658 for _, k := range bc.detachedTailBlocks.Keys() { 659 v, _ := bc.detachedTailBlocks.Get(k) 660 if v != nil { 661 block := v.(*Block) 662 ret = append(ret, block) 663 } 664 } 665 return ret 666 } 667 668 // GetBlock return block of given hash from local storage and detachedBlocks. 669 func (bc *BlockChain) GetBlock(hash byteutils.Hash) *Block { 670 v, _ := bc.cachedBlocks.Get(hash.Hex()) 671 if v == nil { 672 block, err := LoadBlockFromStorage(hash, bc) 673 if err != nil { 674 return nil 675 } 676 return block 677 } 678 679 block := v.(*Block) 680 return block 681 } 682 683 // GetContract return contract of given address 684 func (bc *BlockChain) GetContract(addr *Address) (state.Account, error) { 685 worldState, err := bc.TailBlock().WorldState().Clone() 686 if err != nil { 687 return nil, err 688 } 689 contract, err := CheckContract(addr, worldState) 690 if err != nil { 691 return nil, err 692 } 693 return contract, nil 694 } 695 696 // GetTransaction return transaction of given hash from local storage. 697 func (bc *BlockChain) GetTransaction(hash byteutils.Hash) (*Transaction, error) { 698 worldState, err := bc.TailBlock().WorldState().Clone() 699 if err != nil { 700 return nil, err 701 } 702 tx, err := GetTransaction(hash, worldState) 703 if err != nil { 704 return nil, err 705 } 706 return tx, nil 707 } 708 709 // GetTransactionHeight return transaction's block height 710 func (bc *BlockChain) GetTransactionHeight(hash byteutils.Hash) (uint64, error) { 711 bytes, err := bc.storage.Get(append(hash, []byte(TxBlockHeight)...)) 712 if err != nil && err != storage.ErrKeyNotFound { 713 return 0, err 714 } 715 716 if len(bytes) == 0 { 717 // for empty value (history txs), height = 0 718 return 0, nil 719 } 720 721 return byteutils.Uint64(bytes), nil 722 } 723 724 // GasPrice returns the lowest transaction gas price. 725 func (bc *BlockChain) GasPrice() *util.Uint128 { 726 gasPrice := TransactionMaxGasPrice 727 tailBlock := bc.TailBlock() 728 // search latest block who has transactions, try 128 times at most 729 for i := 0; i < 128; i++ { 730 // if the block is genesis, stop find the parent block 731 if CheckGenesisBlock(tailBlock) { 732 break 733 } 734 735 if len(tailBlock.transactions) > 0 { 736 break 737 } 738 tailBlock = bc.GetBlock(tailBlock.ParentHash()) 739 } 740 741 if len(tailBlock.transactions) > 0 { 742 for _, tx := range tailBlock.transactions { 743 if tx.gasPrice.Cmp(gasPrice) < 0 { 744 gasPrice = tx.gasPrice 745 } 746 } 747 } else { 748 // if no transactions have been submitted, use the default gasPrice 749 gasPrice = bc.txPool.GetMinGasPrice() 750 } 751 752 return gasPrice 753 } 754 755 // SimulateResult the result of simulating transaction execution 756 type SimulateResult struct { 757 GasUsed *util.Uint128 758 Msg string 759 Err error 760 } 761 762 // SimulateTransactionExecution execute transaction in sandbox and rollback all changes, used to EstimateGas and Call api. 763 func (bc *BlockChain) SimulateTransactionExecution(tx *Transaction) (*SimulateResult, error) { 764 if tx == nil { 765 return nil, ErrInvalidArgument 766 } 767 768 // create block. 769 block, err := bc.NewBlock(GenesisCoinbase) 770 if err != nil { 771 return nil, err 772 } 773 774 sVrfSeed, sVrfProof := make([]byte, 32), make([]byte, 129) 775 _, _ = io.ReadFull(rand.Reader, sVrfSeed) 776 _, _ = io.ReadFull(rand.Reader, sVrfProof) 777 block.header.random.VrfSeed = sVrfSeed 778 block.header.random.VrfProof = sVrfProof 779 780 defer block.RollBack() 781 782 // simulate execution. 783 return tx.simulateExecution(block) 784 } 785 786 // Dump dump full chain. 787 func (bc *BlockChain) Dump(count int) string { 788 rl := []string{} 789 block := bc.tailBlock 790 rl = append(rl, block.String()) 791 for i := 1; i < count; i++ { 792 if !CheckGenesisBlock(block) { 793 block = bc.GetBlock(block.ParentHash()) 794 rl = append(rl, block.String()) 795 } 796 } 797 798 rls := "[" + strings.Join(rl, ",") + "]" 799 return rls 800 } 801 802 // StoreBlockToStorage store block 803 func (bc *BlockChain) StoreBlockToStorage(block *Block) error { 804 pbBlock, err := block.ToProto() 805 if err != nil { 806 return err 807 } 808 value, err := proto.Marshal(pbBlock) 809 if err != nil { 810 return err 811 } 812 err = bc.storage.Put(block.Hash(), value) 813 if err != nil { 814 return err 815 } 816 return nil 817 } 818 819 // StoreTailHashToStorage store tail block hash 820 func (bc *BlockChain) StoreTailHashToStorage(block *Block) error { // ToRefine, update func to StoreTailHashToStorage 821 return bc.storage.Put([]byte(Tail), block.Hash()) 822 } 823 824 // StoreLIBHashToStorage store LIB block hash 825 func (bc *BlockChain) StoreLIBHashToStorage(block *Block) error { 826 return bc.storage.Put([]byte(LIB), block.Hash()) 827 } 828 829 // LoadTailFromStorage load tail block 830 func (bc *BlockChain) LoadTailFromStorage() (*Block, error) { 831 hash, err := bc.storage.Get([]byte(Tail)) 832 if err != nil && err != storage.ErrKeyNotFound { 833 return nil, err 834 } 835 if err == storage.ErrKeyNotFound { 836 genesis, err := bc.LoadGenesisFromStorage() 837 if err != nil { 838 return nil, err 839 } 840 841 if err := bc.StoreTailHashToStorage(genesis); err != nil { 842 return nil, err 843 } 844 845 return genesis, nil 846 } 847 848 return LoadBlockFromStorage(hash, bc) 849 } 850 851 // LoadGenesisFromStorage load genesis 852 func (bc *BlockChain) LoadGenesisFromStorage() (*Block, error) { // ToRefine, remove or ? 853 genesis, err := LoadBlockFromStorage(GenesisHash, bc) 854 if err != nil && err != storage.ErrKeyNotFound { 855 return nil, err 856 } 857 if err == storage.ErrKeyNotFound { 858 genesis, err = NewGenesisBlock(bc.genesis, bc) 859 if err != nil { 860 return nil, err 861 } 862 if err := bc.StoreBlockToStorage(genesis); err != nil { 863 return nil, err 864 } 865 heightKey := byteutils.FromUint64(genesis.height) 866 if err := bc.storage.Put(heightKey, genesis.Hash()); err != nil { 867 return nil, err 868 } 869 } 870 return genesis, nil 871 } 872 873 // LoadLIBFromStorage load LIB 874 func (bc *BlockChain) LoadLIBFromStorage() (*Block, error) { 875 hash, err := bc.storage.Get([]byte(LIB)) 876 if err != nil && err != storage.ErrKeyNotFound { 877 return nil, err 878 } 879 880 if err == storage.ErrKeyNotFound { 881 if err := bc.StoreLIBHashToStorage(bc.genesisBlock); err != nil { 882 return nil, err 883 } 884 return bc.genesisBlock, nil 885 } 886 887 return LoadBlockFromStorage(hash, bc) 888 }