7 "github.com/golang/groupcache/singleflight"
9 "github.com/vapor/common"
10 "github.com/vapor/protocol/bc"
11 "github.com/vapor/protocol/bc/types"
12 "github.com/vapor/protocol/state"
16 maxCachedBlockHeaders = 1000
17 maxCachedBlockTransactions = 1000
18 maxCachedVoteResults = 144 // int(60 * 60 * 24 * 1000 / consensus.BlockTimeInterval / consensus.RoundVoteBlockNums)
21 type fillBlockHeaderFn func(hash *bc.Hash, height uint64) (*types.BlockHeader, error)
22 type fillBlockTransactionsFn func(hash *bc.Hash) ([]*types.Tx, error)
23 type fillVoteResultFn func(seq uint64) (*state.VoteResult, error)
25 func newBlockCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn, fillVoteResult fillVoteResultFn) blockCache {
27 lruBlockHeaders: common.NewCache(maxCachedBlockHeaders),
28 lruBlockTxs: common.NewCache(maxCachedBlockTransactions),
29 lruVoteResults: common.NewCache(maxCachedVoteResults),
31 fillBlockHeaderFn: fillBlockHeader,
32 fillBlockTransactionFn: fillBlockTxs,
33 fillVoteResultFn: fillVoteResult,
37 type blockCache struct {
38 lruBlockHeaders *common.Cache
39 lruBlockTxs *common.Cache
40 lruVoteResults *common.Cache
42 fillBlockHeaderFn func(hash *bc.Hash, height uint64) (*types.BlockHeader, error)
43 fillBlockTransactionFn func(hash *bc.Hash) ([]*types.Tx, error)
44 fillVoteResultFn func(seq uint64) (*state.VoteResult, error)
46 singleBlockHeader singleflight.Group
47 singleBlockTxs singleflight.Group
48 singleVoteResult singleflight.Group
51 func (c *blockCache) lookupBlockHeader(hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
52 if bH, ok := c.getBlockHeader(hash); ok {
56 blockHeader, err := c.singleBlockHeader.Do(hash.String(), func() (interface{}, error) {
57 bH, err := c.fillBlockHeaderFn(hash, height)
63 return nil, fmt.Errorf("There are no blockHeader with given hash %s", hash.String())
72 return blockHeader.(*types.BlockHeader), nil
75 func (c *blockCache) lookupBlockTxs(hash *bc.Hash) ([]*types.Tx, error) {
76 if bTxs, ok := c.getBlockTransactions(hash); ok {
80 blockTransactions, err := c.singleBlockTxs.Do(hash.String(), func() (interface{}, error) {
81 bTxs, err := c.fillBlockTransactionFn(hash)
87 return nil, fmt.Errorf("There are no block transactions with given hash %s", hash.String())
90 c.addBlockTxs(*hash, bTxs)
96 return blockTransactions.([]*types.Tx), nil
99 func (c *blockCache) lookupVoteResult(seq uint64) (*state.VoteResult, error) {
100 if vr, ok := c.getVoteResult(seq); ok {
104 seqStr := strconv.FormatUint(seq, 10)
105 voteResult, err := c.singleVoteResult.Do(seqStr, func() (interface{}, error) {
106 v, err := c.fillVoteResultFn(seq)
112 return nil, fmt.Errorf("There are no vote result with given seq %s", seqStr)
121 return voteResult.(*state.VoteResult), nil
124 func (c *blockCache) getBlockHeader(hash *bc.Hash) (*types.BlockHeader, bool) {
125 blockHeader, ok := c.lruBlockHeaders.Get(*hash)
126 if blockHeader == nil {
129 return blockHeader.(*types.BlockHeader), ok
132 func (c *blockCache) getBlockTransactions(hash *bc.Hash) ([]*types.Tx, bool) {
133 txs, ok := c.lruBlockTxs.Get(*hash)
137 return txs.([]*types.Tx), ok
140 func (c *blockCache) getVoteResult(seq uint64) (*state.VoteResult, bool) {
141 voteResult, ok := c.lruVoteResults.Get(seq)
142 if voteResult == nil {
145 return voteResult.(*state.VoteResult), ok
148 func (c *blockCache) addBlockHeader(blockHeader *types.BlockHeader) {
149 c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader)
152 func (c *blockCache) addBlockTxs(hash bc.Hash, txs []*types.Tx) {
153 c.lruBlockTxs.Add(hash, txs)
156 func (c *blockCache) addVoteResult(voteResult *state.VoteResult) {
157 c.lruVoteResults.Add(voteResult.Seq, voteResult)