8 "github.com/bytom/errors"
10 "github.com/bytom/protocol/bc"
11 "github.com/bytom/protocol/bc/legacy"
12 "github.com/bytom/protocol/state"
13 "github.com/bytom/protocol/validation"
16 // maxBlockTxs limits the number of transactions
17 // included in each block.
18 const maxBlockTxs = 10000
20 // saveSnapshotFrequency stores how often to save a state
21 // snapshot to the Store.
22 const saveSnapshotFrequency = time.Hour
25 // ErrBadBlock is returned when a block is invalid.
26 ErrBadBlock = errors.New("invalid block")
28 // ErrStaleState is returned when the Chain does not have a current
30 ErrStaleState = errors.New("stale blockchain state")
32 // ErrBadStateRoot is returned when the computed assets merkle root
33 // disagrees with the one declared in a block header.
34 ErrBadStateRoot = errors.New("invalid state merkle root")
37 // GetBlock returns the block at the given height, if there is one,
38 // otherwise it returns an error.
39 func (c *Chain) GetBlock(height uint64) (*legacy.Block, error) {
40 return c.store.GetBlock(height)
43 // GenerateBlock generates a valid, but unsigned, candidate block from
44 // the current pending transaction pool. It returns the new block and
45 // a snapshot of what the state snapshot is if the block is applied.
47 // After generating the block, the pending transaction pool will be
49 func (c *Chain) GenerateBlock(ctx context.Context, prev *legacy.Block, snapshot *state.Snapshot, now time.Time, txs []*legacy.Tx) (*legacy.Block, *state.Snapshot, error) {
50 // TODO(kr): move this into a lower-level package (e.g. chain/protocol/bc)
51 // so that other packages (e.g. chain/protocol/validation) unit tests can
52 // call this function.
54 timestampMS := bc.Millis(now)
55 if timestampMS < prev.TimestampMS {
56 return nil, nil, fmt.Errorf("timestamp %d is earlier than prevblock timestamp %d", timestampMS, prev.TimestampMS)
59 // Make a copy of the snapshot that we can apply our changes to.
60 newSnapshot := state.Copy(c.state.snapshot)
61 newSnapshot.PruneNonces(timestampMS)
64 BlockHeader: legacy.BlockHeader{
66 Height: prev.Height + 1,
67 PreviousBlockHash: prev.Hash(),
68 TimestampMS: timestampMS,
69 BlockCommitment: legacy.BlockCommitment{},
73 var txEntries []*bc.Tx
75 for _, tx := range txs {
76 if len(b.Transactions) >= maxBlockTxs {
80 // Filter out transactions that are not well-formed.
81 err := c.ValidateTx(tx.Tx)
83 // TODO(bobg): log this?
87 // Filter out transactions that are not yet valid, or no longer
88 // valid, per the block's timestamp.
89 if tx.Tx.MinTimeMs > 0 && tx.Tx.MinTimeMs > b.TimestampMS {
90 // TODO(bobg): log this?
93 if tx.Tx.MaxTimeMs > 0 && tx.Tx.MaxTimeMs < b.TimestampMS {
94 // TODO(bobg): log this?
98 // Filter out double-spends etc.
99 err = newSnapshot.ApplyTx(tx.Tx)
101 // TODO(bobg): log this?
105 b.Transactions = append(b.Transactions, tx)
106 txEntries = append(txEntries, tx.Tx)
111 b.TransactionsMerkleRoot, err = bc.MerkleRoot(txEntries)
113 return nil, nil, errors.Wrap(err, "calculating tx merkle root")
116 b.AssetsMerkleRoot = newSnapshot.Tree.RootHash()
118 return b, newSnapshot, nil
121 // ValidateBlock validates an incoming block in advance of applying it
122 // to a snapshot (with ApplyValidBlock) and committing it to the
123 // blockchain (with CommitAppliedBlock).
124 func (c *Chain) ValidateBlock(block, prev *legacy.Block) error {
125 blockEnts := legacy.MapBlock(block)
126 prevEnts := legacy.MapBlock(prev)
127 err := validation.ValidateBlock(blockEnts, prevEnts)
129 return errors.Sub(ErrBadBlock, err)
131 return errors.Sub(ErrBadBlock, err)
134 // ApplyValidBlock creates an updated snapshot without validating the
136 func (c *Chain) ApplyValidBlock(block *legacy.Block) (*state.Snapshot, error) {
137 //TODO replace with a pre-defined init blo
138 var newSnapshot *state.Snapshot
139 if c.state.snapshot == nil {
140 newSnapshot = state.Empty()
142 newSnapshot = state.Copy(c.state.snapshot)
145 err := newSnapshot.ApplyBlock(legacy.MapBlock(block))
149 //fmt.Printf("want %v, ger %v \n", block.BlockHeader.AssetsMerkleRoot, newSnapshot.Tree.RootHash())
150 if block.AssetsMerkleRoot != newSnapshot.Tree.RootHash() {
151 return nil, ErrBadStateRoot
153 return newSnapshot, nil
156 // CommitBlock commits a block to the blockchain. The block
157 // must already have been applied with ApplyValidBlock or
158 // ApplyNewBlock, which will have produced the new snapshot that's
161 // This function saves the block to the store and sometimes (not more
162 // often than saveSnapshotFrequency) saves the state tree to the
163 // store. New-block callbacks (via asynchronous block-processor pins)
166 // TODO(bobg): rename to CommitAppliedBlock for clarity (deferred from https://github.com/chain/chain/pull/788)
167 func (c *Chain) CommitAppliedBlock(ctx context.Context, block *legacy.Block, snapshot *state.Snapshot) error {
168 // SaveBlock is the linearization point. Once the block is committed
169 // to persistent storage, the block has been applied and everything
170 // else can be derived from that block.
171 err := c.store.SaveBlock(block)
173 return errors.Wrap(err, "storing block")
175 if block.Time().After(c.lastQueuedSnapshot.Add(saveSnapshotFrequency)) {
176 c.queueSnapshot(ctx, block.Height, block.Time(), snapshot)
179 err = c.store.FinalizeBlock(ctx, block.Height)
181 return errors.Wrap(err, "finalizing block")
184 // c.setState will update the local blockchain state and height.
185 // When c.store is a txdb.Store, and c has been initialized with a
186 // channel from txdb.ListenBlocks, then the above call to
187 // c.store.FinalizeBlock will have done a postgresql NOTIFY and
188 // that will wake up the goroutine in NewChain, which also calls
189 // setHeight. But duplicate calls with the same blockheight are
190 // harmless; and the following call is required in the cases where
191 // it's not redundant.
192 c.setState(block, snapshot)
196 func (c *Chain) queueSnapshot(ctx context.Context, height uint64, timestamp time.Time, s *state.Snapshot) {
197 // Non-blockingly queue the snapshot for storage.
198 ps := pendingSnapshot{height: height, snapshot: s}
200 case c.pendingSnapshots <- ps:
201 c.lastQueuedSnapshot = timestamp
203 // Skip it; saving snapshots is taking longer than the snapshotting period.
204 log.Printf(ctx, "snapshot storage is taking too long; last queued at %s",
205 c.lastQueuedSnapshot)
209 func (c *Chain) setHeight(h uint64) {
210 // We call setHeight from two places independently:
211 // CommitBlock and the Postgres LISTEN goroutine.
212 // This means we can get here twice for each block,
213 // and any of them might be arbitrarily delayed,
214 // which means h might be from the past.
215 // Detect and discard these duplicate calls.
217 c.state.cond.L.Lock()
218 defer c.state.cond.L.Unlock()
220 if h <= c.state.height {
224 c.state.cond.Broadcast()
227 func NewInitialBlock(timestamp time.Time) (*legacy.Block, error) {
228 // TODO(kr): move this into a lower-level package (e.g. chain/protocol/bc)
229 // so that other packages (e.g. chain/protocol/validation) unit tests can
230 // call this function.
231 root, err := bc.MerkleRoot(nil) // calculate the zero value of the tx merkle root
233 return nil, errors.Wrap(err, "calculating zero value of tx merkle root")
237 BlockHeader: legacy.BlockHeader{
240 TimestampMS: bc.Millis(timestamp),
241 BlockCommitment: legacy.BlockCommitment{
242 TransactionsMerkleRoot: root,
245 Transactions: []*legacy.Tx{},