8 "github.com/bytom/errors"
10 "github.com/bytom/protocol/bc"
11 "github.com/bytom/protocol/bc/legacy"
12 "github.com/bytom/protocol/state"
15 // maxCachedValidatedTxs is the max number of validated txs to cache.
16 const maxCachedValidatedTxs = 1000
19 // ErrTheDistantFuture is returned when waiting for a blockheight
20 // too far in excess of the tip of the blockchain.
21 ErrTheDistantFuture = errors.New("block height too far in future")
24 // Store provides storage for blockchain data: blocks and state tree
27 // Note, this is different from a state snapshot. A state snapshot
28 // provides access to the state at a given point in time -- outputs
29 // and issuance memory. The Chain type uses Store to load state
30 // from storage and persist validated data.
31 type Store interface {
33 GetBlock(uint64) (*legacy.Block, error)
34 LatestSnapshot(context.Context) (*state.Snapshot, uint64, error)
36 SaveBlock(*legacy.Block) error
37 FinalizeBlock(context.Context, uint64) error
38 SaveSnapshot(context.Context, uint64, *state.Snapshot) error
41 // Chain provides a complete, minimal blockchain database. It
42 // delegates the underlying storage to other objects, and uses
43 // validation logic from package validation to decide what
44 // objects can be safely stored.
46 InitialBlockHash bc.Hash
47 MaxIssuanceWindow time.Duration // only used by generators
50 cond sync.Cond // protects height, block, snapshot
53 snapshot *state.Snapshot
57 lastQueuedSnapshot time.Time
58 pendingSnapshots chan pendingSnapshot
63 assets_amount map[string]uint64
67 type pendingSnapshot struct {
69 snapshot *state.Snapshot
72 // NewChain returns a new Chain using store as the underlying storage.
73 func NewChain(ctx context.Context, initialBlockHash bc.Hash, store Store, txPool *TxPool, heights <-chan uint64) (*Chain, error) {
75 InitialBlockHash: initialBlockHash,
77 pendingSnapshots: make(chan pendingSnapshot, 1),
80 c.state.cond.L = new(sync.Mutex)
82 c.assets_utxo.assets_amount = make(map[string]uint64, 1024) //prepared buffer 1024 key-values
83 c.assets_utxo.cond.L = new(sync.Mutex)
85 log.Printf(ctx, "bytom's Height:%v.", store.Height())
86 c.state.height = store.Height()
88 if c.state.height < 1 {
89 c.state.snapshot = state.Empty()
91 c.state.block, _ = store.GetBlock(c.state.height)
92 c.state.snapshot, _, _ = store.LatestSnapshot(ctx)
95 // Note that c.height.n may still be zero here.
98 for h := range heights {
109 case ps := <-c.pendingSnapshots:
110 err := store.SaveSnapshot(ctx, ps.height, ps.snapshot)
112 log.Error(ctx, err, "at", "saving snapshot")
121 func (c *Chain) GetStore() *Store {
125 // Height returns the current height of the blockchain.
126 func (c *Chain) Height() uint64 {
127 c.state.cond.L.Lock()
128 defer c.state.cond.L.Unlock()
129 return c.state.height
132 // TimestampMS returns the latest known block timestamp.
133 func (c *Chain) TimestampMS() uint64 {
134 c.state.cond.L.Lock()
135 defer c.state.cond.L.Unlock()
136 if c.state.block == nil {
139 return c.state.block.TimestampMS
142 // State returns the most recent state available. It will not be current
143 // unless the current process is the leader. Callers should examine the
144 // returned block header's height if they need to verify the current state.
145 func (c *Chain) State() (*legacy.Block, *state.Snapshot) {
146 c.state.cond.L.Lock()
147 defer c.state.cond.L.Unlock()
148 return c.state.block, c.state.snapshot
151 func (c *Chain) setState(b *legacy.Block, s *state.Snapshot) {
152 c.state.cond.L.Lock()
153 defer c.state.cond.L.Unlock()
156 if b != nil && b.Height > c.state.height {
157 c.state.height = b.Height
158 c.state.cond.Broadcast()
162 // BlockSoonWaiter returns a channel that
163 // waits for the block at the given height,
164 // but it is an error to wait for a block far in the future.
165 // WaitForBlockSoon will timeout if the context times out.
166 // To wait unconditionally, the caller should use WaitForBlock.
167 func (c *Chain) BlockSoonWaiter(ctx context.Context, height uint64) <-chan error {
168 ch := make(chan error, 1)
172 if height > c.Height()+slop {
173 ch <- ErrTheDistantFuture
178 case <-c.BlockWaiter(height):
188 // BlockWaiter returns a channel that
189 // waits for the block at the given height.
190 func (c *Chain) BlockWaiter(height uint64) <-chan struct{} {
191 ch := make(chan struct{}, 1)
193 c.state.cond.L.Lock()
194 defer c.state.cond.L.Unlock()
195 for c.state.height < height {