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 signature, _ := hex.DecodeString(v.Signature)
128 return c.eventDispatcher.Post(event.BlockVerificationEvent{
129 SourceHeight: v.SourceHeight,
130 SourceHash: v.SourceHash,
131 TargetHeight: v.TargetHeight,
132 TargetHash: v.TargetHash,
134 Signature: signature,
138 // BestBlockHeight returns the current height of the blockchain.
139 func (c *Chain) BestBlockHeight() uint64 {
141 defer c.cond.L.Unlock()
142 return c.bestBlockHeader.Height
145 // BestBlockHash return the hash of the chain tail block
146 func (c *Chain) BestBlockHash() *bc.Hash {
148 defer c.cond.L.Unlock()
149 bestHash := c.bestBlockHeader.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.parentCheckpointByPrevHash(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 {
183 defer c.cond.L.Unlock()
184 return c.bestBlockHeader
187 // InMainChain checks wheather a block is in the main chain
188 func (c *Chain) InMainChain(hash bc.Hash) bool {
189 blockHeader, err := c.store.GetBlockHeader(&hash)
194 blockHash, err := c.store.GetMainChainHash(blockHeader.Height)
196 log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height}).Debug("not contain block hash in main chain for specified height")
199 return *blockHash == hash
202 func (c *Chain) SignBlockHeader(blockHeader *types.BlockHeader) {
203 xprv := config.CommonConfig.PrivateKey()
204 signature := xprv.Sign(blockHeader.Hash().Bytes())
205 blockHeader.Set(signature)
208 // This function must be called with mu lock in above level
209 func (c *Chain) setState(blockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, contractView *state.ContractViewpoint) error {
210 finalizedHeight, finalizedHash := c.casper.LastFinalized()
211 if err := c.store.SaveChainStatus(blockHeader, mainBlockHeaders, view, contractView, finalizedHeight, &finalizedHash); err != nil {
216 defer c.cond.L.Unlock()
218 c.bestBlockHeader = blockHeader
220 hash := c.bestBlockHeader.Hash()
221 log.WithFields(log.Fields{"module": logModule, "height": c.bestBlockHeader.Height, "hash": hash.String()}).Debug("chain best status has been update")
226 // BlockWaiter returns a channel that waits for the block at the given height.
227 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
228 ch := make(chan struct{}, 1)
231 defer c.cond.L.Unlock()
232 for c.bestBlockHeader.Height < height {
241 // GetTxPool return chain txpool.
242 func (c *Chain) GetTxPool() *TxPool {
246 // PrevCheckpointByPrevHash get previous checkpoint by previous block hash
247 func (c *Chain) PrevCheckpointByPrevHash(preBlockHash *bc.Hash) (*state.Checkpoint, error) {
248 return c.casper.parentCheckpointByPrevHash(preBlockHash)