8 "github.com/golang/groupcache/lru"
10 "github.com/bytom/errors"
11 "github.com/bytom/log"
12 "github.com/bytom/protocol/bc"
13 "github.com/bytom/protocol/bc/legacy"
14 "github.com/bytom/protocol/state"
17 // maxCachedValidatedTxs is the max number of validated txs to cache.
18 const maxCachedValidatedTxs = 1000
21 // ErrTheDistantFuture is returned when waiting for a blockheight
22 // too far in excess of the tip of the blockchain.
23 ErrTheDistantFuture = errors.New("block height too far in future")
26 // Store provides storage for blockchain data: blocks and state tree
29 // Note, this is different from a state snapshot. A state snapshot
30 // provides access to the state at a given point in time -- outputs
31 // and issuance memory. The Chain type uses Store to load state
32 // from storage and persist validated data.
33 type Store interface {
34 Height(context.Context) (uint64, error)
35 GetBlock(context.Context, uint64) (*legacy.Block, error)
36 LatestSnapshot(context.Context) (*state.Snapshot, uint64, error)
38 SaveBlock(context.Context, *legacy.Block) error
39 FinalizeBlock(context.Context, uint64) error
40 SaveSnapshot(context.Context, uint64, *state.Snapshot) error
43 // Chain provides a complete, minimal blockchain database. It
44 // delegates the underlying storage to other objects, and uses
45 // validation logic from package validation to decide what
46 // objects can be safely stored.
48 InitialBlockHash bc.Hash
49 MaxIssuanceWindow time.Duration // only used by generators
52 cond sync.Cond // protects height, block, snapshot
54 block *legacy.Block // current only if leader
55 snapshot *state.Snapshot // current only if leader
59 lastQueuedSnapshot time.Time
60 pendingSnapshots chan pendingSnapshot
62 prevalidated prevalidatedTxsCache
65 type pendingSnapshot struct {
67 snapshot *state.Snapshot
70 // NewChain returns a new Chain using store as the underlying storage.
71 func NewChain(ctx context.Context, initialBlockHash bc.Hash, store Store, heights <-chan uint64) (*Chain, error) {
73 InitialBlockHash: initialBlockHash,
75 pendingSnapshots: make(chan pendingSnapshot, 1),
76 prevalidated: prevalidatedTxsCache{
77 lru: lru.New(maxCachedValidatedTxs),
80 c.state.cond.L = new(sync.Mutex)
82 c.state.height, _ = store.Height(ctx)
84 // Note that c.height.n may still be zero here.
87 for h := range heights {
98 case ps := <-c.pendingSnapshots:
99 err := store.SaveSnapshot(ctx, ps.height, ps.snapshot)
101 log.Error(ctx, err, "at", "saving snapshot")
110 func (c *Chain) GetStore() *Store {
114 // Height returns the current height of the blockchain.
115 func (c *Chain) Height() uint64 {
116 c.state.cond.L.Lock()
117 defer c.state.cond.L.Unlock()
118 return c.state.height
121 // TimestampMS returns the latest known block timestamp.
122 func (c *Chain) TimestampMS() uint64 {
123 c.state.cond.L.Lock()
124 defer c.state.cond.L.Unlock()
125 if c.state.block == nil {
128 return c.state.block.TimestampMS
131 // State returns the most recent state available. It will not be current
132 // unless the current process is the leader. Callers should examine the
133 // returned block header's height if they need to verify the current state.
134 func (c *Chain) State() (*legacy.Block, *state.Snapshot) {
135 c.state.cond.L.Lock()
136 defer c.state.cond.L.Unlock()
137 return c.state.block, c.state.snapshot
140 func (c *Chain) setState(b *legacy.Block, s *state.Snapshot) {
141 c.state.cond.L.Lock()
142 defer c.state.cond.L.Unlock()
145 if b != nil && b.Height > c.state.height {
146 c.state.height = b.Height
147 c.state.cond.Broadcast()
151 // BlockSoonWaiter returns a channel that
152 // waits for the block at the given height,
153 // but it is an error to wait for a block far in the future.
154 // WaitForBlockSoon will timeout if the context times out.
155 // To wait unconditionally, the caller should use WaitForBlock.
156 func (c *Chain) BlockSoonWaiter(ctx context.Context, height uint64) <-chan error {
157 ch := make(chan error, 1)
161 if height > c.Height()+slop {
162 ch <- ErrTheDistantFuture
167 case <-c.BlockWaiter(height):
177 // BlockWaiter returns a channel that
178 // waits for the block at the given height.
179 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
180 ch := make(chan struct{}, 1)
182 c.state.cond.L.Lock()
183 defer c.state.cond.L.Unlock()
184 for c.state.height < height {