6 "github.com/bytom/errors"
7 "github.com/bytom/protocol/bc"
8 "github.com/bytom/protocol/bc/legacy"
9 "github.com/bytom/protocol/state"
10 "github.com/bytom/protocol/validation"
13 // maxBlockTxs limits the number of transactions
14 // included in each block.
15 const maxBlockTxs = 10000
17 // saveSnapshotFrequency stores how often to save a state
18 // snapshot to the Store.
19 const saveSnapshotFrequency = time.Hour
22 // ErrBadBlock is returned when a block is invalid.
23 ErrBadBlock = errors.New("invalid block")
25 // ErrStaleState is returned when the Chain does not have a current
27 ErrStaleState = errors.New("stale blockchain state")
29 // ErrBadStateRoot is returned when the computed assets merkle root
30 // disagrees with the one declared in a block header.
31 ErrBadStateRoot = errors.New("invalid state merkle root")
34 // GetBlock returns the block at the given height, if there is one,
35 // otherwise it returns an error.
36 func (c *Chain) GetBlock(hash *bc.Hash) (*legacy.Block, error) {
37 return c.store.GetBlock(hash)
40 func (c *Chain) GetBlockByHeight(height uint64) (*legacy.Block, error) {
41 hash, ok := c.state.mainChain[height]
45 return c.GetBlock(hash)
48 // ValidateBlock validates an incoming block in advance of applying it
49 // to a snapshot (with ApplyValidBlock) and committing it to the
50 // blockchain (with CommitAppliedBlock).
51 func (c *Chain) ValidateBlock(block, prev *legacy.Block) error {
52 blockEnts := legacy.MapBlock(block)
53 prevEnts := legacy.MapBlock(prev)
54 err := validation.ValidateBlock(blockEnts, prevEnts)
56 return errors.Sub(ErrBadBlock, err)
58 return errors.Sub(ErrBadBlock, err)
61 // ApplyValidBlock creates an updated snapshot without validating the
63 func (c *Chain) ConnectBlock(block *legacy.Block) error {
64 newSnapshot := state.Copy(c.state.snapshot)
65 if err := newSnapshot.ApplyBlock(legacy.MapBlock(block)); err != nil {
68 if block.AssetsMerkleRoot != newSnapshot.Tree.RootHash() {
69 return ErrBadStateRoot
72 blockHash := block.Hash()
73 if err := c.store.SaveSnapshot(newSnapshot, block.Height, &blockHash); err != nil {
76 c.state.mainChain[block.Height] = &blockHash
77 if err := c.store.SaveMainchain(c.state.mainChain, block.Height, &blockHash); err != nil {
78 delete(c.state.mainChain, block.Height)
81 c.state.snapshot = newSnapshot
82 c.store.SaveStoreStatus(block.Height, &blockHash)
84 for _, tx := range block.Transactions {
85 c.txPool.RemoveTransaction(&tx.Tx.ID)
90 func (c *Chain) getReorganizeBlocks(block *legacy.Block) ([]*legacy.Block, []*legacy.Block) {
91 attachBlocks := []*legacy.Block{}
92 detachBlocks := []*legacy.Block{}
95 for ancestor, ok := c.orphanManage.Get(&ancestor.PreviousBlockHash); ok; {
96 if c.InMainchain(ancestor) {
99 attachBlocks = append([]*legacy.Block{ancestor}, attachBlocks...)
102 for n := c.state.block; n != nil; n, _ = c.GetBlock(&n.PreviousBlockHash) {
103 if n.Hash() == ancestor.Hash() {
106 detachBlocks = append(detachBlocks, n)
109 return attachBlocks, detachBlocks
112 func (c *Chain) AddOrphan(block *legacy.Block) error {
113 attachBlocks, detachBlocks := c.getReorganizeBlocks(block)
114 newSnapshot := state.Copy(c.state.snapshot)
116 for _, detachBlock := range detachBlocks {
117 if err := newSnapshot.DetachBlock(legacy.MapBlock(detachBlock)); err != nil {
122 for _, attachBlock := range attachBlocks {
123 if err := newSnapshot.ApplyBlock(legacy.MapBlock(attachBlock)); err != nil {
128 blockHash := block.Hash()
129 if err := c.store.SaveSnapshot(newSnapshot, block.Height, &blockHash); err != nil {
132 for _, attachBlock := range attachBlocks {
133 attachBlockHash := attachBlock.Hash()
134 c.state.mainChain[attachBlock.Height] = &attachBlockHash
135 c.orphanManage.Delete(&attachBlockHash)
137 c.state.mainChain[block.Height] = &blockHash
138 if err := c.store.SaveMainchain(c.state.mainChain, block.Height, &blockHash); err != nil {
139 delete(c.state.mainChain, block.Height)
142 c.state.snapshot = newSnapshot
143 c.store.SaveStoreStatus(block.Height, &blockHash)
147 func (c *Chain) AddBlock(block *legacy.Block) (bool, error) {
148 blockHash := block.Hash()
149 if c.orphanManage.BlockExist(&blockHash) || c.store.BlockExist(&blockHash) {
150 return c.InMainchain(block), nil
153 if !c.store.BlockExist(&block.PreviousBlockHash) {
154 c.orphanManage.Add(block)
158 preBlock, err := c.GetBlock(&block.PreviousBlockHash)
163 if err := c.ValidateBlock(block, preBlock); err != nil {
166 c.store.SaveBlock(block)
168 if *c.state.mainChain[preBlock.Height] == block.PreviousBlockHash {
169 return false, c.ConnectBlock(block)
172 if block.Bits > c.state.block.Bits {
173 return true, c.AddOrphan(block)
178 func (c *Chain) setHeight(h uint64) {
179 // We call setHeight from two places independently:
180 // CommitBlock and the Postgres LISTEN goroutine.
181 // This means we can get here twice for each block,
182 // and any of them might be arbitrarily delayed,
183 // which means h might be from the past.
184 // Detect and discard these duplicate calls.
186 c.state.cond.L.Lock()
187 defer c.state.cond.L.Unlock()
189 if h <= c.state.height {
193 c.state.cond.Broadcast()