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 // LastFinalizedHeader returns the last finalized 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 // ProcessBlockVerification process block verification
121 func (c *Chain) ProcessBlockVerification(v *Verification) error {
122 if err := c.casper.AuthVerification(v); err != nil {
126 pubKey, _ := hex.DecodeString(v.PubKey)
127 return c.eventDispatcher.Post(event.BlockVerificationEvent{
128 SourceHeight: v.SourceHeight,
129 SourceHash: v.SourceHash,
130 TargetHeight: v.TargetHeight,
131 TargetHash: v.TargetHash,
133 Signature: v.Signature,
137 // BestBlockHeight returns the current height of the blockchain.
138 func (c *Chain) BestBlockHeight() uint64 {
140 defer c.cond.L.Unlock()
141 return c.bestBlockHeader.Height
144 // BestBlockHash return the hash of the chain tail block
145 func (c *Chain) BestBlockHash() *bc.Hash {
147 defer c.cond.L.Unlock()
148 bestHash := c.bestBlockHeader.Hash()
152 // GetValidator return validator by specified blockHash and timestamp
153 func (c *Chain) GetValidator(prevHash *bc.Hash, timeStamp uint64) (*state.Validator, error) {
154 prevCheckpoint, err := c.casper.parentCheckpointByPrevHash(prevHash)
159 validators := prevCheckpoint.Validators()
160 startTimestamp := prevCheckpoint.Timestamp + consensus.ActiveNetParams.BlockTimeInterval
161 order := getValidatorOrder(startTimestamp, timeStamp, uint64(len(validators)))
162 for _, validator := range validators {
163 if validator.Order == int(order) {
164 return validator, nil
167 return nil, errors.New("get blocker failure")
170 func getValidatorOrder(startTimestamp, blockTimestamp, numOfValidators uint64) uint64 {
171 // One round of product block time for all consensus nodes
172 roundBlockTime := numOfValidators * consensus.ActiveNetParams.BlockTimeInterval
173 // The start time of the last round of product block
174 lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
176 return (blockTimestamp - lastRoundStartTime) / consensus.ActiveNetParams.BlockTimeInterval
179 // BestBlockHeader returns the chain tail block
180 func (c *Chain) BestBlockHeader() *types.BlockHeader {
182 defer c.cond.L.Unlock()
183 return c.bestBlockHeader
186 // InMainChain checks wheather a block is in the main chain
187 func (c *Chain) InMainChain(hash bc.Hash) bool {
188 blockHeader, err := c.store.GetBlockHeader(&hash)
193 blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
195 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
198 return *blockHash == hash
201 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) {
202 xprv := config.CommonConfig.PrivateKey()
203 signature := xprv.Sign(blockHeader.Hash().Bytes())
204 blockHeader.Set(signature)
207 // This function must be called with mu lock in above level
208 func (c *Chain) setState(blockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, contractView *state.ContractViewpoint) error {
209 finalizedHeight, finalizedHash := c.casper.LastFinalized()
210 if err := c.store.SaveChainStatus(blockHeader, mainBlockHeaders, view, contractView, finalizedHeight, &finalizedHash); err != nil {
215 defer c.cond.L.Unlock()
217 c.bestBlockHeader = blockHeader
219 hash := c.bestBlockHeader.Hash()
220 log.WithFields(log.Fields{"module": logModule, "height": c.bestBlockHeader.Height, "hash": hash.String()}).Debug("chain best status has been update")
225 // BlockWaiter returns a channel that waits for the block at the given height.
226 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
227 ch := make(chan struct{}, 1)
230 defer c.cond.L.Unlock()
231 for c.bestBlockHeader.Height < height {
240 // GetTxPool return chain txpool.
241 func (c *Chain) GetTxPool() *TxPool {
245 // PrevCheckpointByPrevHash get previous checkpoint by previous block hash
246 func (c *Chain) PrevCheckpointByPrevHash(preBlockHash *bc.Hash) (*state.Checkpoint, error) {
247 return c.casper.parentCheckpointByPrevHash(preBlockHash)