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"
19 maxProcessBlockChSize = 1024
20 maxProcessRollbackSize = 1024
23 // Chain provides functions for working with the Bytom block chain.
25 orphanManage *OrphanManage
29 processBlockCh chan *processBlockMsg
30 processRollbackCh chan *rollbackMsg
31 eventDispatcher *event.Dispatcher
34 bestBlockHeader *types.BlockHeader // the last block on current main chain
37 // NewChain returns a new Chain using store as the underlying storage.
38 func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
39 return NewChainWithOrphanManage(store, txPool, NewOrphanManage(), eventDispatcher)
42 func NewChainWithOrphanManage(store Store, txPool *TxPool, manage *OrphanManage, eventDispatcher *event.Dispatcher) (*Chain, error) {
45 eventDispatcher: eventDispatcher,
48 processRollbackCh: make(chan *rollbackMsg, maxProcessRollbackSize),
49 processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
51 c.cond.L = new(sync.Mutex)
53 storeStatus := store.GetStoreStatus()
54 if storeStatus == nil {
55 if err := c.initChainStatus(); err != nil {
58 storeStatus = store.GetStoreStatus()
62 c.bestBlockHeader, err = c.store.GetBlockHeader(storeStatus.Hash)
67 casper, err := newCasper(store, storeStatus, c.processRollbackCh)
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 if err := c.store.SaveCheckpoints([]*state.Checkpoint{checkpoint}); err != nil {
94 utxoView := state.NewUtxoViewpoint()
95 bcBlock := types.MapBlock(genesisBlock)
96 if err := utxoView.ApplyBlock(bcBlock); err != nil {
100 contractView := state.NewContractViewpoint()
101 genesisBlockHeader := &genesisBlock.BlockHeader
102 return c.store.SaveChainStatus(genesisBlockHeader, []*types.BlockHeader{genesisBlockHeader}, utxoView, contractView, 0, &checkpoint.Hash)
105 func newCasper(store Store, storeStatus *BlockStoreState, rollbackCh chan *rollbackMsg) (*Casper, error) {
106 checkpoints, err := store.CheckpointsFromNode(storeStatus.FinalizedHeight, storeStatus.FinalizedHash)
111 return NewCasper(store, checkpoints, rollbackCh), nil
114 // LastJustifiedHeader return the last justified block header of the block chain
115 func (c *Chain) LastJustifiedHeader() (*types.BlockHeader, error) {
116 _, hash := c.casper.LastJustified()
117 return c.store.GetBlockHeader(&hash)
120 // LastFinalizedHeader return the last finalized block header of the block chain
121 func (c *Chain) LastFinalizedHeader() (*types.BlockHeader, error) {
122 _, hash := c.casper.LastFinalized()
123 return c.store.GetBlockHeader(&hash)
126 // ProcessBlockVerification process block verification
127 func (c *Chain) ProcessBlockVerification(v *Verification) error {
128 if err := c.casper.AuthVerification(v); err != nil {
132 pubKey, _ := hex.DecodeString(v.PubKey)
133 return c.eventDispatcher.Post(event.BlockVerificationEvent{
134 SourceHeight: v.SourceHeight,
135 SourceHash: v.SourceHash,
136 TargetHeight: v.TargetHeight,
137 TargetHash: v.TargetHash,
139 Signature: v.Signature,
143 // BestBlockHeight returns the current height of the blockchain.
144 func (c *Chain) BestBlockHeight() uint64 {
146 defer c.cond.L.Unlock()
147 return c.bestBlockHeader.Height
150 // BestBlockHash return the hash of the chain tail block
151 func (c *Chain) BestBlockHash() *bc.Hash {
153 defer c.cond.L.Unlock()
154 bestHash := c.bestBlockHeader.Hash()
158 // GetValidator return validator by specified blockHash and timestamp
159 func (c *Chain) GetValidator(prevHash *bc.Hash, timeStamp uint64) (*state.Validator, error) {
160 prevCheckpoint, err := c.casper.parentCheckpointByPrevHash(prevHash)
165 validators := prevCheckpoint.Validators()
166 startTimestamp := prevCheckpoint.Timestamp + consensus.ActiveNetParams.BlockTimeInterval
167 order := getValidatorOrder(startTimestamp, timeStamp, uint64(len(validators)))
168 for _, validator := range validators {
169 if validator.Order == int(order) {
170 return validator, nil
173 return nil, errors.New("get blocker failure")
176 func getValidatorOrder(startTimestamp, blockTimestamp, numOfValidators uint64) uint64 {
177 // One round of product block time for all consensus nodes
178 roundBlockTime := numOfValidators * consensus.ActiveNetParams.BlockTimeInterval
179 // The start time of the last round of product block
180 lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
182 return (blockTimestamp - lastRoundStartTime) / consensus.ActiveNetParams.BlockTimeInterval
185 // BestBlockHeader returns the chain tail block
186 func (c *Chain) BestBlockHeader() *types.BlockHeader {
188 defer c.cond.L.Unlock()
189 return c.bestBlockHeader
192 // InMainChain checks wheather a block is in the main chain
193 func (c *Chain) InMainChain(hash bc.Hash) bool {
194 blockHeader, err := c.store.GetBlockHeader(&hash)
199 blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
201 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
204 return *blockHash == hash
207 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) {
208 xprv := config.CommonConfig.PrivateKey()
209 signature := xprv.Sign(blockHeader.Hash().Bytes())
210 blockHeader.Set(signature)
213 // This function must be called with mu lock in above level
214 func (c *Chain) setState(blockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, contractView *state.ContractViewpoint) error {
215 finalizedHeight, finalizedHash := c.casper.LastFinalized()
216 if err := c.store.SaveChainStatus(blockHeader, mainBlockHeaders, view, contractView, finalizedHeight, &finalizedHash); err != nil {
221 defer c.cond.L.Unlock()
223 c.bestBlockHeader = blockHeader
225 hash := c.bestBlockHeader.Hash()
226 log.WithFields(log.Fields{"module": logModule, "height": c.bestBlockHeader.Height, "hash": hash.String()}).Debug("chain best status has been update")
231 // BlockWaiter returns a channel that waits for the block at the given height.
232 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
233 ch := make(chan struct{}, 1)
236 defer c.cond.L.Unlock()
237 for c.bestBlockHeader.Height < height {
246 // GetTxPool return chain txpool.
247 func (c *Chain) GetTxPool() *TxPool {
251 // PrevCheckpointByPrevHash get previous checkpoint by previous block hash
252 func (c *Chain) PrevCheckpointByPrevHash(preBlockHash *bc.Hash) (*state.Checkpoint, error) {
253 return c.casper.parentCheckpointByPrevHash(preBlockHash)