github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/protocol.go (about) 1 package protocol 2 3 import ( 4 "sync" 5 6 log "github.com/sirupsen/logrus" 7 8 "github.com/bytom/bytom/config" 9 "github.com/bytom/bytom/errors" 10 "github.com/bytom/bytom/protocol/bc" 11 "github.com/bytom/bytom/protocol/bc/types" 12 "github.com/bytom/bytom/protocol/state" 13 ) 14 15 const maxProcessBlockChSize = 1024 16 17 // Chain provides functions for working with the Bytom block chain. 18 type Chain struct { 19 index *state.BlockIndex 20 orphanManage *OrphanManage 21 txPool *TxPool 22 store Store 23 processBlockCh chan *processBlockMsg 24 25 cond sync.Cond 26 bestNode *state.BlockNode 27 } 28 29 // NewChain returns a new Chain using store as the underlying storage. 30 func NewChain(store Store, txPool *TxPool) (*Chain, error) { 31 return NewChainWithOrphanManage(store, txPool, NewOrphanManage()) 32 } 33 34 func NewChainWithOrphanManage(store Store, txPool *TxPool, manage *OrphanManage) (*Chain, error) { 35 c := &Chain{ 36 orphanManage: manage, 37 txPool: txPool, 38 store: store, 39 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize), 40 } 41 c.cond.L = new(sync.Mutex) 42 43 storeStatus := store.GetStoreStatus() 44 if storeStatus == nil { 45 if err := c.initChainStatus(); err != nil { 46 return nil, err 47 } 48 storeStatus = store.GetStoreStatus() 49 } 50 51 var err error 52 if c.index, err = store.LoadBlockIndex(storeStatus.Height); err != nil { 53 return nil, err 54 } 55 56 c.bestNode = c.index.GetNode(storeStatus.Hash) 57 c.index.SetMainChain(c.bestNode) 58 go c.blockProcesser() 59 return c, nil 60 } 61 62 func (c *Chain) initChainStatus() error { 63 genesisBlock := config.GenesisBlock() 64 txStatus := bc.NewTransactionStatus() 65 for i := range genesisBlock.Transactions { 66 if err := txStatus.SetStatus(i, false); err != nil { 67 return err 68 } 69 } 70 71 if err := c.store.SaveBlock(genesisBlock, txStatus); err != nil { 72 return err 73 } 74 75 utxoView := state.NewUtxoViewpoint() 76 bcBlock := types.MapBlock(genesisBlock) 77 if err := utxoView.ApplyBlock(bcBlock, txStatus); err != nil { 78 return err 79 } 80 81 node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil) 82 if err != nil { 83 return err 84 } 85 return c.store.SaveChainStatus(node, utxoView) 86 } 87 88 // BestBlockHeight returns the current height of the blockchain. 89 func (c *Chain) BestBlockHeight() uint64 { 90 c.cond.L.Lock() 91 defer c.cond.L.Unlock() 92 return c.bestNode.Height 93 } 94 95 // BestBlockHash return the hash of the chain tail block 96 func (c *Chain) BestBlockHash() *bc.Hash { 97 c.cond.L.Lock() 98 defer c.cond.L.Unlock() 99 return &c.bestNode.Hash 100 } 101 102 // BestBlockHeader returns the chain tail block 103 func (c *Chain) BestBlockHeader() *types.BlockHeader { 104 node := c.index.BestNode() 105 return node.BlockHeader() 106 } 107 108 // InMainChain checks wheather a block is in the main chain 109 func (c *Chain) InMainChain(hash bc.Hash) bool { 110 return c.index.InMainchain(hash) 111 } 112 113 // CalcNextSeed return the seed for the given block 114 func (c *Chain) CalcNextSeed(preBlock *bc.Hash) (*bc.Hash, error) { 115 node := c.index.GetNode(preBlock) 116 if node == nil { 117 return nil, errors.New("can't find preblock in the blockindex") 118 } 119 return node.CalcNextSeed(), nil 120 } 121 122 // CalcNextBits return the seed for the given block 123 func (c *Chain) CalcNextBits(preBlock *bc.Hash) (uint64, error) { 124 node := c.index.GetNode(preBlock) 125 if node == nil { 126 return 0, errors.New("can't find preblock in the blockindex") 127 } 128 return node.CalcNextBits(), nil 129 } 130 131 func (c *Chain) GetBlockIndex() *state.BlockIndex { 132 return c.index 133 } 134 135 // This function must be called with mu lock in above level 136 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error { 137 if err := c.store.SaveChainStatus(node, view); err != nil { 138 return err 139 } 140 141 c.cond.L.Lock() 142 defer c.cond.L.Unlock() 143 144 c.index.SetMainChain(node) 145 c.bestNode = node 146 147 log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update") 148 c.cond.Broadcast() 149 return nil 150 } 151 152 // BlockWaiter returns a channel that waits for the block at the given height. 153 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} { 154 ch := make(chan struct{}, 1) 155 go func() { 156 c.cond.L.Lock() 157 defer c.cond.L.Unlock() 158 for c.bestNode.Height < height { 159 c.cond.Wait() 160 } 161 ch <- struct{}{} 162 }() 163 164 return ch 165 } 166 167 // GetTxPool return chain txpool. 168 func (c *Chain) GetTxPool() *TxPool { 169 return c.txPool 170 }