7 log "github.com/sirupsen/logrus"
9 "github.com/bytom/bytom/config"
10 "github.com/bytom/bytom/consensus"
11 "github.com/bytom/bytom/errors"
12 "github.com/bytom/bytom/event"
13 "github.com/bytom/bytom/protocol/bc"
14 "github.com/bytom/bytom/protocol/bc/types"
15 "github.com/bytom/bytom/protocol/state"
18 const maxProcessBlockChSize = 1024
20 // Chain provides functions for working with the Bytom block chain.
22 index *state.BlockIndex
23 orphanManage *OrphanManage
27 processBlockCh chan *processBlockMsg
28 rollbackNotifyCh chan bc.Hash
29 eventDispatcher *event.Dispatcher
32 bestNode *state.BlockNode
35 // NewChain returns a new Chain using store as the underlying storage.
36 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
37 return NewChainWithOrphanManage(store, txPool, NewOrphanManage(), eventDispatcher)
40 func NewChainWithOrphanManage(store Store, txPool *TxPool, manage *OrphanManage, eventDispatcher *event.Dispatcher) (*Chain, error) {
43 eventDispatcher: eventDispatcher,
46 rollbackNotifyCh: make(chan bc.Hash),
47 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
49 c.cond.L = new(sync.Mutex)
51 storeStatus := store.GetStoreStatus()
52 if storeStatus == nil {
53 if err := c.initChainStatus(); err != nil {
56 storeStatus = store.GetStoreStatus()
60 if c.index, err = store.LoadBlockIndex(storeStatus.Height); err != nil {
64 c.bestNode = c.index.GetNode(storeStatus.Hash)
65 c.index.SetMainChain(c.bestNode)
67 casper, err := newCasper(store, storeStatus, c.rollbackNotifyCh)
77 func (c *Chain) initChainStatus() error {
78 genesisBlock := config.GenesisBlock()
79 if err := c.store.SaveBlock(genesisBlock); err != nil {
83 checkpoint := &state.Checkpoint{
85 Hash: genesisBlock.Hash(),
86 Timestamp: genesisBlock.Timestamp,
87 Status: state.Justified,
90 utxoView := state.NewUtxoViewpoint()
91 bcBlock := types.MapBlock(genesisBlock)
92 if err := utxoView.ApplyBlock(bcBlock); err != nil {
96 node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
101 contractView := state.NewContractViewpoint()
102 return c.store.SaveChainStatus(node, utxoView, contractView, []*state.Checkpoint{checkpoint}, 0, &checkpoint.Hash)
105 func newCasper(store Store, storeStatus *BlockStoreState, rollbackNotifyCh chan bc.Hash) (*Casper, error) {
106 checkpoints, err := store.CheckpointsFromNode(storeStatus.FinalizedHeight, storeStatus.FinalizedHash)
111 return NewCasper(store, checkpoints, rollbackNotifyCh), nil
114 // BestBlockHeight returns the last irreversible block header of the blockchain
115 func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
116 _, hash := c.casper.LastFinalized()
117 node := c.index.GetNode(&hash)
118 return node.BlockHeader()
121 // ProcessBlockVerification process block verification
122 func (c *Chain) ProcessBlockVerification(v *Verification) error {
123 if err := c.casper.AuthVerification(v); err != nil {
127 pubKey, _ := hex.DecodeString(v.PubKey)
128 signature, _ := hex.DecodeString(v.Signature)
129 return c.eventDispatcher.Post(event.BlockVerificationEvent{
130 SourceHeight: v.SourceHeight,
131 SourceHash: v.SourceHash,
132 TargetHeight: v.TargetHeight,
133 TargetHash: v.TargetHash,
135 Signature: signature,
139 // BestBlockHeight returns the current height of the blockchain.
140 func (c *Chain) BestBlockHeight() uint64 {
142 defer c.cond.L.Unlock()
143 return c.bestNode.Height
146 // BestBlockHash return the hash of the chain tail block
147 func (c *Chain) BestBlockHash() *bc.Hash {
149 defer c.cond.L.Unlock()
150 return &c.bestNode.Hash
153 // GetValidator return validator by specified blockHash and timestamp
154 func (c *Chain) GetValidator(prevHash *bc.Hash, timeStamp uint64) (*state.Validator, error) {
155 prevCheckpoint, err := c.casper.prevCheckpointByPrevHash(prevHash)
160 validators := prevCheckpoint.Validators()
161 startTimestamp := prevCheckpoint.Timestamp + consensus.ActiveNetParams.BlockTimeInterval
162 order := getValidatorOrder(startTimestamp, timeStamp, uint64(len(validators)))
163 for _, validator := range validators {
164 if validator.Order == int(order) {
165 return validator, nil
168 return nil, errors.New("get blocker failure")
171 func getValidatorOrder(startTimestamp, blockTimestamp, numOfValidators uint64) uint64 {
172 // One round of product block time for all consensus nodes
173 roundBlockTime := numOfValidators * consensus.ActiveNetParams.BlockTimeInterval
174 // The start time of the last round of product block
175 lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
177 return (blockTimestamp - lastRoundStartTime) / consensus.ActiveNetParams.BlockTimeInterval
180 // BestBlockHeader returns the chain tail block
181 func (c *Chain) BestBlockHeader() *types.BlockHeader {
182 node := c.index.BestNode()
183 return node.BlockHeader()
186 // InMainChain checks wheather a block is in the main chain
187 func (c *Chain) InMainChain(hash bc.Hash) bool {
188 return c.index.InMainchain(hash)
191 func (c *Chain) GetBlockIndex() *state.BlockIndex {
195 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) {
196 xprv := config.CommonConfig.PrivateKey()
197 signature := xprv.Sign(blockHeader.Hash().Bytes())
198 blockHeader.Set(signature)
201 // This function must be called with mu lock in above level
202 func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint, contractView *state.ContractViewpoint, checkpoints ...*state.Checkpoint) error {
203 finalizedHeight, finalizedHash := c.casper.LastFinalized()
204 if err := c.store.SaveChainStatus(node, view, contractView, checkpoints, finalizedHeight, &finalizedHash); err != nil {
209 defer c.cond.L.Unlock()
211 c.index.SetMainChain(node)
214 log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update")
219 // BlockWaiter returns a channel that waits for the block at the given height.
220 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
221 ch := make(chan struct{}, 1)
224 defer c.cond.L.Unlock()
225 for c.bestNode.Height < height {
234 // GetTxPool return chain txpool.
235 func (c *Chain) GetTxPool() *TxPool {